; ACKNAK32
;
; Programma per Proteus
;
; (C) 2004 Simone Zanella Productions
;
; Riceve dati da un terminale connesso via RS-232 che comunica con il protocollo Datalogic Ack-Nak PC32;
; i dati ricevuti (se la trasmissione ha avuto successo) sono successivamente introdotti in emulazione di
; tastiera - ogni dato è terminato da Enter (Invio).
; 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)
;
; 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;
; - TIMEOUT: timeout (in millisecondi) per la ricezione di un pacchetto dal terminale;
; - EVALFIRSTBLOCK: indica se il primo pacchetto debba essere valutato o scartato;
; - CHARDELAY: ritardo intercarattere per la trasmissione;
; - DTRDELAY: intervallo per l'abbassamento del segnale DTR;
; - NAKSTREAM: numero di NAK inviati per forzare un abort della trasmissione (out-of-sync).
;
; 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 configurazione
; ---------------------------

; Porta seriale
COMPORT = "COM1"
; Baud rate
COMSPEED = 9600
; Parità (None, Odd, Even, Mark, Space: solo iniziale)
COMPARITY = "N"
; Bit di dati
COMDATA = 8
; 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 = 0.5

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

; Valuta o meno il primo blocco inviato (di solito utilizzato per identificare il nome del file)
EVALFIRSTBLOCK = 1

; Ritardo intercarattere
CHARDELAY = 0.001

; Tempo di alzata DTR
DTRDELAY = 0.002

; Numero di NAK inviati per "scollegare" un terminale dopo un timeout
NAKSTREAM = 10

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

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

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

WHILE 1
  ; Attende l'intervallo di poll
  SLEEP(POLLINTERVAL)
  
  R = W32READCOM(HCOM, 0)
  IF STRLEN(R)
    Q = MSRicevi232(R)
    IF NEQ(Q, -1)
      WHILE QUEUELEN(Q)
        L = DEQUEUE(Q)
        ; Se si vuole selezionare una particola finestra, si può utilizzare 
        ; un'espressione simile alla seguente:
        ; W32SETFOCUS(W32FINDWINDOW("*ULTRAEDIT-32*"))
        W32SENDKEYS(KTrans(L) "{ENTER}")
        SLEEP(PACE)
      LOOP
      QUEUEFREE(Q)
    FI    
    ; Variante con salvataggio/ripristino finestra corrente e selezione blocco notes
    ; IF NEQ(Q, -1)
    ;   ; Preleva la finestra corrente
    ;   HOLD = W32GETFOCUS()
    ;     
    ;   ; Cerca il blocco notes
    ;   H = W32FINDWINDOW("*Blocco note*")
    ;   IF EQ(H, 0)
    ;     ; Non trovato - lo lancia
    ;     W32SHELL("NOTEPAD.EXE")
    ;     ; Attende un secondo che si renda disponibile
    ;     SLEEP(1)
    ;     ; Cerca la sua finestra nuovamente
    ;     H = W32FINDWINDOW("*Blocco note*")
    ;   FI
    ;   ; Se trovato, seleziona la sua finestra ed invia i dati
    ;   IF NEQ(H, 0)
    ;     W32SETFOCUS(H)
    ;     WHILE QUEUELEN(Q)
    ;       L = DEQUEUE(Q)
    ;       W32SENDKEYS(KTrans(L) "{ENTER}")
    ;       SLEEP(PACE)
    ;     LOOP
    ;   ELSE
    ;     ; Impossibile aprire il blocco notes - dati persi!
    ;   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)
  ; 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)

; Apertura seriale con parametri richiesti
hcom = W32CREATEFILE(comport, NOR(_W32_GENERIC_WRITE, _W32_GENERIC_READ), 0, \
                     _W32_OPEN_EXISTING, 0)

IF EQ(hcom, -1)
  CONSOLELN "Impossibile aprire " comport "."
  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 "Errore nell'impostazione della porta (" 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 MSRicevi232(r)

