added comments
[goodfet] / client / GoodFETMCPCANCommunication.py
index f5fc9c9..f0e6eaf 100644 (file)
@@ -3,14 +3,12 @@
 #
 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
 #
-#
-# Ted's working copy
-#   1) getting hot reads on frequency
-#   2) allow sniffing in "normal" mode to get ack bits
-#       --check if that's whats causing error flags in board-to-board transmission
-#
+#  Edited By: Chris Hoder    2013
+#             Ted Summers    2013
+#             Grayson Zulauf 2013
 #
 
+
 import sys;
 import binascii;
 import array;
@@ -24,18 +22,25 @@ import Queue
 
 class GoodFETMCPCANCommunication:
     
-    def __init__(self, dataLocation):
-       self.client=GoodFETMCPCAN(); """ Communication with the bus"""
+    def __init__(self, dataLocation = "../../contrib/ThayerData/"):
+       self.client=GoodFETMCPCAN();
+       """ Communication with the bus"""
        self.client.serInit()
        self.client.MCPsetup();
        #self.DATA_LOCATION = "../../contrib/ThayerData/"
-       self.DATA_LOCATION = dataLocation; """ Stores file data location. This is the root folder where basic sniffs will be stored"""
-       self.INJECT_DATA_LOCATION  = self.DATA_LOCATION+"InjectedData/" """ stores the sub folder path where injected data will be stored"""
+       self.DATA_LOCATION = dataLocation; 
+       """ Stores file data location. This is the root folder where basic sniffs will be stored"""
+       self.INJECT_DATA_LOCATION  = self.DATA_LOCATION+"InjectedData/" 
+       """ stores the sub folder path where injected data will be stored"""
        
 
     
     def printInfo(self):
-        """ This method will print information about the board to the termina. It is usefull for diagnostics"""
+        """ 
+        This method will print information about the board to the terminal. 
+        It is good for diagnostics.
+        """
+        
         self.client.MCPreqstatConfiguration();
         
         print "MCP2515 Info:\n\n";
@@ -78,61 +83,29 @@ class GoodFETMCPCANCommunication:
     #   SNIFF
     ##########################
          
-    def sniff(self,freq,duration,description, verbose=True, comment=None, filename=None, standardid=None, debug=False, faster=False, parsed=True, data = None,writeToFile=True):
+    def sniff(self,freq,duration,description, verbose=True, comment=None, filename=None, standardid=None, debug=False, faster=False, parsed=True, data = None,writeToFile=True, db0 = None, db1 = None):
         """
         
         """
         #reset eveything on the chip
         self.client.serInit() 
         self.reset()
-          
-        #### ON-CHIP FILTERING
-        if(standardid != None):
-            if( comment == None):
-                comment = ""
-            self.client.MCPreqstatConfiguration();  
-            self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
-            self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
-            self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
-            if(len(standardid)>2):
-               self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
-               self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
-               self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s 
-            
-            for filter,ID in enumerate(standardid):
-        
-               if (filter==0):
-                RXFSIDH = 0x00;
-                RXFSIDL = 0x01;
-               elif (filter==1):
-                RXFSIDH = 0x04;
-                RXFSIDL = 0x05;
-               elif (filter==2):
-                RXFSIDH = 0x08;
-                RXFSIDL = 0x09;
-               elif (filter==3):
-                RXFSIDH = 0x10;
-                RXFSIDL = 0x11;
-               elif (filter==4):
-                RXFSIDH = 0x14;
-                RXFSIDL = 0x15;
-               else:
-                RXFSIDH = 0x18;
-                RXFSIDL = 0x19;
-        
-               #### split SID into different regs
-               SIDlow = (ID & 0x07) << 5;  # get SID bits 2:0, rotate them to bits 7:5
-               SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
-               
-               #write SID to regs 
-               self.client.poke8(RXFSIDH,SIDhigh);
-               self.client.poke8(RXFSIDL, SIDlow);
-        
-               if (verbose == True):
-                   print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
-               comment += ("f%d" %(ID))
-        
         
