Beispiel #1
0
    def run(self):
        """
        Start SWAP server thread
        """       
        try:
            # Network configuration settings
            self._xmlnetwork = XmlNetwork(self._xmlSettings.network_file)
            self.devaddress = self._xmlnetwork.devaddress
            self.security = self._xmlnetwork.security
            self.password = Password(self._xmlnetwork.password)
            
            # Serial configuration settings
            self._xmlserial = XmlSerial(self._xmlSettings.serial_file)
        
            # Create and start serial modem object
            self.modem = SerialModem(self._xmlserial.port, self._xmlserial.speed, self.verbose)

            # Declare receiving callback function
            self.modem.setRxCallback(self._ccPacketReceived)
    
            # Set modem configuration from _xmlnetwork
            param_changed = False
            # Device address
            if self._xmlnetwork.devaddress is not None:
                if self.modem.devaddress != self._xmlnetwork.devaddress:
                    if self.modem.setDevAddress(self._xmlnetwork.devaddress) == False:
                        raise SwapException("Unable to set modem's device address to " + self._xmlnetwork.devaddress)
                    else:
                        param_changed = True
            # Device address
            if self._xmlnetwork.network_id is not None:
                if self.modem.syncword != self._xmlnetwork.network_id:
                    if self.modem.setSyncWord(self._xmlnetwork.network_id) == False:
                        raise SwapException("Unable to set modem's network ID to " + self._xmlnetwork.network_id)
                    else:
                        param_changed = True
            # Frequency channel
            if self._xmlnetwork.freq_channel is not None:
                if self.modem.freq_channel != self._xmlnetwork.freq_channel:
                    if self.modem.setFreqChannel(self._xmlnetwork.freq_channel) == False:
                        raise SwapException("Unable to set modem's frequency channel to " + self._xmlnetwork.freq_channel)
                    else:
                        param_changed = True
    
            # Return to data mode if necessary
            if param_changed == True:
                self.modem.goToDataMode()
                            
            self.is_running = True
            
            # Notify parent about the start of the server
            self._eventHandler.swapServerStarted()
                    
            # Discover motes in the current SWAP network
            self._discoverMotes()
        except SwapException:
            threading.Thread.__init__(self)
            raise
        
        threading.Thread.__init__(self)        
Beispiel #2
0
    def run(self):
        """
        Start SWAP server thread
        """       
        try:
            # Network configuration settings
            self._xmlnetwork = XmlNetwork(self._xmlSettings.network_file)
            self.devaddress = self._xmlnetwork.devaddress
            self.security = self._xmlnetwork.security
            self.password = Password(self._xmlnetwork.password)
            
            # Serial configuration settings
            self._xmlserial = XmlSerial(self._xmlSettings.serial_file)
        
            # Create and start serial modem object
            self.modem = SerialModem(self._xmlserial.port, self._xmlserial.speed, self.verbose)

            # Declare receiving callback function
            self.modem.setRxCallback(self._ccPacketReceived)
    
            # Set modem configuration from _xmlnetwork
            param_changed = False
            # Device address
            if self._xmlnetwork.devaddress is not None:
                if self.modem.devaddress != self._xmlnetwork.devaddress:
                    if self.modem.setDevAddress(self._xmlnetwork.devaddress) == False:
                        raise SwapException("Unable to set modem's device address to " + self._xmlnetwork.devaddress)
                    else:
                        param_changed = True
            # Device address
            if self._xmlnetwork.network_id is not None:
                if self.modem.syncword != self._xmlnetwork.network_id:
                    if self.modem.setSyncWord(self._xmlnetwork.network_id) == False:
                        raise SwapException("Unable to set modem's network ID to " + self._xmlnetwork.network_id)
                    else:
                        param_changed = True
            # Frequency channel
            if self._xmlnetwork.freq_channel is not None:
                if self.modem.freq_channel != self._xmlnetwork.freq_channel:
                    if self.modem.setFreqChannel(self._xmlnetwork.freq_channel) == False:
                        raise SwapException("Unable to set modem's frequency channel to " + self._xmlnetwork.freq_channel)
                    else:
                        param_changed = True
    
            # Return to data mode if necessary
            if param_changed == True:
                self.modem.goToDataMode()
                            
            self.is_running = True
            
            # Notify parent about the start of the server
            self._eventHandler.swapServerStarted()
                    
            # Discover motes in the current SWAP network
            self._discoverMotes()
        except SwapException:
            threading.Thread.__init__(self)
            raise
        
        threading.Thread.__init__(self)        
