; SPROTOCOL ; ; Program for Proteus ; ; (C) 2004 Simone Zanella Productions ; ; Emulates keyboard (wedge emulation) by entering data coming from a serial device using Datalogic® Special 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 also 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 the terminal; ; - TXSETUP: flag - if not zero, transmission request is sent by the script and ; the terminal expects ACK after each record sent; ; - TIMEOUT: timeout (ms) for receiving a packet from the terminal; ; - ASCII_STXO: start of block (for frames following the first; set to 0 to skip). ; ; You should modify the function ProcessRecord to select which information should be sent ; (by default, only the code is sent). ; ; 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" ; Communication parameters ; ------------------------ ; Serial port COMPORT = "COM1" ; Baud rate COMSPEED = 9600 ; Parity (None, Odd, Even, Mark, Space: only first letter) COMPARITY = "M" ; Data bits COMDATA = 7 ; Stop bits COMSTOP = 1 ; Flowcontrol (Rts/cts, Xon/xoff, E [both], None: only uppercase letter) COMFLOW = "N" ; Delay to wait after sending each line in keyboard emulation (in seconds) PACE = 0.02 ; Poll interval POLLINTERVAL = 1 ; Request transmission TXSETUP = 1 ; Timeout (ms) for receiving a packet from the terminal TIMEOUT = 1500 ; Terminator (default = "{ENTER}") POSTFIX = "{ENTER}" ; Start of block (for frames following the first; set to 0 to skip) ASCII_STXO = 0 ; --------------------------- HCOM = OpenCom(COMPORT, COMSPEED, COMPARITY, COMDATA, COMSTOP, COMFLOW) STXO = CHR(ASCII_STXO) ; Start of block (first frame) ASCII_STXF = 2 STXF = CHR(ASCII_STXF) ; End of text ASCII_ETX = 3 ETX = CHR(ASCII_ETX) ; Record terminator (replaced by ETX in the last record) ASCII_ETB = 23 ETB = CHR(ASCII_ETB) ; End of block ASCII_EOB = 13 EOB = CHR(ASCII_EOB) ; First record: ; STX RECORD ETB LRC CR ; ; Following records: ; [STX] RECORD ETB|ETX LRC CR ; (ETX replaces ETB in the last record) ACK = CHR(6) NAK = CHR(21) WHILE 1 ; Wait the specified interval SLEEP(POLLINTERVAL) ; If it is not a service and the user pressed ESC, exit !ifndef SERVICE IF KBDHIT() IF EQ(GETCH(), 27) BREAK FI FI !endif IF TXSETUP ; Send ACK W32WRITEFILE(HCOM, ACK) FI NCHAR = W32WAITRXCHAR(HCOM, TIMEOUT) IF NCHAR ; Characters received RXSpecialProtocol() FI LOOP W32CLOSEHANDLE(HCOM) ABORT 0 FUNCTION RXSpecialProtocol() firstblock = 1 lastblock = 0 rxabort = 0 nakcount = 0 _Q = QUEUENEW() rest = "" WHILE 1 s = rest W32READCOM(_HCOM, 0) WHILE NOT(STRSTR(s, _EOB)) n = W32WAITRXCHAR(_HCOM, _TIMEOUT) IF n s = s W32READCOM(_HCOM, 0) ELSE ; In case of timeout, send NAK and retry 2 times INC(@nakcount) IF LT(nakcount, 2) s = "" IF _TXSETUP W32WRITEFILE(_HCOM, _NAK) FI ELSE rxabort = 1 FI BREAK FI LOOP IF rxabort BREAK FI ; Cut previous EOB (if necessary) IF STREQ(LEFT(s, 1), _EOB) s = RESTFROM(s, 2) FI rest = s REPEAT p = STRSTR(rest, _EOB) IF p s = LEFT(rest, p) rest = RESTFROM(rest, INC(p)) ELSE BREAK FI record = "" result = CheckFrame(s, firstblock, @record, @lastblock) IF result IF _TXSETUP W32WRITEFILE(_HCOM, _ACK) FI ; Process record IF NOT(firstblock) ENQUEUE(_Q, record) ELSE firstblock = 0 FI IF lastblock BREAK FI ELSE IF _TXSETUP W32WRITEFILE(_HCOM, _NAK) FI FI UNTIL ISEMPTY(rest) IF lastblock BREAK FI LOOP IF NOT(rxabort) EmulateKeyboard(_Q) FI QUEUEFREE(_Q) RETURN FUNCTION CheckFrame(s, firstblock, record, lastblock) ; Start of frame is invalid? IF firstblock IF STRNEQ(LEFT(s, 1), _STXF) RETURN 0 FI ELSE IF _ASCII_STXO IF STRNEQ(LEFT(s, 1), _STXO) RETURN 0 FI FI FI ; Verify End Of Block IF STRNEQ(RIGHT(s, 1), _EOB) RETURN 0 FI ; Cut End Of Block s = LEFT(s, -1) ; Isolate LRC lrc = RIGHT(s, 2) ; Cut LRC s = LEFT(s, -2) ; Isolate ETB etb = RIGHT(s, 1) ; The character before LRC must be ETB or ETX (last block) IF AND(STRNEQ(etb, _ETB), STRNEQ(etb, _ETX)) RETURN 0 FI ; Verify LRC IF NOT(VerifyLRC(lrc, s, firstblock)) RETURN 0 FI ; Check if lastblock and update parameter lastblock = STREQ(RIGHT(s, 1), _ETX) ; Store record record = LEFT(s, -1) IF _ASCII_STXO record = RESTFROM(record, 2) FI RETURN 1 FUNCTION CalcLRC(s, firstblock) acc = 0 l = STRLEN(s) ; XOR all characters in s FOR x = 1 to l NXOR(@acc, ASC(SUBSTR(s, x, 1))) NEXT ; Set most significant bit IF firstblock NAND(@acc, 0x7F) ELSE IF MOD(l, 2) NOR(@acc, 0x80) ELSE NAND(@acc, 0x7F) FI FI ; Calculate c1 and c2 c1 = CHR(ADD(NAND(SHIFTRT(acc, 4), 0xF), 0x40)) c2 = CHR(ADD(NAND(acc, 0xF), 0x40)) RETURN c1 c2 FUNCTION VerifyLRC(lrc, s, firstblock) RETURN STREQ(lrc, CalcLRC(s, firstblock)) FUNCTION EmulateKeyboard(q) ; Alternate version which saves/restores current window and selects Notepad before wedging data ; ; Saves current window ; hOld = W32GETFOCUS() ; ; ; Look for Notepad ; hNotepad = W32FINDWINDOW("*Notepad*") ; IF EQ(hNotepad, 0) ; ; Not found - open it ; W32SHELL("NOTEPAD.EXE") ; ; Wait 1 second for it to become available ; SLEEP(1) ; ; Look up again its window ; hNotepad = W32FINDWINDOW("*Notepad*") ; FI ; ; If found, select its window and wedge data ; IF EQ(hNotepad, 0) ; W32SETFOCUS(hOld) ; RETURN ; FI ; W32SETFOCUS(hNotepad) WHILE QUEUELEN(q) scode = DEQUEUE(q) IF STREQ(LEFT(scode, 1), "^") stime = SUBSTR(scode, 2, 4) scode = RESTFROM(scode, 7) ELSE stime = "" scode = RESTFROM(scode, 2) FI p = STRSTR(scode, "]") IF EQ(p, 0) sqt = "1" ELSE sqt = RESTFROM(scode, INC(p)) scode = LEFT(scode, DEC(p)) FI sbartype = RIGHT(scode, 1) scode = LEFT(scode, -1) ProcessRecord(stime, scode, sbartype, sqt) LOOP ; Alternate version - restore old window ; W32SETFOCUS(hOld) RETURN FUNCTION ProcessRecord(stime, scode, sbartype, sqt) ; If a specific window is to be selected, the following function can be used: ; W32SETFOCUS(W32FINDWINDOW("*ULTRAEDIT-32*")) W32SENDKEYS(KTrans(scode) _POSTFIX) SLEEP(_PACE) RETURN 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) !ifndef SERVICE CONSOLELN "Port " comport " could not be opened." !endif 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 !ifndef SERVICE CONSOLELN "Error configuring port (" W32GETLASTERROR() ")." !endif 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