mirror of
https://github.com/adrcs/ip400.git
synced 2025-07-17 09:05:45 +03:00
added utils
This commit is contained in:
parent
a9a3f739b4
commit
a9b13d2c39
85 changed files with 9213 additions and 0 deletions
448
rpi/stm32flash/serial_posix.c
Normal file
448
rpi/stm32flash/serial_posix.c
Normal file
|
@ -0,0 +1,448 @@
|
|||
/*
|
||||
stm32flash - Open Source ST STM32 flash program for *nix
|
||||
Copyright (C) 2010 Geoffrey McRae <geoff@spacevs.com>
|
||||
|
||||
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 <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/file.h>
|
||||
|
||||
/* To detect BSD for baud rate encoding */
|
||||
#if defined(__unix__) || defined(__UNIX__) || (defined(__APPLE__) && defined(__MACH__))
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "serial.h"
|
||||
#include "port.h"
|
||||
|
||||
#ifndef TERMIOS_TIMEOUT_MS
|
||||
#define TERMIOS_TIMEOUT_MS 500
|
||||
#endif
|
||||
|
||||
#define TERMIOS_TIMEOUT ((TERMIOS_TIMEOUT_MS)/100)
|
||||
|
||||
struct serial {
|
||||
int fd;
|
||||
struct termios oldtio;
|
||||
struct termios newtio;
|
||||
char setup_str[11];
|
||||
};
|
||||
|
||||
static serial_t *serial_open(const char *device)
|
||||
{
|
||||
serial_t *h = calloc(sizeof(serial_t), 1);
|
||||
|
||||
h->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (h->fd < 0) {
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(lockf(h->fd,F_TLOCK,0) != 0)
|
||||
{
|
||||
fprintf(stderr, "Error: %s is already open\n", device);
|
||||
free(h);
|
||||
return NULL;
|
||||
}
|
||||
fcntl(h->fd, F_SETFL, 0);
|
||||
|
||||
tcgetattr(h->fd, &h->oldtio);
|
||||
tcgetattr(h->fd, &h->newtio);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void serial_flush(const serial_t *h)
|
||||
{
|
||||
tcflush(h->fd, TCIFLUSH);
|
||||
}
|
||||
|
||||
static void serial_close(serial_t *h)
|
||||
{
|
||||
serial_flush(h);
|
||||
tcsetattr(h->fd, TCSANOW, &h->oldtio);
|
||||
lockf(h->fd, F_ULOCK, 0);
|
||||
close(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)
|
||||
{
|
||||
speed_t port_baud;
|
||||
tcflag_t port_bits;
|
||||
tcflag_t port_parity;
|
||||
tcflag_t port_stop;
|
||||
struct termios settings;
|
||||
|
||||
switch (baud) {
|
||||
case SERIAL_BAUD_1200: port_baud = B1200; break;
|
||||
case SERIAL_BAUD_1800: port_baud = B1800; break;
|
||||
case SERIAL_BAUD_2400: port_baud = B2400; break;
|
||||
case SERIAL_BAUD_4800: port_baud = B4800; break;
|
||||
case SERIAL_BAUD_9600: port_baud = B9600; break;
|
||||
case SERIAL_BAUD_19200: port_baud = B19200; break;
|
||||
case SERIAL_BAUD_38400: port_baud = B38400; break;
|
||||
case SERIAL_BAUD_57600: port_baud = B57600; break;
|
||||
case SERIAL_BAUD_115200: port_baud = B115200; break;
|
||||
case SERIAL_BAUD_230400: port_baud = B230400; break;
|
||||
#ifdef BSD
|
||||
case SERIAL_BAUD_460800: port_baud = 460800; break;
|
||||
case SERIAL_BAUD_500000: port_baud = 500000; break;
|
||||
case SERIAL_BAUD_576000: port_baud = 576000; break;
|
||||
case SERIAL_BAUD_921600: port_baud = 921600; break;
|
||||
case SERIAL_BAUD_1000000: port_baud = 1000000; break;
|
||||
case SERIAL_BAUD_1152000: port_baud = 1152000; break;
|
||||
case SERIAL_BAUD_1500000: port_baud = 1500000; break;
|
||||
case SERIAL_BAUD_2000000: port_baud = 2000000; break;
|
||||
case SERIAL_BAUD_2500000: port_baud = 2500000; break;
|
||||
case SERIAL_BAUD_3000000: port_baud = 3000000; break;
|
||||
case SERIAL_BAUD_3500000: port_baud = 3500000; break;
|
||||
case SERIAL_BAUD_4000000: port_baud = 4000000; break;
|
||||
#else
|
||||
#ifdef B460800
|
||||
case SERIAL_BAUD_460800: port_baud = B460800; break;
|
||||
#endif /* B460800 */
|
||||
#ifdef B921600
|
||||
case SERIAL_BAUD_921600: port_baud = B921600; break;
|
||||
#endif /* B921600 */
|
||||
#ifdef B500000
|
||||
case SERIAL_BAUD_500000: port_baud = B500000; break;
|
||||
#endif /* B500000 */
|
||||
#ifdef B576000
|
||||
case SERIAL_BAUD_576000: port_baud = B576000; break;
|
||||
#endif /* B576000 */
|
||||
#ifdef B1000000
|
||||
case SERIAL_BAUD_1000000: port_baud = B1000000; break;
|
||||
#endif /* B1000000 */
|
||||
#ifdef B1152000
|
||||
case SERIAL_BAUD_1152000: port_baud = B1152000; break;
|
||||
#endif /* B1152000 */
|
||||
#ifdef B1500000
|
||||
case SERIAL_BAUD_1500000: port_baud = B1500000; break;
|
||||
#endif /* B1500000 */
|
||||
#ifdef B2000000
|
||||
case SERIAL_BAUD_2000000: port_baud = B2000000; break;
|
||||
#endif /* B2000000 */
|
||||
#ifdef B2500000
|
||||
case SERIAL_BAUD_2500000: port_baud = B2500000; break;
|
||||
#endif /* B2500000 */
|
||||
#ifdef B3000000
|
||||
case SERIAL_BAUD_3000000: port_baud = B3000000; break;
|
||||
#endif /* B3000000 */
|
||||
#ifdef B3500000
|
||||
case SERIAL_BAUD_3500000: port_baud = B3500000; break;
|
||||
#endif /* B3500000 */
|
||||
#ifdef B4000000
|
||||
case SERIAL_BAUD_4000000: port_baud = B4000000; break;
|
||||
#endif /* B4000000 */
|
||||
#endif /* BSD */
|
||||
|
||||
case SERIAL_BAUD_INVALID:
|
||||
default:
|
||||
return PORT_ERR_BAUD;
|
||||
}
|
||||
|
||||
switch (bits) {
|
||||
case SERIAL_BITS_5: port_bits = CS5; break;
|
||||
case SERIAL_BITS_6: port_bits = CS6; break;
|
||||
case SERIAL_BITS_7: port_bits = CS7; break;
|
||||
case SERIAL_BITS_8: port_bits = CS8; break;
|
||||
|
||||
default:
|
||||
return PORT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
switch (parity) {
|
||||
case SERIAL_PARITY_NONE: port_parity = 0; break;
|
||||
case SERIAL_PARITY_EVEN: port_parity = PARENB; break;
|
||||
case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break;
|
||||
|
||||
default:
|
||||
return PORT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
switch (stopbit) {
|
||||
case SERIAL_STOPBIT_1: port_stop = 0; break;
|
||||
case SERIAL_STOPBIT_2: port_stop = CSTOPB; break;
|
||||
|
||||
default:
|
||||
return PORT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* reset the settings */
|
||||
#ifndef __sun /* Used by GNU and BSD. Ignore __SVR4 in test. */
|
||||
cfmakeraw(&h->newtio);
|
||||
#else /* __sun */
|
||||
h->newtio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR
|
||||
| IGNCR | ICRNL | IXON);
|
||||
h->newtio.c_oflag &= ~OPOST;
|
||||
h->newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
|
||||
h->newtio.c_cflag &= ~(CSIZE | PARENB);
|
||||
h->newtio.c_cflag |= CS8;
|
||||
#endif /* __sun */
|
||||
#ifdef __QNXNTO__
|
||||
h->newtio.c_cflag &= ~(CSIZE | IHFLOW | OHFLOW);
|
||||
#else
|
||||
h->newtio.c_cflag &= ~(CSIZE | CRTSCTS);
|
||||
#endif
|
||||
h->newtio.c_cflag &= ~(CSIZE | CRTSCTS);
|
||||
h->newtio.c_cflag &= ~(PARENB | PARODD);
|
||||
h->newtio.c_cflag &= ~CSTOPB;
|
||||
h->newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR);
|
||||
h->newtio.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE);
|
||||
h->newtio.c_oflag &= ~(OPOST | ONLCR);
|
||||
|
||||
/* setup the new settings */
|
||||
if (cfsetispeed(&h->newtio, port_baud) ||
|
||||
cfsetospeed(&h->newtio, port_baud)) {
|
||||
fprintf(stderr, "Failed to specify baud rate\n");
|
||||
return PORT_ERR_BAUD;
|
||||
}
|
||||
|
||||
h->newtio.c_cflag |=
|
||||
port_parity |
|
||||
port_bits |
|
||||
port_stop |
|
||||
CLOCAL |
|
||||
CREAD;
|
||||
if ( port_parity != 0 )
|
||||
h->newtio.c_iflag |= INPCK;
|
||||
|
||||
h->newtio.c_cc[VMIN] = 0;
|
||||
h->newtio.c_cc[VTIME] = TERMIOS_TIMEOUT; /* in units of 0.1 s */
|
||||
|
||||
/* set the settings */
|
||||
serial_flush(h);
|
||||
if (tcsetattr(h->fd, TCSANOW, &h->newtio) != 0) {
|
||||
fprintf(stderr, "Error: Failed to apply settings\n");
|
||||
return PORT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* confirm they were set */
|
||||
tcgetattr(h->fd, &settings);
|
||||
|
||||
if (cfgetispeed(&settings) != port_baud ||
|
||||
cfgetospeed(&settings) != port_baud) {
|
||||
fprintf(stderr, "Failed to set baud rate\n");
|
||||
return PORT_ERR_BAUD;
|
||||
}
|
||||
|
||||
if (settings.c_iflag != h->newtio.c_iflag ||
|
||||
settings.c_oflag != h->newtio.c_oflag ||
|
||||
settings.c_cflag != h->newtio.c_cflag ||
|
||||
settings.c_lflag != h->newtio.c_lflag) {
|
||||
fprintf(stderr, "Failed to set terminal flags\n");
|
||||
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_posix_open(struct port_interface *port,
|
||||
struct port_options *ops)
|
||||
{
|
||||
serial_t *h;
|
||||
port_err_t ret;
|
||||
|
||||
/* user takes care of all port setup */
|
||||
if (ops->baudRate == SERIAL_BAUD_KEEP) {
|
||||
h = serial_open(ops->device);
|
||||
if (h == NULL)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
port->private = h;
|
||||
return PORT_ERR_OK;
|
||||
}
|
||||
|
||||
/* 1. 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;
|
||||
|
||||
/* 2. open it */
|
||||
h = serial_open(ops->device);
|
||||
if (h == NULL)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
/* 3. check for tty (but only warn) */
|
||||
if (!isatty(h->fd))
|
||||
fprintf(stderr, "Warning: Not a tty: %s\n", ops->device);
|
||||
|
||||
/* 4. set options */
|
||||
ret = serial_setup(h, ops->baudRate,
|
||||
serial_get_bits(ops->serial_mode),
|
||||
serial_get_parity(ops->serial_mode),
|
||||
serial_get_stopbit(ops->serial_mode));
|
||||
if (ret != PORT_ERR_OK) {
|
||||
serial_close(h);
|
||||
return ret;
|
||||
}
|
||||
|
||||
port->private = h;
|
||||
return PORT_ERR_OK;
|
||||
}
|
||||
|
||||
static port_err_t serial_posix_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_posix_read(struct port_interface *port, void *buf,
|
||||
size_t nbyte)
|
||||
{
|
||||
serial_t *h;
|
||||
ssize_t r;
|
||||
uint8_t *pos = (uint8_t *)buf;
|
||||
|
||||
h = (serial_t *)port->private;
|
||||
if (h == NULL)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
while (nbyte) {
|
||||
r = read(h->fd, pos, nbyte);
|
||||
if (r == 0)
|
||||
return PORT_ERR_TIMEDOUT;
|
||||
if (r < 0)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
nbyte -= r;
|
||||
pos += r;
|
||||
}
|
||||
return PORT_ERR_OK;
|
||||
}
|
||||
|
||||
static port_err_t serial_posix_write(struct port_interface *port, void *buf,
|
||||
size_t nbyte)
|
||||
{
|
||||
serial_t *h;
|
||||
ssize_t r;
|
||||
const uint8_t *pos = (const uint8_t *)buf;
|
||||
|
||||
h = (serial_t *)port->private;
|
||||
if (h == NULL)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
while (nbyte) {
|
||||
r = write(h->fd, pos, nbyte);
|
||||
if (r < 1)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
nbyte -= r;
|
||||
pos += r;
|
||||
}
|
||||
return PORT_ERR_OK;
|
||||
}
|
||||
|
||||
static port_err_t serial_posix_gpio(struct port_interface *port,
|
||||
serial_gpio_t n, int level)
|
||||
{
|
||||
serial_t *h;
|
||||
int bit, lines;
|
||||
|
||||
h = (serial_t *)port->private;
|
||||
if (h == NULL)
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
switch (n) {
|
||||
case GPIO_RTS:
|
||||
bit = TIOCM_RTS;
|
||||
break;
|
||||
|
||||
case GPIO_DTR:
|
||||
bit = TIOCM_DTR;
|
||||
break;
|
||||
|
||||
case GPIO_BRK:
|
||||
if (level == 0)
|
||||
return PORT_ERR_OK;
|
||||
if (tcsendbreak(h->fd, 1))
|
||||
return PORT_ERR_UNKNOWN;
|
||||
return PORT_ERR_OK;
|
||||
|
||||
default:
|
||||
return PORT_ERR_UNKNOWN;
|
||||
}
|
||||
|
||||
/* handle RTS/DTR */
|
||||
if (ioctl(h->fd, TIOCMGET, &lines))
|
||||
return PORT_ERR_UNKNOWN;
|
||||
lines = level ? lines | bit : lines & ~bit;
|
||||
if (ioctl(h->fd, TIOCMSET, &lines))
|
||||
return PORT_ERR_UNKNOWN;
|
||||
|
||||
return PORT_ERR_OK;
|
||||
}
|
||||
|
||||
static const char *serial_posix_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_posix_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_posix",
|
||||
.flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY,
|
||||
.open = serial_posix_open,
|
||||
.close = serial_posix_close,
|
||||
.flush = serial_posix_flush,
|
||||
.read = serial_posix_read,
|
||||
.write = serial_posix_write,
|
||||
.gpio = serial_posix_gpio,
|
||||
.get_cfg_str = serial_posix_get_cfg_str,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue