summaryrefslogtreecommitdiff
path: root/spectro/usbio.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/usbio.c')
-rw-r--r--spectro/usbio.c115
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);