Skip to content

Commit

Permalink
[iec] sync and troubleshooting protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
idolpx committed Oct 19, 2024
1 parent a6f49ce commit a6b59a0
Show file tree
Hide file tree
Showing 20 changed files with 293 additions and 168 deletions.
Binary file removed data/BUILD_IEC/ml.0.spr
Binary file not shown.
Binary file removed data/BUILD_IEC/mlb.prg
Binary file not shown.
4 changes: 2 additions & 2 deletions lib/FileSystem/fnFsTNFSvfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ int vfs_tnfs_fstat(void* ctx, int fd, struct stat * st)
// New basepath will be stored in basepath
esp_err_t vfs_tnfs_register(tnfsMountInfo &m_info, char *basepath, int basepathlen)
{
// Trying to initialze the struct as coumented (e.g. ".write_p = &function")
// Trying to initialze the struct as docoumented (e.g. ".write_p = &function")
// results in compiloer error "non-trivial desginated initializers not supported"
esp_vfs_t vfs;
memset(&vfs, 0, sizeof(vfs));
Expand All @@ -258,7 +258,7 @@ esp_err_t vfs_tnfs_register(tnfsMountInfo &m_info, char *basepath, int basepathl
vfs.rename_p = &vfs_tnfs_rename;

// We'll use the address of our tnfsMountInfo to provide a unique base path
// for this instance wihtout keeping track of how many we create
// for this instance without keeping track of how many we create
snprintf(basepath, basepathlen, "/tnfs%p", &m_info);
esp_err_t e = esp_vfs_register(basepath, &vfs, &m_info);

Expand Down
21 changes: 11 additions & 10 deletions lib/bus/iec/iec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,12 @@ void IRAM_ATTR systemBus::service()
detected_protocol = PROTOCOL_SERIAL;
protocol = selectProtocol();
//release ( PIN_IEC_SRQ );
}

if ( status ( PIN_IEC_ATN ) )
{
state = BUS_ACTIVE;
}
// Let's check ATN again before we exit and clean up
if ( status ( PIN_IEC_ATN ) )
{
state = BUS_ACTIVE;
}

} while( state > BUS_IDLE );
Expand Down Expand Up @@ -499,12 +500,12 @@ void systemBus::read_command()
// Sometimes ATN isn't released immediately. Wait for ATN to be
// released before trying to process the command.
// Long ATN delay (>1.5ms) seems to occur more frequently with VIC-20.
pull ( PIN_IEC_SRQ );
//pull ( PIN_IEC_SRQ );
protocol->timeoutWait ( PIN_IEC_ATN, RELEASED, TIMEOUT_DEFAULT, false );

// Delay after ATN is RELEASED
//protocol->wait( TIMING_Ttk, false );
release ( PIN_IEC_SRQ );
//release ( PIN_IEC_SRQ );
}


