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, db0 = None, db1 = None):
92 #reset eveything on the chip
96 # filtering for specific packets
97 if(db0 != None and db1 != None and standardid != None):
98 self.filterForPacket(standardid[0], db0, db1, verbose)
101 comment += ("f%d[%d][%d]" %(standardid[0], db0, db1))
102 # filtering for standard ID
103 elif(standardid != None):
104 self.addFilter(standardid, verbose)
107 for ID in standardid:
108 comment += ("f%d" %(ID))
111 self.client.MCPsetrate(freq);
113 # This will handle the files so that we do not loose them. each day we will create a new csv file
114 if( filename==None and writeToFile == True):
115 #get folder information (based on today's date)
116 now = datetime.datetime.now()
117 datestr = now.strftime("%Y%m%d")
118 path = self.DATA_LOCATION+datestr+".csv"
121 if( writeToFile == True):
122 outfile = open(filename,'a');
123 dataWriter = csv.writer(outfile,delimiter=',');
124 dataWriter.writerow(['# Time Error Bytes 1-13']);
125 dataWriter.writerow(['#' + description])
127 self.client.MCPreqstatNormal();
128 print "Listening...";
130 starttime = time.time();
132 while((time.time()-starttime < duration)):
135 packet=self.client.fastrxpacket();
137 packet=self.client.rxpacket();
139 #add the data to list if the pointer was included
140 if(data != None and packet != None):
141 #data.append(self.client.packet2parsedstr(packet))
142 packetParsed = self.client.packet2parsed(packet)
143 packetParsed["time"] =time.time()
144 data.put(packetParsed)
147 MCPstatusReg = self.client.MCPrxstatus();
148 messagestat=MCPstatusReg&0xC0;
149 messagetype=MCPstatusReg&0x18;
150 if(messagestat == 0xC0):
151 print "Message in both buffers; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
152 elif(messagestat == 0x80):
153 print "Message in RXB1; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
154 elif(messagestat == 0x40):
155 print "Message in RXB0; message type is %02x (0x00 is standard data, 0x08 is standard remote)." %messagetype
156 elif(messagestat == 0x00):
157 print "No messages in buffers."
158 #check to see if there was a packet
161 if (packet!=None and writeToFile == True):
164 row.append("%f"%time.time());
167 #if we want to print a parsed message
169 packetParsed = self.client.packet2parsed(packet)
170 sId = packetParsed.get('sID')
171 msg = "sID: %04d" %sId
172 if( packetParsed.get('eID')):
173 msg += " eID: %d" %packetParsed.get('eID')
174 msg += " rtr: %d"%packetParsed['rtr']
175 length = packetParsed['length']
176 msg += " length: %d"%length
178 for i in range(0,length):
180 msg +=" %03d"% packetParsed[dbidx]
181 #msg = self.client.packet2parsedstr(packet)
183 # if we want to print just the message as it is read off the chip
185 print self.client.packet2str(packet)
190 MCPeflgReg=self.client.peek8(0x2D);
191 print"EFLG register equals: %x" %MCPeflgReg;
192 if((MCPeflgReg & 0xC0)==0xC0):
193 print "WARNING: BOTH overflow flags set. Missed a packet. Clearing and proceeding."
194 elif(MCPeflgReg & 0x80):
195 print "WARNING: RXB1 overflow flag set. A packet has been missed. Clearing and proceeding."
196 elif(MCPeflgReg & 0x40):
197 print "WARNING: RXB0 overflow flag set. A packet has been missed. Clearing and proceeding."
198 self.client.MCPbitmodify(0x2D,0xC0,0x00);
199 print"EFLG register set to: %x" % self.client.peek(0x2D);
202 if (self.client.peek8(0x2C) & 0x80):
203 self.client.MCPbitmodify(0x2C,0x80,0x00);
204 print "ERROR: Malformed packet recieved: " + self.client.packet2str(packet);
209 row.append(0); #since we don't check for errors if we're not in debug mode...
212 #how long the sniff was for
214 #boolean that tells us if there was filtering. 0 == no filters, 1 == filters
215 if(standardid != None):
219 #write packet to file
221 row.append("%02x"%ord(byte));
222 dataWriter.writerow(row);
223 if(writeToFile == True):
225 print "Listened for %d seconds, captured %d packets." %(duration,packetcount);
229 # def filterStdSweep(self, freq, low, high, time = 5):
231 # self.client.serInit()
232 # self.client.MCPsetup()
233 # for i in range(low, high+1, 6):
234 # print "sniffing id: %d, %d, %d, %d, %d, %d" % (i,i+1,i+2,i+3,i+4,i+5)
235 # comment= "sweepFilter: "
236 # #comment = "sweepFilter_%d_%d_%d_%d_%d_%d" % (i,i+1,i+2,i+3,i+4,i+5)
237 # 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)
238 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [i, i+1, i+2, i+3, i+4, i+5])
240 # for j in range(i,i+5):
241 # comment = "sweepFilter: "
242 # #comment = "sweepFilter: %d" % (j)
243 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % j
244 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [j, j, j, j])
249 # def sweepRandom(self, freq, number = 5, time = 200):
252 # self.client.serInit()
253 # self.client.MCPsetup()
254 # for i in range(0,number+1,6):
256 # comment = "sweepFilter: "
257 # for j in range(0,6,1):
258 # id = randrange(2047)
259 # #comment += "_%d" % id
263 # description = "Running a sweep filer for all the possible standard IDs. This runs the following : " + comment
264 # count = self.sniff(freq=freq, duration=time, description=description, comment = comment, standardid = idsTemp)
266 # for element in idsTemp:
267 # #comment = "sweepFilter: %d" % (element)
268 # comment="sweepFilter: "
269 # description = "Running a sweep filer for all the possible standard IDs. This run filters for: %d " % element
270 # count = self.sniff(freq=freq, duration = time, description = description,comment = comment, standardid = [element, element, element])
275 def sniffTest(self, freq):
277 This method will preform a test to see if we can sniff corretly formed packets from the CAN bus.
280 @param freq: frequency of the CAN bus
284 print "Calling MCPsetrate for %i." %rate;
285 self.client.MCPsetrate(rate);
286 self.client.MCPreqstatNormal();
288 print "Mode: %s" % self.client.MCPcanstatstr();
289 print "CNF1: %02x" %self.client.peek8(0x2a);
290 print "CNF2: %02x" %self.client.peek8(0x29);
291 print "CNF3: %02x\n" %self.client.peek8(0x28);
294 packet=self.client.rxpacket();
297 if (self.client.peek8(0x2C) & 0x80):
298 self.client.MCPbitmodify(0x2C,0x80,0x00);
299 print "malformed packet recieved: "+ self.client.packet2str(packet);
301 print "properly formatted packet recieved" + self.client.packet2str(packet);
304 def freqtest(self,freq):
306 This method will test the frequency provided to see if it is the correct frequency for this CAN bus.
309 @param freq: The frequency to listen to the CAN bus.
312 self.client.MCPsetup();
314 self.client.MCPsetrate(freq);
315 self.client.MCPreqstatListenOnly();
317 print "CAN Freq Test: %3d kHz" %freq;
322 starttime = time.time();
323 while((time.time()-starttime < args.time)):
324 packet=self.client.rxpacket();
328 if (self.client.peek8(0x2C) & 0x80):
329 print "malformed packet recieved"
331 self.client.MCPbitmodify(0x2C,0x80,0x00);
333 print self.client.packet2str(packet);
335 print "Results for %3.1d kHz: recieved %3d packets, registered %3d RX errors." %(freq, x, errors);
338 def isniff(self,freq):
339 """ An intelligent sniffer, decodes message format """
340 """ More features to be added soon """
342 self.client.MCPsetrate(freq);
343 self.client.MCPreqstatListenOnly();
345 packet=self.client.rxpacket();
354 print "\nArbID: " + self.client.packet2str(arbid);
355 print "EID: " + self.client.packet2str(eid);
356 print "DLC: " + self.client.packet2str(dlc);
357 print "Data: " + self.client.packet2str(data);
360 """ This will perform a test on the GOODTHOPTER10. Diagnostic messages will be printed
364 print "Just reset..."
365 print "EFLG register: %02x" % self.client.peek8(0x2d);
366 print "Tx Errors: %3d" % self.client.peek8(0x1c);
367 print "Rx Errors: %3d" % self.client.peek8(0x1d);
368 print "CANINTF: %02x" %self.client.peek8(0x2C);
369 self.client.MCPreqstatConfiguration();
370 self.client.poke8(0x60,0x66);
371 self.client.MCPsetrate(500);
372 self.client.MCPreqstatNormal();
373 print "In normal mode now"
374 print "EFLG register: %02x" % self.client.peek8(0x2d);
375 print "Tx Errors: %3d" % self.client.peek8(0x1c);
376 print "Rx Errors: %3d" % self.client.peek8(0x1d);
377 print "CANINTF: %02x" %self.client.peek8(0x2C);
378 print "Waiting on packets.";
382 packet=self.client.rxpacket();
384 print "Message recieved: %s" % self.client.packet2str(packet);
386 checkcount=checkcount+1;
387 if (checkcount%30==0):
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);
396 def addFilter(self,standardid, verbose= True):
397 """ This method will configure filters on the board. Filters are positive filters meaning that they will only
398 store messages that match the ids provided in the list of standardid. Since there are 2 buffers and due to the configuration
399 of how the filtering works (see MCP2515 documentation), at least 3 filters must be set to guarentee you do not get any
400 unwanted messages. However even with only 1 filter set you should get all messages from that ID but the other buffer will store
401 any additional messages.
402 @type standardid: list of integers
403 @param standardid: List of standard ids that need to be set. There can be at most 6 filters set.
404 @type verbose: Boolean
405 @param verbose: If true it will print out messages and diagnostics to terminal.
408 @return: This method does not return anything
409 @todo: rename setFilters
412 ### ON-CHIP FILTERING
413 if(standardid != None):
414 self.client.MCPreqstatConfiguration();
415 self.client.poke8(0x60,0x26); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1, BUKT=1)
416 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
417 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
418 if(len(standardid)>2):
419 self.client.poke8(0x70,0x20); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RMX0=1)
420 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
421 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
423 for filter,ID in enumerate(standardid):
444 #### split SID into different regs
445 SIDlow = (ID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
446 SIDhigh = (ID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
449 self.client.poke8(RXFSIDH,SIDhigh);
450 self.client.poke8(RXFSIDL, SIDlow);
452 if (verbose == True):
453 print "Filtering for SID %d (0x%02xh) with filter #%d"%(ID, ID, filter);
455 self.client.MCPreqstatNormal();
457 def filterForPacket(self, standardid, DB0, DB1, verbose= True):
459 This method will configure filters on the board to listen for a specific packet originating
460 from standardid with data bytes 0 and 1. It will configure all six filters, so you will not receive any other packets.
462 @type standardid: integer
463 @param standardid: standardID to listen for
465 @param standardid: DB0 contents to filter for
467 @param standardid: DB1 contents to filter for
468 @type verbose: Boolean
469 @param verbose: If true it will print out messages and diagnostics to terminal.
472 @return: This method does not return anything
475 ### ON-CHIP FILTERING
477 self.client.MCPreqstatConfiguration();
479 # SID filtering: set CTRL registers to only accept standard messages
480 self.client.poke8(0x60,0x06); # set RXB0 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM=1, BUKT=1)
481 self.client.poke8(0x70,0x00); # set RXB1 CTRL register to ONLY accept STANDARD messages with filter match (RXM1=0, RXM0=1)
483 # Mask buffer 0 to match SID, DB0, DB1
484 self.client.poke8(0x20,0xFF); #set buffer 0 mask 1 (SID 10:3) to FF
485 self.client.poke8(0x21,0xE0); #set buffer 0 mask 2 bits 7:5 (SID 2:0) to 1s
486 self.client.poke8(0x22,0xFF); #set buffer 0 mask 3 (DB0) to FF
487 self.client.poke8(0x23,0xFF); #set buffer 0 mask 4 (DB0) to FF
489 # Mask buffer 1 to match SID, DB0, DB1
490 self.client.poke8(0x24,0xFF); #set buffer 1 mask 1 (SID 10:3) to FF
491 self.client.poke8(0x25,0xE0); #set buffer 1 mask 2 bits 7:5 (SID 2:0) to 1s
492 self.client.poke8(0x26,0xFF); #set buffer 1 mask 3 (DB0) to FF
493 self.client.poke8(0x27,0xFF); #set buffer 1 mask 4 (DB1) to FF
495 # Split SID into high and low bytes
496 SIDlow = (standardid & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
497 SIDhigh = (standardid >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
500 for filter in range(0,5):
532 self.client.poke8(RXFSIDH, SIDhigh);
533 self.client.poke8(RXFSIDL, SIDlow);
534 self.client.poke8(RXFDB0, DB0);
535 self.client.poke8(RXFDB1, DB1);
537 if (verbose == True):
538 print "Filtering for SID %d DB0 %d DB1 %d with filter #%d"%(standardid, DB0, DB1, filter);
540 self.client.MCPreqstatNormal();
542 def multiPacketTest(self):
545 self.client.MCPsetrate(500);
546 self.client.MCPreqstatNormal();
548 packet0 = [0x00, 0x00, 0x00,0x00, # pad out EID regs
549 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
550 # lower nibble is DLC
551 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
553 packet1 = [0x00, 0x20, 0x00,0x00, # pad out EID regs
554 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
555 # lower nibble is DLC
556 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
557 packet2 = [0x00, 0x40, 0x00,0x00, # pad out EID regs
558 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
559 # lower nibble is DLC
560 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
562 comm.multiPacketSpit(packet0=packet0, packet1=packet1, packet2=packet2)
564 comm.multiPacketSpit(packet0rts=True, packet1rts=True, packet2rts=True)
565 comm.multiPacketSpit(packet2rts=True)
566 comm.multiPacketSpit(packet1rts=True)
567 comm.multiPacketSpit(packet0rts=True)
571 def multiPacketSpit(self, packet0 = None, packet1 = None, packet2 = None, packet0rts = False, packet1rts = False, packet2rts = False):
573 This method writes packets to the chip's TX buffers and/or sends the contents of the buffers onto the bus.
575 @type packet0: list of integer
576 @param packet0: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF0
578 @type packet1: list of integer
579 @param packet1: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF1
581 @type packet2: list of integer
582 @param packet2: A list of 13 integers of the format [SIDhigh SIDlow 0 0 DLC DB0-7] to be loaded into TXBF2
584 @type packet0rts: Boolean
585 @param packet0rts: If true the message in TX buffer 0 will be sent
587 @type packet2rts: Boolean
588 @param packet0rts: If true the message in TX buffer 1 will be sent
590 @type packet2rts: Boolean
591 @param packet0rts: If true the message in TX buffer 2 will be sent
596 self.client.writetxbuffer(packet0,0)
597 # print("trying to write TX buffer 0");
600 if (packet1 != None):
601 self.client.writetxbuffer(packet1,1)
602 # print("trying to write TX buffer 1");
605 if (packet2 != None):
606 self.client.writetxbuffer(packet2,2)
607 # print("trying to write TX buffer 2");
612 # print("trying to send TX buffer 0")
614 # print("trying to send TX buffer 1")
616 # print("trying to send TX buffer 2")
618 self.client.MCPrts(TXB0=packet0rts, TXB1=packet1rts, TXB2=packet2rts)
621 def spitSetup(self,freq):
623 This method sets up the chip for transmitting messages, but does not transmit anything itself.
626 self.client.MCPsetrate(freq);
627 self.client.MCPreqstatNormal();
630 def spitSingle(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
632 This method will spit a single message onto the bus. If there is no packet information provided then the
633 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
634 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
635 This method will setup the bus and call the spit method, L{spit}. This method includes a bus reset and initialization.
638 @param freq: The frequency of the bus
640 @type standardid: list of integer
641 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
643 @type repeat: Boolean
644 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
646 @type writes: Integer
647 @param writes: Number of writes of the packet
649 @type period: Integer
650 @param period: Time delay between injections of the packet in Milliseconds
653 @param debug: When true debug status messages will be printed to the terminal
656 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
657 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
661 self.spitSetup(freq);
662 spit(self,freq, standardid, repeat,writes, period, debug , packet)
664 def spit(self,freq, standardid, repeat,writes, period = None, debug = False, packet = None):
666 This method will spit a single message onto the bus. If there is no packet information provided then the
667 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
668 a gap of period (milliseconds) between each message. This will continue for the the number of times specified in the writes input.
669 This method does not include bus setup, it must be done before the method call.
673 @param freq: The frequency of the bus
675 @type standardid: list of integer
676 @param standardid: This is a single length list with one integer elment that corresponds to the standard id you wish to write to
678 @type repeat: Boolean
679 @param repeat: If true the message will be repeatedly injected. if not the message will only be injected 1 time
681 @type writes: Integer
682 @param writes: Number of writes of the packet
684 @type period: Integer
685 @param period: Time delay between injections of the packet in Milliseconds
688 @param debug: When true debug status messages will be printed to the terminal
691 @param packet: Contains the data bytes for the packet which is assumed to be of length 8. Each byte is stored as
692 an integer and can range from 0 to 255 (8 bits). If packet == None then an RTR will be sent on the given
697 #### split SID into different regs
698 SIDlow = (standardid[0] & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
699 SIDhigh = (standardid[0] >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
703 # if no packet, RTR for inputted arbID
704 # so packet to transmit is SID + padding out EID registers + RTR request (set bit 6, clear lower nibble of DLC register)
705 packet = [SIDhigh, SIDlow, 0x00,0x00,0x40]
710 # if we do have a packet, packet is SID + padding out EID registers + DLC of 8 + packet
712 """@todo: allow for variable-length packets"""
713 # TODO: allow for variable-length packets
715 packet = [SIDhigh, SIDlow, 0x00,0x00, # pad out EID regs
716 0x08, # bit 6 must be set to 0 for data frame (1 for RTR)
717 # lower nibble is DLC
718 packet[0],packet[1],packet[2],packet[3],packet[4],packet[5],packet[6],packet[7]]
722 if self.client.MCPcanstat()>>5!=0:
723 print "Warning: currently in %s mode. NOT in normal mode! May not transmit.\n" %self.client.MCPcanstatstr();
724 print "\nInitial state:"
725 print "Tx Errors: %3d" % self.client.peek8(0x1c);
726 print "Rx Errors: %3d" % self.client.peek8(0x1d);
727 print "Error Flags: %02x\n" % self.client.peek8(0x2d);
728 print "TXB0CTRL: %02x" %self.client.peek8(0x30);
729 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
730 print "\n\nATTEMPTING TRANSMISSION!!!"
732 print "Transmitting packet: "
733 #print self.client.packet2str(packet)
735 self.client.txpacket(packet);
738 """@todo: the repeat variable is no longer needed and can be removed """
739 print "\nNow looping on transmit. "
741 for i in range(0,writes):
742 self.client.MCPrts(TXB0=True);
744 time.sleep(period/1000) # pause for period ms before sending again
745 #print time.time()-tic
746 #starttime = time.time();
747 #while((time.time()-starttime < duration)):
748 # self.client.MCPrts(TXB0=True);
749 # print "MSG printed"
751 for i in range(0,writes):
752 self.client.MCPrts(TXB0=True);
753 print "messages injected"
758 TXB0CTRL = self.client.peek8(0x30);
760 print "Tx Errors: %3d" % self.client.peek8(0x1c);
761 print "Rx Errors: %3d" % self.client.peek8(0x1d);
762 print "EFLG register: %02x" % self.client.peek8(0x2d);
763 print "TXB0CTRL: %02x" %TXB0CTRL;
764 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
766 while(TXB0CTRL | 0x00 != 0x00):
768 TXB0CTRL = self.client.peek8(0x30);
769 if (checkcount %30 ==0):
770 print "Tx Errors: %3d" % self.client.peek8(0x1c);
771 print "Rx Errors: %3d" % self.client.peek8(0x1d);
772 print "EFLG register: %02x" % self.client.peek8(0x2d);
773 print "TXB0CTRL: %02x" %TXB0CTRL;
774 print "CANINTF: %02x\n" %self.client.peek8(0x2C);
777 def setRate(self,freq):
779 This method will reset the frequency that the MCP2515 expects the CAN bus to be on.
782 @param freq: Frequency of the CAN bus
784 self.client.MCPsetrate(freq);
788 # This will write the data provided in the packets which is expected to be a list of lists
789 # of the following form:
790 # for a given row = packets[i]
791 # row[0] time delay relative to the last packet. if 0 or empty there will be no delay
792 # row[1] = Standard ID (integer)
793 # row[2] = Data Length (0-8) (if it is zero we assume an Remote Transmit Request)
794 # row[3] = Data Byte 0
795 # row[4] = Data Byte 1
796 # .... up to Data Byte 8 ( THIS ASSUMES A PACKET OF LENGTH 8!!!
797 def writeData(self,packets,freq):
798 self.client.serInit()
801 if( row[0] != 0 and row[0] != ""):
804 #### split SID into different regs
805 SIDlow = (sID & 0x07) << 5; # get SID bits 2:0, rotate them to bits 7:5
806 SIDhigh = (sID >> 3) & 0xFF; # get SID bits 10:3, rotate them to bits 7:0
807 packet = [SIDhigh,SIDlow,0x00,0x00,0x08]
810 for i in range(3,dlc+3):
811 packet.append(row[i])
813 self.client.txpacket(packet)
819 if __name__ == "__main__":
821 parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,description='''\
823 Run commands on the MCP2515. Valid commands are:
827 peek 0x(start) [0x(stop)]
837 parser.add_argument('verb', choices=['info', 'test','peek', 'reset', 'sniff', 'freqtest','snifftest', 'spit', 'packet', 'multipacket']);
838 parser.add_argument('-f', '--freq', type=int, default=500, help='The desired frequency (kHz)', choices=[100, 125, 250, 500, 1000]);
839 parser.add_argument('-t','--time', type=int, default=15, help='The duration to run the command (s)');
840 parser.add_argument('-o', '--output', default=None,help='Output file');
841 parser.add_argument("-d", "--description", help='Description of experiment (included in the output file)', default="");
842 parser.add_argument('-v',"--verbose",action='store_false',help='-v will stop packet output to terminal', default=True);
843 parser.add_argument('-c','--comment', help='Comment attached to ech packet uploaded',default=None);
844 parser.add_argument('-b', '--debug', action='store_true', help='-b will turn on debug mode, printing packet status', default=False);
845 parser.add_argument('-a', '--standardid', type=int, action='append', help='Standard ID to accept with filter 0 [1, 2, 3, 4, 5]', default=None);
846 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);
847 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);
848 parser.add_argument('-db0', '--databyte0', type=int, default = None, help='-db0 to filter for a specfic data byte');
849 parser.add_argument('-db1', '--databyte1', type=int, default = None, help='-db0 to filter for a specfic data byte');
853 args = parser.parse_args();
856 filename = args.output
857 description = args.description
858 verbose = args.verbose
859 comments = args.comment
861 standardid = args.standardid
867 comm = GoodFETMCPCANCommunication("./");
869 if(args.verb=="packet"):
870 comm.filterForPacket(standardid=standardid[0], DB0=db0, DB1=db1, verbose= True)
871 if(args.verb=="multipacket"):
872 comm.multiPacketTest();
874 ##########################
876 ##########################
878 # Prints MCP state info
880 if(args.verb=="info"):
884 ##########################
886 ##########################
890 if(args.verb=="reset"):
893 ##########################
895 ##########################
897 # runs in ListenOnly mode
898 # utility function to pull info off the car's CAN bus
901 if(args.verb=="sniff"):
902 comm.sniff(freq=freq,duration=duration,description=description,verbose=verbose,comment=comments,filename=filename, standardid=standardid, debug=debug, faster=faster, db0=db0, db1=db1)
904 ##########################
906 ##########################
908 # runs in NORMAL mode
909 # intended for NETWORKED MCP chips to verify proper operation
912 if(args.verb=="snifftest"):
913 comm.sniffTest(freq=freq)
916 ##########################
918 ##########################
920 # runs in LISTEN ONLY mode
921 # tests bus for desired frequency --> sniffs bus for specified length of time and reports
922 # if packets were properly formatted
926 if(args.verb=="freqtest"):
927 comm.freqtest(freq=freq)
931 ##########################
933 ##########################
935 # """ An intelligent sniffer, decodes message format """
936 # """ More features to be added soon """
937 if(args.verb=="isniff"):
938 comm.isniff(freq=freq)
941 ##########################
943 ##########################
945 # Runs in LOOPBACK mode
946 # self-check diagnostic
947 # wasn't working before due to improperly formatted packet
949 # ...add automatic packet check rather than making user verify successful packet
950 if(args.verb=="test"):
953 if(args.verb=="peek"):
956 start=int(sys.argv[2],16);
959 stop=int(sys.argv[3],16);
960 print "Peeking from %04x to %04x." % (start,stop);
962 print "%04x: %02x" % (start,client.peek8(start));
965 ##########################
967 ##########################
969 # Basic packet transmission
970 # runs in NORMAL MODE!
972 # checking TX error flags--> currently throwing error flags on every
973 # transmission (travis thinks this is because we're sniffing in listen-only
974 # and thus not generating an ack bit on the recieving board)
975 if(args.verb=="spit"):
976 comm.spitSingle(freq=freq, standardid=standardid,duration=duration, repeat=repeat, debug=debug)