Beispiel #3
0
class SwapServer(threading.Thread):
    """
    SWAP server class
    """
    # Maximum waiting time (in ms) for ACK's
    _MAX_WAITTIME_ACK = 2000
    # Max tries for any SWAP command
    _MAX_SWAP_COMMAND_TRIES = 3

   
    def run(self):
        """
        Start SWAP server thread
        """       
        try:
            # Network configuration settings
            self._xmlnetwork = XmlNetwork(self._xmlSettings.network_file)
            self.devaddress = self._xmlnetwork.devaddress
            self.security = self._xmlnetwork.security
            self.password = Password(self._xmlnetwork.password)
            
            # Serial configuration settings
            self._xmlserial = XmlSerial(self._xmlSettings.serial_file)
        
            # Create and start serial modem object
            self.modem = SerialModem(self._xmlserial.port, self._xmlserial.speed, self.verbose)

            # Declare receiving callback function
            self.modem.setRxCallback(self._ccPacketReceived)
    
            # Set modem configuration from _xmlnetwork
            param_changed = False
            # Device address
            if self._xmlnetwork.devaddress is not None:
                if self.modem.devaddress != self._xmlnetwork.devaddress:
                    if self.modem.setDevAddress(self._xmlnetwork.devaddress) == False:
                        raise SwapException("Unable to set modem's device address to " + self._xmlnetwork.devaddress)
                    else:
                        param_changed = True
            # Network id
            if self._xmlnetwork.network_id is not None:
                if self.modem.syncword != self._xmlnetwork.network_id:
                    if self.modem.setSyncWord(self._xmlnetwork.network_id) == False:
                        raise SwapException("Unable to set modem's network ID to " + self._xmlnetwork.network_id)
                    else:
                        param_changed = True
            # Frequency channel
            if self._xmlnetwork.freq_channel is not None:
                if self.modem.freq_channel != self._xmlnetwork.freq_channel:
                    if self.modem.setFreqChannel(self._xmlnetwork.freq_channel) == False:
                        raise SwapException("Unable to set modem's frequency channel to " + self._xmlnetwork.freq_channel)
                    else:
                        param_changed = True
    
            # Return to data mode if necessary
            if param_changed == True:
                self.modem.goToDataMode()
                            
            self.is_running = True
            
            # Notify parent about the start of the server
            self._eventHandler.swapServerStarted()
                    
            # Discover motes in the current SWAP network
            self._discoverMotes()
        except SwapException as ex:
            threading.Thread.__init__(self)
            # Report error to SwapInterface
            self._eventHandler.swapServerError(ex)
        
        threading.Thread.__init__(self)        
           

    def stop(self):
        """
        Stop SWAP server
        """
        
        print "Stopping SWAP server..."
        
        # Stop modem
        if self.modem is not None:
            self.modem.stop()
        self.is_running = False
        
        # Save network data
        print "Saving network data..."
        
        try:
            self.network.save()
        except SwapException:
            raise
        
        threading.Thread.__init__(self)


    def resetNetwork(self):
        """
        Clear SWAP network data and read swapnet file again
        """
        # Clear network data
        self.network.read()

        
    def _ccPacketReceived(self, ccPacket):
        """
        CcPacket received
        
        @param ccPacket: CcPacket received        
        """
        try:
            # Convert CcPacket into SwapPacket
            swPacket = SwapPacket(ccPacket)
            # Notify event
            self._eventHandler.swapPacketReceived(swPacket)  
        except SwapException:
            return
        
        # Check function code
        # STATUS packet received
        if swPacket.function == SwapFunction.STATUS:
            if swPacket.value is None:
                return
            try:
                # Check status message (ecpected response, nonce, ...)?
                self._checkStatus(swPacket)
            except SwapException:
                raise
            # Check type of data received
            # Product code received
            if swPacket.regId == SwapRegId.ID_PRODUCT_CODE:
                try:
                    extended_address = (swPacket.function & 0x80) != 0
                    mote = SwapMote(self, swPacket.value.toAsciiHex(), swPacket.srcAddress, swPacket.security, swPacket.nonce, extended_address)
                    mote.nonce = swPacket.nonce
                    self._checkMote(mote)
                except IOError as ex:
                    raise SwapException("Unable to create mote: {0}".format(ex))
                except SwapException:
                    raise
            # Device address received
            elif swPacket.regId == SwapRegId.ID_DEVICE_ADDR:
                # Check address in list of motes
                if self._updateMoteAddress(swPacket.srcAddress, swPacket.value.toInteger()):
                    # Update network file
                    self.network.save()
            # System state received
            elif swPacket.regId == SwapRegId.ID_SYSTEM_STATE:
                self._updateMoteState(swPacket)
            # Periodic Tx interval received
            elif swPacket.regId == SwapRegId.ID_TX_INTERVAL:
                # Update interval in list of motes
                if self._updateMoteTxInterval(swPacket):
                    # Update network file
                    self.network.save()
            # For any other register id
            else:
                # Update register in the list of motes
                self._updateRegisterValue(swPacket)
        # QUERY packet received
        elif swPacket.function == SwapFunction.QUERY:
            # Query addressed to our gateway?
            if swPacket.destAddress == self.modem.devaddress:
                # Get mote from register address
                mote = self.network.get_mote(address=swPacket.regAddress)
                if mote is not None:
                    # Send status packet
                    self.send_status(mote, swPacket.regId)
        # COMMAND packet received
        elif swPacket.function == SwapFunction.COMMAND:
            # Command addressed to our gateway?
            if swPacket.destAddress == self.modem.devaddress:
                # Get mote from register address
                mote = self.network.get_mote(address=swPacket.regAddress)
                if mote is not None:
                    # Anti-playback security enabled?
                    if self._xmlnetwork.security & 0x01:
                        # Check nonces
                        if mote.nonce != swPacket.nonce:
                            # Nonce missmatch. Transmit correct nonce
                            self.send_nonce()
                            return               
                    # Send command packet to target mote
                    self.setMoteRegister(mote, swPacket.regId, swPacket.value, sendack=True)
                    

    def _checkMote(self, mote):
        """
        Check SWAP mote from against the current list
        
        @param mote: to be searched in the list
        """
        # Add mote to the network
        if self.network.add_mote(mote):
            # Save mote in SWAP network file
            self.network.save()
            # Notify event handler about the discovery of a new mote
            if self._eventHandler.newMoteDetected is not None:
                self._eventHandler.newMoteDetected(mote)
            # Notify the event handler about the discovery of new endpoints
            if mote.regular_registers is not None:
                for reg in mote.regular_registers:
                    for endp in reg.parameters:
                        if  self._eventHandler.newEndpointDetected is not None:
                            self._eventHandler.newEndpointDetected(endp)
                       
        if self._poll_regular_regs:
            # Query all individual registers owned by this mote
            if mote.regular_registers is not None:
                for reg in mote.regular_registers:
                    reg.sendSwapQuery()
            
            
    def _updateMoteAddress(self, oldAddr, newAddr):
        """
        Update new mote address in list
        
        @param oldAddr: Old address
        @param newAddr: New address
        
        @return True if the value changed. False otherwise
        """
        # Has the address really changed?
        if oldAddr == newAddr:
            return False
        # Get mote from list
        mote = self.network.get_mote(address=oldAddr)
        if mote is not None:
            mote.address = newAddr
            # Notify address change to event handler
            if self._eventHandler.moteAddressChanged is not None:
                self._eventHandler.moteAddressChanged(mote)
                
            return True
        return False


    def _updateMoteState(self, packet):
        """
        Update mote state in list

        @param packet: SWAP packet to extract the information from
        
        @return True if the value changed. False otherwise
        """
        # New system state
        state = packet.value.toInteger()

        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Has the state really changed?
            if mote.state == state:
                return False

            # Update mote's state
            mote.update_state(state)
            
            # Notify state change to event handler
            if self._eventHandler.moteStateChanged is not None:
                self._eventHandler.moteStateChanged(mote)

            return True
        return False
    

    def _updateMoteTxInterval(self, packet):
        """
        Update mote Tx interval in list

        @param packet: SWAP packet to extract the information from
        
        @return True if the value changed. False otherwise
        """
        # New periodic Tx interval (in seconds)
        interval = packet.value.toInteger()

        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Has the interval really changed?
            if mote.txinterval == interval:
                return False

            # Update system state in the list
            mote.txinterval = interval
            
            return True
        return False
       
        
    def _updateRegisterValue(self, packet):
        """
        Update register value in the list of motes

        @param packet: SWAP packet to extract the information from
        """
        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Search within its list of regular registers
            if mote.regular_registers is not None:
                for reg in mote.regular_registers:
                    # Same register ID?
                    if reg.id == packet.regId:
                        # Check if value changed and its length
                        if reg.value is not None:
                            if packet.value is None:
                                return
                            if reg.getLength() != packet.value.getLength():
                                return
                            if reg.value.isEqual(packet.value):
                                return

                        # Save new register value
                        reg.setValue(packet.value)
                        # Notify register'svalue change to event handler
                        if self._eventHandler.registerValueChanged is not None:
                            self._eventHandler.registerValueChanged(reg)
                        # Notify endpoint's value change to event handler
                        if self._eventHandler.endpointValueChanged is not None:
                            # Has any of the endpoints changed?
                            for endp in reg.parameters:
                                if endp.valueChanged == True:
                                    self._eventHandler.endpointValueChanged(endp)
                        return
            # Search within its list of config registers
            if mote.config_registers is not None:
                for reg in mote.config_registers:
                    # Same register ID?
                    if reg.id == packet.regId:
                        # Did register's value change?
                        if not reg.value.isEqual(packet.value):
                            # Save new register value
                            reg.setValue(packet.value)
                            # Notify register'svalue change to event handler
                            if self._eventHandler.registerValueChanged is not None:
                                self._eventHandler.registerValueChanged(reg)
                            # Notify parameter's value change to event handler
                            if self._eventHandler.parameterValueChanged is not None:
                                # Has any of the endpoints changed?
                                for param in reg.parameters:
                                    if param.valueChanged == True:
                                        self._eventHandler.parameterValueChanged(param)
                            # Update network file
                            self.network.save()
                            return
            return


    def _checkStatus(self, status):
        """
        Compare expected SWAP status against status packet received
        Update security nonces

        @param status: SWAP packet to extract the information from
        """
        # Check possible command ACK
        if (self._expectedAck is not None) and (status.function == SwapFunction.STATUS):
            if status.regAddress == self._expectedAck.regAddress:
                if status.regId == self._expectedAck.regId:
                    self._packetAcked = self._expectedAck.value.isEqual(status.value) 

        # Check possible response to a precedent query
        self._valueReceived = None
        if (self._expectedRegister is not None) and (status.function == SwapFunction.STATUS):
            if status.regAddress == self._expectedRegister.getAddress():
                if status.regId == self._expectedRegister.id:
                    self._valueReceived = status.value

        # Update security option and nonce in list
        mote = self.network.get_mote(address=status.srcAddress)
        
        if mote is not None:       
            # Check nonce?
            if self._xmlnetwork.security & 0x01:
                # Discard status packet in case of incorrect nonce
                if mote.nonce > 0 and status.nonce != 1:
                    lower_limit = mote.nonce
                    upper_limit = mote.nonce + 5
                    
                    
                    if upper_limit > 0xFF:
                        upper_limit -= 0x100
                                                
                    if not (lower_limit < status.nonce <= upper_limit):
                        if (lower_limit > upper_limit):
                            if not (lower_limit < status.nonce <= 0xFF):
                                if not (status.nonce <= upper_limit):
                                    raise SwapException("Mote " + str(mote.address) + ": anti-playback nonce missmatch. Possible attack!")
                        else:
                            raise SwapException("Mote " + str(mote.address) + ": anti-playback nonce missmatch. Possible attack!")
                
            mote.security = status.security
            mote.nonce = status.nonce
            

    def _discoverMotes(self):
        """
        Send broadcasted query to all available (awaken) motes asking them
        to identify themselves
        """
        self._poll_regular_regs = True
        query = SwapQueryPacket(SwapRegId.ID_PRODUCT_CODE)
        query.send(self)
        t = threading.Timer(20.0, self._endPollingValues)
        t.start()


    def _endPollingValues(self):
        """
        End polling regular registers each time a product code is received
        """
        self._poll_regular_regs = False


    def send_status(self, mote, regid):
        """
        Send status message informing about a register

        @param mote: Mote containing the register
        @param regid: Register ID
        """
        # Get register
        reg = mote.getRegister(regid)
        if reg is not None:
            # Status packet to be sent
            status = SwapStatusPacket(mote.address, regid, reg.value)
            status.srcAddress = self._xmlnetwork.devaddress
            self.nonce += 1
            if self.nonce > 0xFF:
                self.nonce = 0
            status.nonce = self.nonce
            status.send(self)    


    def send_nonce(self):
        """
        Transmit server's current nonce
        """
        # Convert nonce to SWAP value
        value = SwapValue(self.nonce)
        # Status packet to be sent
        status = SwapStatusPacket(self._xmlnetwork.devaddress, SwapRegId.ID_SECU_NONCE, value)
        self.nonce += 1
        if self.nonce > 0xFF:
            self.nonce = 0
        status.nonce = self.nonce
        status.send(self)


    def setMoteRegister(self, mote, regid, value, sendack=False):
        """
        Set new register value on wireless mote
        Non re-entrant method!!

        @param mote: Mote containing the register
        @param regid: Register ID
        @param value: New register value
        @param sendack; Send status message from server

        @return True if the command is correctly ack'ed. Return False otherwise
        """
        # Send command multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send command            
            ack = mote.cmdRegister(regid, value)
            # Wait for aknowledgement from mote
            if self._waitForAck(ack, SwapServer._MAX_WAITTIME_ACK):
                if sendack:
                    # Send status message
                    self.send_status(mote, regid)
                return True;    # ACK received
        return False            # Got no ACK from mote


    def setEndpointValue(self, endpoint, value):
        """
        Set endpoint value

        @param endpoint: Endpoint to be controlled
        @param value: New endpoint value

        @return True if the command is correctly ack'ed. Return False otherwise
        """
        # Send command multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send command            
            ack = endpoint.sendSwapCmd(value)
            # Wait for aknowledgement from mote
            if self._waitForAck(ack, SwapServer._MAX_WAITTIME_ACK):
                return True;    # ACK received
        return False            # Got no ACK from mote


    def queryMoteRegister(self, mote, regId):
        """
        Query mote register, wait for response and return value
        Non re-entrant method!!
        
        @param mote: Mote containing the register
        @param regId: Register ID
        
        @return register value
        """
        # Queried register
        register = SwapRegister(mote, regId)
        # Send query multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send query
            register.sendSwapQuery()
            # Wait for aknowledgement from mote
            regVal = self._waitForReg(register, SwapServer._MAX_WAITTIME_ACK)
            if regVal is not None:
                break   # Got response from mote
        return regVal


    def _waitForAck(self, ackpacket, wait_time):
        """
        Wait for ACK (SWAP status packet)
        Non re-entrant method!!

        @param ackpacket: SWAP status packet to expect as a valid ACK
        @param wait_time: Max waiting time in milliseconds
        
        @return True if the ACK is received. False otherwise
        """
        self._packetAcked = False
        # Expected ACK packet (SWAP status)
        self._expectedAck = ackpacket
        
        #loops = wait_time / 10
        start = time.time()
        while not self._packetAcked:
            time.sleep(0.1)
            if (time.time() - start)*1000 >= wait_time:
                break
            
        res = self._packetAcked
        self._expectedAck = None
        self._packetAcked = False
        return res


    def _waitForReg(self, register, waitTime):
        """
        Wait for ACK (SWAP status packet)
        Non re-entrant method!!
        
        @param register: Expected register to be informed about
        @param waitTime: Max waiting time in milliseconds
        
        @return True if the ACK is received. False otherwise
        """
        # Expected ACK packet (SWAP status)
        self._expectedRegister = register

        loops = waitTime / 10
        while self._valueReceived is None:
            time.sleep(0.01)
            loops -= 1
            if loops == 0:
                break

        res = self._valueReceived
        self._expectedRegister = None
        self._valueReceived = None
        return res


    def getNetId(self):
        """
        Get current network ID
        
        @return Network ID
        """
        return self.modem.syncword


    def update_definition_files(self):
        """
        Update Device Definition Files from remote server
        """
        print "Downloading Device Definition Files"

        local_dir = XmlSettings.device_localdir
        try:
            os.stat(local_dir)
        except:
            os.mkdir(local_dir)              
                
        try:
          local_file = XmlSettings.device_localdir + os.sep + "devices.xml"
          remote_file = XmlSettings.device_remote + "/devices.xml"
          remote = urllib2.urlopen(remote_file)
          local = open(local_file, 'wb')
          local.write(remote.read())
          local.close()
        except Exception:
          print "Unable to download devices.xml from remote server"

        device_info = XmlDeviceDir()
    
        # Create developer folders
        for developer in device_info.developers:
            developer_dir = local_dir + os.sep + developer.name
            print "Developer", developer.name, ":"
            try:
                os.stat(developer_dir)
            except:
                os.mkdir(developer_dir)
                
            try:
                # Download device definition files for each developer folder
                for device in developer.devices:
                    device_name = device.option
                    print "Downloading", device.option + ".xml"
                    local_file = developer_dir + os.sep + device_name + ".xml"
                    remote_file = XmlSettings.device_remote + "/" + developer.name + "/" + device_name + ".xml"
                    remote = urllib2.urlopen(remote_file)
                    local = open(local_file, 'wb')
                    local.write(remote.read())
                    local.close()

            except Exception as e:
                print "Unable to update Device Definition File " + device_name + ".xml"
                    
        """
        local_tar = XmlSettings.device_localdir + ".tar"
        
        try:
            remote = urllib2.urlopen(XmlSettings.device_remote)
            local = open(local_tar, 'wb')
            local.write(remote.read())
            local.close()
            
            tar = tarfile.open(local_tar)
            direc = os.path.dirname(XmlSettings.device_localdir)
            tar.extractall(path=direc)
            tar.close()
            
            os.remove(local_tar)
        except:
            print "Unable to update Device Definition Files"
        """
        
        
    def __init__(self, eventHandler, settings=None, start=True):
        """
        Class constructor

        @param eventHandler: Parent event handler object
        @param settings: path to the main configuration file
        @param verbose: Verbose SWAP traffic
        @param start: Start server upon creation if this flag is True
        """
        threading.Thread.__init__(self)
        self._stop = threading.Event()

        ## Serial wireless gateway
        self.modem = None
        # Server's device address
        self.devaddress = 1
        # Server's Security nonce
        self.nonce = 0
        # Security option
        self.security = 0
        # Encryption password
        self.password = 0
        # True if last packet was ack'ed
        self._packetAcked = False
        # Expected ACK packet (SWAP status packet containing a given endpoint data)
        self._expectedAck = None
        # Value received about register being queried
        self._valueReceived = None
        # Register being queried
        self._expectedRegister = None

        # Event handling object. Its class must define the following methods
        # in order to dispatch incoming SWAP events:
        # - newMoteDetected(mote)
        # - newEndpointDetected(endpoint)
        # - newParameterDetected(parameter)
        # - moteStateChanged(mote)
        # - moteAddressChanged(mote)
        # - registerValueChanged(register)
        # - endpointValueChanged(endpoint)
        # - parameterValueChanged(parameter)
        self._eventHandler = eventHandler

        # General settings
        self._xmlSettings = XmlSettings(settings)

        # Update Device Definition Files from Internet server
        if self._xmlSettings.updatedef:
            self.update_definition_files()

        ## Verbose SWAP frames
        self.verbose = False
        if self._xmlSettings.debug > 0:
            self.verbose = True

        ## Network data
        self.network = SwapNetwork(self, self._xmlSettings.swap_file)

        ## Tells us if the server is running
        self.is_running = False
        
        ## Poll regular registers whenever a product code packet is received
        self._poll_regular_regs = False
        
        # Start server
        if start:
            self.start()