Expand Down Expand Up @@ -835,14 +836,14 @@ void IRAM_ATTR systemBus::deviceListen()
void IRAM_ATTR systemBus::deviceTalk()
{
// Now do bus turnaround
//pull(PIN_IEC_SRQ);
pull(PIN_IEC_SRQ);
if (!turnAround())
{
Debug_printv("error flags[%d]", flags);
state = BUS_ERROR;
return;
}
//release(PIN_IEC_SRQ);
release(PIN_IEC_SRQ);

// We have recieved a CMD and we should talk now:
state = BUS_PROCESS;
Expand Down Expand Up @@ -871,7 +872,7 @@ bool IRAM_ATTR systemBus::turnAround()
*/

// Wait for CLK to be released
pull ( PIN_IEC_SRQ );
//pull ( PIN_IEC_SRQ );
if (protocol->timeoutWait(PIN_IEC_CLK_IN, RELEASED, TIMEOUT_Ttlta) == TIMEOUT_Ttlta)
{
Debug_printv("Wait until the computer releases the CLK line\r\n");
Expand All @@ -881,7 +882,7 @@ bool IRAM_ATTR systemBus::turnAround()
}
release ( PIN_IEC_DATA_OUT );
pull ( PIN_IEC_CLK_OUT );
release ( PIN_IEC_SRQ );
//release ( PIN_IEC_SRQ );

// 80us minimum delay after TURNAROUND
// *** IMPORTANT!
Expand Down
4 changes: 4 additions & 0 deletions lib/bus/iec/ieee-488.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//
// https://www.pagetable.com/?p=1023
// https://ia601902.us.archive.org/9/items/PET_and_the_IEEE488_Bus_1980_McGraw-Hill/PET_and_the_IEEE488_Bus_1980_McGraw-Hill.pdf
//
18 changes: 10 additions & 8 deletions lib/bus/iec/protocol/_protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ IECProtocol::IECProtocol() {
esp_timer_create_args_t args = {
.callback = onTimer,
.arg = this,
.name = nullptr
.dispatch_method = ESP_TIMER_ISR,
.name = "onTimer"
};
esp_timer_create(&args, &timer_handle);
};
Expand All @@ -40,13 +41,14 @@ IECProtocol::~IECProtocol() {
void IECProtocol::timer_start(uint64_t timeout_us)
{
timer_timedout = false;
esp_timer_stop(timer_handle);
timer_started = esp_timer_get_time();
esp_timer_start_once(timer_handle, timeout_us);
//IEC.pull( PIN_IEC_SRQ );
}
void IECProtocol::timer_stop()
{
esp_timer_stop(timer_handle);
timer_elapsed = esp_timer_get_time() - timer_started;
//IEC.release( PIN_IEC_SRQ );
}

Expand Down Expand Up @@ -93,7 +95,6 @@ int16_t IRAM_ATTR IECProtocol::timeoutWait(uint8_t pin, bool target_status, size
uint64_t start = 0;
uint64_t current = 0;
uint64_t elapsed = 0;
bool atn_status = false;

#ifndef IEC_SPLIT_LINES
IEC.release ( pin );
Expand All @@ -113,9 +114,9 @@ int16_t IRAM_ATTR IECProtocol::timeoutWait(uint8_t pin, bool target_status, size
IEC.release ( PIN_IEC_ATN );
#endif

// // Sample ATN and set flag to indicate COMMAND or DATA mode
// atn_status = IEC.status ( PIN_IEC_ATN );
// if ( atn_status ) IEC.flags |= ATN_PULLED;
// Sample ATN and set flag to indicate COMMAND or DATA mode
if( IEC.status ( PIN_IEC_ATN ) )
IEC.flags |= ATN_PULLED;
}

//IEC.pull ( PIN_IEC_SRQ );
Expand All @@ -134,9 +135,10 @@ int16_t IRAM_ATTR IECProtocol::timeoutWait(uint8_t pin, bool target_status, size
return wait_us;
}

if ( watch_atn && (IEC.flags & ATN_PULLED) )
if ( watch_atn )
{
return -1;
if ( IEC.flags & ATN_PULLED )
return -1;
}

if ( IEC.state < BUS_ACTIVE || elapsed > FOREVER )
Expand Down
1 change: 1 addition & 0 deletions lib/bus/iec/protocol/_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Protocol
};

bool timer_timedout = false;
uint64_t timer_started = 0;
uint64_t timer_elapsed = 0;


Expand Down
107 changes: 54 additions & 53 deletions lib/bus/iec/protocol/cpbstandardserial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ CPBStandardSerial::CPBStandardSerial()
.callback = onSendBits,
.arg = this,
.dispatch_method = ESP_TIMER_ISR,
.name = "Send"
.name = "onSendBits"
};
esp_timer_create(&args, &timer_send_h);
//Debug_printv("send_timer_create");
Expand Down Expand Up @@ -119,6 +119,7 @@ uint8_t CPBStandardSerial::receiveByte()
// to accept data. What happens next is variable.

// Wait for all other devices to release the data line
//IEC.release( PIN_IEC_DATA_IN );
if ( timeoutWait ( PIN_IEC_DATA_IN, RELEASED, FOREVER, false ) == TIMED_OUT )
{
Debug_printv ( "Wait for all other devices to release the data line" );
Expand All @@ -131,10 +132,8 @@ uint8_t CPBStandardSerial::receiveByte()
// will do nothing. The listener should be watching, and if 200 microseconds pass
// without the Clock line going to true, it has a special task to perform: note EOI.

//IEC.pull ( PIN_IEC_SRQ );
IEC.pull ( PIN_IEC_SRQ );
if ( timeoutWait ( PIN_IEC_CLK_IN, PULLED, TIMING_Tye, false ) == TIMING_Tye )
// timer_start( TIMING_Tye );
// while ( IEC.status ( PIN_IEC_CLK_IN ) != PULLED )
{
// INTERMISSION: EOI
// If the Ready for Data signal isn't acknowledged by the talker within 200 microseconds, the
Expand All @@ -152,30 +151,23 @@ uint8_t CPBStandardSerial::receiveByte()

//IEC.pull ( PIN_IEC_SRQ );

//if ( timer_timedout )
{
timer_timedout = false;
IEC.flags |= EOI_RECVD;

// Acknowledge by pull down data more than 60us
//wait ( TIMING_Th );
IEC.pull ( PIN_IEC_DATA_OUT );
wait ( TIMING_Tei );
IEC.release ( PIN_IEC_DATA_OUT );
timer_timedout = false;
IEC.flags |= EOI_RECVD;

// Wait for clock line to be pulled
timeoutWait ( PIN_IEC_CLK_IN, PULLED, TIMING_Tye, false );
}
// Acknowledge by pull down data more than 60us
//wait ( TIMING_Th );
IEC.pull ( PIN_IEC_DATA_OUT );
wait ( TIMING_Tei );
IEC.release ( PIN_IEC_DATA_OUT );

//usleep( 2 );
//IEC.release ( PIN_IEC_SRQ );
//usleep( 2 );
// Wait for clock line to be pulled
//timeoutWait ( PIN_IEC_CLK_IN, PULLED, TIMING_Tye, false );
}
//IEC.release ( PIN_IEC_SRQ );
IEC.release ( PIN_IEC_SRQ );

// Sample ATN and set flag to indicate COMMAND or DATA mode
if ( IEC.status ( PIN_IEC_ATN ) )
IEC.flags |= ATN_PULLED;
// // Sample ATN and set flag to indicate COMMAND or DATA mode
// if ( IEC.status ( PIN_IEC_ATN ) )
// IEC.flags |= ATN_PULLED;

// STEP 3: RECEIVING THE BITS
//IEC.pull ( PIN_IEC_SRQ );
Expand Down Expand Up @@ -229,18 +221,23 @@ uint8_t CPBStandardSerial::receiveBits ()
{
IEC.bit = 0;
IEC.byte = 0;
timer_start( TIMEOUT_DEFAULT );

timer_start( TIMEOUT_DEFAULT );
while ( IEC.bit < 7 )
{
if ( timer_timedout )
{
Debug_printv ( "Timeout bit[%d]", IEC.bit );
IEC.flags |= ERROR;
return 0;
}

usleep( 2 );
IEC.pull( PIN_IEC_SRQ );
usleep( 1 );
IEC.release( PIN_IEC_SRQ );
usleep( 1 );
}
timer_stop();

// If there is a 218us delay before bit 7, the controller uses JiffyDOS
timer_start( TIMING_PROTOCOL_DETECT );
Expand Down Expand Up @@ -270,8 +267,12 @@ uint8_t CPBStandardSerial::receiveBits ()
}
}

usleep( 2 );
IEC.pull( PIN_IEC_SRQ );
usleep( 1 );
IEC.release( PIN_IEC_SRQ );
usleep( 1 );
}
timer_stop();

