; SPROTOCOL
;
; Programma per Proteus
;
; (C) 2004 Simone Zanella Productions
;
; Riceve dati inviati nel formato Datalogic® Special protocol da un dispositivo seriale e li 
; inserisce in emulazione di tastiera.
; Questo programma può essere installato come script associato al servizio Proteus.
;
; I parametri di comunicazione si trovano all'inizio del programma e sono:
; - COMPORT = porta di comunicazione ("COM1", "COM2", ecc.)
; - COMSPEED = velocità di comunicazione (1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200)
; - COMPARITY = "N" (nessuna), "E" (pari), "O" (dispari), "M" (marca), "S" (spazio)
; - COMDATA = 7 o 8 (bit di dati)
; - COMSTOP = 1 o 2 (bit di stop)
; - COMFLOW = "R" (RTS/CTS detto anche hardware), "X" (XON/XOFF detto anche software), "E" (entrambi), "N" (nessuno)
; - POSTFIX = terminatore (di solito: "{ENTER}")
;
; E' poi possibile specificare:
; - PACE: ritardo dopo l'invio in emulazione di tastiera di ciascuna riga (in secondi);
; - POLLINTERVAL: periodicità (in secondi) con la quale il programma verifica la presenza di dati disponibili;
; - TXSETUP: flag - se non zero, la richiesta di trasmissione è inviata dallo script ed il terminale
;   si aspetta un ACK dopo ogni record inviato;
; - TIMEOUT: timeout (in millisecondi) per la ricezione di un pacchetto dal terminale;
; - ASCII_STXO: codice ASCII del carattere Start of Block (per i frame seguenti al primo; impostare a 0 per saltarlo).
;
; Il codice commentato più sotto permette anche in alternativa di:
; - selezionare una specifica finestra (applicativo Ultra-Edit) ed inviare il dato verbatim, seguito da Invio;
; - lanciare il blocco note (se non aperto), introdurre il dato verbatim (seguito da Invio) e tornare alla finestra
;   iniziale.

#!proteus -z -j

!include "win32.prt"

; Parametri di comunicazione
; --------------------------

; Porta seriale
COMPORT = "COM1"
; Baud rate
COMSPEED = 9600
; Parità (None, Odd, Even, Mark, Space: solo iniziale)
COMPARITY = "M"
; Bit di dati
COMDATA = 7
; Bit di stop
COMSTOP = 1
; Controllo di flusso (Rts/cts, Xon/xoff, Entrambi, Nessuno: solo iniziale)
COMFLOW = "N"

; Ritardo interlinea
PACE = 0.02

; Intervallo di polling
POLLINTERVAL = 1

; Richiesta di trasmissione dallo script
TXSETUP = 1

; Timeout (in millisecondi) per la ricezione di un pacchetto dal terminale
TIMEOUT = 1500

; Terminatore (default = "{ENTER}")
POSTFIX = "{ENTER}"

; Start of block (per i frame che seguono il primo; impostare a 0 per saltarlo)
ASCII_STXO = 0

; ---------------------------

HCOM = OpenCom(COMPORT, COMSPEED, COMPARITY, COMDATA, COMSTOP, COMFLOW)

STXO = CHR(ASCII_STXO)

; Start of block (primo frame)
ASCII_STXF = 2
STXF = CHR(ASCII_STXF)

; End of text
ASCII_ETX = 3
ETX = CHR(ASCII_ETX)

