2 # GoodFET SPI Flash Client
4 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
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
17 import csv, time, argparse;
20 from random import randrange
21 from GoodFETMCPCAN import GoodFETMCPCAN;
22 from intelhex import IntelHex;
25 class GoodFETMCPCANCommunication:
27 def __init__(self, dataLocation):
28 self.client=GoodFETMCPCAN();
29 """ Communication with the bus"""
31 self.client.MCPsetup();
32 #self.DATA_LOCATION = "../../contrib/ThayerData/"
33 self.DATA_LOCATION = dataLocation;
34 """ Stores file data location. This is the root folder where basic sniffs will be stored"""
35 self.INJECT_DATA_LOCATION = self.DATA_LOCATION+"InjectedData/"
36 """ stores the sub folder path where injected data will be stored"""
42 This method will print information about the board to the terminal.
43 It is good for diagnostics
46 self.client.MCPreqstatConfiguration();
48 print "MCP2515 Info:\n\n";
50 print "Mode: %s" % self.client.MCPcanstatstr();
51 print "Read Status: %02x" % self.client.MCPreadstatus();
52 print "Rx Status: %02x" % self.client.MCPrxstatus();
53 print "Error Flags: %02x" % self.client.peek8(0x2D);
54 print "Tx Errors: %3d" % self.client.peek8(0x1c);
55 print "Rx Errors: %3d\n" % self.client.peek8(0x1d);
58 print "CNF1: %02x" %self.client.peek8(0x2a);
59 print "CNF2: %02x" %self.client.peek8(0x29);
60 print "CNF3: %02x\n" %self.client.peek8(0x28);
61 print "RXB0 CTRL: %02x" %self.client.peek8(0x60);
62 print "RXB1 CTRL: %02x" %self.client.peek8(0x70);
65 print "RXB0: %02x" %self.client.peek8(0x60);
66 print "RXB1: %02x" %self.client.peek8(0x70);
67 print "RXB0 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x20), self.client.peek8(0x21), self.client.peek8(0x22), self.client.peek8(0x23));
68 print "RXB1 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x24), self.client.peek8(0x25), self.client.peek8(0x26), self.client.peek8(0x27));
72 packet0=self.client.readrxbuffer(0);
73 packet1=self.client.readrxbuffer(1);
74 for foo in [packet0, packet1]:
75 print self.client.packet2str(foo);
81 self.client.MCPsetup();
84 ##########################
86 ##########################
88 def sniff(self,freq,duration,description, verbose=True, comment=None, filename=None, standardid=None, debug=False, faster=False, parsed=True, data = None,writeToFile=True):
92 #reset eveything on the chip
96 #### ON-CHIP FILTERING
97 if(standardid != None):
100 self.client.MCPreqstatConfiguration();
101 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
102 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
103 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
104 if(len(standardid)>2):
105 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
106 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
107 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
109 for filter,ID in enumerate(standardid):
130 #### split SID into different regs
131 SIDlow = (ID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
132 SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
135 self.client.poke8(RXFSIDH,SIDhigh);
136 self.client.poke8(RXFSIDL, SIDlow);
138 if (verbose == True):
139 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
140 comment += ("f%d" %(ID))
143 self.client.MCPsetrate(freq);
145 # This will handle the files so that we do not loose them. each day we will create a new csv file
146 if( filename==None and writeToFile == True):
147 #get folder information (based on today's date)
148 now = datetime.datetime.now()
149 datestr = now.strftime("%Y%m%d")
150 path = self.DATA_LOCATION+datestr+".csv"
153 if( writeToFile == True):
154 outfile = open(filename,'a');
155 dataWriter = csv.writer(outfile,delimiter=',');
156 dataWriter.writerow(['# Time Error Bytes 1-13']);
157 dataWriter.writerow(['#' + description])
159 self.client.MCPreqstatNormal();
160 print "Listening...";
162 starttime = time.time();
164 while((time.time()-starttime < duration)):
167 packet=self.client.fastrxpacket();
169 packet=self.client.rxpacket();
171 #add the data to list if the pointer was included
172 if(data != None and packet != None):
173 #data.append(self.client.packet2parsedstr(packet))
174 packetParsed = self.client.packet2parsed(packet)
175 packetParsed["time"] =time.time()
176 data.put(packetParsed)
179 MCPstatusReg = self.client.MCPrxstatus();
180 messagestat=MCPstatusReg&0xC0;
181 messagetype=MCPstatusReg&0x18;
182 if(messagestat == 0xC0):
183 print "Message in both buffers; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
184 elif(messagestat == 0x80):
185 print "Message in RXB1; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
186 elif(messagestat == 0x40):
187 print "Message in RXB0; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
188 elif(messagestat == 0x00):
189 print "No messages in buffers."
190 #check to see if there was a packet
193 if (packet!=None and writeToFile == True):
196 row.append("%f"%time.time());
199 #if we want to print a parsed message
201 packetParsed = self.client.packet2parsed(packet)
202 sId = packetParsed.get('sID')
203 msg = "sID: %04d" %sId
204 if( packetParsed.get('eID')):
205 msg += " eID: %d" %packetParsed.get('eID')
206 msg += " rtr: %d"%packetParsed['rtr']
207 length = packetParsed['length']
208 msg += " length: %d"%length
210 for i in range(0,length):
212 msg +=" %03d"% ord(packetParsed[dbidx])
213 #msg = self.client.packet2parsedstr(packet)
215 # if we want to print just the message as it is read off the chip
217 print self.client.packet2str(packet)
222 MCPeflgReg=self.client.peek8(0x2D);
223 print"EFLG register equals: %x" %MCPeflgReg;
224 if((MCPeflgReg & 0xC0)==0xC0):
225 print "WARNING: BOTH overflow flags set. Missed a packet. Clearing and proceeding."
226 elif(MCPeflgReg & 0x80):
227 print "WARNING: RXB1 overflow flag set. A packet has been missed. Clearing and proceeding."
228 elif(MCPeflgReg & 0x40):
229 print "WARNING: RXB0 overflow flag set. A packet has been missed. Clearing and proceeding."
230 self.client.MCPbitmodify(0x2D,0xC0,0x00);
231 print"EFLG register set to: %x" % self.client.peek(0x2D);
234 if (self.client.peek8(0x2C) & 0x80):
235 self.client.MCPbitmodify(0x2C,0x80,0x00);
236 print "ERROR: Malformed packet recieved: " + self.client.packet2str(packet);
241 row.append(0); #since we don't check for errors if we're not in debug mode...
244 #how long the sniff was for
246 #boolean that tells us if there was filtering. 0 == no filters, 1 == filters
247 if(standardid != None):
251 #write packet to file
253 row.append("%02x"%ord(byte));
254 dataWriter.writerow(row);
255 if(writeToFile == True):
257 print "Listened for %d seconds, captured %d packets." %(duration,packetcount);
261 # def filterStdSweep(self, freq, low, high, time = 5):
263 # self.client.serInit()
264 # self.client.MCPsetup()
265 # for i in range(low, high+1, 6):
266 # print "sniffing id: %d, %d, %d, %d, %d, %d" % (i,i+1,i+2,i+3,i+4,i+5)
267 # comment= "sweepFilter: "
268 # #comment = "sweepFilter_%d_%d_%d_%d_%d_%d" % (i,i+1,i+2,i+3,i+4,i+5)
269 # 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)
270 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [i, i+1, i+2, i+3, i+4, i+5])
272 # for j in range(i,i+5):
273 # comment = "sweepFilter: "
274 # #comment = "sweepFilter: %d" % (j)
275 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % j
276 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [j, j, j, j])
281 # def sweepRandom(self, freq, number = 5, time = 200):
284 # self.client.serInit()
285 # self.client.MCPsetup()
286 # for i in range(0,number+1,6):
288 # comment = "sweepFilter: "
289 # for j in range(0,6,1):
290 # id = randrange(2047)
291 # #comment += "_%d" % id
295 # description = "Running a sweep filer for all the possible standard IDs. This runs the following : " + comment
296 # count = self.sniff(freq=freq, duration=time, description=description, comment = comment, standardid = idsTemp)
298 # for element in idsTemp:
299 # #comment = "sweepFilter: %d" % (element)
300 # comment="sweepFilter: "
301 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % element
302 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [element, element, element])
307 def sniffTest(self, freq):
309 This method will preform a test to see if we can sniff corretly formed packets from the CAN bus.
312 @param freq: frequency of the CAN bus
316 print "Calling MCPsetrate for %i." %rate;
317 self.client.MCPsetrate(rate);
318 self.client.MCPreqstatNormal();
320 print "Mode: %s" % self.client.MCPcanstatstr();
321 print "CNF1: %02x" %self.client.peek8(0x2a);
322 print "CNF2: %02x" %self.client.peek8(0x29);
323 print "CNF3: %02x\n" %self.client.peek8(0x28);
326 packet=self.client.rxpacket();
329 if (self.client.peek8(0x2C) & 0x80):
330 self.client.MCPbitmodify(0x2C,0x80,0x00);
331 print "malformed packet recieved: "+ self.client.packet2str(packet);
333 print "properly formatted packet recieved" + self.client.packet2str(packet);
336 def freqtest(self,freq):
338 This method will test the frequency provided to see if it is the correct frequency for this CAN bus.
341 @param freq: The frequency to listen to the CAN bus.
344 self.client.MCPsetup();
346 self.client.MCPsetrate(freq);
347 self.client.MCPreqstatListenOnly();
349 print "CAN Freq Test: %3d kHz" %freq;
354 starttime = time.time();
355 while((time.time()-starttime < args.time)):
356 packet=self.client.rxpacket();
360 if (self.client.peek8(0x2C) & 0x80):
361 print "malformed packet recieved"
363 self.client.MCPbitmodify(0x2C,0x80,0x00);
365 print self.client.packet2str(packet);
367 print "Results for %3.1d kHz: recieved %3d packets, registered %3d RX errors." %(freq, x, errors);
370 def isniff(self,freq):
371 """ An intelligent sniffer, decodes message format """
372 """ More features to be added soon """
374 self.client.MCPsetrate(freq);
375 self.client.MCPreqstatListenOnly();
377 packet=self.client.rxpacket();
386 print "\nArbID: " + self.client.packet2str(arbid);
387 print "EID: " + self.client.packet2str(eid);
388 print "DLC: " + self.client.packet2str(dlc);
389 print "Data: " + self.client.packet2str(data);
392 """ This will perform a test on the GOODTHOPTER10. Diagnostic messages will be printed
396 print "Just reset..."
397 print "EFLG register: %02x" % self.client.peek8(0x2d);
398 print "Tx Errors: %3d" % self.client.peek8(0x1c);
399 print "Rx Errors: %3d" % self.client.peek8(0x1d);
400 print "CANINTF: %02x" %self.client.peek8(0x2C);
401 self.client.MCPreqstatConfiguration();
402 self.client.poke8(0x60,0x66);
403 self.client.MCPsetrate(500);
404 self.client.MCPreqstatNormal();
405 print "In normal mode now"
406 print "EFLG register: %02x" % self.client.peek8(0x2d);
407 print "Tx Errors: %3d" % self.client.peek8(0x1c);
408 print "Rx Errors: %3d" % self.client.peek8(0x1d);
409 print "CANINTF: %02x" %self.client.peek8(0x2C);
410 print "Waiting on packets.";
414 packet=self.client.rxpacket();
416 print "Message recieved: %s" % self.client.packet2str(packet);
418 checkcount=checkcount+1;
419 if (checkcount%30==0):
420 print "EFLG register: %02x" % self.client.peek8(0x2d);
421 print "Tx Errors: %3d" % self.client.peek8(0x1c);
422 print "Rx Errors: %3d" % self.client.peek8(0x1d);
423 print "CANINTF: %02x" %self.client.peek8(0x2C);
428 def addFilter(self,standardid, verbose= True):
429 """ This method will configure filters on the board. Filters are positive filters meaning that they will only
430 store messages that match the ids provided in the list of standardid. Since there are 2 buffers and due to the configuration
431 of how the filtering works (see MCP2515 documentation), at least 3 filters must be set to guarentee you do not get any
432 unwanted messages. However even with only 1 filter set you should get all messages from that ID but the other buffer will store
433 any additional messages.
434 @type standardid: list of integers
435 @param standardid: List of standard ids that need to be set. There can be at most 6 filters set.
436 @type verbose: Boolean
437 @param verbose: If true it will print out messages and diagnostics to terminal.
440 @return: This method does not return anything
441 @todo: rename setFilters
444 ### ON-CHIP FILTERING
445 if(standardid != None):
446 self.client.MCPreqstatConfiguration();
447 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
448 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
449 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
450 if(len(standardid)>2):
451 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
452 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
453 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
455 for filter,ID in enumerate(standardid):
476 #### split SID into different regs
477 SIDlow = (ID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
478 SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
481 self.client.poke8(RXFSIDH,SIDhigh);
482 self.client.poke8(RXFSIDL, SIDlow);
484 if (verbose == True):
485 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
487 self.client.MCPreqstatNormal();
489 def filterForPacket(self, standardid, DB0, DB1, verbose= True):
491 This method will configure filters on the board to listen for a specific packet originating
492 from standardid with data bytes 0 and 1. It will configure all six filters, so you will not receive any other packets.
494 @type standardid: integer
495 @param standardid: standardID to listen for
497 @param standardid: DB0 contents to filter for
499 @param standardid: DB1 contents to filter for
500 @type verbose: Boolean
501 @param verbose: If true it will print out messages and diagnostics to terminal.
504 @return: This method does not return anything
507 ### ON-CHIP FILTERING
509 self.client.MCPreqstatConfiguration();
511 # SID filtering: set CTRL registers to only accept standard messages
512 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
513 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
515 # Mask buffer 0 to match SID, DB0, DB1
516 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
517 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
518 self.client.poke8(0x22,0xFF); #set buffer 0 mask 3 (DB0) to FF
519 self.client.poke8(0x23,0xFF); #set buffer 0 mask 4 (DB0) to FF
521 # Mask buffer 1 to match SID, DB0, DB1
522 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
523 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
524 self.client.poke8(0x26,0xFF); #set buffer 1 mask 3 (DB0) to FF
525 self.client.poke8(0x27,0xFF); #set buffer 1 mask 4 (DB1) to FF
527 # Split SID into high and low bytes
528 SIDlow = (standardid & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
529 SIDhigh = (standardid >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
532 for filter in range(0,5):
565 self.client.poke8(RXFSIDH, SIDhigh);
566 self.client.poke8(RXFSIDL, SIDlow);
567 self.client.poke8(RXFDB0, DB0);
568 self.client.poke8(RXFDB1, DB1);
570 if (verbose == True):
571 print "Filtering for SID %d DB0 0x%02xh DB1 0x%02xh with filter #%d"%(ID, DB0, DB1, filter);
573 self.client.MCPreqstatNormal();
578 def spitSetup(self,freq):
580 This method sets up the chip for transmitting messages, but does not transmit anything itself.
583 self.client.MCPsetrate(freq);
584 self.client.MCPreqstatNormal();
587 def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
589 This method will spit a single message onto the bus. If there is no packet information provided then the
590 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
591 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
592 This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
595 @param freq: The frequency of the bus
597 @type standardid: list of integer
598 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
600 @type repeat: Boolean
601 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
603 @type writes: Integer
604 @param writes: Number of writes of the packet
606 @type period: Integer
607 @param period: Time delay between injections of the packet in Milliseconds
610 @param debug: When true debug status messages will be printed to the terminal
613 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
614 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
618 self.spitSetup(freq);
619 spit(self,freq, standardid, repeat,writes, period, debug , packet)
621 def spit(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
623 This method will spit a single message onto the bus. If there is no packet information provided then the
624 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
625 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
626 This method does not include bus setup, it must be done before the method call.
630 @param freq: The frequency of the bus
632 @type standardid: list of integer
633 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
635 @type repeat: Boolean
636 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
638 @type writes: Integer
639 @param writes: Number of writes of the packet
641 @type period: Integer
642 @param period: Time delay between injections of the packet in Milliseconds
645 @param debug: When true debug status messages will be printed to the terminal
648 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
649 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
654 #### split SID into different regs
655 SIDlow = (standardid[0] & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
656 SIDhigh = (standardid[0] >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
660 # if no packet, RTR for inputted arbID
661 # so packet to transmit is SID + padding out EID registers + RTR request (set bit 6, clear lower nibble of DLC register)
662 packet = [SIDhigh, SIDlow, 0x00,0x00,0x40]
667 # if we do have a packet, packet is SID + padding out EID registers + DLC of 8 + packet
669 """@todo: allow for variable-length packets"""
670 # TODO: allow for variable-length packets
672 packet = [SIDhigh, SIDlow, 0x00,0x00, # pad out EID regs
673 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
674 # lower nibble is DLC
675 packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]]
679 if self.client.MCPcanstat()>>5!=0:
680 print "Warning: currently in %s mode. NOT in normal mode! May not transmit.\n" %self.client.MCPcanstatstr();
681 print "\nInitial state:"
682 print "Tx Errors: %3d" % self.client.peek8(0x1c);
683 print "Rx Errors: %3d" % self.client.peek8(0x1d);
684 print "Error Flags: %02x\n" % self.client.peek8(0x2d);
685 print "TXB0CTRL: %02x" %self.client.peek8(0x30);
686 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
687 print "\n\nATTEMPTING TRANSMISSION!!!"
690 print "Transmitting packet: "
691 #print self.client.packet2str(packet)
693 self.client.txpacket(packet);
696 """@todo: the repeat variable is no longer needed and can be removed """
697 print "\nNow looping on transmit. "
699 for i in range(0,writes):
700 self.client.MCPrts(TXB0=True);
702 time.sleep(period/1000) # pause for period ms before sending again
703 #print time.time()-tic
704 #starttime = time.time();
705 #while((time.time()-starttime < duration)):
706 # self.client.MCPrts(TXB0=True);
707 # print "MSG printed"
709 for i in range(0,writes):
710 self.client.MCPrts(TXB0=True);
711 print "messages injected"
716 TXB0CTRL = self.client.peek8(0x30);
718 print "Tx Errors: %3d" % self.client.peek8(0x1c);
719 print "Rx Errors: %3d" % self.client.peek8(0x1d);
720 print "EFLG register: %02x" % self.client.peek8(0x2d);
721 print "TXB0CTRL: %02x" %TXB0CTRL;
722 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
724 while(TXB0CTRL | 0x00 != 0x00):
726 TXB0CTRL = self.client.peek8(0x30);
727 if (checkcount %30 ==0):
728 print "Tx Errors: %3d" % self.client.peek8(0x1c);
729 print "Rx Errors: %3d" % self.client.peek8(0x1d);
730 print "EFLG register: %02x" % self.client.peek8(0x2d);
731 print "TXB0CTRL: %02x" %TXB0CTRL;
732 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
735 def setRate(self,freq):
737 This method will reset the frequency that the MCP2515 expects the CAN bus to be on.
740 @param freq: Frequency of the CAN bus
742 self.client.MCPsetrate(freq);
745 # This will write the data provided in the packets which is expected to be a list of lists
746 # of the following form:
747 # for a given row = packets[i]
748 # row[0] time delay relative to the last packet. if 0 or empty there will be no delay
749 # row[1] = Standard ID (integer)
750 # row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
751 # row[3] = Data Byte 0
752 # row[4] = Data Byte 1
753 # .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
754 def writeData(self,packets,freq):
755 self.client.serInit()
758 if( row[0] != 0 and row[0] != ""):
761 #### split SID into different regs
762 SIDlow = (sID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
763 SIDhigh = (sID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
764 packet = [SIDhigh,SIDlow,0x00,0x00,0x08]
767 for i in range(3,dlc+3):
768 packet.append(row[i])
770 self.client.txpacket(packet)
776 if __name__ == "__main__":
778 parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''\
780 Run commands on the MCP2515. Valid commands are:
784 peek 0x(start) [0x(stop)]
794 parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit']);
795 parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
796 parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
797 parser.add_argument('-o', '--output', default=None,help='Output file');
798 parser.add_argument("-d", "--description", help='Description of experiment (included in the output file)', default="");
799 parser.add_argument('-v',"--verbose",action='store_false',help='-v will stop packet output to terminal', default=True);
800 parser.add_argument('-c','--comment', help='Comment attached to ech packet uploaded',default=None);
801 parser.add_argument('-b', '--debug', action='store_true', help='-b will turn on debug mode, printing packet status', default=False);
802 parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
803 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);
804 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);
807 args = parser.parse_args();
810 filename = args.output
811 description = args.description
812 verbose = args.verbose
813 comments = args.comment
815 standardid = args.standardid
819 comm = GoodFETMCPCANCommunication();
821 ##########################
823 ##########################
825 # Prints MCP state info
827 if(args.verb=="info"):
831 ##########################
833 ##########################
837 if(args.verb=="reset"):
840 ##########################
842 ##########################
844 # runs in ListenOnly mode
845 # utility function to pull info off the car's CAN bus
848 if(args.verb=="sniff"):
849 comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster)
851 ##########################
853 ##########################
855 # runs in NORMAL mode
856 # intended for NETWORKED MCP chips to verify proper operation
859 if(args.verb=="snifftest"):
860 comm.sniffTest(freq=freq)
863 ##########################
865 ##########################
867 # runs in LISTEN ONLY mode
868 # tests bus for desired frequency --> sniffs bus for specified length of time and reports
869 # if packets were properly formatted
873 if(args.verb=="freqtest"):
874 comm.freqtest(freq=freq)
878 ##########################
880 ##########################
882 # """ An intelligent sniffer, decodes message format """
883 # """ More features to be added soon """
884 if(args.verb=="isniff"):
885 comm.isniff(freq=freq)
888 ##########################
890 ##########################
892 # Runs in LOOPBACK mode
893 # self-check diagnostic
894 # wasn't working before due to improperly formatted packet
896 # ...add automatic packet check rather than making user verify successful packet
897 if(args.verb=="test"):
900 if(args.verb=="peek"):
903 start=int(sys.argv[2],16);
906 stop=int(sys.argv[3],16);
907 print "Peeking from %04x to %04x." % (start,stop);
909 print "%04x: %02x" % (start,client.peek8(start));
912 ##########################
914 ##########################
916 # Basic packet transmission
917 # runs in NORMAL MODE!
919 # checking TX error flags--> currently throwing error flags on every
920 # transmission (travis thinks this is because we're sniffing in listen-only
921 # and thus not generating an ack bit on the recieving board)
922 if(args.verb=="spit"):
923 comm.spitSingle(freq=freq, standardid=standardid,duration=duration, repeat=repeat, debug=debug)