📄 serialsource.c
字号:
#if defined(_WIN32) && !defined(__CYGWIN__)
/* Avoid confusing windows w/o cygwin w/ cygwin */
#define LOSE32
#endif
#ifndef LOSE32
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/time.h>
#include <stdio.h>
#ifdef __CYGWIN__
#include <windows.h>
#include <io.h>
#else
#include <stdint.h>
#endif
#endif
#ifdef LOSE32
#include <windows.h>
#include <stdint.h>
#endif
/* C implementation of the mote serial protocol. See
net.tinyos.packet.Packetizer for more details */
#undef DEBUG
#include "serialsource.h"
#include "serialprotocol.h"
typedef int bool;
enum {
#ifndef __CYGWIN__
#ifndef LOSE32
FALSE = 0,
TRUE = 1,
#endif
#endif
BUFSIZE = 256,
MTU = 256,
ACK_TIMEOUT = 100000, /* in us */
SYNC_BYTE = SERIAL_HDLC_FLAG_BYTE,
ESCAPE_BYTE = SERIAL_HDLC_CTLESC_BYTE,
P_ACK = SERIAL_SERIAL_PROTO_ACK,
P_PACKET_ACK = SERIAL_SERIAL_PROTO_PACKET_ACK,
P_PACKET_NO_ACK = SERIAL_SERIAL_PROTO_PACKET_NOACK,
P_UNKNOWN = SERIAL_SERIAL_PROTO_PACKET_UNKNOWN
};
struct packet_list
{
uint8_t *packet;
int len;
struct packet_list *next;
};
struct serial_source_t {
#ifndef LOSE32
int fd;
#else
HANDLE hComm;
#endif
bool non_blocking;
void (*message)(serial_source_msg problem);
/* Receive state */
struct {
uint8_t buffer[BUFSIZE];
int bufpos, bufused;
uint8_t packet[MTU];
bool in_sync, escaped;
int count;
struct packet_list *queue[256]; // indexed by protocol
} recv;
struct {
uint8_t seqno;
uint8_t *escaped;
int escapeptr;
uint16_t crc;
} send;
};
#ifndef LOSE32
static tcflag_t parse_baudrate(int requested)
{
int baudrate;
switch (requested)
{
#ifdef B50
case 50: baudrate = B50; break;
#endif
#ifdef B75
case 75: baudrate = B75; break;
#endif
#ifdef B110
case 110: baudrate = B110; break;
#endif
#ifdef B134
case 134: baudrate = B134; break;
#endif
#ifdef B150
case 150: baudrate = B150; break;
#endif
#ifdef B200
case 200: baudrate = B200; break;
#endif
#ifdef B300
case 300: baudrate = B300; break;
#endif
#ifdef B600
case 600: baudrate = B600; break;
#endif
#ifdef B1200
case 1200: baudrate = B1200; break;
#endif
#ifdef B1800
case 1800: baudrate = B1800; break;
#endif
#ifdef B2400
case 2400: baudrate = B2400; break;
#endif
#ifdef B4800
case 4800: baudrate = B4800; break;
#endif
#ifdef B9600
case 9600: baudrate = B9600; break;
#endif
#ifdef B19200
case 19200: baudrate = B19200; break;
#endif
#ifdef B38400
case 38400: baudrate = B38400; break;
#endif
#ifdef B57600
case 57600: baudrate = B57600; break;
#endif
#ifdef B115200
case 115200: baudrate = B115200; break;
#endif
#ifdef B230400
case 230400: baudrate = B230400; break;
#endif
#ifdef B460800
case 460800: baudrate = B460800; break;
#endif
#ifdef B500000
case 500000: baudrate = B500000; break;
#endif
#ifdef B576000
case 576000: baudrate = B576000; break;
#endif
#ifdef B921600
case 921600: baudrate = B921600; break;
#endif
#ifdef B1000000
case 1000000: baudrate = B1000000; break;
#endif
#ifdef B1152000
case 1152000: baudrate = B1152000; break;
#endif
#ifdef B1500000
case 1500000: baudrate = B1500000; break;
#endif
#ifdef B2000000
case 2000000: baudrate = B2000000; break;
#endif
#ifdef B2500000
case 2500000: baudrate = B2500000; break;
#endif
#ifdef B3000000
case 3000000: baudrate = B3000000; break;
#endif
#ifdef B3500000
case 3500000: baudrate = B3500000; break;
#endif
#ifdef B4000000
case 4000000: baudrate = B4000000; break;
#endif
default:
baudrate = 0;
}
return baudrate;
}
#endif
#ifdef DEBUG
static void dump(const char *msg, unsigned char *packet, int len)
{
int i;
printf("%s", msg);
for (i = 0; i < len; i++)
printf(" %02x", packet[i]);
putchar('\n');
}
#endif
static void message(serial_source src, serial_source_msg msg)
{
if (src->message)
src->message(msg);
}
static int serial_read(serial_source src, int non_blocking, void *buffer, int n)
{
#ifndef LOSE32
fd_set fds;
int cnt;
if (non_blocking)
{
cnt = read(src->fd, buffer, n);
/* Work around buggy usb serial driver (returns 0 when no data
is available). Mac OS X seems to like to do this too (at
least with a Keyspan 49WG).
*/
if (cnt == 0)
{
cnt = -1;
errno = EAGAIN;
}
return cnt;
}
else
for (;;)
{
FD_ZERO(&fds);
FD_SET(src->fd, &fds);
cnt = select(src->fd + 1, &fds, NULL, NULL, NULL);
if (cnt < 0)
return -1;
cnt = read(src->fd, buffer, n);
if (cnt != 0)
return cnt;
}
#else // LOSE32
int cnt;
if (non_blocking) {
ReadFile(src->hComm, buffer, n, &cnt, NULL);
return cnt;
} else {
for (;;) {
DWORD eventMask;
SetCommMask(src->hComm, EV_RXCHAR);
if (!WaitCommEvent(src->hComm, &eventMask, NULL)) {
return -1;
}
ReadFile(src->hComm, buffer, n, &cnt, NULL);
if (cnt != 0) {
return cnt;
}
}
}
#endif
}
serial_source open_serial_source(const char *device, int baud_rate,
int non_blocking,
void (*message)(serial_source_msg problem))
/* Effects: opens serial port device at specified baud_rate. If non_blocking
is true, read_serial_packet calls will be non-blocking (writes are
always blocking, for now at least)
Returns: descriptor for serial forwarder at host:port, or
NULL for failure (bad device or bad baud rate)
*/
{
#ifndef LOSE32
struct termios newtio;
int fd;
tcflag_t baudflag = parse_baudrate(baud_rate);
if (!baudflag)
return NULL;
fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd < 0)
return NULL;
#ifdef __CYGWIN__
/* For some very mysterious reason, this incantation is necessary to make
the serial port work under some windows machines */
HANDLE handle = (HANDLE)get_osfhandle(fd);
DCB dcb;
if (!(GetCommState(handle, &dcb) && SetCommState(handle, &dcb)))
{
close(fd);
return NULL;
}
#endif
/* Serial port setting */
memset(&newtio, 0, sizeof(newtio));
newtio.c_cflag = CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR | IGNBRK;
cfsetispeed(&newtio, baudflag);
cfsetospeed(&newtio, baudflag);
/* Raw output_file */
newtio.c_oflag = 0;
if (tcflush(fd, TCIFLUSH) >= 0 &&
tcsetattr(fd, TCSANOW, &newtio) >= 0)
{
serial_source src = malloc(sizeof *src);
if (src)
{
memset(src, 0, sizeof *src);
src->fd = fd;
src->non_blocking = non_blocking;
src->message = message;
src->send.seqno = 37;
return src;
}
}
close(fd);
return NULL;
#else // LOSE32
LPCTSTR ComName = (LPCTSTR)device;
HANDLE hComm;
DCB dcb;
serial_source src;
int buflen = MultiByteToWideChar(CP_ACP,0,(PCSTR)device,-1,(LPWSTR)ComName,0);
MultiByteToWideChar(CP_ACP,0,(PCSTR)device,-1,(LPWSTR)ComName,buflen);
//syncronize
hComm = CreateFile(ComName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hComm == INVALID_HANDLE_VALUE) {
return NULL;
}
PurgeComm(hComm, PURGE_RXCLEAR);
GetCommState(hComm, &dcb);
dcb.BaudRate = baud_rate;
dcb.ByteSize = 8;
dcb.Parity = NOPARITY;
dcb.fParity = FALSE;
dcb.StopBits = ONESTOPBIT;
if (SetCommState(hComm, &dcb) == 0) {
return NULL;
}
src = malloc(sizeof *src);
if (src) {
memset(src, 0, sizeof *src);
src->hComm = hComm;
src->non_blocking = non_blocking;
src->message = message;
src->send.seqno = 37;
}
return src;
#endif // LOSE32
}
#ifndef LOSE32
int serial_source_fd(serial_source src)
/* Returns: the file descriptor used by serial source src (useful when
non-blocking reads were requested)
*/
{
return src->fd;
}
#endif
#ifdef LOSE32
HANDLE serial_source_handle(serial_source src)
/* Returns: the file descriptor used by serial source src (useful when
non-blocking reads were requested)
*/
{
return src->hComm;
}
#endif
int close_serial_source(serial_source src)
/* Effects: closes serial source src
Returns: 0 if successful, -1 if some problem occured (but source is
considered closed anyway)
*/
{
#ifndef LOSE32
int ok = close(src->fd);
#else
int ok = CloseHandle(src->hComm);
#endif
free(src);
return ok;
}
static int source_wait(serial_source src, struct timeval *deadline)
/* Effects: waits until deadline for some data on source. deadline
can be NULL for indefinite waiting.
Returns: 0 if data is available, -1 if the deadline expires
*/
{
#ifndef LOSE32
struct timeval tv;
fd_set fds;
int cnt;
if (src->recv.bufpos < src->recv.bufused)
return 0;
for (;;)
{
if (deadline)
{
gettimeofday(&tv, NULL);
tv.tv_sec = deadline->tv_sec - tv.tv_sec;
tv.tv_usec = deadline->tv_usec - tv.tv_usec;
if (tv.tv_usec < 0)
{
tv.tv_usec += 1000000;
tv.tv_sec--;
}
if (tv.tv_sec < 0)
return -1;
}
FD_ZERO(&fds);
FD_SET(src->fd, &fds);
cnt = select(src->fd + 1, &fds, NULL, NULL, deadline ? &tv : NULL);
if (cnt < 0)
{
if (errno == EINTR)
continue;
message(src, msg_unix_error);
return -1;
}
if (cnt == 0)
return -1;
return 0;
}
#else // LOSE32
// FIXME: the deadline is ignored here
DWORD eventMask;
SetCommMask(src->hComm, EV_RXCHAR);
if (!WaitCommEvent(src->hComm, &eventMask, NULL)) {
return -1;
}
return 0;
#endif
}
static int source_write(serial_source src, const void *buffer, int count)
{
#ifndef LOSE32
int actual = 0;
if (fcntl(src->fd, F_SETFL, 0) < 0)
{
message(src, msg_unix_error);
return -1;
}
while (count > 0)
{
int n = write(src->fd, buffer, count);
if (n < 0 && errno == EINTR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -