示例#1
0
 def do_disconnect(self, arg: str):
     'Disconnect from an RTU'
     if len(self.__rtu_comms) > 0:
         rtuaddr = runprompt(
             listq(message='Disconnect from which RTU?',
                   choices=self.__rtu_comms.keys()))
         self.__keepalive_kill[rtuaddr] = True  # Stop keepalive
         t = self.__keepalive[rtuaddr]
         t.join()
         self.__rtu_u_state[rtuaddr] = 0x08  # Expect STOPDT con
         pkt = APDU() / APCI(ApduLen=4, Type=0x03, UType=0x04)  # STOPDT act
         self.__rtu_comms[rtuaddr].send(pkt.build())
         while self.__rtu_u_state[
                 rtuaddr] is not None and self.__rtu_u_state[rtuaddr] > 0:
             print(f'\rTerminating connection with {rtuaddr:s} ... ',
                   end='')
             sleep(0.33)
         print('')
         self.__killsignals[rtuaddr] = True
         t = self.__threads.pop(rtuaddr)
         t.join()
         s = self.__rtu_comms.pop(rtuaddr)
         d = self.__rtu_data.pop(rtuaddr)
         k = self.__killsignals.pop(rtuaddr)
         self.__rtu_asdu.pop(rtuaddr)
         s.close()
     else:
         print('Not connected to any RTUs')
示例#2
0
 def do_connect(self, arg: str):
     'Connect to a new RTU'
     try:
         arg = arg.split(';')
         self.__rtu_asdu[arg[0]] = arg[1]
         arg = arg[0]
         assert IPv4_REGEX.match(arg) is not None
         if '/' in arg:
             prefix = int(arg.split('/')[1])
             assert prefix > 0 and prefix <= 32
         s = socket.socket(socket.AF_INET, socket.SOCK_STREAM,
                           socket.IPPROTO_TCP)
         s.settimeout(2)
         s.connect((arg, IEC104_PORT))
         self.__rtu_comms[arg] = s
         self.__killsignals[arg] = False
         self.__rtu_u_state[arg] = 0x02  # Expect a STARTDT con U-frame
         self.__rtu_i_state[arg] = None  # Don't expect any I-frames
         t = Thread(target=self.__handle_rtu, kwargs={
             's': s,
             'k': arg
         })  # Create a receiving thread for this RTU.
         t.start()
         self.__threads[arg] = t
         pkt = APDU() / APCI(ApduLen=4, Type=0x03,
                             UType=0x01)  # STARTDT act
         s.send(pkt.build())
         while self.__rtu_u_state[
                 arg] is not None and self.__rtu_u_state[arg] > 0:
             print(f'\rInitiating connection with peer {arg:s} ... ',
                   end='')
             sleep(0.33)
         print('')
         if self.__rtu_u_state[arg] is None:
             print(f'Unable to connect to {arg:s}')
             self.__killsignals[arg] = True
             t = self.__threads.pop(arg)
             t.join()
             s.close()
             self.__rtu_asdu.pop(arg)
             self.__rtu_comms.pop(arg)
             self.__killsignals.pop(arg)
             self.__rtu_i_state.pop(arg)
             self.__rtu_u_state.pop(arg)
             if arg in self.__rtu_data.keys():
                 self.__rtu_data.pop(arg)
         else:
             self.__keepalive_kill[arg] = False
             t = Thread(target=self.__keepalive_handler,
                        kwargs={
                            's': s,
                            'k': arg
                        })  # Create a keepalive thread for this RTU.
             t.start()
             self.__keepalive[arg] = t
     except AssertionError:
         print('Invalid IPv4 address: %s' % arg)
     except socket.timeout:
         print('Unable to connect to %s' % arg)
     return False
示例#3
0
 def __keepalive_handler(self, s: socket.socket, k:str):
     while not self.__done and not self.__keepalive_kill[k]:
         sleep(10) # Send a keepalive every 10 seconds
         self.__rtu_u_state[k] = 0x20 # Expect a TESTFR con
         pkt = APDU()/APCI(ApduLen=4, Type=0x03, UType=0x10) # 'TESTFR act' as a keepalive
         self.__rtu_comms[k].send(pkt.build())
         while self.__rtu_u_state[k] is not None and self.__rtu_u_state[k] > 0:
             sleep(0.33)
示例#4
0
def build_104_asdu_packet(typeASDU: int,
                          asdu: int,
                          ioa: int,
                          tx: int,
                          rx: int,
                          causeTx: int = 1,
                          **kwargs) -> bytes:
    pkt = APDU()
    pkt /= APCI(ApduLen=APDULEN[typeASDU], Type=0x00, Tx=tx, Rx=rx)
    if typeASDU == 3:
        pkt /= ASDU(TypeId=typeASDU,
                    SQ=0,
                    NumIx=1,
                    CauseTx=causeTx,
                    Test=0,
                    OA=0,
                    Addr=asdu,
                    IOA=[IOA3(IOA=ioa, DIQ=DIQ(DPI=kwargs['value'], flags=0))])
    elif typeASDU == 36:
        ct = cp56time()
        pkt /= ASDU(
            TypeId=typeASDU,
            SQ=0,
            NumIx=1,
            CauseTx=causeTx,
            Test=0,
            OA=0,
            Addr=asdu,
            IOA=[IOA36(IOA=ioa, Value=kwargs['value'], QDS=0x00, CP56Time=ct)])
    elif typeASDU == 45:
        pkt /= ASDU(TypeId=typeASDU,
                    SQ=0,
                    NumIx=1,
                    CauseTx=causeTx,
                    Test=0,
                    OA=0,
                    Addr=asdu,
                    IOA=[
                        IOA45(IOA=ioa,
                              SCO=SCO(SE=kwargs['SE'],
                                      QU=kwargs['QU'],
                                      SCS=kwargs['SCS']))
                    ])
    elif typeASDU == 50:
        pkt /= ASDU(
            TypeId=typeASDU,
            SQ=0,
            NumIx=1,
            CauseTx=causeTx,
            Test=0,
            OA=0,
            Addr=asdu,
            IOA=[IOA50(IOA=ioa, Value=kwargs['value'], QOS=QOS(QL=0, SE=0))])
    else:
        raise AttributeError
    if __name__ == '__main__':
        pkt.show()
    return pkt.build()
示例#5
0
def testfr(actcon: bool = False) -> bytes:
    pkt = APDU() / APCI(ApduLen=4, Type=0x03, UType=0x10 << int(actcon))
    return pkt.build()