Beispiel #4
0
class SwapServer(threading.Thread):
    """
    SWAP server class
    """
    # Maximum waiting time (in ms) for ACK's
    _MAX_WAITTIME_ACK = 2000
    # Max tries for any SWAP command
    _MAX_SWAP_COMMAND_TRIES = 3

    def run(self):
        """
        Start SWAP server thread
        """
        try:
            # Network configuration settings
            self._xmlnetwork = XmlNetwork(self._xmlSettings.network_file)
            self.devaddress = self._xmlnetwork.devaddress
            self.security = self._xmlnetwork.security
            self.password = Password(self._xmlnetwork.password)

            # Serial configuration settings
            self._xmlserial = XmlSerial(self._xmlSettings.serial_file)

            # Create and start serial modem object
            self.modem = SerialModem(self._xmlserial.port,
                                     self._xmlserial.speed, self.verbose)

            # Declare receiving callback function
            self.modem.setRxCallback(self._ccPacketReceived)

            # Set modem configuration from _xmlnetwork
            param_changed = False
            # Device address
            if self._xmlnetwork.devaddress is not None:
                if self.modem.devaddress != self._xmlnetwork.devaddress:
                    if self.modem.setDevAddress(
                            self._xmlnetwork.devaddress) == False:
                        raise SwapException(
                            "Unable to set modem's device address to " +
                            self._xmlnetwork.devaddress)
                    else:
                        param_changed = True
            # Network id
            if self._xmlnetwork.network_id is not None:
                if self.modem.syncword != self._xmlnetwork.network_id:
                    if self.modem.setSyncWord(
                            self._xmlnetwork.network_id) == False:
                        raise SwapException(
                            "Unable to set modem's network ID to " +
                            self._xmlnetwork.network_id)
                    else:
                        param_changed = True
            # Frequency channel
            if self._xmlnetwork.freq_channel is not None:
                if self.modem.freq_channel != self._xmlnetwork.freq_channel:
                    if self.modem.setFreqChannel(
                            self._xmlnetwork.freq_channel) == False:
                        raise SwapException(
                            "Unable to set modem's frequency channel to " +
                            self._xmlnetwork.freq_channel)
                    else:
                        param_changed = True

            # Return to data mode if necessary
            if param_changed == True:
                self.modem.goToDataMode()

            self.is_running = True

            # Notify parent about the start of the server
            self._eventHandler.swapServerStarted()

            # Discover motes in the current SWAP network
            self._discoverMotes()
        except SwapException as ex:
            threading.Thread.__init__(self)
            # Report error to SwapInterface
            self._eventHandler.swapServerError(ex)

        threading.Thread.__init__(self)

    def stop(self):
        """
        Stop SWAP server
        """

        print "Stopping SWAP server..."

        # Stop modem
        if self.modem is not None:
            self.modem.stop()
        self.is_running = False

        # Save network data
        print "Saving network data..."

        try:
            self.network.save()
        except SwapException:
            raise

        threading.Thread.__init__(self)

    def resetNetwork(self):
        """
        Clear SWAP network adata nd read swapnet file again
        """
        # Clear network data
        self.network.read()

    def _ccPacketReceived(self, ccPacket):
        """
        CcPacket received
        
        @param ccPacket: CcPacket received        
        """
        try:
            # Convert CcPacket into SwapPacket
            swPacket = SwapPacket(ccPacket)
            # Notify event
            self._eventHandler.swapPacketReceived(swPacket)
        except SwapException:
            return

        # Check function code
        # STATUS packet received
        if swPacket.function == SwapFunction.STATUS:
            if swPacket.value is None:
                return
            try:
                # Check status message (ecpected response, nonce, ...)?
                self._checkStatus(swPacket)
            except SwapException:
                raise
            # Check type of data received
            # Product code received
            if swPacket.regId == SwapRegId.ID_PRODUCT_CODE:
                try:
                    extended_address = (swPacket.function & 0x80) != 0
                    mote = SwapMote(self, swPacket.value.toAsciiHex(),
                                    swPacket.srcAddress, swPacket.security,
                                    swPacket.nonce, extended_address)
                    mote.nonce = swPacket.nonce
                    self._checkMote(mote)
                except IOError as ex:
                    raise SwapException(
                        "Unable to create mote: {0}".format(ex))
                except SwapException:
                    raise
            # Device address received
            elif swPacket.regId == SwapRegId.ID_DEVICE_ADDR:
                # Check address in list of motes
                if self._updateMoteAddress(swPacket.srcAddress,
                                           swPacket.value.toInteger()):
                    # Update network file
                    self.network.save()
            # System state received
            elif swPacket.regId == SwapRegId.ID_SYSTEM_STATE:
                self._updateMoteState(swPacket)
            # Periodic Tx interval received
            elif swPacket.regId == SwapRegId.ID_TX_INTERVAL:
                # Update interval in list of motes
                if self._updateMoteTxInterval(swPacket):
                    # Update network file
                    self.network.save()
            # For any other register id
            else:
                # Update register in the list of motes
                self._updateRegisterValue(swPacket)
        # QUERY packet received
        elif swPacket.function == SwapFunction.QUERY:
            # Query addressed to our gateway?
            if swPacket.destAddress == self.modem.devaddress:
                # Get mote from register address
                mote = self.network.get_mote(address=swPacket.regAddress)
                if mote is not None:
                    # Send status packet
                    self.send_status(mote, swPacket.regId)
        # COMMAND packet received
        elif swPacket.function == SwapFunction.COMMAND:
            # Command addressed to our gateway?
            if swPacket.destAddress == self.modem.devaddress:
                # Get mote from register address
                mote = self.network.get_mote(address=swPacket.regAddress)
                if mote is not None:
                    # Anti-playback security enabled?
                    if self._xmlnetwork.security & 0x01:
                        # Check nonces
                        if mote.nonce != swPacket.nonce:
                            # Nonce missmatch. Transmit correct nonce
                            self.send_nonce()
                            return
                    # Send command packet to target mote
                    self.setMoteRegister(mote,
                                         swPacket.regId,
                                         swPacket.value,
                                         sendack=True)

    def _checkMote(self, mote):
        """
        Check SWAP mote from against the current list
        
        @param mote: to be searched in the list
        """
        # Add mote to the network
        if self.network.add_mote(mote):
            # Save mote in SWAP network file
            self.network.save()
            # Notify event handler about the discovery of a new mote
            if self._eventHandler.newMoteDetected is not None:
                self._eventHandler.newMoteDetected(mote)
            # Notify the event handler about the discovery of new endpoints
            for reg in mote.regular_registers:
                for endp in reg.parameters:
                    if self._eventHandler.newEndpointDetected is not None:
                        self._eventHandler.newEndpointDetected(endp)

        if self._poll_regular_regs:
            # Query all individual registers owned by this mote
            for reg in mote.regular_registers:
                reg.sendSwapQuery()

    def _updateMoteAddress(self, oldAddr, newAddr):
        """
        Update new mote address in list
        
        @param oldAddr: Old address
        @param newAddr: New address
        
        @return True if the value changed. False otherwise
        """
        # Has the address really changed?
        if oldAddr == newAddr:
            return False
        # Get mote from list
        mote = self.network.get_mote(address=oldAddr)
        if mote is not None:
            mote.address = newAddr
            # Notify address change to event handler
            if self._eventHandler.moteAddressChanged is not None:
                self._eventHandler.moteAddressChanged(mote)

            return True
        return False

    def _updateMoteState(self, packet):
        """
        Update mote state in list

        @param packet: SWAP packet to extract the information from
        
        @return True if the value changed. False otherwise
        """
        # New system state
        state = packet.value.toInteger()

        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Has the state really changed?
            if mote.state == state:
                return False

            # Update mote's state
            mote.update_state(state)

            # Notify state change to event handler
            if self._eventHandler.moteStateChanged is not None:
                self._eventHandler.moteStateChanged(mote)

            return True
        return False

    def _updateMoteTxInterval(self, packet):
        """
        Update mote Tx interval in list

        @param packet: SWAP packet to extract the information from
        
        @return True if the value changed. False otherwise
        """
        # New periodic Tx interval (in seconds)
        interval = packet.value.toInteger()

        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Has the interval really changed?
            if mote.txinterval == interval:
                return False

            # Update system state in the list
            mote.txinterval = interval

            return True
        return False

    def _updateRegisterValue(self, packet):
        """
        Update register value in the list of motes

        @param packet: SWAP packet to extract the information from
        """
        # Get mote from list
        mote = self.network.get_mote(address=packet.regAddress)
        if mote is not None:
            # Search within its list of regular registers
            if mote.regular_registers is not None:
                for reg in mote.regular_registers:
                    # Same register ID?
                    if reg.id == packet.regId:
                        # Check if value changed and its length
                        if reg.value is not None:
                            if reg.value.isEqual(packet.value):
                                return
                            if packet.value is None:
                                return
                            if reg.getLength() != packet.value.getLength():
                                return

                        # Save new register value
                        reg.setValue(packet.value)
                        # Notify register'svalue change to event handler
                        if self._eventHandler.registerValueChanged is not None:
                            self._eventHandler.registerValueChanged(reg)
                        # Notify endpoint's value change to event handler
                        if self._eventHandler.endpointValueChanged is not None:
                            # Has any of the endpoints changed?
                            for endp in reg.parameters:
                                if endp.valueChanged == True:
                                    self._eventHandler.endpointValueChanged(
                                        endp)
                        return
            # Search within its list of config registers
            if mote.config_registers is not None:
                for reg in mote.config_registers:
                    # Same register ID?
                    if reg.id == packet.regId:
                        # Did register's value change?
                        if not reg.value.isEqual(packet.value):
                            # Save new register value
                            reg.setValue(packet.value)
                            # Notify register'svalue change to event handler
                            if self._eventHandler.registerValueChanged is not None:
                                self._eventHandler.registerValueChanged(reg)
                            # Notify parameter's value change to event handler
                            if self._eventHandler.parameterValueChanged is not None:
                                # Has any of the endpoints changed?
                                for param in reg.parameters:
                                    if param.valueChanged == True:
                                        self._eventHandler.parameterValueChanged(
                                            param)
                            # Update network file
                            self.network.save()
                            return
            return

    def _checkStatus(self, status):
        """
        Compare expected SWAP status against status packet received
        Update security nonces

        @param status: SWAP packet to extract the information from
        """
        # Check possible command ACK
        if (self._expectedAck is not None) and (status.function
                                                == SwapFunction.STATUS):
            if status.regAddress == self._expectedAck.regAddress:
                if status.regId == self._expectedAck.regId:
                    self._packetAcked = self._expectedAck.value.isEqual(
                        status.value)

        # Check possible response to a precedent query
        self._valueReceived = None
        if (self._expectedRegister is not None) and (status.function
                                                     == SwapFunction.STATUS):
            if status.regAddress == self._expectedRegister.getAddress():
                if status.regId == self._expectedRegister.id:
                    self._valueReceived = status.value

        # Update security option and nonce in list
        mote = self.network.get_mote(address=status.srcAddress)

        if mote is not None:
            # Check nonce?
            if self._xmlnetwork.security & 0x01:
                # Discard status packet in case of incorrect nonce
                if mote.nonce > 0 and status.nonce != 1:
                    lower_limit = mote.nonce
                    upper_limit = mote.nonce + 5

                    if upper_limit > 0xFF:
                        upper_limit -= 0x100

                    if not (lower_limit < status.nonce <= upper_limit):
                        if (lower_limit > upper_limit):
                            if not (lower_limit < status.nonce <= 0xFF):
                                if not (status.nonce <= upper_limit):
                                    raise SwapException(
                                        "Mote " + str(mote.address) +
                                        ": anti-playback nonce missmatch. Possible attack!"
                                    )
                        else:
                            raise SwapException(
                                "Mote " + str(mote.address) +
                                ": anti-playback nonce missmatch. Possible attack!"
                            )

            mote.security = status.security
            mote.nonce = status.nonce

    def _discoverMotes(self):
        """
        Send broadcasted query to all available (awaken) motes asking them
        to identify themselves
        """
        self._poll_regular_regs = True
        query = SwapQueryPacket(SwapRegId.ID_PRODUCT_CODE)
        query.send(self)
        t = threading.Timer(20.0, self._endPollingValues)
        t.start()

    def _endPollingValues(self):
        """
        End polling regular registers each time a product code is received
        """
        self._poll_regular_regs = False

    def send_status(self, mote, regid):
        """
        Send status message informing about a register

        @param mote: Mote containing the register
        @param regid: Register ID
        """
        # Get register
        reg = mote.getRegister(regid)
        if reg is not None:
            # Status packet to be sent
            status = SwapStatusPacket(mote.address, regid, reg.value)
            status.srcAddress = self._xmlnetwork.devaddress
            self.nonce += 1
            if self.nonce > 0xFF:
                self.nonce = 0
            status.nonce = self.nonce
            status.send(self)

    def send_nonce(self):
        """
        Transmit server's current nonce
        """
        # Convert nonce to SWAP value
        value = SwapValue(self.nonce)
        # Status packet to be sent
        status = SwapStatusPacket(self._xmlnetwork.devaddress,
                                  SwapRegId.ID_SECU_NONCE, value)
        self.nonce += 1
        if self.nonce > 0xFF:
            self.nonce = 0
        status.nonce = self.nonce
        status.send(self)

    def setMoteRegister(self, mote, regid, value, sendack=False):
        """
        Set new register value on wireless mote
        Non re-entrant method!!

        @param mote: Mote containing the register
        @param regid: Register ID
        @param value: New register value
        @param sendack; Send status message from server

        @return True if the command is correctly ack'ed. Return False otherwise
        """
        # Send command multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send command
            ack = mote.cmdRegister(regid, value)
            # Wait for aknowledgement from mote
            if self._waitForAck(ack, SwapServer._MAX_WAITTIME_ACK):
                if sendack:
                    # Send status message
                    self.send_status(mote, regid)
                return True
                # ACK received
        return False  # Got no ACK from mote

    def setEndpointValue(self, endpoint, value):
        """
        Set endpoint value

        @param endpoint: Endpoint to be controlled
        @param value: New endpoint value

        @return True if the command is correctly ack'ed. Return False otherwise
        """
        # Send command multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send command
            ack = endpoint.sendSwapCmd(value)
            # Wait for aknowledgement from mote
            if self._waitForAck(ack, SwapServer._MAX_WAITTIME_ACK):
                return True
                # ACK received
        return False  # Got no ACK from mote

    def queryMoteRegister(self, mote, regId):
        """
        Query mote register, wait for response and return value
        Non re-entrant method!!
        
        @param mote: Mote containing the register
        @param regId: Register ID
        
        @return register value
        """
        # Queried register
        register = SwapRegister(mote, regId)
        # Send query multiple times if necessary
        for i in range(SwapServer._MAX_SWAP_COMMAND_TRIES):
            # Send query
            register.sendSwapQuery()
            # Wait for aknowledgement from mote
            regVal = self._waitForReg(register, SwapServer._MAX_WAITTIME_ACK)
            if regVal is not None:
                break  # Got response from mote
        return regVal

    def _waitForAck(self, ackpacket, wait_time):
        """
        Wait for ACK (SWAP status packet)
        Non re-entrant method!!

        @param ackpacket: SWAP status packet to expect as a valid ACK
        @param wait_time: Max waiting time in milliseconds
        
        @return True if the ACK is received. False otherwise
        """
        self._packetAcked = False
        # Expected ACK packet (SWAP status)
        self._expectedAck = ackpacket

        #loops = wait_time / 10
        start = time.time()
        while not self._packetAcked:
            time.sleep(0.1)
            if (time.time() - start) * 1000 >= wait_time:
                break

        res = self._packetAcked
        self._expectedAck = None
        self._packetAcked = False
        return res

    def _waitForReg(self, register, waitTime):
        """
        Wait for ACK (SWAP status packet)
        Non re-entrant method!!
        
        @param register: Expected register to be informed about
        @param waitTime: Max waiting time in milliseconds
        
        @return True if the ACK is received. False otherwise
        """
        # Expected ACK packet (SWAP status)
        self._expectedRegister = register

        loops = waitTime / 10
        while self._valueReceived is None:
            time.sleep(0.01)
            loops -= 1
            if loops == 0:
                break

        res = self._valueReceived
        self._expectedRegister = None
        self._valueReceived = None
        return res

    def getNetId(self):
        """
        Get current network ID
        
        @return Network ID
        """
        return self.modem.syncword

    def update_definition_files(self):
        """
        Update Device Definition Files from remote server
        """
        print "Downloading Device Definition Files"
        local_tar = XmlSettings.device_localdir + ".tar"

        try:
            remote = urllib2.urlopen(XmlSettings.device_remote)
            local = open(local_tar, 'wb')
            local.write(remote.read())
            local.close()

            tar = tarfile.open(local_tar)
            direc = os.path.dirname(XmlSettings.device_localdir)
            tar.extractall(path=direc)
            tar.close()

            os.remove(local_tar)
        except:
            print "Unable to update Device Definition Files"

    def __init__(self, eventHandler, settings=None, start=True):
        """
        Class constructor

        @param eventHandler: Parent event handler object
        @param settings: path to the main configuration file
        @param verbose: Verbose SWAP traffic
        @param start: Start server upon creation if this flag is True
        """
        threading.Thread.__init__(self)
        self._stop = threading.Event()

        ## Serial wireless gateway
        self.modem = None
        # Server's device address
        self.devaddress = 1
        # Server's Security nonce
        self.nonce = 0
        # Security option
        self.security = 0
        # Encryption password
        self.password = 0
        # True if last packet was ack'ed
        self._packetAcked = False
        # Expected ACK packet (SWAP status packet containing a given endpoint data)
        self._expectedAck = None
        # Value received about register being queried
        self._valueReceived = None
        # Register being queried
        self._expectedRegister = None

        # Event handling object. Its class must define the following methods
        # in order to dispatch incoming SWAP events:
        # - newMoteDetected(mote)
        # - newEndpointDetected(endpoint)
        # - newParameterDetected(parameter)
        # - moteStateChanged(mote)
        # - moteAddressChanged(mote)
        # - registerValueChanged(register)
        # - endpointValueChanged(endpoint)
        # - parameterValueChanged(parameter)
        self._eventHandler = eventHandler

        # General settings
        self._xmlSettings = XmlSettings(settings)

        # Update Device Definition Files from Internet server
        if self._xmlSettings.updatedef:
            self.update_definition_files()

        ## Verbose SWAP frames
        self.verbose = False
        if self._xmlSettings.debug > 0:
            self.verbose = True

        ## Network data
        self.network = SwapNetwork(self, self._xmlSettings.swap_file)

        ## Tells us if the server is running
        self.is_running = False

        ## Poll regular registers whenever a product code packet is received
        self._poll_regular_regs = False

        # Start server
        if start:
            self.start()