def __init__(self, settings=None): """ Class constructor @param settings: path to the main configuration file """ # Callbacks not being used self.registerValueChanged = None # wxPython app self.app = wx.App(False) # Start SWAP server try: # Superclass call SwapInterface.__init__(self, settings, False) # Clear error file SwapException.clear() except SwapException as ex: ex.display() ex.log() # Open SWAP Device Management Tool self.dmtframe = MainFrame("SWAP Device Management Tool", self, server=self.server) #self.dmtframe.SetSize(wx.Size(370,500)) self.app.SetTopWindow(self.dmtframe) self.dmtframe.CenterOnScreen() self.dmtframe.Show(True) self.app.MainLoop()
def __init__(self, portname="/dev/ttyUSB0", speed=38400, verbose=False): """ Class constructor @param portname: Name/path of the serial port @param speed: Serial baudrate in bps @param verbose: Print out SWAP traffic (True or False) """ # Serial mode (command or data modes) self._sermode = SerialModem.Mode.DATA # Response to the last AT command sent to the serial modem self._atresponse = "" # AT response received from modem self.__atresponse_received = None # "Packet received" callback function. To be defined by the parent object self._ccpacket_received = None ## Name(path) of the serial port self.portname = portname ## Speed of the serial port in bps self.portspeed = speed ## Hardware version of the serial modem self.hwversion = None ## Firmware version of the serial modem self.fwversion = None try: # Open serial port self._serport = SerialPort(self.portname, self.portspeed, verbose) # Define callback function for incoming serial packets self._serport.setRxCallback(self._serialPacketReceived) # Run serial port thread self._serport.start() # This flags switches to True when the serial modem is ready self._wait_modem_start = False start = time.time() soft_reset = False while self._wait_modem_start == False: elapsed = time.time() - start if not soft_reset and elapsed > 5: self.reset() soft_reset = True elif soft_reset and elapsed > 10: raise SwapException("Unable to reset serial modem") # Retrieve modem settings # Switch to command mode if not self.goToCommandMode(): raise SwapException("Modem is unable to enter command mode") # Hardware version response = self.runAtCommand("ATHV?\r") if response is None: raise SwapException("Unable to retrieve Hardware Version from serial modem") self.hwversion = long(response, 16) # Firmware version response = self.runAtCommand("ATFV?\r") if response is None: raise SwapException("Unable to retrieve Firmware Version from serial modem") self.fwversion = long(response, 16) # Frequency channel response = self.runAtCommand("ATCH?\r") if response is None: raise SwapException("Unable to retrieve Frequency Channel from serial modem") ## Frequency channel of the serial gateway self.freq_channel = int(response, 16) # Synchronization word response = self.runAtCommand("ATSW?\r") if response is None: raise SwapException("Unable to retrieve Synchronization Word from serial modem") ## Synchronization word of the serial gateway self.syncword = int(response, 16) # Device address response = self.runAtCommand("ATDA?\r") if response is None: raise SwapException("Unable to retrieve Device Address from serial modem") ## Device address of the serial gateway self.devaddress = int(response, 16) # Switch to data mode self.goToDataMode() except: raise
def update(self): """ Update parameter's value, posibly after a change in its parent register """ self.valueChanged = False if self.register is None: raise SwapException("Register not specified for current endpoint") return # Keep old value oldParamVal = self.value.clone() # This is a particular case: endpoint is an ASCII string taking all the # register space if self.type in [SwapType.STRING, SwapType.BSTRING]: self.value = self.register.value else: # Current register value converted to list lstRegVal = self.register.value.toList() # Total bits to be copied indexReg = self.bytePos shiftReg = 7 - self.bitPos bitsToCopy = self.byteSize * 8 + self.bitSize # Current parameter value in list format lstParamVal = self.value.toList() if len(lstParamVal) == 0: return indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if indexReg >= len(lstRegVal): break if (lstRegVal[indexReg] >> shiftReg) & 0x01 == 0: mask = ~(1 << shiftParam) lstParamVal[indexParam] &= mask else: mask = 1 << shiftParam lstParamVal[indexParam] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Did the value change? if not self.value.isEqual(oldParamVal): self.valueChanged = True # Update time stamp self.lastupdate = time.time()
def sendSwapCmd(self, value): """ Send SWAP command for the current endpoint @param value: New endpoint value @return Expected SWAP status response to be received from the mote """ # This is a particular case: endpoint is an ASCII string taking all the # register space if self.type == SwapType.STRING and type(value) in [str, unicode]: lstRegVal = value else: # Convert to SwapValue if value.__class__ is SwapValue: swap_value = value else: # Byte length length = self.byteSize if self.bitSize > 0: length += 1 if type(value) is list: res = value elif type(value) in [str, unicode]: if self.type == SwapType.NUMBER: try: # Possible integer number res = int(value) except ValueError: try: # Possible float number res = float(value) except ValueError: raise SwapException( value + " is not a valid numeric value for " + self.name) elif self.type == SwapType.BINARY: if value.lower() in [ "on", "open", "1", "true", "enabled" ]: res = 1 else: res = 0 else: # SwapType.STRING, SwapType.BSTRING res = value else: res = value if type(res) in [int, float]: if self.unit is not None: res -= self.unit.offset res /= self.unit.factor # Take integer part only res = math.modf(res) swap_value = SwapValue(res, length) # Register value in list format lstRegVal = [] lstRegVal[:] = self.register.value.toList() # Build register value indexReg = self.bytePos shiftReg = 7 - self.bitPos # Total bits to be copied from this parameter bitsToCopy = self.byteSize * 8 + self.bitSize # Parameter value in list format lstParamVal = swap_value.toList() indexParam = 0 shiftParam = self.bitSize - 1 if shiftParam < 0: shiftParam = 7 for i in range(bitsToCopy): if (lstParamVal[indexParam] >> shiftParam) & 0x01 == 0: mask = ~(1 << shiftReg) lstRegVal[indexReg] &= mask else: mask = 1 << shiftReg lstRegVal[indexReg] |= mask shiftReg -= 1 shiftParam -= 1 # Register byte over? if shiftReg < 0: indexReg += 1 shiftReg = 7 # Parameter byte over? if shiftParam < 0: indexParam += 1 shiftParam = 7 # Convert to SWapValue newRegVal = SwapValue(lstRegVal) # Send SWAP command return self.register.sendSwapCmd(newRegVal)
def read(self): """ Read configuration file """ # Parse XML file tree = xml.parse(self.fileName) if tree is None: return # Get the root node root = tree.getroot() # List of developers lstElemDevel = root.findall("developer") if lstElemDevel is not None: for devel in lstElemDevel: # Get developer id strDevelId = devel.get("id") if strDevelId is None: raise SwapException( "Developer section needs a valid ID in " + __xmldirfile__) return develId = int(strDevelId) # Get developer name strDevelName = devel.get("name") if strDevelName is None: raise SwapException("Developer section needs a name in " + __xmldirfile__) return # Create developer entry developer = DeveloperEntry(develId, strDevelName) # Parse devices belonging to this developer lstDevs = devel.findall("dev") if lstDevs is not None: for dev in lstDevs: # Get product id strProdId = dev.get("id") if strProdId is None: raise SwapException( "Device section needs a valid ID in " + __xmldirfile__) return prodId = int(strProdId) # Get folder name / command-line option strOption = dev.get("name") if strOption is None: raise SwapException( "Device section needs a comman-line option in " + __xmldirfile__) return # Get GUI label strLabel = dev.get("label") if strLabel is None: raise SwapException( "Device section needs a label in " + __xmldirfile__) return # Create device entry device = DeviceEntry(prodId, strOption, strLabel) # Add device to the developer entry developer.addDevice(device) # Append developer to the list self.developers.append(developer)
def getRegList(self, config=False): """ Return list of registers @param config: Set to True if Configuration register are required. False for regular ones @return List of registers """ if self.fileName is None: return None # List of config registers belonging to the current device lstRegs = [] # Parse XML file tree = xml.parse(self.fileName) if tree is None: return None # Get the root node root = tree.getroot() # Get manufacturer # List of register elements belonging to the device regtype = "regular" if config == True: regtype = "config" lstElemReg = root.findall(regtype + "/reg") if lstElemReg is not None: for reg in lstElemReg: # Get register id strRegId = reg.get("id") if strRegId is not None: regId = int(strRegId) # Get register name regName = reg.get("name", default="") # Create register from id and mote swRegister = SwapRegister(self.mote, regId, regName) # List of endpoints belonging to the register if config == True: elementName = "param" else: elementName = "endpoint" lstElemParam = reg.findall(elementName) for param in lstElemParam: # Read XML fields paramType = param.get("type", default="num") paramDir = param.get("dir", default="inp") paramName = param.get("name", default="") paramPos = "0" elem = param.find("position") if elem is not None: paramPos = elem.text paramSize = "1" elem = param.find("size") if elem is not None: paramSize = elem.text paramDef = "0" elem = param.find("default") if elem is not None: paramDef = elem.text if paramType in [SwapType.NUMBER, SwapType.BINARY]: try: defVal = int(paramDef) except ValueError: try: defVal = float(paramDef) except ValueError: raise SwapException("Default value " + str(paramDef) + " is not a number") return else: defVal = paramDef verif = None elem = param.find("verif") if elem is not None: verif = elem.text # Get list of units units = param.findall("units/unit") lstUnits = None if units is not None and len(units) > 0: lstUnits = [] for unit in units: name = unit.get("name", default=None) factor = unit.get("factor", default=1) offset = unit.get("offset", default=0) calc = unit.get("calc", default=None) xmlUnit = XmlUnit(name, factor, offset, calc) lstUnits.append(xmlUnit) if config == True: # Create SWAP config parameter swParam = SwapCfgParam(register=swRegister, pType=paramType, name=paramName, position=paramPos, size=paramSize, default=defVal, verif=verif) else: # Create SWAP endpoint swParam = SwapEndpoint(register=swRegister, pType=paramType, direction=paramDir, name=paramName, position=paramPos, size=paramSize, default=defVal, verif=verif, units=lstUnits) # Add current parameter to the register swRegister.add(swParam) # Create empty value for the register swRegister.value = SwapValue([0] * swRegister.getLength()) swRegister.update() # Add endpoint to the list lstRegs.append(swRegister) if len(lstRegs) == 0: return None else: return lstRegs
def __init__(self, ccPacket=None, destAddr=SwapAddress.BROADCAST_ADDR, hop=0, nonce=0, function=SwapFunction.STATUS, regAddr=0, regId=0, value=None, extended_addr=False): """ Class constructor @param ccPacket: Raw CcPacket where to take the information from @param destAddr: Destination address @param hop: Transmission hop count @param nonce: Security nonce @param function: SWAP function code (see SwapDefs.SwapFunction for more details) @param regAddr: Register address (address of the mote where the register really resides) @param regId: Register ID @param value: Register value """ CcPacket.__init__(self) ## Extended address disabled by default self.extended_address = extended_addr ## Destination address self.destAddress = destAddr ## Source address self.srcAddress = regAddr ## Hop count for repeating purposes self.hop = hop ## Security option self.security = 0 ## Security nonce self.nonce = nonce ## Function code self.function = function ## Register address self.regAddress = regAddr ## Register ID self.regId = regId ## SWAP value self.value = value if ccPacket is not None: if len(ccPacket.data) < 7: raise SwapException("Packet received is too short") # Hop count for repeating purposes self.hop = (ccPacket.data[2] >> 4) & 0x0F # Security option self.security = ccPacket.data[2] & 0x0F # Security nonce self.nonce = ccPacket.data[3] # Superclass attributes ## RSSI byte self.rssi = ccPacket.rssi ## LQI byte self.lqi = ccPacket.lqi ## CcPacket data field self.data = ccPacket.data # Smart Encryption enabled? if self.security & 0x02 and SwapPacket.smart_encrypt_pwd is not None: # Decrypt packet self.smart_encryption(SwapPacket.smart_encrypt_pwd, decrypt=True) # AES-128 Encryption enabled? elif self.security & 0x04 and SwapPacket.aes_encrypt_pwd is not None: # Decrypt packet self.aes_encryption(SwapPacket.aes_encrypt_pwd, decrypt=True) elif self.security & 0x06: return # Function code self.function = ccPacket.data[4] & 0x7F # Extended address indicator self.extended_address = (ccPacket.data[4] & 0x80) != 0 if self.extended_address: # Destination address self.destAddress = (ccPacket.data[0] << 8) | ccPacket.data[1] # Source address self.srcAddress = (ccPacket.data[5] << 8) | ccPacket.data[6] # Register address self.regAddress = (ccPacket.data[7] << 8) | ccPacket.data[8] # Register ID self.regId = ccPacket.data[9] # Register value if len(ccPacket.data) >= 11: self.value = SwapValue(ccPacket.data[10:]) else: # Destination address self.destAddress = ccPacket.data[0] # Source address self.srcAddress = ccPacket.data[1] # Register address self.regAddress = ccPacket.data[5] # Register ID self.regId = ccPacket.data[6] # Register value if len(ccPacket.data) >= 8: self.value = SwapValue(ccPacket.data[7:]) else: self._update_ccdata()
def __init__(self, server=None, product_code=None, address=0xFF, security=0, nonce=0): """ Class constructor @param server: SWAP server object @param product_code: Product Code @param address: Mote address """ if server is None: raise SwapException( "SwapMote constructor needs a valid SwapServer object") ## Swap server object self.server = server ## Product code self.product_code = product_code ## Product ID self.product_id = 0 ## Manufacturer ID self.manufacturer_id = 0 ## Definition settings self.config = None # Get manufacturer and product id from product code """ if product_code is not None: for i in range(4): self.manufacturer_id = self.manufacturer_id | (product_code[i] << 8 * (3-i)) self.product_id = self.product_id | (product_code[i + 4] << 8 * (3-i)) """ try: self.manufacturer_id = long(product_code[0:8], 16) self.product_id = long(product_code[8:], 16) except: raise SwapException("Incorrect product code received") # Definition file ## Definition settings try: self.definition = XmlDevice(self) except: raise ## Device address self.address = address ## Security option self.security = security ## Current mote's security nonce self.nonce = nonce ## State of the mote self.state = SwapState.RXOFF ## List of regular registers provided by this mote self.regular_registers = None ## List of config registers provided by this mote self.config_registers = None if self.definition is not None: # List of regular registers self.regular_registers = self.definition.getRegList() # List of config registers self.config_registers = self.definition.getRegList(config=True) ## Time stamp of the last update received from mote self.timestamp = time.time() ## Powerdown mode self.pwrdownmode = self.definition.pwrdownmode ## Interval between periodic transmissions self.txinterval = self.definition.txinterval
def run(self): """ Run serial port listener on its own thread """ self._go_on = True if self._serport is not None: if self._serport.isOpen(): # Flush buffers self._serport.flushInput() self._serport.flushOutput() serbuf = [] # Listen for incoming serial data while self._go_on: try: # Read single byte (non blocking function) ch = self._serport.read() if len(ch) > 0: # End of serial packet? if ch == '\r' or ((ch == '(') and (len(serbuf) > 0)): strBuf = "".join(serbuf) serbuf = [] # Enable for debug only if self._verbose == True: print "Rved: " + strBuf # Notify reception if self.serial_received is not None: try: self.serial_received(strBuf) except SwapException as ex: ex.display() elif ch != '\n': # Append char at the end of the buffer (list) serbuf.append(ch) else: time.sleep(0.01) except serial.SerialException: raise SwapException("Serial port " + self.portname + " not available") except OSError: raise SwapException( str(sys.exc_type) + ": " + str(sys.exc_info())) # Anything to be sent? #self._send_lock.acquire() if not self._strtosend.empty(): if time.time( ) - self.last_transmission_time > SerialPort.txdelay: strpacket = self._strtosend.get() # Send serial packet self._serport.write(strpacket) # Update time stamp self.last_transmission_time = time.time() # Enable for debug only if self._verbose == True: print "Sent: " + strpacket #self._send_lock.release() else: raise SwapException("Unable to read serial port " + self.portname + " since it is not open") else: raise SwapException("Unable to read serial port " + self.portname + " since it is not open") print "Closing serial port..."