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(); """ Communication with the bus"""
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"""
38 """ This method will print information about the board to the termina. It is usefull for diagnostics"""
39 self.client.MCPreqstatConfiguration();
41 print "MCP2515 Info:\n\n";
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);
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);
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));
65 packet0=self.client.readrxbuffer(0);
66 packet1=self.client.readrxbuffer(1);
67 for foo in [packet0, packet1]:
68 print self.client.packet2str(foo);
74 self.client.MCPsetup();
77 ##########################
79 ##########################
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):
85 #reset eveything on the chip
89 #### ON-CHIP FILTERING
90 if(standardid != None):
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
102 for filter,ID in enumerate(standardid):
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
128 self.client.poke8(RXFSIDH,SIDhigh);
129 self.client.poke8(RXFSIDL, SIDlow);
131 if (verbose == True):
132 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
133 comment += ("f%d" %(ID))
136 self.client.MCPsetrate(freq);
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"
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])
152 self.client.MCPreqstatNormal();
153 print "Listening...";
155 starttime = time.time();
157 while((time.time()-starttime < duration)):
160 packet=self.client.fastrxpacket();
162 packet=self.client.rxpacket();
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)
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
186 if (packet!=None and writeToFile == True):
189 row.append("%f"%time.time());
192 #if we want to print a parsed message
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
203 for i in range(0,length):
205 msg +=" %03d"% ord(packetParsed[dbidx])
206 #msg = self.client.packet2parsedstr(packet)
208 # if we want to print just the message as it is read off the chip
210 print self.client.packet2str(packet)
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);
227 if (self.client.peek8(0x2C) & 0x80):
228 self.client.MCPbitmodify(0x2C,0x80,0x00);
229 print "ERROR: Malformed packet recieved: " + self.client.packet2str(packet);
234 row.append(0); #since we don't check for errors if we're not in debug mode...
237 #how long the sniff was for
239 #boolean that tells us if there was filtering. 0 == no filters, 1 == filters
240 if(standardid != None):
244 #write packet to file
246 row.append("%02x"%ord(byte));
247 dataWriter.writerow(row);
248 if(writeToFile == True):
250 print "Listened for %d seconds, captured %d packets." %(duration,packetcount);
254 # def filterStdSweep(self, freq, low, high, time = 5):
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])
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])
274 # def sweepRandom(self, freq, number = 5, time = 200):
277 # self.client.serInit()
278 # self.client.MCPsetup()
279 # for i in range(0,number+1,6):
281 # comment = "sweepFilter: "
282 # for j in range(0,6,1):
283 # id = randrange(2047)
284 # #comment += "_%d" % id
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)
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])
300 def sniffTest(self, freq):
304 print "Calling MCPsetrate for %i." %rate;
305 self.client.MCPsetrate(rate);
306 self.client.MCPreqstatNormal();
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);
314 packet=self.client.rxpacket();
317 if (self.client.peek8(0x2C) & 0x80):
318 self.client.MCPbitmodify(0x2C,0x80,0x00);
319 print "malformed packet recieved: "+ self.client.packet2str(packet);
321 print "properly formatted packet recieved" + self.client.packet2str(packet);
324 def freqtest(self,freq):
326 self.client.MCPsetup();
328 self.client.MCPsetrate(freq);
329 self.client.MCPreqstatListenOnly();
331 print "CAN Freq Test: %3d kHz" %freq;
336 starttime = time.time();
337 while((time.time()-starttime < args.time)):
338 packet=self.client.rxpacket();
342 if (self.client.peek8(0x2C) & 0x80):
343 print "malformed packet recieved"
345 self.client.MCPbitmodify(0x2C,0x80,0x00);
347 print self.client.packet2str(packet);
349 print "Results for %3.1d kHz: recieved %3d packets, registered %3d RX errors." %(freq, x, errors);
352 def isniff(self,freq):
353 """ An intelligent sniffer, decodes message format """
354 """ More features to be added soon """
356 self.client.MCPsetrate(freq);
357 self.client.MCPreqstatListenOnly();
359 packet=self.client.rxpacket();
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);
374 """ This will perform a test on the GOODTHOPTER10. Diagnostic messages will be printed
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.";
396 packet=self.client.rxpacket();
398 print "Message recieved: %s" % self.client.packet2str(packet);
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);
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.
422 @return: This method does not return anything
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
436 for filter,ID in enumerate(standardid):
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
462 self.client.poke8(RXFSIDH,SIDhigh);
463 self.client.poke8(RXFSIDL, SIDlow);
465 if (verbose == True):
466 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
468 self.client.MCPreqstatNormal();
470 def filterForPacket(self, standardid, DB0, DB1, verbose= True):
471 """ 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.
472 @type standardid: integer
473 @param standardid: standardID to listen for
475 @param standardid: DB0 contents to filter for
477 @param standardid: DB1 contents to filter for
478 @type verbose: Boolean
479 @param verbose: If true it will print out messages and diagnostics to terminal.
482 @return: This method does not return anything
485 ### ON-CHIP FILTERING
487 self.client.MCPreqstatConfiguration();
489 # SID filtering: set CTRL registers to only accept standard messages
490 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
491 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
493 # Mask buffer 0 to match SID, DB0, DB1
494 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
495 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
496 self.client.poke8(0x22,0xFF); #set buffer 0 mask 3 (DB0) to FF
497 self.client.poke8(0x23,0xFF); #set buffer 0 mask 4 (DB0) to FF
499 # Mask buffer 1 to match SID, DB0, DB1
500 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
501 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
502 self.client.poke8(0x26,0xFF); #set buffer 1 mask 3 (DB0) to FF
503 self.client.poke8(0x27,0xFF); #set buffer 1 mask 4 (DB1) to FF
505 # Split SID into high and low bytes
506 SIDlow = (standardid & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
507 SIDhigh = (standardid >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
510 for filter in range(0,5):
543 self.client.poke8(RXFSIDH, SIDhigh);
544 self.client.poke8(RXFSIDL, SIDlow);
545 self.client.poke8(RXFDB0, DB0);
546 self.client.poke8(RXFDB1, DB1);
548 if (verbose == True):
549 print "Filtering for SID %d DB0 0x%02xh DB1 0x%02xh with filter #%d"%(ID, DB0, DB1, filter);
551 self.client.MCPreqstatNormal();
556 def spitSetup(self,freq):
558 This method sets up the chip for transmitting messages, but does not transmit anything itself.
561 self.client.MCPsetrate(freq);
562 self.client.MCPreqstatNormal();
565 def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
567 This method will spit a single message onto the bus. If there is no packet information provided then the
568 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
569 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
570 This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
573 @param freq: The frequency of the bus
575 @type standardid: list of integer
576 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
578 @type repeat: Boolean
579 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
581 @type writes: Integer
582 @param writes: Number of writes of the packet
584 @type period: Integer
585 @param period: Time delay between injections of the packet in Milliseconds
588 @param debug: When true debug status messages will be printed to the terminal
591 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
592 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
596 self.spitSetup(freq);
597 spit(self,freq, standardid, repeat,writes, period, debug , packet)
599 def spit(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
601 This method will spit a single message onto the bus. If there is no packet information provided then the
602 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
603 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
604 This method does not include bus setup, it must be done before the method call.
608 @param freq: The frequency of the bus
610 @type standardid: list of integer
611 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
613 @type repeat: Boolean
614 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
616 @type writes: Integer
617 @param writes: Number of writes of the packet
619 @type period: Integer
620 @param period: Time delay between injections of the packet in Milliseconds
623 @param debug: When true debug status messages will be printed to the terminal
626 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
627 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
632 #### split SID into different regs
633 SIDlow = (standardid[0] & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
634 SIDhigh = (standardid[0] >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
638 # if no packet, RTR for inputted arbID
639 # so packet to transmit is SID + padding out EID registers + RTR request (set bit 6, clear lower nibble of DLC register)
640 packet = [SIDhigh, SIDlow, 0x00,0x00,0x40]
645 # if we do have a packet, packet is SID + padding out EID registers + DLC of 8 + packet
647 """@todo: allow for variable-length packets"""
648 # TODO: allow for variable-length packets
650 packet = [SIDhigh, SIDlow, 0x00,0x00, # pad out EID regs
651 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
652 # lower nibble is DLC
653 packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]]
657 if self.client.MCPcanstat()>>5!=0:
658 print "Warning: currently in %s mode. NOT in normal mode! May not transmit.\n" %self.client.MCPcanstatstr();
659 print "\nInitial state:"
660 print "Tx Errors: %3d" % self.client.peek8(0x1c);
661 print "Rx Errors: %3d" % self.client.peek8(0x1d);
662 print "Error Flags: %02x\n" % self.client.peek8(0x2d);
663 print "TXB0CTRL: %02x" %self.client.peek8(0x30);
664 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
665 print "\n\nATTEMPTING TRANSMISSION!!!"
668 print "Transmitting packet: "
669 #print self.client.packet2str(packet)
671 self.client.txpacket(packet);
674 """@todo: the repeat variable is no longer needed and can be removed """
675 print "\nNow looping on transmit. "
677 for i in range(0,writes):
678 self.client.MCPrts(TXB0=True);
680 time.sleep(period/1000) # pause for period ms before sending again
681 #print time.time()-tic
682 #starttime = time.time();
683 #while((time.time()-starttime < duration)):
684 # self.client.MCPrts(TXB0=True);
685 # print "MSG printed"
687 for i in range(0,writes):
688 self.client.MCPrts(TXB0=True);
689 print "messages injected"
694 TXB0CTRL = self.client.peek8(0x30);
696 print "Tx Errors: %3d" % self.client.peek8(0x1c);
697 print "Rx Errors: %3d" % self.client.peek8(0x1d);
698 print "EFLG register: %02x" % self.client.peek8(0x2d);
699 print "TXB0CTRL: %02x" %TXB0CTRL;
700 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
702 while(TXB0CTRL | 0x00 != 0x00):
704 TXB0CTRL = self.client.peek8(0x30);
705 if (checkcount %30 ==0):
706 print "Tx Errors: %3d" % self.client.peek8(0x1c);
707 print "Rx Errors: %3d" % self.client.peek8(0x1d);
708 print "EFLG register: %02x" % self.client.peek8(0x2d);
709 print "TXB0CTRL: %02x" %TXB0CTRL;
710 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
713 def setRate(self,freq):
715 This method will reset the frequency that the MCP2515 expects the CAN bus to be on.
718 @param freq: Frequency of the CAN bus
720 self.client.MCPsetrate(freq);
723 # This will write the data provided in the packets which is expected to be a list of lists
724 # of the following form:
725 # for a given row = packets[i]
726 # row[0] time delay relative to the last packet. if 0 or empty there will be no delay
727 # row[1] = Standard ID (integer)
728 # row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
729 # row[3] = Data Byte 0
730 # row[4] = Data Byte 1
731 # .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
732 def writeData(self,packets,freq):
733 self.client.serInit()
736 if( row[0] != 0 and row[0] != ""):
739 #### split SID into different regs
740 SIDlow = (sID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
741 SIDhigh = (sID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
742 packet = [SIDhigh,SIDlow,0x00,0x00,0x08]
745 for i in range(3,dlc+3):
746 packet.append(row[i])
748 self.client.txpacket(packet)
754 if __name__ == "__main__":
756 parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''\
758 Run commands on the MCP2515. Valid commands are:
762 peek 0x(start) [0x(stop)]
772 parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit']);
773 parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
774 parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
775 parser.add_argument('-o', '--output', default=None,help='Output file');
776 parser.add_argument("-d", "--description", help='Description of experiment (included in the output file)', default="");
777 parser.add_argument('-v',"--verbose",action='store_false',help='-v will stop packet output to terminal', default=True);
778 parser.add_argument('-c','--comment', help='Comment attached to ech packet uploaded',default=None);
779 parser.add_argument('-b', '--debug', action='store_true', help='-b will turn on debug mode, printing packet status', default=False);
780 parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
781 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);
782 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);
785 args = parser.parse_args();
788 filename = args.output
789 description = args.description
790 verbose = args.verbose
791 comments = args.comment
793 standardid = args.standardid
797 comm = GoodFETMCPCANCommunication();
799 ##########################
801 ##########################
803 # Prints MCP state info
805 if(args.verb=="info"):
809 ##########################
811 ##########################
815 if(args.verb=="reset"):
818 ##########################
820 ##########################
822 # runs in ListenOnly mode
823 # utility function to pull info off the car's CAN bus
826 if(args.verb=="sniff"):
827 comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster)
829 ##########################
831 ##########################
833 # runs in NORMAL mode
834 # intended for NETWORKED MCP chips to verify proper operation
837 if(args.verb=="snifftest"):
838 comm.sniffTest(freq=freq)
841 ##########################
843 ##########################
845 # runs in LISTEN ONLY mode
846 # tests bus for desired frequency --> sniffs bus for specified length of time and reports
847 # if packets were properly formatted
851 if(args.verb=="freqtest"):
852 comm.freqtest(freq=freq)
856 ##########################
858 ##########################
860 # """ An intelligent sniffer, decodes message format """
861 # """ More features to be added soon """
862 if(args.verb=="isniff"):
863 comm.isniff(freq=freq)
866 ##########################
868 ##########################
870 # Runs in LOOPBACK mode
871 # self-check diagnostic
872 # wasn't working before due to improperly formatted packet
874 # ...add automatic packet check rather than making user verify successful packet
875 if(args.verb=="test"):
878 if(args.verb=="peek"):
881 start=int(sys.argv[2],16);
884 stop=int(sys.argv[3],16);
885 print "Peeking from %04x to %04x." % (start,stop);
887 print "%04x: %02x" % (start,client.peek8(start));
890 ##########################
892 ##########################
894 # Basic packet transmission
895 # runs in NORMAL MODE!
897 # checking TX error flags--> currently throwing error flags on every
898 # transmission (travis thinks this is because we're sniffing in listen-only
899 # and thus not generating an ack bit on the recieving board)
900 if(args.verb=="spit"):
901 comm.spitSingle(freq=freq, standardid=standardid,duration=duration, repeat=repeat, debug=debug)