; Terminatore di record (sostituito da ETX nell'ultimo record)
ASCII_ETB = 23
ETB = CHR(ASCII_ETB)

; End of block
ASCII_EOB = 13
EOB = CHR(ASCII_EOB)

; Primo record:
; STX RECORD ETB LRC CR
;
; Record seguenti:
; [STX] RECORD ETB|ETX LRC CR
; (ETX sostituisce ETB nell'ultimo record)

ACK = CHR(6)
NAK = CHR(21)

WHILE 1
  ; Attende per l'intervallo specificato
  SLEEP(POLLINTERVAL)
  
  ; Se non è un servizio e l'utente ha premuto ESC, esce
  !ifndef SERVICE
    IF KBDHIT()
      IF EQ(GETCH(), 27)
        BREAK
      FI
    FI
  !endif
  
  IF TXSETUP
    ; Invia ACK
    W32WRITEFILE(HCOM, ACK)
  FI
  NCHAR = W32WAITRXCHAR(HCOM, TIMEOUT)
  IF NCHAR
    ; Ricevuti dei caratteri
    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 caso di timeout, invia NAK e riprova 2 volte
      INC(@nakcount)
      IF LT(nakcount, 2)
        s = ""
        IF _TXSETUP
          W32WRITEFILE(_HCOM, _NAK)
        FI
      ELSE      
        rxabort = 1
      FI
      BREAK
    FI
  LOOP
  IF rxabort
    BREAK
  FI
  ; Elimina l'EOB precedente (se necessario)
  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
      ; Elabora il 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)

; L'inizio del frame è valido?
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

; Verifica End of block
IF STRNEQ(RIGHT(s, 1), _EOB)
  RETURN 0
FI

; Elimina End Of Block
s = LEFT(s, -1)

; Isola LRC
lrc = RIGHT(s, 2)

; Elimina LRC
s = LEFT(s, -2)

; Isola ETB
etb = RIGHT(s, 1)

; Il carattere che precede LRC deve essere ETB o ETX (ultimo blocco)
IF AND(STRNEQ(etb, _ETB), STRNEQ(etb, _ETX))
  RETURN 0
FI

; Verifica LRC
IF NOT(VerifyLRC(lrc, s, firstblock))
  RETURN 0
FI

; Controlla se è l'ultimo blocco ed aggiorna il relativo parametro
lastblock = STREQ(RIGHT(s, 1), _ETX)

; Memorizza il 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 di tutti i caratteri in s
FOR x = 1 to l
  NXOR(@acc, ASC(SUBSTR(s, x, 1)))
NEXT
; Imposta il bit più significativo
IF firstblock 
  NAND(@acc, 0x7F)
ELSE
  IF MOD(l, 2)
    NOR(@acc, 0x80)  
  ELSE
    NAND(@acc, 0x7F)
  FI
FI
; Calcola c1 e 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)

; Variante con salvataggio/ripristino finestra corrente e selezione blocco notes
;   ; Preleva la finestra corrente
;   hOld = W32GETFOCUS()
;     
;   ; Cerca il blocco notes
;   hNotepad = W32FINDWINDOW("*Blocco note*")
;   IF EQ(hNotepad, 0)
;     ; Non trovato - lo lancia
;     W32SHELL("NOTEPAD.EXE")
;     ; Attende un secondo che si renda disponibile
;     SLEEP(1)
;     ; Cerca la sua finestra nuovamente
;     hNotepad = W32FINDWINDOW("*Notepad*")
;   FI
;   ; Se trovato, seleziona la sua finestra ed invia i dati
;   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
; Variante - ripristina la vecchia finestra
;   W32SETFOCUS(hOld)
RETURN


FUNCTION ProcessRecord(stime, scode, sbartype, sqt)

; Se si vuole selezionare una particola finestra, si può utilizzare 
; un'espressione simile alla seguente:
; 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)
  ; Mappatura dei caratteri speciali: caratteri che non si trovano
  ; sulla tastiera potrebbero richiedere l'introduzione della sequenza
  ; con ALT + numero
  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)

; Apre la porta seriale con i parametri specificati
hcom = W32CREATEFILE(comport, NOR(_W32_GENERIC_WRITE, _W32_GENERIC_READ), 0, \
                     _W32_OPEN_EXISTING, 0)

IF EQ(hcom, -1)
  !ifndef SERVICE
    CONSOLELN "Impossibile aprire " comport "."
  !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 "Errore nell'impostazione della porta (" 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
Midnight Lake iPhone Case Black Women Shoes Black Flat Shoes Leather Flats Black Patent Ballerinas Black Ballet Shoes Casual Shoes Black Shoes Women Balle Record Player Cufflinks Best iPhone XR Clear Cases iPhone XS/XS Max Leather Cases Sale Best iPhone 8/8 Plus Silicone Cases iPhone 7/7 Plus Cases & Screen Protector New Cases For iPhone 6/6 Plus iPhone 8 Case Sale iPhone Xr Case Online iPhone 7 Case UK Online iPhone X Case UK Sale iPhone X Case Deals iPhone Xs Case New Case For iPhone Xr UK Online Case For iPhone 8 UK Outlet Fashion Silver Cufflinks For Men Best Mens Cufflinks Outlet Online The Gold Cufflinks Shop Online Cheap Shirt Cufflinks On Sale Nice Wedding Cufflinks UK Online Top Black Cufflinks UK Online Mens Cufflinks Online Silver Cufflinks For Men Men Cufflinks UK Sale Gold Cufflinks UK Online Gold Cufflinks UK Silver Cufflinks UK Shirt Cufflinks Discount Online Mens Cufflinks Deals & Sales Girls Shoes For Dance Fashion Ballet Dance Shoes Best Ballet Flats Shoes UK Online Cheap Ballet Pointe Shoes UK Online Best Ballet Shoes Outlet Best Dance Shoes Sale Cheap Ballet Flats Sale UK Best Pointe Shoes Online UK Ballet Dance Shoes UK Shoes For Dance UK Best Ballet Slippers Shop Best Yoga Shoes Hotsell