FreeCalypso > hg > freecalypso-reveng
diff fluid-mnf/serial.c @ 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 | 9cecc930d78f |
children | 917e05f03ad2 |
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)