]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Paula and uaeserial.device serial port receive break condition support.
authorToni Wilen <twilen@winuae.net>
Sun, 5 Apr 2020 14:37:46 +0000 (17:37 +0300)
committerToni Wilen <twilen@winuae.net>
Sun, 5 Apr 2020 14:37:46 +0000 (17:37 +0300)
od-win32/parser.cpp
od-win32/parser.h
od-win32/serial_win32.cpp
uaeserial.cpp

index 523ae2d4a2bb3df2b7caa99bf094786b5891fa6e..90248e563f1af34dc5f868562b5d0ba708a8da8b 100644 (file)
@@ -687,6 +687,8 @@ static void *uaeser_trap_thread (void *arg)
                                sigmask |= 1;
                        if ((evtmask & EV_TXEMPTY) && !sd->writeactive)
                                sigmask |= 2;
+                       if (evtmask & EV_BREAK)
+                               sigmask |= 4;
                        startwce(sd, &evtmask);
                }
                cnt = 0;
@@ -741,6 +743,8 @@ int uaeser_read (void *vsd, uae_u8 *data, uae_u32 len)
 
        if (!ClearCommError (sd->hCom, &err, &ComStat))
                return 0;
+       if (err & EV_BREAK)
+               return -1;
        if (len > ComStat.cbInQue)
                return 0;
        if (!ReadFile (sd->hCom, data, len, NULL, &sd->olr)) {
@@ -841,6 +845,7 @@ static int datainoutput;
 static int dataininput, dataininputcnt;
 static OVERLAPPED writeol, readol;
 static int writepending;
+static bool breakpending;
 
 static WSADATA wsadata;
 static SOCKET serialsocket = INVALID_SOCKET;
@@ -1014,7 +1019,7 @@ int openser (const TCHAR *sername)
                return 0;
        }
 
-       SetCommMask (hCom, EV_RXFLAG);
+       SetCommMask (hCom, EV_RXFLAG | EV_BREAK);
        SetupComm (hCom, 65536, 128);
        PurgeComm (hCom, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
        CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
@@ -1059,6 +1064,7 @@ int openser (const TCHAR *sername)
                return 1;
        }
 
+
        write_log (_T("SERIAL: serial driver didn't accept new parameters\n"));
        closeser();
        return 0;
@@ -1151,11 +1157,29 @@ int checkserwrite (int spaceneeded)
        return 1;
 }
 
