osmocon: drain the hdlc sercomm queue through select
[osmocom-bb.git] / src / host / osmocon / osmocon.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <stdint.h>
6 #include <fcntl.h>
7 #include <errno.h>
8 #include <termios.h>
9 #include <sys/ioctl.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <sys/stat.h>
13 #include <sys/un.h>
14
15 #include <sercomm.h>
16
17 #include <osmocore/linuxlist.h>
18 #include <osmocore/select.h>
19 #include <osmocore/talloc.h>
20
21 #include <arpa/inet.h>
22
23 //#include "version.h"
24
25 #define MODEM_BAUDRATE  B115200
26 #define MAX_DNLOAD_SIZE 0xFFFF
27 #define MAX_HDR_SIZE    128
28
29 enum dnload_state {
30         WAITING_PROMPT1,
31         WAITING_PROMPT2,
32         DOWNLOADING,
33 };
34
35 enum dnload_mode {
36         MODE_C123,
37         MODE_C123xor,
38         MODE_C155,
39 };
40
41 struct dnload {
42         enum dnload_state state;
43         enum dnload_mode mode;
44         struct bsc_fd serial_fd;
45         char *filename;
46
47         int print_hdlc;
48
49         /* data to be downloaded */
50         uint8_t *data;
51         int data_len;
52
53         uint8_t *write_ptr;
54
55         /* sockaddr in */
56         struct bsc_fd socket;
57 };
58
59 /**
60  * a connection of the layer2
61  */
62 struct layer2_connection {
63         struct llist_head entry;
64         struct bsc_fd fd;
65 };
66
67 static LLIST_HEAD(connections);
68 static struct dnload dnload;
69
70 static const uint8_t phone_prompt1[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x01, 0x40 };
71 static const uint8_t dnload_cmd[]    = { 0x1b, 0xf6, 0x02, 0x00, 0x52, 0x01, 0x53 };
72 static const uint8_t phone_prompt2[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x02, 0x43 };
73 static const uint8_t phone_ack[]     = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x42 };
74 static const uint8_t phone_nack_magic[]= { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x03, 0x57 };
75 static const uint8_t phone_nack[]    = { 0x1b, 0xf6, 0x02, 0x00, 0x45, 0x53, 0x16 };
76 static const uint8_t ftmtool[] = { "ftmtool" };
77
78 /* The C123 has a hard-coded check inside the ramloder that requires the following
79  * bytes to be always the first four bytes of the image */
80 static const uint8_t data_hdr_c123[]    = { 0xee, 0x4c, 0x9f, 0x63 };
81
82 /* The C155 doesn't have some strange restriction on what the first four bytes have
83  * to be, but it starts the ramloader in THUMB mode.  We use the following four bytes
84  * to switch back to ARM mode:
85   800100:       4778            bx      pc
86   800102:       46c0            nop                     ; (mov r8, r8)
87  */
88 static const uint8_t data_hdr_c155[]    = { 0x78, 0x47, 0xc0, 0x46 };
89
90 static const uint8_t dummy_data[]    = { 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde };
91
92 static int serial_init(const char *serial_dev)
93 {
94     struct termios options;
95     int fd, v24;
96
97     fd = open(serial_dev, O_RDWR | O_NOCTTY | O_NDELAY);
98     if (fd < 0)
99         return fd;
100
101     fcntl(fd, F_SETFL, 0);
102
103     /* Configure serial interface */
104     tcgetattr(fd, &options);
105
106     cfsetispeed(&options, MODEM_BAUDRATE);
107     cfsetospeed(&options, MODEM_BAUDRATE);
108
109     /* local read */
110     options.c_cflag &= ~PARENB;
111     options.c_cflag &= ~CSTOPB;
112     options.c_cflag &= ~CSIZE;
113     options.c_cflag |= CS8;
114
115     /* hardware flow control off */
116     options.c_cflag &= ~CRTSCTS;
117
118     /* software flow control off */
119     options.c_iflag &= ~(IXON | IXOFF | IXANY);
120
121     /* we want raw i/o */
122     options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
123     options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
124     options.c_oflag &= ~(ONLCR);
125
126     options.c_cc[VMIN] = 1;
127     options.c_cc[VTIME] = 0;
128     options.c_cc[VINTR] = 0;
129     options.c_cc[VQUIT] = 0;
130     options.c_cc[VSTART] = 0;
131     options.c_cc[VSTOP] = 0;
132     options.c_cc[VSUSP] = 0;
133     
134     tcsetattr(fd, TCSANOW, &options);
135
136     /* set ready to read/write */
137     v24 = TIOCM_DTR | TIOCM_RTS;
138     ioctl(fd, TIOCMBIS, &v24);
139
140     return fd;
141 }
142
143 /* Read the to-be-downloaded file, prepend header and length, append XOR sum */
144 int read_file(const char *filename)
145 {
146         int fd, rc, i;
147         struct stat st;
148         const uint8_t *hdr = NULL;
149         int hdr_len = 0;
150         uint8_t *file_data;
151         uint16_t tot_len;
152         uint8_t nibble;
153         uint8_t running_xor = 0x02;
154
155         fd = open(filename, O_RDONLY);
156         if (fd < 0) {
157                 perror("opening file");
158                 exit(1);
159         }
160
161         rc = fstat(fd, &st);
162         if (st.st_size > MAX_DNLOAD_SIZE) {
163                 fprintf(stderr, "The maximum file size is 64kBytes (%u bytes)\n",
164                         MAX_DNLOAD_SIZE);
165                 return -EFBIG;
166         }
167
168         if (dnload.data) {
169                 free(dnload.data);
170                 dnload.data = NULL;
171         }
172
173         dnload.data = malloc(MAX_HDR_SIZE + st.st_size);
174         if (!dnload.data) {
175                 close(fd);
176                 fprintf(stderr, "No memory\n");
177                 return -ENOMEM;
178         }
179
180         /* copy in the header, if any */
181         switch (dnload.mode) {
182         case MODE_C155:
183                 hdr = data_hdr_c155;
184                 hdr_len = sizeof(data_hdr_c155);
185                 break;
186         case MODE_C123:
187         case MODE_C123xor:
188                 hdr = data_hdr_c123;
189                 hdr_len = sizeof(data_hdr_c123);
190                 break;
191         default:
192                 break;
193         }
194
195         if (hdr && hdr_len)
196                 memcpy(dnload.data, hdr, hdr_len);
197
198         /* 2 bytes for length + header */
199         file_data = dnload.data + 2 + hdr_len;
200
201         /* write the length, keep running XOR */
202         tot_len = hdr_len + st.st_size;
203         nibble = tot_len >> 8;
204         dnload.data[0] = nibble;
205         running_xor ^= nibble;
206         nibble = tot_len & 0xff;
207         dnload.data[1] = nibble;
208         running_xor ^= nibble;
209
210         if (hdr_len && hdr) {
211                 memcpy(dnload.data+2, hdr, hdr_len);
212
213                 for (i = 0; i < hdr_len; i++)
214                         running_xor ^= hdr[i];
215         }
216
217         rc = read(fd, file_data, st.st_size);
218         if (rc < 0) {
219                 perror("error reading file\n");
220                 free(dnload.data);
221                 dnload.data = NULL;
222                 close(fd);
223                 return -EIO;
224         }
225         if (rc < st.st_size) {
226                 free(dnload.data);
227                 dnload.data = NULL;
228                 close(fd);
229                 fprintf(stderr, "Short read of file (%d < %d)\n",
230                         rc, (int)st.st_size);
231                 return -EIO;
232         }
233
234         close(fd);
235
236         dnload.data_len = (file_data+st.st_size) - dnload.data;
237
238         /* calculate XOR sum */
239         for (i = 0; i < st.st_size; i++)
240                 running_xor ^= file_data[i];
241
242         dnload.data[dnload.data_len++] = running_xor;
243
244         /* initialize write pointer to start of data */
245         dnload.write_ptr = dnload.data;
246
247         printf("read_file(%s): file_size=%u, hdr_len=%u, dnload_len=%u\n",
248                 filename, (int)st.st_size, hdr_len, dnload.data_len);
249
250         return 0;
251 }
252
253 static void hexdump(const uint8_t *data, unsigned int len)
254 {
255         const uint8_t *bufptr = data;
256         int n;
257
258         for (n=0; bufptr, n < len; n++, bufptr++)
259                 printf("%02x ", *bufptr);
260         printf("\n");
261 }
262
263 #define WRITE_BLOCK     4096
264
265 static int handle_write_dnload(void)
266 {
267         int bytes_left, write_len, rc;
268
269         printf("handle_write(): ");
270         if (dnload.write_ptr == dnload.data) {
271                 /* no bytes have been transferred yet */
272                 if (dnload.mode == MODE_C155 ||
273                     dnload.mode == MODE_C123xor) {
274                         uint8_t xor_init = 0x02;
275                         write(dnload.serial_fd.fd, &xor_init, 1);
276                 } else
277                         usleep(1);
278         } else if (dnload.write_ptr >= dnload.data + dnload.data_len) { 
279                 printf("finished\n");
280                 dnload.write_ptr = dnload.data;
281                 dnload.serial_fd.when &= ~BSC_FD_WRITE;
282                 return 1;
283         }
284
285         /* try to write a maximum of WRITE_BLOCK bytes */
286         bytes_left = (dnload.data + dnload.data_len) - dnload.write_ptr;
287         write_len = WRITE_BLOCK;
288         if (bytes_left < WRITE_BLOCK)
289                 write_len = bytes_left;
290
291         rc = write(dnload.serial_fd.fd, dnload.write_ptr, write_len);
292         if (rc < 0) {
293                 perror("Error during write");
294                 return rc;
295         }
296
297         dnload.write_ptr += rc;
298
299         printf("%u bytes (%tu/%u)\n", rc, dnload.write_ptr - dnload.data, dnload.data_len);
300
301         return 0;
302 }
303
304 static int handle_write(void)
305 {
306         uint8_t c;
307
308         switch (dnload.state) {
309         case DOWNLOADING:
310                 return handle_write_dnload();
311         default:
312                 if (sercomm_drv_pull(&c) != 0) {
313                         if (write(dnload.serial_fd.fd, &c, 1) != 1)
314                                 perror("short write");
315                 } else
316                         dnload.serial_fd.when &= ~BSC_FD_WRITE;
317         }
318
319         return 0;
320 }
321
322 static uint8_t buffer[sizeof(phone_prompt1)];
323 static uint8_t *bufptr = buffer;
324
325 static void hdlc_send_to_phone(uint8_t dlci, uint8_t *data, int len)
326 {
327         struct msgb *msg;
328         uint8_t c, *dest;
329
330         printf("hdlc_send_to_phone(dlci=%u): ", dlci);
331         hexdump(data, len);
332
333         if (len > 512) {
334                 fprintf(stderr, "Too much data to send. %u\n", len);
335                 return;
336         }
337
338         /* push the message into the stack */
339         msg = sercomm_alloc_msgb(512);
340         if (!msg) {
341                 fprintf(stderr, "Failed to create data for the frame.\n");
342                 return;
343         }
344
345         /* copy the data */
346         dest = msgb_put(msg, len);
347         memcpy(dest, data, len);
348
349         sercomm_sendmsg(dlci, msg);
350
351         dnload.serial_fd.when |= BSC_FD_WRITE;
352 }
353
354 static void hdlc_console_cb(uint8_t dlci, struct msgb *msg)
355 {
356         write(1, msg->data, msg->len);
357         msgb_free(msg);
358 }
359
360 static void hdlc_l1a_cb(uint8_t dlci, struct msgb *msg)
361 {
362         struct layer2_connection *con;
363         u_int16_t *len;
364
365         len = (u_int16_t *) msgb_push(msg, 2);
366         *len = htons(msg->len - sizeof(*len));
367
368         llist_for_each_entry(con, &connections, entry) {
369                 if (write(con->fd.fd, msg->data, msg->len) != msg->len) {
370                         fprintf(stderr, "Failed to write msg to the socket..\n");
371                         continue;
372                 }
373         }
374
375         msgb_free(msg);
376 }
377
378 static void print_hdlc(uint8_t *buffer, int length)
379 {
380         int i;
381
382         for (i = 0; i < length; ++i)
383                 if (sercomm_drv_rx_char(buffer[i]) == 0)
384                         printf("Dropping sample '%c'\n", buffer[i]);
385 }
386
387 static int handle_read(void)
388 {
389         int rc, nbytes, buf_left;
390
391         buf_left = sizeof(buffer) - (bufptr - buffer);
392         if (buf_left <= 0) {
393                 memmove(buffer, buffer+1, sizeof(buffer)-1);
394                 bufptr -= 1;
395                 buf_left = 1;
396         }
397
398         nbytes = read(dnload.serial_fd.fd, bufptr, buf_left);
399         if (nbytes <= 0)
400                 return nbytes;
401
402         if (!dnload.print_hdlc) {
403                 printf("got %i bytes from modem, ", nbytes);
404                 printf("data looks like: ");
405                 hexdump(bufptr, nbytes);
406         } else {
407                 print_hdlc(bufptr, nbytes);
408         }
409
410         if (!memcmp(buffer, phone_prompt1, sizeof(phone_prompt1))) {
411                 printf("Received PROMPT1 from phone, responding with CMD\n");
412                 dnload.print_hdlc = 0;
413                 dnload.state = WAITING_PROMPT2;
414                 rc = write(dnload.serial_fd.fd, dnload_cmd, sizeof(dnload_cmd));
415
416                 /* re-read file */
417                 rc = read_file(dnload.filename);
418                 if (rc < 0) {
419                         fprintf(stderr, "read_file(%s) failed with %d\n", dnload.filename, rc);
420                         exit(1);
421                 }
422         } else if (!memcmp(buffer, phone_prompt2, sizeof(phone_prompt2))) {
423                 printf("Received PROMPT2 from phone, starting download\n");
424                 dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
425                 dnload.state = DOWNLOADING;
426         } else if (!memcmp(buffer, phone_ack, sizeof(phone_ack))) {
427                 printf("Received DOWNLOAD ACK from phone, your code is running now!\n");
428                 dnload.serial_fd.when = BSC_FD_READ;
429                 dnload.state = WAITING_PROMPT1;
430                 dnload.write_ptr = dnload.data;
431                 dnload.print_hdlc = 1;
432         } else if (!memcmp(buffer, phone_nack, sizeof(phone_nack))) {
433                 printf("Received DOWNLOAD NACK from phone, something went wrong :(\n");
434                 dnload.serial_fd.when = BSC_FD_READ;
435                 dnload.state = WAITING_PROMPT1;
436                 dnload.write_ptr = dnload.data;
437         } else if (!memcmp(buffer, phone_nack_magic, sizeof(phone_nack_magic))) {
438                 printf("Received MAGIC NACK from phone, you need to have \"1003\" at 0x803ce0\n");
439                 dnload.serial_fd.when = BSC_FD_READ;
440                 dnload.state = WAITING_PROMPT1;
441                 dnload.write_ptr = dnload.data;
442         } else if (!memcmp(buffer, ftmtool, sizeof(ftmtool))) {
443                 printf("Received FTMTOOL from phone, ramolader has aborted\n");
444                 dnload.serial_fd.when = BSC_FD_READ;
445                 dnload.state = WAITING_PROMPT1;
446                 dnload.write_ptr = dnload.data;
447         }
448         bufptr += nbytes;
449
450         return nbytes;
451 }
452
453 static int serial_read(struct bsc_fd *fd, unsigned int flags)
454 {
455         int rc;
456
457         if (flags & BSC_FD_READ) {
458                 rc = handle_read();
459                 if (rc == 0)
460                         exit(2);
461         }
462
463         if (flags & BSC_FD_WRITE) {
464                 rc = handle_write();
465                 if (rc == 1)
466                         dnload.state = WAITING_PROMPT1;
467         }
468         return 0;
469 }
470
471 static int parse_mode(const char *arg)
472 {
473         if (!strcasecmp(arg, "c123") ||
474             !strcasecmp(arg, "c140"))
475                 return MODE_C123;
476         else if (!strcasecmp(arg, "c123xor"))
477                 return MODE_C123xor;
478         else if (!strcasecmp(arg, "c155"))
479                 return MODE_C155;
480
481         return -1;
482 }
483
484
485 static int usage(const char *name)
486 {
487         printf("\nUsage: %s [ -v | -h ] [ -p /dev/ttyXXXX ] [ -s /tmp/osmocom_l2 ] ][ -m {c123,c123xor,c155} ] file.bin\n", name);
488         printf("\t* Open serial port /dev/ttyXXXX (connected to your phone)\n"
489                 "\t* Perform handshaking with the ramloader in the phone\n"
490                 "\t* Download file.bin to the attached phone (base address 0x00800100)\n");
491         exit(2);
492 }
493
494 static int version(const char *name)
495 {
496         //printf("\n%s version %s\n", name, VERSION);
497         exit(2);
498 }
499
500 static int un_layer2_read(struct bsc_fd *fd, unsigned int flags)
501 {
502         int rc;
503         u_int16_t length = 0xffff;
504         u_int8_t buf[4096];
505         struct layer2_connection *con;
506
507
508         rc = read(fd->fd, &length, sizeof(length));
509         if (rc <= 0 || ntohs(length) > 512) {
510                 fprintf(stderr, "Unexpected result from socket. rc: %d len: %d\n",
511                         rc, ntohs(length));
512                 goto close;
513         }
514
515         rc = read(fd->fd, buf, ntohs(length));
516         if (rc != ntohs(length)) {
517                 fprintf(stderr, "Could not read data.\n");
518                 goto close;
519         }
520
521         hdlc_send_to_phone(SC_DLCI_L1A_L23, buf, ntohs(length));
522
523         return 0;
524 close:
525         con = (struct layer2_connection *) fd->data;
526
527         close(fd->fd);
528         bsc_unregister_fd(fd);
529         llist_del(&con->entry);
530         talloc_free(con);
531         return -1;
532 }
533
534 /* accept a new connection */
535 static int un_layer2_accept(struct bsc_fd *fd, unsigned int flags)
536 {
537         struct layer2_connection *con;
538         struct sockaddr_un un_addr;
539         socklen_t len;
540         int rc;
541
542         len = sizeof(un_addr);
543         rc = accept(fd->fd, (struct sockaddr *) &un_addr, &len);
544         if (rc < 0) {
545                 fprintf(stderr, "Failed to accept a new connection.\n");
546                 return -1;
547         }
548
549         con = talloc_zero(NULL, struct layer2_connection);
550         if (!con) {
551                 fprintf(stderr, "Failed to create layer2 connection.\n");
552                 return -1;
553         }
554
555         con->fd.fd = rc;
556         con->fd.when = BSC_FD_READ;
557         con->fd.cb = un_layer2_read;
558         con->fd.data = con;
559         if (bsc_register_fd(&con->fd) != 0) {
560                 fprintf(stderr, "Failed to register the fd.\n");
561                 return -1;
562         }
563
564         llist_add(&con->entry, &connections);
565         return 0;
566 }
567
568 /*
569  * Create a server socket for the layer2 stack
570  */
571 static int register_af_unix(const char *un_path)
572 {
573         struct sockaddr_un local;
574         int rc;
575
576         dnload.socket.fd = socket(AF_UNIX, SOCK_STREAM, 0);
577
578         if (dnload.socket.fd < 0) {
579                 fprintf(stderr, "Failed to create Unix Domain Socket.\n");
580                 return -1;
581         }
582
583         local.sun_family = AF_UNIX;
584         strncpy(local.sun_path, un_path, sizeof(local.sun_path));
585         local.sun_path[sizeof(local.sun_path) - 1] = '\0';
586         unlink(local.sun_path);
587         rc = bind(dnload.socket.fd, (struct sockaddr *) &local,
588                   sizeof(local.sun_family) + strlen(local.sun_path));
589         if (rc != 0) {
590                 fprintf(stderr, "Failed to bind the unix domain socket. '%s'\n",
591                         local.sun_path);
592                 return -1;
593         }
594
595         if (listen(dnload.socket.fd, 0) != 0) {
596                 fprintf(stderr, "Failed to listen.\n");
597                 return -1;
598         }
599
600         dnload.socket.when = BSC_FD_READ;
601         dnload.socket.cb = un_layer2_accept;
602
603         if (bsc_register_fd(&dnload.socket) != 0) {
604                 fprintf(stderr, "Failed to register the bfd.\n");
605                 return -1;
606         }
607
608         return 0;
609 }
610
611 extern void hdlc_tpudbg_cb(uint8_t dlci, struct msgb *msg);
612
613 int main(int argc, char **argv)
614 {
615         int opt, flags;
616         char *serial_dev = "/dev/ttyUSB1";
617         char *un_path = "/tmp/osmocom_l2";
618
619         dnload.mode = MODE_C123;
620
621         while ((opt = getopt(argc, argv, "hp:m:s:v")) != -1) {
622                 switch (opt) {
623                 case 'p':
624                         serial_dev = optarg;
625                         break;
626                 case 'm':
627                         dnload.mode = parse_mode(optarg);
628                         if (dnload.mode < 0)
629                                 usage(argv[0]);
630                         break;
631                 case 's':
632                         un_path = optarg;
633                         break;
634                 case 'v':
635                         version(argv[0]);
636                         break;
637                 case 'h':
638                 default:
639                         usage(argv[0]);
640                         break;
641                 }
642         }
643
644         if (argc <= optind) {
645                 fprintf(stderr, "You have to specify the filename\n");
646                 usage(argv[0]);
647         }
648
649         dnload.filename = argv[optind];
650
651         dnload.serial_fd.fd = serial_init(serial_dev);
652         if (dnload.serial_fd.fd < 0) {
653                 fprintf(stderr, "Cannot open serial device %s\n", serial_dev);
654                 exit(1);
655         }
656
657         if (bsc_register_fd(&dnload.serial_fd) != 0) {
658                 fprintf(stderr, "Failed to register the serial.\n");
659                 exit(1);
660         }
661
662         /* Set serial socket to non-blocking mode of operation */
663         flags = fcntl(dnload.serial_fd.fd, F_GETFL);
664         flags |= O_NONBLOCK;
665         fcntl(dnload.serial_fd.fd, F_SETFL, flags);
666
667         dnload.serial_fd.when = BSC_FD_READ;
668         dnload.serial_fd.cb = serial_read;
669
670         /* unix domain socket handling */
671         if (register_af_unix(un_path) != 0)
672                 exit(1);
673
674
675         /* initialize the HDLC layer */
676         sercomm_init();
677         sercomm_register_rx_cb(SC_DLCI_CONSOLE, hdlc_console_cb);
678         sercomm_register_rx_cb(SC_DLCI_DEBUG, hdlc_tpudbg_cb);
679         sercomm_register_rx_cb(SC_DLCI_L1A_L23, hdlc_l1a_cb);
680         while (1)
681                 bsc_select_main(0);
682
683         close(dnload.serial_fd.fd);
684
685         exit(0);
686 }