4e09e9c7704183677fe227f0a86943886d5ae506
[goodfet] / client / GoodFETMCPCANCommunication.py
1 #!/usr/bin/env python
2 # GoodFET SPI Flash Client
3 #
4 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
5 #
6 #
7 # Ted's working copy
8 #   1) getting hot reads on frequency
9 #   2) allow sniffing in "normal" mode to get ack bits
10 #       --check if that's whats causing error flags in board-to-board transmission
11 #
12 #
13
14 import sys;
15 import binascii;
16 import array;
17 import csv, time, argparse;
18 import datetime
19 import os
20 from random import randrange
21 from GoodFETMCPCAN import GoodFETMCPCAN;
22 from intelhex import IntelHex;
23 import Queue
24
25 class GoodFETMCPCANCommunication:
26     
27     def __init__(self, dataLocation):
28        self.client=GoodFETMCPCAN(); """ Communication with the bus"""
29        self.client.serInit()
30        self.client.MCPsetup();
31        #self.DATA_LOCATION = "../../contrib/ThayerData/"
32        self.DATA_LOCATION = dataLocation; """ Stores file data location. This is the root folder where basic sniffs will be stored"""
33        self.INJECT_DATA_LOCATION  = self.DATA_LOCATION+"InjectedData/" """ stores the sub folder path where injected data will be stored"""
34        
35
36     
37     def printInfo(self):
38         """ This method will print information about the board to the termina. It is usefull for diagnostics"""
39         self.client.MCPreqstatConfiguration();
40         
41         print "MCP2515 Info:\n\n";
42         
43         print "Mode: %s" % self.client.MCPcanstatstr();
44         print "Read Status: %02x" % self.client.MCPreadstatus();
45         print "Rx Status:   %02x" % self.client.MCPrxstatus();
46         print "Error Flags:  %02x" % self.client.peek8(0x2D);
47         print "Tx Errors:  %3d" % self.client.peek8(0x1c);
48         print "Rx Errors:  %3d\n" % self.client.peek8(0x1d);
49         
50         print "Timing Info:";
51         print "CNF1: %02x" %self.client.peek8(0x2a);
52         print "CNF2: %02x" %self.client.peek8(0x29);
53         print "CNF3: %02x\n" %self.client.peek8(0x28);
54         print "RXB0 CTRL: %02x" %self.client.peek8(0x60);
55         print "RXB1 CTRL: %02x" %self.client.peek8(0x70);
56         
57         print "RX Info:";
58         print "RXB0: %02x" %self.client.peek8(0x60);
59         print "RXB1: %02x" %self.client.peek8(0x70);
60         print "RXB0 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x20), self.client.peek8(0x21), self.client.peek8(0x22), self.client.peek8(0x23));
61         print "RXB1 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x24), self.client.peek8(0x25), self.client.peek8(0x26), self.client.peek8(0x27));
62
63         
64         print "RX Buffers:"
65         packet0=self.client.readrxbuffer(0);
66         packet1=self.client.readrxbuffer(1);
67         for foo in [packet0, packet1]:
68            print self.client.packet2str(foo);
69            
70     def reset(self):
71         """ 
72         Reset the chip
73         """
74         self.client.MCPsetup();
75     
76     
77     ##########################
78     #   SNIFF
79     ##########################
80          
81     def sniff(self,freq,duration,description, verbose=True, comment=None, filename=None, standardid=None, debug=False, faster=False, parsed=True, data = None,writeToFile=True):
82         """
83         
84         """
85         #reset eveything on the chip
86         self.client.serInit() 
87         self.reset()
88           
89         #### ON-CHIP FILTERING
90         if(standardid != None):
91             if( comment == None):
92                 comment = ""
93             self.client.MCPreqstatConfiguration();  
94             self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
95             self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
96             self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
97             if(len(standardid)>2):
98                self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
99                self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
100                self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s 
101             
102             for filter,ID in enumerate(standardid):
103         
104                if (filter==0):
105                 RXFSIDH = 0x00;
106                 RXFSIDL = 0x01;
107                elif (filter==1):
108                 RXFSIDH = 0x04;
109                 RXFSIDL = 0x05;
110                elif (filter==2):
111                 RXFSIDH = 0x08;
112                 RXFSIDL = 0x09;
113                elif (filter==3):
114                 RXFSIDH = 0x10;
115                 RXFSIDL = 0x11;
116                elif (filter==4):
117                 RXFSIDH = 0x14;
118                 RXFSIDL = 0x15;
119                else:
120                 RXFSIDH = 0x18;
121                 RXFSIDL = 0x19;
122         
123                #### split SID into different regs
124                SIDlow = (ID & 0x07) << 5;  # get SID bits 2:0, rotate them to bits 7:5
125                SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
126                
127                #write SID to regs 
128                self.client.poke8(RXFSIDH,SIDhigh);
129                self.client.poke8(RXFSIDL, SIDlow);
130         
131                if (verbose == True):
132                    print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
133                comment += ("f%d" %(ID))
134         
135         
136         self.client.MCPsetrate(freq);
137         
138         # This will handle the files so that we do not loose them. each day we will create a new csv file
139         if( filename==None and writeToFile == True):
140             #get folder information (based on today's date)
141             now = datetime.datetime.now()
142             datestr = now.strftime("%Y%m%d")
143             path = self.DATA_LOCATION+datestr+".csv"
144             filename = path
145             
146         if( writeToFile == True):
147             outfile = open(filename,'a');
148             dataWriter = csv.writer(outfile,delimiter=',');
149             dataWriter.writerow(['# Time     Error        Bytes 1-13']);
150             dataWriter.writerow(['#' + description])
151             
152         self.client.MCPreqstatNormal();
153         print "Listening...";
154         packetcount = 0;
155         starttime = time.time();
156         
157         while((time.time()-starttime < duration)):
158             
159             if(faster):
160                 packet=self.client.fastrxpacket();
161             else:
162                 packet=self.client.rxpacket();
163                 
164             #add the data to list if the pointer was included
165             if(data != None and packet != None):
166                 #data.append(self.client.packet2parsedstr(packet))
167                 packetParsed = self.client.packet2parsed(packet)
168                 packetParsed["time"] =time.time()
169                 data.put(packetParsed)
170             if(debug == True):
171                 #check packet status
172                 MCPstatusReg = self.client.MCPrxstatus();
173                 messagestat=MCPstatusReg&0xC0;
174                 messagetype=MCPstatusReg&0x18;
175                 if(messagestat == 0xC0):
176                     print "Message in both buffers; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
177                 elif(messagestat == 0x80):
178                     print "Message in RXB1; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
179                 elif(messagestat == 0x40):
180                     print "Message in RXB0; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
181                 elif(messagestat == 0x00):
182                     print "No messages in buffers."
183             #check to see if there was a packet
184             if( packet != None):
185                 packetcount+=1;
186             if (packet!=None and writeToFile == True):
187                 
188                 row = [];
189                 row.append("%f"%time.time());
190                 
191                 if( verbose==True):
192                     #if we want to print a parsed message
193                     if( parsed == True):
194                         packetParsed = self.client.packet2parsed(packet)
195                         sId = packetParsed.get('sID')
196                         msg = "sID: %04d" %sId
197                         if( packetParsed.get('eID')):
198                             msg += " eID: %d" %packetParsed.get('eID')
199                         msg += " rtr: %d"%packetParsed['rtr']
200                         length = packetParsed['length']
201                         msg += " length: %d"%length
202                         msg += " data:"
203                         for i in range(0,length):
204                             dbidx = 'db%d'%i
205                             msg +=" %03d"% ord(packetParsed[dbidx])
206                         #msg = self.client.packet2parsedstr(packet)
207                         print msg
208                     # if we want to print just the message as it is read off the chip
209                     else:
210                         print self.client.packet2str(packet)
211                 
212                 if(debug == True):
213                     
214                     #check overflow
215                     MCPeflgReg=self.client.peek8(0x2D);
216                     print"EFLG register equals: %x" %MCPeflgReg;
217                     if((MCPeflgReg & 0xC0)==0xC0):
218                         print "WARNING: BOTH overflow flags set. Missed a packet. Clearing and proceeding."
219                     elif(MCPeflgReg & 0x80):
220                         print "WARNING: RXB1 overflow flag set. A packet has been missed. Clearing and proceeding."
221                     elif(MCPeflgReg & 0x40):
222                         print "WARNING: RXB0 overflow flag set. A packet has been missed. Clearing and proceeding."
223                     self.client.MCPbitmodify(0x2D,0xC0,0x00);
224                     print"EFLG register set to: %x" % self.client.peek(0x2D);
225                 
226                     #check for errors
227                     if (self.client.peek8(0x2C) & 0x80):
228                         self.client.MCPbitmodify(0x2C,0x80,0x00);
229                         print "ERROR: Malformed packet recieved: " + self.client.packet2str(packet);
230                         row.append(1);
231                     else:
232                         row.append(0);
233                 else:
234                     row.append(0);  #since we don't check for errors if we're not in debug mode...
235                             
236                 row.append(comment)
237                 #how long the sniff was for
238                 row.append(duration)
239                 #boolean that tells us if there was filtering. 0 == no filters, 1 == filters
240                 if(standardid != None):
241                     row.append(1)
242                 else:
243                     row.append(0)
244                 #write packet to file
245                 for byte in packet:
246                     row.append("%02x"%ord(byte));
247                 dataWriter.writerow(row);
248         if(writeToFile == True):
249             outfile.close()
250         print "Listened for %d seconds, captured %d packets." %(duration,packetcount);
251         return packetcount
252         
253         
254 #    def filterStdSweep(self, freq, low, high, time = 5):
255 #        msgIDs = []
256 #        self.client.serInit()
257 #        self.client.MCPsetup()
258 #        for i in range(low, high+1, 6):
259 #            print "sniffing id: %d, %d, %d, %d, %d, %d" % (i,i+1,i+2,i+3,i+4,i+5)
260 #            comment= "sweepFilter: "
261 #            #comment = "sweepFilter_%d_%d_%d_%d_%d_%d" % (i,i+1,i+2,i+3,i+4,i+5)
262 #            description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d, %d, %d, %d, %d, %d" % (i,i+1,i+2,i+3,i+4,i+5)
263 #            count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [i, i+1, i+2, i+3, i+4, i+5])
264 #            if( count != 0):
265 #                for j in range(i,i+5):
266 #                    comment = "sweepFilter: "
267 #                    #comment = "sweepFilter: %d" % (j)
268 #                    description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % j
269 #                    count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [j, j, j, j])
270 #                    if( count != 0):
271 #                        msgIDs.append(j)
272 #        return msgIDs
273     
274 #    def sweepRandom(self, freq, number = 5, time = 200):
275 #        msgIDs = []
276 #        ids = []
277 #        self.client.serInit()
278 #        self.client.MCPsetup()
279 #        for i in range(0,number+1,6):
280 #            idsTemp = []
281 #            comment = "sweepFilter: "
282 #            for j in range(0,6,1):
283 #                id = randrange(2047)
284 #                #comment += "_%d" % id
285 #                idsTemp.append(id)
286 #                ids.append(id)
287 #            print comment
288 #            description = "Running a sweep filer for all the possible standard IDs. This runs the following : " + comment
289 #            count = self.sniff(freq=freq, duration=time, description=description, comment = comment, standardid = idsTemp)
290 #            if( count != 0):
291 #                for element in idsTemp:
292 #                    #comment = "sweepFilter: %d" % (element)
293 #                    comment="sweepFilter: "
294 #                    description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % element
295 #                    count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [element, element, element])
296 #                    if( count != 0):
297 #                        msgIDs.append(j)
298 #        return msgIDs, ids
299     
300     def sniffTest(self, freq):
301         
302         rate = freq;
303         
304         print "Calling MCPsetrate for %i." %rate;
305         self.client.MCPsetrate(rate);
306         self.client.MCPreqstatNormal();
307         
308         print "Mode: %s" % self.client.MCPcanstatstr();
309         print "CNF1: %02x" %self.client.peek8(0x2a);
310         print "CNF2: %02x" %self.client.peek8(0x29);
311         print "CNF3: %02x\n" %self.client.peek8(0x28);
312         
313         while(1):
314             packet=self.client.rxpacket();
315             
316             if packet!=None:                
317                 if (self.client.peek8(0x2C) & 0x80):
318                     self.client.MCPbitmodify(0x2C,0x80,0x00);
319                     print "malformed packet recieved: "+ self.client.packet2str(packet);
320                 else:
321                     print "properly formatted packet recieved" + self.client.packet2str(packet);
322    
323     
324     def freqtest(self,freq):
325         
326         self.client.MCPsetup();
327
328         self.client.MCPsetrate(freq);
329         self.client.MCPreqstatListenOnly();
330     
331         print "CAN Freq Test: %3d kHz" %freq;
332     
333         x = 0;
334         errors = 0;
335     
336         starttime = time.time();
337         while((time.time()-starttime < args.time)):
338             packet=self.client.rxpacket();
339             if packet!=None:
340                 x+=1;
341                 
342                 if (self.client.peek8(0x2C) & 0x80):
343                     print "malformed packet recieved"
344                     errors+=1;
345                     self.client.MCPbitmodify(0x2C,0x80,0x00);
346                 else:         
347                     print self.client.packet2str(packet);
348     
349         print "Results for %3.1d kHz: recieved %3d packets, registered %3d RX errors." %(freq, x, errors);
350     
351
352     def isniff(self,freq):
353         """ An intelligent sniffer, decodes message format """
354         """ More features to be added soon """
355         
356         self.client.MCPsetrate(freq);
357         self.client.MCPreqstatListenOnly();
358         while 1:
359             packet=self.client.rxpacket();
360             if packet!=None:
361                 plist=[];
362                 for byte in packet:
363                     plist.append(byte);
364                 arbid=plist[0:2];
365                 eid=plist[2:4];
366                 dlc=plist[4:5];
367                 data=plist[5:13];         
368                 print "\nArbID: " + self.client.packet2str(arbid);
369                 print "EID: " + self.client.packet2str(eid);
370                 print "DLC: " + self.client.packet2str(dlc);
371                 print "Data: " + self.client.packet2str(data);
372
373     def test(self):
374         """ This will perform a test on the GOODTHOPTER10. Diagnostic messages will be printed
375         out to the terminal
376         """
377         comm.reset();
378         print "Just reset..."
379         print "EFLG register:  %02x" % self.client.peek8(0x2d);
380         print "Tx Errors:  %3d" % self.client.peek8(0x1c);
381         print "Rx Errors:  %3d" % self.client.peek8(0x1d);
382         print "CANINTF: %02x"  %self.client.peek8(0x2C);
383         self.client.MCPreqstatConfiguration();
384         self.client.poke8(0x60,0x66);
385         self.client.MCPsetrate(500);
386         self.client.MCPreqstatNormal();
387         print "In normal mode now"
388         print "EFLG register:  %02x" % self.client.peek8(0x2d);
389         print "Tx Errors:  %3d" % self.client.peek8(0x1c);
390         print "Rx Errors:  %3d" % self.client.peek8(0x1d);
391         print "CANINTF: %02x"  %self.client.peek8(0x2C);
392         print "Waiting on packets.";
393         checkcount = 0;
394         packet=None;
395         while(1):
396             packet=self.client.rxpacket();
397             if packet!=None:
398                 print "Message recieved: %s" % self.client.packet2str(packet);
399             else:
400                 checkcount=checkcount+1;
401                 if (checkcount%30==0):
402                     print "EFLG register:  %02x" % self.client.peek8(0x2d);
403                     print "Tx Errors:  %3d" % self.client.peek8(0x1c);
404                     print "Rx Errors:  %3d" % self.client.peek8(0x1d);
405                     print "CANINTF: %02x"  %self.client.peek8(0x2C);
406
407     
408     
409     
410     def addFilter(self,standardid, verbose= True):
411         """ This method will configure filters on the board. Filters are positive filters meaning that they will only 
412         store messages that match the ids provided in the list of standardid. Since there are 2 buffers and due to the configuration
413         of how the filtering works (see MCP2515 documentation), at least 3 filters must be set to guarentee you do not get any
414         unwanted messages. However even with only 1 filter set you should get all messages from that ID but the other buffer will store 
415         any additional messages.
416         @type standardid: list of integers
417         @param standardid: List of standard ids that need to be set. There can be at most 6 filters set.
418         @type verbose: Boolean
419         @param verbose: If true it will print out messages and diagnostics to terminal.
420         
421         @rtype: None
422         @return: This method does not return anything
423         """
424        
425         ### ON-CHIP FILTERING
426         if(standardid != None):
427             self.client.MCPreqstatConfiguration();  
428             self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
429             self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
430             self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
431             if(len(standardid)>2):
432                self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
433                self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
434                self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s 
435             
436             for filter,ID in enumerate(standardid):
437         
438                if (filter==0):
439                 RXFSIDH = 0x00;
440                 RXFSIDL = 0x01;
441                elif (filter==1):
442                 RXFSIDH = 0x04;
443                 RXFSIDL = 0x05;
444                elif (filter==2):
445                 RXFSIDH = 0x08;
446                 RXFSIDL = 0x09;
447                elif (filter==3):
448                 RXFSIDH = 0x10;
449                 RXFSIDL = 0x11;
450                elif (filter==4):
451                 RXFSIDH = 0x14;
452                 RXFSIDL = 0x15;
453                else:
454                 RXFSIDH = 0x18;
455                 RXFSIDL = 0x19;
456         
457                #### split SID into different regs
458                SIDlow = (ID & 0x07) << 5;  # get SID bits 2:0, rotate them to bits 7:5
459                SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
460                
461                #write SID to regs 
462                self.client.poke8(RXFSIDH,SIDhigh);
463                self.client.poke8(RXFSIDL, SIDlow);
464         
465                if (verbose == True):
466                    print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
467                
468         self.client.MCPreqstatNormal();
469     
470     
471    
472         
473     def spitSetup(self,freq):
474         """ 
475         This method sets up the chip for transmitting messages, but does not transmit anything itself.
476         """
477         self.reset();
478         self.client.MCPsetrate(freq);
479         self.client.MCPreqstatNormal();
480         
481     
482     def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
483         """ 
484         This method will spit a single message onto the bus. If there is no packet information provided then the 
485         message will be sent as a remote transmission request (RTR). The packet length is assumed to be 8 bytes The message can be repeated a given number of times with
486         a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
487         This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
488         
489         @type freq: number
490         @param freq: The frequency of the bus
491         
492         @type standardid: list of integer
493         @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
494         
495         @type repeat: Boolean
496         @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
497         
498         @type writes: Integer
499         @param writes: Number of writes of the packet
500         
501         @type period: Integer
502         @param period: Time delay between injections of the packet in Milliseconds
503         
504         @type debug: Boolean
505         @param debug: When true debug status messages will be printed to the terminal
506         
507         @type packet: List
508         @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
509                        an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
510                        standard id.
511         
512         """
513         self.spitSetup(freq);
514         spit(self,freq, standardid, repeat,writes,  period, debug , packet)
515
516     def spit(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
517         """ 
518         This method will spit a single message onto the bus. If there is no packet information provided then the 
519         message will be sent as a remote transmission request (RTR). The packet length is assumed to be 8 bytes The message can be repeated a given number of times with
520         a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
521         This method does not include bus setup, it must be done before the method call.
522         
523         
524         @type freq: number
525         @param freq: The frequency of the bus
526         
527         @type standardid: list of integer
528         @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
529         
530         @type repeat: Boolean
531         @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
532         
533         @type writes: Integer
534         @param writes: Number of writes of the packet
535         
536         @type period: Integer
537         @param period: Time delay between injections of the packet in Milliseconds
538         
539         @type debug: Boolean
540         @param debug: When true debug status messages will be printed to the terminal
541         
542         @type packet: List
543         @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
544                        an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
545                        standard id.
546         
547         """
548
549         #### split SID into different regs
550         SIDlow = (standardid[0] & 0x07) << 5;  # get SID bits 2:0, rotate them to bits 7:5
551         SIDhigh = (standardid[0] >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
552         
553         if(packet == None):
554             
555             # if no packet, RTR for inputted arbID
556             # so packet to transmit is SID + padding out EID registers + RTR request (set bit 6, clear lower nibble of DLC register)
557             packet = [SIDhigh, SIDlow, 0x00,0x00,0x40] 
558         
559         
560         else:
561
562             # if we do have a packet, packet is SID + padding out EID registers + DLC of 8 + packet
563             #
564             """@todo: allow for variable-length packets"""
565             #    TODO: allow for variable-length packets
566             #
567             packet = [SIDhigh, SIDlow, 0x00,0x00, # pad out EID regs
568                   0x08, # bit 6 must be set to 0 for data frame (1 for RTR) 
569                   # lower nibble is DLC                   
570                  packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]]
571             
572         
573         if(debug):
574             if self.client.MCPcanstat()>>5!=0:
575                 print "Warning: currently in %s mode. NOT in normal mode! May not transmit.\n" %self.client.MCPcanstatstr();
576             print "\nInitial state:"
577             print "Tx Errors:  %3d" % self.client.peek8(0x1c);
578             print "Rx Errors:  %3d" % self.client.peek8(0x1d);
579             print "Error Flags:  %02x\n" % self.client.peek8(0x2d);
580             print "TXB0CTRL: %02x" %self.client.peek8(0x30);
581             print "CANINTF: %02x\n"  %self.client.peek8(0x2C);
582             print "\n\nATTEMPTING TRANSMISSION!!!"
583         
584                 
585         print "Transmitting packet: "
586         #print self.client.packet2str(packet)
587                 
588         self.client.txpacket(packet);
589             
590         if repeat:
591             """@todo: the repeat variable is no longer needed and can be removed """
592             print "\nNow looping on transmit. "
593             if period != None:
594                 for i in range(0,writes):
595                     self.client.MCPrts(TXB0=True);
596                     #tic = time.time()
597                     time.sleep(period/1000) # pause for period ms before sending again
598                     #print time.time()-tic
599                 #starttime = time.time();
600                 #while((time.time()-starttime < duration)):
601                 #    self.client.MCPrts(TXB0=True);
602                 #    print "MSG printed"
603             else:
604                 for i in range(0,writes): 
605                     self.client.MCPrts(TXB0=True);
606         print "messages injected"
607         
608         # MORE DEBUGGING        
609         if(debug): 
610             checkcount = 0;
611             TXB0CTRL = self.client.peek8(0x30);
612         
613             print "Tx Errors:  %3d" % self.client.peek8(0x1c);
614             print "Rx Errors:  %3d" % self.client.peek8(0x1d);
615             print "EFLG register:  %02x" % self.client.peek8(0x2d);
616             print "TXB0CTRL: %02x" %TXB0CTRL;
617             print "CANINTF: %02x\n"  %self.client.peek8(0x2C);
618         
619             while(TXB0CTRL | 0x00 != 0x00):
620                 checkcount+=1;
621                 TXB0CTRL = self.client.peek8(0x30);
622                 if (checkcount %30 ==0):
623                     print "Tx Errors:  %3d" % self.client.peek8(0x1c);
624                     print "Rx Errors:  %3d" % self.client.peek8(0x1d);
625                     print "EFLG register:  %02x" % self.client.peek8(0x2d);
626                     print "TXB0CTRL: %02x" %TXB0CTRL;
627                     print "CANINTF: %02x\n"  %self.client.peek8(0x2C);
628
629
630     def setRate(self,freq):
631         """ 
632         This method will reset the frequency that the MCP2515 expects the CAN bus to be on.
633         
634         @type freq: Number
635         @param freq: Frequency of the CAN bus
636         """
637         self.client.MCPsetrate(freq);
638         
639
640     # This will write the data provided in the packets which is expected to be a list of lists
641     # of the following form:
642     # for a given row = packets[i]
643     # row[0] time delay relative to the last packet. if 0 or empty there will be no delay
644     # row[1] = Standard ID (integer)
645     # row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
646     # row[3] = Data Byte 0
647     # row[4] = Data Byte 1
648     #    .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
649     def writeData(self,packets,freq):
650         self.client.serInit()
651         self.spitSetup(freq)
652         for row in packets:
653             if( row[0] != 0 and row[0] != ""):
654                 time.sleep(row[0])
655             sID = row[1]
656             #### split SID into different regs
657             SIDlow = (sID & 0x07) << 5;  # get SID bits 2:0, rotate them to bits 7:5
658             SIDhigh = (sID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
659             packet = [SIDhigh,SIDlow,0x00,0x00,0x08]
660             #dlc = row[2]
661             dlc = 8
662             for i in range(3,dlc+3):
663                 packet.append(row[i])
664             print packet
665             self.client.txpacket(packet)
666                 
667         
668         
669         
670
671 if __name__ == "__main__":  
672
673     parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''\
674     
675         Run commands on the MCP2515. Valid commands are:
676         
677             info 
678             test
679             peek 0x(start) [0x(stop)]
680             reset
681             
682             sniff 
683             freqtest
684             snifftest
685             spit
686         ''')
687         
688     
689     parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit']);
690     parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
691     parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
692     parser.add_argument('-o', '--output', default=None,help='Output file');
693     parser.add_argument("-d", "--description", help='Description of experiment (included in the output file)', default="");
694     parser.add_argument('-v',"--verbose",action='store_false',help='-v will stop packet output to terminal', default=True);
695     parser.add_argument('-c','--comment', help='Comment attached to ech packet uploaded',default=None);
696     parser.add_argument('-b', '--debug', action='store_true', help='-b will turn on debug mode, printing packet status', default=False);
697     parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
698     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);
699     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);
700     
701     
702     args = parser.parse_args();
703     freq = args.freq
704     duration = args.time
705     filename = args.output
706     description = args.description
707     verbose = args.verbose
708     comments = args.comment
709     debug = args.debug
710     standardid = args.standardid
711     faster=args.faster
712     repeat = args.repeat
713
714     comm = GoodFETMCPCANCommunication();
715     
716     ##########################
717     #   INFO
718     ##########################
719     #
720     # Prints MCP state info
721     #
722     if(args.verb=="info"):
723         comm.printInfo()
724         
725            
726     ##########################
727     #   RESET
728     ##########################
729     #
730     #
731             
732     if(args.verb=="reset"):
733         comm.reset()
734         
735     ##########################
736     #   SNIFF
737     ##########################
738     #
739     #   runs in ListenOnly mode
740     #   utility function to pull info off the car's CAN bus
741     #
742     
743     if(args.verb=="sniff"):
744         comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster)    
745                     
746     ##########################
747     #   SNIFF TEST
748     ##########################
749     #
750     #   runs in NORMAL mode
751     #   intended for NETWORKED MCP chips to verify proper operation
752     #
753        
754     if(args.verb=="snifftest"):
755         comm.sniffTest(freq=freq)
756         
757         
758     ##########################
759     #   FREQ TEST
760     ##########################
761     #
762     #   runs in LISTEN ONLY mode
763     #   tests bus for desired frequency --> sniffs bus for specified length of time and reports
764     #   if packets were properly formatted
765     #
766     #
767     
768     if(args.verb=="freqtest"):
769         comm.freqtest(freq=freq)
770
771
772
773     ##########################
774     #   iSniff
775     ##########################
776     #
777     #    """ An intelligent sniffer, decodes message format """
778     #    """ More features to be added soon """
779     if(args.verb=="isniff"):
780         comm.isniff(freq=freq)
781                 
782                 
783     ##########################
784     #   MCP TEST
785     ##########################
786     #
787     #   Runs in LOOPBACK mode
788     #   self-check diagnostic
789     #   wasn't working before due to improperly formatted packet
790     #
791     #   ...add automatic packet check rather than making user verify successful packet
792     if(args.verb=="test"):
793         comm.test()
794         
795     if(args.verb=="peek"):
796         start=0x0000;
797         if(len(sys.argv)>2):
798             start=int(sys.argv[2],16);
799         stop=start;
800         if(len(sys.argv)>3):
801             stop=int(sys.argv[3],16);
802         print "Peeking from %04x to %04x." % (start,stop);
803         while start<=stop:
804             print "%04x: %02x" % (start,client.peek8(start));
805             start=start+1;
806             
807     ##########################
808     #   SPIT
809     ##########################
810     #
811     #   Basic packet transmission
812     #   runs in NORMAL MODE!
813     # 
814     #   checking TX error flags--> currently throwing error flags on every
815     #   transmission (travis thinks this is because we're sniffing in listen-only
816     #   and thus not generating an ack bit on the recieving board)
817     if(args.verb=="spit"):
818         comm.spitSingle(freq=freq, standardid=standardid,duration=duration, repeat=repeat, debug=debug)
819
820
821     
822     
823     
824     
825         
826         
827     
828     
829     
830