+        # filtering for specific packets
+        if(db0 != None and db1 != None and standardid != None):
+            self.filterForPacket(standardid[0], db0, db1, verbose)
+            if(comment == None):
+                comment = ""
+            comment += ("f%d[%d][%d]" %(standardid[0], db0, db1))
+        # filtering for standard ID
+        elif(standardid != None):
+            self.addFilter(standardid, verbose)
+            if(comment == None):
+                comment = ""
+                for ID in standardid:
+                    comment += ("f%d" %(ID))
+
+                
         self.client.MCPsetrate(freq);
         
         # This will handle the files so that we do not loose them. each day we will create a new csv file
@@ -202,7 +175,7 @@ class GoodFETMCPCANCommunication:
                         msg += " data:"
                         for i in range(0,length):
                             dbidx = 'db%d'%i
-                            msg +=" %03d"% ord(packetParsed[dbidx])
+                            msg +=" %03d"% packetParsed[dbidx]
                         #msg = self.client.packet2parsedstr(packet)
                         print msg
                     # if we want to print just the message as it is read off the chip
@@ -298,7 +271,12 @@ class GoodFETMCPCANCommunication:
 #        return msgIDs, ids
     
     def sniffTest(self, freq):
+        """
+        This method will preform a test to see if we can sniff corretly formed packets from the CAN bus.
         
+        @type freq: number
+        @param freq: frequency of the CAN bus
+        """
         rate = freq;
         
         print "Calling MCPsetrate for %i." %rate;
@@ -322,7 +300,13 @@ class GoodFETMCPCANCommunication:
    
     
     def freqtest(self,freq):
+        """
+        This method will test the frequency provided to see if it is the correct frequency for this CAN bus.
         
+        @type freq: Number
+        @param freq: The frequency to listen to the CAN bus.
+        
+        """
         self.client.MCPsetup();
 
         self.client.MCPsetrate(freq);
@@ -420,6 +404,7 @@ class GoodFETMCPCANCommunication:
         
         @rtype: None
         @return: This method does not return anything
