; ACKNAK32 ; ; Program for Proteus ; ; (C) 2004 Simone Zanella Productions ; ; Emulates keyboard (wedge emulation) by entering data coming from a serial device using Datalogic ; Ack-Nak PC32 protocol. ; This program can be installed as a script for Proteus Service. ; ; Communication parameters can be found at the very beginning of the program; the meaning is as follow: ; - COMPORT = communication port ("COM1", "COM2", etc.) ; - COMSPEED = communication speed (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 baud) ; - COMPARITY = "N" (none), "E" (even), "O" (odd), "M" (mark), "S" (space) ; - COMDATA = 7 o 8 (data bits) ; - COMSTOP = 1 o 2 (stop bits) ; - COMFLOW = "R" (RTS/CTS or hardware), "X" (XON/XOFF or software), "E" (both), "N" (none) ; - POSTFIX = terminator (usually: "{ENTER}") ; ; It is possible to specify: ; - PACE: Delay to wait after sending each line in keyboard emulation (in seconds); ; - POLLINTERVAL: number of seconds after which the program polls for data; ; - TIMEOUT: timeout (ms) for receiving a packet from the terminal; ; - EVALFIRSTBLOCK: flag that specifies if first packet is to be evaluated or discarded; ; - CHARDELAY: intercharacter delay during serial transmission; ; - DTRDELAY: delay before lowering DTR signal; ; - NAKSTREAM: number of NAKs sent to abort transmission (out-of-sync). ; ; The lines below (commented out) allow for alternate behaviours: ; - bring to the foreground a specific window (Ultra-Edit) and emulate keyboard; ; - open notepad (if it is not running), emulate keyboard and return to previous window. #!proteus -z -j !include "win32.prt" ; Parametri di configurazione ; --------------------------- ; Serial port COMPORT = "COM1" ; Baud rate COMSPEED = 9600 ; Parity (None, Odd, Even, Mark, Space: only first letter) COMPARITY = "E" ; Data bits COMDATA = 7 ; Stop bits COMSTOP = 1 ; Flowcontrol (Rts/cts, Xon/xoff, E [both], None: only uppercase letter) COMFLOW = "N" ; Terminator POSTFIX = "" ; Inter-line delay (seconds) PACE = 0.02 ; Polling interval POLLINTERVAL = 0.5 ; Timeout (ms) for receiving a package from the terminal TIMEOUT = 3000 ; Flag that specifies if first packet is to be evaluated or discarded (used to identify file name) EVALFIRSTBLOCK = 0 ; Intercharacter delay CHARDELAY = 0.001 ; Delay before lowering DTR signal DTRDELAY = 0.002 ; Number of NAKs sent to abort transmission (out-of-sync) NAKSTREAM = 10 ; --------------------------- ACK = CHR(6) NAK = CHR(21) HCOM = OPENCOM(COMPORT, COMSPEED, COMPARITY, COMDATA, COMSTOP, COMFLOW) WHILE 1 ; Wait the specified interval SLEEP(POLLINTERVAL) R = W32READCOM(HCOM, 0) IF STRLEN(R) Q = MSReceive232(R) IF NEQ(Q, -1) WHILE QUEUELEN(Q) L = DEQUEUE(Q) ; If a specific window is to be selected, the following function can be used: ; W32SETFOCUS(W32FINDWINDOW("*ULTRAEDIT-32*")) W32SENDKEYS(KTrans(L) POSTFIX) SLEEP(PACE) LOOP QUEUEFREE(Q) FI ; Alternate version which saves/restores current window and selects Notepad before wedging data ; IF NEQ(Q, -1) ; ; Saves current window ; HOLD = W32GETFOCUS() ; ; ; Look for Notepad ; H = W32FINDWINDOW("*Notepad*") ; IF EQ(H, 0) ; ; Not found - open it ; W32SHELL("NOTEPAD.EXE") ; ; Wait 1 second for it to become available ; SLEEP(1) ; ; Look up again its window ; H = W32FINDWINDOW("*Notepad*") ; FI ; ; If found, select its window and wedge data ; IF NEQ(H, 0) ; W32SETFOCUS(H) ; WHILE QUEUELEN(Q) ; L = DEQUEUE(Q) ; W32SENDKEYS(KTrans(L) "{ENTER}") ; SLEEP(PACE) ; LOOP ; ELSE ; ; Notepad could not be opened - data lost! ; FI ; W32SETFOCUS(HOLD) ; QUEUEFREE(Q) ; FI FI LOOP W32CLOSEHANDLE(HCOM) ABORT 0 FUNCTION KTrans(s) l = STRLEN(s) r = "" FOR x = 1 TO l c = SUBSTR(s, x, 1) ; Special characters: characters which are not available on the keyboard ; require special treatment (Alt + 3 digits) - useful for foreign keyboards SWITCH c STREQ ON "~" r = r "{ALT DOWN}{NUMPAD1}{NUMPAD2}{NUMPAD6}{ALT UP}" ON "{" r = r "{ALT DOWN}{NUMPAD1}{NUMPAD2}{NUMPAD3}{ALT UP}" ON "}" r = r "{ALT DOWN}{NUMPAD1}{NUMPAD2}{NUMPAD5}{ALT UP}" ON "+", "^", "%", "(", ")", "[", "]" r = r "{" c "}" OTHER r = r c OFF NEXT RETURN r FUNCTION OpenCom(comport, comspeed, comparity, comdata, comstop, comflow) ; Open serial port with specified parameters hcom = W32CREATEFILE(comport, NOR(_W32_GENERIC_WRITE, _W32_GENERIC_READ), 0, \ _W32_OPEN_EXISTING, 0) IF EQ(hcom, -1) CONSOLELN "Port " comport " could not be opened." ABORT 2 FI compar = VECNEW(13) v = W32GETCOMSTATE(hcom, compar) VECSET(compar, 2, comspeed) v = NOR(_W32_COM_BINARY, _W32_COM_PARITY_ON) SWITCH LEFT(comflow, 1) STRIEQ ON "R" NOR(@v, _W32_COM_RTS_HANDSHAKE, _W32_COM_CTSFLOW_ON) ON "X" NOR(@v, _W32_COM_XONXOFF_OUT, _W32_COM_XONXOFF_IN, _W32_COM_XOFF_CONTINUE) ON "E" NOR(@v, _W32_COM_RTS_HANDSHAKE, _W32_COM_CTSFLOW_ON, \ _W32_COM_XONXOFF_OUT, _W32_COM_XONXOFF_IN, _W32_COM_XOFF_CONTINUE) ON "N" OFF VECSET(compar, 3, v) VECSET(compar, 7, comdata) SWITCH LEFT(comparity, 1) STRIEQ ON "N" v = _W32_COM_PARITY_NONE ON "E" v = _W32_COM_PARITY_EVEN ON "O" v = _W32_COM_PARITY_ODD ON "M" v = _W32_COM_PARITY_MARK ON "S" v = _W32_COM_PARITY_SPACE OFF VECSET(compar, 8, v) SWITCH comstop ON 1 VECSET(compar, 9, 0) ON 2 VECSET(compar, 9, 2) OFF v = W32SETCOMSTATE(hcom, compar) VECFREE(compar) IF v CONSOLELN "Error configuring port (" W32GETLASTERROR() ")." W32CLOSEHANDLE(hcom) ABORT 3 FI tout = VECNEW(5) VECSET(tout, 1, 0) VECSET(tout, 2, 0) VECSET(tout, 3, 0) VECSET(tout, 4, 0) VECSET(tout, 5, 0) W32SETCOMTIMEOUTS(hcom, tout) VECFREE(tout) RETURN hcom FUNCTION MSReceive232(r) q = QUEUENEW() ct = 0 nacknum = 0 fine = "-0000FF" CHR(13) firstblock = NOT(_EVALFIRSTBLOCK) ; Block received s = "" ; Receive packet, with timeout. WHILE 1 IF STRLEN(r) s = s r IF LT(STRLEN(s), ADD("0x" SUBSTR(s, 2, 2), 8)) ; Incomplete packet: wait for remaining data r = W32READCOM(_HCOM, 0) CONTINUE FI s = left(s, ADD("0x" SUBSTR(s, 2, 2), 8)) ; Packet complete: check it IF STREQ(s, fine) ; File complete: send ACK over the line SendChar(_ACK) RETURN q ELSE IF AckNackCheckPacket(s, ct) W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR)) ; Packet ok: send ACK over the line SendChar(_ACK) IF NOT(firstblock) s = SUBSTR(s, 5, SUB(STRLEN(s), 8)) ENQUEUE(q, s) ELSE ; Ignore first block (file name?) firstblock = 0 FI ; Reset number of nacks nacknum = 0 s = "" ELSE ; Verify if the device is trying to resend previous packet; ; if this is the case, ignore the packet because it was ; saved correctly and send ACK ct2 = DEC(ct) IF LT(ct2, 0) ct2 = 9 FI IF AckNackCheckPacket(s, ct2) W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR)) ; Packet ok: send ACK over the line SendChar(_ACK) ; Reset number of nacks and timeout nacknum = 0 s = "" ELSE ; Incorrect packet: send NAK over the line SendChar(_NAK) W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR)) INC(@nacknum) IF GT(nacknum, 31) SendChar(REPLICATE(_NAK, _NAKSTREAM)) ; Too many nacks: failed QUEUEFREE(q) RETURN -1 FI s = "" FI FI FI FI IF NOT(W32WAITRXCHAR(_HCOM, _TIMEOUT)) ; "Timeout" SendChar(REPLICATE(_NAK, _NAKSTREAM)) QUEUEFREE(q) RETURN -1 FI r = W32READCOM(_HCOM, 0) LOOP RETURN FUNCTION AckNackCheckPacket(block, @counter) ; Check if packet is correct; add 1 to counter if it is so IF OR(STRNEQ(LEFT(block, 1), "-"), \ STRNEQ(RIGHT(block, 1), CHR(13)), \ NEQ(LEFT(RIGHT(block, 4), 1), counter), \ STRNEQ(CheckSum(SUBSTR(block, 2, SUB(STRLEN(block), 4))), LEFT(RIGHT(block, 3), 2))) RETURN 0 ELSE INC(@counter) IF GT(counter, 9) counter = 0 FI FI RETURN 1 FUNCTION CheckSum(data) ; Calculate check digit chk = 0 dl = STRLEN(data) FOR x = 1 TO dl ADD(@chk, ASC(SUBSTR(data, x, 1))) NEXT MOD(@chk, 256) RETURN PFORMAT("02X", chk) FUNCTION SendChar(s) ; Lower DTR W32ESCCOMFUNC(_HCOM, _W32_COM_CLRDTR) SLEEP(_CHARDELAY) W32WRITEFILE(_HCOM, s) ; Wait transmission buffer is empty W32WAITTXOVER(_HCOM, 1000) SLEEP(_DTRDELAY) ; Raise DTR W32ESCCOMFUNC(_HCOM, _W32_COM_SETDTR) RETURN