; WEDGEF64 ; ; Program for Proteus ; ; (C) 2004 Simone Zanella Productions ; ; Emulates keyboard by entering data coming from a serial device using Datalogic® wedge protocol ; (used by F64/F67 keyboard emulators). ; 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 (default 0.64); ; - TIMEOUT: timeout (ms) for receiving a packet from the terminal. ; ; You should modify the function EmulateKeyboard to select which information should be 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 = "E" ; 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 = 0.64 ; Timeout (ms) for receiving a packet from the terminal TIMEOUT = 500 ; Terminator (default = "{ENTER}") POSTFIX = "{ENTER}" ; --------------------------- HCOM = OpenCom(COMPORT, COMSPEED, COMPARITY, COMDATA, COMSTOP, COMFLOW) ACK = CHR(6) NAK = CHR(21) NULL = CHR(0) ESC = CHR(0x1B) CR = CHR(0x0D) LF = CHR(0x0A) ETB = CHR(0x17) EOT = CHR(0x04) PACKETENQ = MKPacket(NULL ESC "5$" ESC CR) 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 ; Send ENQ W32WRITEFILE(HCOM, PACKETENQ) NCHAR = W32WAITRXCHAR(HCOM, TIMEOUT) IF NCHAR ; Characters received RXWedgeProtocol() FI LOOP W32CLOSEHANDLE(HCOM) ABORT 0 FUNCTION RXWedgeProtocol() lastblock = 0 rxabort = 0 nakcount = 0 _Q = QUEUENEW() lastpacketsent = _PACKETENQ status = 0 WHILE 1 s = W32READCOM(_HCOM, 0) WHILE NOT(STRSTR(s, _LF)) n = W32WAITRXCHAR(_HCOM, _TIMEOUT) IF n s = s W32READCOM(_HCOM, 0) nakcount = 0 ELSE ; In case of timeout, send NAK and retry 2 times INC(@nakcount) IF LT(nakcount, 2) s = "" W32READCOM(_HCOM, 0) W32WRITEFILE(_HCOM, lastpacketsent) CONTINUE ELSE ; Too many NAK: abort (discard all records received) rxabort = 1 FI BREAK FI LOOP IF rxabort BREAK FI p = STRSTR(s, _LF) s = LEFT(s, p) record = "" result = CheckFrame(s, @record, @lastblock) W32READCOM(_HCOM, 0) IF result SWITCH status ON 0 ; Check if it has received [xx]<RUN> IF STREQ(RIGHT(record, 5), "<RUN>") W32WRITEFILE(_HCOM, _ACK) ; Reset record pointer lastpacketsent = MKPacket(_NULL _ESC "0#" _ESC _CR) W32WRITEFILE(_HCOM, lastpacketsent) INC(@status) ELSE ; Record ok: add it lastpacketsent = _NAK W32WRITEFILE(_HCOM, _ACK) status = 2 IF NOT(lastblock) ENQUEUE(_Q, record) FI ; W32WRITEFILE(_HCOM, _NAK) FI ON 1 IF STREQ(LEFT(record, 5), "<ACK>") W32WRITEFILE(_HCOM, _ACK) ; Request first 100 records lastpacketsent = MKPacket(_NULL _ESC "0#100" _ESC _CR) W32WRITEFILE(_HCOM, lastpacketsent) INC(@status) ELSE ; Record ok: add it lastpacketsent = _NAK W32WRITEFILE(_HCOM, _ACK) INC(@status) IF NOT(lastblock) ENQUEUE(_Q, record) FI ; W32WRITEFILE(_HCOM, _NAK) FI ON 2 ; Record ok: add it lastpacketsent = _NAK W32WRITEFILE(_HCOM, _ACK) IF NOT(lastblock) ENQUEUE(_Q, record) FI OFF ELSE ; Record not valid W32WRITEFILE(_HCOM, _NAK) FI IF lastblock IF EQ(lastblock, 1) ; ETB received, wait for EOT lastblock = 0 ; Request another 100 records (if available) lastpacketsent = MKPacket(_NULL _ESC "0#100" _ESC _CR) W32WRITEFILE(_HCOM, lastpacketsent) status = 2 ELSE BREAK FI FI LOOP IF NOT(rxabort) EmulateKeyboard(_Q) FI QUEUEFREE(_Q) RETURN FUNCTION MKPacket(s) RETURN s CalcLRC(s) _LF FUNCTION CheckFrame(s, record, lastblock) ; Start of frame is invalid? IF STRNEQ(LEFT(s, 2), _NULL _NULL) IF STRNEQ(LEFT(s, 1), _NULL) RETURN 0 ELSE s = _NULL s FI FI ; Verify End Of Block IF STRNEQ(RIGHT(s, 1), _LF) RETURN 0 FI ; Cut End Of Block s = LEFT(s, -1) ; Isolate LRC lrc = RIGHT(s, 1) ; Cut LRC s = LEFT(s, -1) IF STRNEQ(RIGHT(s, 1), _CR) RETURN 0 FI ; Verify LRC IF NOT(VerifyLRC(lrc, s)) RETURN 0 FI ; Cut initial NULLs s = RESTFROM(s, 3) ; Cut ending CR s = LEFT(s, -1) ; Check if lastblock and update parameter SWITCH LEFT(s, 1) STREQ ON _EOT lastblock = 1 ON _ETB lastblock = 2 OTHER lastblock = 0 OFF ; Store record record = s RETURN 1 FUNCTION CalcLRC(s) acc = 0 l = STRLEN(s) ; XOR all characters in s FOR x = 1 to l NXOR(@acc, ASC(SUBSTR(s, x, 1))) NEXT RETURN CHR(acc) FUNCTION VerifyLRC(lrc, s) RETURN STREQ(lrc, CalcLRC(s)) 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) W32SENDKEYS(KTrans(DEQUEUE(q)) _POSTFIX) SLEEP(_PACE) LOOP ; Alternate version - restore old window ; W32SETFOCUS(hOld) 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