/* stm32flash - Open Source ST STM32 flash program for *nix Copyright (C) 2010 Geoffrey McRae Copyright (C) 2010 Gareth McMullin This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include "compiler.h" #include "serial.h" #include "port.h" struct serial { HANDLE fd; DCB oldtio; DCB newtio; char setup_str[11]; }; static serial_t *serial_open(const char *device) { serial_t *h = calloc(sizeof(serial_t), 1); char *devName; /* timeout in ms */ COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 0}; /* Fix the device name if required */ if (strlen(device) > 4 && device[0] != '\\') { devName = calloc(1, strlen(device) + 5); sprintf(devName, "\\\\.\\%s", device); } else { devName = (char *)device; } /* Create file handle for port */ h->fd = CreateFile(devName, GENERIC_READ | GENERIC_WRITE, 0, /* Exclusive access */ NULL, /* No security */ OPEN_EXISTING, 0, /* No overlap */ NULL); if (devName != device) free(devName); if (h->fd == INVALID_HANDLE_VALUE) { if (GetLastError() == ERROR_FILE_NOT_FOUND) fprintf(stderr, "File not found: %s\n", device); free(h); return NULL; } SetupComm(h->fd, 4096, 4096); /* Set input and output buffer size */ SetCommTimeouts(h->fd, &timeouts); SetCommMask(h->fd, EV_ERR); /* Notify us of error events */ /* DCBlength should be initialized before calling GetCommState */ h->oldtio.DCBlength = sizeof(DCB); h->newtio.DCBlength = sizeof(DCB); GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */ GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */ /* PurgeComm(h->fd, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); */ return h; } static void serial_flush(const serial_t __unused *h) { /* We shouldn't need to flush in non-overlapping (blocking) mode */ /* tcflush(h->fd, TCIFLUSH); */ } static void serial_close(serial_t *h) { serial_flush(h); SetCommState(h->fd, &h->oldtio); CloseHandle(h->fd); free(h); } static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, const serial_bits_t bits, const serial_parity_t parity, const serial_stopbit_t stopbit) { switch (baud) { case SERIAL_BAUD_1200: h->newtio.BaudRate = CBR_1200; break; /* case SERIAL_BAUD_1800: h->newtio.BaudRate = CBR_1800; break; */ case SERIAL_BAUD_2400: h->newtio.BaudRate = CBR_2400; break; case SERIAL_BAUD_4800: h->newtio.BaudRate = CBR_4800; break; case SERIAL_BAUD_9600: h->newtio.BaudRate = CBR_9600; break; case SERIAL_BAUD_19200: h->newtio.BaudRate = CBR_19200; break; case SERIAL_BAUD_38400: h->newtio.BaudRate = CBR_38400; break; case SERIAL_BAUD_57600: h->newtio.BaudRate = CBR_57600; break; case SERIAL_BAUD_115200: h->newtio.BaudRate = CBR_115200; break; case SERIAL_BAUD_128000: h->newtio.BaudRate = CBR_128000; break; case SERIAL_BAUD_256000: h->newtio.BaudRate = CBR_256000; break; /* These are not defined in WinBase.h and might work or not */ case SERIAL_BAUD_230400: h->newtio.BaudRate = 230400; break; case SERIAL_BAUD_460800: h->newtio.BaudRate = 460800; break; case SERIAL_BAUD_500000: h->newtio.BaudRate = 500000; break; case SERIAL_BAUD_576000: h->newtio.BaudRate = 576000; break; case SERIAL_BAUD_921600: h->newtio.BaudRate = 921600; break; case SERIAL_BAUD_1000000: h->newtio.BaudRate = 1000000; break; case SERIAL_BAUD_1500000: h->newtio.BaudRate = 1500000; break; case SERIAL_BAUD_2000000: h->newtio.BaudRate = 2000000; break; case SERIAL_BAUD_INVALID: default: return PORT_ERR_UNKNOWN; } switch (bits) { case SERIAL_BITS_5: h->newtio.ByteSize = 5; break; case SERIAL_BITS_6: h->newtio.ByteSize = 6; break; case SERIAL_BITS_7: h->newtio.ByteSize = 7; break; case SERIAL_BITS_8: h->newtio.ByteSize = 8; break; default: return PORT_ERR_UNKNOWN; } switch (parity) { case SERIAL_PARITY_NONE: h->newtio.Parity = NOPARITY; break; case SERIAL_PARITY_EVEN: h->newtio.Parity = EVENPARITY; break; case SERIAL_PARITY_ODD: h->newtio.Parity = ODDPARITY; break; default: return PORT_ERR_UNKNOWN; } switch (stopbit) { case SERIAL_STOPBIT_1: h->newtio.StopBits = ONESTOPBIT; break; case SERIAL_STOPBIT_2: h->newtio.StopBits = TWOSTOPBITS; break; default: return PORT_ERR_UNKNOWN; } /* reset the settings */ h->newtio.fOutxCtsFlow = FALSE; h->newtio.fOutxDsrFlow = FALSE; h->newtio.fDtrControl = DTR_CONTROL_DISABLE; h->newtio.fDsrSensitivity = FALSE; h->newtio.fTXContinueOnXoff = FALSE; h->newtio.fOutX = FALSE; h->newtio.fInX = FALSE; h->newtio.fErrorChar = FALSE; h->newtio.fNull = FALSE; h->newtio.fRtsControl = RTS_CONTROL_DISABLE; h->newtio.fAbortOnError = FALSE; /* set the settings */ serial_flush(h); if (!SetCommState(h->fd, &h->newtio)) return PORT_ERR_UNKNOWN; snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", serial_get_baud_int(baud), serial_get_bits_int(bits), serial_get_parity_str(parity), serial_get_stopbit_int(stopbit) ); return PORT_ERR_OK; } static port_err_t serial_w32_open(struct port_interface *port, struct port_options *ops) { serial_t *h; /* 1. check device name match */ if (!(!strncmp(ops->device, "COM", 3) && isdigit(ops->device[3])) && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM")) && isdigit(ops->device[strlen("\\\\.\\COM")]))) return PORT_ERR_NODEV; /* 2. check options */ if (ops->baudRate == SERIAL_BAUD_INVALID) return PORT_ERR_UNKNOWN; if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) return PORT_ERR_UNKNOWN; if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) return PORT_ERR_UNKNOWN; if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) return PORT_ERR_UNKNOWN; /* 3. open it */ h = serial_open(ops->device); if (h == NULL) return PORT_ERR_UNKNOWN; /* 4. set options */ if (serial_setup(h, ops->baudRate, serial_get_bits(ops->serial_mode), serial_get_parity(ops->serial_mode), serial_get_stopbit(ops->serial_mode) ) != PORT_ERR_OK) { serial_close(h); return PORT_ERR_UNKNOWN; } port->private = h; return PORT_ERR_OK; } static port_err_t serial_w32_close(struct port_interface *port) { serial_t *h; h = (serial_t *)port->private; if (h == NULL) return PORT_ERR_UNKNOWN; serial_close(h); port->private = NULL; return PORT_ERR_OK; } static port_err_t serial_w32_read(struct port_interface *port, void *buf, size_t nbyte) { serial_t *h; DWORD r; uint8_t *pos = (uint8_t *)buf; h = (serial_t *)port->private; if (h == NULL) return PORT_ERR_UNKNOWN; while (nbyte) { ReadFile(h->fd, pos, nbyte, &r, NULL); if (r == 0) return PORT_ERR_TIMEDOUT; nbyte -= r; pos += r; } return PORT_ERR_OK; } static port_err_t serial_w32_write(struct port_interface *port, void *buf, size_t nbyte) { serial_t *h; DWORD r; uint8_t *pos = (uint8_t *)buf; h = (serial_t *)port->private; if (h == NULL) return PORT_ERR_UNKNOWN; while (nbyte) { if (!WriteFile(h->fd, pos, nbyte, &r, NULL)) return PORT_ERR_UNKNOWN; if (r < 1) return PORT_ERR_UNKNOWN; nbyte -= r; pos += r; } return PORT_ERR_OK; } static port_err_t serial_w32_gpio(struct port_interface *port, serial_gpio_t n, int level) { serial_t *h; int bit; h = (serial_t *)port->private; if (h == NULL) return PORT_ERR_UNKNOWN; switch (n) { case GPIO_RTS: bit = level ? SETRTS : CLRRTS; break; case GPIO_DTR: bit = level ? SETDTR : CLRDTR; break; case GPIO_BRK: if (level == 0) return PORT_ERR_OK; if (EscapeCommFunction(h->fd, SETBREAK) == 0) return PORT_ERR_UNKNOWN; usleep(500000); if (EscapeCommFunction(h->fd, CLRBREAK) == 0) return PORT_ERR_UNKNOWN; return PORT_ERR_OK; default: return PORT_ERR_UNKNOWN; } /* handle RTS/DTR */ if (EscapeCommFunction(h->fd, bit) == 0) return PORT_ERR_UNKNOWN; return PORT_ERR_OK; } static const char *serial_w32_get_cfg_str(struct port_interface *port) { serial_t *h; h = (serial_t *)port->private; return h ? h->setup_str : "INVALID"; } static port_err_t serial_w32_flush(struct port_interface *port) { serial_t *h; h = (serial_t *)port->private; if (h == NULL) return PORT_ERR_UNKNOWN; serial_flush(h); return PORT_ERR_OK; } struct port_interface port_serial = { .name = "serial_w32", .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, .open = serial_w32_open, .close = serial_w32_close, .flush = serial_w32_flush, .read = serial_w32_read, .write = serial_w32_write, .gpio = serial_w32_gpio, .get_cfg_str = serial_w32_get_cfg_str, };