#! /usr/bin/env python # This script reads packet data from the listen node through the serial port # and prints one data line for each tx, rx, ch measurement, and includes # the time the measurement was recorded, and the measured RSS. # # Version History: # # Version 1.0: Initial Release # # Version 1.1: 26 Sept 2012. # Fixes problems that occur when packets are dropped: # a) Changes the way the "ch", the channel the RSS was measured on, # is calculated. If rxId > txId, then "ch" is the same as the current # channel. Otherwise ch is the previous channel in channelList. # This is always correct. The old way could be in error if a packet # was dropped by the listen node. # b) Does not try to prevent output of a 127 "no measurement key". This # number is returned by the nodes themselves when the don't measure # the RSS on a link. Downstream algorithms can use that information # differently, depending on the application. Previous code copied the # most recently measured value for that link into the current line. # c) Changes when a line is output. Previous code output every cycle, that # is, at the lowest channel for the lowest node id. Now, we simply # keep track of which links have received a RSS measurement during this # line. The line is output whenever any link sees a 2nd measurement. # This ensures that no data is overwritten in the case that the listen # node hears few packets that arrive seemingly out of order. # import sys from serial import * from pylab import * def hex2signedint(he): #"""Convert from hexidecimal 2's complement to signed 8 bit integer.""" return (int(he,16) + 2**7) % 2**8 - 2**7 def prevChannel(channelList, ch_now): if (channelList.count(ch_now) > 0): i = channelList.index(ch_now) rval = channelList[(i-1) % len(channelList)] else: rval = -1 # Key for bad ch_now input return rval # What channels are measured by your nodes, in order of their measurement? # USER: SET THIS TO THE CHANNELS IN YOUR CHANNEL GROUP channelList = [14, 18, 22, 26] # What node numbers are yours, that you want to see output to the file. # USER: SET THIS TO THE NODE IDS ASSIGNED TO YOU. DO NOT INCLUDE THE LISTEN NODE NUMBER nodeList = [5,6] # A link is a (txId, rxId, chNum) combination. # 11 <= chNum <= 26, but is limited to those in "channelList" # txId and RxId are positive integers, again, depending on your nodes. # Examples: #linksToPlot = [ (5,6,14), (5,6,18), (5,6,22), (5,6,26)] linksToPlot = [ (6,5,14), (6,5,18), (6,5,22), (6,5,26)] #linksToPlot = [ (1,2,11), (1,2,15), (1,2,19), (1,2,23), (2,1,11), (2,1,15), (2,1,19), (2,1,23)] #linksToPlot = [ (5,6,14), (5,6,18), (5,6,22), (5,6,26)] #linksToPlot = [ (1,2,11), (2,1,11)] # USER: The following serial "file name" changes depending on your operating # system, and what name is assigned to the serial port when your listen # node is plugged in. serial_line = '/dev/ttyACM0' # How many nodes the sensors have as the max # nodes (what # they're programmed with) # USER: THIS SHOULD NOT BE CHANGED, IT IS 6 FOR ALL GROUPS IN OUR CLASS maxNodes = 6 # Parameters that are due to our implementation of the listen node. numNodes = len(nodeList) rssIndex = 3 string_length = maxNodes + 7 suffix = ['ef','be'] # "0xBEEF" ser = Serial(serial_line,38400) # Initialize data, output file nodeSet = set(nodeList) channelSet = set(channelList) currentLine = [] # Init serial data buffer "currentLine" as empty. currentLinkRSS = [127] * len(linksToPlot) currentLinkTime = [0] * len(linksToPlot) prevTimeForTxId = [0] * (maxNodes+1) # Run forever, adding one integer at a time from the serial port, # whenever an integer is available. while(1): tempInt = ser.read().encode('hex') currentLine.append(tempInt) # Whenever the end-of-line sequence is read, operate on the "packet" of data. if currentLine[-2:] == suffix: if len(currentLine) != string_length: sys.stderr.write('packet corrupted - wrong string length\n') del currentLine[:] continue currentLineInt = [int(x, 16) for x in currentLine] rxId = currentLineInt[2] currentCh = currentLineInt[-4] #print [currentLineInt[0:3], [hex2signedint(he) for he in currentLine[3:9]], currentLineInt[9:]] #print rxId if (rxId not in nodeSet) or (currentCh not in channelSet): del currentLine[:] continue timeStamp = 256*currentLineInt[1] + currentLineInt[0] # The most recent transmission of node rxId is the time stamp reported # on this line. prevTimeForTxId[rxId] = timeStamp # Each line in the serial data has RSS values for multiple txids. # Output one line per txid, rxid, ch combo. for txId in nodeList: # If the rxId is after the txId, then no problem -- currentCh # is also the channel that node txId was transmitting on when # node rxId made the measurement, because nodes transmit on a # channel in increasing order. if rxId > txId: ch = currentCh else: ch = prevChannel(channelList, currentCh) if (linksToPlot.count((txId, rxId, ch)) > 0): i = linksToPlot.index((txId, rxId, ch)) # If the RSS has already been recorded for this link on # this "line", then output the line first, and then restart # with a new line. if currentLinkRSS[i] < 127: # Output currentLinkRSS & currentLinkTime vectors s = str(currentLinkTime[0]) + ' ' + str(currentLinkRSS[0]) for n in range(1,len(linksToPlot)): s += ' ' + str(currentLinkTime[n]) + ' ' + str(currentLinkRSS[n]) sys.stdout.write(s + '\n') sys.stdout.flush() # Restart with a new line by resetting currentLinkRSS and # currentLinkTime currentLinkRSS = [127] * len(linksToPlot) currentLinkTime = [0] * len(linksToPlot) # Store the RSS & time it was recorded. currentLinkRSS[i] = hex2signedint(currentLine[rssIndex+txId-1]) currentLinkTime[i] = prevTimeForTxId[txId] # Remove serial data from the buffer. currentLine = []