changeset 342:6ff231195905

fluid-mnf/serial.[ch]: beginning of Linux port
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 13 Mar 2020 05:39:37 +0000
parents 1cd24530c0ae
children 917e05f03ad2
files fluid-mnf/serial.c fluid-mnf/serial.h
diffstat 2 files changed, 112 insertions(+), 198 deletions(-) [+]
line wrap: on
line diff
--- a/fluid-mnf/serial.c	Fri Mar 13 02:51:54 2020 +0000
+++ b/fluid-mnf/serial.c	Fri Mar 13 05:39:37 2020 +0000
@@ -8,136 +8,111 @@
  *
  * $Id: serial.c 1.23 Fri, 18 Oct 2002 08:53:12 +0200 mmj $
  *
+ * This serial interface handling architecture has been majorly redesigned
+ * by Mychaela N. Falconia for the present fluid-mnf Linux port.
+ *
+ * Because FLUID supports Calypso high baud rates of 203125, 406250 and 812500
+ * bps, as well as D-Sample XXO (eXternal Xtal Oscillator) baud rates of
+ * 230400, 460800 and 912600 bps, the present fluid-mnf port had to be made
+ * quite Linux-specific, using the same raw ioctl approach as is used in
+ * freecalypso-tools/libserial-linux.
+ *
  ******************************************************************************/
 
 #include "fluid.h"
 #include "serial.h"
 #include "trace.h"
 
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <asm/ioctls.h>
+#include <asm/termbits.h>
 #include <assert.h>
 #include <stdio.h>
-
-#if defined(MSC) || defined(BCC)
-  #include <windows.h> // for Sleep()
-#else
-//  #error Not compiling for MSC or BCC?
-#endif
-
-
-extern void target_recv_push(char *buf, int size);
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 
 /******************************************************************************
- * OS Independent
- ******************************************************************************/
-
-static void serial_listener(void);
-
-#if (OS == WIN32)
-
-/******************************************************************************
- * Win32 Driver
+ * Linux Driver
  ******************************************************************************/
 