+        @todo: rename setFilters
         """
        
         ### ON-CHIP FILTERING
@@ -461,34 +446,37 @@ class GoodFETMCPCANCommunication:
                #write SID to regs 
                self.client.poke8(RXFSIDH,SIDhigh);
                self.client.poke8(RXFSIDL, SIDlow);
-        
+                       
                if (verbose == True):
                    print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
                
         self.client.MCPreqstatNormal();
     
     def filterForPacket(self, standardid, DB0, DB1, verbose= True):
-        """ This method will configure filters on the board to listen for a specific packet originating from standardid with data bytes 0 and 1. It will configure all six filters, so you will not recieve any other packets.
-            @type standardid: integer
-            @param standardid: standardID to listen for
-            @type DB0: integer
-            @param standardid: DB0 contents to filter for
-            @type DB1: integer
-            @param standardid: DB1 contents to filter for
-            @type verbose: Boolean
-            @param verbose: If true it will print out messages and diagnostics to terminal.
-            
-            @rtype: None
-            @return: This method does not return anything
-            """
+        """ 
+        This method will configure filters on the board to listen for a specific packet originating 
+        from standardid with data bytes 0 and 1. It will configure all six filters, so you will not receive any other packets.
+        
+        @type standardid: integer
+        @param standardid: standardID to listen for
+        @type DB0: integer
+        @param standardid: DB0 contents to filter for
+        @type DB1: integer
+        @param standardid: DB1 contents to filter for
+        @type verbose: Boolean
+        @param verbose: If true it will print out messages and diagnostics to terminal.
+        
+        @rtype: None
+        @return: This method does not return anything
+        """
         
         ### ON-CHIP FILTERING
        
         self.client.MCPreqstatConfiguration();  
         
         # SID filtering: set CTRL registers to only accept standard messages
-        self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
-        self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
+        self.client.poke8(0x60,0x06); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
+        self.client.poke8(0x70,0x00); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
 
         # Mask buffer 0 to match SID, DB0, DB1
         self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
@@ -538,7 +526,6 @@ class GoodFETMCPCANCommunication:
                 RXFSIDL = 0x19;
                 RXFDB0 = 0x1A;
                 RXFDB1 = 0x1B;
-            
 
             self.client.poke8(RXFSIDH, SIDhigh);
             self.client.poke8(RXFSIDL, SIDlow);
@@ -546,12 +533,88 @@ class GoodFETMCPCANCommunication:
             self.client.poke8(RXFDB1, DB1);
                 
             if (verbose == True):
-                print "Filtering for SID %d DB0 0x%02xh DB1 0x%02xh with filter #%d"%(ID, DB0, DB1, filter);
+                print "Filtering for SID %d DB0 %d DB1 %d with filter #%d"%(standardid, DB0, DB1, filter);
         
-        self.client.MCPreqstatNormal();
-    
+        self.client.MCPreqstatNormal();   
     
-   
+    def multiPacketTest(self):
+        
+        self.reset();
+        self.client.MCPsetrate(500);
+        self.client.MCPreqstatNormal();
+        
+        packet0 = [0x00, 0x00, 0x00,0x00, # pad out EID regs
+                   0x08, # bit 6 must be set to 0 for data frame (1 for RTR) 
+                   # lower nibble is DLC                   
+                   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+        
+        packet1 = [0x00, 0x20, 0x00,0x00, # pad out EID regs
+                   0x08, # bit 6 must be set to 0 for data frame (1 for RTR) 
+                   # lower nibble is DLC                   
+                   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+        packet2 = [0x00, 0x40, 0x00,0x00, # pad out EID regs
+                   0x08, # bit 6 must be set to 0 for data frame (1 for RTR) 
+                   # lower nibble is DLC                   
+                   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
+            
+        comm.multiPacketSpit(packet0=packet0, packet1=packet1, packet2=packet2)
+        
+        comm.multiPacketSpit(packet0rts=True, packet1rts=True, packet2rts=True)
+        comm.multiPacketSpit(packet2rts=True)
+        comm.multiPacketSpit(packet1rts=True)
+        comm.multiPacketSpit(packet0rts=True)
+        
+
+
+    def multiPacketSpit(self, packet0 = None, packet1 = None, packet2 = None, packet0rts = False, packet1rts = False, packet2rts = False):
+        """ 
+            This method writes packets to the chip's TX buffers and/or sends the contents of the buffers onto the bus.
+            
+            @type packet0: list of integer
+            @param packet0: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF0
+            
+            @type packet1: list of integer
+            @param packet1: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF1
+            
+            @type packet2: list of integer
+            @param packet2: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF2
+            
+            @type packet0rts: Boolean
+            @param packet0rts: If true the message in TX buffer 0 will be sent
+            
+            @type packet2rts: Boolean
+            @param packet0rts: If true the message in TX buffer 1 will be sent
+            
+            @type packet2rts: Boolean
+            @param packet0rts: If true the message in TX buffer 2 will be sent
+            
+        """
+        
+        if(packet0 != None):
+            self.client.writetxbuffer(packet0,0)
+        #   print("trying to write TX buffer 0");
+        #  for db in packet0:
+        #      print" %d" %db
+        if (packet1 != None):
+            self.client.writetxbuffer(packet1,1)
+            # print("trying to write TX buffer 1");
+                # for db in packet0:
+                    #     print" %d" %db
+        if (packet2 != None):
+            self.client.writetxbuffer(packet2,2)
+            # print("trying to write TX buffer 2");
+                #  for db in packet0:
+                    #   print" %d" %db
+            
+        #  if(packet0rts):
+            #    print("trying to send TX buffer 0")
+        #if(packet1rts):
+            #    print("trying to send TX buffer 1")
+        #if(packet2rts):
+            #    print("trying to send TX buffer 2")
+
+        self.client.MCPrts(TXB0=packet0rts, TXB1=packet1rts, TXB2=packet2rts)
         
     def spitSetup(self,freq):
         """ 
