Add support for 2600-daptor II when flashed as an AVox-USB converter.

Basically, for this device we use software flow control rather than hardware CTS signal.
This commit is contained in:
Stephen Anthony 2020-08-21 16:04:49 -02:30
parent 0ef60c517b
commit c00fda482d
10 changed files with 100 additions and 19 deletions

View File

@ -34,8 +34,8 @@
one ZIP file, and distribute just that file. one ZIP file, and distribute just that file.
* Extended AtariVox support to handle flow control, so that long phrases * Extended AtariVox support to handle flow control, so that long phrases
are no longer corrupted/cut off. Note that some USB-serial adaptors are no longer corrupted/cut off. This includes properly supporting the
don't support this mode, so there may still be issues with those. 2600-daptor II, which is flashable to an AVox-USB converter.
* Added option to select the audio device. * Added option to select the audio device.

View File

@ -56,10 +56,27 @@ bool AtariVox::read(DigitalPin pin)
switch(pin) switch(pin)
{ {
// Pin 2: SpeakJet READY // Pin 2: SpeakJet READY
// CTS (Clear To Send) is sent directly to pin 2 // READY signal is sent directly to pin 2
// We also deal with the case where devices send CTS inverted
case DigitalPin::Two: case DigitalPin::Two:
return setPin(pin, mySerialPort->isCTS() ^ myCTSFlip); {
// Some USB-serial adaptors support only CTS, others support only
// software flow control
// So we check the state of both then AND the results, on the
// assumption that if a mode isn't supported, then it reads as TRUE
// and doesn't change the boolean result
// Thus the logic is:
// READY_SIGNAL = READY_STATE_CTS && READY_STATE_FLOW
// Note that we also have to take inverted CTS into account
// When using software flow control, only update on a state change
uInt8 flowCtrl = 0;
if(mySerialPort->readByte(flowCtrl))
myReadyStateSoftFlow = flowCtrl == 0x11; // XON
// Now combine the results of CTS and'ed with flow control
return setPin(pin,
(mySerialPort->isCTS() ^ myCTSFlip) && myReadyStateSoftFlow);
}
default: default:
return SaveKey::read(pin); return SaveKey::read(pin);

View File

@ -32,7 +32,7 @@ class FilesystemNode;
This code owes a great debt to Alex Herbert's AtariVox documentation and This code owes a great debt to Alex Herbert's AtariVox documentation and
driver code. driver code.
@author B. Watson @author B. Watson, Stephen Anthony
*/ */
class AtariVox : public SaveKey class AtariVox : public SaveKey
{ {
@ -91,7 +91,9 @@ class AtariVox : public SaveKey
*/ */
void reset() override; void reset() override;
string about(bool swappedPorts) const override { return Controller::about(swappedPorts) + myAboutString; } string about(bool swappedPorts) const override {
return Controller::about(swappedPorts) + myAboutString;
}
private: private:
void clockDataIn(bool value); void clockDataIn(bool value);
@ -117,9 +119,11 @@ class AtariVox : public SaveKey
// "close enough". // "close enough".
uInt64 myLastDataWriteCycle{0}; uInt64 myLastDataWriteCycle{0};
// Some USB-Serial adaptors either don't support CTS, or send the signal // When using software flow control, assume the device starts in READY mode
// as inverted; we detect that when opening the port, and flip the signal bool myReadyStateSoftFlow{true};
// when necessary
// Some USB-Serial adaptors send the CTS signal inverted; we detect
// that when opening the port, and flip the signal when necessary
bool myCTSFlip{false}; bool myCTSFlip{false};
// Holds information concerning serial port usage // Holds information concerning serial port usage

View File

@ -43,7 +43,6 @@ class SerialPort
/** /**
Read a byte from the serial port. Read a byte from the serial port.
NOTE: This is for potential future use; no class currently uses this.
@param data Destination for the byte read from the port @param data Destination for the byte read from the port
@return True if a byte was read, else false @return True if a byte was read, else false

View File

@ -63,14 +63,21 @@ bool SerialPortMACOS::openPort(const string& device)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortMACOS::readByte(uInt8& data)
{
if(myHandle)
return read(myHandle, &data, 1) == 1;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortMACOS::writeByte(uInt8 data) bool SerialPortMACOS::writeByte(uInt8 data)
{ {
if(myHandle) if(myHandle)
{
// cerr << "SerialPortMACOS::writeByte " << int(data) << endl;
return write(myHandle, &data, 1) == 1; return write(myHandle, &data, 1) == 1;
}
return false; return false;
} }

View File

@ -40,6 +40,14 @@ class SerialPortMACOS : public SerialPort
*/ */
bool openPort(const string& device) override; bool openPort(const string& device) override;
/**
Read a byte from the serial port.
@param data Destination for the byte read from the port
@return True if a byte was read, else false
*/
bool readByte(uInt8& data) override;
/** /**
Write a byte to the serial port. Write a byte to the serial port.

View File

@ -49,7 +49,9 @@ bool SerialPortUNIX::openPort(const string& device)
if(myHandle <= 0) if(myHandle <= 0)
return false; return false;
// Open the device in nonblocking mode // Clear buffers, then open the device in nonblocking mode
tcflush(myHandle, TCOFLUSH);
tcflush(myHandle, TCIFLUSH);
fcntl(myHandle, F_SETFL, FNDELAY); fcntl(myHandle, F_SETFL, FNDELAY);
struct termios termios; struct termios termios;
@ -64,14 +66,21 @@ bool SerialPortUNIX::openPort(const string& device)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortUNIX::readByte(uInt8& data)
{
if(myHandle)
return read(myHandle, &data, 1) == 1;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortUNIX::writeByte(uInt8 data) bool SerialPortUNIX::writeByte(uInt8 data)
{ {
if(myHandle) if(myHandle)
{
// cerr << "SerialPortUNIX::writeByte " << int(data) << endl;
return write(myHandle, &data, 1) == 1; return write(myHandle, &data, 1) == 1;
}
return false; return false;
} }

View File

@ -40,6 +40,14 @@ class SerialPortUNIX : public SerialPort
*/ */
bool openPort(const string& device) override; bool openPort(const string& device) override;
/**
Read a byte from the serial port.
@param data Destination for the byte read from the port
@return True if a byte was read, else false
*/
bool readByte(uInt8& data) override;
/** /**
Write a byte to the serial port. Write a byte to the serial port.

View File

@ -62,6 +62,14 @@ bool SerialPortWINDOWS::openPort(const string& device)
dcb.Parity = NOPARITY; dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT; dcb.StopBits = ONESTOPBIT;
SetCommState(myHandle, &dcb); SetCommState(myHandle, &dcb);
COMMTIMEOUTS commtimeouts;
commtimeouts.ReadIntervalTimeout = MAXDWORD;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 1;
commtimeouts.WriteTotalTimeoutMultiplier = 0;
commtimeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(myHandle, &commtimeouts);
} }
else else
return false; return false;
@ -69,13 +77,26 @@ bool SerialPortWINDOWS::openPort(const string& device)
return true; return true;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortWINDOWS::readByte(uInt8& data)
{
if(myHandle)
{
DWORD read;
ReadFile(myHandle, &data, 1, &read, NULL);
return read == 1;
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortWINDOWS::writeByte(uInt8 data) bool SerialPortWINDOWS::writeByte(uInt8 data)
{ {
if(myHandle) if(myHandle)
{ {
DWORD written; DWORD written;
return WriteFile(myHandle, &data, 1, &written, 0) == TRUE; WriteFile(myHandle, &data, 1, &written, NULL);
return written == 1;
} }
return false; return false;
} }

View File

@ -39,6 +39,14 @@ class SerialPortWINDOWS : public SerialPort
*/ */
bool openPort(const string& device) override; bool openPort(const string& device) override;
/**
Read a byte from the serial port.
@param data Destination for the byte read from the port
@return True if a byte was read, else false
*/
bool readByte(uInt8& data) override;
/** /**
Write a byte to the serial port. Write a byte to the serial port.