-#include <windows.h>
+static int target_fd;
+static struct termios2 target_termios;
+
+static const char port_name_prefix[] = "/dev/ttyUSB";
+
+static void fill_termios(int bps)
+{
+	int termios_baud_code;
 
-static HANDLE     hCom;
-static HANDLE     thread_handle = NULL;
-static DWORD      thread_id;
-static OVERLAPPED read_overlapped;
-static OVERLAPPED write_overlapped;
-static DCB        dcb;
-
-const char PORT_NAME_PRE[] = "COM";
-// A special syntax is required when accessing com ports greater than 9, e.g., "\\.\COM10"
-const char PORT_NAME_PREFIX[] = "\\\\.\\COM";
+	switch (bps) {
+	case 9600:
+		termios_baud_code = B9600;
+		break;
+	case 19200:
+		termios_baud_code = B19200;
+		break;
+	case 38400:
+		termios_baud_code = B38400;
+		break;
+	case 57600:
+		termios_baud_code = B57600;
+		break;
+	case 115200:
+		termios_baud_code = B115200;
+		break;
+	case 230400:
+		termios_baud_code = B230400;
+		break;
+	case 460800:
+		termios_baud_code = B460800;
+		break;
+	case 921600:
+		termios_baud_code = B921600;
+		break;
+	default:
+		termios_baud_code = BOTHER;
+	}
+	target_termios.c_iflag = IGNBRK;
+	target_termios.c_oflag = 0;
+	target_termios.c_cflag = termios_baud_code | CLOCAL|HUPCL|CREAD|CS8;
+	target_termios.c_lflag = 0;
+	target_termios.c_cc[VMIN] = 1;
+	target_termios.c_cc[VTIME] = 0;
+	target_termios.c_ispeed = bps;
+	target_termios.c_ospeed = bps;
+}
 
 int serial_init(int uart, int bps, char *flowcontrol)
 {
-    int error;
-    COMMTIMEOUTS timeouts;
-    char pc_comport[32];
-
-    sprintf(pc_comport, "%s%d", PORT_NAME_PREFIX, uart);
-
-    hCom = CreateFile(pc_comport,
-                      GENERIC_READ | GENERIC_WRITE,
-                      0,    // comm devices must be opened w/exclusive-access
-                      NULL, // no security attributes
-                      OPEN_EXISTING, // comm devices must use OPEN_EXISTING
-                      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
-                      NULL  // hTemplate must be NULL for comm devices
-        );
-    if (hCom == INVALID_HANDLE_VALUE)
-        return E_OS + E_UART_INIT;
-
-    // We will build on the current configuration, and skip setting the size
-    // of the input and output buffers with SetupComm.
-    if (!GetCommState(hCom, &dcb))
-        return E_OS + E_UART_INIT;
-
-    dcb.fAbortOnError = FALSE; // Hmm? (Dont't remember exactly what this is)
-    dcb.ByteSize = 8;          // Data size, xmit, and rcv
-    dcb.Parity = NOPARITY;     // No parity bit
-    dcb.StopBits = ONESTOPBIT; // One stop bit
-    dcb.fOutxCtsFlow = 0;      // Disable CTS HW handshaking!
-    dcb.fOutxDsrFlow = 0;      // Disable DSR HW handshaking!
-    dcb.fDsrSensitivity = 0;   // Disable DSR HW handshaking!
-
-    // Note the DTR = +12V and RTS = -12V is needed to power the serial
-    // level converter!
+	char ttyport[32];
+	static int zero = 0;
 
-    switch (flowcontrol[0]) {
-    case 'n': dcb.fDtrControl = DTR_CONTROL_DISABLE; break;
-    case 'h': dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; break;
-    case 'p':
-    default:
-        dcb.fDtrControl = DTR_CONTROL_ENABLE; break;
-    }
-    switch (flowcontrol[1]) {
-    case 'p': dcb.fRtsControl = RTS_CONTROL_ENABLE; break;
-    case 'h': dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; break;
-    case 'n':
-    default:
-        dcb.fRtsControl = RTS_CONTROL_DISABLE; break;
-    }
-
-    if (!SetCommState(hCom, &dcb))
-        return E_OS + E_UART_INIT;
-
-    if ((error = serial_baudrate_set(bps)) < 0)
-        return error;
+	sprintf(ttyport, "%s%d", port_name_prefix, uart);
+	target_fd = open(ttyport, O_RDWR|O_NONBLOCK);
+	if (target_fd < 0)
+		return E_OS + E_UART_INIT;
+	ioctl(target_fd, TIOCEXCL);
+	fill_termios(bps);
+	if (ioctl(target_fd, TCSETSF2, &target_termios) < 0)
+		return E_OS + E_UART_INIT;
+	ioctl(target_fd, FIONBIO, &zero);
 
-    timeouts.ReadIntervalTimeout = 0;
-    timeouts.ReadTotalTimeoutMultiplier = 0;
-    timeouts.ReadTotalTimeoutConstant = 0;
-    timeouts.WriteTotalTimeoutMultiplier = 0;
-    timeouts.WriteTotalTimeoutConstant = 0;
-
-    assert(SetCommTimeouts (hCom, &timeouts));
-    assert(SetCommMask (hCom, EV_RXCHAR));
-    //assert(SetupComm (hCom, INPUT_BUFFER_SIZE, OUTPUT_BUFFER_SIZE));
-
-    sprintf(pc_comport, "read%s%d", PORT_NAME_PRE, uart);
-    read_overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, pc_comport);
+	if (arg_uart_level_convert) {
+		/*
+		 * Powering TI's serial level converter
+		 * with DTR = +12V and RTS = -12V
+		 */
+		serial_dtr(1);
+		serial_rts(0);
+	}
 
-    sprintf(pc_comport, "write%s%d", PORT_NAME_PRE, uart);
-    write_overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, pc_comport);
-
-    thread_handle =
-        CreateThread (NULL,
-                      0,
-                      (LPTHREAD_START_ROUTINE) serial_listener,
-                      NULL,
-                      0,
-                      &thread_id);
-
-    if (thread_handle == NULL)
-        return E_OS + E_UART_INIT;
-
-    serial_reset();
-
-    return 0;
+	serial_reset();
+	return 0;
 }
 
 int serial_is_baudrate(int bps)