@@ -565,7 +628,7 @@ class GoodFETMCPCANCommunication:
     def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
         """ 
         This method will spit a single message onto the bus. If there is no packet information provided then the 
-        message will be sent as a remote transmission request (RTR). The packet length is assumed to be 8 bytes The message can be repeated given number of times with
+        message will be sent as a remote transmission request (RTR). The packet length is assumed to be 8 bytes The message can be repeated given number of times with
         a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
         This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
         
@@ -663,7 +726,6 @@ class GoodFETMCPCANCommunication:
             print "TXB0CTRL: %02x" %self.client.peek8(0x30);
             print "CANINTF: %02x\n"  %self.client.peek8(0x2C);
             print "\n\nATTEMPTING TRANSMISSION!!!"
-        
                 
         print "Transmitting packet: "
         #print self.client.packet2str(packet)
@@ -718,6 +780,7 @@ class GoodFETMCPCANCommunication:
         @param freq: Frequency of the CAN bus
         """
         self.client.MCPsetrate(freq);
+
         
 
     # This will write the data provided in the packets which is expected to be a list of lists
@@ -730,6 +793,25 @@ class GoodFETMCPCANCommunication:
     # row[4] = Data Byte 1
     #    .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
     def writeData(self,packets,freq):
+        """
+        This method will write a list of packets to the bus at the given frequency. This method assumes a packet 
+        length of 8 for all packets as well as a standard id.
+        
+        @type packets: List of Lists
+        @param packets: The list of packets to be injected into the bus. Each element of packets is a list that is 
+        a packet to be injected onto the bus. These packets are assumed to be in the following format::
+                 row[0] time delay relative to the last packet. if 0 or empty there will be no delay
+                 row[1] = Standard ID (integer)
+                 row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
+                 row[3] = Data Byte 0
+                 row[4] = Data Byte 1
+                 ...
+                 row[10] = Data Byte 7
+        
+        @type freq: number
+        @param freq: Frequency of the CAN bus
+        
+        """
         self.client.serInit()
         self.spitSetup(freq)
         for row in packets:
@@ -746,6 +828,8 @@ class GoodFETMCPCANCommunication:
                 packet.append(row[i])
             print packet
             self.client.txpacket(packet)
+
+
                 
         
         
@@ -769,7 +853,7 @@ if __name__ == "__main__":
         ''')
         
     
-    parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit']);
+    parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit', 'packet', 'multipacket']);
     parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
     parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
     parser.add_argument('-o', '--output', default=None,help='Output file');
@@ -780,6 +864,9 @@ if __name__ == "__main__":
     parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
     parser.add_argument('-x', '--faster', action='store_true', help='-x will use "fast packet recieve," which may duplicate packets and/or cause other weird behavior.', default=False);
     parser.add_argument('-r', '--repeat', action='store_true', help='-r with "spit" will continuously send the inputted packet. This will put the GoodTHOPTHER into an infinite loop.', default=False);
+    parser.add_argument('-db0', '--databyte0', type=int, default = None, help='-db0 to filter for a specfic data byte');
+    parser.add_argument('-db1', '--databyte1', type=int, default = None, help='-db0 to filter for a specfic data byte');
+
     
     
     args = parser.parse_args();
@@ -793,8 +880,15 @@ if __name__ == "__main__":
     standardid = args.standardid
     faster=args.faster
     repeat = args.repeat
+    db0 = args.databyte0
+    db1 = args.databyte1
 
-    comm = GoodFETMCPCANCommunication();
+    comm = GoodFETMCPCANCommunication("./");
+    
+    if(args.verb=="packet"):
+        comm.filterForPacket(standardid=standardid[0], DB0=db0, DB1=db1, verbose= True)
+    if(args.verb=="multipacket"):
+        comm.multiPacketTest();
     
     ##########################
     #   INFO
@@ -824,7 +918,7 @@ if __name__ == "__main__":
     #
     
     if(args.verb=="sniff"):
-        comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster)    
+        comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster, db0=db0, db1=db1)    
                     
     ##########################
     #   SNIFF TEST