// Wait for CLK to be pulled after last bit
if ( timeoutWait ( PIN_IEC_CLK_IN, PULLED, FOREVER, false ) == TIMED_OUT )
Expand Down Expand Up @@ -396,7 +397,7 @@ bool CPBStandardSerial::sendByte(uint8_t data, bool eoi)
// line to false. Suppose there is more than one listener. The Data line will go false
// only when all listeners have RELEASED it - in other words, when all listeners are ready
// to accept data.
IEC.pull ( PIN_IEC_SRQ );
//IEC.pull ( PIN_IEC_SRQ );
if ( timeoutWait ( PIN_IEC_DATA_IN, RELEASED, FOREVER ) == TIMED_OUT )
{
if ( !(IEC.flags & ATN_PULLED) )
Expand All @@ -407,7 +408,7 @@ bool CPBStandardSerial::sendByte(uint8_t data, bool eoi)

return false; // return error because of ATN or timeout
}
IEC.release ( PIN_IEC_SRQ );
//IEC.release ( PIN_IEC_SRQ );

// What happens next is variable. Either the talker will pull the
// Clock line back to true in less than 200 microseconds - usually within 60 microseconds - or it
Expand Down Expand Up @@ -471,33 +472,33 @@ bool CPBStandardSerial::sendByte(uint8_t data, bool eoi)

