diff --git a/code/inventory/scan.c b/code/inventory/scan.c new file mode 100644 index 0000000..539b12d --- /dev/null +++ b/code/inventory/scan.c @@ -0,0 +1,94 @@ +/* + * scan.c - Phase 1 inventory demo: scan UPC barcodes and display them. + * + * Opens the barcode serial channel (TTY:D) and its own console/keyboard + * channel (CON:), then waits on both at once: a completed scan is validated + * as a UPC-A and printed; pressing Esc quits. + * + * Asynchronous two-channel wait (PLIB pattern): each request is started with + * p_ioc, which sets a status word to E_FILE_PENDING until the request + * completes. p_iowait blocks until some request finishes; we then check each + * status word, cancel the other outstanding request, and loop. Every started + * request is matched by exactly one completion (real or cancelled) so the I/O + * semaphore stays balanced. See "Asynchronous I/O" in the PLIB Reference. + */ +#include +#include "bcode.h" +#include "upc.h" + +#define KEY_ESC 27 + +/* + * If a request on chan is still pending, cancel it and reap the resulting + * completion, so the started p_ioc is balanced by a wait. + */ +LOCAL_C VOID cancelPending(VOID *chan, WORD *pStat) +{ + if (*pStat == E_FILE_PENDING) { + p_iow(chan, P_FCANCEL); + p_waitstat(pStat); + } +} + +GLDEF_C INT main(VOID) +{ + VOID *bchan; /* barcode serial channel */ + VOID *kchan; /* keyboard console channel */ + WORD bStat, kStat; /* async status words */ + UBYTE bRaw[BCODE_MAXLEN]; /* raw bytes from one serial read */ + UBYTE kRaw[1]; /* one keystroke */ + TEXT line[BCODE_MAXLEN]; /* barcode assembled across reads */ + INT lineLen = 0; + UWORD bLen, kLen; + INT err; + INT quit = 0; + + if ((err = bcodeOpen(&bchan)) < 0) { + p_printf("Cannot open barcode port TTY:D (err %d)\n", err); + return 1; + } + if ((err = p_open(&kchan, "CON:", (UINT)-1)) < 0) { + p_printf("Cannot open console (err %d)\n", err); + bcodeClose(bchan); + return 1; + } + + p_printf("Inventory scan demo\n"); + p_printf("Scan a UPC, or press Esc to quit.\n\n"); + + while (quit == 0) { + /* Start one asynchronous read on each channel. */ + bLen = sizeof(bRaw); + p_ioc(bchan, P_FREAD, &bStat, bRaw, &bLen); + kLen = sizeof(kRaw); + p_ioc(kchan, P_FREAD, &kStat, kRaw, &kLen); + + p_iowait(); + + /* Keypress? Cancel the scan read and check for Esc. */ + if (kStat != E_FILE_PENDING) { + cancelPending(bchan, &bStat); + if (kStat >= 0 && kRaw[0] == KEY_ESC) + quit = 1; + continue; + } + + /* Scanner delivered bytes. Cancel the keypress read and assemble. */ + if (bStat != E_FILE_PENDING) { + cancelPending(kchan, &kStat); + if (bStat >= 0 && bLen > 0) { + if (bcodeAssemble(bRaw, (INT)bLen, line, &lineLen, BCODE_MAXLEN)) { + if (upcIsValid(line)) + p_printf("OK %s\n", line); + else + p_printf("BAD %s (not a valid UPC-A)\n", line); + } + } + } + } + + p_printf("\nDone.\n"); + p_close(kchan); + bcodeClose(bchan); + return 0; +}