ao-tools: Wait for device to become ready instead of failing
[fw/altos] / ao-tools / lib / cc-usb.c
index 80d9c04f7ec5271074c730b3bf01c17f2845f610..a3a19d5cda58c875fce4c0dc90d54d15013fa3a2 100644 (file)
@@ -53,6 +53,8 @@ struct cc_usb {
 
        struct cc_hex_read      hex_buf[CC_NUM_HEX_READ];
        int                     hex_count;
+
+       int                     remote;
 };
 
 #define NOT_HEX        0xff
@@ -121,9 +123,10 @@ cc_handle_hex_read(struct cc_usb *cc)
 static void
 cc_usb_dbg(int indent, uint8_t *bytes, int len)
 {
-       int     eol = 1;
+       static int      eol = 1;
        int     i;
        uint8_t c;
+       ccdbg_debug(CC_DEBUG_BITBANG, "<<<%d bytes>>>", len);
        while (len--) {
                c = *bytes++;
                if (eol) {
@@ -133,12 +136,17 @@ cc_usb_dbg(int indent, uint8_t *bytes, int len)
                }
                switch (c) {
                case '\r':
-                       ccdbg_debug(CC_DEBUG_BITBANG, "^M");
+                       ccdbg_debug(CC_DEBUG_BITBANG, "\\r");
                        break;
                case '\n':
                        eol = 1;
+                       ccdbg_debug(CC_DEBUG_BITBANG, "\\n\n");
+                       break;
                default:
-                       ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
+                       if (c < ' ' || c > '~')
+                               ccdbg_debug(CC_DEBUG_BITBANG, "\\%02x", c);
+                       else
+                               ccdbg_debug(CC_DEBUG_BITBANG, "%c", c);
                }
        }
 }
@@ -252,10 +260,10 @@ cc_usb_printf(struct cc_usb *cc, char *format, ...)
 }
 
 int
-cc_usb_getchar(struct cc_usb *cc)
+cc_usb_getchar_timeout(struct cc_usb *cc, int timeout)
 {
        while (cc->in_pos == cc->in_count) {
-               if (_cc_usb_sync(cc, 5000) < 0) {
+               if (_cc_usb_sync(cc, timeout) < 0) {
                        fprintf(stderr, "USB link timeout\n");
                        exit(1);
                }
@@ -263,6 +271,12 @@ cc_usb_getchar(struct cc_usb *cc)
        return cc->in_buf[cc->in_pos++];
 }
 
+int
+cc_usb_getchar(struct cc_usb *cc)
+{
+       return cc_usb_getchar_timeout(cc, 5000);
+}
+
 void
 cc_usb_getline(struct cc_usb *cc, char *line, int max)
 {
@@ -372,21 +386,61 @@ cc_usb_reset(struct cc_usb *cc)
        return 1;
 }
 
+void
+cc_usb_open_remote(struct cc_usb *cc, int freq, char *call)
+{
+       if (!cc->remote) {
+               fprintf (stderr, "freq %dkHz\n", freq);
+               fprintf (stderr, "call %s\n", call);
+               cc_usb_printf(cc, "\nc F %d\nc c %s\np\nE 0\n", freq, call);
+               do {
+                       cc->in_count = cc->in_pos = 0;
+                       _cc_usb_sync(cc, 100);
+               } while (cc->in_count > 0);
+               cc->remote = 1;
+       }
+}
+
+void
+cc_usb_close_remote(struct cc_usb *cc)
+{
+       if (cc->remote) {
+               cc_usb_printf(cc, "~");
+               cc->remote = 0;
+       }
+}
+
 static struct termios  save_termios;
 
+#include <errno.h>
+
 struct cc_usb *
 cc_usb_open(char *tty)
 {
        struct cc_usb   *cc;
        struct termios  termios;
+       int             i;
 
        if (!tty)
                tty = DEFAULT_TTY;
        cc = calloc (sizeof (struct cc_usb), 1);
        if (!cc)
                return NULL;
-       cc->fd = open(tty, O_RDWR | O_NONBLOCK);
-       if (cc->fd < 0) {
+       i = 0;
+       for (;;) {
+               cc->fd = open(tty, O_RDWR | O_NONBLOCK);
+               if (cc->fd >= 0)
+                       break;
+               i++;
+               if (errno == EBUSY || errno == EPERM || errno == EACCES) {
+                       fprintf(stderr, "open failed, pausing");
+                       perror(tty);
+                       if (i < 20) {
+                               sleep(3);
+                               continue;
+                       }
+               }
+
                perror(tty);
                free (cc);
                return NULL;
@@ -394,8 +448,10 @@ cc_usb_open(char *tty)
        tcgetattr(cc->fd, &termios);
        save_termios = termios;
        cfmakeraw(&termios);
+       cfsetospeed(&termios, B9600);
+       cfsetispeed(&termios, B9600);
        tcsetattr(cc->fd, TCSAFLUSH, &termios);
-       cc_usb_printf(cc, "E 0\nm 0\n");
+       cc_usb_printf(cc, "\nE 0\nm 0\n");
        do {
                cc->in_count = cc->in_pos = 0;
                _cc_usb_sync(cc, 100);
@@ -406,6 +462,8 @@ cc_usb_open(char *tty)
 void
 cc_usb_close(struct cc_usb *cc)
 {
+       cc_usb_close_remote(cc);
+       cc_usb_sync(cc);
        tcsetattr(cc->fd, TCSAFLUSH, &save_termios);
        close (cc->fd);
        free (cc);