2 # GoodFET SPI Flash Client
4 # (C) 2012 Travis Goodspeed <travis at radiantmachines.com>
6 # Edited By: Chris Hoder 2013
15 import csv, time, argparse;
18 from random import randrange
19 from GoodFETMCPCAN import GoodFETMCPCAN;
20 from intelhex import IntelHex;
23 class GoodFETMCPCANCommunication:
25 def __init__(self, dataLocation = "../../contrib/ThayerData/"):
26 self.client=GoodFETMCPCAN();
27 """ Communication with the bus"""
29 self.client.MCPsetup();
30 #self.DATA_LOCATION = "../../contrib/ThayerData/"
31 self.DATA_LOCATION = dataLocation;
32 """ Stores file data location. This is the root folder where basic sniffs will be stored"""
33 self.INJECT_DATA_LOCATION = self.DATA_LOCATION+"InjectedData/"
34 """ stores the sub folder path where injected data will be stored"""
40 This method will print information about the board to the terminal.
41 It is good for diagnostics
44 self.client.MCPreqstatConfiguration();
46 print "MCP2515 Info:\n\n";
48 print "Mode: %s" % self.client.MCPcanstatstr();
49 print "Read Status: %02x" % self.client.MCPreadstatus();
50 print "Rx Status: %02x" % self.client.MCPrxstatus();
51 print "Error Flags: %02x" % self.client.peek8(0x2D);
52 print "Tx Errors: %3d" % self.client.peek8(0x1c);
53 print "Rx Errors: %3d\n" % self.client.peek8(0x1d);
56 print "CNF1: %02x" %self.client.peek8(0x2a);
57 print "CNF2: %02x" %self.client.peek8(0x29);
58 print "CNF3: %02x\n" %self.client.peek8(0x28);
59 print "RXB0 CTRL: %02x" %self.client.peek8(0x60);
60 print "RXB1 CTRL: %02x" %self.client.peek8(0x70);
63 print "RXB0: %02x" %self.client.peek8(0x60);
64 print "RXB1: %02x" %self.client.peek8(0x70);
65 print "RXB0 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x20), self.client.peek8(0x21), self.client.peek8(0x22), self.client.peek8(0x23));
66 print "RXB1 masks: %02x, %02x, %02x, %02x" %(self.client.peek8(0x24), self.client.peek8(0x25), self.client.peek8(0x26), self.client.peek8(0x27));
70 packet0=self.client.readrxbuffer(0);
71 packet1=self.client.readrxbuffer(1);
72 for foo in [packet0, packet1]:
73 print self.client.packet2str(foo);
79 self.client.MCPsetup();
82 ##########################
84 ##########################
86 def sniff(self,freq,duration,description, verbose=True, comment=None, filename=None, standardid=None, debug=False, faster=False, parsed=True, data = None,writeToFile=True, db0 = None, db1 = None):
90 #reset eveything on the chip
94 # filtering for specific packets
95 if(db0 != None and db1 != None and standardid != None):
96 self.filterForPacket(standardid[0], db0, db1, verbose)
99 comment += ("f%d[%d][%d]" %(standardid[0], db0, db1))
100 # filtering for standard ID
101 elif(standardid != None):
102 self.addFilter(standardid, verbose)
105 for ID in standardid:
106 comment += ("f%d" %(ID))
109 self.client.MCPsetrate(freq);
111 # This will handle the files so that we do not loose them. each day we will create a new csv file
112 if( filename==None and writeToFile == True):
113 #get folder information (based on today's date)
114 now = datetime.datetime.now()
115 datestr = now.strftime("%Y%m%d")
116 path = self.DATA_LOCATION+datestr+".csv"
119 if( writeToFile == True):
120 outfile = open(filename,'a');
121 dataWriter = csv.writer(outfile,delimiter=',');
122 dataWriter.writerow(['# Time Error Bytes 1-13']);
123 dataWriter.writerow(['#' + description])
125 self.client.MCPreqstatNormal();
126 print "Listening...";
128 starttime = time.time();
130 while((time.time()-starttime < duration)):
133 packet=self.client.fastrxpacket();
135 packet=self.client.rxpacket();
137 #add the data to list if the pointer was included
138 if(data != None and packet != None):
139 #data.append(self.client.packet2parsedstr(packet))
140 packetParsed = self.client.packet2parsed(packet)
141 packetParsed["time"] =time.time()
142 data.put(packetParsed)
145 MCPstatusReg = self.client.MCPrxstatus();
146 messagestat=MCPstatusReg&0xC0;
147 messagetype=MCPstatusReg&0x18;
148 if(messagestat == 0xC0):
149 print "Message in both buffers; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
150 elif(messagestat == 0x80):
151 print "Message in RXB1; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
152 elif(messagestat == 0x40):
153 print "Message in RXB0; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
154 elif(messagestat == 0x00):
155 print "No messages in buffers."
156 #check to see if there was a packet
159 if (packet!=None and writeToFile == True):
162 row.append("%f"%time.time());
165 #if we want to print a parsed message
167 packetParsed = self.client.packet2parsed(packet)
168 sId = packetParsed.get('sID')
169 msg = "sID: %04d" %sId
170 if( packetParsed.get('eID')):
171 msg += " eID: %d" %packetParsed.get('eID')
172 msg += " rtr: %d"%packetParsed['rtr']
173 length = packetParsed['length']
174 msg += " length: %d"%length
176 for i in range(0,length):
178 msg +=" %03d"% packetParsed[dbidx]
179 #msg = self.client.packet2parsedstr(packet)
181 # if we want to print just the message as it is read off the chip
183 print self.client.packet2str(packet)
188 MCPeflgReg=self.client.peek8(0x2D);
189 print"EFLG register equals: %x" %MCPeflgReg;
190 if((MCPeflgReg & 0xC0)==0xC0):
191 print "WARNING: BOTH overflow flags set. Missed a packet. Clearing and proceeding."
192 elif(MCPeflgReg & 0x80):
193 print "WARNING: RXB1 overflow flag set. A packet has been missed. Clearing and proceeding."
194 elif(MCPeflgReg & 0x40):
195 print "WARNING: RXB0 overflow flag set. A packet has been missed. Clearing and proceeding."
196 self.client.MCPbitmodify(0x2D,0xC0,0x00);
197 print"EFLG register set to: %x" % self.client.peek(0x2D);
200 if (self.client.peek8(0x2C) & 0x80):
201 self.client.MCPbitmodify(0x2C,0x80,0x00);
202 print "ERROR: Malformed packet recieved: " + self.client.packet2str(packet);
207 row.append(0); #since we don't check for errors if we're not in debug mode...
210 #how long the sniff was for
212 #boolean that tells us if there was filtering. 0 == no filters, 1 == filters
213 if(standardid != None):
217 #write packet to file
219 row.append("%02x"%ord(byte));
220 dataWriter.writerow(row);
221 if(writeToFile == True):
223 print "Listened for %d seconds, captured %d packets." %(duration,packetcount);
227 # def filterStdSweep(self, freq, low, high, time = 5):
229 # self.client.serInit()
230 # self.client.MCPsetup()
231 # for i in range(low, high+1, 6):
232 # print "sniffing id: %d, %d, %d, %d, %d, %d" % (i,i+1,i+2,i+3,i+4,i+5)
233 # comment= "sweepFilter: "
234 # #comment = "sweepFilter_%d_%d_%d_%d_%d_%d" % (i,i+1,i+2,i+3,i+4,i+5)
235 # 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)
236 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [i, i+1, i+2, i+3, i+4, i+5])
238 # for j in range(i,i+5):
239 # comment = "sweepFilter: "
240 # #comment = "sweepFilter: %d" % (j)
241 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % j
242 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [j, j, j, j])
247 # def sweepRandom(self, freq, number = 5, time = 200):
250 # self.client.serInit()
251 # self.client.MCPsetup()
252 # for i in range(0,number+1,6):
254 # comment = "sweepFilter: "
255 # for j in range(0,6,1):
256 # id = randrange(2047)
257 # #comment += "_%d" % id
261 # description = "Running a sweep filer for all the possible standard IDs. This runs the following : " + comment
262 # count = self.sniff(freq=freq, duration=time, description=description, comment = comment, standardid = idsTemp)
264 # for element in idsTemp:
265 # #comment = "sweepFilter: %d" % (element)
266 # comment="sweepFilter: "
267 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % element
268 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [element, element, element])
273 def sniffTest(self, freq):
275 This method will preform a test to see if we can sniff corretly formed packets from the CAN bus.
278 @param freq: frequency of the CAN bus
282 print "Calling MCPsetrate for %i." %rate;
283 self.client.MCPsetrate(rate);
284 self.client.MCPreqstatNormal();
286 print "Mode: %s" % self.client.MCPcanstatstr();
287 print "CNF1: %02x" %self.client.peek8(0x2a);
288 print "CNF2: %02x" %self.client.peek8(0x29);
289 print "CNF3: %02x\n" %self.client.peek8(0x28);
292 packet=self.client.rxpacket();
295 if (self.client.peek8(0x2C) & 0x80):
296 self.client.MCPbitmodify(0x2C,0x80,0x00);
297 print "malformed packet recieved: "+ self.client.packet2str(packet);
299 print "properly formatted packet recieved" + self.client.packet2str(packet);
302 def freqtest(self,freq):
304 This method will test the frequency provided to see if it is the correct frequency for this CAN bus.
307 @param freq: The frequency to listen to the CAN bus.
310 self.client.MCPsetup();
312 self.client.MCPsetrate(freq);
313 self.client.MCPreqstatListenOnly();
315 print "CAN Freq Test: %3d kHz" %freq;
320 starttime = time.time();
321 while((time.time()-starttime < args.time)):
322 packet=self.client.rxpacket();
326 if (self.client.peek8(0x2C) & 0x80):
327 print "malformed packet recieved"
329 self.client.MCPbitmodify(0x2C,0x80,0x00);
331 print self.client.packet2str(packet);
333 print "Results for %3.1d kHz: recieved %3d packets, registered %3d RX errors." %(freq, x, errors);
336 def isniff(self,freq):
337 """ An intelligent sniffer, decodes message format """
338 """ More features to be added soon """
340 self.client.MCPsetrate(freq);
341 self.client.MCPreqstatListenOnly();
343 packet=self.client.rxpacket();
352 print "\nArbID: " + self.client.packet2str(arbid);
353 print "EID: " + self.client.packet2str(eid);
354 print "DLC: " + self.client.packet2str(dlc);
355 print "Data: " + self.client.packet2str(data);
358 """ This will perform a test on the GOODTHOPTER10. Diagnostic messages will be printed
362 print "Just reset..."
363 print "EFLG register: %02x" % self.client.peek8(0x2d);
364 print "Tx Errors: %3d" % self.client.peek8(0x1c);
365 print "Rx Errors: %3d" % self.client.peek8(0x1d);
366 print "CANINTF: %02x" %self.client.peek8(0x2C);
367 self.client.MCPreqstatConfiguration();
368 self.client.poke8(0x60,0x66);
369 self.client.MCPsetrate(500);
370 self.client.MCPreqstatNormal();
371 print "In normal mode now"
372 print "EFLG register: %02x" % self.client.peek8(0x2d);
373 print "Tx Errors: %3d" % self.client.peek8(0x1c);
374 print "Rx Errors: %3d" % self.client.peek8(0x1d);
375 print "CANINTF: %02x" %self.client.peek8(0x2C);
376 print "Waiting on packets.";
380 packet=self.client.rxpacket();
382 print "Message recieved: %s" % self.client.packet2str(packet);
384 checkcount=checkcount+1;
385 if (checkcount%30==0):
386 print "EFLG register: %02x" % self.client.peek8(0x2d);
387 print "Tx Errors: %3d" % self.client.peek8(0x1c);
388 print "Rx Errors: %3d" % self.client.peek8(0x1d);
389 print "CANINTF: %02x" %self.client.peek8(0x2C);
394 def addFilter(self,standardid, verbose= True):
395 """ This method will configure filters on the board. Filters are positive filters meaning that they will only
396 store messages that match the ids provided in the list of standardid. Since there are 2 buffers and due to the configuration
397 of how the filtering works (see MCP2515 documentation), at least 3 filters must be set to guarentee you do not get any
398 unwanted messages. However even with only 1 filter set you should get all messages from that ID but the other buffer will store
399 any additional messages.
400 @type standardid: list of integers
401 @param standardid: List of standard ids that need to be set. There can be at most 6 filters set.
402 @type verbose: Boolean
403 @param verbose: If true it will print out messages and diagnostics to terminal.
406 @return: This method does not return anything
407 @todo: rename setFilters
410 ### ON-CHIP FILTERING
411 if(standardid != None):
412 self.client.MCPreqstatConfiguration();
413 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
414 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
415 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
416 if(len(standardid)>2):
417 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
418 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
419 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
421 for filter,ID in enumerate(standardid):
442 #### split SID into different regs
443 SIDlow = (ID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
444 SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
447 self.client.poke8(RXFSIDH,SIDhigh);
448 self.client.poke8(RXFSIDL, SIDlow);
450 if (verbose == True):
451 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
453 self.client.MCPreqstatNormal();
455 def filterForPacket(self, standardid, DB0, DB1, verbose= True):
457 This method will configure filters on the board to listen for a specific packet originating
458 from standardid with data bytes 0 and 1. It will configure all six filters, so you will not receive any other packets.
460 @type standardid: integer
461 @param standardid: standardID to listen for
463 @param standardid: DB0 contents to filter for
465 @param standardid: DB1 contents to filter for
466 @type verbose: Boolean
467 @param verbose: If true it will print out messages and diagnostics to terminal.
470 @return: This method does not return anything
473 ### ON-CHIP FILTERING
475 self.client.MCPreqstatConfiguration();
477 # SID filtering: set CTRL registers to only accept standard messages
478 self.client.poke8(0x60,0x06); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
479 self.client.poke8(0x70,0x00); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
481 # Mask buffer 0 to match SID, DB0, DB1
482 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
483 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
484 self.client.poke8(0x22,0xFF); #set buffer 0 mask 3 (DB0) to FF
485 self.client.poke8(0x23,0xFF); #set buffer 0 mask 4 (DB0) to FF
487 # Mask buffer 1 to match SID, DB0, DB1
488 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
489 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
490 self.client.poke8(0x26,0xFF); #set buffer 1 mask 3 (DB0) to FF
491 self.client.poke8(0x27,0xFF); #set buffer 1 mask 4 (DB1) to FF
493 # Split SID into high and low bytes
494 SIDlow = (standardid & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
495 SIDhigh = (standardid >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
498 for filter in range(0,5):
530 self.client.poke8(RXFSIDH, SIDhigh);
531 self.client.poke8(RXFSIDL, SIDlow);
532 self.client.poke8(RXFDB0, DB0);
533 self.client.poke8(RXFDB1, DB1);
535 if (verbose == True):
536 print "Filtering for SID %d DB0 %d DB1 %d with filter #%d"%(standardid, DB0, DB1, filter);
538 self.client.MCPreqstatNormal();
540 def multiPacketTest(self):
543 self.client.MCPsetrate(500);
544 self.client.MCPreqstatNormal();
546 packet0 = [0x00, 0x00, 0x00,0x00, # pad out EID regs
547 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
548 # lower nibble is DLC
549 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
551 packet1 = [0x00, 0x20, 0x00,0x00, # pad out EID regs
552 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
553 # lower nibble is DLC
554 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
555 packet2 = [0x00, 0x40, 0x00,0x00, # pad out EID regs
556 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
557 # lower nibble is DLC
558 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
560 comm.multiPacketSpit(packet0=packet0, packet1=packet1, packet2=packet2)
562 comm.multiPacketSpit(packet0rts=True, packet1rts=True, packet2rts=True)
563 comm.multiPacketSpit(packet2rts=True)
564 comm.multiPacketSpit(packet1rts=True)
565 comm.multiPacketSpit(packet0rts=True)
569 def multiPacketSpit(self, packet0 = None, packet1 = None, packet2 = None, packet0rts = False, packet1rts = False, packet2rts = False):
571 This method writes packets to the chip's TX buffers and/or sends the contents of the buffers onto the bus.
573 @type packet0: list of integer
574 @param packet0: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF0
576 @type packet1: list of integer
577 @param packet1: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF1
579 @type packet2: list of integer
580 @param packet2: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF2
582 @type packet0rts: Boolean
583 @param packet0rts: If true the message in TX buffer 0 will be sent
585 @type packet2rts: Boolean
586 @param packet0rts: If true the message in TX buffer 1 will be sent
588 @type packet2rts: Boolean
589 @param packet0rts: If true the message in TX buffer 2 will be sent
594 self.client.writetxbuffer(packet0,0)
595 # print("trying to write TX buffer 0");
598 if (packet1 != None):
599 self.client.writetxbuffer(packet1,1)
600 # print("trying to write TX buffer 1");
603 if (packet2 != None):
604 self.client.writetxbuffer(packet2,2)
605 # print("trying to write TX buffer 2");
610 # print("trying to send TX buffer 0")
612 # print("trying to send TX buffer 1")
614 # print("trying to send TX buffer 2")
616 self.client.MCPrts(TXB0=packet0rts, TXB1=packet1rts, TXB2=packet2rts)
619 def spitSetup(self,freq):
621 This method sets up the chip for transmitting messages, but does not transmit anything itself.
624 self.client.MCPsetrate(freq);
625 self.client.MCPreqstatNormal();
628 def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
630 This method will spit a single message onto the bus. If there is no packet information provided then the
631 message will be sent as a remote transmission request (RTR). The packet length is assumed to be 8 bytes The message can be repeated given number of times with
632 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
633 This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
636 @param freq: The frequency of the bus
638 @type standardid: list of integer
639 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
641 @type repeat: Boolean
642 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
644 @type writes: Integer
645 @param writes: Number of writes of the packet
647 @type period: Integer
648 @param period: Time delay between injections of the packet in Milliseconds
651 @param debug: When true debug status messages will be printed to the terminal
654 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
655 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
659 self.spitSetup(freq);
660 spit(self,freq, standardid, repeat,writes, period, debug , packet)
662 def spit(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
664 This method will spit a single message onto the bus. If there is no packet information provided then the
665 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
666 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
667 This method does not include bus setup, it must be done before the method call.
671 @param freq: The frequency of the bus
673 @type standardid: list of integer
674 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
676 @type repeat: Boolean
677 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
679 @type writes: Integer
680 @param writes: Number of writes of the packet
682 @type period: Integer
683 @param period: Time delay between injections of the packet in Milliseconds
686 @param debug: When true debug status messages will be printed to the terminal
689 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
690 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
695 #### split SID into different regs
696 SIDlow = (standardid[0] & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
697 SIDhigh = (standardid[0] >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
701 # if no packet, RTR for inputted arbID
702 # so packet to transmit is SID + padding out EID registers + RTR request (set bit 6, clear lower nibble of DLC register)
703 packet = [SIDhigh, SIDlow, 0x00,0x00,0x40]
708 # if we do have a packet, packet is SID + padding out EID registers + DLC of 8 + packet
710 """@todo: allow for variable-length packets"""
711 # TODO: allow for variable-length packets
713 packet = [SIDhigh, SIDlow, 0x00,0x00, # pad out EID regs
714 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
715 # lower nibble is DLC
716 packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]]
720 if self.client.MCPcanstat()>>5!=0:
721 print "Warning: currently in %s mode. NOT in normal mode! May not transmit.\n" %self.client.MCPcanstatstr();
722 print "\nInitial state:"
723 print "Tx Errors: %3d" % self.client.peek8(0x1c);
724 print "Rx Errors: %3d" % self.client.peek8(0x1d);
725 print "Error Flags: %02x\n" % self.client.peek8(0x2d);
726 print "TXB0CTRL: %02x" %self.client.peek8(0x30);
727 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
728 print "\n\nATTEMPTING TRANSMISSION!!!"
730 print "Transmitting packet: "
731 #print self.client.packet2str(packet)
733 self.client.txpacket(packet);
736 """@todo: the repeat variable is no longer needed and can be removed """
737 print "\nNow looping on transmit. "
739 for i in range(0,writes):
740 self.client.MCPrts(TXB0=True);
742 time.sleep(period/1000) # pause for period ms before sending again
743 #print time.time()-tic
744 #starttime = time.time();
745 #while((time.time()-starttime < duration)):
746 # self.client.MCPrts(TXB0=True);
747 # print "MSG printed"
749 for i in range(0,writes):
750 self.client.MCPrts(TXB0=True);
751 print "messages injected"
756 TXB0CTRL = self.client.peek8(0x30);
758 print "Tx Errors: %3d" % self.client.peek8(0x1c);
759 print "Rx Errors: %3d" % self.client.peek8(0x1d);
760 print "EFLG register: %02x" % self.client.peek8(0x2d);
761 print "TXB0CTRL: %02x" %TXB0CTRL;
762 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
764 while(TXB0CTRL | 0x00 != 0x00):
766 TXB0CTRL = self.client.peek8(0x30);
767 if (checkcount %30 ==0):
768 print "Tx Errors: %3d" % self.client.peek8(0x1c);
769 print "Rx Errors: %3d" % self.client.peek8(0x1d);
770 print "EFLG register: %02x" % self.client.peek8(0x2d);
771 print "TXB0CTRL: %02x" %TXB0CTRL;
772 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
775 def setRate(self,freq):
777 This method will reset the frequency that the MCP2515 expects the CAN bus to be on.
780 @param freq: Frequency of the CAN bus
782 self.client.MCPsetrate(freq);
786 # This will write the data provided in the packets which is expected to be a list of lists
787 # of the following form:
788 # for a given row = packets[i]
789 # row[0] time delay relative to the last packet. if 0 or empty there will be no delay
790 # row[1] = Standard ID (integer)
791 # row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
792 # row[3] = Data Byte 0
793 # row[4] = Data Byte 1
794 # .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
795 def writeData(self,packets,freq):
797 This method will write a list of packets to the bus at the given frequency. This method assumes a packet
798 length of 8 for all packets as well as a standard id.
800 @type packets: List of Lists
801 @param packets: The list of packets to be injected into the bus. Each element of packets is a list that is
802 a packet to be injected onto the bus. These packets are assumed to be in the following format::
803 row[0] time delay relative to the last packet. if 0 or empty there will be no delay
804 row[1] = Standard ID (integer)
805 row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
809 row[10] = Data Byte 7
812 @param freq: Frequency of the CAN bus
815 self.client.serInit()
818 if( row[0] != 0 and row[0] != ""):
821 #### split SID into different regs
822 SIDlow = (sID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
823 SIDhigh = (sID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
824 packet = [SIDhigh,SIDlow,0x00,0x00,0x08]
827 for i in range(3,dlc+3):
828 packet.append(row[i])
830 self.client.txpacket(packet)
836 if __name__ == "__main__":
838 parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''\
840 Run commands on the MCP2515. Valid commands are:
844 peek 0x(start) [0x(stop)]
854 parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit', 'packet', 'multipacket']);
855 parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
856 parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
857 parser.add_argument('-o', '--output', default=None,help='Output file');
858 parser.add_argument("-d", "--description", help='Description of experiment (included in the output file)', default="");
859 parser.add_argument('-v',"--verbose",action='store_false',help='-v will stop packet output to terminal', default=True);
860 parser.add_argument('-c','--comment', help='Comment attached to ech packet uploaded',default=None);
861 parser.add_argument('-b', '--debug', action='store_true', help='-b will turn on debug mode, printing packet status', default=False);
862 parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
863 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);
864 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);
865 parser.add_argument('-db0', '--databyte0', type=int, default = None, help='-db0 to filter for a specfic data byte');
866 parser.add_argument('-db1', '--databyte1', type=int, default = None, help='-db0 to filter for a specfic data byte');
870 args = parser.parse_args();
873 filename = args.output
874 description = args.description
875 verbose = args.verbose
876 comments = args.comment
878 standardid = args.standardid
884 comm = GoodFETMCPCANCommunication("./");
886 if(args.verb=="packet"):
887 comm.filterForPacket(standardid=standardid[0], DB0=db0, DB1=db1, verbose= True)
888 if(args.verb=="multipacket"):
889 comm.multiPacketTest();
891 ##########################
893 ##########################
895 # Prints MCP state info
897 if(args.verb=="info"):
901 ##########################
903 ##########################
907 if(args.verb=="reset"):
910 ##########################
912 ##########################
914 # runs in ListenOnly mode
915 # utility function to pull info off the car's CAN bus
918 if(args.verb=="sniff"):
919 comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster, db0=db0, db1=db1)
921 ##########################
923 ##########################
925 # runs in NORMAL mode
926 # intended for NETWORKED MCP chips to verify proper operation
929 if(args.verb=="snifftest"):
930 comm.sniffTest(freq=freq)
933 ##########################
935 ##########################
937 # runs in LISTEN ONLY mode
938 # tests bus for desired frequency --> sniffs bus for specified length of time and reports
939 # if packets were properly formatted
943 if(args.verb=="freqtest"):
944 comm.freqtest(freq=freq)
948 ##########################
950 ##########################
952 # """ An intelligent sniffer, decodes message format """
953 # """ More features to be added soon """
954 if(args.verb=="isniff"):
955 comm.isniff(freq=freq)
958 ##########################
960 ##########################
962 # Runs in LOOPBACK mode
963 # self-check diagnostic
964 # wasn't working before due to improperly formatted packet
966 # ...add automatic packet check rather than making user verify successful packet
967 if(args.verb=="test"):
970 if(args.verb=="peek"):
973 start=int(sys.argv[2],16);
976 stop=int(sys.argv[3],16);
977 print "Peeking from %04x to %04x." % (start,stop);
979 print "%04x: %02x" % (start,client.peek8(start));
982 ##########################
984 ##########################
986 # Basic packet transmission
987 # runs in NORMAL MODE!
989 # checking TX error flags--> currently throwing error flags on every
990 # transmission (travis thinks this is because we're sniffing in listen-only
991 # and thus not generating an ack bit on the recieving board)
992 if(args.verb=="spit"):
993 comm.spitSingle(freq=freq, standardid=standardid,duration=duration, repeat=repeat, debug=debug)