]> git.sesse.net Git - ultimatescore/blob - client/bodet.cpp
Make the roster scripts executable.
[ultimatescore] / client / bodet.cpp
1 // Bodet BT-6000 decoder.
2
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <termios.h>
7 #include <unistd.h>
8
9 #include <string>
10 #include <vector>
11
12 #include <arpa/inet.h>
13 #include <netinet/in.h>
14 #include <netinet/tcp.h>
15 #include <stdlib.h>
16 #include <sys/types.h>
17 #include <sys/socket.h>
18
19 using namespace std;
20
21 int sock;
22 sockaddr_in6 saddr6;
23
24 void process(const string &buf)
25 {
26         unsigned char checksum = 0;
27         for (size_t i = 1; i <= buf.size() - 2; ++i) {
28                 checksum ^= buf[i];
29         }
30         checksum &= 0x7f;
31         if (checksum < 0x20) {
32                 checksum += 0x20;
33         }
34         if (checksum != buf.back()) {
35         //      fprintf(stderr, "discarding message with broken checksum: [%s] [%x vs. %x]\n", buf.c_str(), checksum, buf.back());
36         } else {
37                 string realmsg = buf.substr(3, buf.size() - 5);
38                 sendto(sock, realmsg.data(), realmsg.size(), 0, (sockaddr *)&saddr6, sizeof(saddr6));
39         }
40 }
41
42 int main(int argc, char **argv)
43 {
44         sock = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
45         if (sock == -1) {
46                 perror("socket");
47                 exit(1);
48         }
49
50         int one = 1;
51         if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) == -1) {
52                 perror("setsockopt");
53                 exit(1);
54         }
55
56         memset(&saddr6, 0, sizeof(saddr6));
57         saddr6.sin6_family = AF_INET6;
58         if (argc >= 2) {
59                 if (inet_pton(AF_INET6, argv[1], &saddr6.sin6_addr) != 1) {
60                         fprintf(stderr, "Invalid address '%s'\n", argv[1]);
61                         exit(1);
62                 }
63         } else {
64                 inet_pton(AF_INET6, "::1", &saddr6.sin6_addr);
65         }
66
67         int port = 6000;
68         if (argc >= 3) {
69                 port = atoi(argv[2]);
70         }
71         saddr6.sin6_port = htons(port);
72
73         const char *serialpath = "/dev/ttyUSB0";
74         if (argc >= 4) {
75                 serialpath = argv[3];
76         }
77         int serialfd = open(serialpath, O_RDWR);
78         if (serialfd == -1) {
79                 perror(serialpath);
80                 exit(1);
81         }
82
83         struct termios options;
84         memset(&options, 0, sizeof(options));
85         options.c_cflag = B9600 | CS8 | CLOCAL | CREAD;
86         options.c_iflag = IGNBRK | IGNPAR;
87         options.c_lflag = 0;
88         options.c_cc[VMIN] = 1;  // Blocking read, minimum one byte.
89         tcsetattr(serialfd, TCSANOW, &options);
90
91         string buf;
92
93         for ( ;; ) {
94                 char ch;
95                 int ret = read(serialfd, &ch, 1);
96                 if (ret == -1) {
97                         perror("read");
98                         exit(1);
99                 }
100                 if (ret == 0) {
101                         fprintf(stderr, "short read\n");
102                         exit(1);
103                 }
104
105                 putchar(ch);
106                 fflush(stdout);
107                 if (ch == 1) {  // SOH
108                         buf = ch;
109                         continue;
110                 } 
111                 if (buf.size() == 1) {
112                         // Address
113                         buf.push_back(ch);
114                         continue;
115                 }
116                 if (ch == 2) {  // STX
117                         if (buf.size() == 2) {
118                                 buf.push_back(ch);
119                         } else {
120                                 buf.clear();  // STX out-of-order
121                         }
122                         continue;
123                 }
124
125                 if (!buf.empty() && buf.back() == 3) {  // Last was ETX, so this is LTC.
126                         buf.push_back(ch);
127                         process(buf);
128                         buf.clear();
129                         continue;
130                 }
131
132                 if (ch == 3) {  // ETX
133                         if (buf.size() >= 4) {
134                                 buf.push_back(ch);
135                         } else {
136                                 buf.clear();  // ETX out-of-order
137                         }
138                         continue;
139                 }
140                 buf.push_back(ch);
141         }
142 }