@@ -173,23 +148,12 @@
 
 int serial_baudrate_set(int bps)
 {
-#if 0
-    if (!GetCommState(hCom, &dcb))
-        return E_OS + E_UART_PARAM;
-#endif
-
     bps = serial_is_baudrate(bps);
     if (bps == 0)
         return E_OS + E_UART_PARAM;
 
-    /* Replace 812K with 827K. Otherwise, the chip will automatically select 800K. */ 
-    /* 800K is OK, but we might as well gain the extra 3% speed :-) */
-    if (bps == 812500)
-        dcb.BaudRate = 827586;
-    else
-        dcb.BaudRate = bps;
-
-    if (!SetCommState(hCom, &dcb))
+    fill_termios(bps);
+    if (ioctl(target_fd, TCSETSF2, &target_termios) < 0)
         return E_OS + E_UART_PARAM;
 
     return bps;
@@ -197,27 +161,19 @@
 
 int serial_baudrate_get(void)
 {
-    return dcb.BaudRate;
+    return target_termios.c_ospeed;
 }
 
 void serial_exit(void)
 {
-    DWORD exit_code;
-
     serial_reset();
-
-    (void) GetExitCodeThread (thread_handle, &exit_code);
-    (void) TerminateThread (thread_handle, exit_code);
-
-    (void) CloseHandle (hCom);
-    (void) CloseHandle (read_overlapped.hEvent);
-    (void) CloseHandle (write_overlapped.hEvent);
+    close(target_fd);
 }
 
 // Clear buffers and transactions.
 void serial_reset(void)
 {
-    PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
+	ioctl(target_fd, TCFLSH, TCIOFLUSH);
 }
 
 // Return the number of milli-seconds it takes to transfer <n> bytes.
@@ -233,19 +189,12 @@
 
 int serial_send(char *buf, int size)
 {
-    DWORD written;
-
-    ResetEvent(write_overlapped.hEvent); // why?
+	int cc;
 
-    if (!WriteFile(hCom, buf, size, &written, &write_overlapped)) {
-        if (GetLastError() == ERROR_IO_PENDING) {
-            if (GetOverlappedResult(hCom, &write_overlapped,
-                                    &written, TRUE) == FALSE)
-                written = E_OS + E_UART_DRV_SEND;
-        }
-    }
-
-    return written;
+	cc = write(target_fd, buf, size);
+	if (cc < 0)
+		cc = E_OS + E_UART_DRV_SEND;
+	return cc;
 }
 
 
@@ -255,43 +204,12 @@
 
 void serial_recv_reset(void)
 {
-    PurgeComm(hCom, PURGE_RXABORT|PURGE_RXCLEAR);
+	ioctl(target_fd, TCFLSH, TCIFLUSH);
 }
 
-static void serial_listener(void)
+int serial_recv(char *buf, int size, int timeout)
 {
-    DWORD event_mask;
-    char buf[64];
-    DWORD size;
-
-    while (1)
-    {
-        // Wait the event signalling characters received.
-        if (WaitCommEvent (hCom, &event_mask, NULL) != TRUE) {
-            main_msg("WaitCommEvent(): error %d\n", GetLastError());
-            return;
-        }
-        tr(TrTargetDrv, "|");
-
-        // Read all characters received in the buffer.  Mysteriously, it
-        // does NOT work with a buffer size greater than one!
-        do {
-            if (!ReadFile(hCom, buf, 1, &size, &read_overlapped))
-            {
-                if (GetLastError() == ERROR_IO_PENDING) {
-                    GetOverlappedResult(hCom, &read_overlapped, &size, TRUE);
-                }
-                else {
-                    main_msg("ReadFile(): error %d\n", GetLastError());
-                    serial_recv_reset();
-                    break;
-                }
-            }
-            // Push the data to upper layer
-            target_recv_push(buf, size);
-
-        } while (size);
-    }
+	/* to be filled */
 }
 
 
@@ -301,34 +219,28 @@
 
 void serial_rts(char state)
 {
+    int rts_arg = TIOCM_RTS;
+
     if (state)
-        EscapeCommFunction(hCom, SETRTS);
+        ioctl(target_fd, TIOCMBIS, &rts_arg);
     else
-        EscapeCommFunction(hCom, CLRRTS);
+        ioctl(target_fd, TIOCMBIC, &rts_arg);
 }
 
 void serial_dtr(char state)
 {
+    int dtr_arg = TIOCM_DTR;
+
     if (state)
-        EscapeCommFunction(hCom, SETDTR);
+        ioctl(target_fd, TIOCMBIS, &dtr_arg);
     else
-        EscapeCommFunction(hCom, CLRDTR);
+        ioctl(target_fd, TIOCMBIC, &dtr_arg);
 }
 
 void serial_break(char state)
 {
     if (state)
-        SetCommBreak(hCom);
+        ioctl(target_fd, TIOCSBRK);
     else
-        ClearCommBreak(hCom);
+        ioctl(target_fd, TIOCCBRK);
 }
-
-#else // (OS == WIN32)
-
-
-/******************************************************************************
- * Unix driver
- ******************************************************************************/
-
-
-#endif // (OS == WIN32)
--- a/fluid-mnf/serial.h	Fri Mar 13 02:51:54 2020 +0000
+++ b/fluid-mnf/serial.h	Fri Mar 13 05:39:37 2020 +0000
@@ -8,6 +8,9 @@
  *
  * $Id: serial.h 1.8 Wed, 04 Sep 2002 16:32:18 +0200 mmj $
  *
+ * This serial interface handling architecture has been majorly redesigned
+ * by Mychaela N. Falconia for the present fluid-mnf Linux port.
+ *
  ******************************************************************************/
 
 int serial_init(int uart, int baudrate, char *flowcontrol);
@@ -20,8 +23,7 @@
 int serial_transfer_time(int size);
 
 int serial_send(char *buf, int size);
-int serial_putchar(unsigned char ch);
-int serial_recv(char *buf, int size);
+int serial_recv(char *buf, int size, int timeout);
 void serial_recv_reset(void);
 
 void serial_rts(char state);