-
Notifications
You must be signed in to change notification settings - Fork 1
/
serio.c
112 lines (106 loc) · 3.5 KB
/
serio.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include "serio.h"
#include <unistd.h>
#include <fcntl.h>
#include "base64.h"
#include "crc16.h"
#include "packet.h"
#include <string.h>
int bidx;
int serio_init(connection_t *ctx, const char *serdev){
int opts;
bidx=0;
ctx->device=serdev;
ctx->fd=open(ctx->device, O_RDWR | O_NOCTTY | O_NDELAY);
printf("opened\n");
if(ctx->fd == -1 || !isatty(ctx->fd) || tcgetattr(ctx->fd, &(ctx->spconfig)) < 0) {
printf( "failed to open port %s \n",ctx->device);
close(ctx->fd);
return -1;
}
// 8N1
(ctx->spconfig).c_cflag &= ~PARENB;
(ctx->spconfig).c_cflag &= ~CSTOPB;
(ctx->spconfig).c_cflag &= ~CSIZE;
(ctx->spconfig).c_cflag |= CS8;
// no flow control
(ctx->spconfig).c_cflag &= ~CRTSCTS;
(ctx->spconfig).c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
(ctx->spconfig).c_iflag &= ~(IXON | IXOFF | IXANY); // turn off s/w flow ctrl
cfmakeraw(&(ctx->spconfig)); // make raw
// see: http://unixwiz.net/techtips/termios-vmin-vtime.html
(ctx->spconfig).c_cc[VMIN] = 1;
(ctx->spconfig).c_cc[VTIME] = 0;
cfsetispeed(&(ctx->spconfig), B57600);
cfsetospeed(&(ctx->spconfig), B57600);
tcsetattr(ctx->fd,TCSANOW,&(ctx->spconfig));
opts = fcntl(ctx->fd,F_GETFL);
if (opts < 0) {
perror("fcntl(F_GETFL)");
return -1;
}
opts = (opts & ~(O_NDELAY));
if (fcntl(ctx->fd,F_SETFL,opts) < 0) {
perror("fcntl(F_SETFL)");
return -1;
}
printf("serial port opened\n");
tcflush(ctx->fd,TCIOFLUSH);
return 0;
}
void serio_close(connection_t *ctx){
close(ctx->fd);
}
ssize_t serio_send(connection_t *ctx, void *data, size_t len){
int rv;
char datap[2+B64_ENC_LEN(len)];
if(ctx->fd==-1 || len==0 || data==NULL){
return -3;
}
//Add 2 bytes overhead, encode and send
datap[0] = SFRAME;
rv = base64_encode(datap+1,data,len);
if(B64_ENC_LEN(len) != rv){
return -2;
}
datap[1+B64_ENC_LEN(len)] = EFRAME;
return write(ctx->fd,datap,2+B64_ENC_LEN(len));
}
ssize_t serio_recv(connection_t *ctx, char *buf)
{
static char ba[RECVBUF];
char *next;
do {
if(bidx == RECVBUF-1){
bidx=0;
printf("Input buffer overflow!\n");
memset(ba,0x00,RECVBUF);
}
int n = read(ctx->fd, ba+bidx, RECVBUF-(bidx+1)); // read as much as possible
if( n==-1) return -1; // couldn't read
if( n==0 ) {
usleep( 5 * 1000 ); // wait 5 msec try again
continue;
}
#ifdef DEBUG
printf("read(): %i, bidx: %i\n",n, bidx);
#endif
bidx += n;
ba[bidx]=0x00;
} while(strchr(ba,'\n') == NULL);
buf[0]=0x00;
next = strchr(ba,'\n');
next[0] = 0x00;
next++;
//Heartbeat or data?
#ifdef DEBUG
printf("%x\n",ba[0]);
#endif
if(ba[0] != '$'){
strcpy(buf,ba);
}
//Move rest including null to front
memmove(ba,next,strlen(next)+1);
//update length
bidx = strlen(ba);
return strlen(buf);
}