FreeCalypso > hg > freecalypso-reveng
diff fluid-mnf/serial.c @ 311:9cecc930d78f
fluid-mnf: original source from TI,
defenestrated line endings and rearranged directory structure,
but no *.[ch] source file content changes yet
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sat, 29 Feb 2020 05:36:07 +0000 |
parents | |
children | 6ff231195905 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fluid-mnf/serial.c Sat Feb 29 05:36:07 2020 +0000 @@ -0,0 +1,334 @@ +/****************************************************************************** + * FLUID (Flash Loader Utility Independent of Device) + * + * Copyright Texas Instruments, 2001. + * Mads Meisner-Jensen, mmj@ti.com. + * + * Serial/UART driver + * + * $Id: serial.c 1.23 Fri, 18 Oct 2002 08:53:12 +0200 mmj $ + * + ******************************************************************************/ + +#include "fluid.h" +#include "serial.h" +#include "trace.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); + + +/****************************************************************************** + * OS Independent + ******************************************************************************/ + +static void serial_listener(void); + +#if (OS == WIN32) + +/****************************************************************************** + * Win32 Driver + ******************************************************************************/ + +#include <windows.h> + +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"; + +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! + + 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; + + 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); + + 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; +} + +int serial_is_baudrate(int bps) +{ + int i; + const struct rate_s { + int bps; + int baudrate; + } rates[] = { + { 9600, 9600 }, { 9, 9600 }, + { 14400, 14400 }, { 14, 14400 }, + { 19200, 19200 }, { 19, 19200 }, + { 38400, 38400 }, { 38, 38400 }, + { 57600, 57600 }, { 57, 57600 }, + { 115200, 115200 }, { 115, 115200 }, + { 203125, 203125 }, { 203, 203125 }, // 13MHz clock + { 230400, 230400 }, { 230, 230400 }, + { 406250, 406250 }, { 406, 406250 }, // 13MHz clock + { 460800, 460800 }, { 460, 460800 }, + { 812500, 812500 }, { 812, 812500 }, // 13MHz clock + { 921600, 921600 }, { 921, 921600 }, + { 0, 0 } // terminator + }; + + for (i = 0; i < sizeof(rates) / sizeof(struct rate_s) - 1; i++) + if (rates[i].bps == bps) + break; + + tr(TrTargetDrv, "serial_is_baudrate(%d) %d\n", bps, rates[i].baudrate); + + return rates[i].baudrate; +} + +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)) + return E_OS + E_UART_PARAM; + + return bps; +} + +int serial_baudrate_get(void) +{ + return dcb.BaudRate; +} + +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); +} + +// Clear buffers and transactions. +void serial_reset(void) +{ + PurgeComm(hCom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR); +} + +// Return the number of milli-seconds it takes to transfer <n> bytes. +int serial_transfer_time(int size) +{ + return 1000 * 10 * size / serial_baudrate_get(); +} + + +/*************************************** + * Send + ***************************************/ + +int serial_send(char *buf, int size) +{ + DWORD written; + + ResetEvent(write_overlapped.hEvent); // why? + + 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; +} + + +/*************************************** + * Receive + ***************************************/ + +void serial_recv_reset(void) +{ + PurgeComm(hCom, PURGE_RXABORT|PURGE_RXCLEAR); +} + +static void serial_listener(void) +{ + 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); + } +} + + +/****************************************************************************** + * Control of Delta cable special outputs + ******************************************************************************/ + +void serial_rts(char state) +{ + if (state) + EscapeCommFunction(hCom, SETRTS); + else + EscapeCommFunction(hCom, CLRRTS); +} + +void serial_dtr(char state) +{ + if (state) + EscapeCommFunction(hCom, SETDTR); + else + EscapeCommFunction(hCom, CLRDTR); +} + +void serial_break(char state) +{ + if (state) + SetCommBreak(hCom); + else + ClearCommBreak(hCom); +} + +#else // (OS == WIN32) + + +/****************************************************************************** + * Unix driver + ******************************************************************************/ + + +#endif // (OS == WIN32)