diff options
Diffstat (limited to 'spectro/usbio.c')
-rw-r--r-- | spectro/usbio.c | 115 |
1 files changed, 80 insertions, 35 deletions
diff --git a/spectro/usbio.c b/spectro/usbio.c index f8a0529..508b357 100644 --- a/spectro/usbio.c +++ b/spectro/usbio.c @@ -51,14 +51,14 @@ int in_usb_rw = 0; void usb_init_cancel(usb_cancelt *p) { amutex_init(p->cmtx); - amutex_init(p->cond); + amutex_init(p->condx); p->hcancel = NULL; } void usb_uninit_cancel(usb_cancelt *p) { amutex_del(p->cmtx); - amutex_del(p->cond); + amutex_del(p->condx); } /* Used by caller of icoms to re-init for wait_io */ @@ -69,7 +69,7 @@ void usb_reinit_cancel(usb_cancelt *p) { p->hcancel = NULL; p->state = 0; - amutex_lock(p->cond); /* Block until IO is started */ + amutex_lock(p->condx); /* Block until IO is started */ amutex_unlock(p->cmtx); } @@ -79,8 +79,8 @@ static int icoms_usb_wait_io( icoms *p, usb_cancelt *cancelt ) { - amutex_lock(cancelt->cond); /* Wait for unlock */ - amutex_unlock(cancelt->cond); /* Free it up for next time */ + amutex_lock(cancelt->condx); /* Wait for unlock */ + amutex_unlock(cancelt->condx); /* Free it up for next time */ return ICOM_OK; } @@ -94,7 +94,7 @@ static int icoms_usb_wait_io( # include "usbio_ox.c" # endif # if defined(UNIX_X11) -# if defined(__FreeBSD__) +# if defined(__FreeBSD__) || defined(__OpenBSD__) # include "usbio_bsd.c" # else # include "usbio_lx.c" @@ -281,10 +281,19 @@ void (*usbio_term)(int sig) = SIG_DFL; /* On something killing our process, deal with USB cleanup */ static void icoms_sighandler(int arg) { + static amutex_static(lock); + a1logd(g_log, 6, "icoms_sighandler: invoked with arg = %d\n",arg); + + /* Make sure we don't re-enter */ + if (amutex_trylock(lock)) { + return; + } + if (in_usb_rw != 0) in_usb_rw = -1; icoms_cleanup(); + /* Call the existing handlers */ #ifdef UNIX if (arg == SIGHUP && usbio_hup != SIG_DFL && usbio_hup != SIG_IGN) @@ -296,6 +305,8 @@ static void icoms_sighandler(int arg) { usbio_term(arg); a1logd(g_log, 6, "icoms_sighandler: calling exit()\n"); + + amutex_unlock(lock); exit(0); } @@ -353,7 +364,8 @@ void usb_delete_from_cleanup_list(icoms *p) { static int icoms_usb_ser_write( icoms *p, -char *wbuf, +char *wbuf, /* null terminated unless nch > 0 */ +int nwch, /* if > 0, number of characters to write */ double tout) { int len, wbytes; @@ -385,7 +397,10 @@ double tout) else type = icom_usb_trantype_interrutpt; - len = strlen(wbuf); + if (nwch != 0) + len = nwch; + else + len = strlen(wbuf); tout *= 1000.0; /* Timout in msec */ top = (int)(tout + 0.5); /* Timeout period in msecs */ @@ -424,14 +439,15 @@ double tout) /* Read characters into the buffer */ /* Return string will be terminated with a nul */ /* Read only in packet sized chunks, and retry if */ -/* the bytes requested aren'r read, untill we get a */ +/* the bytes requested aren't read, untill we get a */ /* timeout or a terminating char is read */ static int icoms_usb_ser_read(icoms *p, char *rbuf, /* Buffer to store characters read */ int bsize, /* Buffer size */ -char *tc, /* Terminating characers, NULL if none */ -int ntc, /* Number of terminating characters needed to terminate */ +int *pbread, /* Bytes read (not including forced '\000') */ +char *tc, /* Terminating characers, NULL for none or char count mode */ +int ntc, /* Number of terminating characters or char count needed, if 0 use bsize */ double tout) /* Time out in seconds */ { int j, rbytes; @@ -441,10 +457,8 @@ double tout) /* Time out in seconds */ int ep = p->rd_ep; /* End point */ icom_usb_trantype type; /* bulk or interrupt */ int retrv = ICOM_OK; - -#ifdef QUIET_MEMCHECKERS - memset(rbuf, 0, bsize); -#endif + int nreads; /* Number of reads performed */ + int fastserial = 0; /* If fast serial type */ if (!p->is_open) { a1loge(p->log, ICOM_SYS, "icoms_usb_ser_read: device is not open\n"); @@ -472,40 +486,62 @@ double tout) /* Time out in seconds */ return ICOM_SYS; } - for (j = 0; j < bsize; j++) rbuf[j] = 0; - - bsize -= 1; /* Allow space for null */ - bsize -= p->ms_bytes; /* Allow space for modem status bytes */ + if (p->port_type(p) == icomt_usbserial) + fastserial = 1; + for (j = 0; j < bsize; j++) + rbuf[j] = 0; + /* The DTP94 doesn't cope with a timeout on OS X, so we need to avoid */ /* them by giving each read the largest timeout period possible. */ /* This also reduces the problem of libusb 0.1 not returning the */ - /* number of characters read on a timeou. */ + /* number of characters read on a timeout. */ ttop = (int)(tout * 1000.0 + 0.5); /* Total timeout period in msecs */ - a1logd(p->log, 8, "\nicoms_usb_ser_read: ep 0x%x, ttop %d, quant %d\n", p->rd_ep, ttop, p->rd_qa); + a1logd(p->log, 8, "\nicoms_usb_ser_read: ep 0x%x, bytes %d, ttop %d, ntc %d, quant %d\n", p->rd_ep, bsize, ttop, ntc, p->rd_qa); + + bsize -= 1; /* Allow space for null */ + bsize -= p->ms_bytes; /* Allow space for modem status bytes */ /* Until data is all read, we time out, or the user aborts */ - stime = msec_time(); + etime = stime = msec_time(); top = ttop; - for (j = 0; top > 0 && bsize > 1 && j < ntc ;) { + j = (tc == NULL && ntc <= 0) ? -1 : 0; + + for (nreads = 0; top > 0 && bsize > 0 && j < ntc ;) { int c, rv; - int rsize = p->rd_qa < bsize ? p->rd_qa : bsize; + int rsize = bsize; - a1logd(p->log, 8, "icoms_usb_ser_read: attempting to read %d bytes from usb, top = %d, j = %d\n",bsize > p->rd_qa ? p->rd_qa : bsize,top,j); + /* If not a fast USB serial port, read in quanta size chunks */ + if (!fastserial && rsize > p->rd_qa) + rsize = p->rd_qa; + + a1logd(p->log, 8, "icoms_usb_ser_read: attempting to read %d bytes from usb, top = %d, j = %d\n",rsize,top,j); rv = icoms_usb_transaction(p, NULL, &rbytes, type, (unsigned char)ep, (unsigned char *)rbuf, rsize, top); etime = msec_time(); + nreads++; if (rbytes > 0) { /* Account for bytes read */ - /* Account for modem status bytes. Modem bytes are per usb read. */ + /* Account for modem status bytes. Modem bytes are per usb read, */ + /* or every p->rd_qa bytes. */ if (p->ms_bytes) { /* Throw away modem bytes */ - int nb = rbytes < p->ms_bytes ? rbytes : p->ms_bytes; - rbytes -= nb; - memmove(rbuf, rbuf+nb, rbytes); - a1logd(p->log, 8, "icoms_usb_ser_read: discarded %d modem bytes\n",nb); + char *bp = rbuf; + int rb = rbytes; + for (; rb > 0; ) { + int nb = rb < p->ms_bytes ? rb : p->ms_bytes; /* Bytes to shift */ + if (p->interp_ms != NULL && nb >= p->ms_bytes) + retrv |= p->interp_ms(p, (unsigned char *)bp); /* Deal with error flags in ms bytes */ + a1logd(p->log, 8, "icoms_usb_ser_read: discarded %d modem bytes 0x%02x 0x%02x\n",nb,nb >= 1 ? (bp[0] & 0xff) : 0, nb >= 2 ? (bp[1] & 0xff) : 0); + rb -= nb; + rbytes -= nb; + memmove(bp, bp+nb, rb); + bp += p->rd_qa - p->ms_bytes; + rb -= p->rd_qa - p->ms_bytes; + } + rbuf[rbytes] = 0; } a1logd(p->log, 8, "icoms_usb_ser_read: read %d bytes, rbuf = '%s'\n",rbytes,icoms_fix(rrbuf)); @@ -521,7 +557,10 @@ double tout) /* Time out in seconds */ tcp++; } } + a1logd(p->log, 8, "icoms_usb_ser_read: tc count %d\n",j); } else { + if (ntc > 0) + j += rbytes; rbuf += rbytes; } } @@ -534,14 +573,20 @@ double tout) /* Time out in seconds */ } top = ttop - (etime - stime); /* Remaining time */ - if (top <= 0) { /* Run out of time */ - a1logd(p->log, 8, "icoms_usb_ser_read: read ran out of time\n"); - retrv |= ICOM_TO; - break; - } } *rbuf = '\000'; + a1logd(p->log, 8, "icoms_usb_ser_read: read %d total bytes with %d reads\n",rbuf - rrbuf, nreads); + if (pbread != NULL) + *pbread = (rbuf - rrbuf); + + /* If ran out of time and not completed */ + a1logd(p->log, 8, "icoms_usb_ser_read: took %d msec\n",etime - stime); + if (top <= 0 && bsize > 0 && j < ntc) { + a1logd(p->log, 8, "icoms_usb_ser_read: read ran out of time\n"); + a1logd(p->log, 8, "ttop %d, etime - stime %d\n",ttop,etime - stime); + retrv |= ICOM_TO; + } a1logd(p->log, 8, "icoms_usb_ser_read: returning '%s' ICOM err 0x%x\n",icoms_fix(rrbuf),retrv); |