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.
* Extended AtariVox support to handle flow control, so that long phrases
are no longer corrupted/cut off. Note that some USB-serial adaptors
don't support this mode, so there may still be issues with those.
are no longer corrupted/cut off. This includes properly supporting the
2600-daptor II, which is flashable to an AVox-USB converter.
* Added option to select the audio device.

View File

@ -56,10 +56,27 @@ bool AtariVox::read(DigitalPin pin)
switch(pin)
{
// Pin 2: SpeakJet READY
// CTS (Clear To Send) is sent directly to pin 2
// We also deal with the case where devices send CTS inverted
// READY signal is sent directly to pin 2
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:
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
driver code.
@author B. Watson
@author B. Watson, Stephen Anthony
*/
class AtariVox : public SaveKey
{
@ -91,7 +91,9 @@ class AtariVox : public SaveKey
*/
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:
void clockDataIn(bool value);
@ -117,9 +119,11 @@ class AtariVox : public SaveKey
// "close enough".
uInt64 myLastDataWriteCycle{0};
// Some USB-Serial adaptors either don't support CTS, or send the signal
// as inverted; we detect that when opening the port, and flip the signal
// when necessary
// When using software flow control, assume the device starts in READY mode
bool myReadyStateSoftFlow{true};
// 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};
// Holds information concerning serial port usage

View File

@ -43,7 +43,6 @@ class SerialPort
/**
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
@return True if a byte was read, else false

View File

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

View File

@ -40,6 +40,14 @@ class SerialPortMACOS : public SerialPort
*/
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.

View File

@ -49,7 +49,9 @@ bool SerialPortUNIX::openPort(const string& device)
if(myHandle <= 0)
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);
struct termios termios;
@ -64,14 +66,21 @@ bool SerialPortUNIX::openPort(const string& device)
return true;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortUNIX::readByte(uInt8& data)
{
if(myHandle)
return read(myHandle, &data, 1) == 1;
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool SerialPortUNIX::writeByte(uInt8 data)
{
if(myHandle)
{
// cerr << "SerialPortUNIX::writeByte " << int(data) << endl;
return write(myHandle, &data, 1) == 1;
}
return false;
}

View File

@ -40,6 +40,14 @@ class SerialPortUNIX : public SerialPort
*/
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.

View File

@ -62,6 +62,14 @@ bool SerialPortWINDOWS::openPort(const string& device)
dcb.Parity = NOPARITY;
dcb.StopBits = ONESTOPBIT;
SetCommState(myHandle, &dcb);
COMMTIMEOUTS commtimeouts;
commtimeouts.ReadIntervalTimeout = MAXDWORD;
commtimeouts.ReadTotalTimeoutMultiplier = 0;
commtimeouts.ReadTotalTimeoutConstant = 1;
commtimeouts.WriteTotalTimeoutMultiplier = 0;
commtimeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(myHandle, &commtimeouts);
}
else
return false;
@ -69,13 +77,26 @@ bool SerialPortWINDOWS::openPort(const string& device)
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)
{
if(myHandle)
{
DWORD written;
return WriteFile(myHandle, &data, 1, &written, 0) == TRUE;
WriteFile(myHandle, &data, 1, &written, NULL);
return written == 1;
}
return false;
}

View File

@ -39,6 +39,14 @@ class SerialPortWINDOWS : public SerialPort
*/
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.