Exemple #1
0
	def __init__(self):
		super(PacketsModel, self).__init__()
		self.packets = []
		self.nodes = NodesModel()
		self.changed_ = False
Exemple #2
0
class PacketsModel(QAbstractTableModel):
	"""
	This class represents and manages current processed data.
	The data is held in memory as a list.
	"""
	def __init__(self):
		super(PacketsModel, self).__init__()
		self.packets = []
		self.nodes = NodesModel()
		self.changed_ = False
		#self.connect(self.nodes, SIGNAL("changed"), self.changed)
		
	def data(self, index, role=Qt.DisplayRole):
		"""
		This function is used by Qt to obtain data needed by the view.
		It is mandatory for the model to work.
		"""
		if not index.isValid() or not (0 <= index.row() < len(self.packets)):
			return QVariant()
			
		packet = self.packets[index.row()]
		column = index.column()
			
		if role == Qt.DisplayRole:
			if packet.isInvalid:
				if column == ACTIVITY:
					return QVariant('Invalid')
				return QVariant()
			
			if column == ACTIVITY:
				if packet.frameType == TYPE_CMD:
					return QVariant(packet.commandType)
				return QVariant(packet.frameType)
				
			elif column == SEQ:
				return QVariant(packet.seqNumber)
				
			elif column == PAYLOAD:
				if packet.frameType == TYPE_DATA:
					if hasattr(packet, 'payload'):
						return QVariant(packet.payload)
					return QVariant()
					
				elif packet.frameType == TYPE_CMD:
					if hasattr(packet, 'commandPayload'):
						#return QVariant('%s\n(%s)' % (packet.commandType, packet.commandPayload))
						return QVariant(packet.commandPayload)	
					#return QVariant(packet.commandType)
					
				elif packet.frameType == TYPE_BCN:
					return QVariant(packet.bcnPayload)
				return QVariant()
				
			elif column == SRC_ADDR:
				if packet.srcAddrMode in (MODE_16, MODE_64):
					addr = packet.srcAddr if hasattr(packet, 'srcAddr') else '<none>'
					pan = packet.dstPANID if packet.intraPAN == 'Yes' else packet.srcPANID
					# TODO:  internalization will brake this^^^^^^^^^^!!! fix this!
					return QVariant('%s <span style="color:#777;font-size:8pt;">(PAN: %s)</span>' 
								% (self.nodes.getName(addr, pan), pan))
				return QVariant()
			
			elif column == DST_ADDR:
				if packet.dstAddrMode in (MODE_16, MODE_64):
					addr = packet.dstAddr if hasattr(packet, 'dstAddr') else '<none>'
					pan =  packet.dstPANID
					return QVariant('%s <span style="color:#777;font-size:8pt;">(PAN: %s)</span>' 
								% (self.nodes.getName(addr, pan), pan))
				return QVariant()
			
		elif role == Qt.ToolTipRole:
			if packet.isInvalid:
				return QVariant('Recieved packet was invalid, or CRC failded')
			
			if column == ACTIVITY:
				if packet.frameType == TYPE_CMD:
					return QVariant('%s command' % packet.commandType)
				return QVariant('%s frame' % packet.frameType)
				
			elif column == SEQ:
				return QVariant('Sequence number: %s' % packet.seqNumber)
				
			elif column == SRC_ADDR:
				if packet.srcAddrMode in (MODE_16, MODE_64):
					addr = packet.srcAddr if hasattr(packet, 'srcAddr') else '<none>'
					pan = packet.dstPANID if packet.intraPAN == 'Yes' else packet.srcPANID
					# TODO:  internalization will brake this^^^^^^^^^^!!! fix this!
					name = self.nodes.getName(addr, pan)
					if name == addr:
						return QVariant('Node %s in PAN: %s)' % (addr, pan))
					else:
						return QVariant('Node <b>%s</b>, address %s in PAN %s' % (name, addr, pan))
				return QVariant('Address is not available')
			
			elif column == DST_ADDR:
				if packet.dstAddrMode in (MODE_16, MODE_64):
					addr = packet.dstAddr if hasattr(packet, 'dstAddr') else '<none>'
					pan =  packet.dstPANID
					name = self.nodes.getName(addr, pan)
					if name == addr:
						return QVariant('Node %s in PAN: %s)' % (addr, pan))
					else:
						return QVariant('Node <b>%s</b>, address %s in PAN %s' % (name, addr, pan))
				return QVariant('Address is not available')
			
		elif role == Qt.BackgroundColorRole:
			if packet.isInvalid:
				return QVariant(QColor(230, 180, 180))
			if packet.frameType == TYPE_BCN:
				return QVariant(QColor(220, 170, 220))
			elif packet.frameType == TYPE_ACK:
				return QVariant(QColor(215, 235, 195))
			elif packet.frameType == TYPE_DATA:
				return QVariant(QColor(255, 255, 255))
			elif packet.frameType == TYPE_CMD:
				return QVariant(QColor(200, 205, 235))
			
		elif role == Qt.TextAlignmentRole:
			return QVariant(int(Qt.AlignCenter|Qt.AlignVCenter))
		
		return QVariant()
	
	def headerData(self, section, orientation, role=Qt.DisplayRole):
		"""
		This function is used by Qt to obtain columns' headers.
		"""
		if role == Qt.TextAlignmentRole:
			if orientation == Qt.Horizontal:
				return QVariant(int(Qt.AlignCenter|Qt.AlignVCenter))
			return QVariant(int(Qt.AlignCenter|Qt.AlignVCenter))
		if role == Qt.ToolTipRole:
			if section == ACTIVITY:
				return QVariant('Type of frame or command')
			elif section == SEQ:
				return QVariant('Sequence number')
			elif section == PAYLOAD:
				return QVariant('Payload')
			elif section == SRC_ADDR:
				return QVariant("Source address (and source PAN-ID)")
			elif section == DST_ADDR:
				return QVariant("Destination address (and destination PAN-ID)")
		elif role == Qt.DisplayRole:
			if orientation == Qt.Horizontal:
				if section == ACTIVITY:
					return QVariant('Activity')
				elif section == SEQ:
					return QVariant('Seq.')
				elif section == PAYLOAD:
					return QVariant('Payload')
				elif section == SRC_ADDR:
					return QVariant("Source")
				elif section == DST_ADDR:
					return QVariant("Destination")
				return QVariant(int(section + 1)) # if column name unknown, return number
		else:
			return QVariant()
	
	def rowCount(self, index=QModelIndex()):
		"""
		This function is mandatory for the model to work.
		"""
		if not index.isValid():
			return len(self.packets)
		return 0 # <---packets have no children
	
	def columnCount(self, index=QModelIndex()):
		"""
		This function is mandatory for the model to work.
		"""
		return 5
	
	def getPacket(self, index):
		"""
		This function returns packet (Packet) from given index (QModelIndex)
		"""
		return self.packets[index.row()]
	
	def append(self, packet):
		"""
		Adds one packet at end of the packets list
		"""
		self.beginInsertRows(QModelIndex(), len(self.packets), len(self.packets) + 1)
		self.packets.append(packet)
		self.endInsertRows()
		self.changed(True)
		self.nodes.append_from_packet(packet)
	
	def clear(self):
		"""
		Clears the packets list (doesn't clear nodes list)
		"""
		self.beginRemoveRows(QModelIndex(), 0, len(self.packets))
		self.packets = []
		self.endRemoveRows()
	
	def load(self, fh):
		"""
		Load packets from given file handler
		"""
		# first we read all nodes
		for line in filter(lambda l: l.startswith('+NODE:'), fh):
			name = line.rstrip()[line.find('"') + 1:line.rfind('"')]
			line = line.rstrip()[line.rfind('"') + 2:].split(',')
			pan = ''.join(reversed(line[:2])).replace('?', '')
			pan = '0x' + pan.lower() if pan else ''
			address = ''.join(reversed(line[2:4])).replace('?', '')
			address = '0x' + address.lower() if address else ''
			self.nodes.append_unique(Node(pan, address, name))

		# but they are at the end of file so we return to begining now:
		fh.seek(0)
		for line in filter(lambda l: l.startswith('+FRAM:'), fh):
			load, time = (line[19:].split(',')[1:], #load
							line[6:18].split(',')) #time
			load = [int(x, 16) for x in load] #hex->int
			self.append(Packet(load, time))
			
		self.changed(False)
		self.nodes.changed(False)
	
	def save(self, fh):
		"""
		This function writes collected data into a fh file in .154 format
		"""
		#first write head of file
		fh.write('+INFO:IEEE 802.15.4 ZigBeeSniffer Log.\r\n')
		fh.write('+DATE:' + time.ctime() + '\r\n')
		for packet in self.packets:
			load = [len(packet.load)] + packet.load
			load = map(str, map(hex, load))	# int->hex->str
			load = map(lambda x: ('0'+x[2:])[-2:].upper(), load)	# 0xa -> 0A
			load = ','.join(load)						# glue it back
			timee = ','.join(packet.time)
			fh.write('+FRAM:' + timee + ',' + load + '\r\n')
			
		for node in self.nodes.nodes:
			pan = node.panId[2:]     # cut '0x' from begining
			addr = node.address[2:]  # cut '0x' from begining
			line = '+NODE:"%s"' % node.name
			line += ',%s,%s' % (pan[2:], pan[:2]) if pan else ',??,??'  # PAN-ID
			#now split address into pairs (bytes):
			pairs = map(''.join, zip(iter(addr), iter(addr)))
			for pair in reversed(pairs): 
				line += ',%s' % pair
			for i in range(8 - len(pairs)):
				line += ',??'
			line += '\r\n'
			fh.write(line)
		
		self.changed(False)
		
	def changed(self, arg=None):
		if arg is None:
			return self.changed_
		else:
			self.changed_ = arg
			self.emit(SIGNAL("changed"))
			
	
	# ============== methods needed by statistics window ================== 
	def invlaid_count(self):
		return len(filter(lambda packet: packet.isInvalid, self.packets))
		
	def error_rate(self):
		return 100.0 * self.invlaid_count() / self.rowCount()
	
	def coord_count(self):
		coords = filter(lambda packet: hasattr(packet, 'PANCoord'), self.packets)
		return len(filter(lambda packet: packet.PANCoord, coords))
	
	def type_count(self, type, cmd=None):
		if not cmd:
			packets = filter(lambda packet: hasattr(packet, 'frameType'), self.packets)
			return len(filter(lambda packet: packet.frameType == type, packets))
		else:
			commands = filter(lambda packet: hasattr(packet, 'frameType'), self.packets)
			commands = filter(lambda packet: packet.frameType == type, commands)
			return len(filter(lambda packet: packet.commandType == cmd, commands))