FreeCalypso > hg > freecalypso-reveng
view fluid-mnf/serial.c @ 320:20feaf83c661
frbl/reconst/convert.c: better match to original object
still not perfect though
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Thu, 05 Mar 2020 05:01:14 +0000 |
parents | 9cecc930d78f |
children | 6ff231195905 |
line wrap: on
line source
/****************************************************************************** * 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)