diff --git a/CVCncLib/CVCncLib.dll b/CVCncLib/CVCncLib.dll index c3a4dc4e..6d229969 100644 Binary files a/CVCncLib/CVCncLib.dll and b/CVCncLib/CVCncLib.dll differ diff --git a/IOB-WIN/DATA/CONF/3001.ini b/IOB-WIN/DATA/CONF/3001.ini index a320dc5b..48e7be25 100644 --- a/IOB-WIN/DATA/CONF/3001.ini +++ b/IOB-WIN/DATA/CONF/3001.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=TORNOS @@ -32,6 +31,7 @@ AREAY_SIZE=16 ;BIT0=CONN BIT1=Y8.6 BIT2=PZCOUNT.D.6416.DW +;BIT2=X7.1 BIT3=Y8.4 BIT4=Y8.5 AREAD_START=0 @@ -60,18 +60,15 @@ BLINK_FILT=0 ;BLINK_FILT=28 [OPTPAR] -;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice -; attenzione memoria sempre base BYTE (1604 DW --> 6416...) -PZCOUNT_MODE=STD.D.6416.DW -PZREQ_MODE=STD.D.6412.DW -PZCAD_MODE=STD.D.6408.DW -PZGTOT_MODE=STD.D.6420.DW -ENABLE_PZ_RESET=TRUE -ENABLE_PZ_RESET_stopSetup=FALSE -;PZ_DONE_MADDR=1604; pz fatti -;PZ_REQ_MADDR=1603; pz richiesti (DW) +;PZCOUNT_MODE=STD|BIT +;PZCOUNT_MODE=BIT.X7.1 +PZCOUNT_MODE=STD.D.6416.DW ;PZ_CAD_MADDR=1602; cad +;PZ_REQ_MADDR=1603; pz richiesti (DW) +;PZ_DONE_MADDR=1604; pz fatti ;PZ_GTOT_MADDR=1605; pz tot macchina +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master \ No newline at end of file +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3002.ini b/IOB-WIN/DATA/CONF/3002.ini index 2ed4c474..1f96923e 100644 --- a/IOB-WIN/DATA/CONF/3002.ini +++ b/IOB-WIN/DATA/CONF/3002.ini @@ -1,14 +1,13 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=TORNOS MODEL=DT26 [CNC] -; TORNOS DT26 II (IOT ENABLED) +; TORNOS DT26 II IOT ENABLED IP=172.16.199.10 PORT=8193 GETPRGNAME=true @@ -32,6 +31,7 @@ AREAY_SIZE=16 ;BIT0=CONN BIT1=Y8.6 BIT2=PZCOUNT.D.6416.DW +;BIT2=X7.1 BIT3=Y8.4 BIT4=Y8.5 AREAD_START=0 @@ -50,27 +50,25 @@ PAR_SIZE=3 MAX_COUNTER_BLINK = 15 ;bit0 = 0 ;bit1 = 0 -;bit2 = 1 +;bit2 = 0 ;bit3 = 1 ;bit4 = 1 ;bit5 = 0 ;bit6 = 0 ;bit7 = 0 -BLINK_FILT=0 +BLINK_FILT=24 ;BLINK_FILT=28 [OPTPAR] -;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice -; attenzione memoria sempre base BYTE (1604 DW --> 6416...) -PZCOUNT_MODE=STD.D.6416.DW -PZREQ_MODE=STD.D.6412.DW -PZCAD_MODE=STD.D.6408.DW -PZGTOT_MODE=STD.D.6420.DW -ENABLE_PZ_RESET=TRUE -;PZ_DONE_MADDR=1604; pz fatti -;PZ_REQ_MADDR=1603; pz richiesti (DW) +;PZCOUNT_MODE=STD|BIT +;PZCOUNT_MODE=BIT.X7.1 +PZCOUNT_MODE=STD.D.6416.DW ;PZ_CAD_MADDR=1602; cad +;PZ_REQ_MADDR=1603; pz richiesti (DW) +;PZ_DONE_MADDR=1604; pz fatti ;PZ_GTOT_MADDR=1605; pz tot macchina +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3003.ini b/IOB-WIN/DATA/CONF/3003.ini index 0553dbcd..dde1515f 100644 --- a/IOB-WIN/DATA/CONF/3003.ini +++ b/IOB-WIN/DATA/CONF/3003.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=CMZ @@ -61,12 +60,17 @@ BLINK_FILT=0 [OPTPAR] ;PZCOUNT_MODE=STD|BIT -PZCOUNT_MODE=STD.PAR.6711 -ENABLE_PZ_RESET=TRUE +PZCOUNT_MODE=STD.PAR.6711 ;PZ_CAD_MADDR=1602 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3004.ini b/IOB-WIN/DATA/CONF/3004.ini index c07d5863..f66d5a04 100644 --- a/IOB-WIN/DATA/CONF/3004.ini +++ b/IOB-WIN/DATA/CONF/3004.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=BIGLIA @@ -33,7 +32,7 @@ AREAY_SIZE=12 BIT1=Y4.5 BIT2=PZCOUNT.PAR.6711 BIT3=Y3.2 -BIT4=Y8.0 +BIT4=Y8.0 BIT5=Y2.0 AREAD_START=0 AREAD_SIZE=9999 @@ -67,6 +66,12 @@ PZCOUNT_MODE=STD.PAR.6711 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=5 +MAX_SEND_PZC_BLOCK=100 [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3005.ini b/IOB-WIN/DATA/CONF/3005.ini index baee4d8b..a9934b75 100644 --- a/IOB-WIN/DATA/CONF/3005.ini +++ b/IOB-WIN/DATA/CONF/3005.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=BIGLIA @@ -32,7 +31,7 @@ AREAY_SIZE=12 ;BIT0=CONN BIT1=Y4.5 BIT2=PZCOUNT.PAR.6711 -BIT3=Y3.2 +BIT3=Y3.2 BIT4=Y8.0 BIT5=Y2.0 AREAD_START=0 @@ -67,6 +66,12 @@ PZCOUNT_MODE=STD.PAR.6711 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=5 +MAX_SEND_PZC_BLOCK=100 [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3006.ini b/IOB-WIN/DATA/CONF/3006.ini index e31255f0..fce3e9b7 100644 --- a/IOB-WIN/DATA/CONF/3006.ini +++ b/IOB-WIN/DATA/CONF/3006.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=HANWHA @@ -62,10 +61,12 @@ BLINK_FILT=8 [OPTPAR] ;PZCOUNT_MODE=STD|BIT PZCOUNT_MODE=STD.PAR.6711 -;PZ_CAD_MADDR=1602 -;PZ_REQ_MADDR=1603 -;PZ_DONE_MADDR=1604 -;PZ_GTOT_MADDR=1605 +PZ_CAD_MADDR=1602 +PZ_REQ_MADDR=1603 +PZ_DONE_MADDR=1604 +PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3007.ini b/IOB-WIN/DATA/CONF/3007.ini index a1d8be14..b69840bf 100644 --- a/IOB-WIN/DATA/CONF/3007.ini +++ b/IOB-WIN/DATA/CONF/3007.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=STAR @@ -35,13 +34,13 @@ BIT2=PZCOUNT.PAR.6711 BIT3=Y0.2 BIT4=Y1.2 AREAD_START=0 -AREAD_SIZE=9999 +AREAD_SIZE=0 AREAR_START=0 -AREAR_SIZE=64 +AREAR_SIZE=0 AREAX_START=0 -AREAX_SIZE=64 +AREAX_SIZE=0 AREAY_START=0 -AREAY_SIZE=64 +AREAY_SIZE=0 PAR_START=6711 PAR_SIZE=3 @@ -62,10 +61,12 @@ BLINK_FILT=8 [OPTPAR] ;PZCOUNT_MODE=STD|BIT PZCOUNT_MODE=STD.PAR.6711 -;PZ_CAD_MADDR=1602 -;PZ_REQ_MADDR=1603 -;PZ_DONE_MADDR=1604 -;PZ_GTOT_MADDR=1605 +PZ_CAD_MADDR=1602 +PZ_REQ_MADDR=1603 +PZ_DONE_MADDR=1604 +PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3010.ini b/IOB-WIN/DATA/CONF/3010.ini index 49073cfa..54214040 100644 --- a/IOB-WIN/DATA/CONF/3010.ini +++ b/IOB-WIN/DATA/CONF/3010.ini @@ -1,11 +1,10 @@ ;Configurazione IOB-WIN [IOB] CNCTYPE=SIEMENS_TORRI -PING_MS_TIMEOUT=500 [MACHINE] VENDOR=TORRI -MODEL=VUOMARD V100 +MODEL=VUOMARD [CNC] ; Siemens Torri (Vuomard) @@ -30,11 +29,11 @@ ADDR_WRITE=DB701.DBB0 SIZE_READ=52 SIZE_WRITE=138 ;BIT0=CONN -BIT1=DB700.DBB.0.1 +BIT1=DB700.DBB1 ;BIT2=PZCOUNT.STD.DB700.DBW22 -BIT3=DB700.DBB.0.3 -BIT4=DB700.DBB.0.4 -BIT5=DB700.DBB.1.4 ; bit ciclo in test == riscaldamento +BIT3=DB700.DBB3 +BIT4=DB700.DBB4 +BIT5=DB701.DBB4 ; bit ciclo in test == riscaldamento [BLINK] @@ -59,6 +58,8 @@ PZCOUNT_MODE=STD.DB700.DBW22 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3011.ini b/IOB-WIN/DATA/CONF/3011.ini index 4f01e8bc..518386b8 100644 --- a/IOB-WIN/DATA/CONF/3011.ini +++ b/IOB-WIN/DATA/CONF/3011.ini @@ -1,6 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=SIEMENS_TORRI +CNCTYPE=SIEMENS_TORRI PING_MS_TIMEOUT=500 [MACHINE] @@ -14,7 +14,7 @@ CPUTYPE=S7300 RACK=0 SLOT=2 -[SERVER] +[SERVER] MPIP=http://192.168.1.7 MPURL=/MP/IO CMDBASE=/IOB/input/ @@ -29,12 +29,12 @@ ADDR_READ=DB700.DBB0 ADDR_WRITE=DB701.DBB0 SIZE_READ=52 SIZE_WRITE=138 -;BIT0=CONN -BIT1=DB700.DBB.0.1 +;BIT0=CONN +BIT1=DB700.DBB1 ;BIT2=PZCOUNT.STD.DB700.DBW22 -BIT3=DB700.DBB.0.3 -BIT4=DB700.DBB.0.4 -BIT5=DB700.DBB.1.4 ; bit ciclo in test == riscaldamento +BIT3=DB700.DBB3 +BIT4=DB700.DBB4 +BIT5=DB701.DBB4 ;bit ciclo in test == riscaldamento [BLINK] @@ -59,6 +59,8 @@ PZCOUNT_MODE=STD.DB700.DBW22 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3012.ini b/IOB-WIN/DATA/CONF/3012.ini index d6179d92..3e0a95b1 100644 --- a/IOB-WIN/DATA/CONF/3012.ini +++ b/IOB-WIN/DATA/CONF/3012.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=FANUC -PING_MS_TIMEOUT=500 +CNCTYPE=FANUC [MACHINE] VENDOR=TAKAHASHI @@ -66,6 +65,12 @@ PZCOUNT_MODE=STD.PAR.6711 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3013.ini b/IOB-WIN/DATA/CONF/3013.ini index 713ea450..9f975a6b 100644 --- a/IOB-WIN/DATA/CONF/3013.ini +++ b/IOB-WIN/DATA/CONF/3013.ini @@ -1,7 +1,6 @@ ;Configurazione IOB-WIN [IOB] -CNCTYPE=SIEMENS_TORRI -PING_MS_TIMEOUT=500 +CNCTYPE=SIEMENS_TORRI [MACHINE] VENDOR=TORRI @@ -29,12 +28,12 @@ ADDR_READ=DB700.DBB0 ADDR_WRITE=DB701.DBB0 SIZE_READ=52 SIZE_WRITE=138 -;BIT0=CONN -BIT1=DB700.DBB.0.1 +;BIT0=CONN +BIT1=DB700.DBB1 ;BIT2=PZCOUNT.STD.DB700.DBW22 -BIT3=DB700.DBB.0.3 -BIT4=DB700.DBB.0.4 -BIT5=DB700.DBB.1.4 ; bit ciclo in test == riscaldamento +BIT3=DB700.DBB3 +BIT4=DB700.DBB4 +BIT5=DB701.DBB4 ; bit ciclo in test == riscaldamento [BLINK] @@ -59,6 +58,8 @@ PZCOUNT_MODE=STD.DB700.DBW22 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=FALSE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3015.ini b/IOB-WIN/DATA/CONF/3015.ini index a1e1450b..d61f7ea7 100644 --- a/IOB-WIN/DATA/CONF/3015.ini +++ b/IOB-WIN/DATA/CONF/3015.ini @@ -10,7 +10,8 @@ MODEL=SPRINT-32-5 [CNC] ; DMG MORI (IOT ENABLED) IP=192.168.0.12 -PORT=8193 +PORT=19000 +;PORT=8193 GETPRGNAME=true [SERVER] @@ -35,23 +36,24 @@ CMDREBO=/sendReboot.aspx?idxMacchina= ;6) prog in RUN Y5.0 (pag 6 di 12) [MEMORY] +AREAG_SIZE=48 +AREAR_SIZE=0 +AREAX_SIZE=8 +AREAY_SIZE=16 ; Red: Y1.1 | Yellow: Y1.2 | Green Y1.3 | All DoorsClosed: Y4.0 (X5.1) | ..........WrkZone Y8.7 | PZ richiesti: D.7960.DW - PZ prodotti: D.7964.DW ;BIT0=CONN BIT1=Y1.3 BIT2=PZCOUNT.D.7964.DW -BIT3=Y1.1 +BIT3=Y1.1 BIT4=Y1.2 -BIT5=Y1.0 ; blu = feed <= 70 -;BIT6=Y5.0 ; RUN AREAD_START=0 -AREAD_SIZE=99 ;9999 -AREAG_SIZE=48 -AREAR_START=7500 ;0 +AREAD_SIZE=9999 +AREAR_START=0 AREAR_SIZE=64 AREAX_START=0 -AREAX_SIZE=8 ;64 +AREAX_SIZE=64 AREAY_START=0 -AREAY_SIZE=16 ;64 +AREAY_SIZE=64 PAR_START=6711 PAR_SIZE=3 @@ -77,6 +79,8 @@ PZCOUNT_MODE=STD.D.7964.DW ;PZ_REQ_MADDR=1990; pz richiesti (DW) ;PZ_DONE_MADDR=1991; pz fatti (DW) ;PZ_GTOT_MADDR=???; pz tot macchina +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3017.ini b/IOB-WIN/DATA/CONF/3017.ini index eae11b17..4a594292 100644 --- a/IOB-WIN/DATA/CONF/3017.ini +++ b/IOB-WIN/DATA/CONF/3017.ini @@ -52,12 +52,11 @@ BLINK_FILT=0 [OPTPAR] ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice -; attenzione memoria sempre base BYTE (1604 DW --> 6416...) +; attenzione memoria sempre base BYTE (1604 DW --> 6416...) ;PZCOUNT_MODE=STD.DB550.DBDW0 -PZCOUNT_MODE=NONE +PZCOUNT_MODE=NONE DISABLE_PZCOUNT=TRUE ENABLE_DYN_DATA=TRUE -FORCE_DYN_DATA=TRUE TSVC_pressCamFilt=MAX:60 TSVC_pressLinUt=MAX:60 TSVC_tempH2O=MAX:60 @@ -65,6 +64,8 @@ TSVC_tempH2O=MAX:60 ;PZ_REQ_MADDR=1603 ;PZ_DONE_MADDR=1604 ;PZ_GTOT_MADDR=1605 +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE [BRANCH] -NAME=master +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/3018.ini b/IOB-WIN/DATA/CONF/3018.ini index 122d6197..735425f9 100644 --- a/IOB-WIN/DATA/CONF/3018.ini +++ b/IOB-WIN/DATA/CONF/3018.ini @@ -55,6 +55,12 @@ PZCOUNT_MODE=NONE DISABLE_PZCOUNT=TRUE ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; gestione custom timer +timerIntMs=50 ; CONF variabili da recuperare in WebPage (stato macchina, contatori, variabili, ...) LUT_CONF=3018.json diff --git a/IOB-WIN/DATA/CONF/3018.json b/IOB-WIN/DATA/CONF/3018.json index 919cf07d..a817709d 100644 --- a/IOB-WIN/DATA/CONF/3018.json +++ b/IOB-WIN/DATA/CONF/3018.json @@ -57,13 +57,11 @@ "codeMapping": { "Spento": "00", "PowerOn": "01", + "Attesa": "01", "Carico": "03", "A vuoto": "05", "Riserva": "09", - "Alarm": "11", - "STATUS_6": "20", - "STATUS_7": "40", - "STATUS_8": "80" + "Alarm": "11" } } ] diff --git a/IOB-WIN/DATA/CONF/3019.ini b/IOB-WIN/DATA/CONF/3019.ini index 27045c70..db627e9e 100644 --- a/IOB-WIN/DATA/CONF/3019.ini +++ b/IOB-WIN/DATA/CONF/3019.ini @@ -55,8 +55,14 @@ PZCOUNT_MODE=NONE DISABLE_PZCOUNT=TRUE ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; gestione custom timer +timerIntMs=50 ; CONF variabili da recuperare in WebPage (stato macchina, contatori, variabili, ...) -LUT_CONF=3018.json +LUT_CONF=3019.json [BRANCH] NAME=master diff --git a/IOB-WIN/DATA/CONF/3019.json b/IOB-WIN/DATA/CONF/3019.json index 9660c634..93533b10 100644 --- a/IOB-WIN/DATA/CONF/3019.json +++ b/IOB-WIN/DATA/CONF/3019.json @@ -57,13 +57,11 @@ "codeMapping": { "Spento": "00", "PowerOn": "01", + "Attesa": "01", "Carico": "03", "A vuoto": "05", "Riserva": "09", - "Alarm": "11", - "STATUS_6": "20", - "STATUS_7": "40", - "STATUS_8": "80" + "Alarm": "11" } } ] diff --git a/IOB-WIN/DATA/CONF/3020.ini b/IOB-WIN/DATA/CONF/3020.ini index c97f0e5e..a18632f7 100644 --- a/IOB-WIN/DATA/CONF/3020.ini +++ b/IOB-WIN/DATA/CONF/3020.ini @@ -5,7 +5,7 @@ PING_MS_TIMEOUT=500 [MACHINE] VENDOR=TORRI -MODEL=VUOMARD V110 +MODEL=GHIRINGHELLI [CNC] ; Siemens Torri (Vaumard) diff --git a/IOB-WIN/DATA/CONF/3021.ini b/IOB-WIN/DATA/CONF/3021.ini new file mode 100644 index 00000000..ed8b096a --- /dev/null +++ b/IOB-WIN/DATA/CONF/3021.ini @@ -0,0 +1,73 @@ +;Configurazione IOB-WIN +[IOB] +CNCTYPE=FANUC + +[MACHINE] +VENDOR=CITIZEN +MODEL=GN-3200 + +[CNC] +; CITIZEN RETTIFICA 3021 +IP=192.168.0.24 +PORT=8193 +GETPRGNAME=true + +[SERVER] +MPIP=http://192.168.1.7 +MPURL=/MP/IO +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/sendReboot.aspx?idxMacchina= + +[MEMORY] +; Red: Y2.0 | Yellow: Y1.7 | Green Y2.1 | riscaldamento Y7.4 | D19.1 MANCA PEZZO (SE rosso) +;BIT0=CONN +BIT1=Y2.1 +BIT2=PZCOUNT.PAR.6711 +BIT3=Y2.0 +BIT4=Y1.7 +BIT5=Y7.4 +AREAD_START=0 +AREAD_SIZE=0 +AREAG_SIZE=48 +AREAR_START=0 +AREAR_SIZE=0 +AREAX_START=0 +AREAX_SIZE=0 +AREAY_START=0 +AREAY_SIZE=8 +PAR_START=6711 +PAR_SIZE=3 + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 0 +;bit3 = 0 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=16 + +[OPTPAR] +;PZCOUNT_MODE=STD|BIT +PZCOUNT_MODE=STD.PAR.6711 +PZGTOT_MODE=STD.PAR.6712 +PZREQ_MODE=STD.PAR.6713 +;PZCAD_MODE=STD.D.6408.DW +ENABLE_PZ_RESET=TRUE +ENABLE_PZ_RESET_stopSetup=TRUE +;gestione invio pezzi in blocco +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=5 +MAX_SEND_PZC_BLOCK=100 + +[BRANCH] +NAME=develop \ No newline at end of file diff --git a/IOB-WIN/DATA/CONF/VL21.ini b/IOB-WIN/DATA/CONF/VL21.ini index f72c3df2..b4d650aa 100644 --- a/IOB-WIN/DATA/CONF/VL21.ini +++ b/IOB-WIN/DATA/CONF/VL21.ini @@ -1,6 +1,6 @@ ;Configurazione IOB-WIN [IOB] -;Macchina preriscaldo barre per Valvital +;Macchina DENTATRICE per Valvital CNCTYPE=SIEMENS_COMUR PING_MS_TIMEOUT=500 @@ -54,7 +54,7 @@ BLINK_FILT=0 [OPTPAR] ;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice ; attenzione memoria sempre base BYTE (1604 DW --> 6416...) -PZCOUNT_MODE=STD.DB111.DBD2 +PZCOUNT_MODE=SPEC.DB111.DBB2 DISABLE_PZCOUNT=TRUE ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE diff --git a/IOB-WIN/DATA/CONF/VL21.json b/IOB-WIN/DATA/CONF/VL21.json index 7ffc2667..ec9fe306 100644 --- a/IOB-WIN/DATA/CONF/VL21.json +++ b/IOB-WIN/DATA/CONF/VL21.json @@ -1,30 +1,52 @@ { - "mMapWrite": { - "setArt": { - "name": "setArt", - "description": "Articolo", - "memAddr": "DB150.DBB12", - "tipoMem": "String", - "index": 12, - "size": 20 + "mMapWrite": { + "setArt": { + "name": "setArt", + "description": "Articolo", + "memAddr": "DB150.DBB12", + "tipoMem": "String", + "index": 12, + "size": 20 + }, + "setComm": { + "name": "setComm", + "description": "Commessa", + "memAddr": "DB150.DBB32", + "tipoMem": "String", + "index": 32, + "size": 20 + }, + "setPzComm": { + "name": "setPzComm", + "description": "Qty", + "memAddr": "DB150.DBB8", + "tipoMem": "Int", + "index": 8, + "size": 4 + } }, - "setComm": { - "name": "setComm", - "description": "Commessa", - "memAddr": "DB150.DBB32", - "tipoMem": "String", - "index": 32, - "size": 20 - }, - "setPzComm": { - "name": "setPzComm", - "description": "Qty", - "memAddr": "DB150.DBB8", - "tipoMem": "Int", - "index": 8, - "size": 4 + "mMapRead": { + "CodUte": { + "name": "CodUte", + "description": "Codice Utensile in Uso", + "memAddr": "DB150.DBB56", + "tipoMem": "Int", + "index": 56, + "size": 4, + "func": "MAX", + "period": 60, + "factor": 1 + }, + "CodPezzo": { + "name": "CodPezzo", + "description": "Codice Pezzo in lavorazione", + "memAddr": "DB150.DBB52", + "tipoMem": "Int", + "index": 52, + "size": 4, + "func": "MAX", + "period": 60, + "factor": 1 + } } - }, - "mMapRead": { - } } \ No newline at end of file diff --git a/IOB-WIN/GlobalSuppressions.cs b/IOB-WIN/GlobalSuppressions.cs index 35bbaf73..4f496302 100644 --- a/IOB-WIN/GlobalSuppressions.cs +++ b/IOB-WIN/GlobalSuppressions.cs @@ -3,6 +3,8 @@ // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. +using System.Diagnostics.CodeAnalysis; + [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Gli identificatori non devono contenere caratteri di sottolineatura", Justification = "", Scope = "namespace", Target = "~N:IOB_WIN")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1305:Specificare IFormatProvider", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobSiemensSaet.processWhatchDog")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Globalization", "CA1303:Non passare valori letterali come parametri localizzati", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobSiemensSaet.#ctor(IOB_WIN.AdapterForm,IOB_WIN.IobConfiguration)")] @@ -36,4 +38,11 @@ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Le proprietà Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~P:IOB_WIN.MainForm.urlIob2call")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Le proprietà Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~P:IOB_WIN.MainForm.urlReboot")] [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Le proprietà Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~P:IOB_WIN.MainForm.urlUploadFile")] -[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Le proprietà Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~P:IOB_WIN.MainForm.urlUploadFileCloud")] \ No newline at end of file +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "CA1056:Le proprietà Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~P:IOB_WIN.MainForm.urlUploadFileCloud")] +[assembly: SuppressMessage("Usage", "CA2211:I campi non costanti non devono essere visibili", Justification = "", Scope = "member", Target = "~F:IOB_WIN.MainForm.lg")] +[assembly: SuppressMessage("Design", "CA1055:I valori restituiti di Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.callUrl(System.String,System.Boolean)~System.String")] +[assembly: SuppressMessage("Design", "CA1054:I parametri Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.callUrlWithPayload(System.String,System.String,System.Boolean)~System.String")] +[assembly: SuppressMessage("Design", "CA1055:I valori restituiti di Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.callUrlWithPayload(System.String,System.String,System.Boolean)~System.String")] +[assembly: SuppressMessage("Design", "CA1055:I valori restituiti di Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.urlDataBlock(IOB_UT.urlType)~System.String")] +[assembly: SuppressMessage("Design", "CA1055:I valori restituiti di Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.urlFLog(System.String)~System.String")] +[assembly: SuppressMessage("Design", "CA1055:I valori restituiti di Uri non devono essere stringhe", Justification = "", Scope = "member", Target = "~M:IOB_WIN.IobGeneric.urlInput(System.String)~System.String")] diff --git a/IOB-WIN/IOB-WIN.csproj b/IOB-WIN/IOB-WIN.csproj index 7275948e..380f56f9 100644 --- a/IOB-WIN/IOB-WIN.csproj +++ b/IOB-WIN/IOB-WIN.csproj @@ -275,10 +275,18 @@ - - - - + + Always + + + Always + + + Always + + + Always + Always diff --git a/IOB-WIN/IobFanuc.cs b/IOB-WIN/IobFanuc.cs index 7081ba83..32ff6a57 100644 --- a/IOB-WIN/IobFanuc.cs +++ b/IOB-WIN/IobFanuc.cs @@ -8,969 +8,969 @@ using System.Net.NetworkInformation; namespace IOB_WIN { - public class IobFanuc : IobGeneric - { - /// - /// Area memoria G (copia) - /// - protected byte[] MemBlockG = new byte[2]; - /// - /// Area memoria R (copia) - /// - protected byte[] MemBlockR = new byte[2]; - /// - /// Area memoria X (copia) - /// - protected byte[] MemBlockX = new byte[2]; - /// - /// Area memoria Y (copia) - /// - protected byte[] MemBlockY = new byte[2]; - /// - /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO - /// - Dictionary signLUT = new Dictionary(); - - /// - /// wrapper chiamata lettura/scrittura SINGOLO BYTE... - /// - /// - /// - /// - /// - /// - public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte Value) + public class IobFanuc : IobGeneric { - bool answ = false; - if (connectionOk) - { - if (FANUC_ref.Connected) + /// + /// Area memoria G (copia) + /// + protected byte[] MemBlockG = new byte[2]; + /// + /// Area memoria R (copia) + /// + protected byte[] MemBlockR = new byte[2]; + /// + /// Area memoria X (copia) + /// + protected byte[] MemBlockX = new byte[2]; + /// + /// Area memoria Y (copia) + /// + protected byte[] MemBlockY = new byte[2]; + /// + /// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO + /// + Dictionary signLUT = new Dictionary(); + + /// + /// wrapper chiamata lettura/scrittura SINGOLO BYTE... + /// + /// + /// + /// + /// + /// + public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte Value) { - try - { - parentForm.commPlcActive = true; - answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value); - } - catch - { } - } - } - parentForm.commPlcActive = false; - return answ; - } - /// - /// wrapper chiamata lettura/scrittura MULTI BYTE... - /// - /// - /// - /// - /// - /// - public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte[] Value) - { - bool answ = false; - if (connectionOk) - { - if (FANUC_ref.Connected) - { - try - { - parentForm.commPlcActive = true; - answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value); - } - catch - { } - } - } - parentForm.commPlcActive = false; - return answ; - } - /// - /// Oggetto MAIN x connessione FANUC - /// - protected FANUC FANUC_ref; - - /// - /// Dati dell'area D - /// - protected memAreaFanuc areaD; - /// - /// Dati dell'area PARameters - /// - protected memAreaFanuc areaPAR; - /// - /// Dati dell'area R - /// - protected memAreaFanuc areaR; - /// - /// Dati dell'area X - /// - protected memAreaFanuc areaX; - /// - /// Dati dell'area Y - /// - protected memAreaFanuc areaY; - - /// - /// estende l'init della classe base... - /// - /// - /// - public IobFanuc(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) - { - // i dati RAW principali sono 6 byte... - RawInput = new byte[6]; - - // gestione invio ritardato contapezzi - pzCountDelay = utils.CRI("pzCountDelay"); - lastPzCountSend = DateTime.Now; - lastWarnODL = DateTime.Now; - - // inizializzo correttamente aree memoria secondo CONF - iniFileName - IniFile fIni = new IniFile(IOBConf.iniFileName); - // inizializzo aree di memoria correnti... - MemBlockG = new byte[fIni.ReadInteger("MEMORY", "AREAG_SIZE", 8)]; - MemBlockR = new byte[fIni.ReadInteger("MEMORY", "AREAR_SIZE", 8)]; - MemBlockX = new byte[fIni.ReadInteger("MEMORY", "AREAX_SIZE", 8)]; - MemBlockY = new byte[fIni.ReadInteger("MEMORY", "AREAY_SIZE", 8)]; - // loggo aree di memoria avviate... - lgInfo(string.Format("Avviare area di memoria MemBlockG: {0} byte", MemBlockG.Length)); - lgInfo(string.Format("Avviare area di memoria MemBlockR: {0} byte", MemBlockR.Length)); - lgInfo(string.Format("Avviare area di memoria MemBlockX: {0} byte", MemBlockX.Length)); - lgInfo(string.Format("Avviare area di memoria MemBlockY: {0} byte", MemBlockY.Length)); - - // fix enable prgName - enablePrgName = fIni.ReadBoolean("CNC", "GETPRGNAME", true); - - // salvo le aree X-Y-D (per dump/sample/ottimizzazione lettura) - areaD = new memAreaFanuc - { - areaName = "AreaD", - startIdx = fIni.ReadInteger("MEMORY", "AREAD_START", 0), - arraySize = fIni.ReadInteger("MEMORY", "AREAD_SIZE", 0) - }; - areaPAR = new memAreaFanuc - { - areaName = "AreaPARR", - startIdx = fIni.ReadInteger("MEMORY", "PAR_START", 0), - arraySize = fIni.ReadInteger("MEMORY", "PAR_SIZE", 0) - }; - areaR = new memAreaFanuc - { - areaName = "AreaR", - startIdx = fIni.ReadInteger("MEMORY", "AREAR_START", 0), - arraySize = fIni.ReadInteger("MEMORY", "AREAR_SIZE", 0) - }; - areaX = new memAreaFanuc - { - areaName = "AreaX", - startIdx = fIni.ReadInteger("MEMORY", "AREAX_START", 0), - arraySize = fIni.ReadInteger("MEMORY", "AREAX_SIZE", 0) - }; - areaY = new memAreaFanuc - { - areaName = "AreaY", - startIdx = fIni.ReadInteger("MEMORY", "AREAY_START", 0), - arraySize = fIni.ReadInteger("MEMORY", "AREAY_SIZE", 0) - }; - lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaD.areaName, areaD.startIdx, areaD.arraySize)); - lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaR.areaName, areaR.startIdx, areaR.arraySize)); - lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaX.areaName, areaX.startIdx, areaX.arraySize)); - lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaY.areaName, areaY.startIdx, areaY.arraySize)); - - // effettuo lettura della conf sigLUT... cercando 1:1 i bit... - string currBit = ""; - string memArea = ""; - for (int i = 0; i < 8; i++) - { - currBit = string.Format("BIT{0}", i); - memArea = fIni.ReadString("MEMORY", currBit, ""); - // se trovo un valore... - if (!string.IsNullOrEmpty(memArea)) - { - signLUT.Add(currBit, memArea); - } - } - - // è little endian (NON serve conversione) - hasBigEndian = false; - lgInfo("Start init Adapter FANUC all'IP {0}:{1} per IOB {2}", IOBConf.cncIpAddr, IOBConf.cncPort, IOBConf.codIOB); - - // Creo oggetto connessione NC - parentForm.commPlcActive = true; - Runtime.CreateNC(CNC.NcType.FANUC, IOBConf.cncIpAddr, IOBConf.cncPort); - parentForm.commPlcActive = false; - - // aggiungo referenza obj FANUC - FANUC_ref = (FANUC)Runtime.NC; - if (isVerboseLog) - { - lgInfo("FANUC_ref da CncLib"); - } - - // disconnetto e connetto... - if (isVerboseLog) - { - lgInfo("FANUC: tryDisconnect"); - } - - tryDisconnect(); - lgInfo("FANUC: tryConnect"); - tryConnect(); - if (utils.CRB("enableContapezzi")) - { - lgInfo("FANUC: inizio gestione contapezzi"); - try - { - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - if (cIobConf.optPar.Count > 0 && !string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) - { - if (getOptPar("PZCOUNT_MODE").StartsWith("STD")) + bool answ = false; + if (connectionOk) { - lgInfo("Init contapezzi FANUC: pzCntReload(true)"); - pzCntReload(true); - // refresh associazione Macchina - IOB - sendM2IOB(); - // per adesso imposto lettura fanuc == contapezzi (poi farà vera lettura...) - lastCountCNC = contapezzi; + if (FANUC_ref.Connected) + { + try + { + parentForm.commPlcActive = true; + answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value); + } + catch + { } + } + } + parentForm.commPlcActive = false; + return answ; + } + /// + /// wrapper chiamata lettura/scrittura MULTI BYTE... + /// + /// + /// + /// + /// + /// + public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte[] Value) + { + bool answ = false; + if (connectionOk) + { + if (FANUC_ref.Connected) + { + try + { + parentForm.commPlcActive = true; + answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value); + } + catch + { } + } + } + parentForm.commPlcActive = false; + return answ; + } + /// + /// Oggetto MAIN x connessione FANUC + /// + protected FANUC FANUC_ref; + + /// + /// Dati dell'area D + /// + protected memAreaFanuc areaD; + /// + /// Dati dell'area PARameters + /// + protected memAreaFanuc areaPAR; + /// + /// Dati dell'area R + /// + protected memAreaFanuc areaR; + /// + /// Dati dell'area X + /// + protected memAreaFanuc areaX; + /// + /// Dati dell'area Y + /// + protected memAreaFanuc areaY; + + /// + /// estende l'init della classe base... + /// + /// + /// + public IobFanuc(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + // i dati RAW principali sono 6 byte... + RawInput = new byte[6]; + + // gestione invio ritardato contapezzi + pzCountDelay = utils.CRI("pzCountDelay"); + lastPzCountSend = DateTime.Now; + lastWarnODL = DateTime.Now; + + // inizializzo correttamente aree memoria secondo CONF - iniFileName + IniFile fIni = new IniFile(IOBConf.iniFileName); + // inizializzo aree di memoria correnti... + MemBlockG = new byte[fIni.ReadInteger("MEMORY", "AREAG_SIZE", 8)]; + MemBlockR = new byte[fIni.ReadInteger("MEMORY", "AREAR_SIZE", 8)]; + MemBlockX = new byte[fIni.ReadInteger("MEMORY", "AREAX_SIZE", 8)]; + MemBlockY = new byte[fIni.ReadInteger("MEMORY", "AREAY_SIZE", 8)]; + // loggo aree di memoria avviate... + lgInfo(string.Format("Avviare area di memoria MemBlockG: {0} byte", MemBlockG.Length)); + lgInfo(string.Format("Avviare area di memoria MemBlockR: {0} byte", MemBlockR.Length)); + lgInfo(string.Format("Avviare area di memoria MemBlockX: {0} byte", MemBlockX.Length)); + lgInfo(string.Format("Avviare area di memoria MemBlockY: {0} byte", MemBlockY.Length)); + + // fix enable prgName + enablePrgName = fIni.ReadBoolean("CNC", "GETPRGNAME", true); + + // salvo le aree X-Y-D (per dump/sample/ottimizzazione lettura) + areaD = new memAreaFanuc + { + areaName = "AreaD", + startIdx = fIni.ReadInteger("MEMORY", "AREAD_START", 0), + arraySize = fIni.ReadInteger("MEMORY", "AREAD_SIZE", 0) + }; + areaPAR = new memAreaFanuc + { + areaName = "AreaPARR", + startIdx = fIni.ReadInteger("MEMORY", "PAR_START", 0), + arraySize = fIni.ReadInteger("MEMORY", "PAR_SIZE", 0) + }; + areaR = new memAreaFanuc + { + areaName = "AreaR", + startIdx = fIni.ReadInteger("MEMORY", "AREAR_START", 0), + arraySize = fIni.ReadInteger("MEMORY", "AREAR_SIZE", 0) + }; + areaX = new memAreaFanuc + { + areaName = "AreaX", + startIdx = fIni.ReadInteger("MEMORY", "AREAX_START", 0), + arraySize = fIni.ReadInteger("MEMORY", "AREAX_SIZE", 0) + }; + areaY = new memAreaFanuc + { + areaName = "AreaY", + startIdx = fIni.ReadInteger("MEMORY", "AREAY_START", 0), + arraySize = fIni.ReadInteger("MEMORY", "AREAY_SIZE", 0) + }; + lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaD.areaName, areaD.startIdx, areaD.arraySize)); + lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaR.areaName, areaR.startIdx, areaR.arraySize)); + lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaX.areaName, areaX.startIdx, areaX.arraySize)); + lgInfo(string.Format("Salvata area di memoria: {0}, da {1} per {2} byte", areaY.areaName, areaY.startIdx, areaY.arraySize)); + + // effettuo lettura della conf sigLUT... cercando 1:1 i bit... + string currBit = ""; + string memArea = ""; + for (int i = 0; i < 8; i++) + { + currBit = string.Format("BIT{0}", i); + memArea = fIni.ReadString("MEMORY", currBit, ""); + // se trovo un valore... + if (!string.IsNullOrEmpty(memArea)) + { + signLUT.Add(currBit, memArea); + } + } + + // è little endian (NON serve conversione) + hasBigEndian = false; + lgInfo("Start init Adapter FANUC all'IP {0}:{1} per IOB {2}", IOBConf.cncIpAddr, IOBConf.cncPort, IOBConf.codIOB); + + // Creo oggetto connessione NC + parentForm.commPlcActive = true; + Runtime.CreateNC(CNC.NcType.FANUC, IOBConf.cncIpAddr, IOBConf.cncPort); + parentForm.commPlcActive = false; + + // aggiungo referenza obj FANUC + FANUC_ref = (FANUC)Runtime.NC; + if (isVerboseLog) + { + lgInfo("FANUC_ref da CncLib"); + } + + // disconnetto e connetto... + if (isVerboseLog) + { + lgInfo("FANUC: tryDisconnect"); + } + + tryDisconnect(); + lgInfo("FANUC: tryConnect"); + tryConnect(); + if (utils.CRB("enableContapezzi")) + { + lgInfo("FANUC: inizio gestione contapezzi"); + try + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + if (cIobConf.optPar.Count > 0 && !string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) + { + if (getOptPar("PZCOUNT_MODE").StartsWith("STD")) + { + lgInfo("Init contapezzi FANUC: pzCntReload(true)"); + pzCntReload(true); + // refresh associazione Macchina - IOB + sendM2IOB(); + // per adesso imposto lettura fanuc == contapezzi (poi farà vera lettura...) + lastCountCNC = contapezzi; + } + else + { + contapezzi = 0; + lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); + } + } + else + { + contapezzi = 0; + lgInfo("Parametro mancante PZCOUNT_MODE"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in contapezzi FANUC"); + } + } + // finisco INIT ADAPTER + lgInfo("End init Adapter FANUC"); + } + + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + case taskType.sendWatchDogMes2Plc: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.startSetup: + // reset contapezzi inizio setup + taskOk = resetContapezziCNC(); + taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.stopSetup: + // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO + if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") + { + taskOk = resetContapezziCNC(); + } + taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + default: + taskVal = "SKIPPED | NO EXEC"; + lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + } + return taskDone; + } + /// + /// Effettua reset del contapezzi + /// + /// + public override bool resetContapezziCNC() + { + bool answ = false; + // ...SE abilitato da conf IOB + if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE") + { + // scrivo valore 0 x il contapezzi + try + { + // contapezzi ATTUALE + if (!string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + string memAddr = getOptPar("PZCOUNT_MODE"); + if (memAddr.StartsWith("STD")) + { + // inizio verifica area memoria/parametro levando prima parte codice + memAddr = memAddr.Replace("STD.", ""); + // var di appoggio + int cntAddr = 0; + // var contapezzi a zero.... + object newVal = new object(); + newVal = 0; + // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 + if (memAddr.StartsWith("PAR.")) + { + // recupero parametro... + int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); + if (cntAddr == 0) + { + cntAddr = 6711; + } + + // processo RESET contapezzi (lavorati) + stopwatch.Restart(); + FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("W{0}-PAR", 4), stopwatch.ElapsedTicks); + } + } + // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW + else + { + memAddressFanuc areaCounter = new memAddressFanuc(memAddr); + + if (isVerboseLog) + { + lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); + } + // leggo! + stopwatch.Restart(); + // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato + switch (areaCounter.vType) + { + case "B": + byte valB = 0; + FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB); + newVal = valB; + break; + case "D": + ushort valW = 0; + FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW); + newVal = valW; + break; + case "DW": + uint valDW = 0; + FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW); + break; + default: + break; + } + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("W-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); + } + } + stopwatch.Stop(); + } + } + } + catch (Exception exc) + { + lgError(exc, "Errore in RESET contapezzi FANUC"); + connectionOk = false; + } + answ = true; + } + return answ; + } + + /// + /// Override disconnessione + /// + public override void tryDisconnect() + { + if (connectionOk) + { + string szStatusConnection = ""; + try + { + FANUC_ref.Disconnect(ref szStatusConnection); + connectionOk = false; + // resetto timing! + TimingData.resetData(); + lgInfo(szStatusConnection); + lgInfo("Effettuata disconnessione adapter FANUC!"); + } + catch (Exception exc) + { + lgFatal(exc, "Errore nella disconnessione dall'adapter FANUC"); + } } else { - contapezzi = 0; - lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); + lgError("IMPOSSIBILE effettuare disconnessione: Connessione non disponibile..."); } - } - else - { - contapezzi = 0; - lgInfo("Parametro mancante PZCOUNT_MODE"); - } } - catch (Exception exc) + /// + /// Override connessione + /// + public override void tryConnect() { - lgError(exc, "Errore in contapezzi FANUC"); - } - } - // finisco INIT ADAPTER - lgInfo("End init Adapter FANUC"); - } - - - /// - /// Processo i task richiesti e li elimino dalla coda 1:1 - /// - /// - public override Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - bool taskOk = false; - string taskVal = ""; - // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - switch (tName) - { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceResetPzCount: - case taskType.forceSetPzCount: - case taskType.setArt: - case taskType.setComm: - case taskType.setProg: - case taskType.sendWatchDogMes2Plc: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.startSetup: - // reset contapezzi inizio setup - taskOk = resetContapezziCNC(); - taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.stopSetup: - // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO - if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") + if (!connectionOk) { - taskOk = resetContapezziCNC(); + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) + { + if (verboseLog || periodicLog) + { + lgInfo("FANUC: ConnKO - tryConnect"); + } + // in primis salvo data ping... + lastPING = DateTime.Now; + // ora PING!!! + Ping pingSender = new Ping(); + IPAddress address = IPAddress.Loopback; + IPAddress.TryParse(cIobConf.cncIpAddr, out address); + PingReply reply = pingSender.Send(address, 100); + // se passa il ping faccio il resto... + if (reply.Status == IPStatus.Success) + { + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + FANUC_ref.Connect(ref szStatusConnection); + parentForm.commPlcActive = false; + lgInfo("szStatusConnection: " + szStatusConnection); + connectionOk = true; + // refresh stato allarmi!!! + if (connectionOk) + { + dtAvvioAdp = DateTime.Now; + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal(string.Format("Errore nella connessione all'adapter FANUC: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc)); + connectionOk = false; + lgInfo(string.Format("Eccezione in TryConnect, Adapter NON running, pausa di {0} msec prima di ulteriori tentativi di riconnessione", utils.CRI("waitRecMSec"))); + } + } + else + { + // loggo no risposta ping ... + connectionOk = false; + if (verboseLog || periodicLog) + { + lgInfo(string.Format("Attenzione: controllo PING fallito per IP {0} - {1}", cIobConf.cncIpAddr, reply.Status)); + } + } + } } - taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - default: - taskVal = "SKIPPED | NO EXEC"; - lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - } - return taskDone; - } - /// - /// Effettua reset del contapezzi - /// - /// - public override bool resetContapezziCNC() - { - bool answ = false; - // ...SE abilitato da conf IOB - if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE") - { - // scrivo valore 0 x il contapezzi - try - { - // contapezzi ATTUALE - if (!string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) - { - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - string memAddr = getOptPar("PZCOUNT_MODE"); - if (memAddr.StartsWith("STD")) + // se non è ancora connesso faccio procesisng memoria caso disconnesso... + if (!connectionOk) { - // inizio verifica area memoria/parametro levando prima parte codice - memAddr = memAddr.Replace("STD.", ""); - // var di appoggio - int cntAddr = 0; - // var contapezzi a zero.... - object newVal = new object(); - newVal = 0; - // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 - if (memAddr.StartsWith("PAR.")) - { - // recupero parametro... - int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); - if (cntAddr == 0) - { - cntAddr = 6711; - } - - // processo RESET contapezzi (lavorati) - stopwatch.Restart(); - FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("W{0}-PAR", 4), stopwatch.ElapsedTicks); - } - } - // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW - else - { - memAddressFanuc areaCounter = new memAddressFanuc(memAddr); - - if (isVerboseLog) - { - lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); - } - // leggo! - stopwatch.Restart(); - // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato - switch (areaCounter.vType) - { - case "B": - byte valB = 0; - FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB); - newVal = valB; - break; - case "D": - ushort valW = 0; - FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW); - newVal = valW; - break; - case "DW": - uint valDW = 0; - FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW); - break; - default: - break; - } - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("W-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); - } - } - stopwatch.Stop(); + // processo semafori ed invio... + processMemoryDiscon(); } - } } - catch (Exception exc) + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) { - lgError(exc, "Errore in RESET contapezzi FANUC"); - connectionOk = false; - } - answ = true; - } - return answ; - } - - /// - /// Override disconnessione - /// - public override void tryDisconnect() - { - if (connectionOk) - { - string szStatusConnection = ""; - try - { - FANUC_ref.Disconnect(ref szStatusConnection); - connectionOk = false; - // resetto timing! - TimingData.resetData(); - lgInfo(szStatusConnection); - lgInfo("Effettuata disconnessione adapter FANUC!"); - } - catch (Exception exc) - { - lgFatal(exc, "Errore nella disconnessione dall'adapter FANUC"); - } - } - else - { - lgError("IMPOSSIBILE effettuare disconnessione: Connessione non disponibile..."); - } - } - /// - /// Override connessione - /// - public override void tryConnect() - { - if (!connectionOk) - { - // controllo che il ping sia stato tentato almeno pingTestSec fa... - if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) - { - if (verboseLog || periodicLog) - { - lgInfo("FANUC: ConnKO - tryConnect"); - } - // in primis salvo data ping... - lastPING = DateTime.Now; - // ora PING!!! - Ping pingSender = new Ping(); - IPAddress address = IPAddress.Loopback; - IPAddress.TryParse(cIobConf.cncIpAddr, out address); - PingReply reply = pingSender.Send(address, 100); - // se passa il ping faccio il resto... - if (reply.Status == IPStatus.Success) - { - string szStatusConnection = ""; + base.readSemafori(ref currDispData); try { - // ora provo connessione... - parentForm.commPlcActive = true; - FANUC_ref.Connect(ref szStatusConnection); - parentForm.commPlcActive = false; - lgInfo("szStatusConnection: " + szStatusConnection); - connectionOk = true; - // refresh stato allarmi!!! - if (connectionOk) - { - dtAvvioAdp = DateTime.Now; - if (adpRunning) + if (verboseLog) { - lgInfo("Connessione OK"); + lgInfo("inizio read semafori"); } - } - else - { - lgError("Impossibile procedere, connessione mancante..."); - } + + currDispData.semIn = Semaforo.SV; + // inizio letture, SEMPRE DA ZERO (possibile ottimizzazione...) + int memIndex = 0; + // controllo area R: se ha dati (> 0 byte) --> leggo! + if (MemBlockR.Length > 0) + { + stopwatch.Restart(); + FanucMemRW(R, FANUC.MemType.R, memIndex, ref MemBlockR); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-R", MemBlockR.Length), stopwatch.ElapsedTicks); + } + // log + if (verboseLog) + { + for (int i = 0; i < MemBlockR.Length; i++) + { + lgInfo(string.Format("MemBlockR{0}: {1}", i, utils.binaryForm(MemBlockR[i]))); + } + } + } + // controllo area X: se ha dati (> 0 byte) --> leggo! + if (MemBlockX.Length > 0) + { + stopwatch.Restart(); + FanucMemRW(R, FANUC.MemType.X, memIndex, ref MemBlockX); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-X", MemBlockX.Length), stopwatch.ElapsedTicks); + } + // log + if (verboseLog) + { + for (int i = 0; i < MemBlockX.Length; i++) + { + lgInfo(string.Format("MemBlockX{0}: {1}", i, utils.binaryForm(MemBlockX[i]))); + } + } + } + // controllo area Y: se ha dati (> 0 byte) --> leggo! + if (MemBlockY.Length > 0) + { + stopwatch.Restart(); + FanucMemRW(R, FANUC.MemType.Y, memIndex, ref MemBlockY); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-Y", MemBlockY.Length), stopwatch.ElapsedTicks); + } + // log + if (verboseLog) + { + for (int i = 0; i < MemBlockY.Length; i++) + { + lgInfo(string.Format("MemBlockY{0}: {1}", i, utils.binaryForm(MemBlockY[i]))); + } + } + } + stopwatch.Stop(); + // salvo il solo BYTE dell'input decifrando il semaforo... + decodeToBitmap(); + reportRawInput(ref currDispData); } catch (Exception exc) { - lgFatal(string.Format("Errore nella connessione all'adapter FANUC: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc)); - connectionOk = false; - lgInfo(string.Format("Eccezione in TryConnect, Adapter NON running, pausa di {0} msec prima di ulteriori tentativi di riconnessione", utils.CRI("waitRecMSec"))); + lgError(string.Format("Eccezione in readSemafori:{0}{1}", Environment.NewLine, exc)); + connectionOk = false; + currDispData.semIn = Semaforo.SR; } - } - else - { - // loggo no risposta ping ... - connectionOk = false; - if (verboseLog || periodicLog) + } + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + private void decodeToBitmap() + { + // init a zero... + B_input = 0; + if (connectionOk) { - lgInfo(string.Format("Attenzione: controllo PING fallito per IP {0} - {1}", cIobConf.cncIpAddr, reply.Status)); - } - } - } - } - // se non è ancora connesso faccio procesisng memoria caso disconnesso... - if (!connectionOk) - { - // processo semafori ed invio... - processMemoryDiscon(); - } - } - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - base.readSemafori(ref currDispData); - try - { - if (verboseLog) - { - lgInfo("inizio read semafori"); - } - - currDispData.semIn = Semaforo.SV; - // inizio letture, SEMPRE DA ZERO (possibile ottimizzazione...) - int memIndex = 0; - // controllo area R: se ha dati (> 0 byte) --> leggo! - if (MemBlockR.Length > 0) - { - stopwatch.Restart(); - FanucMemRW(R, FANUC.MemType.R, memIndex, ref MemBlockR); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-R", MemBlockR.Length), stopwatch.ElapsedTicks); - } - // log - if (verboseLog) - { - for (int i = 0; i < MemBlockR.Length; i++) - { - lgInfo(string.Format("MemBlockR{0}: {1}", i, utils.binaryForm(MemBlockR[i]))); - } - } - } - // controllo area X: se ha dati (> 0 byte) --> leggo! - if (MemBlockX.Length > 0) - { - stopwatch.Restart(); - FanucMemRW(R, FANUC.MemType.X, memIndex, ref MemBlockX); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-X", MemBlockX.Length), stopwatch.ElapsedTicks); - } - // log - if (verboseLog) - { - for (int i = 0; i < MemBlockX.Length; i++) - { - lgInfo(string.Format("MemBlockX{0}: {1}", i, utils.binaryForm(MemBlockX[i]))); - } - } - } - // controllo area Y: se ha dati (> 0 byte) --> leggo! - if (MemBlockY.Length > 0) - { - stopwatch.Restart(); - FanucMemRW(R, FANUC.MemType.Y, memIndex, ref MemBlockY); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-Y", MemBlockY.Length), stopwatch.ElapsedTicks); - } - // log - if (verboseLog) - { - for (int i = 0; i < MemBlockY.Length; i++) - { - lgInfo(string.Format("MemBlockY{0}: {1}", i, utils.binaryForm(MemBlockY[i]))); - } - } - } - stopwatch.Stop(); - // salvo il solo BYTE dell'input decifrando il semaforo... - decodeToBitmap(); - reportRawInput(ref currDispData); - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in readSemafori:{0}{1}", Environment.NewLine, exc)); - connectionOk = false; - currDispData.semIn = Semaforo.SR; - } - } - /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO - /// - private void decodeToBitmap() - { - // init a zero... - B_input = 0; - if (connectionOk) - { - // SE SI E' CONNESSO al FANUC allora è 1=powerON... - if (FANUC_ref.Connected) - { - B_input += 1 << 0; - } - - // decodifico impiegando dictionary... cercando il TIPO di memoria & co... - string bKey = ""; - string bVal = ""; - char area; - // valore INVERTED (default è false) - bool invSignal = false; - string memArea = ""; - string[] memIdx; - int bitNum = 0; - int byteNum = 0; - int byte2check = 0; - for (int i = 0; i < 8; i++) - { - bKey = string.Format("BIT{0}", i); - // cerco se ci sia in LUT - if (signLUT.ContainsKey(bKey)) - { - // recupero nome variabile... - bVal = signLUT[bKey]; - // se l'area è PZCOUNT... processo PUNTUALMENTE il CONTAPEZZI... - if (bVal.StartsWith("PZCOUNT")) - { - string currODL = ""; - try - { - currODL = utils.callUrl(urlGetCurrODL); - // solo SE HO un ODL... - if (string.IsNullOrEmpty(currODL) || currODL == "0") + // SE SI E' CONNESSO al FANUC allora è 1=powerON... + if (FANUC_ref.Connected) { - if (periodicLog) - { - lgInfo(string.Format("Fanuc | Lettura ODL andata a vuoto: currODL: {0}", currODL)); - } + B_input += 1 << 0; + } + + // decodifico impiegando dictionary... cercando il TIPO di memoria & co... + string bKey = ""; + string bVal = ""; + char area; + // valore INVERTED (default è false) + bool invSignal = false; + string memArea = ""; + string[] memIdx; + int bitNum = 0; + int byteNum = 0; + int byte2check = 0; + for (int i = 0; i < 8; i++) + { + bKey = string.Format("BIT{0}", i); + // cerco se ci sia in LUT + if (signLUT.ContainsKey(bKey)) + { + // recupero nome variabile... + bVal = signLUT[bKey]; + // se l'area è PZCOUNT... processo PUNTUALMENTE il CONTAPEZZI... + if (bVal.StartsWith("PZCOUNT")) + { + string currODL = ""; + try + { + currODL = utils.callUrl(urlGetCurrODL); + // solo SE HO un ODL... + if (string.IsNullOrEmpty(currODL) || currODL == "0") + { + if (periodicLog) + { + lgInfo(string.Format("Fanuc | Lettura ODL andata a vuoto: currODL: {0}", currODL)); + } + } + else + { + // se variato o scaduto timeout log... + if (periodicLog || (currIdxODL.ToString() != currODL)) + { + lgInfo(string.Format("Fanuc | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL)); + } + // provo a salvare nuovo ODL + int.TryParse(currODL, out currIdxODL); + } + } + catch (Exception exc) + { + if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15) + { + lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL); + lastWarnODL = DateTime.Now; + } + } + if (!string.IsNullOrEmpty(currODL) && currODL != "0") + { + // controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x distanziare invio e ridurre letture + if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + { + // se sono differenti MOSTRO... + if (lastCountCNC != contapezzi) + { + // registro contapezzi + lgInfo(string.Format("Differenza Contapezzi: READ: {0} | Interno {1}", lastCountCNC, contapezzi)); + + } + // verifico se variato contapezzi... + if (lastCountCNC > contapezzi) + { + // salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio + contapezzi++; + needRefreshPzCount = true; + // salvo in semaforo! + B_input += 1 << 2; + // registro contapezzi + lgInfo(string.Format("Contapezzi FANUC: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi)); + } + // invio a server contapezzi (aggiornato) + string retVal = utils.callUrl(urlSetPzCount + contapezzi.ToString()); + // verifica se tutto OK + if (retVal != contapezzi.ToString()) + { + // errore salvataggio contapezzi + lgInfo($"Errore salvataggio Contapezzi FANUC: lastCountCNC {lastCountCNC} | contapezzi {contapezzi} | risposta: {retVal}"); + // rileggo il counter pezzi da server + pzCntReload(true); + } + // resetto timer... + lastPzCountSend = DateTime.Now; + } + } + else + { + if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + { + lgInfo(string.Format("Attenzione: mancanza ODL non procedo con gestione contapezzi. Contapezzi FANUC: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi)); + // resetto timer... + lastPzCountSend = DateTime.Now; + } + } + } + else // area "normale" byte.bit + { + // di norma è segnale normale => 1, altrimenti inverse => 0... + invSignal = false; + // cerco se sia inverse (ultimo char "!") --> registro e elimino char... + invSignal = bVal.StartsWith("!"); + // tolgo comunque inversione... + bVal = bVal.Replace("!", ""); + // recupero area... + area = bVal[0]; + // altrimenti decodifico area... + memArea = bVal.Substring(1, bVal.Length - 1); + memIdx = memArea.Split('.'); + // calcolo bit e byte number... + int.TryParse(memIdx[0], out byteNum); + if (memIdx.Length > 1) + { + int.TryParse(memIdx[1], out bitNum); + } + // in base al nome cerco in una delle aree.. e prendo solo solo quel bit di quel byte... + switch (area) + { + case 'G': + byte2check = MemBlockG[byteNum]; + break; + case 'R': + byte2check = MemBlockR[byteNum]; + break; + case 'X': + byte2check = MemBlockX[byteNum]; + break; + case 'Y': + byte2check = MemBlockY[byteNum]; + break; + default: + break; + } + // a secondo che sia segnale normale o inverso... + if (invSignal) + { + // controllo se il bit sia NON attivo (basso)... == 0... + if ((byte2check & (1 << bitNum)) == 0) + { + B_input += 1 << i; + } + } + else + { + // controllo se il bit sia attivo (alto)... != 0 + if ((byte2check & (1 << bitNum)) != 0) + { + B_input += 1 << i; + } + } + } + } + } + } + // log opzionale! + if (verboseLog) + { + lgInfo(string.Format("Trasformazione B_input: {0}", B_input)); + } + } + /// + /// Recupero programma in lavorazione + /// + /// + public override string getPrgName() + { + string prgName = ""; + // recupero NUOVO prgName... + try + { + // recupero nome programma MAIN + prgName = utils.purgedChar2String(FANUC_ref.getPrgNameMain()); + // trimmo path del programma, ovvero "CNCMEMUSERPATH1" + prgName = prgName.Replace(utils.CRS("basePrgMemPath"), ""); + lgInfo("Current PROG: {0}", prgName); + } + catch (Exception exc) + { + lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc)); + connectionOk = false; + } + return prgName; + } + + /// + /// Recupero programma in lavorazione come Dictionary FANUC... + /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) + /// - altre stringhe: ogni singolo parametro / valore + /// + /// + public override Dictionary getSysInfo() + { + Dictionary outVal = new Dictionary(); + stopwatch.Restart(); + CncLib.Focas1.ODBSYS answ = FANUC_ref.getSysInfo(); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("SYS-INFO"), stopwatch.ElapsedTicks); + } + + try + { + string cnc_type = new string(answ.cnc_type); + string mt_type = new string(answ.mt_type); + string series = new string(answ.series); + string version = new string(answ.version); + string axes = new string(answ.axes); + //short addInfo = answ.addinfo; + short max_axis = answ.max_axis; + // preparo i singoli valori dell'array... + outVal.Add("SYSINFO", string.Format("{0}#{1}#{2}#{3}#{4}#{5}", cnc_type, mt_type, series, version, axes, max_axis)); + outVal.Add("CNC", cnc_type); + outVal.Add("MTT", mt_type); + outVal.Add("SER", series); + outVal.Add("VER", version); + outVal.Add("AXS", string.Format("{0}|{1}", axes, max_axis)); + } + catch (Exception exc) + { + lgError(exc, "Errore in getSysInfo"); + connectionOk = false; + } + return outVal; + } + /// + /// Effettua vero processing contapezzi: + /// 6711: pezzi lavorati + /// 6712: pezzi lavorati totali + /// 6713: pezzi richiesti + /// + public override void processContapezzi() + { + if (utils.CRB("enableContapezzi")) + { + // procedo SOLO SE ho connessione... + if (connectionOk) + { + try + { + // controllo di AVERE parametri opzionali x conteggi vari + if (cIobConf.optPar.Count > 0) + { + // contapezzi ATTUALE + if (!string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + string memAddr = getOptPar("PZCOUNT_MODE"); + if (memAddr.StartsWith("STD")) + { + // inizio verifica area memoria/parametro levando prima parte codice + memAddr = memAddr.Replace("STD.", ""); + // var di appoggio + int cntAddr = 0; + object outputVal = new object(); + // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 + if (memAddr.StartsWith("PAR.")) + { + // recupero parametro... + int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); + if (cntAddr == 0) + { + cntAddr = 6711; + } + + // processo parametro contapezzi (lavorati) + stopwatch.Restart(); + FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4), stopwatch.ElapsedTicks); + } + + // salvo ultimo conteggio rilevato + int newVal = -1; + Int32.TryParse(outputVal.ToString(), out newVal); + lastCountCNC = newVal > -1 ? newVal : lastCountCNC; + } + // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW + else + { + memAddressFanuc areaCounter = new memAddressFanuc(memAddr); + + if (isVerboseLog) + { + lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); + } + + // leggo! + stopwatch.Restart(); + // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato + switch (areaCounter.vType) + { + case "B": + byte valB = 0; + FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB); + outputVal = valB; + break; + case "D": + ushort valW = 0; + FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW); + outputVal = valW; + break; + case "DW": + uint valDW = 0; + FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW); + if (isVerboseLog) + { + lgInfo("[1] valDW contapezzi: {0}", valDW); + } + + outputVal = valDW; + if (isVerboseLog) + { + lgInfo("[2] outputVal contapezzi: {0}", outputVal); + } + + break; + default: + break; + } + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); + } + + // salvo... + int newVal = -1; + Int32.TryParse(outputVal.ToString(), out newVal); + lastCountCNC = newVal > -1 ? newVal : lastCountCNC; + if (isVerboseLog) + { + lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC); + } + } + stopwatch.Stop(); + } + } + + } + } + catch (Exception exc) + { + lgError(exc, "Errore in contapezzi FANUC"); + connectionOk = false; + } } else { - // se variato o scaduto timeout log... - if (periodicLog || (currIdxODL.ToString() != currODL)) - { - lgInfo(string.Format("Fanuc | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL)); - } - // provo a salvare nuovo ODL - int.TryParse(currODL, out currIdxODL); + lgError("Errore: manca connessione in contapezzi FANUC"); } - } - catch (Exception exc) - { - if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15) - { - lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL); - lastWarnODL = DateTime.Now; - } - } - if (!string.IsNullOrEmpty(currODL) && currODL != "0") - { - // controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x distanziare invio e ridurre letture - if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) - { - // se sono differenti MOSTRO... - if (lastCountCNC != contapezzi) - { - // registro contapezzi - lgInfo(string.Format("Differenza Contapezzi: READ: {0} | Interno {1}", lastCountCNC, contapezzi)); - - } - // verifico se variato contapezzi... - if (lastCountCNC > contapezzi) - { - // salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio - contapezzi++; - needRefreshPzCount = true; - // salvo in semaforo! - B_input += 1 << 2; - // registro contapezzi - lgInfo(string.Format("Contapezzi FANUC: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi)); - } - // invio a server contapezzi (aggiornato) - string retVal = utils.callUrl(urlSetPzCount + contapezzi.ToString()); - // verifica se tutto OK - if (retVal != contapezzi.ToString()) - { - // errore salvataggio contapezzi - lgInfo($"Errore salvataggio Contapezzi FANUC: lastCountCNC {lastCountCNC} | contapezzi {contapezzi} | risposta: {retVal}"); - // rileggo il counter pezzi da server - pzCntReload(true); - } - // resetto timer... - lastPzCountSend = DateTime.Now; - } - } - else - { - if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) - { - lgInfo(string.Format("Attenzione: mancanza ODL non procedo con gestione contapezzi. Contapezzi FANUC: {0} | Contapezzi interno {1}", lastCountCNC, contapezzi)); - // resetto timer... - lastPzCountSend = DateTime.Now; - } - } } - else // area "normale" byte.bit + } + /// + /// Recupero altri counters se ci sono + /// + public override void processOtherCounters() + { + try { - // di norma è segnale normale => 1, altrimenti inverse => 0... - invSignal = false; - // cerco se sia inverse (ultimo char "!") --> registro e elimino char... - invSignal = bVal.StartsWith("!"); - // tolgo comunque inversione... - bVal = bVal.Replace("!", ""); - // recupero area... - area = bVal[0]; - // altrimenti decodifico area... - memArea = bVal.Substring(1, bVal.Length - 1); - memIdx = memArea.Split('.'); - // calcolo bit e byte number... - int.TryParse(memIdx[0], out byteNum); - if (memIdx.Length > 1) - { - int.TryParse(memIdx[1], out bitNum); - } - // in base al nome cerco in una delle aree.. e prendo solo solo quel bit di quel byte... - switch (area) - { - case 'G': - byte2check = MemBlockG[byteNum]; - break; - case 'R': - byte2check = MemBlockR[byteNum]; - break; - case 'X': - byte2check = MemBlockX[byteNum]; - break; - case 'Y': - byte2check = MemBlockY[byteNum]; - break; - default: - break; - } - // a secondo che sia segnale normale o inverso... - if (invSignal) - { - // controllo se il bit sia NON attivo (basso)... == 0... - if ((byte2check & (1 << bitNum)) == 0) + // controllo di AVERE parametri opzionali x conteggi vari + if (cIobConf.optPar.Count > 0) { - B_input += 1 << i; - } - } - else - { - // controllo se il bit sia attivo (alto)... != 0 - if ((byte2check & (1 << bitNum)) != 0) - { - B_input += 1 << i; - } - } - } - } - } - } - // log opzionale! - if (verboseLog) - { - lgInfo(string.Format("Trasformazione B_input: {0}", B_input)); - } - } - /// - /// Recupero programma in lavorazione - /// - /// - public override string getPrgName() - { - string prgName = ""; - // recupero NUOVO prgName... - try - { - // recupero nome programma MAIN - prgName = utils.purgedChar2String(FANUC_ref.getPrgNameMain()); - // trimmo path del programma, ovvero "CNCMEMUSERPATH1" - prgName = prgName.Replace(utils.CRS("basePrgMemPath"), ""); - lgInfo("Current PROG: {0}", prgName); - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc)); - connectionOk = false; - } - return prgName; - } - - /// - /// Recupero programma in lavorazione come Dictionary FANUC... - /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) - /// - altre stringhe: ogni singolo parametro / valore - /// - /// - public override Dictionary getSysInfo() - { - Dictionary outVal = new Dictionary(); - stopwatch.Restart(); - CncLib.Focas1.ODBSYS answ = FANUC_ref.getSysInfo(); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("SYS-INFO"), stopwatch.ElapsedTicks); - } - - try - { - string cnc_type = new string(answ.cnc_type); - string mt_type = new string(answ.mt_type); - string series = new string(answ.series); - string version = new string(answ.version); - string axes = new string(answ.axes); - //short addInfo = answ.addinfo; - short max_axis = answ.max_axis; - // preparo i singoli valori dell'array... - outVal.Add("SYSINFO", string.Format("{0}#{1}#{2}#{3}#{4}#{5}", cnc_type, mt_type, series, version, axes, max_axis)); - outVal.Add("CNC", cnc_type); - outVal.Add("MTT", mt_type); - outVal.Add("SER", series); - outVal.Add("VER", version); - outVal.Add("AXS", string.Format("{0}|{1}", axes, max_axis)); - } - catch (Exception exc) - { - lgError(exc, "Errore in getSysInfo"); - connectionOk = false; - } - return outVal; - } - /// - /// Effettua vero processing contapezzi: - /// 6711: pezzi lavorati - /// 6712: pezzi lavorati totali - /// 6713: pezzi richiesti - /// - public override void processContapezzi() - { - if (utils.CRB("enableContapezzi")) - { - // procedo SOLO SE ho connessione... - if (connectionOk) - { - try - { - // controllo di AVERE parametri opzionali x conteggi vari - if (cIobConf.optPar.Count > 0) - { - // contapezzi ATTUALE - if (!string.IsNullOrEmpty(getOptPar("PZCOUNT_MODE"))) - { - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - string memAddr = getOptPar("PZCOUNT_MODE"); - if (memAddr.StartsWith("STD")) - { - // inizio verifica area memoria/parametro levando prima parte codice - memAddr = memAddr.Replace("STD.", ""); - // var di appoggio - int cntAddr = 0; - object outputVal = new object(); - // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 - if (memAddr.StartsWith("PAR.")) - { - // recupero parametro... - int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); - if (cntAddr == 0) - { - cntAddr = 6711; - } - - // processo parametro contapezzi (lavorati) - stopwatch.Restart(); - FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4), stopwatch.ElapsedTicks); - } - - // salvo ultimo conteggio rilevato - int newVal = -1; - Int32.TryParse(outputVal.ToString(), out newVal); - lastCountCNC = newVal > -1 ? newVal : lastCountCNC; - } - // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW - else - { - memAddressFanuc areaCounter = new memAddressFanuc(memAddr); - - if (isVerboseLog) - { - lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); - } - - // leggo! - stopwatch.Restart(); - // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato - switch (areaCounter.vType) - { - case "B": - byte valB = 0; - FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB); - outputVal = valB; - break; - case "D": - ushort valW = 0; - FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW); - outputVal = valW; - break; - case "DW": - uint valDW = 0; - FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW); - if (isVerboseLog) - { - lgInfo("[1] valDW contapezzi: {0}", valDW); - } - - outputVal = valDW; - if (isVerboseLog) - { - lgInfo("[2] outputVal contapezzi: {0}", outputVal); - } - - break; - default: - break; - } - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); - } - - // salvo... - int newVal = -1; - Int32.TryParse(outputVal.ToString(), out newVal); - lastCountCNC = newVal > -1 ? newVal : lastCountCNC; - if (isVerboseLog) - { - lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC); - } - } - stopwatch.Stop(); - } - } - - } - } - catch (Exception exc) - { - lgError(exc, "Errore in contapezzi FANUC"); - connectionOk = false; - } - } - else - { - lgError("Errore: manca connessione in contapezzi FANUC"); - } - } - } - /// - /// Recupero altri counters se ci sono - /// - public override void processOtherCounters() - { - try - { - // controllo di AVERE parametri opzionali x conteggi vari - if (cIobConf.optPar.Count > 0) - { - string newVal = ""; + string newVal = ""; #if false // controllo SE salvare contapezzo if (getOptPar("PZCOUNT_MODE") != "") @@ -978,457 +978,457 @@ namespace IOB_WIN sendOptVal("PZ_COUNT", lastCountCNC); } #endif - // controllo SE devo gestire contatore pezzi REQUESTED (lanciati) - if (!string.IsNullOrEmpty(getOptPar("PZREQ_MODE"))) - { - newVal = getValByParam("PZREQ_MODE"); - sendOptVal("PZ_REQ", newVal); - } - // controllo SE devo gestire contatore CADENZA (secondi ciclo rilevati) - if (!string.IsNullOrEmpty(getOptPar("PZGTOT_MODE"))) - { - newVal = getValByParam("PZGTOT_MODE"); - sendOptVal("PZ_GTOT", newVal); - } - // controllo SE devo gestire contatore CADENZA (secondi ciclo rilevati) - if (!string.IsNullOrEmpty(getOptPar("PZCAD_MODE"))) - { - newVal = getValByParam("PZCAD_MODE"); - sendOptVal("CICLE_CAD", newVal); - } - } - } - catch (Exception exc) - { - lgError(exc, "Eccezione in processOtherCounters"); - } - } - /// - /// Recupera il valore INT dal nome del parametro per successivo processing - /// - /// - /// - private string getValByParam(string varName) - { - string answ = ""; - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - string memAddr = getOptPar(varName); - if (memAddr.StartsWith("STD")) - { - // inizio verifica area memoria/parametro levando prima parte codice - memAddr = memAddr.Replace("STD.", ""); - // var di appoggio - int cntAddr = 0; - object outputVal = new object(); - // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 - if (memAddr.StartsWith("PAR.")) - { - // recupero parametro... - int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); - // processo parametro - stopwatch.Restart(); - FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4), stopwatch.ElapsedTicks); - } - // salvo valore - answ = outputVal.ToString(); - } - // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW - else - { - memAddressFanuc areaCounter = new memAddressFanuc(memAddr); - - if (isVerboseLog) - { - lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); - } - - // leggo! - stopwatch.Restart(); - // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato - switch (areaCounter.vType) - { - case "B": - byte valB = 0; - FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB); - outputVal = valB; - break; - case "D": - ushort valW = 0; - FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW); - outputVal = valW; - break; - case "DW": - uint valDW = 0; - FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW); - if (isVerboseLog) - { - lgInfo("[1] valDW PAR: {0}", valDW); - } - - outputVal = valDW; - if (isVerboseLog) - { - lgInfo("[2] outputVal PAR: {0}", outputVal); - } - - break; - default: - break; - } - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); - } - - // salvo... - answ = outputVal.ToString(); - if (isVerboseLog) - { - lgInfo("[3] PAR letto: {0} | {1}", varName, answ); - } - } - stopwatch.Stop(); - } - return answ; - } - /// - /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) - /// - public override void processMode() - { - // processo SOLO SE connected... - if (connectionOk) - { - if (FANUC_ref.Connected) - { - if (utils.CRB("enableMode")) - { - try - { - // leggo tutto da 0 a 43... - int memIndex = 0; - // controllo modalità lettura memoria - stopwatch.Restart(); - FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-G-AREA", MemBlockG.Length), stopwatch.ElapsedTicks); - } - - stopwatch.Stop(); - // verifico modo con valore corrente, se cambia aggiorno... - CNC_MODE newMode = decodeG43(MemBlockG[43]); - if (newMode != currMode) - { - // aggiorno! - currMode = newMode; - // conversione NUM MODE in descrizione da ENUM - string descrMode = Enum.GetName(typeof(CNC_MODE), currMode); - // accodo x invio - string sVal = string.Format("[CNC_MODE]{0}", descrMode); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("CNC_MODE", descrMode)); - } + // controllo SE devo gestire contatore pezzi REQUESTED (lanciati) + if (!string.IsNullOrEmpty(getOptPar("PZREQ_MODE"))) + { + newVal = getValByParam("PZREQ_MODE"); + sendOptVal("PZ_REQ", newVal); + } + // controllo SE devo gestire contatore PEZZI TOTALI + if (!string.IsNullOrEmpty(getOptPar("PZGTOT_MODE"))) + { + newVal = getValByParam("PZGTOT_MODE"); + sendOptVal("PZ_GTOT", newVal); + } + // controllo SE devo gestire contatore CADENZA (secondi ciclo rilevati) + if (!string.IsNullOrEmpty(getOptPar("PZCAD_MODE"))) + { + newVal = getValByParam("PZCAD_MODE"); + sendOptVal("CICLE_CAD", newVal); + } + } } catch (Exception exc) { - lgError(exc, string.Format("Errore in process Mode G43: {0}{1}", Environment.NewLine, exc)); - connectionOk = false; - stopwatch.Stop(); + lgError(exc, "Eccezione in processOtherCounters"); } - } } - } - } - /// - /// decodifica il modo dai valori del byte G43 - /// - /// - /// - protected static CNC_MODE decodeG43(byte currVal) - { - // hard coded da valori tabellari a MODI definiti in CNC_MODE... - CNC_MODE answ = CNC_MODE.ND; - switch (currVal) - { - case 0: - answ = CNC_MODE.MDI; - break; - case 1: - answ = CNC_MODE.MEN; - break; - case 3: - answ = CNC_MODE.EDIT; - break; - case 4: - answ = CNC_MODE.HANDLE_INC; - break; - case 5: - answ = CNC_MODE.JOG; - break; - case 6: - answ = CNC_MODE.TJOG; - break; - case 7: - answ = CNC_MODE.THND; - break; - case 33: - answ = CNC_MODE.RMT; - break; - case 133: - answ = CNC_MODE.REF; - break; - default: - answ = CNC_MODE.ND; - break; - } - return answ; - } - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); - // processo SOLO SE connected... - if (connectionOk) - { - if (FANUC_ref.Connected) + /// + /// Recupera il valore INT dal nome del parametro per successivo processing + /// + /// + /// + private string getValByParam(string varName) { - stopwatch.Restart(); - CncLib.Focas1.ODBDY2_1 answ = FANUC_ref.getAllDynData(); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("PROC-DYN-DATA"), stopwatch.ElapsedTicks); - } + string answ = ""; + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + string memAddr = getOptPar(varName); + if (memAddr.StartsWith("STD")) + { + // inizio verifica area memoria/parametro levando prima parte codice + memAddr = memAddr.Replace("STD.", ""); + // var di appoggio + int cntAddr = 0; + object outputVal = new object(); + // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711 + if (memAddr.StartsWith("PAR.")) + { + // recupero parametro... + int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr); + // processo parametro + stopwatch.Restart(); + FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4), stopwatch.ElapsedTicks); + } + // salvo valore + answ = outputVal.ToString(); + } + // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW + else + { + memAddressFanuc areaCounter = new memAddressFanuc(memAddr); - try - { - string actf = answ.actf.ToString(); - string acts = answ.acts.ToString(); - //string numAlarm = answ.alarm.ToString(); - // preparo i singoli valori dell'array... - //outVal.Add("DYNDATA", string.Format("{0}#{1}#{2}", actf, acts, numAlarm)); - outVal.Add("DYNDATA", string.Format("FEED {0}#SPEED_RPM {1}", actf, acts)); - if (utils.CRB("SendFeedSpeed")) - { - outVal.Add("FEED", actf); - outVal.Add("SPEED_RPM", acts); - //outVal.Add("NUM_ALARM", numAlarm); + if (isVerboseLog) + { + lgInfo("[0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType); + } + + // leggo! + stopwatch.Restart(); + // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato + switch (areaCounter.vType) + { + case "B": + byte valB = 0; + FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB); + outputVal = valB; + break; + case "D": + ushort valW = 0; + FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW); + outputVal = valW; + break; + case "DW": + uint valDW = 0; + FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW); + if (isVerboseLog) + { + lgInfo("[1] valDW PAR: {0}", valDW); + } + + outputVal = valDW; + if (isVerboseLog) + { + lgInfo("[2] outputVal PAR: {0}", outputVal); + } + + break; + default: + break; + } + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), stopwatch.ElapsedTicks); + } + + // salvo... + answ = outputVal.ToString(); + if (isVerboseLog) + { + lgInfo("[3] PAR letto: {0} | {1}", varName, answ); + } + } + stopwatch.Stop(); } - if (utils.CRB("SendAxPos")) - { - // salvo le posizioni... - CncLib.Focas1.FAXIS posAx = answ.pos; - int[] currPosAbs = posAx.absolute; - int i = 0; - foreach (var item in currPosAbs) - { - i++; - outVal.Add(string.Format("POS_{0:00}", i), item.ToString()); - } - } - } - catch (Exception exc) - { - lgError(exc, "Errore in getDynData"); - } - stopwatch.Stop(); + return answ; } - } - return outVal; - } - /// - /// Recupero dati override (da area G che è già stata letta...) - /// - /// - public override Dictionary getOverrides() - { - Dictionary outVal = new Dictionary(); - // processo SOLO SE connected... - if (connectionOk) - { - if (FANUC_ref.Connected) + /// + /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) + /// + public override void processMode() { - if (utils.CRB("enableMode") && MemBlockG != null) - { - outVal.Add("FEED_OVER", MemBlockG[30].ToString()); - outVal.Add("RAPID_OVER", MemBlockG[12].ToString()); - } + // processo SOLO SE connected... + if (connectionOk) + { + if (FANUC_ref.Connected) + { + if (utils.CRB("enableMode") && MemBlockG != null && MemBlockG.Length > 0) + { + try + { + // leggo tutto da 0 a 43... + int memIndex = 0; + // controllo modalità lettura memoria + stopwatch.Restart(); + FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-G-AREA", MemBlockG.Length), stopwatch.ElapsedTicks); + } + + stopwatch.Stop(); + // verifico modo con valore corrente, se cambia aggiorno... + CNC_MODE newMode = decodeG43(MemBlockG[43]); + if (newMode != currMode) + { + // aggiorno! + currMode = newMode; + // conversione NUM MODE in descrizione da ENUM + string descrMode = Enum.GetName(typeof(CNC_MODE), currMode); + // accodo x invio + string sVal = string.Format("[CNC_MODE]{0}", descrMode); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("CNC_MODE", descrMode)); + } + } + catch (Exception exc) + { + lgError(exc, string.Format("Errore in process Mode G43: {0}{1}", Environment.NewLine, exc)); + connectionOk = false; + stopwatch.Stop(); + } + } + } + } + } + /// + /// decodifica il modo dai valori del byte G43 + /// + /// + /// + protected static CNC_MODE decodeG43(byte currVal) + { + // hard coded da valori tabellari a MODI definiti in CNC_MODE... + CNC_MODE answ = CNC_MODE.ND; + switch (currVal) + { + case 0: + answ = CNC_MODE.MDI; + break; + case 1: + answ = CNC_MODE.MEN; + break; + case 3: + answ = CNC_MODE.EDIT; + break; + case 4: + answ = CNC_MODE.HANDLE_INC; + break; + case 5: + answ = CNC_MODE.JOG; + break; + case 6: + answ = CNC_MODE.TJOG; + break; + case 7: + answ = CNC_MODE.THND; + break; + case 33: + answ = CNC_MODE.RMT; + break; + case 133: + answ = CNC_MODE.REF; + break; + default: + answ = CNC_MODE.ND; + break; + } + return answ; + } + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + Dictionary outVal = new Dictionary(); + // processo SOLO SE connected... + if (connectionOk) + { + if (FANUC_ref.Connected) + { + stopwatch.Restart(); + CncLib.Focas1.ODBDY2_1 answ = FANUC_ref.getAllDynData(); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("PROC-DYN-DATA"), stopwatch.ElapsedTicks); + } + + try + { + string actf = answ.actf.ToString(); + string acts = answ.acts.ToString(); + //string numAlarm = answ.alarm.ToString(); + // preparo i singoli valori dell'array... + //outVal.Add("DYNDATA", string.Format("{0}#{1}#{2}", actf, acts, numAlarm)); + outVal.Add("DYNDATA", string.Format("FEED {0}#SPEED_RPM {1}", actf, acts)); + if (utils.CRB("SendFeedSpeed")) + { + outVal.Add("FEED", actf); + outVal.Add("SPEED_RPM", acts); + //outVal.Add("NUM_ALARM", numAlarm); + } + if (utils.CRB("SendAxPos")) + { + // salvo le posizioni... + CncLib.Focas1.FAXIS posAx = answ.pos; + int[] currPosAbs = posAx.absolute; + int i = 0; + foreach (var item in currPosAbs) + { + i++; + outVal.Add(string.Format("POS_{0:00}", i), item.ToString()); + } + } + } + catch (Exception exc) + { + lgError(exc, "Errore in getDynData"); + } + stopwatch.Stop(); + } + } + return outVal; + } + /// + /// Recupero dati override (da area G che è già stata letta...) + /// + /// + public override Dictionary getOverrides() + { + Dictionary outVal = new Dictionary(); + // processo SOLO SE connected... + if (connectionOk) + { + if (FANUC_ref.Connected) + { + if (utils.CRB("enableMode") && MemBlockG != null && MemBlockG.Length > 0) + { + outVal.Add("FEED_OVER", MemBlockG[30].ToString()); + outVal.Add("RAPID_OVER", MemBlockG[12].ToString()); + } + } + } + return outVal; + } + + /// + /// Override salvataggio valori in memoria... + /// + /// tipo di DUMP + public override void saveMemDump(dumpType tipo) + { + // se l'area ha una size > 0... + if (areaD.arraySize > 0) + { + dump_MemArea(tipo, FANUC.MemType.D, areaD.startIdx, areaD.arraySize); + } + // se l'area ha una size > 0... + if (areaR.arraySize > 0) + { + dump_MemArea(tipo, FANUC.MemType.R, areaR.startIdx, areaR.arraySize); + } + // se l'area ha una size > 0... + if (areaX.arraySize > 0) + { + dump_MemArea(tipo, FANUC.MemType.X, areaX.startIdx, areaX.arraySize); + } + // se l'area ha una size > 0... + if (areaY.arraySize > 0) + { + dump_MemArea(tipo, FANUC.MemType.Y, areaY.startIdx, areaY.arraySize); + } + // se l'area ha una size > 0... + if (areaPAR.arraySize > 0) + { + dump_ParArea(tipo, areaPAR.startIdx, areaPAR.arraySize); + } + } + /// + /// Dump area D della memoria + /// + /// tipo di DUMP: START (sovrascrivendo) / SAMPLE (salva tanti campionamenti) + /// tipo memoria + /// area memoria di partenza + /// dimensione memoria + private void dump_MemArea(dumpType tipo, FANUC.MemType tipoMem, int memIndex, int memSizeByte) + { + DateTime adesso = DateTime.Now; + string nomeFileB = ""; + string nomeFileW = ""; + string nomeFileDW = ""; + Dictionary mappaValori = new Dictionary(); + // per sicurezza verifico < 9999 byte + if (memSizeByte > 9999) + { + memSizeByte = 9999; + } + // leggo TUTTI i (MAX 9999) byte della memoria D... + byte[] MemBlockCurr = new byte[memSizeByte]; + if (verboseLog) + { + lgInfo("START MemDump", tipoMem); + } + + stopwatch.Restart(); + FanucMemRW(R, tipoMem, memIndex, ref MemBlockCurr); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-{1}", MemBlockCurr.Length, tipoMem), stopwatch.ElapsedTicks); + } + + if (verboseLog) + { + lgInfo("END MemDump", tipoMem); + } + + // seconda del tipo di lettura definisco i nomi delle variabili... + if (tipo == dumpType.SAMPLE) + { + nomeFileB = string.Format(@"{0}\SAMPLES\{1}_{2}_Byte_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); + nomeFileW = string.Format(@"{0}\SAMPLES\{1}_{2}_W_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); + nomeFileDW = string.Format(@"{0}\SAMPLES\{1}_{2}_DW_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); + } + else + { + // salvo in file i dati letti come BYTE + nomeFileB = string.Format(@"{0}\{1}_{2}_Byte.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); + nomeFileW = string.Format(@"{0}\{1}_{2}_W.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); + nomeFileDW = string.Format(@"{0}\{1}_{2}_DW.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); + } + + // salvo in file i dati letti come BYTE + mappaValori = new Dictionary(); + for (int i = 0; i < MemBlockCurr.Length; i++) + { + mappaValori.Add(i.ToString("0000"), MemBlockCurr[i].ToString()); + } + utils.WritePlain(mappaValori, nomeFileB); + + // salvo in file i dati letti come Word (2byte) + mappaValori = new Dictionary(); + for (int i = 0; i < MemBlockCurr.Length / 2; i++) + { + mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockCurr, i * 2).ToString()); + } + utils.WritePlain(mappaValori, nomeFileW); + + // salvo in file i dati letti come DWord (4byte) + mappaValori = new Dictionary(); + for (int i = 0; i < MemBlockCurr.Length / 4; i++) + { + mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockCurr, i * 4).ToString()); + } + utils.WritePlain(mappaValori, nomeFileDW); + } + /// + /// Dump area PARAMETRI + /// + /// tipo di DUMP: START (sovrascrivendo) / SAMPLE (salva tanti campionamenti) + /// Parametro di partenza + /// Numero parametri da esportare... memoria + private void dump_ParArea(dumpType tipo, int memIndex, int numPar) + { + DateTime adesso = DateTime.Now; + string nomeFile = ""; + Dictionary mappaValori = new Dictionary(); + // per sicurezza verifico < 9999 parametri + if (numPar > 9999) + { + numPar = 9999; + } + + // leggo TUTTI i (MAX 9999) byte della memoria D... + object[] paramsArray = new object[numPar]; + if (verboseLog) + { + lgInfo("START ParamDump"); + } + + stopwatch.Restart(); + for (int i = 0; i < numPar; i++) + { + FANUC_ref.F_RW_Param_Integer(false, memIndex + i, 3, ref paramsArray[i]); + } + + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4 * numPar), stopwatch.ElapsedTicks); + } + + if (verboseLog) + { + lgInfo("END ParamDump"); + } + + // seconda del tipo di lettura definisco i nomi delle variabili... + if (tipo == dumpType.SAMPLE) + { + nomeFile = string.Format(@"{0}\SAMPLES\{1}_{2}_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, "PAR", adesso); + } + else + { + nomeFile = string.Format(@"{0}\{1}_{2}.dat", utils.dataDatDir, cIobConf.codIOB, "PAR"); + } + + // salvo in file i dati letti + mappaValori = new Dictionary(); + for (int i = 0; i < paramsArray.Length; i++) + { + mappaValori.Add(i.ToString("0000"), paramsArray[i].ToString()); + } + utils.WritePlain(mappaValori, nomeFile); } - } - return outVal; } - - /// - /// Override salvataggio valori in memoria... - /// - /// tipo di DUMP - public override void saveMemDump(dumpType tipo) - { - // se l'area ha una size > 0... - if (areaD.arraySize > 0) - { - dump_MemArea(tipo, FANUC.MemType.D, areaD.startIdx, areaD.arraySize); - } - // se l'area ha una size > 0... - if (areaR.arraySize > 0) - { - dump_MemArea(tipo, FANUC.MemType.R, areaR.startIdx, areaR.arraySize); - } - // se l'area ha una size > 0... - if (areaX.arraySize > 0) - { - dump_MemArea(tipo, FANUC.MemType.X, areaX.startIdx, areaX.arraySize); - } - // se l'area ha una size > 0... - if (areaY.arraySize > 0) - { - dump_MemArea(tipo, FANUC.MemType.Y, areaY.startIdx, areaY.arraySize); - } - // se l'area ha una size > 0... - if (areaPAR.arraySize > 0) - { - dump_ParArea(tipo, areaPAR.startIdx, areaPAR.arraySize); - } - } - /// - /// Dump area D della memoria - /// - /// tipo di DUMP: START (sovrascrivendo) / SAMPLE (salva tanti campionamenti) - /// tipo memoria - /// area memoria di partenza - /// dimensione memoria - private void dump_MemArea(dumpType tipo, FANUC.MemType tipoMem, int memIndex, int memSizeByte) - { - DateTime adesso = DateTime.Now; - string nomeFileB = ""; - string nomeFileW = ""; - string nomeFileDW = ""; - Dictionary mappaValori = new Dictionary(); - // per sicurezza verifico < 9999 byte - if (memSizeByte > 9999) - { - memSizeByte = 9999; - } - // leggo TUTTI i (MAX 9999) byte della memoria D... - byte[] MemBlockCurr = new byte[memSizeByte]; - if (verboseLog) - { - lgInfo("START MemDump", tipoMem); - } - - stopwatch.Restart(); - FanucMemRW(R, tipoMem, memIndex, ref MemBlockCurr); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-{1}", MemBlockCurr.Length, tipoMem), stopwatch.ElapsedTicks); - } - - if (verboseLog) - { - lgInfo("END MemDump", tipoMem); - } - - // seconda del tipo di lettura definisco i nomi delle variabili... - if (tipo == dumpType.SAMPLE) - { - nomeFileB = string.Format(@"{0}\SAMPLES\{1}_{2}_Byte_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); - nomeFileW = string.Format(@"{0}\SAMPLES\{1}_{2}_W_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); - nomeFileDW = string.Format(@"{0}\SAMPLES\{1}_{2}_DW_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem, adesso); - } - else - { - // salvo in file i dati letti come BYTE - nomeFileB = string.Format(@"{0}\{1}_{2}_Byte.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); - nomeFileW = string.Format(@"{0}\{1}_{2}_W.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); - nomeFileDW = string.Format(@"{0}\{1}_{2}_DW.dat", utils.dataDatDir, cIobConf.codIOB, tipoMem); - } - - // salvo in file i dati letti come BYTE - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockCurr.Length; i++) - { - mappaValori.Add(i.ToString("0000"), MemBlockCurr[i].ToString()); - } - utils.WritePlain(mappaValori, nomeFileB); - - // salvo in file i dati letti come Word (2byte) - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockCurr.Length / 2; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockCurr, i * 2).ToString()); - } - utils.WritePlain(mappaValori, nomeFileW); - - // salvo in file i dati letti come DWord (4byte) - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockCurr.Length / 4; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockCurr, i * 4).ToString()); - } - utils.WritePlain(mappaValori, nomeFileDW); - } - /// - /// Dump area PARAMETRI - /// - /// tipo di DUMP: START (sovrascrivendo) / SAMPLE (salva tanti campionamenti) - /// Parametro di partenza - /// Numero parametri da esportare... memoria - private void dump_ParArea(dumpType tipo, int memIndex, int numPar) - { - DateTime adesso = DateTime.Now; - string nomeFile = ""; - Dictionary mappaValori = new Dictionary(); - // per sicurezza verifico < 9999 parametri - if (numPar > 9999) - { - numPar = 9999; - } - - // leggo TUTTI i (MAX 9999) byte della memoria D... - object[] paramsArray = new object[numPar]; - if (verboseLog) - { - lgInfo("START ParamDump"); - } - - stopwatch.Restart(); - for (int i = 0; i < numPar; i++) - { - FANUC_ref.F_RW_Param_Integer(false, memIndex + i, 3, ref paramsArray[i]); - } - - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("R{0}-PAR", 4 * numPar), stopwatch.ElapsedTicks); - } - - if (verboseLog) - { - lgInfo("END ParamDump"); - } - - // seconda del tipo di lettura definisco i nomi delle variabili... - if (tipo == dumpType.SAMPLE) - { - nomeFile = string.Format(@"{0}\SAMPLES\{1}_{2}_{3:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, cIobConf.codIOB, "PAR", adesso); - } - else - { - nomeFile = string.Format(@"{0}\{1}_{2}.dat", utils.dataDatDir, cIobConf.codIOB, "PAR"); - } - - // salvo in file i dati letti - mappaValori = new Dictionary(); - for (int i = 0; i < paramsArray.Length; i++) - { - mappaValori.Add(i.ToString("0000"), paramsArray[i].ToString()); - } - utils.WritePlain(mappaValori, nomeFile); - } - } } diff --git a/IOB-WIN/IobGeneric.cs b/IOB-WIN/IobGeneric.cs index f07ab712..3d0cd1ac 100644 --- a/IOB-WIN/IobGeneric.cs +++ b/IOB-WIN/IobGeneric.cs @@ -1,3511 +1,3531 @@ -using IOB_UT; -using MapoSDK; -using Newtonsoft.Json; -using NLog; -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Linq; -using System.Net; -using System.Net.NetworkInformation; -using System.Text; +using IOB_UT; +using MapoSDK; +using Newtonsoft.Json; +using NLog; +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.NetworkInformation; +using System.Text; using System.Threading; -using System.Threading.Tasks; -using System.Windows.Forms; - -namespace IOB_WIN -{ - /// - /// Evento per incapsulare datix refresh pagina - /// - public class iobRefreshedEventArgs : EventArgs - { - /// - /// classe obj privata - /// - private readonly newDisplayData _newDisplayData; - /// - /// salvataggio obj - /// - /// - public iobRefreshedEventArgs(newDisplayData newObject) - { - _newDisplayData = newObject; - } - /// - /// Proprietà lettura displayData aggiornato - /// - public newDisplayData DisplayDataObject - { - get { return _newDisplayData; } - } - } - - public class IobGeneric - { - #region variabili serializzate in REDIS +using System.Threading.Tasks; +using System.Windows.Forms; +namespace IOB_WIN +{ /// - /// Oggetto connessione REDIS - /// - public RedisIobCache redisMan; - - - #endregion - - #region variabili ed oggetti base - - /// - /// Dizionario valori impostati x produzione - /// - protected Dictionary currProdData = new Dictionary(); - /// - /// TImeout x ping al server - /// - protected int pingServerMsTimeout = utils.CRI("pingMsTimeout"); - /// - /// Log verboso da configurazione (SOLO CHAIVE "verbose"... - /// - public bool isVerboseLog { get; set; } = utils.CRB("verbose"); - /// - /// Coda massima ammessa per FLog (se <=0 disattivata...) - /// - protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog"); - /// - /// stato Online/Offline della IOB - /// - public bool IobOnline - { - get - { - return utils.IOB_Online; - } - set - { - utils.IOB_Online = value; - } - } - /// - /// stato Online/Offline del server MP IO (su REDIS) - /// - public static bool MPOnline - { - get - { - return utils.MPIO_Online; - } - set - { - utils.MPIO_Online = value; - } - } - /// - /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...) - /// - protected bool inSetup = false; - /// - /// Variabile booleana che indica se sia necessario fare refresh del contapezzi - /// - public bool needRefreshPzCount = true; - /// - /// Indicazione VETO PING a server sino alla data-ora indicata - /// - public static DateTime dtVetoPing - { - get - { - return utils.dtVetoPing; - } - set - { - utils.dtVetoPing = value; - } - } - /// - /// Indicazione VETO invio a server sino alla data-ora indicata - /// - public static DateTime dtVetoSend - { - get - { - return utils.dtVetoSend; - } - set - { - utils.dtVetoSend = value; - } - } - /// - /// Imposta veto chiamata split (durante chiamata, per 60 sec) - /// - public DateTime vetoSplit = DateTime.Now.AddMinutes(1); - /// - /// Indicazione VETO check status IOB x evitare loop troppo stretti... - /// - public DateTime dtVetoCheckIOB = DateTime.Now.AddDays(-1); - /// - /// Contapezzi attuale - /// - public Int32 contapezzi = 0; - /// - /// Ultima lettura variabile contapezzi da CNC - /// - public Int32 lastCountCNC = 0; - /// - /// ODL attualmente sulla macchina - /// - public Int32 currIdxODL; - /// - /// Ultimo invio contapezzi (x invio delayed) - /// - protected DateTime lastPzCountSend; - /// - /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi) - /// - protected DateTime lastWarnODL; - /// - /// Ritardo minimo x invio contapezzi - /// - protected int pzCountDelay; - /// - /// Abilitazione lettura PrgName - /// - public bool enablePrgName = true; - /// - /// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...) - /// - public bool doStartMemDump; - /// - /// Indica se sia richiesto campionamento memoria PERIODICO - /// - public bool doSampleMemory; - /// - /// Evento Iob ha subito un refresh - /// - public event EventHandler eh_refreshed; - /// - /// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE) - /// - public bool hasBigEndian = false; - /// - /// alias booleano false = R - /// - public bool R = false; - /// - /// alias booleano true = W - /// - public bool W = true; - /// - /// wrapper di log - /// - protected static Logger lg; - /// - /// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...) - /// - public string lastSignInVal = ""; - /// - /// dataOra ultimo log periodico... - /// - public DateTime lastPeriodicLog; - /// - /// dataOra ultimo segnale inviato... - /// - public DateTime lastWatchDog; - /// - /// dataOra ultima verifica CNC disconnesso... - /// - public DateTime lastDisconnCheck; - /// - /// dataOra ultimo PING inviato verso il PLC... - /// - public DateTime lastPING; - /// - /// DataOra ultima lettura da PLC - /// - public DateTime lastReadPLC; - /// - /// Oggetto della coda degli elementi letti (e non ancora trasmessi) - /// - public ConcurrentQueue QueueIN = new ConcurrentQueue(); - /// - /// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi) - /// - public ConcurrentQueue QueueFLog = new ConcurrentQueue(); - /// - /// Coda valori ALLARMI ove gestiti... - /// - public ConcurrentQueue QueueAlarm = new ConcurrentQueue(); - /// - /// Coda valori MESSAGGI/EVENTI (da non sottocampionare come samples)... - /// - public ConcurrentQueue QueueMessages = new ConcurrentQueue(); - - /// - /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC - /// - protected bool adpCommAct; - /// - /// valore booleano di check se sia stato AVVIATO l'adapter (Running) - /// - public bool adpRunning = false; - /// - /// valore booleano di check se l'adapter STIA SALVANDO - /// - public bool adpSaving = false; - /// - /// valore booleano (richiesta di riavvio automatico) - /// - public bool adpTryRestart; - /// - /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... - /// - public bool DemoIn - { - get - { - return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn"); - } - } - /// - /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...) - /// - public static bool DemoInSample - { - get - { - return baseUtils.CRB("DemoInSample"); - } - } - /// - /// Numero simulazioni ammesse... - /// - protected int numSim { get; set; } - /// - /// Numero letture IN da avvio - /// - protected int nReadIN { get; set; } - /// - /// Numero letture IN da avvio - /// - protected int nReadFilt { get; set; } - /// - /// Numero invii OUT (svuotamento coda) - /// - protected int nSendOut { get; set; } - /// - /// Verifica se sia in modalità DEMO x dati OUTPUT - /// - public static bool DemoOut - { - get - { - return utils.CRB("DemoOut"); - } - } - /// - /// Contatore x invio dati SignalIN - /// - public int counterSigIN { get; set; } - /// - /// Contatore x invio dati FluxLog - /// - public int counterFLog { get; set; } - /// - /// Ultimo URL - /// - public string lastUrl { get; set; } - /// - /// Ultimo programma letto - /// - public string lastPrgName { get; set; } - /// - /// Ultimo SysInfo letto - /// - public string lastSysInfo { get; set; } - /// - /// Ultimo DynData (sunto) letto - /// - public string lastDynDataCtrlVal { get; set; } - /// - /// Ultimo ARRAY DynData letto - /// - public Dictionary lastDynData { get; set; } = new Dictionary(); - /// - /// Ultimo Alarm letto - /// - public string lastAlarm { get; set; } - /// - /// Ultimo Override set letto - /// - public string lastOverrideFS { get; set; } - /// - /// Ultimo Override set letto - /// - public string lastOverrideRapid { get; set; } - - /// - /// Abilitazione invio pezzi "in blocco" per recupero contapezzi - /// - public bool enableSendPzCountBlock = false; - /// - /// Massimo numero di px da inviare in blocco - /// - public int maxSendPzCountBlock = 10; - /// - /// Minimo numero di px da inviare in blocco - /// - public int minSendPzCountBlock = 5; - - - /// - /// Array dei contatori x segnali blinking - /// - protected int[] i_counters; - /// - /// Vettore 16 BIT valori precedenti - /// - protected int B_previous; - /// - /// Vettore 16 BIT valori in ingresso al filtro - /// - protected int B_input; - /// - /// Vettore 16 BIT valori in uscita dal filtro - /// - protected int B_output; - /// - /// 32 byte input base (es strobe, 8 word da 32 bit di flags...) - /// - public byte[] RawInput = new byte[32]; - /// - /// 32 byte output base (es ack, 8 word da 32 bit di flags...) - /// - public byte[] RawOutput = new byte[32]; - /// - /// Modo corrente (da classe ENUM) - /// - public CNC_MODE currMode; - - /// - /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN) - /// - public bool verboseLog - { - get - { - bool answ = false; - int logEvery = utils.CRI("logEvery"); - if (logEvery < 1) - { - logEvery = 10; - } - - answ = utils.CRB("verbose") && (nReadIN % logEvery == 0); - return answ; - } - } - /// - /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...) - /// - public bool periodicLog - { - get - { - bool answ = false; - answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut")); - if (answ) - { - lastPeriodicLog = DateTime.Now; - } - - return answ; - } - } - /// - /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati - /// - public virtual void reportRawInput(ref newDisplayData currDispData) - { - // processo eventualmente aggiungendo ad elementi esistenti... - if (currDispData == null) - { - currDispData = new newDisplayData(); - } - try - { - StringBuilder sb = new StringBuilder(); - sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}"); - sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}"); - sb.Append($"{Environment.NewLine}"); - sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}"); - int i = 0; - foreach (var item in RawInput) - { - sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}"); - i++; - } - sb.Append("-------------------------------"); - currDispData.currBitmap = sb.ToString(); - } - catch - { } - } - /// - /// Salva valori indicati in prod data - /// - /// Item KVP di cui salvare i dati in currProdData come chiave/valore - /// - public void saveProdData(KeyValuePair item) - { - // imposto i valori... - if (currProdData.ContainsKey(item.Key)) - { - currProdData[item.Key] = item.Value; - } - else - { - currProdData.Add(item.Key, item.Value); - } - } - /// - /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"= - /// - public bool procIotMem = false; - /// - /// porta x adapter (x restart) - /// - protected int adpPortNum; - /// - /// DataOra ultimo avvio adapter x watchdog - /// - protected DateTime adpStartRun; - /// - /// Data/ora ultimo avvio adapter - /// - public DateTime dtAvvioAdp = DateTime.Now; - /// - /// Data/ora ultimo spegnimento adapter - /// - public DateTime dtStopAdp = DateTime.Now; - /// - /// Oggetto cronometro x campionamento durate chiamate - /// - public Stopwatch stopwatch = new Stopwatch(); - /// - /// Conteggio ATTUALE ore macchina ON - /// - public double contOreMaccOn; - /// - /// Conteggio ATTUALE ore macchina IN LAVORO - /// - public double contOreMaccLav; - - /// - /// Data/ora ultima volta che IOB è stato dichairato online - /// - public DateTime lastIobOnline = DateTime.Now.AddHours(-1); - /// - /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) - /// - protected Dictionary TSVC_Data = new Dictionary(); - /// - /// Dizionario ultimi valori (double) delle TSVC - /// - protected Dictionary LastTSVC = new Dictionary(); - /// - /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a scadenza periodo...) - /// - protected Dictionary VarArray = new Dictionary(); - - #endregion - - /// - /// Form chiamante - /// - protected AdapterForm parentForm; - /// - /// Conf adapter corrente - /// - public IobConfiguration cIobConf; - /// - /// indica se serva refresh parametri e quindi PLC... - /// - protected bool needRefresh = true; - /// - /// Valore MINIMO limite x decidere invio di dati come array Json - /// - protected int minJsonData { get; set; } = utils.CRI("minJsonData"); - /// - /// Valore limite MASSIMO di invio di dati come array Json - /// - protected int maxJsonData { get; set; } = utils.CRI("maxJsonData"); - /// - /// Valore limite MASSIMO di invio di dati come array Json x EVENTI - /// - protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv"); - /// - /// Secondi standard x veto check status e log + /// Evento per incapsulare dati x refresh pagina /// - protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds"); - /// - /// ultimo tentativo connessione... - /// - protected DateTime lastConnectTry; - /// - /// Struttura memoria PLC x lettura/scrittura da JSON file - /// - public plcMemMap memMap; - /// - /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto - /// - /// - /// - public IobGeneric(AdapterForm caller, IobConfiguration IOBConf) - { - // init oggetto redis... - redisMan = new RedisIobCache(IOBConf.serverData.MPIP, IOBConf.codIOB); - - // salvo il form chiamante - parentForm = caller; - // configurazione... - cIobConf = IOBConf; - - lastConnectTry = DateTime.Now; - - // aggiungo nel logger IDX Macchina - lg = LogManager.GetCurrentClassLogger(); - - lgInfo("Avvio preliminare AdapterGeneric"); - // aggiungo altri defaults - setDefaults(true); - - setParamPlc(); - - // checkLogDir x shrink! - checkShrinkDir(); - - // concluso! - lgInfo("Istanziata classe preliminare IOBGeneric"); - } - /// - /// Imposto alcuni valori di default - /// - /// indica se sia richeisto di SVUOTARE le code delel info - private void setDefaults(bool resetQueue) - { - numSim = utils.CRI("numSim"); - lastPrgName = ""; - nReadIN = 0; - nReadFilt = 0; - nSendOut = 0; - currMode = 0; - lastAlarm = ""; - doStartMemDump = utils.CRB("doStartMemDump"); - doSampleMemory = utils.CRB("doSampleMemory"); - // svuoto code se richiesto - if (resetQueue) - { - QueueIN = new ConcurrentQueue(); - QueueFLog = new ConcurrentQueue(); - QueueAlarm = new ConcurrentQueue(); - QueueMessages = new ConcurrentQueue(); - } - // imposto contatori blink a zero... - i_counters = new int[32]; - lastPeriodicLog = DateTime.Now; - // fix parametri generali... - enablePrgName = true; - } - /// - /// Invia messaggio a logWatcher - /// - /// - /// - protected void sendToTaskWatch(string messType, string message) - { - parentForm.taskWatcher = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}"; - } - /// - /// Invia messaggio a logWatcher - /// - /// - /// - protected void sendToLogWatch(string messType, string message) - { - newDisplayData currDispData = new newDisplayData(); - currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}"; - parentForm.updateFormDisplay(currDispData); - } - /// - /// Invia messaggio a logWatcher - /// - /// - /// - /// - protected void sendToLogWatch(string messType, string message, params object[] args) - { - try - { - string expString = string.Format(message, args); - newDisplayData currDispData = new newDisplayData(); - currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}"; - parentForm.updateFormDisplay(currDispData); - } - catch - { } - } - /// - /// Invia messaggio a logWatcher - /// - /// - /// - /// - /// - protected void sendToLogWatch(string messType, string message, Exception exception, params object[] args) - { - try - { - string expString = string.Format(message, args); - newDisplayData currDispData = new newDisplayData(); - currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}{Environment.NewLine}{exception}"; - parentForm.updateFormDisplay(currDispData); - } - catch - { } - } - /// - /// Lettura memorie conf speciali (json) - /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json - /// - protected virtual void loadMemConf() - { - lgInfo("BEGIN loadMemConf"); - // variabili x gestione send contapezzi in blocco - string currPar = getOptPar("ENABLE_SEND_PZC_BLOCK"); - if (!string.IsNullOrEmpty(currPar)) - { - bool.TryParse(currPar, out enableSendPzCountBlock); - // se abilitato leggo num pezzi da reinviare in blocco - if (enableSendPzCountBlock) - { - int.TryParse(getOptPar("MAX_SEND_PZC_BLOCK"), out maxSendPzCountBlock); - int.TryParse(getOptPar("MIN_SEND_PZC_BLOCK"), out minSendPzCountBlock); - } - } - else - { - lgError("loadMemConf: parametro ENABLE_SEND_PZC_BLOCK non trovato, verificare anche MAX_SEND_PZC_BLOCK e MIN_SEND_PZC_BLOCK"); - } - // inizializzo LUT decodifica - string jsonConf = getOptPar("PARAM_CONF"); - if (!string.IsNullOrEmpty(jsonConf)) - { - string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{jsonConf}"; - lgInfo($"Apertura file {jsonFileName}"); - StreamReader reader = new StreamReader(jsonFileName); - string jsonData = reader.ReadToEnd(); - if (!string.IsNullOrEmpty(jsonData)) - { - lgInfo($"File json composto da {jsonData.Length} caratteri"); - try - { - memMap = JsonConvert.DeserializeObject(jsonData); - lgInfo($"Decodifica aree memMap: trovati {memMap.mMapRead.Count} valori TSVC"); - lgInfo($"Decodifica aree memMap: trovati {memMap.mMapWrite.Count} parametri "); - // se ho variabili read --> genero dati TSVC... - if (memMap.mMapRead.Count > 0) - { - TSVC_Data.Clear(); - LastTSVC.Clear(); - VCData currConf; - int periodo = 0; - VC_func funz = VC_func.POINT; - // accodo nella conf... - foreach (var item in memMap.mMapRead) - { - funz = item.Value.func; - periodo = item.Value.period; - currConf = new VCData() - { - Funzione = funz, - Period = periodo, - DTStart = DateTime.Now.AddHours(-1), - dataArray = new List() - }; - TSVC_Data.Add(item.Key, currConf); - } - // documento... - foreach (var item in TSVC_Data) - { - lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); - // salvo i valori PREC... - LastTSVC.Add(item.Key, 0); - } - } - // infine se obj memoria valido salvo in MP-IO x sue applicazioni - if (memMap != null) - { - // invio su cloud conf memoria... - string rawData = JsonConvert.SerializeObject(memMap); - utils.callUrlNow($"{urlSaveMemMap}", rawData); - // salvo ANCHE come parametri i valori... - objItem currItem = new objItem(); - List allParam = new List(); - // valori WRITE - foreach (var item in memMap.mMapWrite) - { - currItem = new objItem() - { - uid = item.Value.name, - name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, - writable = true - }; - allParam.Add(currItem); - } - // valori READ - foreach (var item in memMap.mMapRead) - { - currItem = new objItem() - { - uid = item.Value.name, - name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, - writable = false - }; - allParam.Add(currItem); - } - // invio su cloud parametri! - rawData = JsonConvert.SerializeObject(allParam); - utils.callUrl($"{urlSaveAllParams}", rawData); - } - } - catch (Exception exc) - { - lgError($"Eccezione in decodifica conf json{Environment.NewLine}{exc}"); - } - } - else - { - lgError("Errore in loadMemConf: file json vuoto!"); - } - reader.Dispose(); - } - else - { - lgInfo("loadMemConf: non trovata opzione PARAM_CONF in file INI"); - } - // loggo - lgInfo("DONE loadMemConf"); - } - /// - /// Impostazioni parametri PLC - /// - protected virtual void setParamPlc() - { - loadMemConf(); - fixDefaultPar(); - } - /// - /// Imposta eventuali altri valori default - /// - private void fixDefaultPar() + public class iobRefreshedEventArgs : EventArgs { - // parametro max tentativi PING... - string s_maxPingRetry = getOptPar("MAX_PING_RETRY"); - if (!string.IsNullOrEmpty(s_maxPingRetry)) - { - int numRetry = 5; - int.TryParse(s_maxPingRetry, out numRetry); - maxPingRetry = numRetry; - } + /// + /// classe obj privata + /// + private readonly newDisplayData _newDisplayData; + /// + /// salvataggio obj + /// + /// + public iobRefreshedEventArgs(newDisplayData newObject) + { + _newDisplayData = newObject; + } + /// + /// Proprietà lettura displayData aggiornato + /// + public newDisplayData DisplayDataObject + { + get { return _newDisplayData; } + } } - /// - /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - protected void lgInfo(string message, bool sendToForm = true) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Info(message); - if (sendToForm) - { - sendToLogWatch("INFO", message); - } - } - /// - /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - protected void lgInfo(string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Info(message, args); - sendToLogWatch("INFO", message, args); - } - /// - /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - protected void lgError(string message, bool sendToForm = true) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Error(message); - if (sendToForm) - { - sendToLogWatch("ERROR", message); - } - } - /// - /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - protected void lgError(string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Error(message, args); - sendToLogWatch("ERROR", message, args); - } - /// - /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - /// - protected void lgError(Exception exception, string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Error(exception, message, args); - sendToLogWatch("ERROR", message, exception, args); - } - /// - /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - protected void lgFatal(string message, bool sendToForm = true) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Fatal(message); - if (sendToForm) - { - sendToLogWatch("FATAL", message); - } - } - /// - /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - protected void lgFatal(string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Fatal(message, args); - sendToLogWatch("FATAL", message, args); - } - /// - /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - /// - /// - protected void lgFatal(Exception exception, string message, params object[] args) - { - lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; - lg.Fatal(exception, message, args); - sendToLogWatch("FATAL", message, exception, args); - } - - #region metodi adapter - - /// - /// Invia informazioni associazione IOB 2 machine - /// - protected void sendM2IOB() - { - if (checkServerAlive) - { - lgInfo("chiamata URL " + urlSetM2IOB); - utils.callUrlNow(urlSetM2IOB); - } - } - /// - /// Chiede elenco dei task da eseguire - /// - formato Json - /// - array di KVP / Dictionary - /// - formato definito da API x MP/IO/: - /// - KEY: task - /// - VALUE: array JSon KVP - /// - protected string getTask2exe() - { - string answ = ""; - if (checkServerAlive) - { - string url2call = $"{urlGetTask2Exe}"; - if (verboseLog) - { - lgInfo("chiamata URL " + url2call); - } - answ = utils.callUrlNow(url2call); - } - return answ; - } - /// - /// Stringa raw dei parametri da scrivere... - /// - /// - protected string getParams2write() - { - string answ = ""; - string url2call = $"{urlGetParams2Write}"; - if (verboseLog) - { - lgInfo("chiamata URL " + url2call); - } - answ = utils.callUrlNow(url2call); - // se vuoto faccio seconda prova... - if (string.IsNullOrEmpty(answ)) - { - answ = utils.callUrlNow(url2call); - } - return answ; - } - /// - /// Cancella dal server i task eseguiti - /// - /// - /// - /// - protected string remTask2exe(string taskName, string esitoTask) - { - string answ = ""; - if (checkServerAlive) - { - string url2call = $"{urlRemTask2Exe}{taskName}"; - lgInfo($"Task2Exe | {esitoTask} | chiamata URL {url2call}"); - answ = utils.callUrlNow(url2call); - } - return answ; - } - - /// - /// Invia al server IO i valori dei parametri opzionali (es counters) - /// - /// Nome parametro - /// Valore parametro - protected void sendOptVal(string paramName, string paramValue) - { - if (checkServerAlive) - { - string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}"; - lgInfo("chiamata URL " + url2call); - utils.callUrlNow(url2call); - } - } - /// - /// Invia al server IO i valori dei parametri opzionali (es counters) - /// - /// Nome parametro - /// Valore parametro INT - protected void sendOptVal(string paramName, int paramValueInt) - { - // override! - sendOptVal(paramName, paramValueInt.ToString()); - } - /// - /// Effettua rilettura del contapezzi dal server MP/IO - /// - /// Forza rilettura da DB tempi ciclo rilevati - public void pzCntReload(bool forceCountRec) - { - // legge da IO server ULTIMO valore CONTPEZZI al riavvio... - string currServerCount = ""; - string lastIdxODL = ""; - if (checkServerAlive) - { - // leggo PRIMA ODL .... - lastIdxODL = utils.callUrl(urlGetCurrODL); - lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL); - // se ho valori in coda da trasmettere uso dati REDIS - if (forceCountRec) + public class IobGeneric + { + #region variabili serializzate in REDIS + + /// + /// Oggetto connessione REDIS + /// + public RedisIobCache redisMan; + + + #endregion + + #region variabili ed oggetti base + + /// + /// Dizionario valori impostati x produzione + /// + protected Dictionary currProdData = new Dictionary(); + /// + /// TImeout x ping al server + /// + protected int pingServerMsTimeout = utils.CRI("pingMsTimeout"); + /// + /// Log verboso da configurazione (SOLO CHAIVE "verbose"... + /// + public bool isVerboseLog { get; set; } = utils.CRB("verbose"); + /// + /// Coda massima ammessa per FLog (se <=0 disattivata...) + /// + protected int maxQueueFLog { get; set; } = utils.CRI("maxQueueFLog"); + /// + /// stato Online/Offline della IOB + /// + public bool IobOnline { - // uso dati da TCiclo registrati... - currServerCount = utils.callUrl(urlGetPzCountRec); - lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount); - } - else - { - // uso il contapezzi dichiarato dall'IOB stesso - currServerCount = utils.callUrl(urlGetPzCount); - lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount); - } - // controllo: SE NON HO ODL... - if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0") - { - // NON AGGIORNO - contapezzi = lastCountCNC; - lgInfo($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezzi} | lastCountCNC {lastCountCNC}"); - } - else - { - if (!string.IsNullOrEmpty(currServerCount)) - { - // se "-1" resto a ultimo... - if (currServerCount != "-1") + get { - int newVal = -1; - Int32.TryParse(currServerCount, out newVal); - contapezzi = newVal > -1 ? newVal : contapezzi; - lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount); - } - else - { - // NON AGGIORNO - contapezzi = lastCountCNC; - lgInfo("Errore lettura contapezzi (-1) - uso lastCountCNC --> " + contapezzi); - } - } - else - { - // registro che ho UN NUOVO ODL - lgInfo(string.Format("Lettura ODL in pzCntReload, {0} --> {1}", currIdxODL, lastIdxODL)); - // provo a salvare nuovo ODL - int.TryParse(lastIdxODL, out currIdxODL); - // segno contapezzi a zero... - contapezzi = 0; - lgInfo("RESET contapezzi (ZERO)"); - - } - } - } - else - { - // se server NON pronto... - contapezzi = lastCountCNC; - lgError("Errore server NON pronto in pzCntReload"); - } - } - - /// - /// Avvia l'adapter sulla porta richiesta - /// - /// indica se sia richeisto di SVUOTARE le code delel info - public virtual void startAdapter(bool resetQueue) - { - lgInfo("Starting adapter..."); - maxJsonData = utils.CRI("maxJsonData"); - maxJsonDataEv = utils.CRI("maxJsonDataEv"); - parentForm.commPlcActive = false; - adpRunning = true; - dtAvvioAdp = DateTime.Now; - lastWatchDog = dtAvvioAdp; - lastPING = dtAvvioAdp; - lastReadPLC = dtAvvioAdp.AddMinutes(-1); - lastDisconnCheck = dtAvvioAdp; - TimingData.resetData(); - // aggiungo altri defaults - setDefaults(resetQueue); - adpTryRestart = true; - parentForm.displayTaskAndLog("Adapter Started!"); - } - - /// - /// ferma l'adapter... - /// - /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico) - /// indica se sia richeisto di SVUOTARE le code delel info - public virtual void stopAdapter(bool tryRestart, bool forceDequeue) - { - if (forceDequeue) - { - // svuoto le code dei valori letti e non ancora trasmessi... - parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali..."); - while (QueueIN.Count > 0) - { - // INVIO COMUNQUE...!!! - string valore = ""; - QueueIN.TryDequeue(out valore); - sendToMoonPro(urlType.SignIN, valore); - } - parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG..."); - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > minJsonData) - { - while (QueueFLog.Count > 0) - { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueFLog.Count > maxJsonData) - { - string currVal = ""; - // prendoi primi maxJsonDataValori - for (int i = 0; i < maxJsonData; i++) - { - QueueFLog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.FLog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueFLog.ToList(); - // invio - sendDataBlock(urlType.FLog, listaValori); - // svuoto! - QueueFLog = new ConcurrentQueue(); - } - } - // HO FINITO invio di FLog... - } - else - { - string currVal = ""; - while (QueueFLog.Count > 0) - { - // INVIO COMUNQUE...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); - } - } - } - parentForm.displayTaskAndLog("Stopping adapter..."); - adpTryRestart = false; - - parentForm.displayTaskAndLog("Stopping adapter - last periodic data read..."); - - // chiudo la connessione all'adapter... - tryDisconnect(); - dtStopAdp = DateTime.Now; - adpTryRestart = tryRestart; - adpRunning = false; - // chiudo! - parentForm.displayTaskAndLog("Adapter Stopped."); - parentForm.commPlcActive = false; - } - - /// - /// effettua recupero dati ed invio valori modificati... - /// - /// - public void getAndSend(gatherCycle ciclo) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! - try - { - trySendValues(); - } - catch (Exception exc) - { - lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria"); - currDispData.semOut = Semaforo.SR; - } - // controllo connessione/connettività - if (connectionOk) - { - // controllo non sia già in esecuzione... - if (!adpCommAct) - { - // provo ad avviare - try - { - // imposto flag adapter running.. - adpCommAct = true; - adpStartRun = DateTime.Now; - } - catch (Exception exc) - { - string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}"; - adpCommAct = false; - adpStartRun = DateTime.Now; - currDispData.newLiveLogData = errore; - } - if (adpCommAct) - { - // try / catch generale altrimenti segno che è disconnesso... - try - { - bool showDebugData = false; - if (ciclo == gatherCycle.VHF) - { - processVHF(); - } - // processing dati memoria (lettura, filtraggio, enqueque) - else if (ciclo == gatherCycle.HF) - { - processWhatchDog(); - processAllMemory(); - processMode(); - } - else if (ciclo == gatherCycle.MF) - { - processServerRequests(); - processOverride(); - processContapezzi(); - processCncAlarms(); - processDynData(); - } - else if (ciclo == gatherCycle.LF) - { - processOtherCounters(); - processProgram(); - // verifico se devo gestire cambio ODL in modo automatico - processAutoOdl(); - } - else if (ciclo == gatherCycle.VLF) - { - if (utils.CRB("enableContapezzi")) - { - // rilettura contapezzi da server... - lgInfo("Ciclo VLF: pzCntReload(true)"); - if (!isMulti) - { - pzCntReload(true); - } - // refresh associazione Macchina - IOB - sendM2IOB(); - } - // recupero dati SETUP (sysinfo) e li invio/mostro se variati... - processSysInfo(); - // checkLogDir x shrink! - checkShrinkDir(); - // eventuale log! - if (utils.CRB("recTime")) - { - logTimeResults(); - } - } - // mostra eventuali altri dati di processo... - reportDataProc(); - if (showDebugData) - { - // verifica se debba salvare e mostrare dati - checkSavePersDataLayer(); - } - } - catch (Exception exc) - { - // segnalo eccezione e indico disconnesso... - lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); - parentForm.fermaAdapter(true, false, true); - } - // tolgo flag running - adpCommAct = false; - } - else - { - if (periodicLog) - { - lgInfo("ADP not running..."); - } - } - } - else - { - // log ADP running - lgError("Non eseguo chiamata: ADP ancora in running"); - // se è bloccato da oltre maxSec lo sblocco... - if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec")) - { - // tolgo flag running - adpCommAct = false; - adpStartRun = DateTime.Now; - } - } - } - else - { - // provo a riconnettere SE abilitato tryRestart... - if (adpTryRestart && !connectionOk) - { - // controllo se sia scaduto periodi di veto al tryConnect... - int waitRecMSec = utils.CRI("waitRecMSec") * 2; - DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec); - if (DateTime.Now > dtVeto) - { - lgInfo($"Retry Time Elapsed (waited for {waitRecMSec} ms)--> NOW tryConnect"); - lastConnectTry = DateTime.Now; - tryConnect(); - } - } - currDispData.semIn = Semaforo.SR; - } - raiseRefresh(currDispData); - } - - protected void raiseRefresh(newDisplayData currDispData) - { - if (currDispData.hasData) - { - // segnalo refresh! - if (eh_refreshed != null) - { - eh_refreshed(this, new iobRefreshedEventArgs(currDispData)); - } - } - } - - /// - /// Cerca di inviare su un altro thread i vari dati accumulati... - /// - private void trySendValues() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - try - { - // verifico se risponde il server... - if (checkServerAlive) - { - bool iobOk = false; - if (utils.CRB("sendDataByThread")) - { - Task taskCheck = TaskEx.Run(() => iobOk = checkIobEnabled); - } - else - { - iobOk = checkIobEnabled; - } - // verifico SE posso inviare dati - if (iobOk) - { - currDispData.semOut = Semaforo.SV; - // verificare come gestire il task secondario senza interferenza (chiamate update su FORM da thread secondari danno errori) - if (utils.CRB("sendDataByThread")) - { - // invio con thread separato... - Task taskSigIN = TaskEx.Run(() => svuotaCodaSignIN()); - Task taskFlog = TaskEx.Run(() => svuotaCodaFLog()); - } - else - { - // gestione queue SignalIN (invio, display) - svuotaCodaSignIN(); - currDispData.counter = contapezzi; - raiseRefresh(currDispData); - // provo a svuotare coda contapezzi - svuotaCodaContapezzi(); - currDispData.counter = contapezzi; - raiseRefresh(currDispData); - // gestione queue FluxLog (invio, display) - svuotaCodaFLog(); - raiseRefresh(currDispData); - } - } - else - { - // mostro VETO-SEND x invio... GIALLO - currDispData.semOut = Semaforo.SG; - if (periodicLog) - { - lgInfo("IOB - VETO SEND"); - } - } - } - else - { - // mostro SERVER KO x invio... ROSSO - currDispData.semOut = Semaforo.SR; - if (periodicLog) - { - lgInfo("IOB - SERVER NOT READY"); - } - } - } - catch (Exception exc) - { - lgError($"Errore in fase trySendValues{Environment.NewLine}{exc}"); - currDispData.semOut = Semaforo.SR; - } - raiseRefresh(currDispData); - } - - private void svuotaCodaContapezzi() - { - // permetto al max 2 tentativi infruttuosi... - int maxTry = 2; - int oldContapezzi = contapezzi; - // se ho contapezzi OLTRE limite... - while ((MPOnline) && (lastCountCNC > contapezzi + minSendPzCountBlock)) - { - lgInfo($"Ciclo svuotaCodaContapezzi --> lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi}"); - if (!isMulti) - { - pzCntReload(true); - } - // provo invio - trySendPzCountBlock(); - // verifica per evitare loop infinito invio fallito - if (oldContapezzi == contapezzi) - { - maxTry--; - } - else - { - maxTry = 2; - oldContapezzi = contapezzi; - } - // verifico maxTry: se li ho esauriti esco! - if (maxTry <= 0) - { - return; - } - // aspetto x dare tempo calcolo - Thread.Sleep(400); - } - } - - /// - /// Effettua ciclo controllo richieste server - /// - public void processServerRequests() - { - Dictionary task2exe = new Dictionary(); - Dictionary taskDone = new Dictionary(); - // recupero elenco delle cose da fare - string resp = getTask2exe(); - if (!string.IsNullOrEmpty(resp)) - { - try - { - task2exe = JsonConvert.DeserializeObject>(resp); - // se ho da fare chiamo esecuzione.. - if (task2exe.Count > 0) - { - taskDone = processTask(task2exe); - } - } - catch (Exception exc) - { - lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); - } - } - } - - public Dictionary processTask(Dictionary task2exe) - { - Dictionary taskDone = new Dictionary(); - if (task2exe != null) - { - lgInfo($"Task2Exe: trovati {task2exe.Count} task da eseguire, procedo"); - // chiamo procedura esecutiva (diversa x ogni IOB) - taskDone = executeTasks(task2exe); - // loggo tutti i task done... - foreach (var item in taskDone) - { - sendToTaskWatch(item.Key, item.Value); - } - // ora chiamo la cancellazione dei task eseguiti... - foreach (var item in taskDone) - { - remTask2exe(item.Key, item.Value); - } - } - return taskDone; - } - - /// - /// Esecuzione dei task richiesti e pulizia coda richieste eseguite - /// - /// - public virtual Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - if (task2exe != null) - { - bool taskOk = false; - string taskVal = ""; - // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY... - switch (tName) - { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceSetPzCount: - case taskType.sendWatchDogMes2Plc: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.setArt: - case taskType.setComm: - case taskType.setProg: - case taskType.setPzComm: - // recupero dati da memMap... - if (memMap.mMapWrite.ContainsKey(item.Key)) - { - dataConf currMem = memMap.mMapWrite[item.Key]; - string addr = currMem.memAddr; - taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte"; - // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà - memMap.mMapWrite[item.Key].value = item.Value; - } - else - { - taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}"; - } - break; - case taskType.forceResetPzCount: - // reset contapezzi inizio setup - taskOk = resetContapezziCNC(); - taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.startSetup: - // reset contapezzi inizio setup - taskOk = resetContapezziCNC(); - taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.stopSetup: - // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO - if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") - { - taskOk = resetContapezziCNC(); - } - taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; - lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.setParameter: - // richiedo da URL i parametri WRITE da popolare - lgInfo("Chiamata processMemWriteRequests"); - taskVal = processMemWriteRequests(); - // se restituiscce "" faccio altra prova... - if (string.IsNullOrEmpty(taskVal)) - { - // i parametri me li aspetto come stringa composta paramName|paramvalue - if (item.Value.Contains("|")) - { - string[] paramsJob = item.Value.Split('|'); - taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; - } - else - { - taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; - } - } - break; - default: - taskVal = "SKIPPED | NO EXEC"; - lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - } - } - return taskDone; - } - /// - /// Processa le richieste di scrittura memoria - /// - /// - protected string processMemWriteRequests() - { - string answ = ""; - // li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC) - List writeList = new List(); - List updatedPar = new List(); - // recupero elenco delle cose da fare - string resp = getParams2write(); - if (!string.IsNullOrEmpty(resp)) - { - try - { - writeList = JsonConvert.DeserializeObject>(resp); - // se ho da fare chiamo esecuzione.. - if (writeList.Count > 0) - { - foreach (var item in writeList) - { - // scrivo in memoria - if (memMap.mMapWrite.ContainsKey(item.uid)) - { - memMap.mMapWrite[item.uid].value = item.reqValue; - // accodo in stringa taskVal... - answ += $" | Parameter {item.uid} --> {item.reqValue}"; - // sistemo valori - item.value = item.reqValue; - lgInfo($"Effettuato update parametro: actVal = {item.value} | reqVal = {item.reqValue}"); - item.reqValue = ""; - // salvo in lista da ritrasmettere - updatedPar.Add(item); - } - else - { - answ += $" | Error: parameter {item.uid} not found"; - } - } - // richiamo scrittura parametri su PLC - plcWriteParams(updatedPar); - // invio su cloud parametri! - string rawData = JsonConvert.SerializeObject(updatedPar); - utils.callUrl($"{urlUpdateWriteParams}", rawData); - } - } - catch (Exception exc) - { - lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); - } - } - else - { - lgError("Non è stata ricevuta risposta x task da eseguire"); - } - return answ; - } - /// - /// Metodo da overridare x scrivere DAVVERO i aprametri sul PLC - /// - /// - protected virtual void plcWriteParams(List updatedPar) - { - // non faccio nulla di base... - } - - /// - /// Metodo generico di reset contapezzi... - /// - /// - public virtual bool resetContapezziCNC() - { - return false; - } - /// - /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... - /// - /// Pezzi richiesti - /// - public virtual bool setContapezziCNC(int newPzCount) - { - return false; - } - - /// - /// Verifica e se necessario comprime directory log... - /// - private void checkShrinkDir() - { - string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB); - baseUtils.shrinkDir(path); - } - - private void reportDataProc() - { - // update valori visualizzazione... - parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut); - } - - /// - /// riporta il log di tutti i dati di results temporali registrati - /// - public void logTimeResults() - { - if (TimingData.results.Count > 0) - { - lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); - int globNumCall = 0; - TimeSpan globAvgMsec = new TimeSpan(0); - foreach (TimeRec item in TimingData.results) - { - // loggo SOLO se del mio IOB corrente... - if (item.classCall == cIobConf.codIOB) - { - lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); - globNumCall += item.numCall; - globAvgMsec += item.totMsec; - } - } - // riporto conteggio medio al secondo... - lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); - lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine); - // mostro in form statistiche globali! - parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds)); - } - } - /// - /// processa dataLayer e se necessario salva/mostra - /// - public static void checkSavePersDataLayer() - { - } - public static void resetDebugConsole() - { - } - - /// - /// Metodo base connessione... - /// - public virtual void tryConnect() - { - dtAvvioAdp = DateTime.Now; - } - /// - /// Metodo base disconnessione... - /// - public virtual void tryDisconnect() - { - - } - protected bool _connOk = false; - /// - /// Salva verifica stato connessione OK - /// - /// - public virtual bool connectionOk - { - get - { - return _connOk || DemoIn; - } - set - { - _connOk = value; - } - } - /// - /// Max tentativi ping permessi (default: 5) - /// - protected int maxPingRetry { get; set; } = 5; - - /// - /// indica se ping disabilitato da optPar - /// - public bool pingDisabled - { - get - { - bool answ = false; - bool.TryParse(getOptPar("NO_PING"), out answ); - return answ; - } - } - /// - /// test ping all'indirizzo PLC/CNC impostato nei parametri - /// - /// - protected IPStatus testPingMachine - { - get - { - IPStatus answ = IPStatus.Unknown; - // se disabilitato salto... - if (pingDisabled) - { - answ = IPStatus.Success; - } - else - { - IPAddress address; - PingReply reply; - using (Ping pingSender = new Ping()) - { - address = IPAddress.Loopback; - IPAddress.TryParse(cIobConf.cncIpAddr, out address); - int pingMsTimeout = cIobConf.pingMsTimeout; - reply = pingSender.Send(address, pingMsTimeout); - answ = reply.Status; - } - } - return answ; - } - } - - #endregion - - #region layer persistenza dati - - /// - /// Dizionario di persistenza per i valori da salvare da/su file - /// - public Dictionary persistenceLayer; - - /// - /// recupera valore salvato in persistence layer (se non c'è crea...) - /// - /// - /// - private string getStoredVal(string keyVal) - { - string value = ""; - try - { - if (persistenceLayer != null) - { - if (!persistenceLayer.TryGetValue(keyVal, out value)) - { - persistenceLayer.Add(keyVal, "0"); - } - } - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); - } - return value; - } - /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT - /// - /// - /// - private uint getStoredValUInt(string keyVal) - { - uint answ = 0; - try - { - answ = Convert.ToUInt32(getStoredVal(keyVal)); - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc)); - } - // verifico che il valore sia minore di 9/10 del valore massimo... - answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0; - return answ; - } - /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come INT - /// - /// - /// - private long getStoredValLong(string keyVal) - { - long answ = 0; - try - { - answ = Convert.ToInt64(getStoredVal(keyVal)); - } - catch - { } - // verifico che il valore sia minore di 9/10 del valore massimo... - answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0; - return answ; - } - /// - /// recupera valore salvato in persistence layer (se non c'è crea...) come double - /// - /// - /// - private double getStoredValDouble(string keyVal) - { - double answ = 0; - try - { - answ = Convert.ToDouble(getStoredVal(keyVal)); - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc)); - } - answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0; - return answ; - } - - /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE - /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValString(int i, string newVal, string searchString) - { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal; - } - /// - /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce - /// - /// - /// - /// - /// Nuovo valore incrementato - private void updateValUInt(int i, uint newVal, string searchString) - { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // salvo in ram! - persistenceLayer[keyVal] = newVal.ToString(); - } - /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce - /// - /// - /// - /// - /// Nuovo valore incrementato - private uint updateValUIntByIncr(int i, uint delta, string searchString) - { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - uint contAct = getStoredValUInt(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; - } - /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce - /// - /// - /// - /// - /// Nuovo valore incrementato - private long updateValLongByIncr(int i, long delta, string searchString) - { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - long contAct = getStoredValLong(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; - } - /// - /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce - /// - /// - /// - /// - /// Nuovo valore incrementato - private double updateValDoubleByIncr(int i, double delta, string searchString) - { - // stringa da cercare.. - string keyVal = string.Format(searchString, i + 1); - // recupero valore precedente... - double contAct = getStoredValDouble(keyVal); - // nuovo valore... - contAct += delta; - // salvo in ram! - persistenceLayer[keyVal] = contAct.ToString(); - // rendo il valore! - return contAct; - } - - #endregion - - #region area lettura configurazioni - - /// - /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria - /// - /// nome vettore memoria - /// file origine - /// dimensione (in byte) della memoria - /// dimensione (in byte) della memoria - protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett) - { - otherData lastData = new otherData(); - int totRighe = 0; - string linea; - totRighe = File.ReadLines(nomeFile).Count(); - // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco... - vettoreConf = new otherData[File.ReadLines(nomeFile).Count()]; - // carica da file... - StreamReader file = new StreamReader(nomeFile); - // leggo 1 linea alla volta... - int numRiga = 0; - int bitNum = 0; - int byteNum = 0; - while ((linea = file.ReadLine()) != null) - { - // SE non è un commento... - if (linea.Substring(0, 1) != "#") - { - // se finisce per BIT allora processo bit-a-bit... - if (linea.EndsWith("BOOL")) - { - try - { - string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.'); - // calcolo bit e byte number... - int.TryParse(memIdx[0], out byteNum); - if (memIdx.Length > 1) - { - int.TryParse(memIdx[1], out bitNum); - } - else - { - bitNum = 0; - } - } - catch - { - byteNum = 0; - bitNum = 0; - } - lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum); - vettoreConf[numRiga] = lastData; - } - else - { - lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize); - vettoreConf[numRiga] = lastData; - } - numRiga++; - } - } - // salvo lunghezza file... - try - { - numVett = Convert.ToInt32(lastData.memAddr) + 1; - } - catch - { - numVett = numRiga + 1; - } - // chiudo file - file.Close(); - // ora trimmo vettore al solo numero VERO dei valori caricati... - Array.Resize(ref vettoreConf, numRiga); - - if (isVerboseLog) - { - lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile)); - } - } - /// - /// Decodifica file MAP generico - /// - /// - /// - /// - /// - /// - /// - protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) - { - string[] valori = linea.Split(separator); - int shift = 0; - try - { - shift = Convert.ToInt32(valori[0]) - 1; - } - catch - { } - string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); - return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); - } - /// - /// Decodifica file MAP (caso .bit) - /// - /// - /// - /// indirizzo Byte: indirizzo di partenza memoria - /// dimensione singolo slot in byte - /// indirizzo bit: numero riga x calcolo indice bit - /// - protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) - { - string[] valori = linea.Split(separator); - int shift = 0; - try - { - shift = Convert.ToInt32(valori[0]) - 1; - } - catch - { } - int resto = 0; - Math.DivRem(BitNum, 8, out resto); - string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); - return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); - } - /// - /// Cerca se esiste il parametro opzionale e lo restituisce - /// - /// - /// - public string getOptPar(string key) - { - string answ = ""; - if (cIobConf.optPar.Count > 0) - { - // controllo SE HO il parametro - if (cIobConf.optPar.ContainsKey(key)) - { - answ = cIobConf.optPar[key]; - } - } - return answ; - } - /// - /// Cerca parametri opzionali in modalità "like" del nome - /// - /// - /// - public Dictionary findOptPar(string keyStartSearch = "") - { - Dictionary answ = new Dictionary(); - // controllo SE keySearch !="" - if (!string.IsNullOrWhiteSpace(keyStartSearch)) - { - if (cIobConf.optPar.Count > 0) - { - // ciclo su tutti e cerco occorrenze che INIZINO... - foreach (var item in cIobConf.optPar) - { - if (item.Key.StartsWith(keyStartSearch)) - { - answ.Add(item.Key, item.Value); - } - } - } - } - return answ; - } - - - - #endregion - - #region IOB METHODS - - /// - /// Valore del num max invii consecutivi da coda... - /// - protected static int nMaxSend - { - get - { - int answ = 5; - try - { - answ = utils.CRI("nMaxSend"); - } - catch - { } - return answ; - } - } - /// - /// DateTime Ultimo valore simulazione generato - /// - public DateTime lastSim; - /// - /// contatore x simulazione valori input - /// - public int countSim = 0; - /// - /// URL per check alive... - /// - public string urlAlive - { - get - { - return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE); - } - } - /// - /// URL per check se abilitato... - /// - public string urlIobEnabled - { - get - { - return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB); - } - } - /// - /// URL per recupero inizio ODL... - /// - public string urlInizioOdlIob - { - get - { - return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_ODL_STARTED, cIobConf.codIOB); - } - } - /// - /// URL per recupero idle time IOB... - /// - public string urlIdleTime - { - get - { - return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_IDLE_TIME, cIobConf.codIOB); - } - } - /// - /// URL per forzare split ODL... - /// - public string urlForceSplit - { - get - { - return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_FORCLE_SPLIT_ODL, cIobConf.codIOB); - } - } - /// - /// URL per segnalazione reboot... - /// - public string urlReboot - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress()); - } - catch - { - answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB); - } - return answ; - } - } - /// - /// URL per salvataggio contapezzi... - /// - public string urlGetCurrODL - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlGetCurrODL"); - } - return answ; - } - } - /// - /// URL per salvataggio contapezzi... - /// - public string urlSetPzCount - { - get - { - string answ = ""; - try - { - answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/{cIobConf.codIOB}?counter="; - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSetPzCount"); - } - return answ; - } - } - /// - /// URL per salvataggio contapezzi (quelli della macchina: PLC/CNC)... - /// - public string urlSetPzCountMAC - { - get - { - string answ = ""; - try - { - answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/MAC_{cIobConf.codIOB}?counter="; - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSetPzCountMAC"); - } - return answ; - } - } - /// - /// URL per INVIO IN BLOCCO di un INCREMENTO x contapezzi (quelli della macchina: PLC/CNC)... - /// - public string urlAddPzCount - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/savePzCountInc/{3}?qty=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlAddPzCount"); - } - return answ; - } - } - /// - /// URL per salvataggio VALORI opzionali... - /// - public string urlSetOptVal - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSetOptVal"); - } - return answ; - } - } - /// - /// URL per richiamo parametri da scrivere... - /// - public string urlGetParams2Write - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/getObjItems2Write/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlGetParams2Write"); - } - return answ; - } - } - /// - /// URL per richiamo task da eseguire... - /// - public string urlGetTask2Exe - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlGetTask2Exe"); - } - return answ; - } - } - /// - /// URL per richiamo task da eseguire... - /// - public string urlRemTask2Exe - { - get - { - string answ = ""; - try - { - answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlRemTask2Exe"); - } - return answ; - } - } - /// - /// URL per recupero contapezzi... - /// - public string urlGetPzCount - { - get - { - string answ = ""; - try - { - answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounter/{cIobConf.codIOB}"; - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlGetPzCount"); - } - return answ; - } - } - /// - /// URL per recupero contapezzi REGISTRATI da TC... - /// - public string urlGetPzCountRec - { - get - { - string answ = ""; - try - { - answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounterTCRec/{cIobConf.codIOB}"; - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlGetPzCountRec"); - } - return answ; - } - } - /// - /// URL per salvataggio dati associazione Machine 2 IOB... - /// - public string urlSetM2IOB - { - get - { - string answ = ""; - try - { - string machineName = Environment.MachineName; - answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSetM2IOB"); - } - return answ; - } - } - /// - /// URL per salvataggio dati conf memoria IOB... - /// - public string urlSaveMemMap - { - get - { - string answ = ""; - try - { - string machineName = Environment.MachineName; - answ = string.Format(@"http://{0}{1}{2}/saveConf/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSaveMemConf"); - } - return answ; - } - } - /// - /// URL per salvataggio dati PARAMETRI IOB... - /// - public string urlSaveAllParams - { - get - { - string answ = ""; - try - { - string machineName = Environment.MachineName; - string apiCall = "setObjItems"; - answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSaveMemConf"); - } - return answ; - } - } - /// - /// URL per salvataggio in UPSERT dei PARAMETRI IOB scritti... - /// - public string urlUpdateWriteParams - { - get - { - string answ = ""; - try - { - string machineName = Environment.MachineName; - string apiCall = "upsertObjItems"; - answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB); - } - catch (Exception exc) - { - lgError(exc, "Errore in composizione urlSaveMemConf"); - } - return answ; - } - } - public static string GetMACAddress() - { - NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); - String sMacAddress = string.Empty; - foreach (NetworkInterface adapter in nics) - { - if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card - { - IPInterfaceProperties properties = adapter.GetIPProperties(); - //sMacAddress = adapter.GetPhysicalAddress().ToString(); - sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); - } - } - return sMacAddress; - } - /// - /// Fornisce URL INPUT per i parametri richiesti - /// - /// valore salvato in coda formato dtEve#valore#counter - /// - public string urlInput(string queueVal) - { - // URL base x input - string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE); - // decodifica valore! - string[] valori = qDecodeIN(queueVal); - // aggiungo macchina e valore... - answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]); - // aggiondo dataOra evento e corrente + contatore... - answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]); - return answ; - } - /// - /// Fornisce URL di tipo FluxLog - /// - /// valore salvato in coda nel formato dtEve#flux#valore#counter - /// - public string urlFLog(string queueVal) - { - // URL base x input - string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG); - // decodifica valore! - string[] valori = qDecodeIN(queueVal); - // aggiungo macchina e valore... - answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); - // aggiondo dataOra evento e corrente + contatore... - answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); - return answ; - } - /// - /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi - /// - /// - /// - public string urlDataBlock(urlType tipoUrl) - { - // verifico la parte di link "tipoComando" - string tipoComando = tipoUrl == urlType.FLog ? cIobConf.serverData.CMDFLOG_JSON : cIobConf.serverData.CMDBASE_JSON; - // URL base x input - string answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, tipoComando, cIobConf.codIOB); - return answ; - } - /// - /// Restituisce un payload in formato json della lista di valori ricevuta - /// - /// Tipo di URL (eventi / FLog) - /// elenco di valori da coda string salvata - /// - public string jsonPayload(urlType tipoUrl, List elencoValori) - { - string answ = ""; - if (tipoUrl == urlType.FLog) - { - flogData currData = new flogData(); - flogJsonPayload fullObj = new flogJsonPayload(); - fullObj.fluxData = new List(); - string[] valori; - int counter = 0; - DateTime dtEve = DateTime.Now; - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - //DateTime.TryParse(valori[0], out dtEve); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[3], out counter); - currData = new flogData() - { - flux = valori[1], - valore = valori[2], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullObj.fluxData.Add(currData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullObj); - } - catch (Exception exc) - { - lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - } - else - { - evData currData = new evData(); - evJsonPayload fullObj = new evJsonPayload(); - fullObj.eventList = new List(); - string[] valori; - int counter = 0; - DateTime dtEve = DateTime.Now; - // inizio processando ogni valore - foreach (var item in elencoValori) - { - valori = qDecodeIN(item); - //DateTime.TryParse(valori[0], out dtEve); - CultureInfo provider = CultureInfo.InvariantCulture; - DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); - int.TryParse(valori[2], out counter); - currData = new evData() - { - valore = valori[1], - dtEve = dtEve, - dtCurr = DateTime.Now, - cnt = counter - }; - fullObj.eventList.Add(currData); - } - // conversione finale - try - { - answ = JsonConvert.SerializeObject(fullObj); - } - catch (Exception exc) - { - lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); - } - } - return answ; - } - /// - /// Reset dei webclients - /// - public static void resetWebClients() - { - utils.resetWebClients(); - } - /// - /// Effettua chiamata URL e restituisce risultato - /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrl(string URL, bool doAsync) - { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) - { - //Task resp = utils.callUrlAsync(URL); - //answ = resp.Result; - answ = utils.callUrlAsync(URL); - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL); - } - return answ; - } - /// - /// Effettua chiamata URL e restituisce risultato - /// - /// - /// - /// invio in modalità async (NON GARANTITO ordine...) - /// - public static string callUrlWithPayload(string URL, string payload, bool doAsync) - { - string answ = ""; - // Chiamata ASINCRONA - if (doAsync) - { - answ = utils.callUrlAsync(URL, payload); - } - // chiamata SOLO NORMALE SINCRONA... - else - { - answ = utils.callUrl(URL, payload); - } - return answ; - } - /// - /// test ping all'indirizzo impostato nei parametri - /// - /// - private IPStatus testPingServer - { - get - { - IPStatus answ = IPStatus.Unknown; ; - IPAddress address; - PingReply reply; - using (Ping pingSender = new Ping()) - { - address = IPAddress.Loopback; - int maxRetry = maxPingRetry + 1; - int numRetry = 1; ; - string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", ""); - IPAddress.TryParse(ipAdrr, out address); - reply = pingSender.Send(address, pingServerMsTimeout); - // se ho timeout riprovo... - while (reply.Status != IPStatus.Success && numRetry < maxRetry) - { - lgInfo($"Ping KO | reply: {reply.Status} --> retry"); - reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2); - numRetry++; - if (reply.Status == IPStatus.Success) - { - lgInfo("PING OK!"); - break; + return utils.IOB_Online; } - } - } - answ = reply.Status; - return answ; - } - } - /// - /// Verifica se il server sia ALIVE (tramite PING) - /// - public bool checkServerAlive - { - get - { - bool answ = false; - // controllo se ho un VETO all'invio... - if (dtVetoPing < DateTime.Now) - { - if (DemoOut) - { - answ = false; - } - else - { - IPStatus pingStatus = testPingServer; - // se passa il ping faccio il resto... - if (pingStatus == IPStatus.Success) - { - string callResp = ""; - try - { - // chiamo URL, se restituisce "OK" è alive! - callResp = callUrl(urlAlive, false); - answ = (callResp == "OK"); - } - catch (Exception exc) - { - lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc); - } - // attesa casuale se necessario - var rand = new Random(); - // primi 3 test - int maxTry = 3; - while (maxTry > 0 && !answ) - { - try - { - Thread.Sleep(rand.Next(150, 500)); - callResp = callUrl(urlAlive, false); - answ = (callResp == "OK"); - maxTry--; - } - catch - { } - } - // se NON OK riprovo ANCORA 1 volta... - if (!answ) - { - resetWebClients(); - Thread.Sleep(rand.Next(500, 1000)); - callResp = callUrl(urlAlive, false); - answ = (callResp == "OK"); - } - // altri 3 - maxTry = 3; - while (maxTry > 0 && !answ) - { - try - { - Thread.Sleep(rand.Next(150, 500)); - callResp = callUrl(urlAlive, false); - answ = (callResp == "OK"); - maxTry--; - } - catch - { } - } - // verifico SE è variato stato online/offline... - if (MPOnline != answ) - { - // se ORA sono online riporto... - if (answ) - { - lgInfo("SERVER ONLINE in checkServerAlive"); - parentForm.commSrvActive = 1; - dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec); - } - else - { - lgInfo("SERVER OFFLINE in checkServerAlive"); - parentForm.commSrvActive = 0; - } - // salvo nuovo status... - MPOnline = answ; - } - else - { - // allungo periodo controllo... - dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3); - } - } - else - { - lgInfo($"SERVER NOT RESPONDING (PING at {cIobConf.serverData.MPIP})"); - MPOnline = false; - // imposto veto a 10 volte reinvio dati standard... - dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3); - utils.dtVetoSend = dtVetoPing; - } - } - } - else - { - // altrimenti passo ultimo valore noto... - answ = MPOnline; - } - return answ; - } - } - /// - /// Verifica se la IOB sia ENABLED (da server o Demo) - /// - private bool checkIobEnabled - { - get - { - bool answ = false; - // controllo se ho veto al check... - if (dtVetoCheckIOB < DateTime.Now) - { - if (DemoOut) - { - answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); - } - else - { - try - { - // chiamo URL, se restituisce "OK" è enabled! - string callResp = callUrl(urlIobEnabled, true); - answ = (callResp == "OK"); - // attesa casuale se necessario - var rand = new Random(); - // primi 2 test - int maxTry = 2; - while (maxTry > 0 && !answ) - { - Thread.Sleep(rand.Next(250, 500)); - callResp = callUrl(urlIobEnabled, true); - answ = (callResp == "OK"); - maxTry--; - } - // se NON OK riprovo ANCORA 1 volta... - if (!answ) - { - resetWebClients(); - Thread.Sleep(rand.Next(250, 1000)); - callResp = callUrl(urlIobEnabled, false); - answ = (callResp == "OK"); - } - // altri 2 - maxTry = 2; - while (maxTry > 0 && !answ) - { - Thread.Sleep(rand.Next(250, 500)); - callResp = callUrl(urlIobEnabled, false); - answ = (callResp == "OK"); - maxTry--; - } - // salvo status... - IobOnline = answ; - // se online imposto veto check a 5 x tempo reinvio... - if (answ) - { - lastIobOnline = DateTime.Now; - } - dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5); - } - catch - { } - } - // verifico SE è variato stato online/offline... - if (IobOnline != answ) - { - // se ORA sono online riporto... - if (answ) - { - lgInfo("IOB ONLINE for server MP/IO"); - } - else - { - lgInfo("IOB OFFLINE for server MP/IO"); - } - } - // fix colore - if (answ) - { - parentForm.commSrvActive = 2; - } - else - { - parentForm.commSrvActive = 1; - } - } - else - { - // altrimenti passo ultimo valore noto - answ = IobOnline; - } - return answ; - } - } - /// - /// Processo la coda SignalIN... - /// - public void svuotaCodaSignIN() - { - // verifico SE la coda abbia dei valori... - if (QueueIN.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) - { - if (QueueIN.Count > 0) - { - string currVal = ""; - // se online provo - if (MPOnline) + set { - if (IobOnline) - { - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueIN.Count > 1) - { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueIN.Count > maxJsonDataEv) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonDataEv; j++) - { - QueueIN.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.SignIN, listaValori); - } - else - { - // invio in blocco - listaValori = QueueIN.ToList(); - // invio - sendDataBlock(urlType.SignIN, listaValori); - // svuoto! - QueueIN = new ConcurrentQueue(); - } - } - else - { - // INVIO SINGOLO...!!! - QueueIN.TryDequeue(out currVal); - sendToMoonPro(urlType.SignIN, currVal); - } - // salvo come last signal in il currVal ultimo... SE !="" - if (!string.IsNullOrEmpty(currVal)) - { - lastSignInVal = currVal; - } - } - else - { - break; - } - } - else - { - break; + utils.IOB_Online = value; } - } - else - { - break; - } } - - } - } - - /// - /// Processo la coda FLog... - /// - private void svuotaCodaFLog() - { - //controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! - if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) - { - string wdStatus = "elapsed"; - string sVal = string.Format("[WDST]{0}", wdStatus); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("WDST", wdStatus)); - lastWatchDog = DateTime.Now; - } - // verifico SE la coda abbia dei valori... - if (QueueFLog.Count > 0) - { - // invio pacchetto di dati (max da conf) - for (int i = 0; i < nMaxSend; i++) + /// + /// stato Online/Offline del server MP IO (su REDIS) + /// + public static bool MPOnline { - // SE ho qualcosa in coda... - if (QueueFLog.Count > 0) - { - string currVal = ""; - if (MPOnline) + get { - if (IobOnline) - { - // se ho + di 2 elementi in coda --> uso invio JSON in blocco... - if (QueueFLog.Count > 1) + return utils.MPIO_Online; + } + set + { + utils.MPIO_Online = value; + } + } + /// + /// Indica impianto IN SETUP (fino a quando SMETTE di esserlo...) + /// + protected bool inSetup = false; + /// + /// Variabile booleana che indica se sia necessario fare refresh del contapezzi + /// + public bool needRefreshPzCount = true; + /// + /// Indicazione VETO PING a server sino alla data-ora indicata + /// + public static DateTime dtVetoPing + { + get + { + return utils.dtVetoPing; + } + set + { + utils.dtVetoPing = value; + } + } + /// + /// Indicazione VETO invio a server sino alla data-ora indicata + /// + public static DateTime dtVetoSend + { + get + { + return utils.dtVetoSend; + } + set + { + utils.dtVetoSend = value; + } + } + /// + /// Imposta veto chiamata split (durante chiamata, per 60 sec) + /// + public DateTime vetoSplit = DateTime.Now.AddMinutes(1); + /// + /// Indicazione VETO check status IOB x evitare loop troppo stretti... + /// + public DateTime dtVetoCheckIOB = DateTime.Now.AddDays(-1); + /// + /// Contapezzi attuale + /// + public Int32 contapezzi = 0; + /// + /// Ultima lettura variabile contapezzi da CNC + /// + public Int32 lastCountCNC = 0; + /// + /// ODL attualmente sulla macchina + /// + public Int32 currIdxODL; + /// + /// Ultimo invio contapezzi (x invio delayed) + /// + protected DateTime lastPzCountSend; + /// + /// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi) + /// + protected DateTime lastWarnODL; + /// + /// Ritardo minimo x invio contapezzi + /// + protected int pzCountDelay; + /// + /// Abilitazione lettura PrgName + /// + public bool enablePrgName = true; + /// + /// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...) + /// + public bool doStartMemDump; + /// + /// Indica se sia richiesto campionamento memoria PERIODICO + /// + public bool doSampleMemory; + /// + /// Evento Iob ha subito un refresh + /// + public event EventHandler eh_refreshed; + /// + /// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE) + /// + public bool hasBigEndian = false; + /// + /// alias booleano false = R + /// + public bool R = false; + /// + /// alias booleano true = W + /// + public bool W = true; + /// + /// wrapper di log + /// + protected static Logger lg; + /// + /// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...) + /// + public string lastSignInVal = ""; + /// + /// dataOra ultimo log periodico... + /// + public DateTime lastPeriodicLog; + /// + /// dataOra ultimo segnale inviato... + /// + public DateTime lastWatchDog; + /// + /// dataOra ultima verifica CNC disconnesso... + /// + public DateTime lastDisconnCheck; + /// + /// dataOra ultimo PING inviato verso il PLC... + /// + public DateTime lastPING; + /// + /// DataOra ultima lettura da PLC + /// + public DateTime lastReadPLC; + /// + /// Oggetto della coda degli elementi letti (e non ancora trasmessi) + /// + public ConcurrentQueue QueueIN = new ConcurrentQueue(); + /// + /// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi) + /// + public ConcurrentQueue QueueFLog = new ConcurrentQueue(); + /// + /// Coda valori ALLARMI ove gestiti... + /// + public ConcurrentQueue QueueAlarm = new ConcurrentQueue(); + /// + /// Coda valori MESSAGGI/EVENTI (da non sottocampionare come samples)... + /// + public ConcurrentQueue QueueMessages = new ConcurrentQueue(); + + /// + /// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC + /// + protected bool adpCommAct; + /// + /// valore booleano di check se sia stato AVVIATO l'adapter (Running) + /// + public bool adpRunning = false; + /// + /// valore booleano di check se l'adapter STIA SALVANDO + /// + public bool adpSaving = false; + /// + /// valore booleano (richiesta di riavvio automatico) + /// + public bool adpTryRestart; + /// + /// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA... + /// + public bool DemoIn + { + get + { + return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn"); + } + } + /// + /// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...) + /// + public static bool DemoInSample + { + get + { + return baseUtils.CRB("DemoInSample"); + } + } + /// + /// Numero simulazioni ammesse... + /// + protected int numSim { get; set; } + /// + /// Numero letture IN da avvio + /// + protected int nReadIN { get; set; } + /// + /// Numero letture IN da avvio + /// + protected int nReadFilt { get; set; } + /// + /// Numero invii OUT (svuotamento coda) + /// + protected int nSendOut { get; set; } + /// + /// Verifica se sia in modalità DEMO x dati OUTPUT + /// + public static bool DemoOut + { + get + { + return utils.CRB("DemoOut"); + } + } + /// + /// Contatore x invio dati SignalIN + /// + public int counterSigIN { get; set; } + /// + /// Contatore x invio dati FluxLog + /// + public int counterFLog { get; set; } + /// + /// Ultimo URL + /// + public string lastUrl { get; set; } + /// + /// Ultimo programma letto + /// + public string lastPrgName { get; set; } + /// + /// Ultimo SysInfo letto + /// + public string lastSysInfo { get; set; } + /// + /// Ultimo DynData (sunto) letto + /// + public string lastDynDataCtrlVal { get; set; } + /// + /// Ultimo ARRAY DynData letto + /// + public Dictionary lastDynData { get; set; } = new Dictionary(); + /// + /// Ultimo Alarm letto + /// + public string lastAlarm { get; set; } + /// + /// Ultimo Override set letto + /// + public string lastOverrideFS { get; set; } + /// + /// Ultimo Override set letto + /// + public string lastOverrideRapid { get; set; } + + /// + /// Abilitazione invio pezzi "in blocco" per recupero contapezzi + /// + public bool enableSendPzCountBlock = false; + /// + /// Massimo numero di px da inviare in blocco + /// + public int maxSendPzCountBlock = 10; + /// + /// Minimo numero di px da inviare in blocco + /// + public int minSendPzCountBlock = 5; + + + /// + /// Array dei contatori x segnali blinking + /// + protected int[] i_counters; + /// + /// Vettore 16 BIT valori precedenti + /// + protected int B_previous; + /// + /// Vettore 16 BIT valori in ingresso al filtro + /// + protected int B_input; + /// + /// Vettore 16 BIT valori in uscita dal filtro + /// + protected int B_output; + /// + /// 32 byte input base (es strobe, 8 word da 32 bit di flags...) + /// + public byte[] RawInput = new byte[32]; + /// + /// 32 byte output base (es ack, 8 word da 32 bit di flags...) + /// + public byte[] RawOutput = new byte[32]; + /// + /// Modo corrente (da classe ENUM) + /// + public CNC_MODE currMode; + + /// + /// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN) + /// + public bool verboseLog + { + get + { + bool answ = false; + int logEvery = utils.CRI("logEvery"); + if (logEvery < 1) { - List listaValori = new List(); - // se ho + di maxJsonData elementi --> invio un set di dati alla volta - if (QueueFLog.Count > maxJsonData) - { - // prendoi primi maxJsonDataValori - for (int j = 0; j < maxJsonData; j++) - { - QueueFLog.TryDequeue(out currVal); - listaValori.Add(currVal); - } - sendDataBlock(urlType.FLog, listaValori); - } - else - { - // invio in blocco - listaValori = QueueFLog.ToList(); - // invio - sendDataBlock(urlType.FLog, listaValori); - // svuoto! - QueueFLog = new ConcurrentQueue(); - } + logEvery = 10; } - else + + answ = utils.CRB("verbose") && (nReadIN % logEvery == 0); + return answ; + } + } + /// + /// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...) + /// + public bool periodicLog + { + get + { + bool answ = false; + answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut")); + if (answ) { - // INVIO SINGOLO...!!! - QueueFLog.TryDequeue(out currVal); - sendToMoonPro(urlType.FLog, currVal); + lastPeriodicLog = DateTime.Now; } - } - else - { - break; - } + + return answ; + } + } + /// + /// Aggiunge ai dati da inviare alla parentform i valori di RawInput rilevati + /// + public virtual void reportRawInput(ref newDisplayData currDispData) + { + // processo eventualmente aggiungendo ad elementi esistenti... + if (currDispData == null) + { + currDispData = new newDisplayData(); + } + try + { + StringBuilder sb = new StringBuilder(); + sb.Append($"B_input --> {(short)B_input}{Environment.NewLine}"); + sb.Append($"{baseUtils.binaryForm(B_input)}{Environment.NewLine}"); + sb.Append($"{Environment.NewLine}"); + sb.Append($"----------- RAW Data Memory -----------{Environment.NewLine}"); + int i = 0; + foreach (var item in RawInput) + { + sb.Append($"B{i:00} --> {baseUtils.binaryForm(item)} = {(short)item}{Environment.NewLine}"); + i++; + } + sb.Append("-------------------------------"); + currDispData.currBitmap = sb.ToString(); + } + catch + { } + } + /// + /// Salva valori indicati in prod data + /// + /// Item KVP di cui salvare i dati in currProdData come chiave/valore + /// + public void saveProdData(KeyValuePair item) + { + // imposto i valori... + if (currProdData.ContainsKey(item.Key)) + { + currProdData[item.Key] = item.Value; } else { - break; + currProdData.Add(item.Key, item.Value); } - } - else - { - break; - } } - } - } - /// - /// Classe fittizia in caso di processing task in VHF - /// - public virtual void processVHF() - { - } - /// - /// Classe fittizia in caso di processing watchdog data - /// - public virtual void processWhatchDog() - { - } + /// + /// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"= + /// + public bool procIotMem = false; + /// + /// porta x adapter (x restart) + /// + protected int adpPortNum; + /// + /// DataOra ultimo avvio adapter x watchdog + /// + protected DateTime adpStartRun; + /// + /// Data/ora ultimo avvio adapter + /// + public DateTime dtAvvioAdp = DateTime.Now; + /// + /// Data/ora ultimo spegnimento adapter + /// + public DateTime dtStopAdp = DateTime.Now; + /// + /// Oggetto cronometro x campionamento durate chiamate + /// + public Stopwatch stopwatch = new Stopwatch(); + /// + /// Conteggio ATTUALE ore macchina ON + /// + public double contOreMaccOn; + /// + /// Conteggio ATTUALE ore macchina IN LAVORO + /// + public double contOreMaccLav; - /// - /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo... - /// - private void processAllMemory() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // in primis SALVO valori previous/precedenti - B_previous = B_output; - // poi faccio lettura NUOVI valori - readAllData(ref currDispData); - // eseguo il filtering dei valori (per i bit "blinking") - filterData(); - // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo... - if (B_output != B_previous) - { - accodaSigIN(ref currDispData); - } - raiseRefresh(currDispData); - } - /// - /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... - /// - public void processMemoryDiscon() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // controllo contatore invio "keepalive"... invio solo a scadenza - if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) - { - // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... - B_input = 0; - B_output = 0; - B_previous = 0; - accodaSigIN(ref currDispData); - // update controllo - lastDisconnCheck = DateTime.Now; - } - raiseRefresh(currDispData); - } - /// - /// Esegue filtraggio dati x bit blinking!!! - /// - private void filterData() - { - // effettuo filtraggio dei valori letti... inizializzo OUT! - B_output = 0; - // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN... - if (cIobConf.BLINK_FILT == 0) - { - B_output = B_input; - } - else - { - // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT... - B_output = B_input & ~cIobConf.BLINK_FILT; - // calcolo il valore dei BIT che "passano la maschera" - int iBlink = B_input & cIobConf.BLINK_FILT; - // ...aggiungo i "bit che passano" - B_output += iBlink; + /// + /// Data/ora ultima volta che IOB è stato dichairato online + /// + public DateTime lastIobOnline = DateTime.Now.AddHours(-1); + /// + /// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...) + /// + protected Dictionary TSVC_Data = new Dictionary(); + /// + /// Dizionario ultimi valori (double) delle TSVC + /// + protected Dictionary LastTSVC = new Dictionary(); + /// + /// Dizionario di VARIABILI da trattare come eventi (da inviare quando cambiano oppure a scadenza periodo...) + /// + protected Dictionary VarArray = new Dictionary(); - // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters... - BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) }); - int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray(); - for (int i = 0; i < bitsUp.Length; i++) + #endregion + + /// + /// Form chiamante + /// + protected AdapterForm parentForm; + /// + /// Conf adapter corrente + /// + public IobConfiguration cIobConf; + /// + /// indica se serva refresh parametri e quindi PLC... + /// + protected bool needRefresh = true; + /// + /// Valore MINIMO limite x decidere invio di dati come array Json + /// + protected int minJsonData { get; set; } = utils.CRI("minJsonData"); + /// + /// Valore limite MASSIMO di invio di dati come array Json + /// + protected int maxJsonData { get; set; } = utils.CRI("maxJsonData"); + /// + /// Valore limite MASSIMO di invio di dati come array Json x EVENTI + /// + protected int maxJsonDataEv { get; set; } = utils.CRI("maxJsonDataEv"); + /// + /// Secondi standard x veto check status e log + /// + protected int vetoSeconds { get; set; } = utils.CRI("vetoSeconds"); + /// + /// ultimo tentativo connessione... + /// + protected DateTime lastConnectTry; + /// + /// Struttura memoria PLC x lettura/scrittura da JSON file + /// + public plcMemMap memMap; + /// + /// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto + /// + /// + /// + public IobGeneric(AdapterForm caller, IobConfiguration IOBConf) { - // SE 1... impostiamo contatori al MAX - if (bitsUp[i] == 1) - { - // se era zero indico START blink... - if (i_counters[i] == 0) + // init oggetto redis... + redisMan = new RedisIobCache(IOBConf.serverData.MPIP, IOBConf.codIOB); + + // salvo il form chiamante + parentForm = caller; + // configurazione... + cIobConf = IOBConf; + + lastConnectTry = DateTime.Now; + + // aggiungo nel logger IDX Macchina + lg = LogManager.GetCurrentClassLogger(); + + lgInfo("Avvio preliminare AdapterGeneric"); + // aggiungo altri defaults + setDefaults(true); + + setParamPlc(); + + // checkLogDir x shrink! + checkShrinkDir(); + + // concluso! + lgInfo("Istanziata classe preliminare IOBGeneric"); + } + /// + /// Imposto alcuni valori di default + /// + /// indica se sia richeisto di SVUOTARE le code delel info + private void setDefaults(bool resetQueue) + { + numSim = utils.CRI("numSim"); + lastPrgName = ""; + nReadIN = 0; + nReadFilt = 0; + nSendOut = 0; + currMode = 0; + lastAlarm = ""; + doStartMemDump = utils.CRB("doStartMemDump"); + doSampleMemory = utils.CRB("doSampleMemory"); + // svuoto code se richiesto + if (resetQueue) { - lgInfo("START BLINK: B{0}", i); + QueueIN = new ConcurrentQueue(); + QueueFLog = new ConcurrentQueue(); + QueueAlarm = new ConcurrentQueue(); + QueueMessages = new ConcurrentQueue(); } - // imposto comunque contatore al cambio fronte... - i_counters[i] = cIobConf.MAX_COUNTER_BLINK; - } + // imposto contatori blink a zero... + i_counters = new int[32]; + lastPeriodicLog = DateTime.Now; + // fix parametri generali... + enablePrgName = true; } - - // quelli che sono zero... LI RECUPERO E LI PROCESSO... - int iZero = ~B_input & cIobConf.BLINK_FILT; - BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) }); - int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray(); - for (int i = 0; i < bitsDown.Length; i++) + /// + /// Invia messaggio a logWatcher + /// + /// + /// + protected void sendToTaskWatch(string messType, string message) { - // se era a zero (invertito...) - if (bitsDown[i] == 1) - { - // SE è in corso il conteggio... - if (i_counters[i] > 0) + parentForm.taskWatcher = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}"; + } + /// + /// Invia messaggio a logWatcher + /// + /// + /// + protected void sendToLogWatch(string messType, string message) + { + newDisplayData currDispData = new newDisplayData(); + currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {message}"; + parentForm.updateFormDisplay(currDispData); + } + /// + /// Invia messaggio a logWatcher + /// + /// + /// + /// + protected void sendToLogWatch(string messType, string message, params object[] args) + { + try { - // decremento! - i_counters[i] -= 1; - // se è zero NON faccio nulla, altrimenti SOMMO... - if (i_counters[i] > 0) - { - B_output += 1 << i; - } - else - { - lgInfo("END BLINK: B{0}", i); - } + string expString = string.Format(message, args); + newDisplayData currDispData = new newDisplayData(); + currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}"; + parentForm.updateFormDisplay(currDispData); } - } + catch + { } } - } - } - - /// - /// Effettua lettura dati - /// Parametri da aggiornare x display in form - /// - public virtual void readAllData(ref newDisplayData currDispData) - { - if (currDispData == null) - { - currDispData = new newDisplayData(); - } - try - { - if (DemoIn) + /// + /// Invia messaggio a logWatcher + /// + /// + /// + /// + /// + protected void sendToLogWatch(string messType, string message, Exception exception, params object[] args) { - // segnalo che sono in Demo - currDispData.semIn = Semaforo.SV; - } - if (connectionOk) - { - readSemafori(ref currDispData); - lastReadPLC = DateTime.Now; - } - else - { - lgError("Errore connessione mancante x readSemafori"); - } - - nReadIN++; - // aggiorno valore mostrato... - displayRawData(ref currDispData); - } - catch - { - currDispData.semIn = Semaforo.SR; - } - raiseRefresh(currDispData); - } - /// - /// Effettua gestioen programma: legge e mostra su display... - /// - private void processProgram() - { - string currPrgName = ""; - // se abilitata lettura prgName - if (enablePrgName) - { - if (connectionOk) - { - currPrgName = getPrgName(); - } - else - { - lgError("Errore connessione mancante x getPrgName"); - } - - } - else - { - currPrgName = lastPrgName; - } - // verifico SE sia cambiato il programma... - if (lastPrgName != currPrgName) - { - // salvo! - lastPrgName = currPrgName; - string sVal = string.Format("[PROG]{0}", currPrgName); - - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("PROG", currPrgName)); - } - } - /// - /// Effettua verifica se abilitato invio pezzi in blocco e nel caso - /// - invio in blocco pezzi - /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio - /// - public void trySendPzCountBlock() - { - // in primis HA SENSO procedere SOLO SE server MP è Online... - if (MPOnline) - { - // SOLO SE online la macchina... - if (IobOnline) - { - int numIncr = 0; - int qtyAdded = 0; - // verifico se la funzione SIA abilitata - if (enableSendPzCountBlock) - { - int delta = lastCountCNC - contapezzi; - // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock - if (delta > minSendPzCountBlock) + try { - // init obj display - newDisplayData currDispData = new newDisplayData(); - // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1... - numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock; - // invio il num max di pezzi ammesso in blocco! - lastUrl = $"{urlAddPzCount}{numIncr}"; - string resp = utils.callUrlNow(lastUrl); - if (!string.IsNullOrEmpty(resp)) - { - // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti) - int.TryParse(resp, out qtyAdded); - if (qtyAdded > 0) + string expString = string.Format(message, args); + newDisplayData currDispData = new newDisplayData(); + currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | {messType} | {expString}{Environment.NewLine}{exception}"; + parentForm.updateFormDisplay(currDispData); + } + catch + { } + } + /// + /// Lettura memorie conf speciali (json) + /// ...SE inserito in [OPTPAR] come PARAM_CONF=nome.json + /// + protected virtual void loadMemConf() + { + lgInfo("BEGIN loadMemConf"); + // variabili x gestione send contapezzi in blocco + string currPar = getOptPar("ENABLE_SEND_PZC_BLOCK"); + if (!string.IsNullOrEmpty(currPar)) + { + bool.TryParse(currPar, out enableSendPzCountBlock); + // se abilitato leggo num pezzi da reinviare in blocco + if (enableSendPzCountBlock) { - // aggiorno IL MIO contapezzi... - contapezzi += qtyAdded; - lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezzi: {contapezzi}"); - // invio conferma contapezzi.. - string retVal = utils.callUrl($"{urlSetPzCount}{contapezzi}"); - // verifica se tutto OK - if (retVal != contapezzi.ToString()) - { - // errore salvataggio contapezzi - lgInfo($"trySendPzCountBlock: errore salvataggio contapezzi: contapezzi {contapezzi} | risposta: {retVal}"); - } + int.TryParse(getOptPar("MAX_SEND_PZC_BLOCK"), out maxSendPzCountBlock); + int.TryParse(getOptPar("MIN_SEND_PZC_BLOCK"), out minSendPzCountBlock); + } + } + else + { + lgError("loadMemConf: parametro ENABLE_SEND_PZC_BLOCK non trovato, verificare anche MAX_SEND_PZC_BLOCK e MIN_SEND_PZC_BLOCK"); + } + // inizializzo LUT decodifica + string jsonConf = getOptPar("PARAM_CONF"); + if (!string.IsNullOrEmpty(jsonConf)) + { + string jsonFileName = $"{Application.StartupPath}/DATA/CONF/{jsonConf}"; + lgInfo($"Apertura file {jsonFileName}"); + StreamReader reader = new StreamReader(jsonFileName); + string jsonData = reader.ReadToEnd(); + if (!string.IsNullOrEmpty(jsonData)) + { + lgInfo($"File json composto da {jsonData.Length} caratteri"); + try + { + memMap = JsonConvert.DeserializeObject(jsonData); + lgInfo($"Decodifica aree memMap: trovati {memMap.mMapRead.Count} valori TSVC"); + lgInfo($"Decodifica aree memMap: trovati {memMap.mMapWrite.Count} parametri "); + // se ho variabili read --> genero dati TSVC... + if (memMap.mMapRead.Count > 0) + { + TSVC_Data.Clear(); + LastTSVC.Clear(); + VCData currConf; + int periodo = 0; + VC_func funz = VC_func.POINT; + // accodo nella conf... + foreach (var item in memMap.mMapRead) + { + funz = item.Value.func; + periodo = item.Value.period; + currConf = new VCData() + { + Funzione = funz, + Period = periodo, + DTStart = DateTime.Now.AddHours(-1), + dataArray = new List() + }; + TSVC_Data.Add(item.Key, currConf); + } + // documento... + foreach (var item in TSVC_Data) + { + lgInfo($"TSVC: {item.Key} | periodo: {item.Value.Period} | funz: {item.Value.Funzione}"); + // salvo i valori PREC... + LastTSVC.Add(item.Key, 0); + } + } + // infine se obj memoria valido salvo in MP-IO x sue applicazioni + if (memMap != null) + { + // invio su cloud conf memoria... + string rawData = JsonConvert.SerializeObject(memMap); + utils.callUrlNow($"{urlSaveMemMap}", rawData); + // salvo ANCHE come parametri i valori... + objItem currItem = new objItem(); + List allParam = new List(); + // valori WRITE + foreach (var item in memMap.mMapWrite) + { + currItem = new objItem() + { + uid = item.Value.name, + name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, + writable = true + }; + allParam.Add(currItem); + } + // valori READ + foreach (var item in memMap.mMapRead) + { + currItem = new objItem() + { + uid = item.Value.name, + name = !string.IsNullOrEmpty(item.Value.description) ? item.Value.description : item.Value.name, + writable = false + }; + allParam.Add(currItem); + } + // invio su cloud parametri! + rawData = JsonConvert.SerializeObject(allParam); + utils.callUrl($"{urlSaveAllParams}", rawData); + } + } + catch (Exception exc) + { + lgError($"Eccezione in decodifica conf json{Environment.NewLine}{exc}"); + } } else { - lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO"); + lgError("Errore in loadMemConf: file json vuoto!"); } - } - currDispData.newUrlCallData = lastUrl; - currDispData.counter = contapezzi; - currDispData.semOut = Semaforo.SV; - raiseRefresh(currDispData); + reader.Dispose(); } - } - } - else - { - lgInfo("Impossibile trySendPzCountBlock: IobOnline è false"); - } - } - else - { - lgInfo("Impossibile trySendPzCountBlock: MPOnline è false"); - } - } - /// - /// Verifica se sia machcina multi = DoppioPallet da CONF - /// - public bool isMulti - { - get - { - bool answ = false; - if (cIobConf.optPar.Count > 0) - { - // cerco con chaive reale IS_MULTI - string keyName = "IS_MULTI"; - if (!cIobConf.optPar.ContainsKey(keyName)) - { - // legacy: accetto anche SIM_MULTI... - keyName = "SIM_MULTI"; - } - // vera verifica su chaive... - if (cIobConf.optPar.ContainsKey(keyName)) - { - string SIM_MULTI = getOptPar(keyName); - answ = SIM_MULTI == "1"; - } - } - return answ; - } - } - /// - /// Verifica e processing x gestione ODL automatica - /// - public void processAutoOdl() - { - bool fatto = false; - if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) - { - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - string fullUrl = ""; - if (isMulti) - { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); - } - // controllo SIA abilitato... - bool doProc = false; - DateTime adesso = DateTime.Now; - bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); - if (doProc) - { - // carico i parametri di configurazione x reset ODL... - string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_IDLE_MIN"); - string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); - if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) - { - int minOdlDurHours = -1; - int minPlcIdelMin = -1; - int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); - int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); - // controllo parametri validi - if (minOdlDurHours > 0 && minPlcIdelMin > 0) + else { - // leggo da server inizio ODL... se non multi 1 solo... - DateTime inizioOdl = DateTime.Now; - string rawDataInizio = ""; - if (!isMulti) - { - rawDataInizio = callUrl(urlInizioOdlIob, false); - DateTime.TryParse(rawDataInizio, out inizioOdl); - } - else - { - DateTime tmpData = DateTime.Now; - // prendo il + vecchio... - foreach (var item in elencoMulti) + lgInfo("loadMemConf: non trovata opzione PARAM_CONF in file INI"); + } + // loggo + lgInfo("DONE loadMemConf"); + } + /// + /// Impostazioni parametri PLC + /// + protected virtual void setParamPlc() + { + loadMemConf(); + fixDefaultPar(); + } + /// + /// Imposta eventuali altri valori default + /// + private void fixDefaultPar() + { + // parametro max tentativi PING... + string s_maxPingRetry = getOptPar("MAX_PING_RETRY"); + if (!string.IsNullOrEmpty(s_maxPingRetry)) + { + int numRetry = 5; + int.TryParse(s_maxPingRetry, out numRetry); + maxPingRetry = numRetry; + } + } + + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgInfo(string message, bool sendToForm = true) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Info(message); + if (sendToForm) + { + sendToLogWatch("INFO", message); + } + } + /// + /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgInfo(string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Info(message, args); + sendToLogWatch("INFO", message, args); + } + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgError(string message, bool sendToForm = true) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Error(message); + if (sendToForm) + { + sendToLogWatch("ERROR", message); + } + } + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgError(string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Error(message, args); + sendToLogWatch("ERROR", message, args); + } + /// + /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + /// + protected void lgError(Exception exception, string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Error(exception, message, args); + sendToLogWatch("ERROR", message, exception, args); + } + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + protected void lgFatal(string message, bool sendToForm = true) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Fatal(message); + if (sendToForm) + { + sendToLogWatch("FATAL", message); + } + } + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + protected void lgFatal(string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Fatal(message, args); + sendToLogWatch("FATAL", message, args); + } + /// + /// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere... + /// + /// + /// + /// + protected void lgFatal(Exception exception, string message, params object[] args) + { + lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB; + lg.Fatal(exception, message, args); + sendToLogWatch("FATAL", message, exception, args); + } + + #region metodi adapter + + /// + /// Invia informazioni associazione IOB 2 machine + /// + protected void sendM2IOB() + { + if (checkServerAlive) + { + lgInfo("chiamata URL " + urlSetM2IOB); + utils.callUrlNow(urlSetM2IOB); + } + } + /// + /// Chiede elenco dei task da eseguire + /// - formato Json + /// - array di KVP / Dictionary + /// - formato definito da API x MP/IO/: + /// - KEY: task + /// - VALUE: array JSon KVP + /// + protected string getTask2exe() + { + string answ = ""; + if (checkServerAlive) + { + string url2call = $"{urlGetTask2Exe}"; + if (verboseLog) { - fullUrl = $"{urlInizioOdlIob}|{item}"; - rawDataInizio = callUrl(fullUrl, false); - DateTime.TryParse(rawDataInizio, out tmpData); - inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; + lgInfo("chiamata URL " + url2call); } - } - // verifico se sia scaduto... - if (inizioOdl.AddHours(minOdlDurHours) < adesso) - { - string rawIdle = ""; - int idlePeriod = 0; + answ = utils.callUrlNow(url2call); + } + return answ; + } + /// + /// Stringa raw dei parametri da scrivere... + /// + /// + protected string getParams2write() + { + string answ = ""; + string url2call = $"{urlGetParams2Write}"; + if (verboseLog) + { + lgInfo("chiamata URL " + url2call); + } + answ = utils.callUrlNow(url2call); + // se vuoto faccio seconda prova... + if (string.IsNullOrEmpty(answ)) + { + answ = utils.callUrlNow(url2call); + } + return answ; + } + /// + /// Cancella dal server i task eseguiti + /// + /// + /// + /// + protected string remTask2exe(string taskName, string esitoTask) + { + string answ = ""; + if (checkServerAlive) + { + string url2call = $"{urlRemTask2Exe}{taskName}"; + lgInfo($"Task2Exe | {esitoTask} | chiamata URL {url2call}"); + answ = utils.callUrlNow(url2call); + } + return answ; + } + + /// + /// Invia al server IO i valori dei parametri opzionali (es counters) + /// + /// Nome parametro + /// Valore parametro + protected void sendOptVal(string paramName, string paramValue) + { + if (checkServerAlive) + { + string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}"; + lgInfo("chiamata URL " + url2call); + utils.callUrlNow(url2call); + } + } + /// + /// Invia al server IO i valori dei parametri opzionali (es counters) + /// + /// Nome parametro + /// Valore parametro INT + protected void sendOptVal(string paramName, int paramValueInt) + { + // override! + sendOptVal(paramName, paramValueInt.ToString()); + } + /// + /// Effettua rilettura del contapezzi dal server MP/IO + /// + /// Forza rilettura da DB tempi ciclo rilevati + public void pzCntReload(bool forceCountRec) + { + // legge da IO server ULTIMO valore CONTPEZZI al riavvio... + string currServerCount = ""; + string lastIdxODL = ""; + if (checkServerAlive) + { + // leggo PRIMA ODL .... + lastIdxODL = utils.callUrl(urlGetCurrODL); + lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetCurrODL, lastIdxODL); + // se ho valori in coda da trasmettere uso dati REDIS + if (forceCountRec) + { + // uso dati da TCiclo registrati... + currServerCount = utils.callUrl(urlGetPzCountRec); + lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount); + } + else + { + // uso il contapezzi dichiarato dall'IOB stesso + currServerCount = utils.callUrl(urlGetPzCount); + lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount); + } + // controllo: SE NON HO ODL... + if (string.IsNullOrEmpty(lastIdxODL) || lastIdxODL == "0") + { + // NON AGGIORNO + contapezzi = lastCountCNC; + lgInfo($"Errore lettura ODL (vuoto) resta tutto invariato contapezzi: {contapezzi} | lastCountCNC {lastCountCNC}"); + } + else + { + if (!string.IsNullOrEmpty(currServerCount)) + { + // se "-1" resto a ultimo... + if (currServerCount != "-1") + { + int newVal = -1; + Int32.TryParse(currServerCount, out newVal); + contapezzi = newVal > -1 ? newVal : contapezzi; + lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount); + } + else + { + // NON AGGIORNO + contapezzi = lastCountCNC; + lgInfo("Errore lettura contapezzi (-1) - uso lastCountCNC --> " + contapezzi); + } + } + else + { + // registro che ho UN NUOVO ODL + lgInfo(string.Format("Lettura ODL in pzCntReload, {0} --> {1}", currIdxODL, lastIdxODL)); + // se ODL differente e NUOVO è zero --> resetto! + if (currIdxODL.ToString() != lastIdxODL && lastIdxODL == "0") + { + // cambiato ODL quindi reset... + contapezzi = 0; + lgInfo("Nuovo ODL==0, RESET contapezzi (-->ZERO)"); + } + // provo a salvare nuovo ODL + int.TryParse(lastIdxODL, out currIdxODL); + } + } + } + else + { + // se server NON pronto... + contapezzi = lastCountCNC; + lgError("Errore server NON pronto in pzCntReload"); + } + } + + /// + /// Avvia l'adapter sulla porta richiesta + /// + /// indica se sia richeisto di SVUOTARE le code delel info + public virtual void startAdapter(bool resetQueue) + { + lgInfo("Starting adapter..."); + maxJsonData = utils.CRI("maxJsonData"); + maxJsonDataEv = utils.CRI("maxJsonDataEv"); + parentForm.commPlcActive = false; + adpRunning = true; + dtAvvioAdp = DateTime.Now; + lastWatchDog = dtAvvioAdp; + lastPING = dtAvvioAdp; + lastReadPLC = dtAvvioAdp.AddMinutes(-1); + lastDisconnCheck = dtAvvioAdp; + TimingData.resetData(); + // aggiungo altri defaults + setDefaults(resetQueue); + adpTryRestart = true; + parentForm.displayTaskAndLog("Adapter Started!"); + } + + /// + /// ferma l'adapter... + /// + /// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico) + /// indica se sia richeisto di SVUOTARE le code delel info + public virtual void stopAdapter(bool tryRestart, bool forceDequeue) + { + if (forceDequeue) + { + // svuoto le code dei valori letti e non ancora trasmessi... + parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali..."); + while (QueueIN.Count > 0) + { + // INVIO COMUNQUE...!!! + string valore = ""; + QueueIN.TryDequeue(out valore); + sendToMoonPro(urlType.SignIN, valore); + } + parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG..."); + // se ho + di 2 elementi in coda --> uso invio JSON in blocco... + if (QueueFLog.Count > minJsonData) + { + while (QueueFLog.Count > 0) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueFLog.Count > maxJsonData) + { + string currVal = ""; + // prendoi primi maxJsonDataValori + for (int i = 0; i < maxJsonData; i++) + { + QueueFLog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.FLog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueFLog.ToList(); + // invio + sendDataBlock(urlType.FLog, listaValori); + // svuoto! + QueueFLog = new ConcurrentQueue(); + } + } + // HO FINITO invio di FLog... + } + else + { + string currVal = ""; + while (QueueFLog.Count > 0) + { + // INVIO COMUNQUE...!!! + QueueFLog.TryDequeue(out currVal); + sendToMoonPro(urlType.FLog, currVal); + } + } + } + parentForm.displayTaskAndLog("Stopping adapter..."); + adpTryRestart = false; + + parentForm.displayTaskAndLog("Stopping adapter - last periodic data read..."); + + // chiudo la connessione all'adapter... + tryDisconnect(); + dtStopAdp = DateTime.Now; + adpTryRestart = tryRestart; + adpRunning = false; + // chiudo! + parentForm.displayTaskAndLog("Adapter Stopped."); + parentForm.commPlcActive = false; + } + + /// + /// effettua recupero dati ed invio valori modificati... + /// + /// + public void getAndSend(gatherCycle ciclo) + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!! + try + { + trySendValues(); + } + catch (Exception exc) + { + lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria"); + currDispData.semOut = Semaforo.SR; + } + // controllo connessione/connettività + if (connectionOk) + { + // controllo non sia già in esecuzione... + if (!adpCommAct) + { + // provo ad avviare + try + { + // imposto flag adapter running.. + adpCommAct = true; + adpStartRun = DateTime.Now; + } + catch (Exception exc) + { + string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}"; + adpCommAct = false; + adpStartRun = DateTime.Now; + currDispData.newLiveLogData = errore; + } + if (adpCommAct) + { + // try / catch generale altrimenti segno che è disconnesso... + try + { + bool showDebugData = false; + if (ciclo == gatherCycle.VHF) + { + processVHF(); + } + // processing dati memoria (lettura, filtraggio, enqueque) + else if (ciclo == gatherCycle.HF) + { + processWhatchDog(); + processAllMemory(); + processMode(); + } + else if (ciclo == gatherCycle.MF) + { + processServerRequests(); + processOverride(); + processContapezzi(); + processCncAlarms(); + processDynData(); + } + else if (ciclo == gatherCycle.LF) + { + processOtherCounters(); + processProgram(); + // verifico se devo gestire cambio ODL in modo automatico + processAutoOdl(); + } + else if (ciclo == gatherCycle.VLF) + { + if (utils.CRB("enableContapezzi")) + { + // rilettura contapezzi da server... + lgInfo("Ciclo VLF: pzCntReload(true)"); + if (!isMulti) + { + pzCntReload(true); + } + // refresh associazione Macchina - IOB + sendM2IOB(); + } + // recupero dati SETUP (sysinfo) e li invio/mostro se variati... + processSysInfo(); + // checkLogDir x shrink! + checkShrinkDir(); + // eventuale log! + if (utils.CRB("recTime")) + { + logTimeResults(); + } + } + // mostra eventuali altri dati di processo... + reportDataProc(); + if (showDebugData) + { + // verifica se debba salvare e mostrare dati + checkSavePersDataLayer(); + } + } + catch (Exception exc) + { + // segnalo eccezione e indico disconnesso... + lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc)); + parentForm.fermaAdapter(true, false, true); + } + // tolgo flag running + adpCommAct = false; + } + else + { + if (periodicLog) + { + lgInfo("ADP not running..."); + } + } + } + else + { + // log ADP running + lgError("Non eseguo chiamata: ADP ancora in running"); + // se è bloccato da oltre maxSec lo sblocco... + if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec")) + { + // tolgo flag running + adpCommAct = false; + adpStartRun = DateTime.Now; + } + } + } + else + { + // provo a riconnettere SE abilitato tryRestart... + if (adpTryRestart && !connectionOk) + { + // controllo se sia scaduto periodi di veto al tryConnect... + int waitRecMSec = utils.CRI("waitRecMSec") * 2; + DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec); + if (DateTime.Now > dtVeto) + { + lgInfo($"Retry Time Elapsed (waited for {waitRecMSec} ms)--> NOW tryConnect"); + lastConnectTry = DateTime.Now; + tryConnect(); + } + } + currDispData.semIn = Semaforo.SR; + } + raiseRefresh(currDispData); + } + + protected void raiseRefresh(newDisplayData currDispData) + { + if (currDispData.hasData) + { + // segnalo refresh! + if (eh_refreshed != null) + { + eh_refreshed(this, new iobRefreshedEventArgs(currDispData)); + } + } + } + + /// + /// Cerca di inviare su un altro thread i vari dati accumulati... + /// + private void trySendValues() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + try + { + // verifico se risponde il server... + if (checkServerAlive) + { + bool iobOk = false; + if (utils.CRB("sendDataByThread")) + { + Task taskCheck = TaskEx.Run(() => iobOk = checkIobEnabled); + } + else + { + iobOk = checkIobEnabled; + } + // verifico SE posso inviare dati + if (iobOk) + { + currDispData.semOut = Semaforo.SV; + // verificare come gestire il task secondario senza interferenza (chiamate update su FORM da thread secondari danno errori) + if (utils.CRB("sendDataByThread")) + { + // invio con thread separato... + Task taskSigIN = TaskEx.Run(() => svuotaCodaSignIN()); + Task taskFlog = TaskEx.Run(() => svuotaCodaFLog()); + } + else + { + // gestione queue SignalIN (invio, display) + svuotaCodaSignIN(); + currDispData.counter = contapezzi; + raiseRefresh(currDispData); + // provo a svuotare coda contapezzi + svuotaCodaContapezzi(); + currDispData.counter = contapezzi; + raiseRefresh(currDispData); + // gestione queue FluxLog (invio, display) + svuotaCodaFLog(); + raiseRefresh(currDispData); + } + } + else + { + // mostro VETO-SEND x invio... GIALLO + currDispData.semOut = Semaforo.SG; + if (periodicLog) + { + lgInfo("IOB - VETO SEND"); + } + } + } + else + { + // mostro SERVER KO x invio... ROSSO + currDispData.semOut = Semaforo.SR; + if (periodicLog) + { + lgInfo("IOB - SERVER NOT READY"); + } + } + } + catch (Exception exc) + { + lgError($"Errore in fase trySendValues{Environment.NewLine}{exc}"); + currDispData.semOut = Semaforo.SR; + } + raiseRefresh(currDispData); + } + + private void svuotaCodaContapezzi() + { + // permetto al max 2 tentativi infruttuosi... + int maxTry = 2; + int oldContapezzi = contapezzi; + // se ho contapezzi OLTRE limite... + while ((MPOnline) && (lastCountCNC > contapezzi + minSendPzCountBlock)) + { + lgInfo($"Ciclo svuotaCodaContapezzi --> lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi}"); if (!isMulti) { - // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto... - rawIdle = callUrl(urlIdleTime, false); - int.TryParse(rawIdle, out idlePeriod); + pzCntReload(true); + } + // provo invio + trySendPzCountBlock(); + // verifica per evitare loop infinito invio fallito + if (oldContapezzi == contapezzi) + { + maxTry--; } else { - int tmpIdle = 0; - // prendo il + grande... - foreach (var item in elencoMulti) - { - fullUrl = $"{urlIdleTime}|{item}"; - rawIdle = callUrl(fullUrl, false); - int.TryParse(rawIdle, out tmpIdle); - idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; - } + maxTry = 2; + oldContapezzi = contapezzi; } - if (idlePeriod >= minPlcIdelMin) + // verifico maxTry: se li ho esauriti esco! + if (maxTry <= 0) { + return; + } + // aspetto x dare tempo calcolo + Thread.Sleep(400); + } + } + + /// + /// Effettua ciclo controllo richieste server + /// + public void processServerRequests() + { + Dictionary task2exe = new Dictionary(); + Dictionary taskDone = new Dictionary(); + // recupero elenco delle cose da fare + string resp = getTask2exe(); + if (!string.IsNullOrEmpty(resp)) + { + try + { + task2exe = JsonConvert.DeserializeObject>(resp); + // se ho da fare chiamo esecuzione.. + if (task2exe.Count > 0) + { + taskDone = processTask(task2exe); + } + } + catch (Exception exc) + { + lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); + } + } + } + + public Dictionary processTask(Dictionary task2exe) + { + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + lgInfo($"Task2Exe: trovati {task2exe.Count} task da eseguire, procedo"); + // chiamo procedura esecutiva (diversa x ogni IOB) + taskDone = executeTasks(task2exe); + // loggo tutti i task done... + foreach (var item in taskDone) + { + sendToTaskWatch(item.Key, item.Value); + } + // ora chiamo la cancellazione dei task eseguiti... + foreach (var item in taskDone) + { + remTask2exe(item.Key, item.Value); + } + } + return taskDone; + } + + /// + /// Esecuzione dei task richiesti e pulizia coda richieste eseguite + /// + /// + public virtual Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebbe togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + if (task2exe != null) + { + bool taskOk = false; + string taskVal = ""; + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY... + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceSetPzCount: + case taskType.sendWatchDogMes2Plc: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + case taskType.setPzComm: + // recupero dati da memMap... + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + string addr = currMem.memAddr; + taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte"; + // salvo il nuovo valore nella memoria... così prox invio lo trasmetterà + memMap.mMapWrite[item.Key].value = item.Value; + } + else + { + taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}"; + } + break; + case taskType.forceResetPzCount: + // reset contapezzi inizio setup + taskOk = resetContapezziCNC(); + taskVal = taskOk ? "RESET PZ COUNT OK" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata forceResetPzCount: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.startSetup: + // reset contapezzi inizio setup + taskOk = resetContapezziCNC(); + taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.stopSetup: + // reset contapezzi fine setup SE ESPLICITAMENTE IMPOSTATO + if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET_stopSetup") == "TRUE") + { + taskOk = resetContapezziCNC(); + } + taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC"; + lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + default: + taskVal = "SKIPPED | NO EXEC"; + lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + } + } + return taskDone; + } + /// + /// Processa le richieste di scrittura memoria + /// + /// + protected string processMemWriteRequests() + { + string answ = ""; + // li salvo nei parametri in memoria locale (ogni adapter DOVREBBE salvare POI sul VERO PLC) + List writeList = new List(); + List updatedPar = new List(); + // recupero elenco delle cose da fare + string resp = getParams2write(); + if (!string.IsNullOrEmpty(resp)) + { + try + { + writeList = JsonConvert.DeserializeObject>(resp); + // se ho da fare chiamo esecuzione.. + if (writeList.Count > 0) + { + foreach (var item in writeList) + { + // scrivo in memoria + if (memMap.mMapWrite.ContainsKey(item.uid)) + { + memMap.mMapWrite[item.uid].value = item.reqValue; + // accodo in stringa taskVal... + answ += $" | Parameter {item.uid} --> {item.reqValue}"; + // sistemo valori + item.value = item.reqValue; + lgInfo($"Effettuato update parametro: actVal = {item.value} | reqVal = {item.reqValue}"); + item.reqValue = ""; + // salvo in lista da ritrasmettere + updatedPar.Add(item); + } + else + { + answ += $" | Error: parameter {item.uid} not found"; + } + } + // richiamo scrittura parametri su PLC + plcWriteParams(updatedPar); + // invio su cloud parametri! + string rawData = JsonConvert.SerializeObject(updatedPar); + utils.callUrl($"{urlUpdateWriteParams}", rawData); + } + } + catch (Exception exc) + { + lgError($"Eccezione in processServerRequests:{Environment.NewLine}{exc}"); + } + } + else + { + lgError("Non è stata ricevuta risposta x task da eseguire"); + } + return answ; + } + /// + /// Metodo da overridare x scrivere DAVVERO i aprametri sul PLC + /// + /// + protected virtual void plcWriteParams(List updatedPar) + { + // non faccio nulla di base... + } + + /// + /// Metodo generico di reset contapezzi... + /// + /// + public virtual bool resetContapezziCNC() + { + return false; + } + /// + /// Metodo generico di IMPOSTAZIONE FORZATA del contapezzi... + /// + /// Pezzi richiesti + /// + public virtual bool setContapezziCNC(int newPzCount) + { + return false; + } + + /// + /// Verifica e se necessario comprime directory log... + /// + private void checkShrinkDir() + { + string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB); + baseUtils.shrinkDir(path); + } + + private void reportDataProc() + { + // update valori visualizzazione... + parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut); + } + + /// + /// riporta il log di tutti i dati di results temporali registrati + /// + public void logTimeResults() + { + if (TimingData.results.Count > 0) + { + lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine); + int globNumCall = 0; + TimeSpan globAvgMsec = new TimeSpan(0); + foreach (TimeRec item in TimingData.results) + { + // loggo SOLO se del mio IOB corrente... + if (item.classCall == cIobConf.codIOB) + { + lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); + globNumCall += item.numCall; + globAvgMsec += item.totMsec; + } + } + // riporto conteggio medio al secondo... + lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB); + lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine); + // mostro in form statistiche globali! + parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds)); + } + } + /// + /// processa dataLayer e se necessario salva/mostra + /// + public static void checkSavePersDataLayer() + { + } + public static void resetDebugConsole() + { + } + + /// + /// Metodo base connessione... + /// + public virtual void tryConnect() + { + dtAvvioAdp = DateTime.Now; + } + /// + /// Metodo base disconnessione... + /// + public virtual void tryDisconnect() + { + + } + protected bool _connOk = false; + /// + /// Salva verifica stato connessione OK + /// + /// + public virtual bool connectionOk + { + get + { + return _connOk || DemoIn; + } + set + { + _connOk = value; + } + } + /// + /// Max tentativi ping permessi (default: 5) + /// + protected int maxPingRetry { get; set; } = 5; + + /// + /// indica se ping disabilitato da optPar + /// + public bool pingDisabled + { + get + { + bool answ = false; + bool.TryParse(getOptPar("NO_PING"), out answ); + return answ; + } + } + /// + /// test ping all'indirizzo PLC/CNC impostato nei parametri + /// + /// + protected IPStatus testPingMachine + { + get + { + IPStatus answ = IPStatus.Unknown; + // se disabilitato salto... + if (pingDisabled) + { + answ = IPStatus.Success; + } + else + { + IPAddress address; + PingReply reply; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + IPAddress.TryParse(cIobConf.cncIpAddr, out address); + int pingMsTimeout = cIobConf.pingMsTimeout; + reply = pingSender.Send(address, pingMsTimeout); + answ = reply.Status; + } + } + return answ; + } + } + + #endregion + + #region layer persistenza dati + + /// + /// Dizionario di persistenza per i valori da salvare da/su file + /// + public Dictionary persistenceLayer; + + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) + /// + /// + /// + private string getStoredVal(string keyVal) + { + string value = ""; + try + { + if (persistenceLayer != null) + { + if (!persistenceLayer.TryGetValue(keyVal, out value)) + { + persistenceLayer.Add(keyVal, "0"); + } + } + } + catch (Exception exc) + { + lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc)); + } + return value; + } + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) come UINT + /// + /// + /// + private uint getStoredValUInt(string keyVal) + { + uint answ = 0; + try + { + answ = Convert.ToUInt32(getStoredVal(keyVal)); + } + catch (Exception exc) + { + lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc)); + } + // verifico che il valore sia minore di 9/10 del valore massimo... + answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0; + return answ; + } + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) come INT + /// + /// + /// + private long getStoredValLong(string keyVal) + { + long answ = 0; + try + { + answ = Convert.ToInt64(getStoredVal(keyVal)); + } + catch + { } + // verifico che il valore sia minore di 9/10 del valore massimo... + answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0; + return answ; + } + /// + /// recupera valore salvato in persistence layer (se non c'è crea...) come double + /// + /// + /// + private double getStoredValDouble(string keyVal) + { + double answ = 0; + try + { + answ = Convert.ToDouble(getStoredVal(keyVal)); + } + catch (Exception exc) + { + lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc)); + } + answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0; + return answ; + } + + /// + /// Aggiorna un valore del dizionario in SOSTITUZIONE + /// + /// + /// + /// + /// Nuovo valore incrementato + private void updateValString(int i, string newVal, string searchString) + { + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal; + } + /// + /// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce + /// + /// + /// + /// + /// Nuovo valore incrementato + private void updateValUInt(int i, uint newVal, string searchString) + { + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // salvo in ram! + persistenceLayer[keyVal] = newVal.ToString(); + } + /// + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// + /// + /// + /// + /// Nuovo valore incrementato + private uint updateValUIntByIncr(int i, uint delta, string searchString) + { + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + uint contAct = getStoredValUInt(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; + } + /// + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// + /// + /// + /// + /// Nuovo valore incrementato + private long updateValLongByIncr(int i, long delta, string searchString) + { + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + long contAct = getStoredValLong(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; + } + /// + /// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce + /// + /// + /// + /// + /// Nuovo valore incrementato + private double updateValDoubleByIncr(int i, double delta, string searchString) + { + // stringa da cercare.. + string keyVal = string.Format(searchString, i + 1); + // recupero valore precedente... + double contAct = getStoredValDouble(keyVal); + // nuovo valore... + contAct += delta; + // salvo in ram! + persistenceLayer[keyVal] = contAct.ToString(); + // rendo il valore! + return contAct; + } + + #endregion + + #region area lettura configurazioni + + /// + /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria + /// + /// nome vettore memoria + /// file origine + /// dimensione (in byte) della memoria + /// dimensione (in byte) della memoria + protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett) + { + otherData lastData = new otherData(); + int totRighe = 0; + string linea; + totRighe = File.ReadLines(nomeFile).Count(); + // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco... + vettoreConf = new otherData[File.ReadLines(nomeFile).Count()]; + // carica da file... + StreamReader file = new StreamReader(nomeFile); + // leggo 1 linea alla volta... + int numRiga = 0; + int bitNum = 0; + int byteNum = 0; + while ((linea = file.ReadLine()) != null) + { + // SE non è un commento... + if (linea.Substring(0, 1) != "#") + { + // se finisce per BIT allora processo bit-a-bit... + if (linea.EndsWith("BOOL")) + { + try + { + string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.'); + // calcolo bit e byte number... + int.TryParse(memIdx[0], out byteNum); + if (memIdx.Length > 1) + { + int.TryParse(memIdx[1], out bitNum); + } + else + { + bitNum = 0; + } + } + catch + { + byteNum = 0; + bitNum = 0; + } + lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum); + vettoreConf[numRiga] = lastData; + } + else + { + lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize); + vettoreConf[numRiga] = lastData; + } + numRiga++; + } + } + // salvo lunghezza file... + try + { + numVett = Convert.ToInt32(lastData.memAddr) + 1; + } + catch + { + numVett = numRiga + 1; + } + // chiudo file + file.Close(); + // ora trimmo vettore al solo numero VERO dei valori caricati... + Array.Resize(ref vettoreConf, numRiga); + + if (isVerboseLog) + { + lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile)); + } + } + /// + /// Decodifica file MAP generico + /// + /// + /// + /// + /// + /// + /// + protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) + { + if (linea != null) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + else + { + return null; + } + } + /// + /// Decodifica file MAP (caso .bit) + /// + /// + /// + /// indirizzo Byte: indirizzo di partenza memoria + /// dimensione singolo slot in byte + /// indirizzo bit: numero riga x calcolo indice bit + /// + protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) + { + if (linea != null) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + int resto = 0; + Math.DivRem(BitNum, 8, out resto); + string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + else + { + return null; + } + } + /// + /// Cerca se esiste il parametro opzionale e lo restituisce + /// + /// + /// + public string getOptPar(string key) + { + string answ = ""; + if (cIobConf.optPar.Count > 0) + { + // controllo SE HO il parametro + if (cIobConf.optPar.ContainsKey(key)) + { + answ = cIobConf.optPar[key]; + } + } + return answ; + } + /// + /// Cerca parametri opzionali in modalità "like" del nome + /// + /// + /// + public Dictionary findOptPar(string keyStartSearch = "") + { + Dictionary answ = new Dictionary(); + // controllo SE keySearch !="" + if (!string.IsNullOrWhiteSpace(keyStartSearch)) + { + if (cIobConf.optPar.Count > 0) + { + // ciclo su tutti e cerco occorrenze che INIZINO... + foreach (var item in cIobConf.optPar) + { + if (item.Key.StartsWith(keyStartSearch)) + { + answ.Add(item.Key, item.Value); + } + } + } + } + return answ; + } + + + + #endregion + + #region IOB METHODS + + /// + /// Valore del num max invii consecutivi da coda... + /// + protected static int nMaxSend + { + get + { + int answ = 5; + try + { + answ = utils.CRI("nMaxSend"); + } + catch + { } + return answ; + } + } + /// + /// DateTime Ultimo valore simulazione generato + /// + public DateTime lastSim; + /// + /// contatore x simulazione valori input + /// + public int countSim = 0; + /// + /// URL per check alive... + /// + public string urlAlive + { + get + { + return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE); + } + } + /// + /// URL per check se abilitato... + /// + public string urlIobEnabled + { + get + { + return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB); + } + } + /// + /// URL per recupero inizio ODL... + /// + public string urlInizioOdlIob + { + get + { + return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_ODL_STARTED, cIobConf.codIOB); + } + } + /// + /// URL per recupero idle time IOB... + /// + public string urlIdleTime + { + get + { + return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_IDLE_TIME, cIobConf.codIOB); + } + } + /// + /// URL per forzare split ODL... + /// + public string urlForceSplit + { + get + { + return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMD_FORCLE_SPLIT_ODL, cIobConf.codIOB); + } + } + /// + /// URL per segnalazione reboot... + /// + public string urlReboot + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress()); + } + catch + { + answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB); + } + return answ; + } + } + /// + /// URL per salvataggio contapezzi... + /// + public string urlGetCurrODL + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlGetCurrODL"); + } + return answ; + } + } + /// + /// URL per salvataggio contapezzi... + /// + public string urlSetPzCount + { + get + { + string answ = ""; + try + { + answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/{cIobConf.codIOB}?counter="; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSetPzCount"); + } + return answ; + } + } + /// + /// URL per salvataggio contapezzi (quelli della macchina: PLC/CNC)... + /// + public string urlSetPzCountMAC + { + get + { + string answ = ""; + try + { + answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/setCounter/MAC_{cIobConf.codIOB}?counter="; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSetPzCountMAC"); + } + return answ; + } + } + /// + /// URL per INVIO IN BLOCCO di un INCREMENTO x contapezzi (quelli della macchina: PLC/CNC)... + /// + public string urlAddPzCount + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/savePzCountInc/{3}?qty=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlAddPzCount"); + } + return answ; + } + } + /// + /// URL per salvataggio VALORI opzionali... + /// + public string urlSetOptVal + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSetOptVal"); + } + return answ; + } + } + /// + /// URL per richiamo parametri da scrivere... + /// + public string urlGetParams2Write + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/getObjItems2Write/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlGetParams2Write"); + } + return answ; + } + } + /// + /// URL per richiamo task da eseguire... + /// + public string urlGetTask2Exe + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlGetTask2Exe"); + } + return answ; + } + } + /// + /// URL per richiamo task da eseguire... + /// + public string urlRemTask2Exe + { + get + { + string answ = ""; + try + { + answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlRemTask2Exe"); + } + return answ; + } + } + /// + /// URL per recupero contapezzi... + /// + public string urlGetPzCount + { + get + { + string answ = ""; + try + { + answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounter/{cIobConf.codIOB}"; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlGetPzCount"); + } + return answ; + } + } + /// + /// URL per recupero contapezzi REGISTRATI da TC... + /// + public string urlGetPzCountRec + { + get + { + string answ = ""; + try + { + answ = $@"http://{cIobConf.serverData.MPIP}{cIobConf.serverData.MPURL}{cIobConf.serverData.CMDALIVE}/getCounterTCRec/{cIobConf.codIOB}"; + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlGetPzCountRec"); + } + return answ; + } + } + /// + /// URL per salvataggio dati associazione Machine 2 IOB... + /// + public string urlSetM2IOB + { + get + { + string answ = ""; + try + { + string machineName = Environment.MachineName; + answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSetM2IOB"); + } + return answ; + } + } + /// + /// URL per salvataggio dati conf memoria IOB... + /// + public string urlSaveMemMap + { + get + { + string answ = ""; + try + { + string machineName = Environment.MachineName; + answ = string.Format(@"http://{0}{1}{2}/saveConf/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSaveMemConf"); + } + return answ; + } + } + /// + /// URL per salvataggio dati PARAMETRI IOB... + /// + public string urlSaveAllParams + { + get + { + string answ = ""; + try + { + string machineName = Environment.MachineName; + string apiCall = "setObjItems"; + answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSaveMemConf"); + } + return answ; + } + } + /// + /// URL per salvataggio in UPSERT dei PARAMETRI IOB scritti... + /// + public string urlUpdateWriteParams + { + get + { + string answ = ""; + try + { + string machineName = Environment.MachineName; + string apiCall = "upsertObjItems"; + answ = string.Format(@"http://{0}{1}{2}/{3}/{4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, apiCall, cIobConf.codIOB); + } + catch (Exception exc) + { + lgError(exc, "Errore in composizione urlSaveMemConf"); + } + return answ; + } + } + public static string GetMACAddress() + { + NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces(); + String sMacAddress = string.Empty; + foreach (NetworkInterface adapter in nics) + { + if (string.IsNullOrEmpty(sMacAddress))// only return MAC Address from first card + { + IPInterfaceProperties properties = adapter.GetIPProperties(); + //sMacAddress = adapter.GetPhysicalAddress().ToString(); + sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray()); + } + } + return sMacAddress; + } + /// + /// Fornisce URL INPUT per i parametri richiesti + /// + /// valore salvato in coda formato dtEve#valore#counter + /// + public string urlInput(string queueVal) + { + // URL base x input + string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE); + // decodifica valore! + string[] valori = qDecodeIN(queueVal); + // aggiungo macchina e valore... + answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]); + // aggiondo dataOra evento e corrente + contatore... + answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]); + return answ; + } + /// + /// Fornisce URL di tipo FluxLog + /// + /// valore salvato in coda nel formato dtEve#flux#valore#counter + /// + public string urlFLog(string queueVal) + { + // URL base x input + string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG); + // decodifica valore! + string[] valori = qDecodeIN(queueVal); + // aggiungo macchina e valore... + answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]); + // aggiondo dataOra evento e corrente + contatore... + answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]); + return answ; + } + /// + /// Formatta URL x invio in DataBlock Json dei dati FLog / eventi + /// + /// + /// + public string urlDataBlock(urlType tipoUrl) + { + // verifico la parte di link "tipoComando" + string tipoComando = tipoUrl == urlType.FLog ? cIobConf.serverData.CMDFLOG_JSON : cIobConf.serverData.CMDBASE_JSON; + // URL base x input + string answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, tipoComando, cIobConf.codIOB); + return answ; + } + /// + /// Restituisce un payload in formato json della lista di valori ricevuta + /// + /// Tipo di URL (eventi / FLog) + /// elenco di valori da coda string salvata + /// + public string jsonPayload(urlType tipoUrl, List elencoValori) + { + string answ = ""; + if (elencoValori != null) + { + if (tipoUrl == urlType.FLog) + { + flogData currData = new flogData(); + flogJsonPayload fullObj = new flogJsonPayload(); + fullObj.fluxData = new List(); + string[] valori; + int counter = 0; + DateTime dtEve = DateTime.Now; + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + //DateTime.TryParse(valori[0], out dtEve); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[3], out counter); + currData = new flogData() + { + flux = valori[1], + valore = valori[2], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullObj.fluxData.Add(currData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullObj); + } + catch (Exception exc) + { + lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + } + else + { + evData currData = new evData(); + evJsonPayload fullObj = new evJsonPayload(); + fullObj.eventList = new List(); + string[] valori; + int counter = 0; + DateTime dtEve = DateTime.Now; + // inizio processando ogni valore + foreach (var item in elencoValori) + { + valori = qDecodeIN(item); + //DateTime.TryParse(valori[0], out dtEve); + CultureInfo provider = CultureInfo.InvariantCulture; + DateTime.TryParseExact(valori[0], "yyyyMMddHHmmssfff", provider, DateTimeStyles.AssumeLocal, out dtEve); + int.TryParse(valori[2], out counter); + currData = new evData() + { + valore = valori[1], + dtEve = dtEve, + dtCurr = DateTime.Now, + cnt = counter + }; + fullObj.eventList.Add(currData); + } + // conversione finale + try + { + answ = JsonConvert.SerializeObject(fullObj); + } + catch (Exception exc) + { + lgError($"Errore in costruzione jsonPayload:{Environment.NewLine}{exc}"); + } + } + } + return answ; + } + /// + /// Reset dei webclients + /// + public static void resetWebClients() + { + utils.resetWebClients(); + } + /// + /// Effettua chiamata URL e restituisce risultato + /// + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrl(string URL, bool doAsync) + { + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) + { + //Task resp = utils.callUrlAsync(URL); + //answ = resp.Result; + answ = utils.callUrlAsync(URL); + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL); + } + return answ; + } + /// + /// Effettua chiamata URL e restituisce risultato + /// + /// + /// + /// invio in modalità async (NON GARANTITO ordine...) + /// + public static string callUrlWithPayload(string URL, string payload, bool doAsync) + { + string answ = ""; + // Chiamata ASINCRONA + if (doAsync) + { + answ = utils.callUrlAsync(URL, payload); + } + // chiamata SOLO NORMALE SINCRONA... + else + { + answ = utils.callUrl(URL, payload); + } + return answ; + } + /// + /// test ping all'indirizzo impostato nei parametri + /// + /// + private IPStatus testPingServer + { + get + { + IPStatus answ = IPStatus.Unknown; ; + IPAddress address; + PingReply reply; + using (Ping pingSender = new Ping()) + { + address = IPAddress.Loopback; + int maxRetry = maxPingRetry + 1; + int numRetry = 1; ; + string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", ""); + IPAddress.TryParse(ipAdrr, out address); + reply = pingSender.Send(address, pingServerMsTimeout); + // se ho timeout riprovo... + while (reply.Status != IPStatus.Success && numRetry < maxRetry) + { + lgInfo($"Ping KO | reply: {reply.Status} --> retry"); + reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2); + numRetry++; + if (reply.Status == IPStatus.Success) + { + lgInfo("PING OK!"); + break; + } + } + } + answ = reply.Status; + return answ; + } + } + /// + /// Verifica se il server sia ALIVE (tramite PING) + /// + public bool checkServerAlive + { + get + { + bool answ = false; + // controllo se ho un VETO all'invio... + if (dtVetoPing < DateTime.Now) + { + if (DemoOut) + { + answ = false; + } + else + { + IPStatus pingStatus = testPingServer; + // se passa il ping faccio il resto... + if (pingStatus == IPStatus.Success) + { + string callResp = ""; + try + { + // chiamo URL, se restituisce "OK" è alive! + callResp = callUrl(urlAlive, false); + answ = (callResp == "OK"); + } + catch (Exception exc) + { + lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc); + } + // attesa casuale se necessario + var rand = new Random(); + // primi 3 test + int maxTry = 3; + while (maxTry > 0 && !answ) + { + try + { + Thread.Sleep(rand.Next(150, 500)); + callResp = callUrl(urlAlive, false); + answ = (callResp == "OK"); + maxTry--; + } + catch + { } + } + // se NON OK riprovo ANCORA 1 volta... + if (!answ) + { + resetWebClients(); + Thread.Sleep(rand.Next(500, 1000)); + callResp = callUrl(urlAlive, false); + answ = (callResp == "OK"); + } + // altri 3 + maxTry = 3; + while (maxTry > 0 && !answ) + { + try + { + Thread.Sleep(rand.Next(150, 500)); + callResp = callUrl(urlAlive, false); + answ = (callResp == "OK"); + maxTry--; + } + catch + { } + } + // verifico SE è variato stato online/offline... + if (MPOnline != answ) + { + // se ORA sono online riporto... + if (answ) + { + lgInfo("SERVER ONLINE in checkServerAlive"); + parentForm.commSrvActive = 1; + dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec); + } + else + { + lgInfo("SERVER OFFLINE in checkServerAlive"); + parentForm.commSrvActive = 0; + } + // salvo nuovo status... + MPOnline = answ; + } + else + { + // allungo periodo controllo... + dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3); + } + } + else + { + lgInfo($"SERVER NOT RESPONDING (PING at {cIobConf.serverData.MPIP})"); + MPOnline = false; + // imposto veto a 10 volte reinvio dati standard... + dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 3); + utils.dtVetoSend = dtVetoPing; + } + } + } + else + { + // altrimenti passo ultimo valore noto... + answ = MPOnline; + } + return answ; + } + } + /// + /// Verifica se la IOB sia ENABLED (da server o Demo) + /// + private bool checkIobEnabled + { + get + { + bool answ = false; + // controllo se ho veto al check... + if (dtVetoCheckIOB < DateTime.Now) + { + if (DemoOut) + { + answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend); + } + else + { + try + { + // chiamo URL, se restituisce "OK" è enabled! + string callResp = callUrl(urlIobEnabled, true); + answ = (callResp == "OK"); + // attesa casuale se necessario + var rand = new Random(); + // primi 2 test + int maxTry = 2; + while (maxTry > 0 && !answ) + { + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, true); + answ = (callResp == "OK"); + maxTry--; + } + // se NON OK riprovo ANCORA 1 volta... + if (!answ) + { + resetWebClients(); + Thread.Sleep(rand.Next(250, 1000)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); + } + // altri 2 + maxTry = 2; + while (maxTry > 0 && !answ) + { + Thread.Sleep(rand.Next(250, 500)); + callResp = callUrl(urlIobEnabled, false); + answ = (callResp == "OK"); + maxTry--; + } + // salvo status... + IobOnline = answ; + // se online imposto veto check a 5 x tempo reinvio... + if (answ) + { + lastIobOnline = DateTime.Now; + } + dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5); + } + catch + { } + } + // verifico SE è variato stato online/offline... + if (IobOnline != answ) + { + // se ORA sono online riporto... + if (answ) + { + lgInfo("IOB ONLINE for server MP/IO"); + } + else + { + lgInfo("IOB OFFLINE for server MP/IO"); + } + } + // fix colore + if (answ) + { + parentForm.commSrvActive = 2; + } + else + { + parentForm.commSrvActive = 1; + } + } + else + { + // altrimenti passo ultimo valore noto + answ = IobOnline; + } + return answ; + } + } + /// + /// Processo la coda SignalIN... + /// + public void svuotaCodaSignIN() + { + // verifico SE la coda abbia dei valori... + if (QueueIN.Count > 0) + { + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) + { + if (QueueIN.Count > 0) + { + string currVal = ""; + // se online provo + if (MPOnline) + { + if (IobOnline) + { + // se ho + di 2 elementi in coda --> uso invio JSON in blocco... + if (QueueIN.Count > 1) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueIN.Count > maxJsonDataEv) + { + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonDataEv; j++) + { + QueueIN.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.SignIN, listaValori); + } + else + { + // invio in blocco + listaValori = QueueIN.ToList(); + // invio + sendDataBlock(urlType.SignIN, listaValori); + // svuoto! + QueueIN = new ConcurrentQueue(); + } + } + else + { + // INVIO SINGOLO...!!! + QueueIN.TryDequeue(out currVal); + sendToMoonPro(urlType.SignIN, currVal); + } + // salvo come last signal in il currVal ultimo... SE !="" + if (!string.IsNullOrEmpty(currVal)) + { + lastSignInVal = currVal; + } + } + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + + } + } + + /// + /// Processo la coda FLog... + /// + private void svuotaCodaFLog() + { + //controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!! + if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec")) + { + string wdStatus = "elapsed"; + string sVal = string.Format("[WDST]{0}", wdStatus); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("WDST", wdStatus)); + lastWatchDog = DateTime.Now; + } + // verifico SE la coda abbia dei valori... + if (QueueFLog.Count > 0) + { + // invio pacchetto di dati (max da conf) + for (int i = 0; i < nMaxSend; i++) + { + // SE ho qualcosa in coda... + if (QueueFLog.Count > 0) + { + string currVal = ""; + if (MPOnline) + { + if (IobOnline) + { + // se ho + di 2 elementi in coda --> uso invio JSON in blocco... + if (QueueFLog.Count > 1) + { + List listaValori = new List(); + // se ho + di maxJsonData elementi --> invio un set di dati alla volta + if (QueueFLog.Count > maxJsonData) + { + // prendoi primi maxJsonDataValori + for (int j = 0; j < maxJsonData; j++) + { + QueueFLog.TryDequeue(out currVal); + listaValori.Add(currVal); + } + sendDataBlock(urlType.FLog, listaValori); + } + else + { + // invio in blocco + listaValori = QueueFLog.ToList(); + // invio + sendDataBlock(urlType.FLog, listaValori); + // svuoto! + QueueFLog = new ConcurrentQueue(); + } + } + else + { + // INVIO SINGOLO...!!! + QueueFLog.TryDequeue(out currVal); + sendToMoonPro(urlType.FLog, currVal); + } + } + else + { + break; + } + } + else + { + break; + } + } + else + { + break; + } + } + } + } + /// + /// Classe fittizia in caso di processing task in VHF + /// + public virtual void processVHF() + { + } + /// + /// Classe fittizia in caso di processing watchdog data + /// + public virtual void processWhatchDog() + { + } + + /// + /// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo... + /// + private void processAllMemory() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // in primis SALVO valori previous/precedenti + B_previous = B_output; + // poi faccio lettura NUOVI valori + readAllData(ref currDispData); + // eseguo il filtering dei valori (per i bit "blinking") + filterData(); + // effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo... + if (B_output != B_previous) + { + accodaSigIN(ref currDispData); + } + raiseRefresh(currDispData); + } + /// + /// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC... + /// + public void processMemoryDiscon() + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // controllo contatore invio "keepalive"... invio solo a scadenza + if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec")) + { + // resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta... + B_input = 0; + B_output = 0; + B_previous = 0; + accodaSigIN(ref currDispData); + // update controllo + lastDisconnCheck = DateTime.Now; + } + raiseRefresh(currDispData); + } + /// + /// Esegue filtraggio dati x bit blinking!!! + /// + private void filterData() + { + // effettuo filtraggio dei valori letti... inizializzo OUT! + B_output = 0; + // in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN... + if (cIobConf.BLINK_FILT == 0) + { + B_output = B_input; + } + else + { + // incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT... + B_output = B_input & ~cIobConf.BLINK_FILT; + // calcolo il valore dei BIT che "passano la maschera" + int iBlink = B_input & cIobConf.BLINK_FILT; + // ...aggiungo i "bit che passano" + B_output += iBlink; + + // calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters... + BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) }); + int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray(); + for (int i = 0; i < bitsUp.Length; i++) + { + // SE 1... impostiamo contatori al MAX + if (bitsUp[i] == 1) + { + // se era zero indico START blink... + if (i_counters[i] == 0) + { + lgInfo("START BLINK: B{0}", i); + } + // imposto comunque contatore al cambio fronte... + i_counters[i] = cIobConf.MAX_COUNTER_BLINK; + } + } + + // quelli che sono zero... LI RECUPERO E LI PROCESSO... + int iZero = ~B_input & cIobConf.BLINK_FILT; + BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) }); + int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray(); + for (int i = 0; i < bitsDown.Length; i++) + { + // se era a zero (invertito...) + if (bitsDown[i] == 1) + { + // SE è in corso il conteggio... + if (i_counters[i] > 0) + { + // decremento! + i_counters[i] -= 1; + // se è zero NON faccio nulla, altrimenti SOMMO... + if (i_counters[i] > 0) + { + B_output += 1 << i; + } + else + { + lgInfo("END BLINK: B{0}", i); + } + } + } + } + } + } + + /// + /// Effettua lettura dati + /// Parametri da aggiornare x display in form + /// + public virtual void readAllData(ref newDisplayData currDispData) + { + if (currDispData == null) + { + currDispData = new newDisplayData(); + } + try + { + if (DemoIn) + { + // segnalo che sono in Demo + currDispData.semIn = Semaforo.SV; + } + if (connectionOk) + { + readSemafori(ref currDispData); + lastReadPLC = DateTime.Now; + } + else + { + lgError("Errore connessione mancante x readSemafori"); + } + + nReadIN++; + // aggiorno valore mostrato... + displayRawData(ref currDispData); + } + catch + { + currDispData.semIn = Semaforo.SR; + } + raiseRefresh(currDispData); + } + /// + /// Effettua gestioen programma: legge e mostra su display... + /// + private void processProgram() + { + string currPrgName = ""; + // se abilitata lettura prgName + if (enablePrgName) + { + if (connectionOk) + { + currPrgName = getPrgName(); + } + else + { + lgError("Errore connessione mancante x getPrgName"); + } + + } + else + { + currPrgName = lastPrgName; + } + // verifico SE sia cambiato il programma... + if (lastPrgName != currPrgName) + { + // salvo! + lastPrgName = currPrgName; + string sVal = string.Format("[PROG]{0}", currPrgName); + + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("PROG", currPrgName)); + } + } + /// + /// Effettua verifica se abilitato invio pezzi in blocco e nel caso + /// - invio in blocco pezzi + /// - aggiornamento del contapezzi (passato come ref) x nuovo valore post invio + /// + public void trySendPzCountBlock() + { + // in primis HA SENSO procedere SOLO SE server MP è Online... + if (MPOnline) + { + // SOLO SE online la macchina... + if (IobOnline) + { + int numIncr = 0; + int qtyAdded = 0; + // verifico se la funzione SIA abilitata + if (enableSendPzCountBlock) + { + int delta = lastCountCNC - contapezzi; + // se è abilitata verifico differenza: se ho DELTA > minSendPzCountBlock --> invio un blocco <= maxSendPzCountBlock + if (delta > minSendPzCountBlock) + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + // resta indietro di ALMENO minSendPzCountBlock pezzi x recuperare 1:1... + numIncr = delta > maxSendPzCountBlock + minSendPzCountBlock ? maxSendPzCountBlock : delta - minSendPzCountBlock; + // invio il num max di pezzi ammesso in blocco! + lastUrl = $"{urlAddPzCount}{numIncr}"; + string resp = utils.callUrlNow(lastUrl); + if (!string.IsNullOrEmpty(resp)) + { + // dalla risposta (come numero) capisco SE ha aggiunto i pezzi (e quanti) + int.TryParse(resp, out qtyAdded); + if (qtyAdded > 0) + { + // aggiorno IL MIO contapezzi... + contapezzi += qtyAdded; + lgInfo($"Inviato incremento contapezzi: send: {numIncr} | resp: {qtyAdded} | contapezzi: {contapezzi}"); + // invio conferma contapezzi.. + string retVal = utils.callUrl($"{urlSetPzCount}{contapezzi}"); + // verifica se tutto OK + if (retVal != contapezzi.ToString()) + { + // errore salvataggio contapezzi + lgInfo($"trySendPzCountBlock: errore salvataggio contapezzi: contapezzi {contapezzi} | risposta: {retVal}"); + } + } + else + { + lgError($"Richiesto incremento {numIncr} ma NON registrato su server MP-IO"); + } + } + currDispData.newUrlCallData = lastUrl; + currDispData.counter = contapezzi; + currDispData.semOut = Semaforo.SV; + raiseRefresh(currDispData); + } + } + } + else + { + lgInfo("Impossibile trySendPzCountBlock: IobOnline è false"); + } + } + else + { + lgInfo("Impossibile trySendPzCountBlock: MPOnline è false"); + } + } + /// + /// Verifica se sia machcina multi = DoppioPallet da CONF + /// + public bool isMulti + { + get + { + bool answ = false; + if (cIobConf.optPar.Count > 0) + { + // cerco con chaive reale IS_MULTI + string keyName = "IS_MULTI"; + if (!cIobConf.optPar.ContainsKey(keyName)) + { + // legacy: accetto anche SIM_MULTI... + keyName = "SIM_MULTI"; + } + // vera verifica su chaive... + if (cIobConf.optPar.ContainsKey(keyName)) + { + string SIM_MULTI = getOptPar(keyName); + answ = SIM_MULTI == "1"; + } + } + return answ; + } + } + /// + /// Verifica e processing x gestione ODL automatica + /// + public void processAutoOdl() + { + bool fatto = false; + if (!string.IsNullOrEmpty(getOptPar("AUTO_CHANGE_ODL"))) + { + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + string fullUrl = ""; + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // controllo SIA abilitato... + bool doProc = false; + DateTime adesso = DateTime.Now; + bool.TryParse(getOptPar("AUTO_CHANGE_ODL"), out doProc); + if (doProc) + { + // carico i parametri di configurazione x reset ODL... + string CHANGE_ODL_HOURS = getOptPar("CHANGE_ODL_IDLE_MIN"); + string CHANGE_ODL_IDLE_MIN = getOptPar("CHANGE_ODL_IDLE_MIN"); + if (!string.IsNullOrEmpty(CHANGE_ODL_HOURS) && !string.IsNullOrEmpty(CHANGE_ODL_IDLE_MIN)) + { + int minOdlDurHours = -1; + int minPlcIdelMin = -1; + int.TryParse(CHANGE_ODL_HOURS, out minOdlDurHours); + int.TryParse(CHANGE_ODL_IDLE_MIN, out minPlcIdelMin); + // controllo parametri validi + if (minOdlDurHours > 0 && minPlcIdelMin > 0) + { + // leggo da server inizio ODL... se non multi 1 solo... + DateTime inizioOdl = DateTime.Now; + string rawDataInizio = ""; + if (!isMulti) + { + rawDataInizio = callUrl(urlInizioOdlIob, false); + DateTime.TryParse(rawDataInizio, out inizioOdl); + } + else + { + DateTime tmpData = DateTime.Now; + // prendo il + vecchio... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlInizioOdlIob}|{item}"; + rawDataInizio = callUrl(fullUrl, false); + DateTime.TryParse(rawDataInizio, out tmpData); + inizioOdl = (tmpData < inizioOdl) ? tmpData : inizioOdl; + } + } + // verifico se sia scaduto... + if (inizioOdl.AddHours(minOdlDurHours) < adesso) + { + string rawIdle = ""; + int idlePeriod = 0; + if (!isMulti) + { + // controllo SE sono fermo (spento o in manuale) per il periodo minimo richiesto... + rawIdle = callUrl(urlIdleTime, false); + int.TryParse(rawIdle, out idlePeriod); + } + else + { + int tmpIdle = 0; + // prendo il + grande... + foreach (var item in elencoMulti) + { + fullUrl = $"{urlIdleTime}|{item}"; + rawIdle = callUrl(fullUrl, false); + int.TryParse(rawIdle, out tmpIdle); + idlePeriod = tmpIdle > idlePeriod ? tmpIdle : idlePeriod; + } + } + if (idlePeriod >= minPlcIdelMin) + { #if false /*************************************************** * Descrizione procedura (OK X SIMULATORI...) @@ -3549,870 +3569,882 @@ namespace IOB_WIN fatto = (rawSplit == "OK") ? true : false; } #endif - fatto = forceSplitOdl(); - lgInfo("Chiamata: processAutoOdl --> forceSplitODL"); + fatto = forceSplitOdl(); + lgInfo("Chiamata: processAutoOdl --> forceSplitODL"); + } + } + } + } } - } } - } - } - } - // loggo se fatto - if (fatto) - { - lgInfo($"Effettuato processAutoOdl"); - } - } - /// - /// Effettua chaimata x split ODL - /// - /// - public bool forceSplitOdl() - { - bool fatto = false; - if (vetoSplit < DateTime.Now) - { - // imposto veto x 1 minuto ad altre chiamate... - vetoSplit = DateTime.Now.AddMinutes(1); - // eseguo SOLO SE sono online... - if (MPOnline && IobOnline) - { - string fullUrl = ""; - string rawSplit = ""; - string IOB_MULTI_CNAME = ""; - string[] elencoMulti = null; - - try - { - /*************************************************** - * Descrizione procedura (OK X SIMULATORI...) - * - * - chiamata su MP/IO - * - verifica che su DB sia abilitato AUTO ODL - * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW - * - viene duplicato e chiuso ODL corrente - * - viene fatto partire ODL nuovo ADESSO - * - num pezzi come ODL precedente (o da media 3 ODL precedenti) - * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) - * - reset contapezzi PLC locale... - * - * - * - * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE - * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) - * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) - * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) - * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) - * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO - * - * ***************************************************/ - - if (isMulti) + // loggo se fatto + if (fatto) { - // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... - IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); - elencoMulti = IOB_MULTI_CNAME.Split(','); + lgInfo($"Effettuato processAutoOdl"); } - // se normale splitto! - if (!isMulti) + } + /// + /// Effettua chaimata x split ODL + /// + /// + public bool forceSplitOdl() + { + bool fatto = false; + if (vetoSplit < DateTime.Now) { - // invio chiamata URL x reset ODL su macchina - rawSplit = callUrl(urlForceSplit, false); - fatto = (rawSplit == "OK") ? true : false; - } - // se multi gestisco il bit delle tavole... - else - { - foreach (string item in elencoMulti) - { - // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato... - fullUrl = $"{urlForceSplit}|{item}"; - rawSplit = callUrl(fullUrl, false); - } - fatto = (rawSplit == "OK") ? true : false; - } - - } - catch (Exception exc) - { - lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); - } - // se fatto --> resetto contapezzi!!! - if (fatto) - { - lastCountCNC = 0; - contapezzi = 0; - } - } - else - { - lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); - } - } - else - { - lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); - } - return fatto; - } - - /// - /// Processo lettura dati sysinfo - /// - private void processSysInfo() - { - if (utils.CRB("enableSysInfo")) - { - Dictionary currSysInfo = new Dictionary(); - - if (connectionOk) - { - currSysInfo = getSysInfo(); - } - else - { - lgError("Errore connessione mancante x getSysInfo"); - } - // verifico SE sia cambiato il programma... - if (lastSysInfo != currSysInfo["SYSINFO"]) - { - // salvo! - lastSysInfo = currSysInfo["SYSINFO"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currSysInfo) - { - sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - } - } - /// - /// Restituisce info sistema - /// - /// - public virtual Dictionary getSysInfo() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - /// - /// Restituisce info DINAMICHE - /// - /// - public virtual Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - /// - /// Restituisce info OVERRIDES - /// - /// - public virtual Dictionary getOverrides() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - /// - /// Recupera eventuali allarmi CNC... - /// - public virtual Dictionary getCncAlarms() - { - Dictionary outVal = new Dictionary(); - return outVal; - } - /// - /// Restituisce programma in esecuzione - /// - public virtual string getPrgName() - { - return ""; - } - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public virtual void readSemafori(ref newDisplayData currDispData) - { - lastReadPLC = DateTime.Now; - } - - /// - /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) - /// - public virtual void processContapezzi() - { } - /// - /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) - /// - public virtual void processOtherCounters() - { } - /// - /// Effettua processing mode/status (EDIT/MDI/...) - /// - public virtual void processMode() - { } - /// - /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi - /// - public void processDynData() - { - bool enableByApp = utils.CRB("enableDynData"); - bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); - bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); - Dictionary currDynData = new Dictionary(); - - if (enableByApp || enableByIob) - { - lgInfo("Inizio processDynData"); - if (connectionOk) - { - currDynData = getDynData(); - } - else - { - lgError("Errore connessione mancante x getDynData"); - } - try - { - string sVal = ""; - // se richiesto send diretto... - if (forceSendByIob) - { - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) - { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // altrimenti verifico SE sia cambiato il valore dei DynData... - else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) - { - // salvo! - lastDynDataCtrlVal = currDynData["DYNDATA"]; - // per ogni valore del dizionario mostro ed accodo! - foreach (var item in currDynData) - { - sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - // salvo array... - lastDynData = currDynData; - } - catch (Exception exc) - { - lgError(exc, "Eccezione in processDynData"); - } - } - } - - /// - /// Effettua processing degli allarmi CNC SE disponibili - /// - public void processCncAlarms() - { - if (utils.CRB("enableAlarms")) - { - Dictionary currAlarms = new Dictionary(); - if (connectionOk) - { - currAlarms = getCncAlarms(); - } - else - { - lgError("Errore connessione mancante x getCncAlarms"); - } - // verifico SE sia cambiato il programma... - if (currAlarms.Count > 0) - { - try - { - if (lastAlarm != currAlarms["CNC_ALARM"]) - { - // salvo! - lastAlarm = currAlarms["CNC_ALARM"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currAlarms) - { - sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - } - catch (Exception exc) - { - lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); - } - } - } - } - - /// - /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) - /// - public virtual void processOverride() - { - bool enableByApp = utils.CRB("enableOverrides"); - bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); - Dictionary currOverride = new Dictionary(); - if (enableByApp || enableByIob) - { - lgInfo("Inizio processOverride"); - if (connectionOk) - { - currOverride = getOverrides(); - } - else - { - lgError("Errore connessione mancante x getOverrides"); - } - - // SE sono connesso... - if (connectionOk) - { - // se HO dei valori override... - if (currOverride.Count > 0) - { - // verifico SE sia cambiato il programma... - if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) - { - // salvo! - lastOverrideFS = currOverride["FEED_OVER"]; - lastOverrideRapid = currOverride["RAPID_OVER"]; - // per ogni valore del dizionario mostro ed accodo! - string sVal = ""; - foreach (var item in currOverride) - { - sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); - } - } - } - } - } - } - /// - /// metodo dummy x salvataggio aree memoria conf x CN - /// - /// tipo di DUMP - public virtual void saveMemDump(dumpType tipo) - { - } - - #endregion - - #region gestione VC e proprocessing - - /// - /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo - /// - /// Nome della VC - /// Valore (nuovo) delal VC - /// - public bool stackVal_TSVC(string VCName, double VCVal) - { - bool answ = false; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - TSVC_Data[VCName].dataArray.Add(VCVal); - // ora verifico scadenza... - if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now) - { - answ = true; - } - } - return answ; - } - /// - /// - /// - /// - /// - /// - /// - public void saveValue(ref Dictionary outVal, double valore, string chiave) - { - bool scaduto = stackVal_TSVC(chiave, valore); - // recupero VC - valore = getVal_TSVC(chiave, scaduto); - if (scaduto) outVal.Add(chiave, $"{valore}"); - LastTSVC[chiave] = valore; - } - /// - /// Recupera la VC x TS, svuotando lista e resettando periodo partenza - /// - /// Nome della VC - /// Reimposta e resetta array VC - /// - public double getVal_TSVC(string VCName, bool doReset) - { - double answ = 0; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - // !!!FARE!!! vero calcolo... x ora FIX a MAX... - foreach (var item in TSVC_Data[VCName].dataArray) - { - answ = item > answ ? item : answ; - } - // ora resetto... SE richiesto... - if (doReset) - { - TSVC_Data[VCName].dataArray = new List(); - TSVC_Data[VCName].DTStart = DateTime.Now; - } - } - return answ; - } - /// - /// Recupera la VC x TS, svuotando lista e resettando periodo partenza - /// - /// Nome della VC - /// Reimposta e resetta array VC - /// - public int getVal_TSVC_int(string VCName, bool doReset) - { - int answ = 0; - // cerco VC... - if (TSVC_Data.ContainsKey(VCName)) - { - // !!!FARE!!! vero calcolo... x ora FIX a MAX... - foreach (var item in TSVC_Data[VCName].dataArray) - { - answ = (int)item > answ ? (int)item : answ; - } - // ora resetto... SE richiesto.. - if (doReset) - { - TSVC_Data[VCName].dataArray = new List(); - TSVC_Data[VCName].DTStart = DateTime.Now; - } - } - return answ; - } - /// - /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza) - /// - /// - /// - /// - public bool monItem2Send(string newVal, DynDataItem item) - { - bool answ = false; - // controllo in base al tipo di function... - switch (item.func) - { - case "SAMPLE": - // controllo se scaduto sample period... - if (item.DTScad < DateTime.Now) - { - answ = true; - } - break; - case "CHANGE": - default: - // controllo se scaduto o se variato... - if (newVal != item.actVal || item.DTScad < DateTime.Now) - { - // aggiorno scadenza e che vada inviato - answ = true; - } - break; - } -#if false - if (answ) - { - // salvo valore - item.val = newVal; - // aggiorno scadenza - item.DTScad = DateTime.Now.AddSeconds(item.sPeriod); - } -#endif - return answ; - } - - #endregion - - #region gestione code (accumulo, invio) - - /// - /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont - /// - protected string qEncodeIN - { - get - { - string answ = ""; - try - { - answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN); - } - catch - { } - return answ; - } - } - /// - /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont - /// Flusso dati - /// Valore da salvare - /// - public string qEncodeFLog(string flusso, string valore) - { - string answ = ""; - try - { - answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog); - } - catch - { } - return answ; - } - /// - /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont - /// DataOra evento registrato - /// Flusso dati - /// Valore da salvare - /// - public string qEncodeFLog(DateTime eventDT, string flusso, string valore) - { - string answ = ""; - try - { - answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", eventDT, flusso, valore, counterFLog); - } - catch - { } - return answ; - } - /// - /// Decodifica valore della coda IN nel formato - /// answ[0]=dtEve - /// answ[1]=valore - /// answ[2]=counter - /// - /// dtEve + '#' + value + '#' + cont - /// - protected static string[] qDecodeIN(string queueVal) - { - return queueVal.Split('#'); - } - /// - /// Accumula in coda i valori Signal IN e logga... - /// Parametri da aggiornare x display in form - /// - public void accodaSigIN(ref newDisplayData currDispData) - { - // mostro dati variati letti... - displayInData(ref currDispData); - // --> accodo (valore già formattato)! - QueueIN.Enqueue(qEncodeIN); - // loggo! - lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN)); - // aggiorno counters ed eventuale reset - nReadFilt++; - if (nReadFilt > int.MaxValue - 1) - { - nReadFilt = 0; // per evitare buffer overflow... - } - - counterSigIN++; - if (counterSigIN > 9999) - { - counterSigIN = 0; - } - } - /// - /// Accumula in coda i valori Flux Log e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeFLog(...) - public void accodaFLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // --> accodo (valore già formattato)! - QueueFLog.Enqueue(encodedVal); - // se abilitato controllo coda FLog (superiore a 0...) - if (maxQueueFLog > 0) - { - // se ho una coda superiore a max ammesso - if (QueueFLog.Count > maxQueueFLog) - { - // elimino valori iniziali fino a tornare al max ammesso... - while (QueueFLog.Count > maxQueueFLog) - { - string currVal = ""; - QueueFLog.TryDequeue(out currVal); - lgInfo($"Eliminazione ca coda FLog per superamento maxLengh: {currVal}"); - } - } - } - // loggo! - lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } - } - /// - /// Accumula in coda i valori ALARM e logga... - /// - /// VALORE RAW (x display) - /// VALORE già processato con qEncodeFLog(...) - public void accodaAlarmLog(string val, string encodedVal) - { - // mostro dati variati letti... - displayOtherData(val); - // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! - QueueFLog.Enqueue(encodedVal); - // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) ho allarmi perdurati... - - // loggo! - lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal)); - counterFLog++; - if (counterFLog > 9999) - { - counterFLog = 0; - } - } - /// - /// Invia una LISTA di valori - /// - /// - /// - public void sendDataBlock(urlType tipoUrl, List listQueueVal) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - if (listQueueVal != null) - { - try - { - // recupero e formatto URL dati da coda... - lastUrl = urlDataBlock(tipoUrl); - // in base al tipo di dato compongo il payload Json da inviare - string payload = jsonPayload(tipoUrl, listQueueVal); - // async a true SE FLog - bool doAsync = tipoUrl == urlType.FLog ? true : false; - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) - { - // chiamo URL! - string answ = callUrlWithPayload(lastUrl, payload, doAsync); - // loggo! - lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); - // se "OK" verde, altrimenti errore --> ROSSO - if (answ.Contains("OK")) - { - currDispData.semOut = Semaforo.SV; - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) + // imposto veto x 1 minuto ad altre chiamate... + vetoSplit = DateTime.Now.AddMinutes(1); + // eseguo SOLO SE sono online... + if (MPOnline && IobOnline) { - lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); + string fullUrl = ""; + string rawSplit = ""; + string IOB_MULTI_CNAME = ""; + string[] elencoMulti = null; + + try + { + /*************************************************** + * Descrizione procedura (OK X SIMULATORI...) + * + * - chiamata su MP/IO + * - verifica che su DB sia abilitato AUTO ODL + * - il server inserisce un evento fine prod HW 1 minuto prima e inizio setup HW + * - viene duplicato e chiuso ODL corrente + * - viene fatto partire ODL nuovo ADESSO + * - num pezzi come ODL precedente (o da media 3 ODL precedenti) + * - conferme pezzi & co... gestione NULL (NON SERVONO si tratta di impianti SENZA gestione vera ODL) + * - reset contapezzi PLC locale... + * + * + * + * DA VALUTARE (x macchine tipo linea con + impianti... es valvital) SE + * - creare una gestione ALTERNATIVA sul server che preveda impianto LEADER e impianti follower (RIGIDAMENTE CONFIGURATI) + * - ogni volta che si fa setup LEADER --> si ripete su impianti FOLLOWER (eventi!!!) + * - viene fatto reset contapezzi sui follower (+ altre operazioni opzionali, ES imposstazione nome commessa, quantità, articolo...) + * - viene fatto reset + nuovo ODL (con stessi articoli e quantità) su follower, SENZA avere gestione x ODL di un codice esterno (quindi registra TUTTO ma NON RITORNERA' dati non avendo link verso esterno) + * - serve NUOVA TABELLA delle macchine LEADER | FOLLOWER (1:n) e gestione da MP/IO + * + * ***************************************************/ + + if (isMulti) + { + // devo chiamare cambio ODL x OGNI tavola: mi servono i parametri opzionali... + IOB_MULTI_CNAME = getOptPar("IOB_MULTI_CNAME"); + elencoMulti = IOB_MULTI_CNAME.Split(','); + } + // se normale splitto! + if (!isMulti) + { + // invio chiamata URL x reset ODL su macchina + rawSplit = callUrl(urlForceSplit, false); + fatto = (rawSplit == "OK") ? true : false; + } + // se multi gestisco il bit delle tavole... + else + { + foreach (string item in elencoMulti) + { + // invio chiamata URL x reset ODL su macchina, ATTENZIONE scriviamo | al posto di "#" che in URL sarebbe filtrato... + fullUrl = $"{urlForceSplit}|{item}"; + rawSplit = callUrl(fullUrl, false); + } + fatto = (rawSplit == "OK") ? true : false; + } + + } + catch (Exception exc) + { + lgError($"Eccezione in forceSplitOdl{Environment.NewLine}{exc}"); + } + // se fatto --> resetto contapezzi!!! + if (fatto) + { + lastCountCNC = 0; + contapezzi = 0; + } + } + else + { + lgError("Richiesto forceSplitOdl ma MP/IOB offline --> NON eseguito"); } - lastIobOnline = DateTime.Now; - } - else - { - currDispData.semOut = Semaforo.SR; - } } else { - lgInfo($"[SERVER KO] {listQueueVal.Count}"); + lgError("Richiesto forceSplitOdl ma veto attivo --> NON eseguito"); } - } - else - { - currDispData.semOut = Semaforo.SV; + return fatto; + } + + /// + /// Processo lettura dati sysinfo + /// + private void processSysInfo() + { + if (utils.CRB("enableSysInfo")) + { + Dictionary currSysInfo = new Dictionary(); + + if (connectionOk) + { + currSysInfo = getSysInfo(); + } + else + { + lgError("Errore connessione mancante x getSysInfo"); + } + // verifico SE sia cambiato il programma... + if (lastSysInfo != currSysInfo["SYSINFO"]) + { + // salvo! + lastSysInfo = currSysInfo["SYSINFO"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currSysInfo) + { + sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + } + /// + /// Restituisce info sistema + /// + /// + public virtual Dictionary getSysInfo() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + /// + /// Restituisce info DINAMICHE + /// + /// + public virtual Dictionary getDynData() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + /// + /// Restituisce info OVERRIDES + /// + /// + public virtual Dictionary getOverrides() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + /// + /// Recupera eventuali allarmi CNC... + /// + public virtual Dictionary getCncAlarms() + { + Dictionary outVal = new Dictionary(); + return outVal; + } + /// + /// Restituisce programma in esecuzione + /// + public virtual string getPrgName() + { + return ""; + } + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public virtual void readSemafori(ref newDisplayData currDispData) + { + lastReadPLC = DateTime.Now; + } + + /// + /// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...) + /// + public virtual void processContapezzi() + { } + /// + /// Effettua processing ALTRI contatori/parametri (ed invia ad IO) + /// + public virtual void processOtherCounters() + { } + /// + /// Effettua processing mode/status (EDIT/MDI/...) + /// + public virtual void processMode() + { } + /// + /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi + /// + public void processDynData() + { + bool enableByApp = utils.CRB("enableDynData"); + bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE"); + bool forceSendByIob = (getOptPar("FORCE_DYN_DATA") == "TRUE"); + Dictionary currDynData = new Dictionary(); + + if (enableByApp || enableByIob) + { + lgInfo("Inizio processDynData"); + if (connectionOk) + { + currDynData = getDynData(); + } + else + { + lgError("Errore connessione mancante x getDynData"); + } + try + { + string sVal = ""; + // se richiesto send diretto... + if (forceSendByIob) + { + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // altrimenti verifico SE sia cambiato il valore dei DynData... + else if (lastDynDataCtrlVal != currDynData["DYNDATA"]) + { + // salvo! + lastDynDataCtrlVal = currDynData["DYNDATA"]; + // per ogni valore del dizionario mostro ed accodo! + foreach (var item in currDynData) + { + sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + // salvo array... + lastDynData = currDynData; + } + catch (Exception exc) + { + lgError(exc, "Eccezione in processDynData"); + } + } + } + + /// + /// Effettua processing degli allarmi CNC SE disponibili + /// + public void processCncAlarms() + { + if (utils.CRB("enableAlarms")) + { + Dictionary currAlarms = new Dictionary(); + if (connectionOk) + { + currAlarms = getCncAlarms(); + } + else + { + lgError("Errore connessione mancante x getCncAlarms"); + } + // verifico SE sia cambiato il programma... + if (currAlarms.Count > 0) + { + try + { + if (lastAlarm != currAlarms["CNC_ALARM"]) + { + // salvo! + lastAlarm = currAlarms["CNC_ALARM"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currAlarms) + { + sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + catch (Exception exc) + { + lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc); + } + } + } + } + + /// + /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) + /// + public virtual void processOverride() + { + bool enableByApp = utils.CRB("enableOverrides"); + bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE"); + Dictionary currOverride = new Dictionary(); + if (enableByApp || enableByIob) + { + lgInfo("Inizio processOverride"); + if (connectionOk) + { + currOverride = getOverrides(); + } + else + { + lgError("Errore connessione mancante x getOverrides"); + } + + // SE sono connesso... + if (connectionOk) + { + // se HO dei valori override... + if (currOverride.Count > 0) + { + // verifico SE sia cambiato il programma... + if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"]) + { + // salvo! + lastOverrideFS = currOverride["FEED_OVER"]; + lastOverrideRapid = currOverride["RAPID_OVER"]; + // per ogni valore del dizionario mostro ed accodo! + string sVal = ""; + foreach (var item in currOverride) + { + sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog(item.Key, item.Value)); + } + } + } + } + } + } + /// + /// metodo dummy x salvataggio aree memoria conf x CN + /// + /// tipo di DUMP + public virtual void saveMemDump(dumpType tipo) + { + } + + #endregion + + #region gestione VC e postprocessing + + /// + /// Processing di Variabili Campionarie x TimeSeries, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo + /// + /// Nome della VC + /// Valore (nuovo) delal VC + /// + public bool stackVal_TSVC(string VCName, double VCVal) + { + bool answ = false; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) + { + TSVC_Data[VCName].dataArray.Add(VCVal); + // ora verifico scadenza... + if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Period) < DateTime.Now) + { + answ = true; + } + } + return answ; + } + /// + /// + /// + /// + /// + /// + /// + public void saveValue(ref Dictionary outVal, double valore, string chiave) + { + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + bool scaduto = stackVal_TSVC(chiave, valore); + // recupero VC + valore = getVal_TSVC(chiave, scaduto); + if (scaduto) + { + outVal.Add(chiave, $"{valore}"); + } + LastTSVC[chiave] = valore; + } + /// + /// Recupera la VC x TS, svuotando lista e resettando periodo partenza + /// + /// Nome della VC + /// Reimposta e resetta array VC + /// + public double getVal_TSVC(string VCName, bool doReset) + { + double answ = 0; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) + { + // !!!FARE!!! vero calcolo... x ora FIX a MAX... + foreach (var item in TSVC_Data[VCName].dataArray) + { + answ = item > answ ? item : answ; + } + // ora resetto... SE richiesto... + if (doReset) + { + TSVC_Data[VCName].dataArray = new List(); + TSVC_Data[VCName].DTStart = DateTime.Now; + } + } + return answ; + } + /// + /// Recupera la VC x TS, svuotando lista e resettando periodo partenza + /// + /// Nome della VC + /// Reimposta e resetta array VC + /// + public int getVal_TSVC_int(string VCName, bool doReset) + { + int answ = 0; + // cerco VC... + if (TSVC_Data.ContainsKey(VCName)) + { + // !!!FARE!!! vero calcolo... x ora FIX a MAX... + foreach (var item in TSVC_Data[VCName].dataArray) + { + answ = (int)item > answ ? (int)item : answ; + } + // ora resetto... SE richiesto.. + if (doReset) + { + TSVC_Data[VCName].dataArray = new List(); + TSVC_Data[VCName].DTStart = DateTime.Now; + } + } + return answ; + } + /// + /// Processa un monitoredItem, e ritorna boolean SE richiede invio (cambio o scadenza) + /// + /// + /// + /// + public bool monItem2Send(string newVal, DynDataItem item) + { + bool answ = false; + if (item != null) + { + // controllo in base al tipo di function... + switch (item.func) + { + case "SAMPLE": + // controllo se scaduto sample period... + if (item.DTScad < DateTime.Now) + { + answ = true; + } + break; + case "CHANGE": + default: + // controllo se scaduto o se variato... + if (newVal != item.actVal || item.DTScad < DateTime.Now) + { + // aggiorno scadenza e che vada inviato + answ = true; + } + break; + } + } + return answ; + } + + #endregion + + #region gestione code (accumulo, invio) + + /// + /// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont + /// + protected string qEncodeIN + { + get + { + string answ = ""; + try + { + answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN); + } + catch + { } + return answ; + } + } + /// + /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont + /// Flusso dati + /// Valore da salvare + /// + public string qEncodeFLog(string flusso, string valore) + { + string answ = ""; + try + { + answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog); + } + catch + { } + return answ; + } + /// + /// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont + /// DataOra evento registrato + /// Flusso dati + /// Valore da salvare + /// + public string qEncodeFLog(DateTime eventDT, string flusso, string valore) + { + string answ = ""; + try + { + answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", eventDT, flusso, valore, counterFLog); + } + catch + { } + return answ; + } + /// + /// Decodifica valore della coda IN nel formato + /// answ[0]=dtEve + /// answ[1]=valore + /// answ[2]=counter + /// + /// dtEve + '#' + value + '#' + cont + /// + protected static string[] qDecodeIN(string queueVal) + { + string[] answ = null; + if (!string.IsNullOrEmpty(queueVal)) + { + try + { + answ = queueVal.Split('#'); + } + catch + { } + } + return answ; + } + /// + /// Accumula in coda i valori Signal IN e logga... + /// Parametri da aggiornare x display in form + /// + public void accodaSigIN(ref newDisplayData currDispData) + { + // mostro dati variati letti... + displayInData(ref currDispData); + // --> accodo (valore già formattato)! + QueueIN.Enqueue(qEncodeIN); // loggo! - lgInfo($"{listQueueVal.Count} records --> [SIM]"); - } - nSendOut += listQueueVal.Count; - // riporto cosa inviato - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; + lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN)); + // aggiorno counters ed eventuale reset + nReadFilt++; + if (nReadFilt > int.MaxValue - 1) + { + nReadFilt = 0; // per evitare buffer overflow... + } + + counterSigIN++; + if (counterSigIN > 9999) + { + counterSigIN = 0; + } } - catch + /// + /// Accumula in coda i valori Flux Log e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeFLog(...) + public void accodaFLog(string val, string encodedVal) { - currDispData.semOut = Semaforo.SR; - } - } - raiseRefresh(currDispData); - } - /// - /// Effettua invio a MoonPro del valore richiesto - /// - /// - /// Valore da trasmettere: es - /// INPUT: lo status rilevato in HEX - /// FLog: il valore da trasmettere per il flusso indicato - public void sendToMoonPro(urlType tipoUrl, string queueVal) - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - try - { - // recupero e formatto URL dati da coda... - switch (tipoUrl) - { - case urlType.FLog: - lastUrl = urlFLog(queueVal); - break; - case urlType.SignIN: - lastUrl = urlInput(queueVal); - break; - default: - lastUrl = ""; - break; - } - // se NON sono in demo effettuo invio! - if (!DemoOut) - { - // SE server alive... - if (checkServerAlive) - { - // chiamo URL! - string answ = callUrl(lastUrl, false); + // mostro dati variati letti... + displayOtherData(val); + // --> accodo (valore già formattato)! + QueueFLog.Enqueue(encodedVal); + // se abilitato controllo coda FLog (superiore a 0...) + if (maxQueueFLog > 0) + { + // se ho una coda superiore a max ammesso + if (QueueFLog.Count > maxQueueFLog) + { + // elimino valori iniziali fino a tornare al max ammesso... + while (QueueFLog.Count > maxQueueFLog) + { + string currVal = ""; + QueueFLog.TryDequeue(out currVal); + lgInfo($"Eliminazione ca coda FLog per superamento maxLengh: {currVal}"); + } + } + } // loggo! - lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ)); - // se oltre 1 min NON era online --> check pezzi! - if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) + lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal)); + counterFLog++; + if (counterFLog > 9999) { - lgInfo($"sendToMoonPro --> offline timeaout ({lastIobOnline}) --> pzCntReload(true)"); - pzCntReload(true); + counterFLog = 0; } - // se richiesto effettuo refresh contapezzi - if (needRefreshPzCount && !isMulti) - { - pzCntReload(true); - needRefreshPzCount = false; - } - lastIobOnline = DateTime.Now; - // se "OK" verde, altrimenti errore --> ROSSO - if (answ == "OK") - { - currDispData.semOut = Semaforo.SV; - } - else - { - currDispData.semOut = Semaforo.SR; - } - } - else - { - lgInfo(string.Format("[SERVER KO] {0}", queueVal)); - } } - else + /// + /// Accumula in coda i valori ALARM e logga... + /// + /// VALORE RAW (x display) + /// VALORE già processato con qEncodeFLog(...) + public void accodaAlarmLog(string val, string encodedVal) { - currDispData.semOut = Semaforo.SV; - // loggo! - lgInfo(string.Format("{0} -> [SIM]", queueVal)); + // mostro dati variati letti... + displayOtherData(val); + // accodo IN PRIMIS al FluxLog --> accodo (valore già formattato)! + QueueFLog.Enqueue(encodedVal); + // accodo ANCHE alla coda allarmi che trasmetterò SOLO SE a scadenza impostata (10 sec?) ho allarmi perdurati... + + // loggo! + lgInfo(string.Format("[QUEUE-ALARM-LOG] {0}", encodedVal)); + counterFLog++; + if (counterFLog > 9999) + { + counterFLog = 0; + } } - nSendOut++; - // riporto cosa inviato + /// + /// Invia una LISTA di valori + /// + /// + /// + public void sendDataBlock(urlType tipoUrl, List listQueueVal) + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + if (listQueueVal != null) + { + try + { + // recupero e formatto URL dati da coda... + lastUrl = urlDataBlock(tipoUrl); + // in base al tipo di dato compongo il payload Json da inviare + string payload = jsonPayload(tipoUrl, listQueueVal); + // async a true SE FLog + bool doAsync = tipoUrl == urlType.FLog ? true : false; + // se NON sono in demo effettuo invio! + if (!DemoOut) + { + // SE server alive... + if (checkServerAlive) + { + // chiamo URL! + string answ = callUrlWithPayload(lastUrl, payload, doAsync); + // loggo! + lgInfo($"[SEND payload] TipoURL: {tipoUrl} | {listQueueVal.Count} records --> {answ}"); + // se "OK" verde, altrimenti errore --> ROSSO + if (answ.Contains("OK")) + { + currDispData.semOut = Semaforo.SV; + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) + { + lgInfo($"sendDataBlock --> offline timeout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); + } + lastIobOnline = DateTime.Now; + } + else + { + currDispData.semOut = Semaforo.SR; + } + } + else + { + lgInfo($"[SERVER KO] {listQueueVal.Count}"); + } + } + else + { + currDispData.semOut = Semaforo.SV; + // loggo! + lgInfo($"{listQueueVal.Count} records --> [SIM]"); + } + nSendOut += listQueueVal.Count; + // riporto cosa inviato + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; + } + catch + { + currDispData.semOut = Semaforo.SR; + } + } + raiseRefresh(currDispData); + } + /// + /// Effettua invio a MoonPro del valore richiesto + /// + /// + /// Valore da trasmettere: es + /// INPUT: lo status rilevato in HEX + /// FLog: il valore da trasmettere per il flusso indicato + public void sendToMoonPro(urlType tipoUrl, string queueVal) + { + // init obj display + newDisplayData currDispData = new newDisplayData(); + try + { + // recupero e formatto URL dati da coda... + switch (tipoUrl) + { + case urlType.FLog: + lastUrl = urlFLog(queueVal); + break; + case urlType.SignIN: + lastUrl = urlInput(queueVal); + break; + default: + lastUrl = ""; + break; + } + // se NON sono in demo effettuo invio! + if (!DemoOut) + { + // SE server alive... + if (checkServerAlive) + { + // chiamo URL! + string answ = callUrl(lastUrl, false); + // loggo! + lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ)); + // se oltre 1 min NON era online --> check pezzi! + if (DateTime.Now.Subtract(lastIobOnline).TotalMinutes > 1 && !isMulti) + { + lgInfo($"sendToMoonPro --> offline timeaout ({lastIobOnline}) --> pzCntReload(true)"); + pzCntReload(true); + } + // se richiesto effettuo refresh contapezzi + if (needRefreshPzCount && !isMulti) + { + pzCntReload(true); + needRefreshPzCount = false; + } + lastIobOnline = DateTime.Now; + // se "OK" verde, altrimenti errore --> ROSSO + if (answ == "OK") + { + currDispData.semOut = Semaforo.SV; + } + else + { + currDispData.semOut = Semaforo.SR; + } + } + else + { + lgInfo(string.Format("[SERVER KO] {0}", queueVal)); + } + } + else + { + currDispData.semOut = Semaforo.SV; + // loggo! + lgInfo(string.Format("{0} -> [SIM]", queueVal)); + } + nSendOut++; + // riporto cosa inviato #if false displayOutData(); -#endif - currDispData.newUrlCallData = lastUrl; - // aggiorno data ultimo watchdog... - lastWatchDog = DateTime.Now; - } - catch - { - currDispData.semOut = Semaforo.SR; - } - raiseRefresh(currDispData); - } +#endif + currDispData.newUrlCallData = lastUrl; + // aggiorno data ultimo watchdog... + lastWatchDog = DateTime.Now; + } + catch + { + currDispData.semOut = Semaforo.SR; + } + raiseRefresh(currDispData); + } - #endregion + #endregion - #region gestione dataMonitor (update visualizzazione valori) + #region gestione dataMonitor (update visualizzazione valori) - /// - /// Mostra i dati grezzi letti in esadecimale - /// Parametri da aggiornare x display in form - /// - private void displayRawData(ref newDisplayData currDispData) - { - // mostro update... - string newString = string.Format("{0:X}", B_input); - currDispData.newInData = newString; -#if false - // salvo coda debug... - QueueDebug.Enqueue(B_input); -#endif - } - /// - /// Update visualizzaizone BIT in ingresso - /// Parametri da aggiornare x display in form - /// - public void displayInData(ref newDisplayData currDispData) - { - // mostro update... - string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8)); - currDispData.newSignalData = newString; -#if false - accodaSignaInlData(newString); -#endif - } - /// - /// Mostra cosa ha/avrebbe inviato - /// - /// - public void displayOtherData(string newData) - { - // mostro update... - accodaOtherData(newData); - } - /// - /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA - /// - /// - public void accodaOtherData(string newLine) - { - // inserisco in cima allo stack, trimmo e aggiorno display - string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3)); - //parentForm.dataMonitor_3 = strOtherData; - parentForm.WriteTextSafe(strOtherData); - } - /// - /// Effettua un trim della stringa al numero max di linee da mostrare a video - /// - /// - /// - public string limitLine2show(string newString) - { - // se num righe superiore a limite trimmo... - if (newString.Split('\n').Length > parentForm.nLine2show) - { - //int idx = newString.LastIndexOf('\r'); - int idx = newString.LastIndexOf(Environment.NewLine); - newString = newString.Substring(0, idx); - } - return newString; - } + /// + /// Mostra i dati grezzi letti in esadecimale + /// Parametri da aggiornare x display in form + /// + private void displayRawData(ref newDisplayData currDispData) + { + // mostro update... + string newString = string.Format("{0:X}", B_input); + currDispData.newInData = newString; +#if false + // salvo coda debug... + QueueDebug.Enqueue(B_input); +#endif + } + /// + /// Update visualizzaizone BIT in ingresso + /// Parametri da aggiornare x display in form + /// + public void displayInData(ref newDisplayData currDispData) + { + if (currDispData != null) + { + // mostro update... + string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8)); + currDispData.newSignalData = newString; + } + } + /// + /// Mostra cosa ha/avrebbe inviato + /// + /// + public void displayOtherData(string newData) + { + // mostro update... + accodaOtherData(newData); + } + /// + /// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA + /// + /// + public void accodaOtherData(string newLine) + { + // inserisco in cima allo stack, trimmo e aggiorno display + string strOtherData = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3)); + //parentForm.dataMonitor_3 = strOtherData; + parentForm.WriteTextSafe(strOtherData); + } + /// + /// Effettua un trim della stringa al numero max di linee da mostrare a video + /// + /// + /// + public string limitLine2show(string newString) + { + // se num righe superiore a limite trimmo... + if (newString.Split('\n').Length > parentForm.nLine2show) + { + //int idx = newString.LastIndexOf('\r'); + int idx = newString.LastIndexOf(Environment.NewLine); + newString = newString.Substring(0, idx); + } + return newString; + } - #endregion + #endregion - } -} + } +} diff --git a/IOB-WIN/IobOSAI.cs b/IOB-WIN/IobOSAI.cs index 3d4ec93d..5e6561c8 100644 --- a/IOB-WIN/IobOSAI.cs +++ b/IOB-WIN/IobOSAI.cs @@ -583,7 +583,7 @@ namespace IOB_WIN /// /// /// - protected CNC_MODE decodeModeOsai(int mode) + protected static CNC_MODE decodeModeOsai(int mode) { CNC_MODE answ = CNC_MODE.ND; switch (mode) diff --git a/IOB-WIN/IobSiemens.cs b/IOB-WIN/IobSiemens.cs index ab49b901..3a07f542 100644 --- a/IOB-WIN/IobSiemens.cs +++ b/IOB-WIN/IobSiemens.cs @@ -10,1487 +10,1545 @@ using System.Net.NetworkInformation; namespace IOB_WIN { - public class IobSiemens : IobGeneric, IDisposable - { - /* -------------------------------------------------------------------------------- - * Controlli SIEMENS tramite libreria S7.net - * - basasto su SIEMENS - * - S7 testato vers 300 e 1200 - * - attenzione conf rack/slot x varie serie controlli - * - necessità apertura metodi pu/get - * - * -------------------------------------------------------------------------------- */ + public class IobSiemens : IobGeneric, IDisposable + { + /* -------------------------------------------------------------------------------- + * Controlli SIEMENS tramite libreria S7.net + * - basasto su SIEMENS + * - S7 testato vers 300 e 1200 + * - attenzione conf rack/slot x varie serie controlli + * - necessità apertura metodi pu/get + * + * -------------------------------------------------------------------------------- */ - #region area componenti base + #region area componenti base - /// - /// Byte dimensione buffer dati memoria (da file map) - /// - public int numByte = 0; - /// - /// Lungh massima stringhe - /// - protected int maxStrChar = 20; - /// - /// indica se scrivere i primi byte x string siemens x indicare lung max e corrente - /// - protected bool writePre = true; - /// - /// Oggetto PLC da ri-utilizzare... - /// - protected Plc currPLC; - /// - /// Oggetto cronometro x test vari... - /// - protected Stopwatch sw = new Stopwatch(); - /// - /// parametri di connessione - /// - protected connParamS7 parametri; + /// + /// Byte dimensione buffer dati memoria (da file map) + /// + public int numByte = 0; + /// + /// Lungh massima stringhe + /// + protected int maxStrChar = 20; + /// + /// indica se scrivere i primi byte x string siemens x indicare lung max e corrente + /// + protected bool writePre = true; + /// + /// Oggetto PLC da ri-utilizzare... + /// + protected Plc currPLC; + /// + /// Oggetto cronometro x test vari... + /// + protected Stopwatch sw = new Stopwatch(); + /// + /// parametri di connessione + /// + protected connParamS7 parametri; - #endregion + #endregion - #region area metodi lettura/Scrittura + #region area metodi lettura/Scrittura - /// - /// Dizionario delel ultime operazioni dis crittura per OGNI memoria (in modo che fa log ogni x sec...) - /// - protected Dictionary lastMemWrite { get; set; } = new Dictionary(); + /// + /// Dizionario delel ultime operazioni dis crittura per OGNI memoria (in modo che fa log ogni x sec...) + /// + protected Dictionary lastMemWrite { get; set; } = new Dictionary(); - /// - /// Inserimento/aggiornamento chiavi/valore in currProdData - /// - /// - /// - public void upsertKey(string chiave, string valore) - { - if (currProdData.ContainsKey(chiave)) - { - currProdData[chiave] = valore; - } - else - { - currProdData.Add(chiave, valore); - } - } - /// - /// Converte direttamente un valore stringa su un oggetto byte[] (senza limitazioni di dimensione) - /// - /// - /// Dimensione massima ammessa per la stringa - /// - public byte[] stringToByte(string valore, int maxLenght) - { - byte[] answ = new byte[1]; - byte[] stringPar = new byte[2]; - byte[] strByte = S7.Net.Types.String.ToByteArray(valore); - int shiftStrByte = writePre ? 2 : 0; - int byteLen = strByte.Length <= maxLenght ? strByte.Length : maxLenght; - if (writePre) - { - // MAX LUN - stringPar[1] = (byte)maxLenght; - // LUNGH STRING - stringPar[0] = (byte)byteLen; - Buffer.BlockCopy(stringPar, 0, answ, 0, shiftStrByte); - } - Buffer.BlockCopy(strByte, 0, answ, shiftStrByte, byteLen); - return answ; - } - /// - /// Converte direttamente un valore Short su un oggetto byte[2] - /// - /// valore da scrivere - public byte[] intToByte(string valore) - { - byte[] answ = new byte[2]; - try - { - short valInt = 0; - short.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt); - int byteLen = 2; - Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}"); - } - return answ; - } - /// - /// Converte direttamente un valore Int su un oggetto byte[4] - /// - /// valore da scrivere - public byte[] dintToByte(string valore) - { - byte[] answ = new byte[4]; - try - { - int valInt = 0; - int.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}"); - } - return answ; - } - /// - /// Converte direttamente un valore UInt16 su un oggetto byte[2] - /// - /// valore da scrivere - public byte[] wordToByte(string valore) - { - byte[] answ = new byte[2]; - try - { - ushort valInt = 0; - ushort.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.Word.ToByteArray(valInt); - int byteLen = 2; - Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}"); - } - return answ; - } - /// - /// Converte direttamente un valore UInt32 su un oggetto byte[4] - /// - /// valore da scrivere - public byte[] dwordToByte(string valore) - { - byte[] answ = new byte[4]; - try - { - ushort valInt = 0; - ushort.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.DWord.ToByteArray(valInt); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}"); - } - return answ; - } - - /// - /// Salvo in memblock il valore stringa indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2) - /// valore da scrivere - public void saveStringOnMemBlock(ref byte[] MemBlock, int startPos, int totLen, string valore) - { - if (MemBlock != null) - { - // loggare valore? fornire un output con memBlock e NON ref? - try + /// + /// Inserimento/aggiornamento chiavi/valore in currProdData + /// + /// + /// + public void upsertKey(string chiave, string valore) { - lgInfo($"saveStringOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | totLen: {totLen} | valore: {valore}"); - byte[] stringPar = new byte[2]; - byte[] strByte = S7.Net.Types.String.ToByteArray(valore); - int byteLen = strByte.Length <= totLen ? strByte.Length : totLen; - int shiftStrByte = writePre ? 2 : 0; - if (writePre) - { - // MAX LUN - stringPar[1] = (byte)totLen; - // LUNGH STRING - stringPar[0] = (byte)byteLen; - Buffer.BlockCopy(stringPar, 0, MemBlock, startPos, shiftStrByte); - } - Buffer.BlockCopy(strByte, 0, MemBlock, startPos + shiftStrByte, byteLen); + if (currProdData.ContainsKey(chiave)) + { + currProdData[chiave] = valore; + } + else + { + currProdData.Add(chiave, valore); + } } - catch (Exception exc) + /// + /// Converte direttamente un valore stringa su un oggetto byte[] (senza limitazioni di dimensione) + /// + /// + /// Dimensione massima ammessa per la stringa + /// + public byte[] stringToByte(string valore, int maxLenght) { - lgError($"Errore in gestione scrittura {valore} alla posizione {startPos} per {totLen} byte{Environment.NewLine}{exc}"); + byte[] answ = new byte[1]; + byte[] stringPar = new byte[2]; + byte[] strByte = S7.Net.Types.String.ToByteArray(valore); + int shiftStrByte = writePre ? 2 : 0; + int byteLen = strByte.Length <= maxLenght ? strByte.Length : maxLenght; + if (writePre) + { + // MAX LUN + stringPar[1] = (byte)maxLenght; + // LUNGH STRING + stringPar[0] = (byte)byteLen; + Buffer.BlockCopy(stringPar, 0, answ, 0, shiftStrByte); + } + Buffer.BlockCopy(strByte, 0, answ, shiftStrByte, byteLen); + return answ; } - } - else - { - lgError("Errore: MemBlock nullo"); - } - } - /// - /// Salvo in memblock il valore stringa indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Nome del parametro da recuperare da prodData x scrivere - /// Posizione inizio scrittura - /// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2) - public void saveStringOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos, int totLen) - { - if (currProdData.ContainsKey(stringKey)) - { - try + /// + /// Converte direttamente un valore Short su un oggetto byte[2] + /// + /// valore da scrivere + public byte[] intToByte(string valore) { - string valore = currProdData[stringKey]; - saveStringOnMemBlock(ref MemBlock, startPos, totLen, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura x key {stringKey}{Environment.NewLine}{exc}"); - } - } - } - - /// - /// Salvo in memblock il valore Int indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// valore da scrivere - public void saveIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore) - { - try - { - short valInt = 0; - short.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt); - int byteLen = 2; - Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); - //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura INT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); - } - } - /// - /// Salvo in memblock il valore Int indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Nome del parametro da recuperare da prodData x scrivere - /// Posizione inizio scrittura - public void saveIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) - { - if (currProdData.ContainsKey(stringKey)) - { - try - { - string valore = currProdData[stringKey]; - saveIntOnMemBlock(ref MemBlock, startPos, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura INT {stringKey}{Environment.NewLine}{exc}"); - } - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// Valore da scrivere - public void saveDIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore) - { - try - { - int valInt = 0; - int.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); - //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Valore da scrivere - /// Posizione inizio scrittura - public void saveDIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) - { - if (currProdData.ContainsKey(stringKey)) - { - try - { - string valore = currProdData[stringKey]; - saveDIntOnMemBlock(ref MemBlock, startPos, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); - } - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// Valore da scrivere - public void saveWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore) - { - try - { - byte[] stringPar = new byte[4]; - int valInt = 0; - int.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); - //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura Word {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Valore da scrivere - /// Posizione inizio scrittura - public void saveWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) - { - if (currProdData.ContainsKey(stringKey)) - { - try - { - string valore = currProdData[stringKey]; - saveDIntOnMemBlock(ref MemBlock, startPos, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); - } - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// Valore da scrivere - public void saveDWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore) - { - try - { - byte[] stringPar = new byte[4]; - int valInt = 0; - int.TryParse(valore, out valInt); - byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); - //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DWord {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); - } - } - /// - /// Salvo in memblock il valore DInt indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Valore da scrivere - /// Posizione inizio scrittura - public void saveDWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) - { - if (currProdData.ContainsKey(stringKey)) - { - try - { - string valore = currProdData[stringKey]; - saveDIntOnMemBlock(ref MemBlock, startPos, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); - } - } - } - /// - /// Salvo in memblock il valore stringa indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Posizione inizio scrittura - /// Valore scrivere - public void saveRealOnMemBlock(ref byte[] MemBlock, int startPos, string valore) - { - try - { - byte[] stringPar = new byte[2]; - - double valReal = 0; - double.TryParse(valore, out valReal); - byte[] strByte = S7.Net.Types.Double.ToByteArray(valReal); - int byteLen = 4; - Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); - //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura REAL {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); - } - } - /// - /// Salvo in memblock il valore stringa indicato con formattazione siemens - /// - /// Blocco memoria come byte[] dove scrivere - /// Valore scrivere - /// Posizione inizio scrittura - public void saveRealOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) - { - if (currProdData.ContainsKey(stringKey)) - { - try - { - string valore = currProdData[stringKey]; - saveRealOnMemBlock(ref MemBlock, startPos, valore); - } - catch (Exception exc) - { - lgError($"Errore in gestione scrittura REAL {stringKey}{Environment.NewLine}{exc}"); - } - } - } - - /// - /// wrapper chiamata LETTURA in blocco MULTI BYTE dell'area read DI DEFAULT... - /// - /// - /// - public bool S7ReadBB(ref byte[] Value) - { - return S7ReadBB(ref Value, parametri.memAddrRead, parametri.memSizeRead); - } - /// - /// wrapper chiamata LETTURA in blocco MULTI BYTE... - /// - /// MATRICE valori letti - /// Area memoria da leggere... - /// Numero byte da leggere - /// - public bool S7ReadBB(ref byte[] Value, string memAddrRead, int numByte) - { - bool answ = false; - if (Value != null) - { - sw.Restart(); - parentForm.commPlcActive = true; - if (testCncConn()) - { - // decodifico memoria... - memAreaSiemens memoria = new memAreaSiemens(memAddrRead); - Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); - // copio in value, sennò do errore... - if (memByteRead.Length == Value.Length) - { - Value = memByteRead; - } - else - { - lgError($"Mismatch dimensione array memoria: indirizzo: {memAddrRead} | passato array di {Value.Length} byte, letti da S7 {memByteRead.Length} byte"); - } - string titolo = $"READ BLOCK MEM BYTE: {parametri.memAddrRead} --> {numByte} byte"; - if (verboseLog) - { - lgInfo(titolo); - } - - string contenuto = $"Contenuto area memoria acquisita{Environment.NewLine}"; - string byteVal = ""; - for (int i = 0; i < memByteRead.Length; i++) - { - byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); - contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); - } - // loggo lettura... - if (verboseLog) - { - lgInfo(contenuto); - } - } - else - { - connectionOk = false; - } - parentForm.commPlcActive = false; - sw.Stop(); - if (utils.CRB("recTime")) - { - TimingData.addResult(cIobConf.codIOB, string.Format("{0}|{1}", parametri.memAddrRead, numByte), sw.ElapsedTicks); - } - } - return answ; - }/// - /// wrapper chiamata LETTURA in blocco MULTI BYTE... default size a parametri.memSizeRead - /// - /// - /// Area memoria da leggere... - /// - public bool S7ReadBB(ref byte[] Value, string memAddrRead) - { - bool answ = false; - answ = S7ReadBB(ref Value, memAddrRead, parametri.memSizeRead); - return answ; - } - /// - /// wrapper chiamata SCRITTURA in blocco MULTI BYTE, DI DEFAUTL su area configurata x scrittura CONTINUA... - /// - /// - /// - public bool S7WriteBB(ref byte[] Value) - { - return S7WriteBB(ref Value, parametri.memAddrWrite); - } - /// - /// Override scrittura in area DBB - /// - /// - /// - /// - public bool S7WriteBB(ref byte[] Value, string memAddrWrite) - { - bool answ = false; - if (Value == null) - { - lgError($"Errore in S7WriteBB: Value è null"); - } - else - { - if (string.IsNullOrEmpty(memAddrWrite)) - { - lgError($"Errore in S7WriteBB: memAddrWrite è vuoto"); - } - else - { - sw.Restart(); - if (testCncConn()) - { + byte[] answ = new byte[2]; try { - // decodifico memoria... - memAreaSiemens memoria = new memAreaSiemens(memAddrWrite); - int numByte = Value.Length; - ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, Value); - switch (errorCode) - { - case ErrorCode.NoError: - maybeLogWrite(memAddrWrite, $"Effettuata correttamente scrittura su PLC: MEMORIA {memAddrWrite} | numByte: {Value.Length} | BIN: {Value.ValToBinString()}"); - answ = true; - break; - case ErrorCode.WrongCPU_Type: - case ErrorCode.ConnectionError: - case ErrorCode.IPAddressNotAvailable: - case ErrorCode.WrongVarFormat: - case ErrorCode.WrongNumberReceivedBytes: - case ErrorCode.SendData: - case ErrorCode.ReadData: - case ErrorCode.WriteData: - lgError($"Errore in S7WriteBB su {memAddrWrite}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); - answ = false; - break; - default: - break; - } + short valInt = 0; + short.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt); + int byteLen = 2; + Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); } catch (Exception exc) { - lgError($"Eccezione in S7WriteBB | memAddrWrite {memAddrWrite} | numByte: {Value.Length}{Environment.NewLine}{exc}"); + lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}"); } - } - sw.Stop(); + return answ; } - } - return answ; - } - /// - /// Verifica SE sia il caso di fare il log della memoria indicata - /// - /// - /// - private void maybeLogWrite(string memAddrWrite, string logValue) - { - bool doWrite = true; - DateTime adesso = DateTime.Now; - if (!lastMemWrite.ContainsKey(memAddrWrite)) - { - lastMemWrite.Add(memAddrWrite, adesso.AddMinutes(-1)); - } - // ora mi leggo valore ultimas crittura e confronto con adesso - try - { - doWrite = (lastMemWrite[memAddrWrite].AddSeconds(vetoSeconds) < adesso); - } - catch (Exception exc) - { - lgError($"Eccezione in maybeLogWrite{Environment.NewLine}{exc}"); - } - // se encessario --> LOG! - if (doWrite) - { - lgInfo(logValue); - lastMemWrite[memAddrWrite] = adesso; - } - } - - /// - /// Override scrittura in area DBB - /// - /// Valore byte[] da scrivere - /// Numero del DB (es 700 per DB700) - /// Indice interno al datablock del byte da cui partire - /// - public bool S7WriteBB(ref byte[] Value, int DbNum, int IndiceMem) - { - bool answ = false; - if (Value == null) - { - lgError($"Errore in S7WriteBB: Value è null"); - } - else - { - if (DbNum < 0 || IndiceMem < 0) + /// + /// Converte direttamente un valore Int su un oggetto byte[4] + /// + /// valore da scrivere + public byte[] dintToByte(string valore) { - lgError($"Errore in S7WriteBB | DbNum: {DbNum} | IndiceMem: {IndiceMem}"); - } - else - { - sw.Restart(); - if (testCncConn()) - { + byte[] answ = new byte[4]; try { - int numByte = Value.Length; - ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, DbNum, IndiceMem, Value); - switch (errorCode) - { - case ErrorCode.NoError: - lgInfo($"Effettuata correttamente scrittura su PLC: DB {DbNum}.{IndiceMem} | numByte: {Value.Length}| {Value.ValToBinString()}"); - break; - case ErrorCode.WrongCPU_Type: - case ErrorCode.ConnectionError: - case ErrorCode.IPAddressNotAvailable: - case ErrorCode.WrongVarFormat: - case ErrorCode.WrongNumberReceivedBytes: - case ErrorCode.SendData: - case ErrorCode.ReadData: - case ErrorCode.WriteData: - lgError($"Errore in S7WriteBB su DB {DbNum}.{IndiceMem}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); - break; - default: - break; - } - answ = true; + int valInt = 0; + int.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); } catch (Exception exc) { - lgError($"Eccezione in S7WriteBB: DbNum {DbNum}, IndiceMem: {IndiceMem}, numByte: {Value.Length}{Environment.NewLine}{exc}"); + lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}"); } - } - sw.Stop(); + return answ; } - } - return answ; - } - - - - #endregion - - #region area principale adapter - - /// - /// Classe base con i metodi x Siemens - /// - /// - /// - public IobSiemens(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) - { - memMap = new plcMemMap(); - writePre = true; - if (IOBConf != null) - { - // gestione invio ritardato contapezzi - pzCountDelay = utils.CRI("pzCountDelay"); - lastPzCountSend = DateTime.Now; - lastWarnODL = DateTime.Now; - // inizializzo parametri... - parametri = new connParamS7() + /// + /// Converte direttamente un valore UInt16 su un oggetto byte[2] + /// + /// valore da scrivere + public byte[] wordToByte(string valore) { - ipAdrr = "127.0.0.1", - tipoCpu = CpuType.S7200, - slot = 0, - rack = 0, - pingMsTimeout = IOBConf.pingMsTimeout, - memAddrRead = "DB1.DBB0", - memAddrWrite = "DB2.DBB0", - memSizeRead = 0, - memSizeWrite = 0 - }; - setParamPlc(); - - // salvo info su conf IOB... - string iobConfSer = ""; - try - { - iobConfSer = JsonConvert.SerializeObject(IOBConf); - } - catch - { } - // finito! - lgInfo($"Init IOB, con {iobConfSer}"); - } - else - { - lgError("Impossibile avviare, IOBConf nullo/non valido!"); - } - } - - /// - /// Test connessione CNC - /// - /// - protected bool testCncConn() - { - bool answ = false; - - IPStatus pingStatus = testPingMachine; - // se passa il ping faccio il resto... - if (pingStatus != IPStatus.Success) - { - lgError(string.Format("Errore in testCncConn: reply Status per {0}: {1}", parametri.ipAdrr, pingStatus)); - } - else - { - if (!currPLC.IsConnected) - { - currPLC.Open(); - } - - if (!currPLC.IsAvailable) - { - lgError(string.Format("PLC Siemens NON disponibile:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString)); - currPLC.ClearLastError(); - } - else - { - if (!currPLC.IsConnected && !pingDisabled) - { - lgError(string.Format("PLC Siemens NON connesso:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString)); - currPLC.ClearLastError(); - parentForm.updateComStats("NO connection"); - } - else - { - parentForm.updateComStats("Connection OK"); - answ = true; - } - } - } - - return answ; - } - /// - /// Imposto parametri PLC - /// - protected override void setParamPlc() - { - // Creo oggetto connessione NC - parentForm.commPlcActive = true; - lgInfo("Start init Adapter SIEMENS all'IP {0} | CPU: {1} | R/S: {2}/{3} | --> IOB {4}", cIobConf.cncIpAddr, cIobConf.cpuType, cIobConf.rack, cIobConf.slot, cIobConf.codIOB); - // SE è necessario refresh... - if (needRefresh) - { - lgInfo("Refreshing connection..."); - if (parametri != null) - { - try - { - parametri.slot = cIobConf.slot; - parametri.rack = cIobConf.rack; - parametri.tipoCpu = (CpuType)Enum.Parse(typeof(CpuType), cIobConf.cpuType); - parametri.ipAdrr = cIobConf.cncIpAddr; - // leggo file init... - lgInfo("Reading ini file..."); - IniFile fIni = new IniFile(cIobConf.iniFileName); - // ora leggo valori speciali - parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", ""); - parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", ""); - parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0); - parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0); - // salvo vettori memoria... - lgInfo("Set RawInput dimensions..."); - RawInput = new byte[parametri.memSizeRead]; - RawOutput = new byte[parametri.memSizeWrite]; - // salvo parametri conn! - lgInfo(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite)); - } - catch (Exception exc) - { - lgError(exc, "Errore in parse parametri da IOBConf"); - } - // ora tento avvio PLC... SE PING OK... - IPStatus esitoPing = testPingMachine; - if (esitoPing == IPStatus.Success) - { - needRefresh = false; + byte[] answ = new byte[2]; try { - currPLC = new Plc(parametri.tipoCpu, parametri.ipAdrr, parametri.rack, parametri.slot); - // disconnetto e connetto... - if (isVerboseLog) - { - lgInfo("SIEMENS: tryDisconnect"); - } - - tryDisconnect(); - // lo ripeto x evitare che ci sia un loop... e tryConnect richiami la procedura corrente... - needRefresh = false; - lgInfo("SIEMENS: tryConnect"); - tryConnect(); - lgInfo("End init Adapter SIEMENS"); - if (isVerboseLog) - { - lgInfo("S7+ CONNESSIONE AVVENUTA"); - } + ushort valInt = 0; + ushort.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.Word.ToByteArray(valInt); + int byteLen = 2; + Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); } catch (Exception exc) { - lgError(exc, "Errore in INIT PLC S7+"); + lgError($"Errore in gestione scrittura INT {valore} in byte{Environment.NewLine}{exc}"); } - } - else - { - lgError($"Errore in ping: esito {esitoPing}"); - } - parentForm.commPlcActive = false; - // carico conf vettore memoria... - loadMemConf(); - - bool enableByApp = utils.CRB("enableContapezzi"); - bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE"); - bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE"); - if ((enableByApp || enableByIob) && !(disableByIob)) - { - lgInfo("SIEMENS: inizio gestione contapezzi"); + return answ; + } + /// + /// Converte direttamente un valore UInt32 su un oggetto byte[4] + /// + /// valore da scrivere + public byte[] dwordToByte(string valore) + { + byte[] answ = new byte[4]; try { - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE"))) - { - if (getOptPar("PZCOUNT_MODE").StartsWith("STD")) + ushort valInt = 0; + ushort.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.DWord.ToByteArray(valInt); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, answ, 0, byteLen); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DINT {valore} in byte{Environment.NewLine}{exc}"); + } + return answ; + } + + /// + /// Salvo in memblock il valore stringa indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2) + /// valore da scrivere + public void saveStringOnMemBlock(ref byte[] MemBlock, int startPos, int totLen, string valore) + { + if (MemBlock != null) + { + // loggare valore? fornire un output con memBlock e NON ref? + try { - lgInfo("Init contapezzi SIEMENS: pzCntReload(true)"); - pzCntReload(true); - // refresh associazione Macchina - IOB - sendM2IOB(); - // per adesso imposto lettura fanuc == contapezzi (poi farà vera lettura...) - lastCountCNC = contapezzi; + lgInfo($"saveStringOnMemBlock: MemBlock size: {MemBlock.Length} | startPos: {startPos} | totLen: {totLen} | valore: {valore}"); + byte[] stringPar = new byte[2]; + byte[] strByte = S7.Net.Types.String.ToByteArray(valore); + int byteLen = strByte.Length <= totLen ? strByte.Length : totLen; + int shiftStrByte = writePre ? 2 : 0; + if (writePre) + { + // MAX LUN + stringPar[1] = (byte)totLen; + // LUNGH STRING + stringPar[0] = (byte)byteLen; + Buffer.BlockCopy(stringPar, 0, MemBlock, startPos, shiftStrByte); + } + Buffer.BlockCopy(strByte, 0, MemBlock, startPos + shiftStrByte, byteLen); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura {valore} alla posizione {startPos} per {totLen} byte{Environment.NewLine}{exc}"); + } + } + else + { + lgError("Errore: MemBlock nullo"); + } + } + /// + /// Salvo in memblock il valore stringa indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Nome del parametro da recuperare da prodData x scrivere + /// Posizione inizio scrittura + /// Lunghezza max stringa (se ci sono 2 byte iniziali verrà ridotta di 2) + public void saveStringOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos, int totLen) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveStringOnMemBlock(ref MemBlock, startPos, totLen, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura x key {stringKey}{Environment.NewLine}{exc}"); + } + } + } + + /// + /// Salvo in memblock il valore Int indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// valore da scrivere + public void saveIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + short valInt = 0; + short.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt); + int byteLen = 2; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura INT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + /// + /// Salvo in memblock il valore Int indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Nome del parametro da recuperare da prodData x scrivere + /// Posizione inizio scrittura + public void saveIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveIntOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura INT {stringKey}{Environment.NewLine}{exc}"); + } + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Valore da scrivere + public void saveDIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + int valInt = 0; + int.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DINT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Valore da scrivere + /// Posizione inizio scrittura + public void saveDIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveDIntOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); + } + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Valore da scrivere + public void saveWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + byte[] stringPar = new byte[4]; + int valInt = 0; + int.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura Word {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Valore da scrivere + /// Posizione inizio scrittura + public void saveWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveDIntOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); + } + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Valore da scrivere + public void saveDWordOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + byte[] stringPar = new byte[4]; + int valInt = 0; + int.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.DInt.ToByteArray(valInt); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DWord {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + /// + /// Salvo in memblock il valore DInt indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Valore da scrivere + /// Posizione inizio scrittura + public void saveDWordOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveDIntOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura DINT {stringKey}{Environment.NewLine}{exc}"); + } + } + } + /// + /// Salvo in memblock il valore stringa indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Valore scrivere + public void saveRealOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + byte[] stringPar = new byte[2]; + + double valReal = 0; + double.TryParse(valore, out valReal); + byte[] strByte = S7.Net.Types.Double.ToByteArray(valReal); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura REAL {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + /// + /// Salvo in memblock il valore stringa indicato con formattazione siemens + /// + /// Blocco memoria come byte[] dove scrivere + /// Valore scrivere + /// Posizione inizio scrittura + public void saveRealOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveRealOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura REAL {stringKey}{Environment.NewLine}{exc}"); + } + } + } + + /// + /// wrapper chiamata LETTURA in blocco MULTI BYTE dell'area read DI DEFAULT... + /// + /// + /// + public bool S7ReadBB(ref byte[] Value) + { + return S7ReadBB(ref Value, parametri.memAddrRead, parametri.memSizeRead); + } + /// + /// wrapper chiamata LETTURA in blocco MULTI BYTE... + /// + /// MATRICE valori letti + /// Area memoria da leggere... + /// Numero byte da leggere + /// + public bool S7ReadBB(ref byte[] Value, string memAddrRead, int numByte) + { + bool answ = false; + if (Value != null) + { + sw.Restart(); + parentForm.commPlcActive = true; + if (testCncConn()) + { + // decodifico memoria... + memAreaSiemens memoria = new memAreaSiemens(memAddrRead); + Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + // copio in value, sennò do errore... + if (memByteRead.Length == Value.Length) + { + Value = memByteRead; + } + else + { + lgError($"Mismatch dimensione array memoria: indirizzo: {memAddrRead} | passato array di {Value.Length} byte, letti da S7 {memByteRead.Length} byte"); + } + string titolo = $"READ BLOCK MEM BYTE: {parametri.memAddrRead} --> {numByte} byte"; + if (verboseLog) + { + lgInfo(titolo); + } + + string contenuto = $"Contenuto area memoria acquisita{Environment.NewLine}"; + string byteVal = ""; + for (int i = 0; i < memByteRead.Length; i++) + { + byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); + } + // loggo lettura... + if (verboseLog) + { + lgInfo(contenuto); + } } else { - contapezzi = 0; - lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); + connectionOk = false; + } + parentForm.commPlcActive = false; + sw.Stop(); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("{0}|{1}", parametri.memAddrRead, numByte), sw.ElapsedTicks); } - } - else - { - contapezzi = 0; - lgInfo("Parametro mancante PZCOUNT_MODE"); - } } - catch (Exception exc) + return answ; + }/// + /// wrapper chiamata LETTURA in blocco MULTI BYTE... default size a parametri.memSizeRead + /// + /// + /// Area memoria da leggere... + /// + public bool S7ReadBB(ref byte[] Value, string memAddrRead) + { + bool answ = false; + answ = S7ReadBB(ref Value, memAddrRead, parametri.memSizeRead); + return answ; + } + /// + /// wrapper chiamata SCRITTURA in blocco MULTI BYTE, DI DEFAUTL su area configurata x scrittura CONTINUA... + /// + /// + /// + public bool S7WriteBB(ref byte[] Value) + { + return S7WriteBB(ref Value, parametri.memAddrWrite); + } + /// + /// Override scrittura in area DBB + /// + /// + /// + /// + public bool S7WriteBB(ref byte[] Value, string memAddrWrite) + { + bool answ = false; + if (Value == null) { - lgError(exc, "Errore in contapezzi SIEMENS"); + lgError($"Errore in S7WriteBB: Value è null"); } - } + else + { + if (string.IsNullOrEmpty(memAddrWrite)) + { + lgError($"Errore in S7WriteBB: memAddrWrite è vuoto"); + } + else + { + sw.Restart(); + if (testCncConn()) + { + try + { + // decodifico memoria... + memAreaSiemens memoria = new memAreaSiemens(memAddrWrite); + int numByte = Value.Length; + ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, Value); + switch (errorCode) + { + case ErrorCode.NoError: + maybeLogWrite(memAddrWrite, $"Effettuata correttamente scrittura su PLC: MEMORIA {memAddrWrite} | numByte: {Value.Length} | BIN: {Value.ValToBinString()}"); + answ = true; + break; + case ErrorCode.WrongCPU_Type: + case ErrorCode.ConnectionError: + case ErrorCode.IPAddressNotAvailable: + case ErrorCode.WrongVarFormat: + case ErrorCode.WrongNumberReceivedBytes: + case ErrorCode.SendData: + case ErrorCode.ReadData: + case ErrorCode.WriteData: + lgError($"Errore in S7WriteBB su {memAddrWrite}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); + answ = false; + break; + default: + break; + } + } + catch (Exception exc) + { + lgError($"Eccezione in S7WriteBB | memAddrWrite {memAddrWrite} | numByte: {Value.Length}{Environment.NewLine}{exc}"); + } + } + sw.Stop(); + } + } + return answ; } - else + /// + /// Verifica SE sia il caso di fare il log della memoria indicata + /// + /// + /// + private void maybeLogWrite(string memAddrWrite, string logValue) { - lgError("Parametri null!"); - } - } - } - /// - /// Override disconnessione - /// - public override void tryDisconnect() - { - if (connectionOk) - { - string szStatusConnection = ""; - try - { - currPLC.Close(); - connectionOk = false; - lgInfo(szStatusConnection); - lgInfo("Effettuata disconnessione adapter SIEMENS!"); - } - catch (Exception exc) - { - lgFatal(exc, "Errore nella disconnessione dall'adapter SIEMENS"); - } - } - else - { - lgError("IMPOSSIBILE effettuare disconnessione SIEMENS: Connessione non disponibile..."); - } - } - /// - /// Override connessione - /// - public override void tryConnect() - { - bool doLog = (verboseLog || periodicLog); - lgInfo("SIEMENS: tryConnect step 01"); - if (!connectionOk) - { - // SE è necessario refresh... - if (needRefresh) - { - lgInfo("SIEMENS: tryConnect step 02"); - - // reimporto parametri PLC se necessario... - setParamPlc(); - } - lgInfo("SIEMENS: tryConnect step 03"); - - // controllo che il ping sia stato tentato almeno pingTestSec fa... - if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) - { - if (doLog) - { - lgInfo("SIEMENS: ConnKO - tryConnect"); - } - lgInfo("SIEMENS: tryConnect step 04"); - - // in primis salvo data ping... - lastPING = DateTime.Now; - // se passa il ping faccio il resto... - if (testPingMachine == IPStatus.Success) - { - string szStatusConnection = ""; + bool doWrite = true; + DateTime adesso = DateTime.Now; + if (!lastMemWrite.ContainsKey(memAddrWrite)) + { + lastMemWrite.Add(memAddrWrite, adesso.AddMinutes(-1)); + } + // ora mi leggo valore ultimas crittura e confronto con adesso try { - // ora provo connessione... - parentForm.commPlcActive = true; - currPLC.Open(); - parentForm.commPlcActive = false; - lgInfo("szStatusConnection: " + szStatusConnection); - connectionOk = true; - // refresh stato allarmi!!! - if (connectionOk) - { - if (adpRunning) - { - lgInfo("Connessione OK"); - } - } - else - { - lgError("Impossibile procedere, connessione mancante..."); - } + doWrite = (lastMemWrite[memAddrWrite].AddSeconds(vetoSeconds) < adesso); } catch (Exception exc) { - lgFatal(string.Format("Errore in TryConnect adapter SIEMENS: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc)); - connectionOk = false; - needRefresh = true; + lgError($"Eccezione in maybeLogWrite{Environment.NewLine}{exc}"); } - } - else - { - // loggo no risposta ping ... - connectionOk = false; - if (doLog) + // se encessario --> LOG! + if (doWrite) { - lgInfo(string.Format("Attenzione: SIEMENS controllo PING fallito per IP {0}", cIobConf.cncIpAddr)); + lgInfo(logValue); + lastMemWrite[memAddrWrite] = adesso; } - } } - } - // se non è ancora connesso faccio procesisng memoria caso disconnesso... - if (!connectionOk) - { - // processo semafori ed invio... - processMemoryDiscon(); - } - } - /// - /// Restituisce path completo file da chiave configurazione - /// - /// chiave conf x file richiesto - /// - protected string filePath(string keyFile) - { - string answ = ""; - try - { - answ = $"{utils.confDir}\\{utils.CRS(keyFile)}"; - } - catch (Exception exc) - { - lgError(exc, "Eccezione in recupero filePath"); - } - return answ; - } - #endregion - - #region Metodi specifici (da verificare/completare in implementazione) - - /// - /// Effettua vero processing contapezzi - /// - public override void processContapezzi() - { - if (utils.CRB("enableContapezzi")) - { - try + /// + /// Override scrittura in area DBB + /// + /// Valore byte[] da scrivere + /// Numero del DB (es 700 per DB700) + /// Indice interno al datablock del byte da cui partire + /// + public bool S7WriteBB(ref byte[] Value, int DbNum, int IndiceMem) { - // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) - if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE"))) - { - string memAddr = getOptPar("PZCOUNT_MODE"); - if (memAddr.StartsWith("STD")) + bool answ = false; + if (Value == null) { - // inizio verifica area memoria/parametro levando prima parte codice - memAddr = memAddr.Replace("STD.", ""); - object outputVal = new object(); - // verifico se si tratta di lettura area DB... formato tipo STD.DB700.DBB22.W - if (memAddr.StartsWith("DB")) - { - memAreaSiemens areaCounter = new memAreaSiemens(memAddr); - - if (isVerboseLog) - { - lgInfo("[0] area memoria: {1}.{2}.{3}", memAddr, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem); - } - // copio da blocco già letto... con switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato - switch (areaCounter.tipoMem) - { - case "B": - byte valB = RawInput[areaCounter.indiceMem]; - outputVal = valB; - break; - case "W": - ushort valW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(2).ToArray()); - outputVal = valW; - break; - case "DW": - uint valDW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray()); - outputVal = valDW; - break; - case "RE": - double valRe = S7.Net.Types.Double.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray()); - outputVal = valRe; - break; - default: - break; - } - // salvo... - int newVal = -1; - Int32.TryParse(outputVal.ToString(), out newVal); - lastCountCNC = newVal > -1 ? newVal : lastCountCNC; - if (isVerboseLog) - { - lgInfo("[2] outputVal contapezzi: {0}", outputVal); - lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC); - } - } - stopwatch.Stop(); - } - } - } - catch (Exception exc) - { - lgError(exc, "Errore in contapezzi SIEMENS"); - } - } - } - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - base.readSemafori(ref currDispData); - try - { - currDispData.semIn = Semaforo.SV; - - if (verboseLog) - { - lgInfo("inizio read semafori"); - } - // leggo TUTTI i byte configurati... - byte[] MemBlock = new byte[parametri.memSizeRead]; - bool fatto = S7ReadBB(ref MemBlock); - Buffer.BlockCopy(MemBlock, 0, RawInput, 0, parametri.memSizeRead); - if (verboseLog) - { - lgInfo(string.Format("RawInput[0]: {0}", utils.binaryForm(RawInput[0]))); - } - // salvo il solo BYTE dell'input decifrando il semaforo... - decodeToBaseBitmap(); - decodeOtherData(); - // riporto bitmap... - reportRawInput(ref currDispData); - } - catch - { - currDispData.semIn = Semaforo.SR; - } - } - /// - /// decodifica da bitmap il CURRENT MODE del controllo - /// - /// - /// - protected virtual string decodeCurrMode(byte currModeBitmap) - { - string answ = ""; - if (verboseLog) - { - lgInfo(string.Format("CURR_MODE raw data: {0}", utils.binaryForm(currModeBitmap))); - } - // decodifica del MODO... B21 - /* - * CURR MODE diviso in BIT: - * B0 (01) = AUTO - * B1 (02) = MDI - * B2 (04) = JOG - * B3 (08) = TeachIN (associato a MDI --> 10) - * B4 (16) = Repos (associato a JOG --> 20) - * B5 (32) = RefPoint (associato a Jog --> 36) - * B6 (64) = Incr1 (associato a Jog --> 68) - * B7 (128) = Incr10 (associato a Jog --> -124 / 132 se UInt) - * */ - - // modi principali - if (currModeBitmap.SelectBit(0)) - { - answ = "AUTO"; - } - else if (currModeBitmap.SelectBit(1)) - { - answ = "MDI"; - } - else if (currModeBitmap.SelectBit(2)) - { - answ = "JOG"; - } - // modi accessori - if (currModeBitmap.SelectBit(3)) - { - answ += " | TEACH-IN"; - } - if (currModeBitmap.SelectBit(4)) - { - answ += " | REPOS"; - } - if (currModeBitmap.SelectBit(5)) - { - answ += " | REF-POINT"; - } - if (currModeBitmap.SelectBit(6)) - { - answ += " | INCR-1"; - } - if (currModeBitmap.SelectBit(7)) - { - answ += " | INCR-10"; - } - return answ; - } - /// - /// Decodifica il resto dell'area x i dati accessori (allarmi, ...) - /// - protected virtual void decodeOtherData() - { - if (verboseLog) - { - - } - } - /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO - /// - protected virtual void decodeToBaseBitmap() - { - // init a zero... - B_input = 0; - } - /// - /// Recupero programma in lavorazione - /// - /// - public override string getPrgName() - { - // valore non presente in vers default... se gestito fare override - string prgName = ""; - return prgName; - } - /// - /// Recupero programma in lavorazione come Dictionary FANUC... - /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) - /// - altre stringhe: ogni singolo parametro / valore - /// - /// - public override Dictionary getSysInfo() - { - // valore non presente in vers default... se gestito fare override - Dictionary outVal = new Dictionary(); - return outVal; - } - /// - /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) - /// - public override void processMode() - { - // valore non presente in vers default... se gestito fare override - if (utils.CRB("enableMode")) - { - } - } - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - // valore non presente in vers default... se gestito fare override - Dictionary outVal = new Dictionary(); - if (utils.CRB("enableTSVC")) - { - // processing SOLO SE ho in memoria abbastanza dati... - if (RawInput.Length < parametri.memSizeRead) - { - lgError($"Impossibile processare getDynData x Siemens PLC, vettore memoria troppo piccolo: {RawInput.Length} byte / {parametri.memSizeRead} byte presenti/richiesti)"); - } - else - { - try - { - // processo x ogni valore configurato... - if (memMap.mMapRead.Count > 0) - { - // inizializzo i valori - bool valBool = false; - double valore = 0; - string valString = ""; - lgInfo("Ciclo recupero dati getDynData"); - // procedo x ogni valore configurato...... - foreach (var item in memMap.mMapRead) - { - // in primis DEVO determinare di quale TIPO di valore ho bisogno... - switch (item.Value.tipoMem) - { - case plcDataType.Boolean: - valBool = S7.Net.Types.Boolean.GetValue(RawInput[item.Value.index], item.Value.size); - break; - case plcDataType.Int: - valore = ((double)S7.Net.Types.Int.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; - saveValue(ref outVal, valore, item.Key); - break; - case plcDataType.DInt: - valore = ((double)S7.Net.Types.DInt.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; - saveValue(ref outVal, valore, item.Key); - break; - case plcDataType.Word: - valore = ((double)S7.Net.Types.Word.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; - saveValue(ref outVal, valore, item.Key); - break; - case plcDataType.DWord: - valore = ((double)S7.Net.Types.DWord.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; - saveValue(ref outVal, valore, item.Key); - break; - case plcDataType.Real: - valore = S7.Net.Types.Double.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()) / item.Value.factor; - saveValue(ref outVal, valore, item.Key); - break; - case plcDataType.String: - valString = S7.Net.Types.String.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()); - break; - default: - break; - } - } + lgError($"Errore in S7WriteBB: Value è null"); } else { - lgInfo($"getDynData: {memMap.mMapRead.Count} record in mMapRead"); - } - } - catch (Exception exc) - { - lgError(exc, "Errore in getDynData x Siemens PLC"); - } - } - } - else - { - lgInfo($"Non processo getDynData: enableTSVC = false"); - } - if (periodicLog || outVal.Count > 0) - { - lgInfo($"Esito getDynData: {outVal.Count} valori VALIDI in outVal"); - } - return outVal; - } - /// - /// OVerride metodo x scrittura parametri su PLC - /// - /// - protected override void plcWriteParams(List updatedPar) - { - dataConf currMem = null; - int byteSize = 0; - byte[] MemBlock = new byte[1]; - string memAddrWrite = ""; - bool fatto = false; - string serObj = ""; - if (updatedPar != null) - { - // controllo i parametri... ne gestisco 4... - foreach (var item in updatedPar) - { - try - { - memAddrWrite = ""; - int valInt = 0; - uint valUInt = 0; - // cerco in area memMapWrite... - if (memMap.mMapWrite.ContainsKey(item.uid)) - { - // recupero! - currMem = memMap.mMapWrite[item.uid]; - byteSize = currMem.size; - memAddrWrite = currMem.memAddr; - MemBlock = new byte[byteSize]; - // faccio preliminarmente upsertKey... - upsertKey(currMem.name, currMem.value); - serObj = JsonConvert.SerializeObject(item); - lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}"); - lgInfo($"---------------{Environment.NewLine}UPDATED PARAM:{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); - serObj = JsonConvert.SerializeObject(currMem); - lgInfo($"---------------{Environment.NewLine}MEMORY CONTENT:{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); - switch (currMem.tipoMem) - { - case plcDataType.Boolean: - break; - case plcDataType.Int: - valInt = getScaledInt(currMem); - saveIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); - break; - case plcDataType.DInt: - valInt = getScaledInt(currMem); - saveDIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); - break; - case plcDataType.Word: - valUInt = getScaledUInt(currMem); - saveWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); - break; - case plcDataType.DWord: - valUInt = getScaledUInt(currMem); - saveDWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); - break; - case plcDataType.Real: - saveRealOnMemBlock(ref MemBlock, 0, currMem.value); - break; - case plcDataType.String: - // se ho writePre --> "allungo" di 2 la dimensione della stringa x MemBlock... - if (writePre) - { - MemBlock = new byte[byteSize + 2]; - } - saveStringOnMemBlock(ref MemBlock, 0, currMem.size, currMem.value); - break; - default: - break; - } - lgInfo($"---------------{Environment.NewLine}MemBlock data:{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}---------------"); - if (!string.IsNullOrEmpty(memAddrWrite)) - { - // scrivo su siemens - fatto = S7WriteBB(ref MemBlock, memAddrWrite); - // se configurato faccio verifica write... - if (getOptPar("WRITE_CHECK") == "TRUE") + if (DbNum < 0 || IndiceMem < 0) { - byte[] MemBlockRead = new byte[MemBlock.Length]; - S7ReadBB(ref MemBlockRead, memAddrWrite, MemBlock.Length); - // se non corrispondessero loggo! - if (!MemBlock.SequenceEqual(MemBlockRead)) - { - lgError($"Errore: mancata corrispondenza tra dati scritti e letti:{Environment.NewLine}Write: {BitConverter.ToString(MemBlock)}{Environment.NewLine}read: {BitConverter.ToString(MemBlockRead)}"); - } - else - { - lgInfo($"Scrittura corretta: {BitConverter.ToString(MemBlockRead)}"); - } + lgError($"Errore in S7WriteBB | DbNum: {DbNum} | IndiceMem: {IndiceMem}"); } - } - else - { - lgInfo($"Errore: memAddrWrite vuoto!"); - } + else + { + sw.Restart(); + if (testCncConn()) + { + try + { + int numByte = Value.Length; + ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, DbNum, IndiceMem, Value); + switch (errorCode) + { + case ErrorCode.NoError: + lgInfo($"Effettuata correttamente scrittura su PLC: DB {DbNum}.{IndiceMem} | numByte: {Value.Length}| {Value.ValToBinString()}"); + break; + case ErrorCode.WrongCPU_Type: + case ErrorCode.ConnectionError: + case ErrorCode.IPAddressNotAvailable: + case ErrorCode.WrongVarFormat: + case ErrorCode.WrongNumberReceivedBytes: + case ErrorCode.SendData: + case ErrorCode.ReadData: + case ErrorCode.WriteData: + lgError($"Errore in S7WriteBB su DB {DbNum}.{IndiceMem}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); + break; + default: + break; + } + answ = true; + } + catch (Exception exc) + { + lgError($"Eccezione in S7WriteBB: DbNum {DbNum}, IndiceMem: {IndiceMem}, numByte: {Value.Length}{Environment.NewLine}{exc}"); + } + } + sw.Stop(); + } + } + return answ; + } + + + + #endregion + + #region area principale adapter + + /// + /// Classe base con i metodi x Siemens + /// + /// + /// + public IobSiemens(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + memMap = new plcMemMap(); + writePre = true; + if (IOBConf != null) + { + // gestione invio ritardato contapezzi + pzCountDelay = utils.CRI("pzCountDelay"); + lastPzCountSend = DateTime.Now; + lastWarnODL = DateTime.Now; + // inizializzo parametri... + parametri = new connParamS7() + { + ipAdrr = "127.0.0.1", + tipoCpu = CpuType.S7200, + slot = 0, + rack = 0, + pingMsTimeout = IOBConf.pingMsTimeout, + memAddrRead = "DB1.DBB0", + memAddrWrite = "DB2.DBB0", + memSizeRead = 0, + memSizeWrite = 0 + }; + setParamPlc(); + + // salvo info su conf IOB... + string iobConfSer = ""; + try + { + iobConfSer = JsonConvert.SerializeObject(IOBConf); + } + catch + { } + // finito! + lgInfo($"Init IOB, con {iobConfSer}"); } else { - lgInfo($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write"); + lgError("Impossibile avviare, IOBConf nullo/non valido!"); } - } - catch (Exception exc) - { - lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}"); - } } - } + + /// + /// Test connessione CNC + /// + /// + protected bool testCncConn() + { + bool answ = false; + + IPStatus pingStatus = testPingMachine; + // se passa il ping faccio il resto... + if (pingStatus != IPStatus.Success) + { + lgError(string.Format("Errore in testCncConn: reply Status per {0}: {1}", parametri.ipAdrr, pingStatus)); + } + else + { + if (!currPLC.IsConnected) + { + currPLC.Open(); + } + + if (!currPLC.IsAvailable) + { + lgError(string.Format("PLC Siemens NON disponibile:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString)); + currPLC.ClearLastError(); + } + else + { + if (!currPLC.IsConnected && !pingDisabled) + { + lgError(string.Format("PLC Siemens NON connesso:{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString)); + currPLC.ClearLastError(); + parentForm.updateComStats("NO connection"); + } + else + { + parentForm.updateComStats("Connection OK"); + answ = true; + } + } + } + + return answ; + } + /// + /// Imposto parametri PLC + /// + protected override void setParamPlc() + { + // Creo oggetto connessione NC + parentForm.commPlcActive = true; + lgInfo("Start init Adapter SIEMENS all'IP {0} | CPU: {1} | R/S: {2}/{3} | --> IOB {4}", cIobConf.cncIpAddr, cIobConf.cpuType, cIobConf.rack, cIobConf.slot, cIobConf.codIOB); + // SE è necessario refresh... + if (needRefresh) + { + lgInfo("Refreshing connection..."); + if (parametri != null) + { + try + { + parametri.slot = cIobConf.slot; + parametri.rack = cIobConf.rack; + parametri.tipoCpu = (CpuType)Enum.Parse(typeof(CpuType), cIobConf.cpuType); + parametri.ipAdrr = cIobConf.cncIpAddr; + // leggo file init... + lgInfo("Reading ini file..."); + IniFile fIni = new IniFile(cIobConf.iniFileName); + // ora leggo valori speciali + parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", ""); + parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", ""); + parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0); + parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0); + // salvo vettori memoria... + lgInfo("Set RawInput dimensions..."); + RawInput = new byte[parametri.memSizeRead]; + RawOutput = new byte[parametri.memSizeWrite]; + // salvo parametri conn! + lgInfo(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite)); + } + catch (Exception exc) + { + lgError(exc, "Errore in parse parametri da IOBConf"); + } + // ora tento avvio PLC... SE PING OK... + IPStatus esitoPing = testPingMachine; + if (esitoPing == IPStatus.Success) + { + needRefresh = false; + try + { + currPLC = new Plc(parametri.tipoCpu, parametri.ipAdrr, parametri.rack, parametri.slot); + // disconnetto e connetto... + if (isVerboseLog) + { + lgInfo("SIEMENS: tryDisconnect"); + } + + tryDisconnect(); + // lo ripeto x evitare che ci sia un loop... e tryConnect richiami la procedura corrente... + needRefresh = false; + lgInfo("SIEMENS: tryConnect"); + tryConnect(); + lgInfo("End init Adapter SIEMENS"); + if (isVerboseLog) + { + lgInfo("S7+ CONNESSIONE AVVENUTA"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in INIT PLC S7+"); + } + } + else + { + lgError($"Errore in ping: esito {esitoPing}"); + } + parentForm.commPlcActive = false; + // carico conf vettore memoria... + loadMemConf(); + + bool enableByApp = utils.CRB("enableContapezzi"); + bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE"); + bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE"); + if ((enableByApp || enableByIob) && !(disableByIob)) + { + lgInfo("SIEMENS: inizio gestione contapezzi"); + try + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE"))) + { + if (getOptPar("PZCOUNT_MODE").StartsWith("STD")) + { + lgInfo("Init contapezzi SIEMENS: pzCntReload(true)"); + pzCntReload(true); + // refresh associazione Macchina - IOB + sendM2IOB(); + // per adesso imposto lettura fanuc == contapezzi (poi farà vera lettura...) + lastCountCNC = contapezzi; + } + else + { + contapezzi = 0; + lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); + } + } + else + { + contapezzi = 0; + lgInfo("Parametro mancante PZCOUNT_MODE"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in contapezzi SIEMENS"); + } + } + } + else + { + lgError("Parametri null!"); + } + } + } + /// + /// Override disconnessione + /// + public override void tryDisconnect() + { + if (connectionOk) + { + string szStatusConnection = ""; + try + { + currPLC.Close(); + connectionOk = false; + lgInfo(szStatusConnection); + lgInfo("Effettuata disconnessione adapter SIEMENS!"); + } + catch (Exception exc) + { + lgFatal(exc, "Errore nella disconnessione dall'adapter SIEMENS"); + } + } + else + { + lgError("IMPOSSIBILE effettuare disconnessione SIEMENS: Connessione non disponibile..."); + } + } + /// + /// Override connessione + /// + public override void tryConnect() + { + bool doLog = (verboseLog || periodicLog); + lgInfo("SIEMENS: tryConnect step 01"); + if (!connectionOk) + { + // SE è necessario refresh... + if (needRefresh) + { + lgInfo("SIEMENS: tryConnect step 02"); + + // reimporto parametri PLC se necessario... + setParamPlc(); + } + lgInfo("SIEMENS: tryConnect step 03"); + + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) + { + if (doLog) + { + lgInfo("SIEMENS: ConnKO - tryConnect"); + } + lgInfo("SIEMENS: tryConnect step 04"); + + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = ""; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + currPLC.Open(); + parentForm.commPlcActive = false; + lgInfo("szStatusConnection: " + szStatusConnection); + connectionOk = true; + // refresh stato allarmi!!! + if (connectionOk) + { + if (adpRunning) + { + lgInfo("Connessione OK"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal(string.Format("Errore in TryConnect adapter SIEMENS: {0}{1}{2}", szStatusConnection, Environment.NewLine, exc)); + connectionOk = false; + needRefresh = true; + } + } + else + { + // loggo no risposta ping ... + connectionOk = false; + if (doLog) + { + lgInfo(string.Format("Attenzione: SIEMENS controllo PING fallito per IP {0}", cIobConf.cncIpAddr)); + } + } + } + } + // se non è ancora connesso faccio procesisng memoria caso disconnesso... + if (!connectionOk) + { + // processo semafori ed invio... + processMemoryDiscon(); + } + } + /// + /// Restituisce path completo file da chiave configurazione + /// + /// chiave conf x file richiesto + /// + protected string filePath(string keyFile) + { + string answ = ""; + try + { + answ = $"{utils.confDir}\\{utils.CRS(keyFile)}"; + } + catch (Exception exc) + { + lgError(exc, "Eccezione in recupero filePath"); + } + return answ; + } + + #endregion + + #region Metodi specifici (da verificare/completare in implementazione) + + /// + /// Effettua vero processing contapezzi + /// + public override void processContapezzi() + { + if (utils.CRB("enableContapezzi")) + { + try + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE"))) + { + string memAddr = getOptPar("PZCOUNT_MODE"); + if (memAddr.StartsWith("STD")) + { + // inizio verifica area memoria/parametro levando prima parte codice + memAddr = memAddr.Replace("STD.", ""); + object outputVal = new object(); + // verifico se si tratta di lettura area DB... formato tipo STD.DB700.DBB22.W + if (memAddr.StartsWith("DB")) + { + memAreaSiemens areaCounter = new memAreaSiemens(memAddr); + + if (isVerboseLog) + { + lgInfo("[0] area memoria: {1}.{2}.{3}", memAddr, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem); + } + // copio da blocco già letto... con switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato + switch (areaCounter.tipoMem) + { + case "B": + byte valB = RawInput[areaCounter.indiceMem]; + outputVal = valB; + break; + case "W": + ushort valW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(2).ToArray()); + outputVal = valW; + break; + case "DW": + uint valDW = S7.Net.Types.Word.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray()); + outputVal = valDW; + break; + case "RE": + double valRe = S7.Net.Types.Double.FromByteArray(RawInput.Skip(areaCounter.indiceMem).Take(4).ToArray()); + outputVal = valRe; + break; + default: + break; + } + // salvo... + int newVal = -1; + Int32.TryParse(outputVal.ToString(), out newVal); + lastCountCNC = newVal > -1 ? newVal : lastCountCNC; + if (isVerboseLog) + { + lgInfo("[2] outputVal contapezzi: {0}", outputVal); + lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC); + } + } + stopwatch.Stop(); + } + else if (memAddr.StartsWith("SPEC")) + { + // inizio verifica area memoria/parametro levando prima parte codice + memAddr = memAddr.Replace("SPEC.", ""); + object outputVal = new object(); + // verifico se si tratta di lettura area DB... formato tipo SPEC.DB700.DBB22.W + if (memAddr.StartsWith("DB")) + { + memAreaSiemens areaCounter = new memAreaSiemens(memAddr); + + if (isVerboseLog) + { + lgInfo("[0] area memoria: {1}.{2}.{3}", memAddr, areaCounter.DbNum, areaCounter.indiceMem, areaCounter.tipoMem); + } + // leggo i dati SPECIFICI... + byte[] MemBlockPZ = new byte[8]; + bool fatto = false; + // copio da blocco LEGGENDO con switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato + switch (areaCounter.tipoMem) + { + case "B": + MemBlockPZ = new byte[1]; + fatto = S7ReadBB(ref MemBlockPZ,memAddr,1); + outputVal = MemBlockPZ[0]; + break; + case "W": + MemBlockPZ = new byte[2]; + fatto = S7ReadBB(ref MemBlockPZ, memAddr, 2); + ushort valW = S7.Net.Types.Word.FromByteArray(MemBlockPZ.ToArray()); + outputVal = valW; + break; + case "DW": + MemBlockPZ = new byte[4]; + fatto = S7ReadBB(ref MemBlockPZ, memAddr, 4); + uint valDW = S7.Net.Types.DWord.FromByteArray(MemBlockPZ.ToArray()); + outputVal = valDW; + break; + case "RE": + MemBlockPZ = new byte[4]; + fatto = S7ReadBB(ref MemBlockPZ, memAddr, 4); + double valRe = S7.Net.Types.Double.FromByteArray(MemBlockPZ.ToArray()); + outputVal = valRe; + break; + default: + break; + } + // salvo... + int newVal = -1; + Int32.TryParse(outputVal.ToString(), out newVal); + lastCountCNC = newVal > -1 ? newVal : lastCountCNC; + if (isVerboseLog) + { + lgInfo("[2] outputVal contapezzi: {0}", outputVal); + lgInfo("[3] lastCountCNC contapezzi: {0}", lastCountCNC); + } + } + stopwatch.Stop(); + } + } + } + catch (Exception exc) + { + lgError(exc, "Errore in contapezzi SIEMENS"); + } + } + } + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + base.readSemafori(ref currDispData); + try + { + currDispData.semIn = Semaforo.SV; + + if (verboseLog) + { + lgInfo("inizio read semafori"); + } + // leggo TUTTI i byte configurati... + byte[] MemBlock = new byte[parametri.memSizeRead]; + bool fatto = S7ReadBB(ref MemBlock); + Buffer.BlockCopy(MemBlock, 0, RawInput, 0, parametri.memSizeRead); + if (verboseLog) + { + lgInfo(string.Format("RawInput[0]: {0}", utils.binaryForm(RawInput[0]))); + } + // salvo il solo BYTE dell'input decifrando il semaforo... + decodeToBaseBitmap(); + decodeOtherData(); + // riporto bitmap... + reportRawInput(ref currDispData); + } + catch + { + currDispData.semIn = Semaforo.SR; + } + } + /// + /// decodifica da bitmap il CURRENT MODE del controllo + /// + /// + /// + protected virtual string decodeCurrMode(byte currModeBitmap) + { + string answ = ""; + if (verboseLog) + { + lgInfo(string.Format("CURR_MODE raw data: {0}", utils.binaryForm(currModeBitmap))); + } + // decodifica del MODO... B21 + /* + * CURR MODE diviso in BIT: + * B0 (01) = AUTO + * B1 (02) = MDI + * B2 (04) = JOG + * B3 (08) = TeachIN (associato a MDI --> 10) + * B4 (16) = Repos (associato a JOG --> 20) + * B5 (32) = RefPoint (associato a Jog --> 36) + * B6 (64) = Incr1 (associato a Jog --> 68) + * B7 (128) = Incr10 (associato a Jog --> -124 / 132 se UInt) + * */ + + // modi principali + if (currModeBitmap.SelectBit(0)) + { + answ = "AUTO"; + } + else if (currModeBitmap.SelectBit(1)) + { + answ = "MDI"; + } + else if (currModeBitmap.SelectBit(2)) + { + answ = "JOG"; + } + // modi accessori + if (currModeBitmap.SelectBit(3)) + { + answ += " | TEACH-IN"; + } + if (currModeBitmap.SelectBit(4)) + { + answ += " | REPOS"; + } + if (currModeBitmap.SelectBit(5)) + { + answ += " | REF-POINT"; + } + if (currModeBitmap.SelectBit(6)) + { + answ += " | INCR-1"; + } + if (currModeBitmap.SelectBit(7)) + { + answ += " | INCR-10"; + } + return answ; + } + /// + /// Decodifica il resto dell'area x i dati accessori (allarmi, ...) + /// + protected virtual void decodeOtherData() + { + if (verboseLog) + { + + } + } + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected virtual void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + } + /// + /// Recupero programma in lavorazione + /// + /// + public override string getPrgName() + { + // valore non presente in vers default... se gestito fare override + string prgName = ""; + return prgName; + } + /// + /// Recupero programma in lavorazione come Dictionary FANUC... + /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) + /// - altre stringhe: ogni singolo parametro / valore + /// + /// + public override Dictionary getSysInfo() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + return outVal; + } + /// + /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) + /// + public override void processMode() + { + // valore non presente in vers default... se gestito fare override + if (utils.CRB("enableMode")) + { + } + } + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + if (utils.CRB("enableTSVC")) + { + // processing SOLO SE ho in memoria abbastanza dati... + if (RawInput.Length < parametri.memSizeRead) + { + lgError($"Impossibile processare getDynData x Siemens PLC, vettore memoria troppo piccolo: {RawInput.Length} byte / {parametri.memSizeRead} byte presenti/richiesti)"); + } + else + { + try + { + // processo x ogni valore configurato... + if (memMap.mMapRead.Count > 0) + { + // inizializzo i valori + bool valBool = false; + double valore = 0; + string valString = ""; + lgInfo("Ciclo recupero dati getDynData"); + // procedo x ogni valore configurato...... + foreach (var item in memMap.mMapRead) + { + // in primis DEVO determinare di quale TIPO di valore ho bisogno... + switch (item.Value.tipoMem) + { + case plcDataType.Boolean: + valBool = S7.Net.Types.Boolean.GetValue(RawInput[item.Value.index], item.Value.size); + break; + case plcDataType.Int: + valore = ((double)S7.Net.Types.Int.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; + saveValue(ref outVal, valore, item.Key); + break; + case plcDataType.DInt: + valore = ((double)S7.Net.Types.DInt.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; + saveValue(ref outVal, valore, item.Key); + break; + case plcDataType.Word: + valore = ((double)S7.Net.Types.Word.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; + saveValue(ref outVal, valore, item.Key); + break; + case plcDataType.DWord: + valore = ((double)S7.Net.Types.DWord.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray())) / item.Value.factor; + saveValue(ref outVal, valore, item.Key); + break; + case plcDataType.Real: + valore = S7.Net.Types.Double.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()) / item.Value.factor; + saveValue(ref outVal, valore, item.Key); + break; + case plcDataType.String: + valString = S7.Net.Types.String.FromByteArray(RawInput.Skip(item.Value.index).Take(item.Value.size).ToArray()); + break; + default: + break; + } + } + } + else + { + lgInfo($"getDynData: {memMap.mMapRead.Count} record in mMapRead"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in getDynData x Siemens PLC"); + } + } + } + else + { + lgInfo($"Non processo getDynData: enableTSVC = false"); + } + if (periodicLog || outVal.Count > 0) + { + lgInfo($"Esito getDynData: {outVal.Count} valori VALIDI in outVal"); + } + return outVal; + } + /// + /// OVerride metodo x scrittura parametri su PLC + /// + /// + protected override void plcWriteParams(List updatedPar) + { + dataConf currMem = null; + int byteSize = 0; + byte[] MemBlock = new byte[1]; + string memAddrWrite = ""; + bool fatto = false; + string serObj = ""; + if (updatedPar != null) + { + // controllo i parametri... ne gestisco 4... + foreach (var item in updatedPar) + { + try + { + memAddrWrite = ""; + int valInt = 0; + uint valUInt = 0; + // cerco in area memMapWrite... + if (memMap.mMapWrite.ContainsKey(item.uid)) + { + // recupero! + currMem = memMap.mMapWrite[item.uid]; + byteSize = currMem.size; + memAddrWrite = currMem.memAddr; + MemBlock = new byte[byteSize]; + // faccio preliminarmente upsertKey... + upsertKey(currMem.name, currMem.value); + serObj = JsonConvert.SerializeObject(item); + lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}"); + lgInfo($"---------------{Environment.NewLine}UPDATED PARAM:{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + serObj = JsonConvert.SerializeObject(currMem); + lgInfo($"---------------{Environment.NewLine}MEMORY CONTENT:{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + switch (currMem.tipoMem) + { + case plcDataType.Boolean: + break; + case plcDataType.Int: + valInt = getScaledInt(currMem); + saveIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + case plcDataType.DInt: + valInt = getScaledInt(currMem); + saveDIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + case plcDataType.Word: + valUInt = getScaledUInt(currMem); + saveWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + case plcDataType.DWord: + valUInt = getScaledUInt(currMem); + saveDWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + case plcDataType.Real: + saveRealOnMemBlock(ref MemBlock, 0, currMem.value); + break; + case plcDataType.String: + // se ho writePre --> "allungo" di 2 la dimensione della stringa x MemBlock... + if (writePre) + { + MemBlock = new byte[byteSize + 2]; + } + saveStringOnMemBlock(ref MemBlock, 0, currMem.size, currMem.value); + break; + default: + break; + } + lgInfo($"---------------{Environment.NewLine}MemBlock data:{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}---------------"); + if (!string.IsNullOrEmpty(memAddrWrite)) + { + // scrivo su siemens + fatto = S7WriteBB(ref MemBlock, memAddrWrite); + // se configurato faccio verifica write... + if (getOptPar("WRITE_CHECK") == "TRUE") + { + byte[] MemBlockRead = new byte[MemBlock.Length]; + S7ReadBB(ref MemBlockRead, memAddrWrite, MemBlock.Length); + // se non corrispondessero loggo! + if (!MemBlock.SequenceEqual(MemBlockRead)) + { + lgError($"Errore: mancata corrispondenza tra dati scritti e letti:{Environment.NewLine}Write: {BitConverter.ToString(MemBlock)}{Environment.NewLine}read: {BitConverter.ToString(MemBlockRead)}"); + } + else + { + lgInfo($"Scrittura corretta: {BitConverter.ToString(MemBlockRead)}"); + } + } + } + else + { + lgInfo($"Errore: memAddrWrite vuoto!"); + } + } + else + { + lgInfo($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write"); + } + } + catch (Exception exc) + { + lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}"); + } + } + } + } + + private static int getScaledInt(dataConf currMem) + { + int valInt; + // prima faccio eventuale fattore di scala... + int.TryParse(currMem.value, out valInt); + if (currMem.factor > 1) + { + valInt = valInt * currMem.factor; + } + + return valInt; + } + private static uint getScaledUInt(dataConf currMem) + { + uint valUInt; + // prima faccio eventuale fattore di scala... + uint.TryParse(currMem.value, out valUInt); + if (currMem.factor > 1) + { + valUInt = valUInt * (uint)currMem.factor; + } + + return valUInt; + } + + /// + /// Metodo dispose x il currPLC contenuto + /// + public void Dispose() + { + currPLC.Dispose(); + } + + #endregion } - - private static int getScaledInt(dataConf currMem) - { - int valInt; - // prima faccio eventuale fattore di scala... - int.TryParse(currMem.value, out valInt); - if (currMem.factor > 1) - { - valInt = valInt * currMem.factor; - } - - return valInt; - } - private static uint getScaledUInt(dataConf currMem) - { - uint valUInt; - // prima faccio eventuale fattore di scala... - uint.TryParse(currMem.value, out valUInt); - if (currMem.factor > 1) - { - valUInt = valUInt * (uint)currMem.factor; - } - - return valUInt; - } - - /// - /// Metodo dispose x il currPLC contenuto - /// - public void Dispose() - { - currPLC.Dispose(); - } - - #endregion - } } diff --git a/IOB-WIN/IobSiemensComur.cs b/IOB-WIN/IobSiemensComur.cs index c9cdd2c9..01e6b799 100644 --- a/IOB-WIN/IobSiemensComur.cs +++ b/IOB-WIN/IobSiemensComur.cs @@ -4,240 +4,249 @@ using System.Collections.Generic; namespace IOB_WIN { - /// - /// Controllo Siemens specifico x impianti COMUR - /// - public class IobSiemensComur : IobSiemens - { - /* -------------------------------------------------------------------------------- - * Controlli SIEMENS COMUR - * - basasto su SIEMENS - * - S7 vers 1500 - * - * STRUTTURA MEMORIA DB150: 56 byte lettura, di cui 4 byte scrittura (4..7), vedere doc allegato - * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\COMUR Dentatrice - * - * Si intende tutto con DB150.DBxx - * - * - parametri processo PLC --> MES - * - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON - * - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia - * - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta * - eseguendo un ciclo automatico. - * - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina accesa * - ma NON sta eseguendo un ciclo automatico. - * - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con carico/ * - scarico pezzo autonomo, 0->Altrimenti. - * - DBX0.7 – Assi In Moto: Segnale pulito sullo stato di movimento Assi. 0->Tutti gli assi della macchina sono fermi, 1->Almeno un asse si sta * - muovendo. - * - DBX1.0 – Impulso Start Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Start Ciclo. - * - DBX1.1 – Impulso Fine Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Fine Ciclo. Attenzione! Questo * - impulso viene generato solo se il Ciclo Automatico finisce correttamente. Non viene generato nel caso in cui il Ciclo Automatico venga interrotto da * - allarmi. - * - DBX1.3 – Impulso Conta Pezzi: Impulso a fronte positivo (0->1) della durata di 1’’ generato al completamento di ogni programma pezzo. - * - DBX2.0 – Preallarmi Pezzi: Segnale pulito di segnalazione Preallarme Pezzi impostabile su CN. 0->Preallarme Disattivo, 1->Preallarme Attivo - * - DBX2.1 – Allarme Pezzi: Segnale pulito di segnalazione Allarme Pezzi impostabile su CN. 0->Allarme Disattivo, 1->Allarme Attivo. - * - DBX2.3 – Fine Vita Utensile: Segnale pulito di segnalazione Allarme Fine Vita Creatore. 0->Allarme Disattivo, 1->Allarme Attivo. - * - DBX2.7 – Ciclo In Attesa: Segnale pulito sullo stato di funzionamento. 1->Ciclo Automatico attivo ma tutti assi fermi, 0->Altrimenti. - * - * - DBD52 - Codice Pezzo In Lavorazione (4byte, REAL) - * - DBD56 - Codice Utensile In Uso (4byte, REAL) - * - * - * - parametri processo MES --> PLC - * - DBX4.0 – Reset Contapezzi Parziale: Segnale per resettare il valore del contatore “Contapezzi parziale”. Impostare il bit a 1 per attivare la funzione (il PLC riporterà a 0 il valore quando completa l’operazione). - * - * - DB150.DBD8 - Numero di Pezzi da produrre per il lotto (4byte, DInt) - * - DB150.[12.0 .. 31.7] - Codice articolo (stringa da 18 char) - * - DB150.[32.0 .. 51.7] - Codice commessa (stringa da 18 char) - * - * - * - DB111.DBD2: PartCounter INT 2.0 Conteggio Parziale di pezzi prodotti dalla macchina - * -------------------------------------------------------------------------------- */ - /// - /// Classe base con i metodi x Siemens + /// Controllo Siemens specifico x impianti COMUR /// - /// - /// - public IobSiemensComur(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + public class IobSiemensComur : IobSiemens { - lgInfo("NEW IOB SIEMENS versione COMUR"); - } + /* -------------------------------------------------------------------------------- + * Controlli SIEMENS COMUR + * - basasto su SIEMENS + * - S7 vers 1500 + * + * STRUTTURA MEMORIA DB150: 56 byte lettura, di cui 4 byte scrittura (4..7), vedere doc allegato + * G:\Drive condivisi\30_Clienti\Valvital\Comunicazione PLC\COMUR Dentatrice + * + * Si intende tutto con DB150.DBxx + * + * - parametri processo PLC --> MES + * - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON + * - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia + * - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta * - eseguendo un ciclo automatico. + * - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina accesa * - ma NON sta eseguendo un ciclo automatico. + * - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con carico/ * - scarico pezzo autonomo, 0->Altrimenti. + * - DBX0.7 – Assi In Moto: Segnale pulito sullo stato di movimento Assi. 0->Tutti gli assi della macchina sono fermi, 1->Almeno un asse si sta * - muovendo. + * - DBX1.0 – Impulso Start Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Start Ciclo. + * - DBX1.1 – Impulso Fine Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Fine Ciclo. Attenzione! Questo * - impulso viene generato solo se il Ciclo Automatico finisce correttamente. Non viene generato nel caso in cui il Ciclo Automatico venga interrotto da * - allarmi. + * - DBX1.3 – Impulso Conta Pezzi: Impulso a fronte positivo (0->1) della durata di 1’’ generato al completamento di ogni programma pezzo. + * - DBX2.0 – Preallarmi Pezzi: Segnale pulito di segnalazione Preallarme Pezzi impostabile su CN. 0->Preallarme Disattivo, 1->Preallarme Attivo + * - DBX2.1 – Allarme Pezzi: Segnale pulito di segnalazione Allarme Pezzi impostabile su CN. 0->Allarme Disattivo, 1->Allarme Attivo. + * - DBX2.3 – Fine Vita Utensile: Segnale pulito di segnalazione Allarme Fine Vita Creatore. 0->Allarme Disattivo, 1->Allarme Attivo. + * - DBX2.7 – Ciclo In Attesa: Segnale pulito sullo stato di funzionamento. 1->Ciclo Automatico attivo ma tutti assi fermi, 0->Altrimenti. + * + * - DBD52 - Codice Pezzo In Lavorazione (4byte, REAL) + * - DBD56 - Codice Utensile In Uso (4byte, REAL) + * + * + * - parametri processo MES --> PLC + * - DBX4.0 – Reset Contapezzi Parziale: Segnale per resettare il valore del contatore “Contapezzi parziale”. Impostare il bit a 1 per attivare la funzione (il PLC riporterà a 0 il valore quando completa l’operazione). + * + * - DB150.DBD8 - Numero di Pezzi da produrre per il lotto (4byte, DInt) + * - DB150.[12.0 .. 31.7] - Codice articolo (stringa da 18 char) + * - DB150.[32.0 .. 51.7] - Codice commessa (stringa da 18 char) + * + * + * - DB111.DBD2: PartCounter INT 2.0 Conteggio Parziale di pezzi prodotti dalla macchina + * -------------------------------------------------------------------------------- */ - #region Metodi specifici (da verificare/completare in implementazione) - - /// - /// Processo i task richiesti e li elimino dalla coda 1:1 - /// - /// - public override Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - bool taskOk = false; - string taskVal = ""; - // inizio con 1 byte di default - byte[] MemBlock = new byte[1]; - string memAddrWrite = ""; - if (task2exe != null) - { - // cerco task specifici - foreach (var item in task2exe) + /// + /// Classe base con i metodi x Siemens + /// + /// + /// + public IobSiemensComur(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY - switch (tName) - { - case taskType.nihil: - case taskType.fixStopSetup: - case taskType.forceResetPzCount: - case taskType.forceSetPzCount: - case taskType.setProg: - case taskType.sendWatchDogMes2Plc: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - break; - case taskType.setArt: - case taskType.setComm: - case taskType.setPzComm: - saveProdData(item); - int byteSize = 0; - // recupero dati da memMap... altrimenti NULLA - if (memMap.mMapWrite.ContainsKey(item.Key)) - { - dataConf currMem = memMap.mMapWrite[item.Key]; - byteSize = currMem.size; - memAddrWrite = currMem.memAddr; - MemBlock = new byte[byteSize]; - if (currMem.tipoMem == plcDataType.String) - { - saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); - } - else if (currMem.tipoMem == plcDataType.DInt) - { - int valDInt = 0; - int.TryParse(item.Value, out valDInt); - MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); - } - else if (currMem.tipoMem == plcDataType.Int) - { - short valDInt = 0; - short.TryParse(item.Value, out valDInt); - MemBlock = S7.Net.Types.Int.ToByteArray(valDInt); - } - } - taskVal = item.Value; - break; - case taskType.startSetup: - // processo scrittura BIT su DB150.DBX4.0 - MemBlock = new byte[1]; - MemBlock[0] = (byte)1; - memAddrWrite = "DB150.DBB4"; - break; - case taskType.stopSetup: - // processo scrittura BIT su DB150.DBX4.0 - MemBlock = new byte[1]; - MemBlock[0] = (byte)0; - memAddrWrite = "DB150.DBB4"; - break; - case taskType.setParameter: - // richiedo da URL i parametri WRITE da popolare - lgInfo("Chiamata processMemWriteRequests"); - taskVal = processMemWriteRequests(); - // se restituiscce "" faccio altra prova... - if (string.IsNullOrEmpty(taskVal)) - { - // i parametri me li aspetto come stringa composta paramName|paramvalue - if (item.Value.Contains("|")) - { - string[] paramsJob = item.Value.Split('|'); - taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; - } - else - { - taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; - } - } - break; - default: - taskVal = "SKIPPED | NO EXEC"; - break; - } - // aggiungo task! - taskDone.Add(item.Key, taskVal); - if (string.IsNullOrEmpty(memAddrWrite)) - { - // scrivo comunque! - taskOk = S7WriteBB(ref MemBlock, memAddrWrite); - } - if (!taskOk) - { - lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); - } + lgInfo("NEW IOB SIEMENS versione COMUR"); } - } - return taskDone; + + #region Metodi specifici (da verificare/completare in implementazione) + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + // inizio con 1 byte di default + byte[] MemBlock = new byte[1]; + string memAddrWrite = ""; + if (task2exe != null) + { + // cerco task specifici + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.setProg: + case taskType.sendWatchDogMes2Plc: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + break; + case taskType.setArt: + case taskType.setComm: + case taskType.setPzComm: + saveProdData(item); + int byteSize = 0; + // recupero dati da memMap... altrimenti NULLA + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + byteSize = currMem.size; + memAddrWrite = currMem.memAddr; + MemBlock = new byte[byteSize]; + if (currMem.tipoMem == plcDataType.String) + { + saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); + } + else if (currMem.tipoMem == plcDataType.DInt) + { + int valDInt = 0; + int.TryParse(item.Value, out valDInt); + MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); + } + else if (currMem.tipoMem == plcDataType.Int) + { + short valDInt = 0; + short.TryParse(item.Value, out valDInt); + MemBlock = S7.Net.Types.Int.ToByteArray(valDInt); + } + } + taskVal = item.Value; + break; + case taskType.startSetup: + // processo scrittura BIT su DB150.DBX4.0 + MemBlock = new byte[1]; + MemBlock[0] = (byte)1; + memAddrWrite = "DB150.DBB4"; + break; + case taskType.stopSetup: + // processo scrittura BIT su DB150.DBX4.0 + MemBlock = new byte[1]; + MemBlock[0] = (byte)0; + memAddrWrite = "DB150.DBB4"; + break; + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + default: + taskVal = "SKIPPED | NO EXEC"; + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + if (string.IsNullOrEmpty(memAddrWrite)) + { + // scrivo comunque! + taskOk = S7WriteBB(ref MemBlock, memAddrWrite); + } + if (!taskOk) + { + lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); + } + } + } + return taskDone; + } + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected override void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO STANDARD + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * B4: manuale + * B5: allarme creatore + * + * + * - BIT di stato + * - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON + * - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia + * - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta eseguendo un ciclo automatico. + * - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina accesa ma NON sta eseguendo un ciclo automatico. + * - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con carico/scarico pezzo autonomo, 0-> Altrimenti. NON HA SENSO perché NON HANNO il robot... + * - DBX0.7 – Assi In Moto: Segnale pulito sullo stato di movimento Assi. 0->Tutti gli assi della macchina sono fermi, 1->Almeno un asse si sta muovendo. + * - DBX1.0 – Impulso Start Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Start Ciclo. + * - DBX1.1 – Impulso Fine Ciclo: Impulso a fronte positivo (0->1) della durata di 1’’ che rappresenta l’evento di Fine Ciclo. Attenzione! Questo impulso viene generato solo se il Ciclo Automatico finisce correttamente. Non viene generato nel caso in cui il Ciclo Automatico venga interrotto da allarmi. + * - DBX1.3 – Impulso Conta Pezzi: Impulso a fronte positivo (0->1) della durata di 1’’ generato al completamento di ogni programma pezzo. + * - DBX2.0 – Preallarmi Pezzi: Segnale pulito di segnalazione Preallarme Pezzi impostabile su CN. 0->Preallarme Disattivo, 1->Preallarme Attivo + * - DBX2.1 – Allarme Pezzi: Segnale pulito di segnalazione Allarme Pezzi impostabile su CN. 0->Allarme Disattivo, 1->Allarme Attivo. + * - DBX2.3 – Fine Vita Utensile: Segnale pulito di segnalazione Allarme Fine Vita Creatore. 0->Allarme Disattivo, 1->Allarme Attivo. + * - DBX2.7 – Ciclo In Attesa: Segnale pulito sullo stato di funzionamento. 1->Ciclo Automatico attivo ma tutti assi fermi, 0->Altrimenti. + * + ----------------------------------------------------- */ + + byte mainData = RawInput[0]; + + int byteSignals = 0; + // bit 0 (poweron) imposto a 1 SE connected... + if (currPLC.IsConnected) + { + byteSignals += (1 << 0); + } + if ((mainData & (1 << 2)) != 0) + { + byteSignals += (1 << 1); + } + + // controllo il bit MAIN dello status + if ((mainData & (1 << 1)) != 0) + { + byteSignals += (1 << 3); + } + + // considero come MANUALE NON ciclo in continuo... + if ((mainData & (1 << 3)) != 0) + { + byteSignals += (1 << 4); + } + + // salvo! + B_input = byteSignals; + + // log opzionale! + if (verboseLog) + { + lgInfo($"Trasformazione dati: RawInput:{RawInput[0]} --> B_input: {B_input}"); + } + } + + #endregion } - - /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO - /// - protected override void decodeToBaseBitmap() - { - // init a zero... - B_input = 0; - - /* ----------------------------------------------------- - * bitmap MAPO STANDARD - * B0: POWER_ON - * B1: RUN - * B2: pzCount - * B3: allarme - * B4: manuale - * - * - * - BIT di stato - * - DBX0.0 - Macchina On: Segnale pulito di informazione sullo stato della macchina. 0->Aux OFF, 1->Aux ON - * - DBX0.1 – Macchina in Allarme: Segnale pulito di macchina in allarme. 0->Nessun Allarme, 1->E’ presente almeno un allarme/anomalia - * - DBX0.2 – Macchina in Ciclo: Segnale pulito sullo stato di funzionamento. 0->La macchina NON sta eseguendo un ciclo automatico, 1->La macchina sta eseguendo un ciclo automatico. - * - DBX0.3 – Macchina Non in Produzione: Segnale pulito sullo stato della macchina. 0->Macchina accesa e in lavorazione automatica, 1->Macchina accesa ma NON sta eseguendo un ciclo automatico. - * - DBX0.4 – Macchina In Ciclo Continuità: Segnale pulito sullo stato di funzionamento. 1->La macchina sta eseguendo un ciclo automatico con carico/scarico pezzo autonomo, 0->Altrimenti. - * - ----------------------------------------------------- */ - - byte mainData = RawInput[0]; - - int byteSignals = 0; - // bit 0 (poweron) imposto a 1 SE connected... - if (currPLC.IsConnected) - { - byteSignals += (1 << 0); - } - if ((mainData & (1 << 2)) == 1) - { - byteSignals += (1 << 1); - } - - // controllo il bit MAIN dello status - if ((mainData & (1 << 1)) == 1) - { - byteSignals += (1 << 3); - } - - // considero come MANUALE NON ciclo in continuo... - if ((mainData & (1 << 4)) == 0 || (mainData & (1 << 3)) == 1) - { - byteSignals += (1 << 4); - } - - // salvo! - B_input = byteSignals; - - // log opzionale! - if (verboseLog) - { - lgInfo($"Trasformazione dati: RawInput:{RawInput[0]} --> B_input: {B_input}"); - } - } - - #endregion - } } diff --git a/IOB-WIN/IobSiemensTorri.cs b/IOB-WIN/IobSiemensTorri.cs index 922ea6ff..c674530e 100644 --- a/IOB-WIN/IobSiemensTorri.cs +++ b/IOB-WIN/IobSiemensTorri.cs @@ -6,275 +6,277 @@ using System.Linq; namespace IOB_WIN { - public class IobSiemensTorri : IobSiemens - { - /* -------------------------------------------------------------------------------- - * Controlli SIEMENS TORRI - * - basasto su SIEMENS - * - S7 vers 1200 - * - * mod: 2019.01.19: aggiunta gestione segnale test/accensione/spegnimento (DB700.B1.4) --> mod StateMachine! - * mod: 2019.04.06: aggiunta indicazione (IOB--> PLC) di stato setup su DB701.B0.4 - * -------------------------------------------------------------------------------- */ - - - /// - /// estende l'init della classe base con i metodi x Siemens specifici x Torri - /// - /// - /// - public IobSiemensTorri(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + public class IobSiemensTorri : IobSiemens { - // dovebbe fare init della classe base, VERIFICARE... - lgInfo("NEW IOB SIEMENS versione TORRI"); - } - /// - /// Processo i task richiesti e li elimino dalla coda 1:1 - /// - /// - public override Dictionary executeTasks(Dictionary task2exe) - { - // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... - Dictionary taskDone = new Dictionary(); - bool taskOk = false; - string taskVal = ""; - // inizio con 1 byte VUOTO - byte[] MemBlock = new byte[1]; + /* -------------------------------------------------------------------------------- + * Controlli SIEMENS TORRI + * - basasto su SIEMENS + * - S7 vers 1200 + * + * mod: 2019.01.19: aggiunta gestione segnale test/accensione/spegnimento (DB700.B1.4) --> mod StateMachine! + * mod: 2019.04.06: aggiunta indicazione (IOB--> PLC) di stato setup su DB701.B0.4 + * -------------------------------------------------------------------------------- */ - // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 - foreach (var item in task2exe) - { - taskOk = false; - taskVal = ""; - // converto richiesta in enum... - taskType tName = taskType.nihil; - Enum.TryParse(item.Key, out tName); - // controllo sulla KEY - switch (tName) + + /// + /// estende l'init della classe base con i metodi x Siemens specifici x Torri + /// + /// + /// + public IobSiemensTorri(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { - case taskType.nihil: - case taskType.forceResetPzCount: - case taskType.forceSetPzCount: - case taskType.setArt: - case taskType.setComm: - case taskType.setProg: - case taskType.sendWatchDogMes2Plc: - taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; - lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.fixStopSetup: - taskVal = "VALUE DB701.0.4 --> 0"; - lgInfo($"Chiamata fixStopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.startSetup: - MemBlock[0] += (1 << 4); - taskVal = "VALUE DB701.0.4 --> 1"; - lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - case taskType.stopSetup: - taskVal = "VALUE DB701.0.4 --> 0"; - lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); - break; - default: - taskVal = "SKIPPED | NO EXEC"; - lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); - break; + // dovebbe fare init della classe base, VERIFICARE... + lgInfo("NEW IOB SIEMENS versione TORRI"); } - taskDone.Add(item.Key, taskVal); - } - // scrivo comunque! - bool fatto = S7WriteBB(ref MemBlock); - return taskDone; - } - - #region da verificare - - /// - /// Recupero dati override in formato dictionary - /// - /// - public override Dictionary getOverrides() - { - Dictionary outVal = new Dictionary(); - uint valDW = 0; - // !!!FARE!!! recuperare da conf memoria, ora HARD CODED - outVal.Add("FEED_OVER", RawInput[19].ToString()); - outVal.Add("RAPID_OVER", RawInput[20].ToString()); - outVal.Add("CURR_MODE", decodeCurrMode(RawInput[21])); - // recupero RPM pezzo/mola !!!FARE!!! cambio nome da config, qui sono 01:conduttrice e 02:operatrice (3013), mentre sono pezzo/mola nella V100 - valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(24).Take(4).ToArray()); - outVal.Add("RPM_01", valDW.ToString()); - valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(28).Take(4).ToArray()); - outVal.Add("RPM_02", valDW.ToString()); - return outVal; - } - - /// - /// Decodifica il resto dell'area TORRI x i dati accessori (allarmi, ...) - /// - protected override void decodeOtherData() - { - if (verboseLog) - { - - } - } - - /// - /// Effettua decodifica aree memoria alla bitmap usata x MAPO - /// - protected override void decodeToBaseBitmap() - { - // init a zero... - B_input = 0; - // TORRI: leggo i primi 8 bit hard coded... - int byteSem = RawInput[0]; - - // azzero powerOn... - byteSem &= ~(1 << 0); - // bit 0 (powerOn) imposto a 1 SE connected... - if (currPLC.IsConnected) - { - byteSem += (1 << 0); - } - - // azzero i bit NON gestiti (2-5-6-7) - byteSem &= ~(1 << 2); - byteSem &= ~(1 << 5); - byteSem &= ~(1 << 6); - byteSem &= ~(1 << 7); - // leggo bit DB700.B1.4 e lo porto al bit 5 --> ciclo test/accensione/spegnimento - if ((RawInput[1] & (1 << 4)) != 0) //se RawInput[1] & 16-- > 5° bit-- > TEST - { - byteSem += (1 << 5); - } - // salvo infine variabile bit x invio - B_input = byteSem; - - - string currODL = ""; - try - { - currODL = utils.callUrl(urlGetCurrODL); - // solo SE HO un ODL... - if (string.IsNullOrEmpty(currODL) || currODL == "0") + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) { - if (periodicLog) - { - lgInfo($"SiemensTorri | Lettura ODL andata a vuoto: currODL: {currODL}"); - } + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + // inizio con 1 byte VUOTO + byte[] MemBlock = new byte[1]; + if (task2exe != null) + { + // cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4 + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.nihil: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.setArt: + case taskType.setComm: + case taskType.setProg: + case taskType.sendWatchDogMes2Plc: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.fixStopSetup: + taskVal = "VALUE DB701.0.4 --> 0"; + lgInfo($"Chiamata fixStopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.startSetup: + MemBlock[0] += (1 << 4); + taskVal = "VALUE DB701.0.4 --> 1"; + lgInfo($"Chiamata startSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + case taskType.stopSetup: + taskVal = "VALUE DB701.0.4 --> 0"; + lgInfo($"Chiamata stopSetup: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + default: + taskVal = "SKIPPED | NO EXEC"; + lgInfo($"Chiamata default senza processing: taskOk: {taskOk} | taskVal: {taskVal}"); + break; + } + taskDone.Add(item.Key, taskVal); + } + // scrivo comunque! + bool fatto = S7WriteBB(ref MemBlock); + } + return taskDone; } - else + + #region da verificare + + /// + /// Recupero dati override in formato dictionary + /// + /// + public override Dictionary getOverrides() { - // se variato o scaduto timeout log... - if (periodicLog || (currIdxODL.ToString() != currODL)) - { - lgInfo($"SiemensTorri | Lettura ODL, currODL: {currODL} --> currIdxODL prec: {currIdxODL}"); - } - // provo a salvare nuovo ODL - int.TryParse(currODL, out currIdxODL); + Dictionary outVal = new Dictionary(); + uint valDW = 0; + // !!!FARE!!! recuperare da conf memoria, ora HARD CODED + outVal.Add("FEED_OVER", RawInput[19].ToString()); + outVal.Add("RAPID_OVER", RawInput[20].ToString()); + outVal.Add("CURR_MODE", decodeCurrMode(RawInput[21])); + // recupero RPM pezzo/mola !!!FARE!!! cambio nome da config, qui sono 01:conduttrice e 02:operatrice (3013), mentre sono pezzo/mola nella V100 + valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(24).Take(4).ToArray()); + outVal.Add("RPM_01", valDW.ToString()); + valDW = S7.Net.Types.DWord.FromByteArray(RawInput.Skip(28).Take(4).ToArray()); + outVal.Add("RPM_02", valDW.ToString()); + return outVal; } - } - catch (Exception exc) - { - if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15) + + /// + /// Decodifica il resto dell'area TORRI x i dati accessori (allarmi, ...) + /// + protected override void decodeOtherData() { - lgError(exc, $"Errore in fase di chiamata URL x ODL corrente | URL chiamato: {urlGetCurrODL}"); - lastWarnODL = DateTime.Now; + if (verboseLog) + { + + } } - } - if (!string.IsNullOrEmpty(currODL) && currODL != "0") - { - // ora processo il contapezzi... - string retVal = ""; - // controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x distanziare invio e ridurre letture - if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO + /// + protected override void decodeToBaseBitmap() { - // Salvo il contapezzi della macchina - retVal = utils.callUrlNow(urlSetPzCountMAC + lastCountCNC.ToString()); - // verifica se tutto OK, ovvero conferma i pezzi inviati - if (retVal != lastCountCNC.ToString()) - { - // errore salvataggio contapezzi - lgInfo($"Errore salvataggio Contapezzi PLC SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi} | Valore tornato: {retVal}"); - // rileggo il counter pezzi da server - pzCntReload(true); - } + // init a zero... + B_input = 0; + // TORRI: leggo i primi 8 bit hard coded... + int byteSem = RawInput[0]; - // se sono differenti MOSTRO... - if (lastCountCNC != contapezzi) - { - // registro contapezzi - lgInfo($"Differenza Contapezzi: CNC READ: {lastCountCNC} | Interno IOB {contapezzi}"); - } - if ((lastCountCNC > contapezzi)) - { - // salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio - contapezzi++; - needRefreshPzCount = true; - // salvo in semaforo! - B_input += 1 << 2; - // registro contapezzi - lgInfo($"Contapezzi SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi}"); - } + // azzero powerOn... + byteSem &= ~(1 << 0); + // bit 0 (powerOn) imposto a 1 SE connected... + if (currPLC.IsConnected) + { + byteSem += (1 << 0); + } - // Salvo il contapezzi della macchina - retVal = utils.callUrlNow(urlSetPzCount + contapezzi.ToString()); - // verifica se tutto OK, ovvero conferma i pezzi inviati - if (retVal != contapezzi.ToString()) - { - // errore salvataggio contapezzi - lgInfo($"Errore salvataggio Contapezzi PLC SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi} | Valore tornato: {retVal}"); - // rileggo il counter pezzi da server - pzCntReload(true); - } + // azzero i bit NON gestiti (2-5-6-7) + byteSem &= ~(1 << 2); + byteSem &= ~(1 << 5); + byteSem &= ~(1 << 6); + byteSem &= ~(1 << 7); + // leggo bit DB700.B1.4 e lo porto al bit 5 --> ciclo test/accensione/spegnimento + if ((RawInput[1] & (1 << 4)) != 0) //se RawInput[1] & 16-- > 5° bit-- > TEST + { + byteSem += (1 << 5); + } + // salvo infine variabile bit x invio + B_input = byteSem; - // verifico se variato contapezzi... e se passato ritardo minimo... - if ((lastCountCNC - contapezzi) > minSendPzCountBlock) - { - trySendPzCountBlock(); - } - // invio a server contapezzi (aggiornato) - retVal = utils.callUrlNow(urlSetPzCount + contapezzi.ToString()); - // verifica se tutto OK - if (retVal != contapezzi.ToString()) - { - // errore salvataggio contapezzi - lgInfo($"Errore salvataggio Contapezzi SIEMENS-TORRI: lastCountCNC {lastCountCNC} | contapezzi {contapezzi} | risposta: {retVal}"); - // rileggo il counter pezzi da server - pzCntReload(true); - } + string currODL = ""; + try + { + currODL = utils.callUrl(urlGetCurrODL); + // solo SE HO un ODL... + if (string.IsNullOrEmpty(currODL) || currODL == "0") + { + if (periodicLog) + { + lgInfo($"SiemensTorri | Lettura ODL andata a vuoto: currODL: {currODL}"); + } + } + else + { + // se variato o scaduto timeout log... + if (periodicLog || (currIdxODL.ToString() != currODL)) + { + lgInfo($"SiemensTorri | Lettura ODL, currODL: {currODL} --> currIdxODL prec: {currIdxODL}"); + } + // provo a salvare nuovo ODL + int.TryParse(currODL, out currIdxODL); + } + } + catch (Exception exc) + { + if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15) + { + lgError(exc, $"Errore in fase di chiamata URL x ODL corrente | URL chiamato: {urlGetCurrODL}"); + lastWarnODL = DateTime.Now; + } + } + if (!string.IsNullOrEmpty(currODL) && currODL != "0") + { + // ora processo il contapezzi... + string retVal = ""; + // controllo se è passato intervallo minimo tra 2 controlli/elaborazioni x distanziare invio e ridurre letture + if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + { + // Salvo il contapezzi della macchina + retVal = utils.callUrlNow(urlSetPzCountMAC + lastCountCNC.ToString()); + // verifica se tutto OK, ovvero conferma i pezzi inviati + if (retVal != lastCountCNC.ToString()) + { + // errore salvataggio contapezzi + lgInfo($"Errore salvataggio Contapezzi PLC SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi} | Valore tornato: {retVal}"); + // rileggo il counter pezzi da server + pzCntReload(true); + } - // resetto timer... - lastPzCountSend = DateTime.Now; + // se sono differenti MOSTRO... + if (lastCountCNC != contapezzi) + { + // registro contapezzi + lgInfo($"Differenza Contapezzi: CNC READ: {lastCountCNC} | Interno IOB {contapezzi}"); + } + if ((lastCountCNC > contapezzi)) + { + // salvo nuovo contapezzi (incremento di 1...) + richiesta refresh conteggio + contapezzi++; + needRefreshPzCount = true; + // salvo in semaforo! + B_input += 1 << 2; + // registro contapezzi + lgInfo($"Contapezzi SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi}"); + } + + // Salvo il contapezzi della macchina + retVal = utils.callUrlNow(urlSetPzCount + contapezzi.ToString()); + // verifica se tutto OK, ovvero conferma i pezzi inviati + if (retVal != contapezzi.ToString()) + { + // errore salvataggio contapezzi + lgInfo($"Errore salvataggio Contapezzi PLC SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno IOB {contapezzi} | Valore tornato: {retVal}"); + // rileggo il counter pezzi da server + pzCntReload(true); + } + + // verifico se variato contapezzi... e se passato ritardo minimo... + if ((lastCountCNC - contapezzi) > minSendPzCountBlock) + { + trySendPzCountBlock(); + } + + // invio a server contapezzi (aggiornato) + retVal = utils.callUrlNow(urlSetPzCount + contapezzi.ToString()); + // verifica se tutto OK + if (retVal != contapezzi.ToString()) + { + // errore salvataggio contapezzi + lgInfo($"Errore salvataggio Contapezzi SIEMENS-TORRI: lastCountCNC {lastCountCNC} | contapezzi {contapezzi} | risposta: {retVal}"); + // rileggo il counter pezzi da server + pzCntReload(true); + } + + // resetto timer... + lastPzCountSend = DateTime.Now; + } + } + else + { + if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + { + lgInfo($"Attenzione: mancanza ODL non procedo con gestione contapezzi. Contapezzi SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno {contapezzi}"); + // resetto timer... + lastPzCountSend = DateTime.Now; + } + } + + // log opzionale! + if (verboseLog) + { + lgInfo("Trasformazione B_input: {B_input}"); + } } - } - else - { - if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay)) + + + /// + /// Recupero programma in lavorazione + /// + /// + public override string getPrgName() { - lgInfo($"Attenzione: mancanza ODL non procedo con gestione contapezzi. Contapezzi SIEMENST-TORRI: {lastCountCNC} | Contapezzi interno {contapezzi}"); - // resetto timer... - lastPzCountSend = DateTime.Now; - } - } - - // log opzionale! - if (verboseLog) - { - lgInfo("Trasformazione B_input: {B_input}"); - } - } - - - /// - /// Recupero programma in lavorazione - /// - /// - public override string getPrgName() - { - string prgName = ""; + string prgName = ""; #if false // recupero NUOVO prgName... try @@ -289,38 +291,38 @@ namespace IOB_WIN lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc)); } #endif - return prgName; - } + return prgName; + } - /// - /// Recupero programma in lavorazione come Dictionary FANUC... - /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) - /// - altre stringhe: ogni singolo parametro / valore - /// - /// - public override Dictionary getSysInfo() - { - Dictionary outVal = new Dictionary(); - try - { - outVal.Add("CPU", currPLC.CPU.ToString()); - outVal.Add("MAX_PDU", currPLC.MaxPDUSize.ToString()); - outVal.Add("RACK", currPLC.Rack.ToString()); - outVal.Add("SLOT", currPLC.Slot.ToString()); - } - catch (Exception exc) - { - lgError(exc, "Errore in getSysInfo"); - } - return outVal; - } - /// - /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) - /// - public override void processMode() - { - if (utils.CRB("enableMode")) - { + /// + /// Recupero programma in lavorazione come Dictionary FANUC... + /// - SYSINFO: (prima KEY globale) TUTTI i valori separati da # (x fare check modifica) + /// - altre stringhe: ogni singolo parametro / valore + /// + /// + public override Dictionary getSysInfo() + { + Dictionary outVal = new Dictionary(); + try + { + outVal.Add("CPU", currPLC.CPU.ToString()); + outVal.Add("MAX_PDU", currPLC.MaxPDUSize.ToString()); + outVal.Add("RACK", currPLC.Rack.ToString()); + outVal.Add("SLOT", currPLC.Slot.ToString()); + } + catch (Exception exc) + { + lgError(exc, "Errore in getSysInfo"); + } + return outVal; + } + /// + /// Esegue processing MODE (e nel contempo recupera altri dati dell'area G) + /// + public override void processMode() + { + if (utils.CRB("enableMode")) + { #if false try { @@ -348,15 +350,15 @@ namespace IOB_WIN lgError(exc, "Errore in process Mode G43"); } #endif - } - } + } + } - /// - /// Recupero dati dinamici... - /// - public override Dictionary getDynData() - { - Dictionary outVal = new Dictionary(); + /// + /// Recupero dati dinamici... + /// + public override Dictionary getDynData() + { + Dictionary outVal = new Dictionary(); #if false inizio = DateTime.Now; CncLib.Focas1.ODBDY2_1 answ = FANUC_ref.getAllDynData(); @@ -393,165 +395,35 @@ namespace IOB_WIN lgError(exc, "Errore in getDynData"); } #endif - return outVal; - } - /// - /// Recupera ULTIMO allarme... - /// - /// - public override Dictionary getCncAlarms() - { - Dictionary outVal = new Dictionary(); - try - { - string almMsg = string.Format("{0} | {1}", currPLC.LastErrorCode.ToString(), currPLC.LastErrorString); - outVal.Add("CNC_ALARM", almMsg); - } - catch (Exception exc) - { - lgError(exc, "Errore in getCncAlarms"); - } - return outVal; - } + return outVal; + } + /// + /// Recupera ULTIMO allarme... + /// + /// + public override Dictionary getCncAlarms() + { + Dictionary outVal = new Dictionary(); + try + { + string almMsg = string.Format("{0} | {1}", currPLC.LastErrorCode.ToString(), currPLC.LastErrorString); + outVal.Add("CNC_ALARM", almMsg); + } + catch (Exception exc) + { + lgError(exc, "Errore in getCncAlarms"); + } + return outVal; + } - /// - /// Override salvataggio valori in memoria... - /// - /// tipo di DUMP - public override void saveMemDump(dumpType tipo) - { -#if false - dump_MemAreaD(); - dump_MemAreaY(); -#endif + /// + /// Override salvataggio valori in memoria... + /// + /// tipo di DUMP + public override void saveMemDump(dumpType tipo) + { + } + + #endregion } - /// - /// Dump PERIODICO area D della memoria - /// - /// area memoria di partenza - /// - private void dump_MemAreaD(int memIndex, int memSyzeByte) - { - // leggo TUTTI i 9999 byte della memoria D... - byte[] MemBlockD = new byte[memSyzeByte]; - stopwatch.Restart(); - if (verboseLog) - { - lgInfo("START MemDump AreaD"); - } -#if false - FanucMemRW(R, FANUC.MemType.D, memIndex, ref MemBlockD); - if (verboseLog) lgInfo("END MemDump AreaD"); - if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpD", MemBlockD.Length), DateTime.Now.Subtract(inizio).Ticks); - // file out! - string nomeFile = ""; - Dictionary mappaValori = new Dictionary(); - // salvo in file i dati letti come DWord (4byte) - nomeFile = string.Format(@"{0}\SAMPLES\MemDump_D_DW_{1:yyyyMMdd_HHmmss}.dat", utils.dataDatDir, DateTime.Now); - for (int i = 0; i < MemBlockD.Length / 4; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockD, i * 4).ToString()); - } - utils.WritePlain(mappaValori, nomeFile); -#endif - } - /// - /// Dump area D della memoria - /// - private void dump_MemAreaD() - { - // faccio chaimate e salvo in file dump... - int memIndex = 0; - // leggo TUTTI i 9999 byte della memoria D... - byte[] MemBlockD = new byte[9999]; - stopwatch.Restart(); - if (verboseLog) - { - lgInfo("START MemDump AreaD"); - } -#if false - FanucMemRW(R, FANUC.MemType.D, memIndex, ref MemBlockD); - if (verboseLog) lgInfo("END MemDump AreaD"); - if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpD", MemBlockD.Length), DateTime.Now.Subtract(inizio).Ticks); - // - string nomeFile = ""; - // salvo in file i dati letti come BYTE - nomeFile = string.Format(@"{0}\MemDump_D_Byte.dat", utils.dataDatDir); - Dictionary mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockD.Length; i++) - { - mappaValori.Add(i.ToString("0000"), MemBlockD[i].ToString()); - } - utils.WritePlain(mappaValori, nomeFile); - - // salvo in file i dati letti come DWord (4byte) - nomeFile = string.Format(@"{0}\MemDump_D_DW.dat", utils.dataDatDir); - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockD.Length / 4; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockD, i * 4).ToString()); - } - utils.WritePlain(mappaValori, nomeFile); - - // salvo in file i dati letti come DWord (4byte) - nomeFile = string.Format(@"{0}\MemDump_D_W.dat", utils.dataDatDir); - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockD.Length / 2; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockD, i * 2).ToString()); - } - utils.WritePlain(mappaValori, nomeFile); -#endif - } - /// - /// Dump area Y della memoria - /// - private void dump_MemAreaY() - { - // faccio chaimate e salvo in file dump... - int memIndex = 0; - // leggo TUTTI i 9999 byte della memoria Y... - byte[] MemBlockY = new byte[10]; - stopwatch.Restart(); - if (verboseLog) - { - lgInfo("START MemDump AreaY"); - } -#if false - FanucMemRW(R, FANUC.MemType.Y, memIndex, ref MemBlockY); - if (verboseLog) lgInfo("END MemDump AreaY"); - if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-MemDumpY", MemBlockY.Length), DateTime.Now.Subtract(inizio).Ticks); - // - string nomeFile = ""; - // salvo in file i dati letti come BYTE - nomeFile = string.Format(@"{0}\MemDump_Y_Byte.dat", utils.dataDatDir); - Dictionary mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockY.Length; i++) - { - mappaValori.Add(i.ToString("0000"), MemBlockY[i].ToString()); - } - utils.WritePlain(mappaValori, nomeFile); - - // salvo in file i dati letti come DWord (4byte) - nomeFile = string.Format(@"{0}\MemDump_Y_DW.dat", utils.dataDatDir); - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockY.Length / 4; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt32(MemBlockY, i * 4).ToString()); - } - utils.WritePlain(mappaValori, nomeFile); - - // salvo in file i dati letti come DWord (4byte) - nomeFile = string.Format(@"{0}\MemDump_Y_W.dat", utils.dataDatDir); - mappaValori = new Dictionary(); - for (int i = 0; i < MemBlockY.Length / 2; i++) - { - mappaValori.Add(i.ToString("0000"), BitConverter.ToUInt16(MemBlockY, i * 2).ToString()); - } - utils.WritePlain(mappaValori, nomeFile); -#endif - } - - #endregion - } } diff --git a/IOB-WIN/IobWPS.cs b/IOB-WIN/IobWPS.cs index bb848db6..69f82a7b 100644 --- a/IOB-WIN/IobWPS.cs +++ b/IOB-WIN/IobWPS.cs @@ -14,345 +14,355 @@ using System.Windows.Forms; namespace IOB_WIN { - /// - /// Generica classe per implementare WebPageScraping (scaricamento web pages anche js-based x recupero informazioni) - /// - public class IobWPS : IobGeneric - { - /* -------------------------------------------------------------------------------- - * Controlli dotati di GENERICA pagina WEB in cui cercare e recuperare informazioni - * - * - il file di conf deve contenere l'URL di base - * - il file di conf deve contenere COSA cercare (es il "contenitore" del dato da estrarre) - * - * -------------------------------------------------------------------------------- */ - /// - /// Vettore della frequenza di ogni status trovato... invio ogni 100 rilevazioni (modulo 100, resto == 1) + /// Generica classe per implementare WebPageScraping (scaricamento web pages anche js-based x recupero informazioni) /// - protected Dictionary freqUnknStatus = new Dictionary(); - /// - /// Pagina web da scaricare - /// - protected string baseUri = "http://127.0.0.1"; - /// - /// Array di configurazione degli oggetti da cercare x decodifica e recupero info - /// - protected Dictionary dataLocatorLUT; - /// - /// Driver per gestione chiamate crawling/scraping - /// - protected IWebDriver driver; - - /// - /// Oggetti decodificati da pagina - /// - protected MonitoredItemsConf monitoredItems; - /// - /// Elementi da recuperare nella apgina web - /// - protected IWebElement element; - - /// - /// Estende l'init della classe base... - /// - /// - /// - public IobWPS(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + public class IobWPS : IobGeneric, IDisposable { - lgInfo("INIT IobWPS"); - //reloadAdapterConf(); - } - /// - /// Ricarica conf adapter... - /// - private void reloadAdapterConf() - { - // init obj display - newDisplayData currDispData = new newDisplayData(); - lgInfo("BEGIN reloadAdapterConf"); - // inizializzo LUT decodifica - string jsonConf = getOptPar("LUT_CONF"); - if (!string.IsNullOrEmpty(jsonConf)) - { - string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{jsonConf}"; - lgInfo($"Apertura file {jsonFullPath}"); - StreamReader reader = new StreamReader(jsonFullPath); - string jsonData = reader.ReadToEnd(); - if (!string.IsNullOrEmpty(jsonData)) + /* -------------------------------------------------------------------------------- + * Controlli dotati di GENERICA pagina WEB in cui cercare e recuperare informazioni + * + * - il file di conf deve contenere l'URL di base + * - il file di conf deve contenere COSA cercare (es il "contenitore" del dato da estrarre) + * + * -------------------------------------------------------------------------------- */ + + /// + /// Vettore della frequenza di ogni status trovato... invio ogni 100 rilevazioni (modulo 100, resto == 1) + /// + protected Dictionary freqUnknStatus = new Dictionary(); + /// + /// Pagina web da scaricare + /// + protected string baseUri = "http://127.0.0.1"; + /// + /// Array di configurazione degli oggetti da cercare x decodifica e recupero info + /// + protected Dictionary dataLocatorLUT; + /// + /// Driver per gestione chiamate crawling/scraping + /// + protected IWebDriver driver; + + /// + /// Oggetti decodificati da pagina + /// + protected MonitoredItemsConf monitoredItems; + /// + /// Elementi da recuperare nella apgina web + /// + protected IWebElement element; + + /// + /// Estende l'init della classe base... + /// + /// + /// + public IobWPS(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) { - try - { - monitoredItems = JsonConvert.DeserializeObject(jsonData); - // salvo baseUri - baseUri = monitoredItems.SrvData.baseUri; - lgInfo($"baseUri = {baseUri}"); - // imposto a zero la bitmap x riavvio! - B_input = 0; - // FORZO invio dati... - accodaSigIN(ref currDispData); - // loggo! - lgInfo($"init input bitmap to zero: {B_input}"); - } - catch (Exception exc) - { - lgError(exc, "Eccezione in decodifica conf json"); - } + lgInfo("INIT IobWPS"); + //reloadAdapterConf(); } - reader.Dispose(); - } - lgInfo("DONE reloadAdapterConf"); - raiseRefresh(currDispData); - } - - #region Metodi specifici (da verificare/completare in implementazione) - - public override void startAdapter(bool resetQueue) - { - // in primis RICARICO conf specifica... - reloadAdapterConf(); - // continuo con start... - base.startAdapter(resetQueue); - } - - /// - /// Override x chiusura driver... - /// - /// - /// - public override void stopAdapter(bool tryRestart, bool forceDequeue) - { - try - { - // in primis chiudo driver... - if (driver != null) + /// + /// Ricarica conf adapter... + /// + private void reloadAdapterConf() { - driver.Quit(); - } - } - catch (Exception exc) - { - lgError(exc, "Eccezione in tryDisconnect"); - } - // continuo - base.stopAdapter(tryRestart, forceDequeue); - } - /// - /// Connessione - /// - public override void tryConnect() - { - // controllo ping --> segno connected... - connectionOk = (testPingMachine == IPStatus.Success); - if (connectionOk) - { - try - { - //var t = TaskEx.Run(() => startDriver()); - //t.Wait(); - // modalità sincrona - startDriver(); - lgInfo("Completato start driver"); - } - catch (Exception exc) - { - lgError(exc, "Eccezione in tryConnect"); - } - } - else - { - // aspetto prima di riprovare... - Thread.Sleep(200); - } - } - /// - /// Avvio del WebDriver - /// - private void startDriver() - { - if (monitoredItems.SrvData.driverName == "CHROME") - { - lgInfo("Starting CHROME Driver"); - // preparo opzione headless x CHROME - var o = new ChromeOptions(); - o.AddArgument("headless"); - ChromeDriverService service = ChromeDriverService.CreateDefaultService(Application.StartupPath); - service.HideCommandPromptWindow = true; - driver = new ChromeDriver(service, o); - } - else - { - lgInfo("Starting FIREFOX Driver"); - // preparo opzione headless x FIREFOX - var o = new FirefoxOptions(); - o.AddArgument("-headless"); - o.SetPreference("app.update.auto", false); - o.SetPreference("app.update.enabled", false); - FirefoxDriverService service = FirefoxDriverService.CreateDefaultService(Application.StartupPath); - service.HideCommandPromptWindow = true; - driver = new FirefoxDriver(service, o); - } - // aggiungo timeout x JScripts - driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(20); - driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(20); - // imposto pagina di acquisizione - driver.Navigate().GoToUrl(baseUri); - } - /// - /// Disconnessione - /// - public override void tryDisconnect() - { - connectionOk = false; - try - { - // in primis chiudo driver... - if (driver != null) - //if (driver != null && driver.WindowHandles.Count > 0) - { - driver.Quit(); - } - } - catch (Exception exc) - { - lgError(exc, "Eccezione in tryDisconnect"); - } - } - /// - /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) - /// - public override void processOverride() - { - } - - /// - /// Recupero dati dinamici in formato dictionary - /// - /// - public override Dictionary getDynData() - { - lgInfo("Chiamata getDynData x IOB WebPageScraping!"); - Dictionary outVal = new Dictionary(); - try - { - /* ---------------------------------------------------------- - * Recupero dalla TUTTE le chiavi richieste... - * */ - - string cKey = ""; - string cVal = ""; - // processo tutti i DynData... - foreach (var item in monitoredItems.DynData) - { - // cerco elemento indicato - element = driver.FindElement(By.Id(item.val)); - cVal = element.Text; - // verifico nome o key... - if (!string.IsNullOrEmpty(item.name)) - { - cKey = item.name; - } - else - { - element = driver.FindElement(By.Id(item.key)); - cKey = element.Text; - } - // controllo se devo inviare (per tipo di dato, x scadenza) - if (monItem2Send(cVal, item)) - { - item.actVal = cVal; - item.DTScad = DateTime.Now.AddSeconds(item.sPeriod); - // accodo! - outVal.Add(cKey, cVal); - } - } - } - catch (Exception exc) - { - lgError(exc, "Errore in getDynData x IOB WPS"); - } - return outVal; - } - - /// - /// Effettua lettura semafori principale - /// Parametri da aggiornare x display in form - /// - public override void readSemafori(ref newDisplayData currDispData) - { - // init a zero... - B_input = 0; - // ciclo! - try - { - // controllo SE il driver SIA attivo... - if (driver != null) - { - string cKey = ""; - string cVal = ""; - // IPOTESI: un UNICO oggetto decodifica status - if (monitoredItems.Status.Count == 1) - { - var item = monitoredItems.Status[0]; - // cerco elemento indicato - element = driver.FindElement(By.Id(item.val)); - cKey = element.Text; - // verifico se mancasse il mapping... - if (!item.codeMapping.ContainsKey(cKey)) + // init obj display + newDisplayData currDispData = new newDisplayData(); + lgInfo("BEGIN reloadAdapterConf"); + // inizializzo LUT decodifica + string jsonConf = getOptPar("LUT_CONF"); + if (!string.IsNullOrEmpty(jsonConf)) { - processUnknStatus(cKey); + string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{jsonConf}"; + lgInfo($"Apertura file {jsonFullPath}"); + StreamReader reader = new StreamReader(jsonFullPath); + string jsonData = reader.ReadToEnd(); + if (!string.IsNullOrEmpty(jsonData)) + { + try + { + monitoredItems = JsonConvert.DeserializeObject(jsonData); + // salvo baseUri + baseUri = monitoredItems.SrvData.baseUri; + lgInfo($"baseUri = {baseUri}"); + // imposto a zero la bitmap x riavvio! + B_input = 0; + // FORZO invio dati... + accodaSigIN(ref currDispData); + // loggo! + lgInfo($"init input bitmap to zero: {B_input}"); + } + catch (Exception exc) + { + lgError(exc, "Eccezione in decodifica conf json"); + } + } + reader.Dispose(); + } + lgInfo("DONE reloadAdapterConf"); + raiseRefresh(currDispData); + } + + #region Metodi specifici (da verificare/completare in implementazione) + + public override void startAdapter(bool resetQueue) + { + // in primis RICARICO conf specifica... + reloadAdapterConf(); + // continuo con start... + base.startAdapter(resetQueue); + } + + /// + /// Override x chiusura driver... + /// + /// + /// + public override void stopAdapter(bool tryRestart, bool forceDequeue) + { + try + { + // in primis chiudo driver... + if (driver != null) + { + driver.Quit(); + } + } + catch (Exception exc) + { + lgError(exc, "Eccezione in tryDisconnect"); + } + // continuo + base.stopAdapter(tryRestart, forceDequeue); + } + /// + /// Connessione + /// + public override void tryConnect() + { + // controllo ping --> segno connected... + connectionOk = (testPingMachine == IPStatus.Success); + if (connectionOk) + { + try + { + //var t = TaskEx.Run(() => startDriver()); + //t.Wait(); + // modalità sincrona + startDriver(); + lgInfo("Completato start driver"); + } + catch (Exception exc) + { + lgError(exc, "Eccezione in tryConnect"); + } } else { - // ora decodifico da variabile status a valore secondo impostazione "codeMapping" - cVal = item.codeMapping[cKey]; - B_input = int.Parse(cVal, System.Globalization.NumberStyles.HexNumber); - currDispData.semIn = Semaforo.SV; + // aspetto prima di riprovare... + Thread.Sleep(200); } - } } - else + /// + /// Avvio del WebDriver + /// + private void startDriver() { - lgError("Errore: driver non pronto (null)"); + if (monitoredItems.SrvData.driverName == "CHROME") + { + lgInfo("Starting CHROME Driver"); + // preparo opzione headless x CHROME + var o = new ChromeOptions(); + o.AddArgument("headless"); + ChromeDriverService service = ChromeDriverService.CreateDefaultService(Application.StartupPath); + service.HideCommandPromptWindow = true; + driver = new ChromeDriver(service, o); + } + else + { + lgInfo("Starting FIREFOX Driver"); + // preparo opzione headless x FIREFOX + var o = new FirefoxOptions(); + o.AddArgument("-headless"); + o.SetPreference("app.update.auto", false); + o.SetPreference("app.update.enabled", false); + FirefoxDriverService service = FirefoxDriverService.CreateDefaultService(Application.StartupPath); + service.HideCommandPromptWindow = true; + driver = new FirefoxDriver(service, o); + } + // aggiungo timeout x JScripts + driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(20); + driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(20); + // imposto pagina di acquisizione + driver.Navigate().GoToUrl(baseUri); } - // riporto bitmap... - reportRawInput(ref currDispData); - } - catch (Exception exc) - { - lgError(exc, "Errore in readSemafori x IOB WPS"); - currDispData.semIn = Semaforo.SR; - } - } - /// - /// Processo stati unknown... - /// - /// - private void processUnknStatus(string cKey) - { - // cerco se avevo già una key nella dictionary... - if (freqUnknStatus.ContainsKey(cKey)) - { - freqUnknStatus[cKey]++; - // se è 1 ogni 100 (%100, resto ==1) --> loggo... - if (freqUnknStatus[cKey] % 100 == 1) + /// + /// Disconnessione + /// + public override void tryDisconnect() + { + connectionOk = false; + try + { + // in primis chiudo driver... + if (driver != null) + //if (driver != null && driver.WindowHandles.Count > 0) + { + driver.Quit(); + } + } + catch (Exception exc) + { + lgError(exc, "Eccezione in tryDisconnect"); + } + } + /// + /// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid) + /// + public override void processOverride() { - lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey} | freq: {freqUnknStatus[cKey]}"); - // accodo come invio di tipo FLOG... - string sVal = string.Format("[UnknStatus] {0}, freq: {1}", cKey, freqUnknStatus); - // chiamo accodamento... - accodaFLog(sVal, qEncodeFLog("UnknStatus", sVal)); } - } - else - { - // creo chiave con freq = 1 - freqUnknStatus.Add(cKey, 1); - // log iniziale - lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey}"); - } - } - #endregion - } + /// + /// Recupero dati dinamici in formato dictionary + /// + /// + public override Dictionary getDynData() + { + lgInfo("Chiamata getDynData x IOB WebPageScraping!"); + Dictionary outVal = new Dictionary(); + try + { + /* ---------------------------------------------------------- + * Recupero dalla TUTTE le chiavi richieste... + * */ + + string cKey = ""; + string cVal = ""; + // processo tutti i DynData... + foreach (var item in monitoredItems.DynData) + { + // cerco elemento indicato + element = driver.FindElement(By.Id(item.val)); + cVal = element.Text; + // verifico nome o key... + if (!string.IsNullOrEmpty(item.name)) + { + cKey = item.name; + } + else + { + element = driver.FindElement(By.Id(item.key)); + cKey = element.Text; + } + // controllo se devo inviare (per tipo di dato, x scadenza) + if (monItem2Send(cVal, item)) + { + item.actVal = cVal; + item.DTScad = DateTime.Now.AddSeconds(item.sPeriod); + // accodo! + outVal.Add(cKey, cVal); + } + } + } + catch (Exception exc) + { + lgError(exc, "Errore in getDynData x IOB WPS"); + } + return outVal; + } + + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + // init a zero... + B_input = 0; + // ciclo! + try + { + // controllo SE il driver SIA attivo... + if (driver != null) + { + string cKey = ""; + string cVal = ""; + // IPOTESI: un UNICO oggetto decodifica status + if (monitoredItems.Status.Count == 1) + { + var item = monitoredItems.Status[0]; + // cerco elemento indicato + element = driver.FindElement(By.Id(item.val)); + cKey = element.Text; + // verifico se mancasse il mapping... + if (!item.codeMapping.ContainsKey(cKey)) + { + processUnknStatus(cKey); + } + else + { + // ora decodifico da variabile status a valore secondo impostazione "codeMapping" + cVal = item.codeMapping[cKey]; + B_input = int.Parse(cVal, System.Globalization.NumberStyles.HexNumber); + if (currDispData != null) + { + currDispData.semIn = Semaforo.SV; + } + } + } + } + else + { + lgError("Errore: driver non pronto (null)"); + } + // riporto bitmap... + reportRawInput(ref currDispData); + } + catch (Exception exc) + { + lgError(exc, "Errore in readSemafori x IOB WPS"); + if (currDispData != null) + currDispData.semIn = Semaforo.SR; + } + } + /// + /// Processo stati unknown... + /// + /// + private void processUnknStatus(string cKey) + { + // cerco se avevo già una key nella dictionary... + if (freqUnknStatus.ContainsKey(cKey)) + { + freqUnknStatus[cKey]++; + // se è 1 ogni 100 (%100, resto ==1) --> loggo... + if (freqUnknStatus[cKey] % 100 == 1) + { + lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey} | freq: {freqUnknStatus[cKey]}"); + // accodo come invio di tipo FLOG... + string sVal = string.Format("[UnknStatus] {0}, freq: {1}", cKey, freqUnknStatus); + // chiamo accodamento... + accodaFLog(sVal, qEncodeFLog("UnknStatus", sVal)); + } + } + else + { + // creo chiave con freq = 1 + freqUnknStatus.Add(cKey, 1); + // log iniziale + lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey}"); + } + } + + public void Dispose() + { + driver.Dispose(); + GC.SuppressFinalize(this); + } + + #endregion + } } diff --git a/IOB-WIN/MainForm.cs b/IOB-WIN/MainForm.cs index 9636209a..e890239e 100644 --- a/IOB-WIN/MainForm.cs +++ b/IOB-WIN/MainForm.cs @@ -237,7 +237,7 @@ namespace IOB_WIN /// /// URL per recuperare i file dell'IOB su CLOUD (SENZA IOB) /// - protected string urlDownloadFileCloud + protected static string urlDownloadFileCloud { get { @@ -264,7 +264,7 @@ namespace IOB_WIN /// /// URL per salvare i file dell'IOB su CLOUD (SENZA IOB) /// - protected string urlUploadFileCloud + protected static string urlUploadFileCloud { get { diff --git a/IOB-WIN/memAddress.cs b/IOB-WIN/memAddress.cs index f547d6f6..0c581f85 100644 --- a/IOB-WIN/memAddress.cs +++ b/IOB-WIN/memAddress.cs @@ -7,130 +7,147 @@ using System.Threading.Tasks; namespace IOB_WIN { - /// - /// Definizione area memoria SIEMENS - /// - public class memAreaSiemens - { /// - /// Indice DB + /// Definizione area memoria SIEMENS /// - public int DbNum = 0; - /// - /// Tipo Memoria (DBD, DBW...) - /// - public string tipoMem = ""; - /// - /// Indice partenza memoria (es DBD0 --> 0) - /// - public int indiceMem = 0; - /// - /// Inizializza da un formato stringa - /// - /// - public memAreaSiemens(string strFormat) + public class memAreaSiemens { - string[] memComp = strFormat.Split('.'); - int.TryParse(memComp[0].Replace("DB", ""), out DbNum); - tipoMem = memComp[1].Substring(2, 1); - int.TryParse(memComp[1].Replace("DB", "").Replace(tipoMem, ""), out indiceMem); + /// + /// Indice DB + /// + public int DbNum = 0; + /// + /// Tipo Memoria (DBD, DBW...) + /// + public string tipoMem = ""; + /// + /// Indice partenza memoria (es DBD0 --> 0) + /// + public int indiceMem = 0; + /// + /// Inizializza da un formato stringa + /// + /// + public memAreaSiemens(string strFormat) + { + if (!string.IsNullOrEmpty(strFormat)) + { + string[] memComp = strFormat.Split('.'); + int.TryParse(memComp[0].Replace("DB", ""), out DbNum); + //tipoMem = memComp[1].Substring(2, 1); + tipoMem = ""; + for (int i = 0; i < memComp[1].Length; i++) + { + if(char.IsLetter(memComp[1][i])) + { + tipoMem += memComp[1][i]; + } + } + // rimuovo DB iniziale.. + tipoMem = tipoMem.Replace("DB", ""); + // ciclo x trovare SOLO stringa + int.TryParse(memComp[1].Replace("DB", "").Replace(tipoMem, ""), out indiceMem); + } + } } - } - /// - /// Definizione area memoria FANUC - /// - public class memAreaFanuc - { /// - /// Nome area memoria + /// Definizione area memoria FANUC /// - public string areaName; - /// - /// Indice inizio array - /// - public int startIdx; - /// - /// Dimensione array memoria - /// - public int arraySize; - } - /// - /// Definizione indirizzo memoria FANUC - /// - public class memAddressFanuc - { - /// - /// Tipo memoria - /// - public FANUC.MemType mType; - /// - /// Posizione memoria - /// - public int mPos; - /// - /// Tipo valore - /// - public string vType; - /// - /// Inizializza da un formato stringa - /// - /// Stringa TipoMem.Indice.DimMem (es D.1604.DW) - public memAddressFanuc(string strFormat) + public class memAreaFanuc { - string[] memComp = strFormat.Split('.'); - switch (memComp[0]) - { - case "A": - mType = FANUC.MemType.A; - break; - case "C": - mType = FANUC.MemType.C; - break; - case "CM": - mType = FANUC.MemType.CM; - break; - case "D": - mType = FANUC.MemType.D; - break; - case "E": - mType = FANUC.MemType.E; - break; - case "F": - mType = FANUC.MemType.F; - break; - case "G": - mType = FANUC.MemType.G; - break; - case "K": - mType = FANUC.MemType.K; - break; - case "M": - mType = FANUC.MemType.M; - break; - case "N": - mType = FANUC.MemType.N; - break; - case "R": - mType = FANUC.MemType.R; - break; - case "T": - mType = FANUC.MemType.T; - break; - case "X": - mType = FANUC.MemType.X; - break; - case "Y": - mType = FANUC.MemType.Y; - break; - case "Z": - mType = FANUC.MemType.Z; - break; - default: - break; - } - int.TryParse(memComp[1], out mPos); - vType = memComp[2]; + /// + /// Nome area memoria + /// + public string areaName; + /// + /// Indice inizio array + /// + public int startIdx; + /// + /// Dimensione array memoria + /// + public int arraySize; + } + /// + /// Definizione indirizzo memoria FANUC + /// + public class memAddressFanuc + { + /// + /// Tipo memoria + /// + public FANUC.MemType mType; + /// + /// Posizione memoria + /// + public int mPos; + /// + /// Tipo valore + /// + public string vType; + /// + /// Inizializza da un formato stringa + /// + /// Stringa TipoMem.Indice.DimMem (es D.1604.DW) + public memAddressFanuc(string strFormat) + { + if (!string.IsNullOrEmpty(strFormat)) + { + string[] memComp = strFormat.Split('.'); + switch (memComp[0]) + { + case "A": + mType = FANUC.MemType.A; + break; + case "C": + mType = FANUC.MemType.C; + break; + case "CM": + mType = FANUC.MemType.CM; + break; + case "D": + mType = FANUC.MemType.D; + break; + case "E": + mType = FANUC.MemType.E; + break; + case "F": + mType = FANUC.MemType.F; + break; + case "G": + mType = FANUC.MemType.G; + break; + case "K": + mType = FANUC.MemType.K; + break; + case "M": + mType = FANUC.MemType.M; + break; + case "N": + mType = FANUC.MemType.N; + break; + case "R": + mType = FANUC.MemType.R; + break; + case "T": + mType = FANUC.MemType.T; + break; + case "X": + mType = FANUC.MemType.X; + break; + case "Y": + mType = FANUC.MemType.Y; + break; + case "Z": + mType = FANUC.MemType.Z; + break; + default: + break; + } + int.TryParse(memComp[1], out mPos); + vType = memComp[2]; + } + } } - } } diff --git a/Jenkinsfile b/Jenkinsfile index 04748931..849779da 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -9,7 +9,7 @@ pipeline { steps { /* calcolo numero versione... diverso x branch MASTER/DEVELOP */ script { - withEnv(['NEXT_BUILD_NUMBER=694']) { + withEnv(['NEXT_BUILD_NUMBER=696']) { // env.versionNumber = VersionNumber(versionNumberString : '3.0.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true) env.versionNumber = VersionNumber(versionNumberString : '3.0.${BUILD_DATE_FORMATTED, "yyMM"}.${BUILDS_ALL_TIME}', projectStartDate : '2006-01-01', skipFailedBuilds: true, overrideBuildsAllTime: '${NEXT_BUILD_NUMBER}') env.APP_NAME = 'MAPO-IOB-WIN' @@ -96,7 +96,7 @@ pipeline { if(env.BRANCH_NAME == "IobMan") { env.classifier = "" // rimuovo vecchio zip... - bat "del /f ${WORKSPACE}\\Releases\\${env.BRANCH_NAME}\\*.zip" + bat "del /f ${WORKSPACE}\\Releases\\${env.BRANCH_NAME}\\*.zip || EXIT /B 0" // Compressione in .zip dell'installer... bat "e:\\7za.exe a -tzip ${WORKSPACE}\\Releases\\${env.BRANCH_NAME}\\MAPO-IOB-MAN.zip ${WORKSPACE}\\IOB-MAN\\bin\\*" // ora mi occupo delle operazioni di invio a NEXUS... diff --git a/SiemensS7/Siemens-S7-Test.sln b/SiemensS7/Siemens-S7-Test.sln new file mode 100644 index 00000000..16c18202 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Siemens-S7-Test", "Siemens-S7-Test\Siemens-S7-Test.csproj", "{A0168CBE-9DA5-4E41-82FF-AFD39C982717}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A0168CBE-9DA5-4E41-82FF-AFD39C982717}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0168CBE-9DA5-4E41-82FF-AFD39C982717}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0168CBE-9DA5-4E41-82FF-AFD39C982717}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0168CBE-9DA5-4E41-82FF-AFD39C982717}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C43DB985-D122-49F0-AE6E-DADEFFC1AD3D} + EndGlobalSection +EndGlobal diff --git a/SiemensS7/Siemens-S7-Test/App.config b/SiemensS7/Siemens-S7-Test/App.config new file mode 100644 index 00000000..8c97693c --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/App.config @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/SiemensS7/Siemens-S7-Test/BinaryFormat.cs b/SiemensS7/Siemens-S7-Test/BinaryFormat.cs new file mode 100644 index 00000000..25dc3365 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/BinaryFormat.cs @@ -0,0 +1,136 @@ +using System; +using System.Globalization; +using System.Numerics; + +namespace Siemens_S7_Test +{ + + public class BinaryFormat : IFormatProvider, ICustomFormatter + { + // IFormatProvider.GetFormat implementation. + public object GetFormat(Type formatType) + { + // Determine whether custom formatting object is requested. + if (formatType == typeof(ICustomFormatter)) + return this; + else + return null; + } + + // Format number in binary (B), octal (O), or hexadecimal (H). + public string Format(string format, object arg, IFormatProvider formatProvider) + { + // Handle format string. + int baseNumber; + // Handle null or empty format string, string with precision specifier. + string thisFmt = String.Empty; + // Extract first character of format string (precision specifiers + // are not supported). + if (!String.IsNullOrEmpty(format)) + thisFmt = format.Length > 1 ? format.Substring(0, 1) : format; + + + // Get a byte array representing the numeric value. + byte[] bytes; + if (arg is sbyte) + { + string byteString = ((sbyte)arg).ToString("X2"); + bytes = new byte[1] { Byte.Parse(byteString, System.Globalization.NumberStyles.HexNumber) }; + } + else if (arg is byte) + { + bytes = new byte[1] { (byte)arg }; + } + else if (arg is short) + { + bytes = BitConverter.GetBytes((short)arg); + } + else if (arg is int) + { + bytes = BitConverter.GetBytes((int)arg); + } + else if (arg is long) + { + bytes = BitConverter.GetBytes((long)arg); + } + else if (arg is ushort) + { + bytes = BitConverter.GetBytes((ushort)arg); + } + else if (arg is uint) + { + bytes = BitConverter.GetBytes((uint)arg); + } + else if (arg is ulong) + { + bytes = BitConverter.GetBytes((ulong)arg); + } + else if (arg is BigInteger) + { + bytes = ((BigInteger)arg).ToByteArray(); + } + else + { + try + { + return HandleOtherFormats(format, arg); + } + catch (FormatException e) + { + throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e); + } + } + + switch (thisFmt.ToUpper()) + { + // Binary formatting. + case "B": + baseNumber = 2; + break; + case "O": + baseNumber = 8; + break; + case "H": + baseNumber = 16; + break; + // Handle unsupported format strings. + default: + try + { + return HandleOtherFormats(format, arg); + } + catch (FormatException e) + { + throw new FormatException(String.Format("The format of '{0}' is invalid.", format), e); + } + } + + // Return a formatted string. + string numericString = String.Empty; + for (int ctr = bytes.GetUpperBound(0); ctr >= bytes.GetLowerBound(0); ctr--) + { + string byteString = Convert.ToString(bytes[ctr], baseNumber); + if (baseNumber == 2) + byteString = new String('0', 8 - byteString.Length) + byteString; + else if (baseNumber == 8) + byteString = new String('0', 4 - byteString.Length) + byteString; + // Base is 16. + else + byteString = new String('0', 2 - byteString.Length) + byteString; + + numericString += byteString + " "; + } + return numericString.Trim(); + } + + private string HandleOtherFormats(string format, object arg) + { + if (arg is IFormattable) + return ((IFormattable)arg).ToString(format, CultureInfo.CurrentCulture); + else if (arg != null) + return arg.ToString(); + else + return String.Empty; + } + } +} diff --git a/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapR.map b/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapR.map new file mode 100644 index 00000000..d6013e48 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapR.map @@ -0,0 +1,14 @@ +# Commenti con cancelletto, struttura un variabile per riga, tipo chiave|valore (occhio che il separatore è configurato da .cofig come "charSep"); spazi e tabulazioni dovrei trimmarli in acquisizione (qui inseriti per comodità di lettura) +# PARAMETRI della DB600 +000|P0_ID |WORD +002|P0_SET_HMI |4BYTE +006|P0_SET_PLC |4BYTE +010|P0_VAL_MAX |4BYTE +014|P0_VAL_MIN |4BYTE +018|P0_UN_MEAS |WORD +020|P1_ID |WORD +022|P1_SET_HMI |4BYTE +026|P1_SET_PLC |4BYTE +030|P1_VAL_MAX |4BYTE +034|P1_VAL_MIN |4BYTE +038|P1_UN_MEAS |WORD \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapW.map b/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapW.map new file mode 100644 index 00000000..28d1ef31 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/DATA/CONF/MMapW.map @@ -0,0 +1,14 @@ +# Commenti con cancelletto, struttura un variabile per riga, tipo chiave|valore (occhio che il separatore è configurato da .cofig come "charSep"); spazi e tabulazioni dovrei trimmarli in acquisizione (qui inseriti per comodità di lettura) +# PARAMETRI della DB600 +000|P0_ID |WORD +002|P0_SET_HMI |4BYTE +006|P0_SET_PLC |4BYTE +010|P0_VAL_MAX |4BYTE +014|P0_VAL_MIN |4BYTE +018|P0_UN_MEAS |WORD +020|P1_ID |WORD +022|P1_SET_HMI |4BYTE +026|P1_SET_PLC |4BYTE +030|P1_VAL_MAX |4BYTE +034|P1_VAL_MIN |4BYTE +038|P1_UN_MEAS |WORD diff --git a/SiemensS7/Siemens-S7-Test/Interfaccia.txt b/SiemensS7/Siemens-S7-Test/Interfaccia.txt new file mode 100644 index 00000000..e77e296a --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Interfaccia.txt @@ -0,0 +1,53 @@ +Interfaccia con TORRI + +DA PLC +- un set di 8 bit di stato macchina + - power on (oppure se vedo spenta...) + - RUN (in lavorazione, semaforo verde) + - contapezzi + - allarme + - in manuale +- un set di 16 byte - 128 allarmi (da confermare) + - ogni bit corrisponde ad un allarme, secondo tabella codificata +- contatori pezzi + - num pz totali + - TempoCiclo ULTIMO pezzo + - bit pezzo buono + - bit pezzo scarto + - bit pezzo da riprendere +- misure + - misura H1 + - misura H2 +- dati macchina + - override speed + - override feed + - giri mandrino pezzo + - giri mandrino mola +- autospegnimento attivo (0=spento, 1 = contapezzi, 2 = fine pallet 1, 3=finepallet 2, 4 = fine pallet 1 & 2) +- num pezzi a spegnimento (SE condizione 1 con contapezzi) +- tempo teorico allo spegnimento + +- bit conferma lettura stringa +- bit conferma lettura inizio commessa +- bit conferma lettura fine commessa + + +VERSO PLC +bit +- bit che indica "nuovi dati stringa da leggere" +- bit inizio commessa +- bit fuine commessa + +stringhe +- codice commessa +- codice articolo +- codice programma +- codice macchina (x controllo coerenza) +- dir programma Fissa su macchcina o parametro +num int +- quantità lotto + + + +ATTENZIONE: letture real devono essere tenute arrotondando alla 4° cifra decimale (NON OLTRE CHE INVENTA) +Avremo 2 DB: 700 scrive PLC, 701 scrive sw esterno \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/NLog.config b/SiemensS7/Siemens-S7-Test/NLog.config new file mode 100644 index 00000000..7a0f3aa1 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/NLog.config @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/SiemensS7/Siemens-S7-Test/NLog.xsd b/SiemensS7/Siemens-S7-Test/NLog.xsd new file mode 100644 index 00000000..2ca3ba82 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/NLog.xsd @@ -0,0 +1,3627 @@ + + + + + + + + + + + + + + + Watch config file for changes and reload automatically. + + + + + Print internal NLog messages to the console. Default value is: false + + + + + Print internal NLog messages to the console error output. Default value is: false + + + + + Write internal NLog messages to the specified file. + + + + + Log level threshold for internal log messages. Default value is: Info. + + + + + Global log level threshold for application log messages. Messages below this level won't be logged. + + + + + Throw an exception when there is an internal error. Default value is: false. Not recommend to set to true in production! + + + + + Throw an exception when there is a configuration error. If not set, determined by throwExceptions. + + + + + Gets or sets a value indicating whether Variables should be kept on configuration reload. Default value is: false. + + + + + Write internal NLog messages to the System.Diagnostics.Trace. Default value is: false. + + + + + Write timestamps for internal NLog messages. Default value is: true. + + + + + Use InvariantCulture as default culture instead of CurrentCulture. Default value is: false. + + + + + Perform message template parsing and formatting of LogEvent messages (true = Always, false = Never, empty = Auto Detect). Default value is: empty. + + + + + + + + + + + + + + Make all targets within this section asynchronous (creates additional threads but the calling thread isn't blocked by any target writes). + + + + + + + + + + + + + + + + + Prefix for targets/layout renderers/filters/conditions loaded from this assembly. + + + + + Load NLog extensions from the specified file (*.dll) + + + + + Load NLog extensions from the specified assembly. Assembly name should be fully qualified. + + + + + + + + + + Name of the logger. May include wildcard characters ('*' or '?'). + + + + + Comma separated list of levels that this rule matches. + + + + + Minimum level that this rule matches. + + + + + Maximum level that this rule matches. + + + + + Level that this rule matches. + + + + + Comma separated list of target names. + + + + + Ignore further rules if this one matches. + + + + + Rule identifier to allow rule lookup with Configuration.FindRuleByName and Configuration.RemoveRuleByName. + + + + + + + + + + + + + + + Default action if none of the filters match. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the file to be included. You could use * wildcard. The name is relative to the name of the current config file. + + + + + Ignore any errors in the include file. + + + + + + + + Variable value. Note, the 'value' attribute has precedence over this one. + + + + + + Variable name. + + + + + Variable value. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events that should be processed in a batch by the lazy writer thread. + + + + + Whether to use the locking queue, instead of a lock-free concurrent queue The locking queue is less concurrent when many logger threads, but reduces memory allocation + + + + + Limit of full s to write before yielding into Performance is better when writing many small batches, than writing a single large batch + + + + + Action to be taken when the lazy writer thread request queue count exceeds the set limit. + + + + + Limit on the number of requests in the lazy writer thread request queue. + + + + + Time in milliseconds to sleep between batches. (1 or less means trigger on new activity) + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + Delay the flush until the LogEvent has been confirmed as written + + + + + Condition expression. Log events who meet this condition will cause a flush on the wrapped target. + + + + + Only flush when LogEvent matches condition. Ignore explicit-flush, config-reload-flush and shutdown-flush + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Number of log events to be buffered. + + + + + Timeout (in milliseconds) after which the contents of buffer will be flushed if there's no write in the specified period of time. Use -1 to disable timed flushes. + + + + + Action to take if the buffer overflows. + + + + + Indicates whether to use sliding timeout. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Encoding to be used. + + + + + Instance of that is used to format log messages. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Get or set the SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Network address. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Maximum queue size. + + + + + Maximum current connections. 0 = no maximum. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Indicates whether to keep connection open whenever possible. + + + + + NDLC item separator. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include stack contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Option to include all properties from the log events + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + NDC item separator. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Viewer parameter name. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-check if the console is available. - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + Enables output using ANSI Color Codes + + + + + The encoding for writing messages to the . + + + + + Indicates whether the error stream (stderr) should be used instead of the output stream (stdout). + + + + + Indicates whether to auto-flush after + + + + + Indicates whether to auto-check if the console has been redirected to file - Disables coloring logic when System.Console.IsOutputRedirected = true + + + + + Indicates whether to use default row highlighting rules. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Condition that must be met in order to set the specified foreground and background color. + + + + + Background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + Compile the ? This can improve the performance, but at the costs of more memory usage. If false, the Regex Cache is used. + + + + + Indicates whether to ignore case when comparing texts. + + + + + Regular expression to be matched. You must specify either text or regex. + + + + + Text to be matched. You must specify either text or regex. + + + + + Indicates whether to match whole words only. + + + + + Background color. + + + + + Foreground color. + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether to auto-flush after + + + + + Indicates whether to auto-check if the console is available - Disables console writing if Environment.UserInteractive = False (Windows Service) - Disables console writing if Console Standard Input is not available (Non-Console-App) + + + + + The encoding for writing messages to the . + + + + + Indicates whether to send the log messages to the standard error instead of the standard output. + + + + + Whether to enable batch writing using char[]-buffers, instead of using + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Obsolete - value will be ignored! The logging code always runs outside of transaction. Gets or sets a value indicating whether to use database transactions. Some data providers require this. + + + + + Indicates whether to keep the database connection open between the log events. + + + + + Name of the database provider. + + + + + Database password. If the ConnectionString is not provided this value will be used to construct the "Password=" part of the connection string. + + + + + Database host name. If the ConnectionString is not provided this value will be used to construct the "Server=" part of the connection string. + + + + + Database user name. If the ConnectionString is not provided this value will be used to construct the "User ID=" part of the connection string. + + + + + Name of the connection string (as specified in <connectionStrings> configuration section. + + + + + Connection string. When provided, it overrides the values specified in DBHost, DBUserName, DBPassword, DBDatabase. + + + + + Database name. If the ConnectionString is not provided this value will be used to construct the "Database=" part of the connection string. + + + + + Connection string using for installation and uninstallation. If not provided, regular ConnectionString is being used. + + + + + Configures isolated transaction batch writing. If supported by the database, then it will improve insert performance. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Text of the SQL command to be run on each log level. + + + + + Type of the SQL command to be run on each log level. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Convert format of the property value + + + + + Culture used for parsing property string-value for type-conversion + + + + + Value to assign on the object-property + + + + + Name for the object-property + + + + + Type of the object-property + + + + + + + + + + + + + + Type of the command. + + + + + Connection string to run the command against. If not provided, connection string from the target is used. + + + + + Indicates whether to ignore failures. + + + + + Command text. + + + + + + + + + + + + + + + + + + Database parameter name. + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Database parameter DbType. + + + + + Database parameter size. + + + + + Database parameter precision. + + + + + Database parameter scale. + + + + + Type of the parameter. + + + + + Convert format of the database parameter value. + + + + + Culture used for parsing parameter string-value for type-conversion + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Layout that renders event Category. + + + + + Optional entry type. When not set, or when not convertible to then determined by + + + + + Layout that renders event ID. + + + + + Name of the Event Log to write to. This can be System, Application or any user-defined name. + + + + + Name of the machine on which Event Log service is running. + + + + + Maximum Event log size in kilobytes. + + + + + Message length limit to write to the Event Log. + + + + + Value to be used as the event Source. + + + + + Action to take if the message is larger than the option. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether to return to the first target after any successful write. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + File encoding. + + + + + Line ending mode. + + + + + Maximum days of archive files that should be kept. + + + + + Indicates whether to compress archive files into the zip archive format. + + + + + Way file archives are numbered. + + + + + Name of the file to be used for an archive. + + + + + Is the an absolute or relative path? + + + + + Indicates whether to automatically archive log files every time the specified time passes. + + + + + Size in bytes above which log files will be automatically archived. Warning: combining this with isn't supported. We cannot create multiple archive files, if they should have the same name. Choose: + + + + + Maximum number of archive files that should be kept. + + + + + Indicates whether the footer should be written only when the file is archived. + + + + + Maximum number of log file names that should be stored as existing. + + + + + Indicates whether to delete old log file on startup. + + + + + File attributes (Windows only). + + + + + Indicates whether to create directories if they do not exist. + + + + + Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + + + Value of the file size threshold to archive old log file on startup. + + + + + Indicates whether to archive old log file on startup. + + + + + Value specifying the date format to use when archiving files. + + + + + Indicates whether to enable log file(s) to be deleted. + + + + + Indicates whether to write BOM (byte order mark) in created files + + + + + Indicates whether to replace file contents on each write instead of appending log message at the end. + + + + + Indicates whether file creation calls should be synchronized by a system global mutex. + + + + + Gets or set a value indicating whether a managed file stream is forced, instead of using the native implementation. + + + + + Is the an absolute or relative path? + + + + + Name of the file to write to. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Indicates whether concurrent writes to the log file by multiple processes on different network hosts. + + + + + Maximum number of seconds that files are kept open. If this number is negative the files are not automatically closed after a period of inactivity. + + + + + Number of files to be kept open. Setting this to a higher value may improve performance in a situation where a single File target is writing to many files (such as splitting by level or by logger). + + + + + Indicates whether to keep log file open instead of opening and closing it on each logging event. + + + + + Whether or not this target should just discard all data that its asked to write. Mostly used for when testing NLog Stack except final write + + + + + Indicates whether concurrent writes to the log file by multiple processes on the same host. + + + + + Number of times the write is appended on the file before NLog discards the log message. + + + + + Delay in milliseconds to wait before attempting to write to the file again. + + + + + Log file buffer size in bytes. + + + + + Maximum number of seconds before open files are flushed. If this number is negative or zero the files are not flushed by timer. + + + + + Indicates whether to automatically flush the file buffers after each log message. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Condition expression. Log events who meet this condition will be forwarded to the wrapped target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Windows domain name to change context to. + + + + + Required impersonation level. + + + + + Type of the logon provider. + + + + + Logon Type. + + + + + User account password. + + + + + Indicates whether to revert to the credentials of the process instead of impersonating another user. + + + + + Username to change context to. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Interval in which messages will be written up to the number of messages. + + + + + Maximum allowed number of messages written per . + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Endpoint address. + + + + + Name of the endpoint configuration in WCF configuration file. + + + + + Indicates whether to use a WCF service contract that is one way (fire and forget) or two way (request-reply) + + + + + Client ID. + + + + + Indicates whether to include per-event properties in the payload sent to the server. + + + + + Indicates whether to use binary message encoding. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + Layout that should be use to calculate the value for the parameter. + + + + + Name of the parameter. + + + + + Type of the parameter. + + + + + Type of the parameter. Obsolete alias for + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Text to be rendered. + + + + + Header. + + + + + Footer. + + + + + Indicates whether NewLine characters in the body should be replaced with tags. + + + + + Priority used for sending mails. + + + + + Encoding to be used for sending e-mail. + + + + + BCC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + CC email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Indicates whether to add new lines between log entries. + + + + + Indicates whether to send message as HTML instead of plain text. + + + + + Sender's email address (e.g. joe@domain.com). + + + + + Mail message body (repeated for each log message send in one mail). + + + + + Mail subject. + + + + + Recipients' email addresses separated by semicolons (e.g. john@domain.com;jane@domain.com). + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Indicates the SMTP client timeout. + + + + + SMTP Server to be used for sending. + + + + + SMTP Authentication mode. + + + + + Username used to connect to SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Password used to authenticate against SMTP server (used when SmtpAuthentication is set to "basic"). + + + + + Indicates whether SSL (secure sockets layer) should be used when communicating with SMTP server. + + + + + Port number that SMTP Server is listening on. + + + + + Indicates whether the default Settings from System.Net.MailSettings should be used. + + + + + Folder where applications save mail messages to be processed by the local SMTP server. + + + + + Specifies how outgoing email messages will be handled. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Max number of items to have in memory + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Class name. + + + + + Method name. The method must be public and static. Use the AssemblyQualifiedName , https://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx e.g. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Encoding to be used. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Network address. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Indicates whether to keep connection open whenever possible. + + + + + Maximum current connections. 0 = no maximum. + + + + + Maximum queue size. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Get or set the SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Encoding to be used. + + + + + Instance of that is used to format log messages. + + + + + End of line value if a newline is appended at the end of log message . + + + + + Maximum message size in bytes. + + + + + Indicates whether to append newline at the end of log message. + + + + + Get or set the SSL/TLS protocols. Default no SSL/TLS is used. Currently only implemented for TCP. + + + + + Network address. + + + + + Size of the connection cache (number of connections which are kept alive). + + + + + The number of seconds a connection will remain idle before the first keep-alive probe is sent + + + + + Maximum queue size. + + + + + Maximum current connections. 0 = no maximum. + + + + + Action that should be taken if the will be more connections than . + + + + + Action that should be taken if the message is larger than maxMessageSize. + + + + + Indicates whether to keep connection open whenever possible. + + + + + NDLC item separator. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + Renderer for log4j:event logger-xml-attribute (Default ${logger}) + + + + + Indicates whether to include NLog-specific extensions to log4j schema. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include stack contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include dictionary contents. + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Option to include all properties from the log events + + + + + AppInfo field. By default it's the friendly name of the current AppDomain. + + + + + NDC item separator. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Indicates whether to perform layout calculation. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Indicates whether performance counter should be automatically created. + + + + + Name of the performance counter category. + + + + + Counter help text. + + + + + Name of the performance counter. + + + + + Performance counter type. + + + + + The value by which to increment the counter. + + + + + Performance counter instance name. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Default filter to be applied when no specific rule matches. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + Condition to be tested. + + + + + Resulting filter to be applied when the condition matches. + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Number of times to repeat each log message. + + + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Number of retries that should be attempted on the wrapped target in case of a failure. + + + + + Time to wait between retries in milliseconds. + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Layout used to format log messages. + + + + + Forward to (Instead of ) + + + + + Always use independent of + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Name of the target. + + + + + Target supports reuse of internal buffers, and doesn't have to constantly allocate new buffers Required for legacy NLog-targets, that expects buffers to remain stable after Write-method exit + + + + + Should we include the BOM (Byte-order-mark) for UTF? Influences the property. This will only work for UTF-8. + + + + + Web service method name. Only used with Soap. + + + + + Web service namespace. Only used with Soap. + + + + + Protocol to be used when calling web service. + + + + + Custom proxy address, include port separated by a colon + + + + + Encoding. + + + + + Web service URL. + + + + + Value whether escaping be done according to the old NLog style (Very non-standard) + + + + + Value whether escaping be done according to Rfc3986 (Supports Internationalized Resource Identifiers - IRIs) + + + + + Indicates whether to pre-authenticate the HttpWebRequest (Requires 'Authorization' in parameters) + + + + + Name of the root XML element, if POST of XML document chosen. If so, this property must not be null. (see and ). + + + + + (optional) root namespace of the XML document, if POST of XML document chosen. (see and ). + + + + + Proxy configuration when calling web service + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + Custom column delimiter value (valid when ColumnDelimiter is set to 'Custom'). + + + + + Column delimiter. + + + + + Quote Character. + + + + + Quoting mode. + + + + + Indicates whether CVS should include header. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Layout of the column. + + + + + Name of the column. + + + + + Override of Quoting mode + + + + + + + + + + + + + + + + + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Option to render the empty object value {} + + + + + Option to suppress the extra spaces in the output json + + + + + List of property names to exclude when is true + + + + + Option to include all properties from the log event (as JSON) + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + How far should the JSON serializer follow object references before backing off + + + + + + + + + + + + + + + + + Layout that will be rendered as the attribute's value. + + + + + Name of the attribute. + + + + + Determines whether or not this attribute will be Json encoded. + + + + + Should forward slashes be escaped? If true, / will be converted to \/ + + + + + Indicates whether to escape non-ascii characters + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + Footer layout. + + + + + Header layout. + + + + + Body layout (can be repeated multiple times). + + + + + + + + + + + + + + + + + + + + + Option to include all properties from the log events + + + + + Indicates whether to include call site (class and method name) in the information sent over the network. + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include contents of the stack. + + + + + Indicates whether to include source info (file name and line number) in the information sent over the network. + + + + + + + + + + + + + + Layout text. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + List of property names to exclude when is true + + + + + Option to include all properties from the log event (as XML) + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + Name of the root XML element + + + + + Value inside the root XML element + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + + + + + + + + + + + Layout that will be rendered as the attribute's value. + + + + + Name of the attribute. + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Whether an attribute with empty value should be included in the output + + + + + + + + + + + + + + + + + + + + + + + + + Determines whether or not this attribute will be Xml encoded. + + + + + Name of the element + + + + + Value inside the element + + + + + Whether a ElementValue with empty value should be included in the output + + + + + Auto indent and create new lines + + + + + List of property names to exclude when is true + + + + + Option to include all properties from the log event (as XML) + + + + + Indicates whether to include contents of the dictionary. + + + + + Indicates whether to include contents of the dictionary. + + + + + How far should the XML serializer follow object references before backing off + + + + + XML element name to use for rendering IList-collections items + + + + + XML attribute name to use when rendering property-key When null (or empty) then key-attribute is not included + + + + + XML element name to use when rendering properties + + + + + XML attribute name to use when rendering property-value When null (or empty) then value-attribute is not included and value is formatted as XML-element-value + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Condition expression. + + + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + Substring to be matched. + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + String to compare the layout to. + + + + + Indicates whether to ignore case when comparing strings. + + + + + Layout to be used to filter log messages. + + + + + + + + + + + + + + + + + + + + + + + + Action to be taken when filter matches. + + + + + Default number of unique filter values to expect, will automatically increase if needed + + + + + Applies the configured action to the initial logevent that starts the timeout period. Used to configure that it should ignore all events until timeout. + + + + + Layout to be used to filter log messages. + + + + + Max number of unique filter values to expect simultaneously + + + + + Max length of filter values, will truncate if above limit + + + + + How long before a filter expires, and logging is accepted again + + + + + Default buffer size for the internal buffers + + + + + Reuse internal buffers, and doesn't have to constantly allocate new buffers + + + + + Append FilterCount to the when an event is no longer filtered + + + + + Insert FilterCount value into when an event is no longer filtered + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/Program.cs b/SiemensS7/Siemens-S7-Test/Program.cs new file mode 100644 index 00000000..b33b15f4 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Program.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace Siemens_S7_Test +{ + static class Program + { + /// + /// Punto di ingresso principale dell'applicazione. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new TestMainForm()); + } + } +} diff --git a/SiemensS7/Siemens-S7-Test/Properties/AssemblyInfo.cs b/SiemensS7/Siemens-S7-Test/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3d8e5f26 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Le informazioni generali relative a un assembly sono controllate dal seguente +// set di attributi. Modificare i valori di questi attributi per modificare le informazioni +// associate a un assembly. +[assembly: AssemblyTitle("Test-S7")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Test-S7")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Se si imposta ComVisible su false, i tipi in questo assembly non saranno visibili +// ai componenti COM. Se è necessario accedere a un tipo in questo assembly da +// COM, impostare su true l'attributo ComVisible per tale tipo. +[assembly: ComVisible(false)] + +// Se il progetto viene esposto a COM, il GUID seguente verrà utilizzato come ID della libreria dei tipi +[assembly: Guid("a0168cbe-9da5-4e41-82ff-afd39c982717")] + +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Versione principale +// Versione secondaria +// Numero di build +// Revisione +// +// È possibile specificare tutti i valori oppure impostare valori predefiniti per i numeri relativi alla revisione e alla build +// usando l'asterisco '*' come illustrato di seguito: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/SiemensS7/Siemens-S7-Test/Properties/Resources.Designer.cs b/SiemensS7/Siemens-S7-Test/Properties/Resources.Designer.cs new file mode 100644 index 00000000..eeae1c81 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Siemens_S7_Test.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Siemens_S7_Test.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/SiemensS7/Siemens-S7-Test/Properties/Resources.resx b/SiemensS7/Siemens-S7-Test/Properties/Resources.resx new file mode 100644 index 00000000..af7dbebb --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/Properties/Settings.Designer.cs b/SiemensS7/Siemens-S7-Test/Properties/Settings.Designer.cs new file mode 100644 index 00000000..49be6d85 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Siemens_S7_Test.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.5.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/SiemensS7/Siemens-S7-Test/Properties/Settings.settings b/SiemensS7/Siemens-S7-Test/Properties/Settings.settings new file mode 100644 index 00000000..39645652 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/SiemensS7/Siemens-S7-Test/Siemens-S7-Test.csproj b/SiemensS7/Siemens-S7-Test/Siemens-S7-Test.csproj new file mode 100644 index 00000000..30c9ebeb --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/Siemens-S7-Test.csproj @@ -0,0 +1,128 @@ + + + + + Debug + AnyCPU + {A0168CBE-9DA5-4E41-82FF-AFD39C982717} + WinExe + Siemens_S7_Test + Siemens-S7-Test + v4.6.2 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\NLog.4.7.0\lib\net45\NLog.dll + + + ..\packages\S7netplus.0.4.0\lib\net452\S7.Net.dll + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + TestMainForm.cs + + + + + + + + TestMainForm.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + Always + + + PreserveNewest + + + Always + + + Always + + + Designer + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + Always + + + Always + + + + + + + + + + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/TestMainForm.Designer.cs b/SiemensS7/Siemens-S7-Test/TestMainForm.Designer.cs new file mode 100644 index 00000000..1c936e28 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/TestMainForm.Designer.cs @@ -0,0 +1,878 @@ +namespace Siemens_S7_Test +{ + partial class TestMainForm + { + /// + /// Variabile di progettazione necessaria. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Pulire le risorse in uso. + /// + /// ha valore true se le risorse gestite devono essere eliminate, false in caso contrario. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Codice generato da Progettazione Windows Form + + /// + /// Metodo necessario per il supporto della finestra di progettazione. Non modificare + /// il contenuto del metodo con l'editor di codice. + /// + private void InitializeComponent() + { + this.txtIP = new System.Windows.Forms.TextBox(); + this.lblIP = new System.Windows.Forms.Label(); + this.cbCpuType = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtMemArea = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtMemSize = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.txtNumRep = new System.Windows.Forms.TextBox(); + this.label13 = new System.Windows.Forms.Label(); + this.btnReadStruct = new System.Windows.Forms.Button(); + this.btnReadString = new System.Windows.Forms.Button(); + this.btnReadDWord = new System.Windows.Forms.Button(); + this.btnReadWord = new System.Windows.Forms.Button(); + this.btnReadReal = new System.Windows.Forms.Button(); + this.btnReadByte = new System.Windows.Forms.Button(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.label11 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.txtSlot = new System.Windows.Forms.TextBox(); + this.label5 = new System.Windows.Forms.Label(); + this.txtRack = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.tslConn = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripStatusLabel1 = new System.Windows.Forms.ToolStripStatusLabel(); + this.toolStripProgressBar1 = new System.Windows.Forms.ToolStripProgressBar(); + this.tslRTime = new System.Windows.Forms.ToolStripStatusLabel(); + this.groupBox4 = new System.Windows.Forms.GroupBox(); + this.btnStrWrite = new System.Windows.Forms.Button(); + this.btnNumWriteB = new System.Windows.Forms.Button(); + this.btnNumWriteDW = new System.Windows.Forms.Button(); + this.btnNumWriteW = new System.Windows.Forms.Button(); + this.txtWriteVal2 = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.txtWriteVal1 = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.txtWriteAddr2 = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.txtWriteAddr1 = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.txtOut = new System.Windows.Forms.TextBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.tabCtrl = new System.Windows.Forms.TabControl(); + this.tabReadTest = new System.Windows.Forms.TabPage(); + this.tabWriteTest = new System.Windows.Forms.TabPage(); + this.tabParam = new System.Windows.Forms.TabPage(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.lblThroughtput = new System.Windows.Forms.Label(); + this.label18 = new System.Windows.Forms.Label(); + this.lblTotSize = new System.Windows.Forms.Label(); + this.lblTimeMin = new System.Windows.Forms.Label(); + this.lblTimeMax = new System.Windows.Forms.Label(); + this.lblTimeAvg = new System.Windows.Forms.Label(); + this.label16 = new System.Windows.Forms.Label(); + this.label15 = new System.Windows.Forms.Label(); + this.label14 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.cmbOutType = new System.Windows.Forms.ComboBox(); + this.groupBox1.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.statusStrip1.SuspendLayout(); + this.groupBox4.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.tabCtrl.SuspendLayout(); + this.tabReadTest.SuspendLayout(); + this.tabWriteTest.SuspendLayout(); + this.tabParam.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.SuspendLayout(); + // + // txtIP + // + this.txtIP.Location = new System.Drawing.Point(85, 23); + this.txtIP.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtIP.Name = "txtIP"; + this.txtIP.Size = new System.Drawing.Size(109, 22); + this.txtIP.TabIndex = 0; + this.txtIP.Text = "192.168.0.102"; + this.txtIP.TextChanged += new System.EventHandler(this.txtIP_TextChanged); + // + // lblIP + // + this.lblIP.AutoSize = true; + this.lblIP.Location = new System.Drawing.Point(16, 26); + this.lblIP.Name = "lblIP"; + this.lblIP.Size = new System.Drawing.Size(63, 17); + this.lblIP.TabIndex = 1; + this.lblIP.Text = "IP ADDR"; + // + // cbCpuType + // + this.cbCpuType.FormattingEnabled = true; + this.cbCpuType.Items.AddRange(new object[] { + "S7200", + "S7300", + "S7400", + "S71200", + "S71500"}); + this.cbCpuType.Location = new System.Drawing.Point(85, 62); + this.cbCpuType.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.cbCpuType.Name = "cbCpuType"; + this.cbCpuType.Size = new System.Drawing.Size(109, 24); + this.cbCpuType.TabIndex = 2; + this.cbCpuType.Text = "S71500"; + this.cbCpuType.SelectedIndexChanged += new System.EventHandler(this.cbCpuType_SelectedIndexChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 64); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(72, 17); + this.label1.TabIndex = 3; + this.label1.Text = "CPU Type"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 23); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(80, 17); + this.label2.TabIndex = 5; + this.label2.Text = "MEM AREA"; + // + // txtMemArea + // + this.txtMemArea.Location = new System.Drawing.Point(148, 20); + this.txtMemArea.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtMemArea.Name = "txtMemArea"; + this.txtMemArea.Size = new System.Drawing.Size(101, 22); + this.txtMemArea.TabIndex = 4; + this.txtMemArea.Text = "DB600.DBB20"; + this.txtMemArea.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.txtMemArea.TextChanged += new System.EventHandler(this.txtMemArea_TextChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(9, 52); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(123, 17); + this.label3.TabIndex = 7; + this.label3.Text = "MEM SIZE (BYTE)"; + // + // txtMemSize + // + this.txtMemSize.Location = new System.Drawing.Point(148, 50); + this.txtMemSize.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtMemSize.Name = "txtMemSize"; + this.txtMemSize.Size = new System.Drawing.Size(101, 22); + this.txtMemSize.TabIndex = 6; + this.txtMemSize.Text = "200"; + this.txtMemSize.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + this.txtMemSize.TextChanged += new System.EventHandler(this.txtMemSize_TextChanged); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cmbOutType); + this.groupBox1.Controls.Add(this.txtNumRep); + this.groupBox1.Controls.Add(this.label13); + this.groupBox1.Controls.Add(this.btnReadStruct); + this.groupBox1.Controls.Add(this.btnReadString); + this.groupBox1.Controls.Add(this.btnReadDWord); + this.groupBox1.Controls.Add(this.btnReadWord); + this.groupBox1.Controls.Add(this.btnReadReal); + this.groupBox1.Controls.Add(this.btnReadByte); + this.groupBox1.Controls.Add(this.txtMemArea); + this.groupBox1.Controls.Add(this.txtMemSize); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Location = new System.Drawing.Point(6, 5); + this.groupBox1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox1.Size = new System.Drawing.Size(672, 105); + this.groupBox1.TabIndex = 8; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Memoria: READ testing"; + // + // txtNumRep + // + this.txtNumRep.Location = new System.Drawing.Point(148, 76); + this.txtNumRep.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtNumRep.Name = "txtNumRep"; + this.txtNumRep.Size = new System.Drawing.Size(101, 22); + this.txtNumRep.TabIndex = 14; + this.txtNumRep.Text = "1"; + this.txtNumRep.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(9, 79); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(72, 17); + this.label13.TabIndex = 15; + this.label13.Text = "# samples"; + // + // btnReadStruct + // + this.btnReadStruct.Location = new System.Drawing.Point(405, 75); + this.btnReadStruct.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadStruct.Name = "btnReadStruct"; + this.btnReadStruct.Size = new System.Drawing.Size(110, 25); + this.btnReadStruct.TabIndex = 12; + this.btnReadStruct.Text = "Read Struc"; + this.btnReadStruct.TextImageRelation = System.Windows.Forms.TextImageRelation.TextAboveImage; + this.btnReadStruct.UseVisualStyleBackColor = true; + this.btnReadStruct.Click += new System.EventHandler(this.btnReadStruct_Click); + // + // btnReadString + // + this.btnReadString.Location = new System.Drawing.Point(405, 49); + this.btnReadString.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadString.Name = "btnReadString"; + this.btnReadString.Size = new System.Drawing.Size(110, 25); + this.btnReadString.TabIndex = 11; + this.btnReadString.Text = "Read String"; + this.btnReadString.UseVisualStyleBackColor = true; + this.btnReadString.Click += new System.EventHandler(this.btnReadString_Click); + // + // btnReadDWord + // + this.btnReadDWord.Location = new System.Drawing.Point(289, 75); + this.btnReadDWord.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadDWord.Name = "btnReadDWord"; + this.btnReadDWord.Size = new System.Drawing.Size(110, 25); + this.btnReadDWord.TabIndex = 10; + this.btnReadDWord.Text = "Read DWord"; + this.btnReadDWord.TextImageRelation = System.Windows.Forms.TextImageRelation.TextAboveImage; + this.btnReadDWord.UseVisualStyleBackColor = true; + this.btnReadDWord.Click += new System.EventHandler(this.btnReadDWord_Click); + // + // btnReadWord + // + this.btnReadWord.Location = new System.Drawing.Point(289, 48); + this.btnReadWord.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadWord.Name = "btnReadWord"; + this.btnReadWord.Size = new System.Drawing.Size(110, 25); + this.btnReadWord.TabIndex = 10; + this.btnReadWord.Text = "Read Word"; + this.btnReadWord.UseVisualStyleBackColor = true; + this.btnReadWord.Click += new System.EventHandler(this.btnReadWord_Click); + // + // btnReadReal + // + this.btnReadReal.Location = new System.Drawing.Point(405, 19); + this.btnReadReal.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadReal.Name = "btnReadReal"; + this.btnReadReal.Size = new System.Drawing.Size(110, 25); + this.btnReadReal.TabIndex = 9; + this.btnReadReal.Text = "Read Real"; + this.btnReadReal.UseVisualStyleBackColor = true; + this.btnReadReal.Click += new System.EventHandler(this.btnReadReal_Click); + // + // btnReadByte + // + this.btnReadByte.Location = new System.Drawing.Point(289, 19); + this.btnReadByte.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnReadByte.Name = "btnReadByte"; + this.btnReadByte.Size = new System.Drawing.Size(110, 25); + this.btnReadByte.TabIndex = 9; + this.btnReadByte.Text = "Read Byte"; + this.btnReadByte.UseVisualStyleBackColor = true; + this.btnReadByte.Click += new System.EventHandler(this.btnReadByte_Click); + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.label11); + this.groupBox3.Controls.Add(this.label6); + this.groupBox3.Controls.Add(this.txtSlot); + this.groupBox3.Controls.Add(this.label5); + this.groupBox3.Controls.Add(this.txtRack); + this.groupBox3.Controls.Add(this.label4); + this.groupBox3.Controls.Add(this.cbCpuType); + this.groupBox3.Controls.Add(this.txtIP); + this.groupBox3.Controls.Add(this.lblIP); + this.groupBox3.Controls.Add(this.label1); + this.groupBox3.Location = new System.Drawing.Point(6, 5); + this.groupBox3.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox3.Size = new System.Drawing.Size(479, 105); + this.groupBox3.TabIndex = 10; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Parametri PLC"; + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(301, 39); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(148, 51); + this.label11.TabIndex = 7; + this.label11.Text = "S7-1200/S7-1500: 0/1\r\nS7-300/S7-400: 0/2\r\nSlot > 0 se eth ext"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(301, 14); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(114, 17); + this.label6.TabIndex = 6; + this.label6.Text = "Note Rack / Slot:"; + // + // txtSlot + // + this.txtSlot.Location = new System.Drawing.Point(253, 62); + this.txtSlot.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtSlot.Name = "txtSlot"; + this.txtSlot.Size = new System.Drawing.Size(41, 22); + this.txtSlot.TabIndex = 5; + this.txtSlot.Text = "1"; + this.txtSlot.TextChanged += new System.EventHandler(this.txtSlot_TextChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(208, 64); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(32, 17); + this.label5.TabIndex = 4; + this.label5.Text = "Slot"; + // + // txtRack + // + this.txtRack.Location = new System.Drawing.Point(253, 23); + this.txtRack.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtRack.Name = "txtRack"; + this.txtRack.Size = new System.Drawing.Size(41, 22); + this.txtRack.TabIndex = 5; + this.txtRack.Text = "0"; + this.txtRack.TextChanged += new System.EventHandler(this.txtRack_TextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(208, 26); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(40, 17); + this.label4.TabIndex = 4; + this.label4.Text = "Rack"; + // + // statusStrip1 + // + this.statusStrip1.ImageScalingSize = new System.Drawing.Size(20, 20); + this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.tslConn, + this.toolStripStatusLabel1, + this.toolStripProgressBar1, + this.tslRTime}); + this.statusStrip1.Location = new System.Drawing.Point(0, 583); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Padding = new System.Windows.Forms.Padding(1, 0, 13, 0); + this.statusStrip1.Size = new System.Drawing.Size(906, 28); + this.statusStrip1.TabIndex = 11; + this.statusStrip1.Text = "statusStrip1"; + // + // tslConn + // + this.tslConn.Name = "tslConn"; + this.tslConn.Size = new System.Drawing.Size(72, 22); + this.tslConn.Text = "Conn: ND"; + // + // toolStripStatusLabel1 + // + this.toolStripStatusLabel1.Name = "toolStripStatusLabel1"; + this.toolStripStatusLabel1.Size = new System.Drawing.Size(13, 22); + this.toolStripStatusLabel1.Text = "|"; + // + // toolStripProgressBar1 + // + this.toolStripProgressBar1.Name = "toolStripProgressBar1"; + this.toolStripProgressBar1.Size = new System.Drawing.Size(100, 20); + // + // tslRTime + // + this.tslRTime.Name = "tslRTime"; + this.tslRTime.Size = new System.Drawing.Size(37, 22); + this.tslRTime.Text = "...ms"; + // + // groupBox4 + // + this.groupBox4.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.groupBox4.Controls.Add(this.btnStrWrite); + this.groupBox4.Controls.Add(this.btnNumWriteB); + this.groupBox4.Controls.Add(this.btnNumWriteDW); + this.groupBox4.Controls.Add(this.btnNumWriteW); + this.groupBox4.Controls.Add(this.txtWriteVal2); + this.groupBox4.Controls.Add(this.label9); + this.groupBox4.Controls.Add(this.txtWriteVal1); + this.groupBox4.Controls.Add(this.label8); + this.groupBox4.Controls.Add(this.txtWriteAddr2); + this.groupBox4.Controls.Add(this.label10); + this.groupBox4.Controls.Add(this.txtWriteAddr1); + this.groupBox4.Controls.Add(this.label7); + this.groupBox4.Location = new System.Drawing.Point(7, 7); + this.groupBox4.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox4.Name = "groupBox4"; + this.groupBox4.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox4.Size = new System.Drawing.Size(1809, 71); + this.groupBox4.TabIndex = 12; + this.groupBox4.TabStop = false; + this.groupBox4.Text = "Memoria: WRITE param"; + // + // btnStrWrite + // + this.btnStrWrite.Location = new System.Drawing.Point(799, 25); + this.btnStrWrite.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnStrWrite.Name = "btnStrWrite"; + this.btnStrWrite.Size = new System.Drawing.Size(41, 23); + this.btnStrWrite.TabIndex = 10; + this.btnStrWrite.Text = "SW"; + this.btnStrWrite.UseVisualStyleBackColor = true; + this.btnStrWrite.Click += new System.EventHandler(this.btnStrWrite_Click); + // + // btnNumWriteB + // + this.btnNumWriteB.Location = new System.Drawing.Point(329, 5); + this.btnNumWriteB.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnNumWriteB.Name = "btnNumWriteB"; + this.btnNumWriteB.Size = new System.Drawing.Size(48, 23); + this.btnNumWriteB.TabIndex = 10; + this.btnNumWriteB.Text = "B"; + this.btnNumWriteB.UseVisualStyleBackColor = true; + this.btnNumWriteB.Click += new System.EventHandler(this.btnNumWriteB_Click); + // + // btnNumWriteDW + // + this.btnNumWriteDW.Location = new System.Drawing.Point(329, 44); + this.btnNumWriteDW.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnNumWriteDW.Name = "btnNumWriteDW"; + this.btnNumWriteDW.Size = new System.Drawing.Size(48, 23); + this.btnNumWriteDW.TabIndex = 10; + this.btnNumWriteDW.Text = "DW"; + this.btnNumWriteDW.UseVisualStyleBackColor = true; + this.btnNumWriteDW.Click += new System.EventHandler(this.btnNumWriteDW_Click); + // + // btnNumWriteW + // + this.btnNumWriteW.Location = new System.Drawing.Point(329, 23); + this.btnNumWriteW.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.btnNumWriteW.Name = "btnNumWriteW"; + this.btnNumWriteW.Size = new System.Drawing.Size(48, 23); + this.btnNumWriteW.TabIndex = 10; + this.btnNumWriteW.Text = "W"; + this.btnNumWriteW.UseVisualStyleBackColor = true; + this.btnNumWriteW.Click += new System.EventHandler(this.btnNumWriteW_Click); + // + // txtWriteVal2 + // + this.txtWriteVal2.Location = new System.Drawing.Point(612, 25); + this.txtWriteVal2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtWriteVal2.Name = "txtWriteVal2"; + this.txtWriteVal2.Size = new System.Drawing.Size(187, 22); + this.txtWriteVal2.TabIndex = 8; + this.txtWriteVal2.Text = "SAMUELEL"; + this.txtWriteVal2.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(571, 27); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(36, 17); + this.label9.TabIndex = 9; + this.label9.Text = "STR"; + // + // txtWriteVal1 + // + this.txtWriteVal1.Location = new System.Drawing.Point(237, 25); + this.txtWriteVal1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtWriteVal1.Name = "txtWriteVal1"; + this.txtWriteVal1.Size = new System.Drawing.Size(85, 22); + this.txtWriteVal1.TabIndex = 8; + this.txtWriteVal1.Text = "987654321"; + this.txtWriteVal1.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(197, 27); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(39, 17); + this.label8.TabIndex = 9; + this.label8.Text = "NUM"; + // + // txtWriteAddr2 + // + this.txtWriteAddr2.Location = new System.Drawing.Point(448, 25); + this.txtWriteAddr2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtWriteAddr2.Name = "txtWriteAddr2"; + this.txtWriteAddr2.Size = new System.Drawing.Size(116, 22); + this.txtWriteAddr2.TabIndex = 6; + this.txtWriteAddr2.Text = "DB600.DBB2"; + this.txtWriteAddr2.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(389, 27); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(59, 17); + this.label10.TabIndex = 7; + this.label10.Text = "ADDR 2"; + // + // txtWriteAddr1 + // + this.txtWriteAddr1.Location = new System.Drawing.Point(71, 25); + this.txtWriteAddr1.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtWriteAddr1.Name = "txtWriteAddr1"; + this.txtWriteAddr1.Size = new System.Drawing.Size(123, 22); + this.txtWriteAddr1.TabIndex = 6; + this.txtWriteAddr1.Text = "DB600.DBB0"; + this.txtWriteAddr1.TextAlign = System.Windows.Forms.HorizontalAlignment.Right; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(5, 27); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(59, 17); + this.label7.TabIndex = 7; + this.label7.Text = "ADDR 1"; + // + // txtOut + // + this.txtOut.BackColor = System.Drawing.SystemColors.Desktop; + this.txtOut.BorderStyle = System.Windows.Forms.BorderStyle.None; + this.txtOut.Font = new System.Drawing.Font("Microsoft Sans Serif", 7F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtOut.ForeColor = System.Drawing.Color.Yellow; + this.txtOut.Location = new System.Drawing.Point(4, 21); + this.txtOut.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.txtOut.Multiline = true; + this.txtOut.Name = "txtOut"; + this.txtOut.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.txtOut.Size = new System.Drawing.Size(569, 388); + this.txtOut.TabIndex = 0; + this.txtOut.Text = "..."; + // + // groupBox2 + // + this.groupBox2.AutoSize = true; + this.groupBox2.Controls.Add(this.txtOut); + this.groupBox2.Location = new System.Drawing.Point(3, 11); + this.groupBox2.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Padding = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.groupBox2.Size = new System.Drawing.Size(579, 428); + this.groupBox2.TabIndex = 9; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Risultati"; + // + // tabCtrl + // + this.tabCtrl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.tabCtrl.Controls.Add(this.tabReadTest); + this.tabCtrl.Controls.Add(this.tabWriteTest); + this.tabCtrl.Controls.Add(this.tabParam); + this.tabCtrl.Location = new System.Drawing.Point(15, 9); + this.tabCtrl.Name = "tabCtrl"; + this.tabCtrl.SelectedIndex = 0; + this.tabCtrl.Size = new System.Drawing.Size(879, 143); + this.tabCtrl.TabIndex = 13; + // + // tabReadTest + // + this.tabReadTest.Controls.Add(this.groupBox1); + this.tabReadTest.Location = new System.Drawing.Point(4, 25); + this.tabReadTest.Name = "tabReadTest"; + this.tabReadTest.Padding = new System.Windows.Forms.Padding(3); + this.tabReadTest.Size = new System.Drawing.Size(871, 114); + this.tabReadTest.TabIndex = 0; + this.tabReadTest.Text = "Read Test"; + this.tabReadTest.UseVisualStyleBackColor = true; + // + // tabWriteTest + // + this.tabWriteTest.Controls.Add(this.groupBox4); + this.tabWriteTest.Location = new System.Drawing.Point(4, 25); + this.tabWriteTest.Name = "tabWriteTest"; + this.tabWriteTest.Size = new System.Drawing.Size(871, 114); + this.tabWriteTest.TabIndex = 2; + this.tabWriteTest.Text = "Write Test"; + this.tabWriteTest.UseVisualStyleBackColor = true; + // + // tabParam + // + this.tabParam.Controls.Add(this.groupBox3); + this.tabParam.Location = new System.Drawing.Point(4, 25); + this.tabParam.Name = "tabParam"; + this.tabParam.Padding = new System.Windows.Forms.Padding(3); + this.tabParam.Size = new System.Drawing.Size(871, 114); + this.tabParam.TabIndex = 1; + this.tabParam.Text = "Parametri"; + this.tabParam.UseVisualStyleBackColor = true; + // + // splitContainer1 + // + this.splitContainer1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.splitContainer1.Location = new System.Drawing.Point(15, 158); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.Controls.Add(this.lblThroughtput); + this.splitContainer1.Panel1.Controls.Add(this.label18); + this.splitContainer1.Panel1.Controls.Add(this.lblTotSize); + this.splitContainer1.Panel1.Controls.Add(this.lblTimeMin); + this.splitContainer1.Panel1.Controls.Add(this.lblTimeMax); + this.splitContainer1.Panel1.Controls.Add(this.lblTimeAvg); + this.splitContainer1.Panel1.Controls.Add(this.label16); + this.splitContainer1.Panel1.Controls.Add(this.label15); + this.splitContainer1.Panel1.Controls.Add(this.label14); + this.splitContainer1.Panel1.Controls.Add(this.label12); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.groupBox2); + this.splitContainer1.Size = new System.Drawing.Size(875, 422); + this.splitContainer1.SplitterDistance = 291; + this.splitContainer1.TabIndex = 15; + // + // lblThroughtput + // + this.lblThroughtput.AutoSize = true; + this.lblThroughtput.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblThroughtput.Location = new System.Drawing.Point(224, 105); + this.lblThroughtput.Name = "lblThroughtput"; + this.lblThroughtput.Size = new System.Drawing.Size(35, 17); + this.lblThroughtput.TabIndex = 9; + this.lblThroughtput.Text = "000"; + this.lblThroughtput.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // label18 + // + this.label18.AutoSize = true; + this.label18.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label18.Location = new System.Drawing.Point(19, 105); + this.label18.Name = "label18"; + this.label18.Size = new System.Drawing.Size(57, 17); + this.label18.TabIndex = 8; + this.label18.Text = "Kb/sec"; + // + // lblTotSize + // + this.lblTotSize.AutoSize = true; + this.lblTotSize.Location = new System.Drawing.Point(227, 20); + this.lblTotSize.Name = "lblTotSize"; + this.lblTotSize.Size = new System.Drawing.Size(32, 17); + this.lblTotSize.TabIndex = 7; + this.lblTotSize.Text = "000"; + this.lblTotSize.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // lblTimeMin + // + this.lblTimeMin.AutoSize = true; + this.lblTimeMin.Location = new System.Drawing.Point(227, 41); + this.lblTimeMin.Name = "lblTimeMin"; + this.lblTimeMin.Size = new System.Drawing.Size(32, 17); + this.lblTimeMin.TabIndex = 6; + this.lblTimeMin.Text = "000"; + this.lblTimeMin.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // lblTimeMax + // + this.lblTimeMax.AutoSize = true; + this.lblTimeMax.Location = new System.Drawing.Point(227, 75); + this.lblTimeMax.Name = "lblTimeMax"; + this.lblTimeMax.Size = new System.Drawing.Size(32, 17); + this.lblTimeMax.TabIndex = 5; + this.lblTimeMax.Text = "000"; + this.lblTimeMax.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // lblTimeAvg + // + this.lblTimeAvg.AutoSize = true; + this.lblTimeAvg.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.lblTimeAvg.Location = new System.Drawing.Point(224, 58); + this.lblTimeAvg.Name = "lblTimeAvg"; + this.lblTimeAvg.Size = new System.Drawing.Size(35, 17); + this.lblTimeAvg.TabIndex = 4; + this.lblTimeAvg.Text = "000"; + this.lblTimeAvg.TextAlign = System.Drawing.ContentAlignment.TopRight; + // + // label16 + // + this.label16.AutoSize = true; + this.label16.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label16.Location = new System.Drawing.Point(19, 58); + this.label16.Name = "label16"; + this.label16.Size = new System.Drawing.Size(80, 17); + this.label16.TabIndex = 3; + this.label16.Text = "TIME: avg"; + // + // label15 + // + this.label15.AutoSize = true; + this.label15.Location = new System.Drawing.Point(19, 75); + this.label15.Name = "label15"; + this.label15.Size = new System.Drawing.Size(73, 17); + this.label15.TabIndex = 2; + this.label15.Text = "TIME: max"; + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(19, 41); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(70, 17); + this.label14.TabIndex = 1; + this.label14.Text = "TIME: min"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(19, 20); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(58, 17); + this.label12.TabIndex = 0; + this.label12.Text = "Tot size"; + // + // cmbOutType + // + this.cmbOutType.FormattingEnabled = true; + this.cmbOutType.Items.AddRange(new object[] { + "byte", + "word", + "dword", + "real", + "struct"}); + this.cmbOutType.Location = new System.Drawing.Point(522, 23); + this.cmbOutType.Name = "cmbOutType"; + this.cmbOutType.Size = new System.Drawing.Size(121, 24); + this.cmbOutType.TabIndex = 16; + this.cmbOutType.Text = "byte"; + this.cmbOutType.SelectedIndexChanged += new System.EventHandler(this.cmbOutType_SelectedIndexChanged); + // + // TestMainForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(906, 611); + this.Controls.Add(this.splitContainer1); + this.Controls.Add(this.statusStrip1); + this.Controls.Add(this.tabCtrl); + this.Margin = new System.Windows.Forms.Padding(3, 2, 3, 2); + this.Name = "TestMainForm"; + this.Text = "SIEMENS S7 TEST"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.statusStrip1.ResumeLayout(false); + this.statusStrip1.PerformLayout(); + this.groupBox4.ResumeLayout(false); + this.groupBox4.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.tabCtrl.ResumeLayout(false); + this.tabReadTest.ResumeLayout(false); + this.tabWriteTest.ResumeLayout(false); + this.tabParam.ResumeLayout(false); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + this.splitContainer1.Panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.TextBox txtIP; + private System.Windows.Forms.Label lblIP; + private System.Windows.Forms.ComboBox cbCpuType; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtMemArea; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox txtMemSize; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.GroupBox groupBox3; + private System.Windows.Forms.TextBox txtSlot; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox txtRack; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.Button btnReadByte; + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.ToolStripStatusLabel tslConn; + private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.ToolStripProgressBar toolStripProgressBar1; + private System.Windows.Forms.ToolStripStatusLabel tslRTime; + private System.Windows.Forms.GroupBox groupBox4; + private System.Windows.Forms.Button btnStrWrite; + private System.Windows.Forms.Button btnNumWriteW; + private System.Windows.Forms.TextBox txtWriteVal2; + private System.Windows.Forms.Label label9; + private System.Windows.Forms.TextBox txtWriteVal1; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.TextBox txtWriteAddr1; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TextBox txtWriteAddr2; + private System.Windows.Forms.Label label10; + private System.Windows.Forms.Button btnReadString; + private System.Windows.Forms.Button btnReadWord; + private System.Windows.Forms.Button btnReadDWord; + private System.Windows.Forms.Button btnReadReal; + private System.Windows.Forms.Button btnNumWriteB; + private System.Windows.Forms.Button btnNumWriteDW; + private System.Windows.Forms.Button btnReadStruct; + private System.Windows.Forms.TextBox txtOut; + private System.Windows.Forms.GroupBox groupBox2; + private System.Windows.Forms.TabControl tabCtrl; + private System.Windows.Forms.TabPage tabReadTest; + private System.Windows.Forms.TabPage tabWriteTest; + private System.Windows.Forms.TabPage tabParam; + private System.Windows.Forms.SplitContainer splitContainer1; + private System.Windows.Forms.Label label11; + private System.Windows.Forms.TextBox txtNumRep; + private System.Windows.Forms.Label label13; + private System.Windows.Forms.Label lblTotSize; + private System.Windows.Forms.Label lblTimeMin; + private System.Windows.Forms.Label lblTimeMax; + private System.Windows.Forms.Label lblTimeAvg; + private System.Windows.Forms.Label label16; + private System.Windows.Forms.Label label15; + private System.Windows.Forms.Label label14; + private System.Windows.Forms.Label label12; + private System.Windows.Forms.Label lblThroughtput; + private System.Windows.Forms.Label label18; + private System.Windows.Forms.ComboBox cmbOutType; + } +} + diff --git a/SiemensS7/Siemens-S7-Test/TestMainForm.cs b/SiemensS7/Siemens-S7-Test/TestMainForm.cs new file mode 100644 index 00000000..e4000d24 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/TestMainForm.cs @@ -0,0 +1,904 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using S7.Net; +using System.Net.NetworkInformation; +using System.Net; +using NLog; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Threading; + +namespace Siemens_S7_Test +{ + public partial class TestMainForm : Form + { + /// + /// Configurazione valori da LEGGERE dal PLC + /// + public otherData[] memMapR; + /// + /// Configurazione valori da SCRIVERE nel PLC + /// + public otherData[] memMapW; + /// + /// Byte dimensione buffer dati memoria (da file map) + /// + public int numByte = 0; + /// + /// Lungh massima stringhe + /// + protected int maxStrChar = 20; + /// + /// Oggetto PLC da ri-utilizzare... + /// + protected Plc currPLC; + /// + /// indica se serva refresh parametri e quindi PLC... + /// + bool needRefresh = true; + /// + /// Oggetto cronometro x test vari... + /// + protected Stopwatch sw = new Stopwatch(); + /// + /// parametri di connessione + /// + protected connParam parametri; + /// + /// titolo x log/debug + /// + protected string titolo = ""; + /// + /// contenuto x log/debug + /// + protected string contenuto = ""; + /// + /// oggetto logging + /// + public static Logger lg; + /// + /// oggetto uiTimer + /// + protected System.Windows.Forms.Timer uiTimer = new System.Windows.Forms.Timer(); + /// + /// Gestione statistiche + /// + public TimingData PerfStats; + /// + /// Array oggetti letti + /// + protected Byte[] memByteRead = new byte[0]; + + public TestMainForm() + { + InitializeComponent(); + + myInit(); + + startUiTimer(); + } + + private void startUiTimer() + { + uiTimer.Tick += UiTimer_Tick; + uiTimer.Start(); + } + + private void UiTimer_Tick(object sender, EventArgs e) + { + advProgBar(); + } + + /// + /// inizializzo + /// + private void myInit() + { + lg = LogManager.GetCurrentClassLogger(); + PerfStats = new TimingData(); + // inizializzo parametri... + parametri = new connParam() + { + ipAdrr = "127.0.0.1", + tipoCpu = CpuType.S7200, + slot = 0, + rack = 0 + }; + setParamPlc(); + // timer + uiTimer.Interval = 20; + } + + /// + /// Imposto parametri PLC + /// + private void setParamPlc() + { + txtOut.Text = ""; + // SE è necessario refresh... + if (needRefresh) + { + lg.Info("Refreshing connection..."); + try + { + short.TryParse(txtSlot.Text, out parametri.slot); + short.TryParse(txtRack.Text, out parametri.rack); + parametri.tipoCpu = (CpuType)Enum.Parse(typeof(CpuType), cbCpuType.SelectedItem.ToString()); + parametri.ipAdrr = txtIP.Text.Trim(); + titolo = "PARAM PLC (pre connect)"; + contenuto = string.Format("IP: {0}{1}", parametri.ipAdrr, Environment.NewLine); + contenuto += string.Format("CPU: {0}{1}", parametri.tipoCpu, Environment.NewLine); + contenuto += string.Format("RACK: {0}{1}", parametri.rack, Environment.NewLine); + contenuto += string.Format("SLOT: {0}", parametri.slot, Environment.NewLine); + } + catch (Exception exc) + { + lg.Error(exc, "Errore in parse parametri"); + } + // ora tento avvio PLC... SE PING OK... + if (testPing() == IPStatus.Success) + { + try + { + currPLC = new Plc(parametri.tipoCpu, parametri.ipAdrr, parametri.rack, parametri.slot); + currPLC.Open(); + if (currPLC.IsConnected) titolo = "CONNESSIONE AVVENUTA"; + } + catch (Exception exc) + { + lg.Error(exc, "Errore in INIT PLC"); + } + needRefresh = false; + } + // carico conf vettore memoria... + loadMemConf(); + // mostra output + showOut(titolo, contenuto); + } + } + /// + /// Caricamento conf memoria DB del SIEMENS + /// + private void loadMemConf() + { + // carico conf memoria + utils.loadConfFile(ref memMapR, filePath("MMapR"), 1, ref numByte); + utils.loadConfFile(ref memMapW, filePath("MMapW"), 1, ref numByte); + } + /// + /// Restituisce path completo file da chaive configurazione + /// + /// chaive conf x file richiesto + /// + protected string filePath(string keyFile) + { + return string.Format(@"{0}\{1}", utils.confDir, utils.CRS(keyFile)); + } + /// + /// Aggiorno statistiche mostrate + /// + protected void updateStats() + { + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + int numTest = 1; + int.TryParse(txtNumRep.Text, out numTest); + lblTimeMin.Text = $"{PerfStats.currStat.min} ms"; + lblTimeMax.Text = $"{PerfStats.currStat.max} ms"; + lblTimeAvg.Text = $"{PerfStats.currStat.avg} ms"; + lblTotSize.Text = $"{numByte * numTest / 1024} kb"; + lblThroughtput.Text = $"{numByte / (1024 * PerfStats.currStat.avg) * 1000} bps"; + } + + /// + /// Esecuzione lettura! + /// + private void eseguiLetturaByte() + { + PerfStats = new TimingData(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + int numTest = 1; + int.TryParse(txtNumRep.Text, out numTest); + //tslRTime.Text = "Start reading BYTE"; + //tslRTime.Invalidate(); + // effettuo numero di test secondo indicazioni... + for (int i = 0; i < numTest; i++) + { + sw.Restart(); + // eseguo test + memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + sw.Stop(); + // salvo risultati + PerfStats.addValue((double)sw.ElapsedMilliseconds); + } + + // mostro update lettura + updateStats(); + + tslRTime.Text = string.Format("{0}", sw.Elapsed); + titolo = string.Format("READ BLOCK MEM BYTE: {0} --> {1} byte", txtMemArea.Text, numByte); + contenuto = ""; + string byteVal = ""; + // verifico se mostrare dati in modalità struct o meno... + + for (int i = 0; i < memByteRead.Length; i++) + { + byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); + } + showOut(titolo, contenuto); + } + } + /// + /// Esecuzione lettura WORD! + /// + private void eseguiLetturaWord() + { + PerfStats = new TimingData(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + int numTest = 1; + int.TryParse(txtNumRep.Text, out numTest); + // effettuo numero di test secondo indicazioni... + for (int i = 0; i < numTest; i++) + { + sw.Restart(); + // eseguo test + memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + sw.Stop(); + // salvo risultati + PerfStats.addValue((double)sw.ElapsedMilliseconds); + } + + // mostro update lettura + updateStats(); + + tslRTime.Text = string.Format("{0}", sw.Elapsed); + titolo = string.Format("READ BLOCK MEM WORD: {0} --> {1} byte", txtMemArea.Text, numByte); + contenuto = ""; + ushort shortVal = 0; + string byteValA = ""; + string byteValB = ""; + for (int i = 0; i < memByteRead.Length / 2; i++) + { + byteValA = Convert.ToString(memByteRead[i * 2], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 2 + 1], 2).PadLeft(8, '0'); + shortVal = S7.Net.Types.Word.FromByteArray(memByteRead.Skip(2 * i).Take(2).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}{4}", i, shortVal, byteValA, byteValB, Environment.NewLine); + } + showOut(titolo, contenuto); + } + } + + /// + /// Esecuzione lettura DWORD! + /// + private void eseguiLetturaDWord() + { + PerfStats = new TimingData(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + int numTest = 1; + int.TryParse(txtNumRep.Text, out numTest); + for (int i = 0; i < numTest; i++) + { + sw.Restart(); + // eseguo test + memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + sw.Stop(); + // salvo risultati + PerfStats.addValue((double)sw.ElapsedMilliseconds); + } + + // mostro update lettura + updateStats(); + + tslRTime.Text = string.Format("{0}", sw.Elapsed); + titolo = string.Format("READ BLOCK MEM WORD: {0} --> {1} byte", txtMemArea.Text, numByte); + contenuto = ""; + uint intVal = 0; + string byteValA = ""; + string byteValB = ""; + string byteValC = ""; + string byteValD = ""; + for (int i = 0; i < memByteRead.Length / 4; i++) + { + byteValA = Convert.ToString(memByteRead[i * 4], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 4 + 1], 2).PadLeft(8, '0'); + byteValC = Convert.ToString(memByteRead[i * 4 + 2], 2).PadLeft(8, '0'); + byteValD = Convert.ToString(memByteRead[i * 4 + 3], 2).PadLeft(8, '0'); + intVal = S7.Net.Types.DWord.FromByteArray(memByteRead.Skip(4 * i).Take(4).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}-{4}-{5}{6}", i, intVal, byteValA, byteValB, byteValC, byteValD, Environment.NewLine); + } + showOut(titolo, contenuto); + } + } + /// + /// Esecuzione lettura come struct + /// + private void eseguiLetturaStruct() + { + sw.Restart(); + if (testCncConn()) + { + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + titolo = string.Format("READ STRUCT: {0} --> {1} byte", txtMemArea.Text, numByte); + + //leggo a ciclo una singola struct... + + int numPar = 50; + ThermoParam objPar = new ThermoParam(); + List ElencoParametri = new List(); + for (int i = 0; i < numPar; i++) + { + objPar = (ThermoParam)currPLC.ReadClass(600, i * 20); + ElencoParametri.Add(objPar); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + + foreach (var item in ElencoParametri) + { + contenuto += $"Id: {item.Id}{Environment.NewLine}"; + contenuto += $"SetpointHMI: {item.SetpointHMI}{Environment.NewLine}"; + contenuto += $"SetpointPLC: {item.SetpointPLC}{Environment.NewLine}"; + contenuto += $"ValMin: {item.ValMin}{Environment.NewLine}"; + contenuto += $"ValMax: {item.ValMax}{Environment.NewLine}"; + contenuto += $"UnitMeasure: {item.UnitMeasure}{Environment.NewLine}"; + contenuto += $"---------{Environment.NewLine}"; + } + + +#if false + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + contenuto = ""; + ushort shortVal = 0; + string byteValA = ""; + string byteValB = ""; + for (int i = 0; i < memByteRead.Length / 2; i++) + { + byteValA = Convert.ToString(memByteRead[i * 2], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 2 + 1], 2).PadLeft(8, '0'); + shortVal = S7.Net.Types.Word.FromByteArray(memByteRead.Skip(2 * i).Take(2).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}{4}", i, shortVal, byteValA, byteValB, Environment.NewLine); + } +#endif + + + showOut(titolo, contenuto); + } + } + protected void animateProgBar() + { + uiTimer.Interval = 20; + } + + protected void advProgBar() + { + toolStripProgressBar1.ProgressBar.Value++; + if (toolStripProgressBar1.ProgressBar.Value >= toolStripProgressBar1.ProgressBar.Maximum) + { + toolStripProgressBar1.ProgressBar.Value = 0; + } + } + + /// + /// Esecuzione lettura Real! + /// + private void eseguiLetturaReal() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + titolo = string.Format("READ BLOCK MEM WORD: {0} --> {1} byte", txtMemArea.Text, numByte); + contenuto = ""; + double realVal = 0; + string byteValA = ""; + string byteValB = ""; + string byteValC = ""; + string byteValD = ""; + for (int i = 0; i < memByteRead.Length / 4; i++) + { + byteValA = Convert.ToString(memByteRead[i * 4], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 4 + 1], 2).PadLeft(8, '0'); + byteValC = Convert.ToString(memByteRead[i * 4 + 2], 2).PadLeft(8, '0'); + byteValD = Convert.ToString(memByteRead[i * 4 + 3], 2).PadLeft(8, '0'); + realVal = S7.Net.Types.Double.FromByteArray(memByteRead.Skip(4 * i).Take(4).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}-{4}-{5}{6}", i, realVal, byteValA, byteValB, byteValC, byteValD, Environment.NewLine); + } + showOut(titolo, contenuto); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + } + /// + /// Esecuzione lettura tipo STRING! + /// + private void eseguiLetturaString() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtMemArea.Text); + int numByte = 1; + int.TryParse(txtMemSize.Text, out numByte); + Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + titolo = string.Format("READ BLOCK MEM STRING: {0} --> {1} byte", txtMemArea.Text, numByte); + contenuto = ""; + string byteVal = ""; + // i primi 2 byte sono LUNGHEZZA MAX e lungh effettiva quindi setto il NUM BYTE.... + for (int i = 0; i < 2; i++) + { + byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); + } + // prendo 2° valore (num max valori) + numByte = memByteRead[1]; + // poi prendo la stringa... + string outVal = ""; + for (int i = 2; i < numByte + 2; i++) + { + outVal += Char.ConvertFromUtf32(memByteRead[i]); + } + contenuto += string.Format("{0}{1}", outVal, Environment.NewLine); + showOut(titolo, contenuto); + } + } + /// + /// Test connessione CNC + /// + /// + private bool testCncConn() + { + bool answ = false; + IPStatus pingStatus = testPing(); + // se passa il ping faccio il resto... + if (pingStatus != IPStatus.Success) + { + titolo = "Errore ping"; + contenuto = string.Format("Reply Status per {0}: {1}", parametri.ipAdrr, pingStatus); + showOut(titolo, contenuto); + } + else + { + if (!currPLC.IsConnected) currPLC.Open(); + bool excludeAvailable = true; + if (excludeAvailable) + { + if (!currPLC.IsConnected) + { + titolo = "Errore connessione"; + //contenuto = string.Format("{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString); + //currPLC.ClearLastError(); + contenuto = "!currPLC.IsConnected"; + showOut(titolo, contenuto); + tslConn.Text = "NO Connection"; + } + else + { + tslConn.Text = "Connection OK"; + answ = true; + } + } + else + { + if (!currPLC.IsAvailable) + { + titolo = "Errore Disponibilità"; + //contenuto = string.Format("{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString); + //currPLC.ClearLastError(); + contenuto = "!currPLC.IsAvailable"; + showOut(titolo, contenuto); + } + else + { + if (!currPLC.IsConnected) + { + titolo = "Errore connessione"; + //contenuto = string.Format("{0} | {1}", currPLC.LastErrorCode, currPLC.LastErrorString); + //currPLC.ClearLastError(); + contenuto = "!currPLC.IsConnected"; + showOut(titolo, contenuto); + tslConn.Text = "NO Connection"; + } + else + { + tslConn.Text = "Connection OK"; + answ = true; + } + } + } + } + return answ; + } + + /// + /// test ping all'indirizzo impostato nei parametri + /// + /// + private IPStatus testPing() + { + IPStatus answ = IPStatus.Unknown; ; + IPAddress address; + PingReply reply; + Ping pingSender = new Ping(); + address = IPAddress.Loopback; + IPAddress.TryParse(parametri.ipAdrr, out address); + reply = pingSender.Send(address, 100); + answ = reply.Status; + return answ; + } + + /// + /// formatta un numero in forma binaria 0/1 a 32 bit (4 byte) + /// + /// + /// + public static string binaryForm(int valore) + { + string answ = ""; + try + { + answ = string.Format(new BinaryFormat(), "{0:B}", valore); + } + catch + { } + return answ; + } + /// + /// aggiorna display in base a selezione tipo output... + /// + /// + /// + protected void showOut(string title, string content) + { + // verifico combo e formatto... + contenuto = ""; + string byteVal = ""; + ushort shortVal = 0; + uint intVal = 0; + string byteValA = ""; + string byteValB = ""; + string byteValC = ""; + string byteValD = ""; + // verifico come mostrare dati (byte, word, struct ...) + switch (cmbOutType.SelectedItem) + { + case "word": + for (int i = 0; i < memByteRead.Length / 2; i++) + { + byteValA = Convert.ToString(memByteRead[i * 2], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 2 + 1], 2).PadLeft(8, '0'); + shortVal = S7.Net.Types.Word.FromByteArray(memByteRead.Skip(2 * i).Take(2).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}{4}", i, shortVal, byteValA, byteValB, Environment.NewLine); + } + break; + case "dword": + for (int i = 0; i < memByteRead.Length / 4; i++) + { + byteValA = Convert.ToString(memByteRead[i * 4], 2).PadLeft(8, '0'); + byteValB = Convert.ToString(memByteRead[i * 4 + 1], 2).PadLeft(8, '0'); + byteValC = Convert.ToString(memByteRead[i * 4 + 2], 2).PadLeft(8, '0'); + byteValD = Convert.ToString(memByteRead[i * 4 + 3], 2).PadLeft(8, '0'); + intVal = S7.Net.Types.DWord.FromByteArray(memByteRead.Skip(4 * i).Take(4).ToArray()); + contenuto += string.Format("W{0:000}: {1} | {2}-{3}-{4}-{5}{6}", i, intVal, byteValA, byteValB, byteValC, byteValD, Environment.NewLine); + } + break; + case "struct": + ThermoParam objPar = new ThermoParam(); + List ElencoParametri = new List(); + IFormatter formatter = new BinaryFormatter(); + // procedo 20 byte alla volta... + for (int i = 0; i < memByteRead.Length / 20; i++) + { + objPar = SerDeserExtensions.Deserializer(memByteRead.Skip(20 * i).Take(20).ToArray()); + ElencoParametri.Add(objPar); + } + foreach (var item in ElencoParametri) + { + contenuto += $"Id: {item.Id}{Environment.NewLine}"; + contenuto += $"SetpointHMI: {item.SetpointHMI}{Environment.NewLine}"; + contenuto += $"SetpointPLC: {item.SetpointPLC}{Environment.NewLine}"; + contenuto += $"ValMin: {item.ValMin}{Environment.NewLine}"; + contenuto += $"ValMax: {item.ValMax}{Environment.NewLine}"; + contenuto += $"UnitMeasure: {item.UnitMeasure}{Environment.NewLine}"; + contenuto += $"---------{Environment.NewLine}"; + } + break; + case "byte": + default: + for (int i = 0; i < memByteRead.Length; i++) + { + byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); + } + break; + } + + + + + string outText = ""; + // a video + outText += string.Format("{0}--------------------------------------------------------------------------------------{0}", Environment.NewLine); + outText += string.Format("- {0}{1}", titolo, Environment.NewLine); + outText += string.Format("--------------------------------------------------------------------------------------{0}", Environment.NewLine); + outText += string.Format("{0}{1}", contenuto, Environment.NewLine); + outText += string.Format("--------------------------------------------------------------------------------------{0}{0}", Environment.NewLine); + + // aggiorno visualizzazione + txtOut.Text = outText; + // loggo! + lg.Info(outText); + } + + /// + /// Esecuzione SCRITTURA Byte! + /// + private void eseguiScritturaByte() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtWriteAddr1.Text); + byte num2write = 0; + string val2write = txtWriteVal2.Text; + byte.TryParse(txtWriteVal1.Text, out num2write); + byte[] DB_Byte = new byte[1]; + DB_Byte[0] = num2write; + currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, DB_Byte); + titolo = string.Format("WRITE BLOCK MEM: {0}", txtWriteAddr1.Text); + contenuto = ""; + contenuto += string.Format("DT: {0} | DbNum: {1} | indiceMem: {2} | num2write: {3}{4}{4}", DataType.DataBlock, memoria.DbNum, memoria.indiceMem, num2write, Environment.NewLine); + string byteVal = ""; + for (int i = 0; i < DB_Byte.Length; i++) + { + byteVal = Convert.ToString(DB_Byte[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, DB_Byte[i], Environment.NewLine); + } + showOut(titolo, contenuto); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + } + /// + /// Esecuzione SCRITTURA WORD! + /// + private void eseguiScritturaWord() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtWriteAddr1.Text); + UInt16 num2write = 0; + string val2write = txtWriteVal2.Text; + UInt16.TryParse(txtWriteVal1.Text, out num2write); + byte[] DB_Byte = new byte[2]; + S7.Net.Types.Word.ToByteArray(num2write).CopyTo(DB_Byte, 0); + currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, DB_Byte); + titolo = string.Format("WRITE BLOCK MEM: {0}", txtWriteAddr1.Text); + contenuto = ""; + contenuto += string.Format("DT: {0} | DbNum: {1} | indiceMem: {2} | num2write: {3}{4}{4}", DataType.DataBlock, memoria.DbNum, memoria.indiceMem, num2write, Environment.NewLine); + string byteVal = ""; + for (int i = 0; i < DB_Byte.Length; i++) + { + byteVal = Convert.ToString(DB_Byte[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, DB_Byte[i], Environment.NewLine); + } + showOut(titolo, contenuto); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + } + /// + /// Esecuzione SCRITTURA DWORD! + /// + private void eseguiScritturaDWord() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtWriteAddr1.Text); + uint num2write = 0; + string val2write = txtWriteVal2.Text; + uint.TryParse(txtWriteVal1.Text, out num2write); + byte[] DB_Byte = new byte[4]; + S7.Net.Types.DWord.ToByteArray(num2write).CopyTo(DB_Byte, 0); + currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, DB_Byte); + titolo = string.Format("WRITE BLOCK MEM: {0}", txtWriteAddr1.Text); + contenuto = ""; + contenuto += string.Format("DT: {0} | DbNum: {1} | indiceMem: {2} | num2write: {3}{4}{4}", DataType.DataBlock, memoria.DbNum, memoria.indiceMem, num2write, Environment.NewLine); + string byteVal = ""; + for (int i = 0; i < DB_Byte.Length; i++) + { + byteVal = Convert.ToString(DB_Byte[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, DB_Byte[i], Environment.NewLine); + } + showOut(titolo, contenuto); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + } + /// + /// Esecuzione SCRITTURA String! + /// + private void eseguiScritturaString() + { + sw.Restart(); + if (testCncConn()) + { + // decodifico memoria... + memAddress memoria = new memAddress(txtWriteAddr2.Text); + int num2write = 0; + // verifico di no sforare con lunghezza + string val2write = txtWriteVal2.Text; + // se è maggiore di maxStrChar TRIMMA::: + if (val2write.Length > maxStrChar) + { + val2write = val2write.Substring(0, 20); + } + // scambio spazi con underscore... e MAIUSCOLO!!! + val2write = val2write.Replace(' ', '_').ToUpper(); + num2write = val2write.Length; + byte[] DB_Byte = new byte[maxStrChar + 2]; + // primi 2 byte sono 20 (fix) e lung effettiva... + DB_Byte[0] = 20; + DB_Byte[1] = (byte)num2write; + // converto 1-1 i char in byte... + for (int i = 0; i < num2write; i++) + { + DB_Byte[2 + i] = (byte)(val2write[i]); + } + currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, DB_Byte); + titolo = string.Format("WRITE BLOCK MEM: {0}", txtWriteAddr1.Text); + contenuto = ""; + contenuto += string.Format("DT: {0} | DbNum: {1} | indiceMem: {2} | stringa: {3}{4}{4}", DataType.DataBlock, memoria.DbNum, memoria.indiceMem, num2write, Environment.NewLine); + showOut(titolo, contenuto); + } + sw.Stop(); + tslRTime.Text = string.Format("{0}", sw.Elapsed); + } + + + /// + /// Scrivo memoria tipo STRING + /// + /// + /// + private void btnStrWrite_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiScritturaString(); + } + + private void txtIP_TextChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void txtRack_TextChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void cbCpuType_SelectedIndexChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void txtSlot_TextChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void txtMemArea_TextChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void txtMemSize_TextChanged(object sender, EventArgs e) + { + needRefresh = true; + } + + private void btnReadByte_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiLetturaByte(); + } + + private void btnReadWord_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiLetturaWord(); + } + + private void btnReadString_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiLetturaString(); + } + + private void btnReadDWord_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiLetturaDWord(); + } + /// + /// Lettura real + /// + /// + /// + private void btnReadReal_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiLetturaReal(); + } + + private void btnNumWriteB_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiScritturaByte(); + } + + private void btnNumWriteDW_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiScritturaDWord(); + } + + private void btnNumWriteW_Click(object sender, EventArgs e) + { + setParamPlc(); + eseguiScritturaWord(); + } + + private void btnReadStruct_Click(object sender, EventArgs e) + { + // effettua lettura intera struct... + setParamPlc(); + eseguiLetturaStruct(); + } + + private void cmbOutType_SelectedIndexChanged(object sender, EventArgs e) + { + showOut("", ""); + } + } + +} diff --git a/SiemensS7/Siemens-S7-Test/TestMainForm.resx b/SiemensS7/Siemens-S7-Test/TestMainForm.resx new file mode 100644 index 00000000..174ebc72 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/TestMainForm.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/ThermoObj.cs b/SiemensS7/Siemens-S7-Test/ThermoObj.cs new file mode 100644 index 00000000..600a505d --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/ThermoObj.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; +using System.Threading.Tasks; + +namespace Siemens_S7_Test +{ + [Serializable] + public class ThermoParam + { + public ushort Id; + public UInt32 SetpointHMI; + public UInt32 SetpointPLC; + public UInt32 ValMax; + public UInt32 ValMin; + public ushort UnitMeasure; + } + + + //public T Deserialize(byte[] param) + //{ + // using (MemoryStream ms = new MemoryStream(param)) + // { + // IFormatter br = new BinaryFormatter(); + // return (T)br.Deserialize(ms); + // } + //} + + public static class SerDeserExtensions + { + public static byte[] Serializer(this object _object) + { + byte[] bytes; + using (var _MemoryStream = new MemoryStream()) + { + IFormatter _BinaryFormatter = new BinaryFormatter(); + _BinaryFormatter.Serialize(_MemoryStream, _object); + bytes = _MemoryStream.ToArray(); + } + return bytes; + } + + public static T Deserializer(this byte[] _byteArray) + { + T ReturnValue; + using (var _MemoryStream = new MemoryStream(_byteArray)) + { + IFormatter _BinaryFormatter = new BinaryFormatter(); + ReturnValue = (T)_BinaryFormatter.Deserialize(_MemoryStream); + } + return ReturnValue; + } + } + +} diff --git a/SiemensS7/Siemens-S7-Test/TimingData.cs b/SiemensS7/Siemens-S7-Test/TimingData.cs new file mode 100644 index 00000000..c88a731c --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/TimingData.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Siemens_S7_Test +{ + public class TimingData + { + /// + /// Array dei valori rilevati in secondi + /// + protected List valori { get; set; } + /// + /// Statistiche attuali + /// + public stats currStat; + /// + /// Tipo dei dati salvato + /// + public string Tipo { get; set; } + public TimingData() + { + valori = new List(); + currStat = new stats(); + } + /// + /// aggiunge dati e restituisce statistiche aggiornate... + /// + /// + /// + public void addValue(double valore) + { + valori.Add(valore); + currStat.min = valori.Min(); + currStat.max = valori.Max(); + currStat.avg = valori.Average(); + currStat.num = valori.Count; + } + } + /// + /// Struttura risultati + /// + public struct stats + { + public double min; + public double max; + public double avg; + public int num; + } + +} diff --git a/SiemensS7/Siemens-S7-Test/connParam.cs b/SiemensS7/Siemens-S7-Test/connParam.cs new file mode 100644 index 00000000..4c641b0d --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/connParam.cs @@ -0,0 +1,18 @@ +using S7.Net; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Siemens_S7_Test +{ + public class connParam + { + public string ipAdrr = ""; + + public CpuType tipoCpu = CpuType.S7300; + public short slot = 0; + public short rack = 0; + } +} diff --git a/SiemensS7/Siemens-S7-Test/logs/.placeholder.txt b/SiemensS7/Siemens-S7-Test/logs/.placeholder.txt new file mode 100644 index 00000000..5f282702 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/logs/.placeholder.txt @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/memAddress.cs b/SiemensS7/Siemens-S7-Test/memAddress.cs new file mode 100644 index 00000000..ccc70960 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/memAddress.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Siemens_S7_Test +{ + public class memAddress + { + /// + /// Indice DB + /// + public int DbNum = 0; + /// + /// Tipo Memoria (DBD, DBW...) + /// + public string tipoMem = ""; + /// + /// Indice partenza memoria (es DBD0 --> 0) + /// + public int indiceMem = 0; + /// + /// Inizializza da un formato stringa + /// + /// + public memAddress(string strFormat) + { + string[] memComp = strFormat.Split('.'); + int.TryParse(memComp[0].Replace("DB", ""), out DbNum); + tipoMem = memComp[1].Substring(2, 1); + int.TryParse(memComp[1].Replace("DB", "").Replace(tipoMem, ""), out indiceMem); + } + } +} diff --git a/SiemensS7/Siemens-S7-Test/packages.config b/SiemensS7/Siemens-S7-Test/packages.config new file mode 100644 index 00000000..fc54bece --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/resources/MHT/MMapR.map b/SiemensS7/Siemens-S7-Test/resources/MHT/MMapR.map new file mode 100644 index 00000000..6eec3133 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/resources/MHT/MMapR.map @@ -0,0 +1,36 @@ +# Commenti con cancelletto, struttura un variabile per riga, tipo chiave|valore (occhio che il separatore è configurato da .cofig come "charSep"); spazi e tabulazioni dovrei trimmarli in acquisizione (qui inseriti per comodità di lettura) +# Segnali BIT per gestione MAPO-IOB-WIN "base" +0.0|IOB_POWER_ON |BIT +0.1|IOB_RUN |BIT +0.2|IOB_COUNT |BIT +0.3|IOB_ALARM |BIT +0.4|IOB_MANUAL |BIT +# segnali BIT x ACK +0.5|ACK_STR |BIT +0.6|ACK_ST_COM |BIT +0.7|ACK_END_COM |BIT +#bit x definizione ultimo pezzo (OK/SCARTO/RILAVORAZIONE) +1.0|LAST_PZ_OK |BIT +1.1|LAST_PZ_KO |BIT +1.2|LAST_PZ_RIL |BIT +# Vettori allarmi (banchi da 32) +002|ALARMS_001 |4BYTE +006|ALARMS_033 |4BYTE +010|ALARMS_065 |4BYTE +014|ALARMS_097 |4BYTE +# Altro valori byte numerici (0..255) +018|AUTO_POWER_OFF |BYTE +019|OVR_SPEED |BYTE +020|OVR_FEED |BYTE +021|CURR_MODE |BYTE +# valori word come UINT 16bit/Word +022|COUNT_TOT |WORD +024|RPM_PEZZO |WORD +026|RPM_MOLA |WORD +028|NUM_PZ_STOP |WORD +030|MIN_TEO_STOP |WORD +032|LOAD_PEZZO |WORD +034|LOAD_MOLA |WORD +036|TC_LAST_PZ |REAL +040|MIS_H1_LAST_PZ |REAL +044|MIS_H2_LAST_PZ |REAL \ No newline at end of file diff --git a/SiemensS7/Siemens-S7-Test/resources/MHT/MMapW.map b/SiemensS7/Siemens-S7-Test/resources/MHT/MMapW.map new file mode 100644 index 00000000..cdcdfcbb --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/resources/MHT/MMapW.map @@ -0,0 +1,27 @@ +# Commenti con cancelletto, struttura un variabile per riga, tipo chiave|valore (occhio che il separatore è configurato da .cofig come "charSep"); spazi e tabulazioni dovrei trimmarli in acquisizione (qui inseriti per comodità di lettura) +# Segnali BIT per gestione richeista lettura valori +0.0|SIG_STR |BIT +0.1|SIG_ST_COM |BIT +0.2|SIG_END_COM |BIT +# valori word come UINT 16bit/Word +002|NUM_PZ_LOTTO |WORD +# dati COMMESSA +006|L_MAX_COMM |BYTE +007|L_ACT_COMM |BYTE +008|COD_COMMESSA |20CHAR +# dati ARTICOLO +006|L_MAX_ART |BYTE +007|L_ACT_ART |BYTE +008|COD_ARTICOLO |20CHAR +# dati PROGRAMMA +006|L_MAX_PROG |BYTE +007|L_ACT_PROG |BYTE +008|COD_PROGRAMMA |20CHAR +# dati MACCHINA +006|L_MAX_MACC |BYTE +007|L_ACT_MACC |BYTE +008|COD_MACCHINA |20CHAR +# dati DIRECTORY +006|L_MAX_DIR |BYTE +007|L_ACT_DIR |BYTE +008|COD_DIRECTORY |20CHAR diff --git a/SiemensS7/Siemens-S7-Test/utils.cs b/SiemensS7/Siemens-S7-Test/utils.cs new file mode 100644 index 00000000..818195d8 --- /dev/null +++ b/SiemensS7/Siemens-S7-Test/utils.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Configuration; +using NLog; +using System.Windows.Forms; + +namespace Siemens_S7_Test +{ + public class utils + { + /// + /// wrapper di log + /// + public static Logger lg; + /// + /// folder archiviazione dati configurazione (DATA\CONF) + /// + public static string confDir + { + get + { + return string.Format(@"{0}\{1}", Application.StartupPath, CRS("dataConfPath")); + } + } + /// + /// legge conf in formato char + /// + /// + /// + public static char CRC(string key) + { + char answ = '-'; + try + { + answ = ConfigurationManager.AppSettings[key].ToCharArray()[0]; + } + catch + { } + return answ; + } + /// + /// legge conf in formato stringa + /// + /// + /// + public static string CRS(string key) + { + string answ = ""; + try + { + answ = ConfigurationManager.AppSettings[key].ToString(); + } + catch + { } + return answ; + } + /// + /// legge conf in formato INT + /// + /// + /// + public static Int32 CRI(string key) + { + int answ = 0; + try + { + answ = Convert.ToInt32(CRS(key)); + } + catch + { } + return answ; + } + /// + /// legge conf in formato BOOLean + /// + /// + /// + public static bool CRB(string key) + { + bool answ = false; + try + { + answ = Convert.ToBoolean(CRS(key)); + } + catch + { } + return answ; + } + /// + /// Decodifica file allarme + /// + /// + /// + /// tipo memoria (R/D/...) + /// indirizzo di partenza memoria + /// dimensione singolo slot in byte + /// + protected static otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + /// + /// Decodifica file MAP (caso ESA/IOT) + /// + /// + /// + /// indirizzo Byte: indirizzo di partenza memoria + /// dimensione singolo slot in byte + /// indirizzo bit: numero riga x calcolo indice bit + /// + protected static otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = Convert.ToInt32(valori[0]) - 1; + } + catch + { } + int resto = 0; + Math.DivRem(BitNum, 8, out resto); + string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + /// + /// Decodifica file MAP (caso FANUC/OSAI/...) + /// + /// + /// + /// tipo memoria (R/D/...) + /// indirizzo Byte: indirizzo di partenza memoria + /// dimensione singolo slot in byte + /// indirizzo bit: numero riga x calcolo indice bit + /// + protected static otherData decodeBitData(string linea, char separator, string memPre, int baseAddr, int memSize, int numRiga) + { + string[] valori = linea.Split(separator); + int shift = 0; + try + { + shift = (Convert.ToInt32(valori[0]) - 1) / (8 * memSize); + } + catch + { } + int resto = 0; + Math.DivRem(numRiga, 8 * memSize, out resto); + string memAddr = string.Format("{0}{1}.{2}", memPre, baseAddr + shift, resto); + return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim()); + } + /// + /// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria + /// + /// nome vettore memoria + /// file origine + /// dimensione (in byte) della memoria + /// dimensione (in byte) della memoria + public static void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett) + { + otherData lastData = new otherData(); + int totRighe = 0; + string linea; + totRighe = File.ReadLines(nomeFile).Count(); + // creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco... + vettoreConf = new otherData[File.ReadLines(nomeFile).Count()]; + // carica da file... + StreamReader file = new StreamReader(nomeFile); + // leggo 1 linea alla volta... + int numRiga = 0; + int bitNum = 0; + int byteNum = 0; + while ((linea = file.ReadLine()) != null) + { + // SE non è un commento... + if (linea.Substring(0, 1) != "#") + { + // se finisce per BIT allora processo bit-a-bit... + if (linea.EndsWith("BOOL")) + { + try + { + string[] memIdx = linea.Split(utils.CRC("charSep"))[0].Split('.'); + // calcolo bit e byte number... + int.TryParse(memIdx[0], out byteNum); + if (memIdx.Length > 1) + { + int.TryParse(memIdx[1], out bitNum); + } + else + { + bitNum = 0; + } + } + catch + { + byteNum = 0; + bitNum = 0; + } + lastData = decodeBitData(linea, utils.CRC("charSep"), byteNum, 1, bitNum); + vettoreConf[numRiga] = lastData; + } + else + { + lastData = decodeOtherData(linea, utils.CRC("charSep"), "", 1, memSize); + vettoreConf[numRiga] = lastData; + } + numRiga++; + } + } + // salvo lunghezza file... + try + { + numVett = Convert.ToInt32(lastData.memAddr) + 1; + } + catch + { + numVett = numRiga + 1; + } + // chiudo file + file.Close(); + // ora trimmo vettore al solo numero VERO dei valori caricati... + Array.Resize(ref vettoreConf, numRiga); + + if (utils.CRB("verbose")) lg.Info(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile)); + } + } + + /// + /// Dato generico (per decodifica) + /// + public class otherData + { + public string codNum; + public string memAddr; + public string varName; + public string dataType; + public otherData() + { + codNum = ""; + memAddr = ""; + varName = ""; + dataType = ""; + } + public otherData(string _codNum, string _memAddr, string _varName, string _dataType) + { + codNum = _codNum; + memAddr = _memAddr; + varName = _varName; + dataType = _dataType; + } + } + +}