; CB1000
;
; Program for Proteus
;
; (C) 2003-2004 Simone Zanella Productions
;
; Emulates keyboard by entering data coming from a device connected through an Ethernet Client Bridge
; (like Symbol CB1000). For the program to work correctly, it is necessary that the device be configured
; so that it accepts connections from the PC where this program is running.
; 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:
; - NETADDR = CB1000 network address
; - NETPORT = CB1000 port number
#!proteus -z -j
!include "win32.prt"
!include "socket.prt"
CONST NETADDR = "172.16.0.90"
CONST NETPORT = 4000
HSock = -1
Connect()
NumBytes = 0
LastTime = W32GETTICKCOUNT()
WHILE 1
; Check if data is waiting at the socket
N = W32IOCTLSOCKET(HSock, FIONREAD, @NumBytes)
IF AND(EQ(N, 0), GT(NumBytes, 0))
; Save the moment of last activity
LastTime = W32GETTICKCOUNT()
; Receive data to Buffer
Buffer = REPLICATE(" ", NumBytes)
N = W32RECV(HSock, @Buffer, 0)
IF LT(N, 0)
; Error: CB1000 was disconnected; try to reconnect
Connect()
ELSE
W32SENDKEYS(KTrans(Buffer) "{ENTER}")
FI
ELSE
IF LT(N, 0)
; Error: CB1000 was disconnected; try to reconnect
Connect()
ELSE
; More than 4 seconds have passed from the moment of last activity: ping the device,
; to be sure it is alive and connected; try to reconnect otherwise
IF GT(SUB(W32GETTICKCOUNT(), LastTime), 4000)
IF LT(Ping(NETADDR), 0)
Connect()
FI
LastTime = W32GETTICKCOUNT()
FI
FI
FI
!ifndef SERVICE
; If the program is not running as a service, pressing Esc will exit
IF KBDHIT()
IF EQ(GETCH(0), 27)
W32SHUTDOWN(HSock, SD_BOTH)
W32CLOSESOCKET(HSock)
ABORT 0
FI
FI
!endif
LOOP
ABORT 0
FUNCTION Connect()
; Close the socket, if it's open
IF NEQ(_HSock, -1)
W32SHUTDOWN(_HSock, _SD_BOTH)
W32CLOSESOCKET(_HSock)
FI
_HSock = -1
WHILE EQ(_HSock, -1)
; Create the socket
WHILE EQ(_HSock, -1)
_HSock = W32SOCKET(_AF_INET, _SOCK_STREAM, _IPPROTO_TCP)
IF EQ(_HSock, -1)
; Wait a second
SLEEP(1)
FI
LOOP
; Try to resolve address
nome = netaddr = _NETADDR
alias = ""
type = 0
addresses = ""
result = W32GETHOSTBYNAME(@nome, @alias, @type, @addresses)
IF EQ(result, 0)
netaddr = TOKEN(addresses, 1, "\t")
FI
; Connect the socket to the specified address/port
result = W32CONNECT(_HSock, _AF_INET, _NETPORT, netaddr)
IF EQ(result, -1)
W32SHUTDOWN(_HSock, _SD_BOTH)
W32CLOSESOCKET(_HSock)
_HSock = -1
; Wait a second
SLEEP(1)
FI
LOOP
RETURN
FUNCTION Ping(netaddr)
; Create the socket
hsock = W32SOCKET(_AF_INET, _SOCK_RAW, _IPPROTO_ICMP)
IF EQ(hsock, -1)
RETURN -1
FI
; Set send/receive timeout
IF EQ(W32SETSOCKOPT(hsock, _SOL_SOCKET, _SO_RCVTIMEO, 1000), -1)
RETURN -2
FI
IF EQ(W32SETSOCKOPT(hsock, _SOL_SOCKET, _SO_SNDTIMEO, 1000), -1)
RETURN -3
FI
; Try to resolve address
nome = netaddr
alias = ""
type = 0
addresses = ""
result = W32GETHOSTBYNAME(@nome, @alias, @type, @addresses)
IF EQ(result, 0)
netaddr = TOKEN(addresses, 1, "\t")
FI
; IcmpHeader:
; BYTE i_type (ECHO = 8)
; BYTE i_code (= 0)
; WORD i_cksum (= 0)
; WORD i_id (= current process ID)
; WORD i_seq (= 0)
; DWORD timestamp (= Tick Count)
seq = 0
buffer = CHR(8) CHR(0) CHR(0) CHR(0) Word2String(W32GETPROCESSID()) Word2String(seq) LongWord2String(W32GETTICKCOUNT()) \
REPLICATE("E", SUB(44, 12))
buffer = LEFT(buffer, 2) Word2String(CHECKSUM(buffer)) RESTFROM(buffer, 5)
; Send ping packet
result = W32SENDTO(hsock, buffer, 0, _AF_INET, 0, netaddr)
IF EQ(result, -1)
RETURN -4
FI
; Receive answer, with timeout
buffer = REPLICATE(" ", 1024)
indirizzo = ""
porta = 0
famiglia = 0
result = W32RECVFROM(hsock, @buffer, 0, @famiglia, @porta, @indirizzo)
IF EQ(result, -1)
RETURN -5
FI
l = MUL(NAND(ASC(LEFT(buffer,1)), 0xF), 4)
; Non-echo type
NEWBUF = RESTFROM(buffer, INC(l))
IF NEQ(ASC(SUBSTR(NEWBUF, 1, 1)), 0)
RETURN -6
FI
; Wrong destination
IF NEQ(String2Word(SUBSTR(NEWBUF, 5, 2)), W32GETPROCESSID())
RETURN -7
FI
; Round-trip time in milliseconds
diff = SUB(W32GETTICKCOUNT(), String2LongWord(SUBSTR(NEWBUF, 9, 4)))
; Close socket and return round-trip time
W32SHUTDOWN(hsock, _SD_BOTH)
W32CLOSESOCKET(hsock)
RETURN diff
FUNCTION CheckSum(s)
; Calculate checksum for the packet
l = STRLEN(s)
chk = 0
x = 1
WHILE GT(l, 1)
ADD(@chk, ASC(SUBSTR(s, x, 1)), MUL(ASC(SUBSTR(s, INC(x), 1)), 256))
SUB(@l, 2)
ADD(@x, 2)
LOOP
IF l
ADD(@chk, ASC(SUBSTR(s, x, 1)))
FI
chk = ADD(SHIFTRT(chk, 16), NAND(chk, 0xFFFF))
ADD(@chk, SHIFTRT(chk, 16))
RETURN NAND(NNOT(chk), 0xFFFF)
FUNCTION String2Word(s)
; Convert from binary to word
RETURN NOR( ASC(LEFT(s, 1)), SHIFTLT(ASC(SUBSTR(s, 2, 1)), 8) )
FUNCTION Word2String(n)
; Convert from word to binary
RETURN CHR(NAND(n, 0xFF)) CHR(NAND(SHIFTRT(n, 8), 0xFF))
FUNCTION String2LongWord(s)
; Convert from binary to long word
RETURN NOR(ASC(LEFT(s, 1)), \
SHIFTLT(ASC(SUBSTR(s, 2, 1)), 8), \
SHIFTLT(ASC(SUBSTR(s, 3, 1)), 16), \
SHIFTLT(ASC(SUBSTR(s, 4, 1)), 24))
FUNCTION LongWord2String(n)
; Convert from long word to binary
RETURN CHR(NAND(n, 0xFF)) CHR(NAND(SHIFTRT(n, 8), 0xFF)) CHR(NAND(SHIFTRT(n, 16), 0xFF)) \
CHR(NAND(SHIFTRT(n, 24), 0xFF))
FUNCTION KTrans(s)
; Special characters: characters which are not available on the keyboard
; require special treatment (Alt + 3 digits) - useful for foreign keyboards
l = STRLEN(s)
r = ""
FOR x = 1 TO l
c = SUBSTR(s, x, 1)
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