; 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