// Wait for listener to accept data
//IEC.pull ( PIN_IEC_SRQ );
// if ( timeoutWait ( PIN_IEC_DATA_IN, PULLED, TIMEOUT_Tf ) == TIMEOUT_Tf )
if ( timeoutWait ( PIN_IEC_DATA_IN, PULLED, TIMEOUT_Tf ) == TIMEOUT_Tf )
{
// RECIEVER TIMEOUT
// If no receiver pulls DATA within 1000 µs at the end of the transmission of a byte (after step 28), a receiver timeout is raised.
Debug_printv ( "Wait for listener to acknowledge byte received (pull data) [%02X]", data );
Debug_printv ( "RECEIVER TIMEOUT" );
IEC.flags |= ERROR;
//IEC.release ( PIN_IEC_SRQ );
return false; // return error because timeout
}
//IEC.release ( PIN_IEC_SRQ );
//IEC.pull ( PIN_IEC_SRQ );
// timer_start( TIMEOUT_Tf );
// while ( IEC.status ( PIN_IEC_DATA_IN ) != PULLED )
// {
// // RECIEVER TIMEOUT
// // If no receiver pulls DATA within 1000 µs at the end of the transmission of a byte (after step 28), a receiver timeout is raised.
// Debug_printv ( "Wait for listener to acknowledge byte received (pull data) [%02x]", data );
// Debug_printv ( "RECEIVER TIMEOUT" );
// IEC.flags |= ERROR;
// IEC.release ( PIN_IEC_SRQ );
// return false; // return error because timeout
// if ( timer_timedout )
// {
// // RECIEVER TIMEOUT
// // If no receiver pulls DATA within 1000 µs at the end of the transmission of a byte (after step 28), a receiver timeout is raised.
// Debug_printv ( "Wait for listener to acknowledge byte received (pull data) [%02X]", data );
// Debug_printv ( "RECEIVER TIMEOUT" );
// IEC.flags |= ERROR;
// //IEC.release ( PIN_IEC_SRQ );
// return false; // return error because timeout
// }
// }
//IEC.release ( PIN_IEC_SRQ );
IEC.pull ( PIN_IEC_SRQ );
timer_start( TIMEOUT_Tf );
while ( IEC.status ( PIN_IEC_DATA_IN ) != PULLED )
{
if ( timer_timedout )
{
// RECIEVER TIMEOUT
// If no receiver pulls DATA within 1000 µs at the end of the transmission of a byte (after step 28), a receiver timeout is raised.
Debug_printv ( "Wait for listener to acknowledge byte received (pull data) [%02x]", data );
Debug_printv ( "RECEIVER TIMEOUT" );
IEC.flags |= ERROR;
IEC.release ( PIN_IEC_SRQ );
return false; // return error because timeout
}
}
IEC.release ( PIN_IEC_SRQ );

// STEP 5: START OVER
// We're finished, and back where we started. The talker is holding the Clock line true,
Expand Down
9 changes: 1 addition & 8 deletions lib/device/iec/drive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,15 +355,8 @@ void iecDrive::iec_command()
{
Debug_printv("command[%s]", payload.c_str());

// if (mstr::startsWith(payload, "cd"))
// set_prefix();
// else if (pt[0] == "pwd")
// get_prefix();
// else if (pt[0] == "id")
// set_device_id();

// Drive level commands
// CBM DOS 2.5
// CBM DOS 2.6
switch ( payload[0] )
{
case 'B':
Expand Down
19 changes: 11 additions & 8 deletions lib/device/iec/drive.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,9 @@ class iecDrive : public virtualDevice
std::unique_ptr<MFile> _base; // Always points to current directory/image
std::string _last_file; // Always points to last loaded file

// Named Channel functions
//std::shared_ptr<MStream> currentStream;
bool registerStream (uint8_t channel);
std::shared_ptr<MStream> retrieveStream ( uint8_t channel );
bool closeStream ( uint8_t channel, bool close_all = false );
uint16_t retrieveLastByte ( uint8_t channel );
void storeLastByte( uint8_t channel, char last);
void flushLastByte( uint8_t channel );
// RAM/ROM
// std::streambuf ram;
std::unique_ptr<MFile> rom; // ROM File for current drive model if available

// Directory
uint16_t sendHeader(std::string header, std::string id);
Expand All @@ -58,6 +53,14 @@ class iecDrive : public virtualDevice
bool saveFile();
void sendFileNotFound();

// Named Channel functions
bool registerStream (uint8_t channel);
std::shared_ptr<MStream> retrieveStream ( uint8_t channel );
bool closeStream ( uint8_t channel, bool close_all = false );
uint16_t retrieveLastByte ( uint8_t channel );
void storeLastByte( uint8_t channel, char last);
void flushLastByte( uint8_t channel );

struct _error_response
{
unsigned char errnum = 73;
Expand Down
Loading

0 comments on commit a6b59a0

Please sign in to comment.