-int readseravail (void)
+void flushser(void)
+{
+       if (!tcpserial && !midi_ready && hCom) {
+               COMSTAT ComStat;
+               DWORD dwErrorFlags;
+               ClearCommError(hCom, &dwErrorFlags, &ComStat);
+               PurgeComm(hCom, PURGE_RXCLEAR);
+       } else {
+               while (readseravail(NULL)) {
+                       int data;
+                       if (readser(&data) <= 0)
+                               break;
+               }
+       }
+}
+
+int readseravail(bool *breakcond)
 {
        COMSTAT ComStat;
        DWORD dwErrorFlags;
 
+       if (breakcond)
+               *breakcond = false;
        if (tcpserial) {
                if (tcp_is_connected ()) {
                        struct timeval tv;
@@ -1183,8 +1207,12 @@ int readseravail (void)
                        return 1;
                if (hCom != INVALID_HANDLE_VALUE)  {
                        ClearCommError (hCom, &dwErrorFlags, &ComStat);
+                       if (breakcond && ((dwErrorFlags & CE_BREAK) || breakpending)) {
+                               *breakcond = true;
+                               breakpending = false;
+                       }
                        if (ComStat.cbInQue > 0)
-                               return 1;
+                               return ComStat.cbInQue;
                }
        }
        return 0;
@@ -1227,6 +1255,8 @@ int readser (int *buffer)
                if (hCom != INVALID_HANDLE_VALUE)  {
                        /* only try to read number of bytes in queue */
                        ClearCommError (hCom, &dwErrorFlags, &ComStat);
+                       if (dwErrorFlags & CE_BREAK)
+                               breakpending = true;
                        if (ComStat.cbInQue)  {
                                int len = ComStat.cbInQue;
                                if (len > sizeof (inputbuffer))
@@ -1261,6 +1291,7 @@ void serialuartbreak (int v)
 
 void getserstat (int *pstatus)
 {
+       DWORD err;
        DWORD stat;
        int status = 0;
 
index c9256d7cd0d634af66980fe1b13199b75aaa145c..36a44fa5cda0297f41425b38a848ebf80abe9ce1 100644 (file)
@@ -9,20 +9,21 @@
 
 #define PRTBUFSIZE 65536
 
-int setbaud (long baud );
+int setbaud(long baud );
 void getserstat(int *status);
-void setserstat (int mask, int onoff);
-int readser (int *buffer);
-int readseravail (void);
+void setserstat(int mask, int onoff);
+int readser(int *buffer);
+int readseravail(bool*);
+void flushser(void);
 void writeser(int c);
 void writeser_flush(void);
-int openser (const TCHAR *sername);
-void closeser (void);
-void doserout (void);
-void closeprinter (void);
-void flushprinter (void);
-int checkserwrite (int spaceneeded);
-void serialuartbreak (int);
+int openser(const TCHAR *sername);
+void closeser(void);
+void doserout(void);
+void closeprinter(void);
+void flushprinter(void);
+int checkserwrite(int spaceneeded);
+void serialuartbreak(int);
 
 void hsyncstuff(void);
 
index 2a10eb652fa45f7533c375dc117627828274d50f..84c77ac11f7209c7526cdd3acf0af45b2d1a1952 100644 (file)
@@ -31,6 +31,8 @@
 #define SERIALDEBUG 0 /* 0, 1, 2 3 */
 #define SERIALHSDEBUG 0
 #define SERIAL_HSYNC_BEFORE_OVERFLOW 200
+#define SERIAL_BREAK_DELAY (20 * maxvpos)
+#define SERIAL_BREAK_TRANSMIT_DELAY 4
 
 #define SERIAL_MAP
 
@@ -164,6 +166,8 @@ bool shmem_serial_create(void)
 static int data_in_serdat; /* new data written to SERDAT */
 static int data_in_serdatr; /* new data received */
 static int data_in_sershift; /* data transferred from SERDAT to shift register */
+static int break_in_serdatr; /* break state */
+static int break_delay;
 static uae_u16 serdatshift; /* serial shift register */
 static uae_u16 serdatshift_masked; /* stop bit masked */
 static int ovrun;
@@ -269,15 +273,6 @@ static TCHAR dochar(int v)
        return '.';
 }
 
-static void flushser(void)
-{
-       while (readseravail() > 0) {
-               int data;
-               if (!readser(&data))
-                       break;
-       }
-}
-
 static bool canreceive(void)
 {
        if (!data_in_serdatr)
@@ -334,50 +329,132 @@ static void checkreceive_serial (void)
                return;
 
        if (ninebit) {
-               if (!readseravail())
-                       return;
-               for (;;) {
-                       if (!readser (&recdata))
-                               return;
-                       if (ninebitdata) {
-                               serdatr = (ninebitdata & 1) << 8;
-                               serdatr |= recdata;
+               bool breakcond;
+               int status = readseravail(&breakcond);
+               if (break_in_serdatr == -1 || break_in_serdatr > 0) {
+                       serial_recv_previous = 0;
+                       serdatr = 0;
+                       if (break_in_serdatr < 0) {
+                               break_in_serdatr = SERIAL_BREAK_DELAY;
+                               break_delay = SERIAL_BREAK_TRANSMIT_DELAY;
+                       }
+                       if (break_in_serdatr == 1) {
                                serdatr |= 0x200;
-                               ninebitdata = 0;
-                               break;
-                       } else {
-                               ninebitdata = recdata;
-                               if ((ninebitdata & ~1) != 0xa8) {
-                                       write_log (_T("SERIAL: 9-bit serial emulation sync lost, %02X != %02X\n"), ninebitdata & ~1, 0xa8);
-                                       ninebitdata = 0;
+                               break_in_serdatr = 0;
+                       }
+                       break_delay--;
+                       if (break_delay && break_in_serdatr) {
+                               return;
+                       }
+                       break_delay = SERIAL_BREAK_TRANSMIT_DELAY;
+               } else {
+                       if (breakcond && !break_in_serdatr) {
+                               break_in_serdatr = -1;
+                               break_in_serdatr -= status;
+                               if (break_in_serdatr == -1)
                                        return;
+                       }
+                       if (status <= 0) {
+                               return;
+                       }
+                       for (;;) {
+                               status = readser(&recdata);
+                               if (!status)
+                                       return;
+                               if (break_in_serdatr > 0) {
+                                       break_in_serdatr = 0;
+                               }
+                               if (ninebitdata) {
+                                       serdatr = (ninebitdata & 1) << 8;
+                                       serdatr |= recdata;
+                                       serdatr |= 0x200;
+                                       ninebitdata = 0;
+                                       if (break_in_serdatr < -1) {
+                                               break_in_serdatr++;
+                                       }
+                                       break;
+                               } else {
+                                       ninebitdata = recdata;
+                                       if ((ninebitdata & ~1) != 0xa8) {
+                                               write_log(_T("SERIAL: 9-bit serial emulation sync lost, %02X != %02X\n"), ninebitdata & ~1, 0xa8);
+                                               ninebitdata = 0;
+                                               return;
+                                       }
+                                       continue;
                                }
-                               continue;
                        }
                }
        } else {
-               if (!readseravail())
-                       return;
-               if (!readser(&recdata))
-                       return;
-               if (currprefs.serial_crlf) {
-                       if (recdata == 0 || (serial_recv_previous == 13 && recdata == 10)) {
-                               //write_log(_T(" [%02X] "), (uae_u8)recdata);
-                               serial_recv_previous = -1;
+               bool breakcond;
+               int status = readseravail(&breakcond);
+               if (break_in_serdatr == -1 || break_in_serdatr > 0) {
+                       // break: stop bit is zero
+                       // Paula for some reason keeps receiving zeros continuously in break condition.
+                       serial_recv_previous = 0;
+                       serdatr = 0;
+                       if (break_in_serdatr < 0) {
+                               break_in_serdatr = SERIAL_BREAK_DELAY;
+                               break_delay = SERIAL_BREAK_TRANSMIT_DELAY;
+#if SERIALDEBUG
+                               write_log(_T("SERIAL: BREAK START\n"));
+#endif
+                       }
+                       // serial.device requires valid serial word before it finally returns break error
+                       if (break_in_serdatr == 1) {
+                               serdatr |= 0x100;
+#if SERIALDEBUG
+                               write_log(_T("SERIAL: BREAK COMPLETE\n"));
+#endif
+                               break_in_serdatr = 0;
+                       }
+                       break_delay--;
+                       if (break_delay && break_in_serdatr) {
+                               return;
+                       }
+                       break_delay = SERIAL_BREAK_TRANSMIT_DELAY;
+               } else {
+                       if (breakcond && !break_in_serdatr) {
+                               break_in_serdatr = -1;
+#if SERIALDEBUG
+                               write_log(_T("SERIAL: BREAK DETECT (%d buffered)\n"), status);
+#endif
+                               break_in_serdatr -= status;
+                               if (break_in_serdatr == -1)
+                                       return;
+                       }
+                       if (status <= 0) {
                                return;
                        }
+                       if (!readser(&recdata))
+                               return;
+                       if (break_in_serdatr > 0) {
+#if SERIALDEBUG
+                               write_log(_T("SERIAL: BREAK END\n"));
+#endif
+                               break_in_serdatr = 0;
+                       }
+                       if (currprefs.serial_crlf) {
+                               if (recdata == 0 || (serial_recv_previous == 13 && recdata == 10)) {
+                                       //write_log(_T(" [%02X] "), (uae_u8)recdata);
+                                       serial_recv_previous = -1;
+                                       return;
+                               }
+                       }
+                       //write_log(_T(" %02X "), (uae_u8)recdata);
+                       serial_recv_previous = recdata;
+                       serdatr = recdata;
+                       serdatr |= 0x0100;
+                       if (break_in_serdatr < -1) {
+                               break_in_serdatr++;
+                       }
                }
-               //write_log(_T(" %02X "), (uae_u8)recdata);
-               serial_recv_previous = recdata;
-               serdatr = recdata;
-               serdatr |= 0x100;
        }
 
        data_in_serdatr = 1;
        serdatr_last_got = 0;
-       serial_check_irq ();
+       serial_check_irq();
 #if SERIALDEBUG > 2
-       write_log (_T("SERIAL: received %02X (%c)\n"), serdatr & 0xff, dochar (serdatr));
+       write_log(_T("SERIAL: received %02X (%c)\n"), serdatr & 0xff, dochar(serdatr));
 #endif
 #endif
 }
@@ -589,6 +666,15 @@ void serial_hsynchandler (void)
        } else if ((serial_period_hsync_counter % serial_period_hsyncs) == 0 && !currprefs.cpu_cycle_exact) {
                checkshiftempty();
        }
+       if (break_in_serdatr > 1) {
+               break_in_serdatr--;
+               if (break_in_serdatr == 1) {
+#if SERIALDEBUG
+                       write_log(_T("SERIAL: BREAK TIMEOUT\n"));
+#endif
+                       flushser();
+               }
+       }
 }
 
 void SERDAT (uae_u16 w)
@@ -618,17 +704,24 @@ void SERDAT (uae_u16 w)
        serdatcopy();
 }
 
-uae_u16 SERDATR (void)
+uae_u16 SERDATR(void)
 {
        serdatr &= 0x03ff;
-       if (!data_in_serdat)
+       if (!data_in_serdat) {
                serdatr |= 0x2000;
-       if (!data_in_sershift)
+       }
+       if (!data_in_sershift) {
                serdatr |= 0x1000;
-       if (data_in_serdatr)
+       }
+       if (data_in_serdatr) {
                serdatr |= 0x4000;
-       if (ovrun)
+       }
+       if (ovrun) {
                serdatr |= 0x8000;
+       }
+       if (break_in_serdatr <= 0) {
+               serdatr |= 0x0800;
+       }
 #if SERIALDEBUG > 2
        write_log (_T("SERIAL: read 0x%04x (%c) %x\n"), serdatr, dochar (serdatr), M68K_GETPC);
 #endif
index cc6a4b028ba0c55ae06ec1bc24a5b6935dcfc841..ffc4a570569006e51bc3c63377bbb3d929098059 100644 (file)
@@ -441,17 +441,21 @@ void uaeser_signal (void *vdev, int sigmask)
                                        io_done = 1;
                                        while (io_length > 0) {
                                                int size = io_length > sizeof(tmp) ? sizeof(tmp) : io_length;
-                                               if (uaeser_read(dev->sysdata, tmp, size)) {
+                                               int status = uaeser_read(dev->sysdata, tmp, size);
+                                               if (status > 0) {
                                                        trap_put_bytes(ctx, tmp, io_data, size);
                                                        io_actual += size;
                                                        io_data += size;
                                                        io_length -= size;
-                                               } else {
+                                               } else if (status == 0) {
                                                        if (io_actual == 0)
                                                                io_done = 0;
                                                        break;
                                                }
                                        }
+                               } else if (sigmask & 4) {
+                                       io_done = 1;
+                                       io_error = SerErr_DetectedBreak;
                                }
                                break;
                        case CMD_WRITE:
@@ -732,7 +736,7 @@ void uaeserialdev_install (void)
                return;
 
        ROM_uaeserialdev_resname = ds (_T("uaeserial.device"));
-       ROM_uaeserialdev_resid = ds (_T("UAE serial.device 0.2"));
+       ROM_uaeserialdev_resid = ds (_T("UAE serial.device 0.3"));
 
        /* initcode */
        initcode = here ();