q = QUEUENEW()
ct = 0
nacknum = 0
fine = "-0000FF" CHR(13)
firstblock = _EVALFIRSTBLOCK

; Riceve blocco
s = ""

; Riceve un pacchetto, con timeout.
WHILE 1
  IF STRLEN(r)
    s = s r
    IF LT(STRLEN(s), ADD("0x" SUBSTR(s, 2, 2), 8))
      ; Blocco incompleto: attende la ricezione dei bytes residui      
      r = W32READCOM(_HCOM, 0)
      CONTINUE
    FI
    s = left(s, ADD("0x" SUBSTR(s, 2, 2), 8))

    ; Pacchetto completo: lo controllo
    IF STREQ(s, fine)
      ; File ricevuto completamente: invia ACK sulla linea
      SendChar(_ACK)
      RETURN q        
    ELSE
      IF AckNackCheckPacket(s, ct)
        W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR))

        ; Controllo ok: invia ACK sulla linea
        SendChar(_ACK)       
        IF NOT(firstblock)
          s = SUBSTR(s, 5, SUB(STRLEN(s), 8))
          ENQUEUE(q, s)
        ELSE
          ; Ignora il primo blocco (nome del file?)
          firstblock = 0
        FI
          
        ; Resetta il numero di nack
        nacknum = 0          
        s = ""
      ELSE
        ; Verifica che non stia riprovando ad inviare
        ; il blocco precedente; in caso affermativo,
        ; lo ignora, perché è già stato salvato
        ; correttamente ed invia un ACK

        ct2 = DEC(ct)
        IF LT(ct2, 0)
          ct2 = 9
        FI
        
        IF AckNackCheckPacket(s, ct2)
          W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR))
      
          ; Controllo ok: invia ACK sulla linea
          SendChar(_ACK)
        
          ; Resetta il numero di nack ed il timeout
          nacknum = 0
          s = ""
        ELSE
          ; Controllo fallito: invia NACK sulla linea
          SendChar(_NAK)
          
          W32PURGECOM(_HCOM, NOR(_W32_PURGE_TXCLEAR, _W32_PURGE_RXCLEAR))
          INC(@nacknum)           
          IF GT(nacknum, 31)
            SendChar(REPLICATE(_NAK, _NAKSTREAM))

            ; Troppi nack: ricezione fallita
            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(blocco, @contatore)

; Verifica se il pacchetto è corretto; in caso affermativo, incrementa il contatore
IF OR(STRNEQ(LEFT(blocco, 1), "-"), \
      STRNEQ(RIGHT(blocco, 1), CHR(13)), \
      NEQ(LEFT(RIGHT(blocco, 4), 1), contatore), \
      STRNEQ(CheckSum(SUBSTR(blocco, 2, SUB(STRLEN(blocco), 4))), LEFT(RIGHT(blocco, 3), 2)))
  RETURN 0
ELSE
  INC(@contatore)
  IF GT(contatore, 9)
    contatore = 0
  FI
FI
RETURN 1


FUNCTION CheckSum(dati)

; Calcola il check digit
chk = 0
dl = STRLEN(dati)
FOR x = 1 TO dl
  ADD(@chk, ASC(SUBSTR(dati, x, 1)))
NEXT
MOD(@chk, 256)
RETURN PFORMAT("02X", chk)


FUNCTION SendChar(s)

; Abbassa il DTR
W32ESCCOMFUNC(_HCOM, _W32_COM_CLRDTR)
SLEEP(_CHARDELAY)
W32WRITEFILE(_HCOM, s)
; Attende che si sia svuotato il buffer di trasmissione
W32WAITTXOVER(_HCOM, 1000)
SLEEP(_DTRDELAY)
; Alza il DTR
W32ESCCOMFUNC(_HCOM, _W32_COM_SETDTR)
RETURN
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