From bf75ea916cc9ce3cf5ebb2d8f80b128f345caa71 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 15:26:31 -0700 Subject: [PATCH 01/11] Add requirements.txt Install dependencies with `pip install -r requirements.txt` --- requirements.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5019a60 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +caneton==1.12.0 +certifi==2018.8.24 +dpkt==1.9.1 From 91d75f7b0f0337c41dfea8a2aa6ee4f1436e4cf0 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 15:37:19 -0700 Subject: [PATCH 02/11] Add argparse and __main__ block to chargeparse.py --- charger/chargeparse.py | 57 ++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 2ea975c..805d5c9 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # based on cantldr.py by jerkey # opens ks_can2serial canbus logs generated by https://github.com/jerkey/ks_can/blob/teslalog/ks_can2serial.ino -inFile = open('/tmp/can2serial.txt') + RESET = '\033[0m' # https://misc.flogisoft.com/bash/tip_colors_and_formatting GREEN = '\033[32m' RED = '\033[31m' @@ -54,28 +54,35 @@ def parseCan(id,data): message = data return message -for line in inFile: # '268:00000000B3000000 16\n' is what a line looks like - if line.find('CAN')!=0: # swallow the init lines from ks_can2serial.ino - id = int(line.split(':')[0],16) - if id in ids: # we ignore CAN IDs not in our list - idIndex = ids.index(id) - parsedLine = parseCan(id,line.split(' ')[0][4:20]) - if lastMsg[idIndex] != parsedLine: # ignore messages that haven't changed since we last saw them - print(str(id)+'\t',end='') - # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) - for i in range(len(parsedLine)): # print character by character, colored according to same or changed - if lastMsg[idIndex].ljust(len(parsedLine))[i]==parsedLine[i]: - print(RESET+parsedLine[i],end='') - else: - print(RED+parsedLine[i],end='') - for i in range(len(parsedLine),128): # pad data with spaces - print(' ',end='') - linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log - mins = int(linetime / (1000*60)) - secs = linetime % 60000 / 1000 - lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time - print('\t'+YELLOW+str(mins).zfill(3)+':',end='') # print the number of minutes: - if secs < 10: - print('0',end='') - print(str(secs)+RESET) # print the number of seconds (a float) and ANSI RESET +def main(data): + for line in data: # '268:00000000B3000000 16\n' is what a line looks like + if line.find('CAN')!=0: # swallow the init lines from ks_can2serial.ino + id = int(line.split(':')[0],16) + if id in ids: # we ignore CAN IDs not in our list + idIndex = ids.index(id) + parsedLine = parseCan(id,line.split(' ')[0][4:20]) + if lastMsg[idIndex] != parsedLine: # ignore messages that haven't changed since we last saw them + print(str(id)+'\t',end='') + # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) + for i in range(len(parsedLine)): # print character by character, colored according to same or changed + if lastMsg[idIndex].ljust(len(parsedLine))[i]==parsedLine[i]: + print(RESET+parsedLine[i],end='') + else: + print(RED+parsedLine[i],end='') + for i in range(len(parsedLine),128): # pad data with spaces + print(' ',end='') + linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log + mins = int(linetime / (1000*60)) + secs = linetime % 60000 / 1000 + lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time + print('\t'+YELLOW+str(mins).zfill(3)+':',end='') # print the number of minutes: + if secs < 10: + print('0',end='') + print(str(secs)+RESET) # print the number of seconds (a float) and ANSI RESET +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('CANdata', type=argparse.FileType('r')) + data = parser.parse_args().CANdata + main(data) From af93a7779ff73ca4ce5cfd1e7428cdb283fe0eaa Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 15:43:02 -0700 Subject: [PATCH 03/11] Bring globals into main() for now --- charger/chargeparse.py | 1 + 1 file changed, 1 insertion(+) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 805d5c9..cdb04c0 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -55,6 +55,7 @@ def parseCan(id,data): return message def main(data): + global lastMsg, ids for line in data: # '268:00000000B3000000 16\n' is what a line looks like if line.find('CAN')!=0: # swallow the init lines from ks_can2serial.ino id = int(line.split(':')[0],16) From 52af81806fd2797fd4858e6019003931b6aeebaa Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 15:46:15 -0700 Subject: [PATCH 04/11] Flatten main in chargeparse.py --- charger/chargeparse.py | 54 ++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index cdb04c0..86aa7e1 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -57,29 +57,37 @@ def parseCan(id,data): def main(data): global lastMsg, ids for line in data: # '268:00000000B3000000 16\n' is what a line looks like - if line.find('CAN')!=0: # swallow the init lines from ks_can2serial.ino - id = int(line.split(':')[0],16) - if id in ids: # we ignore CAN IDs not in our list - idIndex = ids.index(id) - parsedLine = parseCan(id,line.split(' ')[0][4:20]) - if lastMsg[idIndex] != parsedLine: # ignore messages that haven't changed since we last saw them - print(str(id)+'\t',end='') - # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) - for i in range(len(parsedLine)): # print character by character, colored according to same or changed - if lastMsg[idIndex].ljust(len(parsedLine))[i]==parsedLine[i]: - print(RESET+parsedLine[i],end='') - else: - print(RED+parsedLine[i],end='') - for i in range(len(parsedLine),128): # pad data with spaces - print(' ',end='') - linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log - mins = int(linetime / (1000*60)) - secs = linetime % 60000 / 1000 - lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time - print('\t'+YELLOW+str(mins).zfill(3)+':',end='') # print the number of minutes: - if secs < 10: - print('0',end='') - print(str(secs)+RESET) # print the number of seconds (a float) and ANSI RESET + if line.find('CAN') == 0: + # swallow the init lines from ks_can2serial.ino + continue + id = int(line.split(':')[0],16) + if id not in ids: + # we ignore CAN IDs not in our list + continue + idIndex = ids.index(id) + parsedLine = parseCan(id,line.split(' ')[0][4:20]) + if lastMsg[idIndex] == parsedLine: + # ignore messages that haven't changed since we last saw them + continue + print(str(id)+'\t',end='') + # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) + for i in range(len(parsedLine)): + # print character by character, colored according to same or changed + if lastMsg[idIndex].ljust(len(parsedLine))[i]==parsedLine[i]: + print(RESET+parsedLine[i],end='') + else: + print(RED+parsedLine[i],end='') + for i in range(len(parsedLine),128): + # pad data with spaces + print(' ',end='') + linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log + mins = int(linetime / (1000*60)) + secs = linetime % 60000 / 1000 + lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time + print('\t'+YELLOW+str(mins).zfill(3)+':',end='') # print the number of minutes: + if secs < 10: + print('0',end='') + print(str(secs)+RESET) # print the number of seconds (a float) and ANSI RESET if __name__ == '__main__': import argparse From 611bd1638a84b5999adbaefe9ded9ca4c3181e3c Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:01:01 -0700 Subject: [PATCH 05/11] chargeparse: little things in main() --- charger/chargeparse.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 86aa7e1..092bf91 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -60,34 +60,35 @@ def main(data): if line.find('CAN') == 0: # swallow the init lines from ks_can2serial.ino continue - id = int(line.split(':')[0],16) + id = int(line.split(':')[0], 16) if id not in ids: # we ignore CAN IDs not in our list continue idIndex = ids.index(id) - parsedLine = parseCan(id,line.split(' ')[0][4:20]) + #parsedLine = parseCan(id, line.split(' ')[0][4:20]) + parsedLine = parseCan(id, line[4:20]) if lastMsg[idIndex] == parsedLine: # ignore messages that haven't changed since we last saw them continue - print(str(id)+'\t',end='') + print(str(id) + '\t', end='') # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) - for i in range(len(parsedLine)): + for i,c in enumerate(parsedLine): # print character by character, colored according to same or changed - if lastMsg[idIndex].ljust(len(parsedLine))[i]==parsedLine[i]: - print(RESET+parsedLine[i],end='') + if lastMsg[idIndex].ljust(len(parsedLine))[i] == c: + print(RESET + c, end='') else: - print(RED+parsedLine[i],end='') + print(RED + c, end='') for i in range(len(parsedLine),128): # pad data with spaces - print(' ',end='') + print(' ', end='') linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log mins = int(linetime / (1000*60)) secs = linetime % 60000 / 1000 lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time - print('\t'+YELLOW+str(mins).zfill(3)+':',end='') # print the number of minutes: + print('\t' + YELLOW + str(mins).zfill(3) + ':', end='') # print the number of minutes: if secs < 10: - print('0',end='') - print(str(secs)+RESET) # print the number of seconds (a float) and ANSI RESET + print('0', end='') + print(str(secs) + RESET) # print the number of seconds (a float) and ANSI RESET if __name__ == '__main__': import argparse From faf62c3025560bc7d86cc5dae81f6afa9a262b3d Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:05:08 -0700 Subject: [PATCH 06/11] chargeparse: parseCAN uses fewer globals --- charger/chargeparse.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 092bf91..3f172fc 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -11,8 +11,8 @@ lastMsg = [' '] * len(ids) # empty so it's not too short to compare with CHGPH1_vBat = 0.0 # in case we want to tag this data onto some other ID for reference -def parseCan(id,data): - global CHGPH1_vBat, ids, lastMsg +def parseCan(id, data, previousMsg): + global CHGPH1_vBat if id==530: BMS_contactorState = int(data[5],16) # lower 4 bits of third byte BMS_state = int(data[4],16) # high 4 bits of third byte @@ -34,7 +34,7 @@ def parseCan(id,data): elif id==770: BMS_socMin = (int(data[3]+data[0:2],16) & 1023) * 0.1 # "BMS State Of Charge (SOC). This is the minimum displayed brick SOC. This is NOT cell SOC" message = ('BMS_socMin:%.0f' % BMS_socMin)+'%'+' CHGPH1_vBat:%.0f' % CHGPH1_vBat - message = lastMsg[ids.index(id)] # a hack to prevent printing anything + message = previousMsg # a hack to prevent printing anything elif id==924: # didn't see this at all in the 2018-4-9 capture CC_currentLimit_PT = int(data[0:2],16) * 0.5 # "A" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" CC_pilotState_PT = int(data[3],16) & 3 #: 8|2@1+ (1,0) [0|3] "" CHG,GTW @@ -49,7 +49,7 @@ def parseCan(id,data): message += ' BMS_fcContactorPwrIsOn:'+str(int(data[6:8],16) & 16) #: 28|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "This bit indicates if the BMShas powered the FC Contactor Power line which is used by the charger to diagnose its h/w" elif id==551: CHGPH1_vBat = int(data[6:8]+data[4:6],16) * 0.010528564 #: 16|16@1+ (0.010528564,0) [0|690] "V" CHGVI BO_ 551 CHGPH1_HVStatus: 8 CHGPH1 - message = lastMsg[ids.index(id)] # a hack to prevent printing anything + message = previousMsg # a hack to prevent printing anything else: message = data return message @@ -66,15 +66,16 @@ def main(data): continue idIndex = ids.index(id) #parsedLine = parseCan(id, line.split(' ')[0][4:20]) - parsedLine = parseCan(id, line[4:20]) - if lastMsg[idIndex] == parsedLine: + previous = lastMsg[idIndex] + parsedLine = parseCan(id, line[4:20], previous) + if previous == parsedLine: # ignore messages that haven't changed since we last saw them continue print(str(id) + '\t', end='') - # print(parsedLine+';'+str(len(lastMsg[idIndex]))+':'+str(len(parsedLine))) + # print(parsedLine+';'+str(len(previous))+':'+str(len(parsedLine))) for i,c in enumerate(parsedLine): # print character by character, colored according to same or changed - if lastMsg[idIndex].ljust(len(parsedLine))[i] == c: + if previous.ljust(len(parsedLine))[i] == c: print(RESET + c, end='') else: print(RED + c, end='') From 83b5b3952dd909221e4fdd1577a5c74a46d15ad7 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:13:44 -0700 Subject: [PATCH 07/11] chargeparse: overhaul message change tracking - ids and lastMsg lists merged into msgs dict - no more globals in main --- charger/chargeparse.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 3f172fc..f99eef8 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -7,8 +7,6 @@ RED = '\033[31m' YELLOW = '\033[33m' -ids = [530,546,770,924,930,551] # list of CAN IDs we care about -lastMsg = [' '] * len(ids) # empty so it's not too short to compare with CHGPH1_vBat = 0.0 # in case we want to tag this data onto some other ID for reference def parseCan(id, data, previousMsg): @@ -55,18 +53,21 @@ def parseCan(id, data, previousMsg): return message def main(data): - global lastMsg, ids + msgs = {} + for i in [530,546,770,924,930,551]: # list of CAN IDs we care about + # Empty so it's not too short to compare with. Using historical size from string literal. + msgs[i] = ' ' * 239 + for line in data: # '268:00000000B3000000 16\n' is what a line looks like if line.find('CAN') == 0: # swallow the init lines from ks_can2serial.ino continue id = int(line.split(':')[0], 16) - if id not in ids: + if id not in msgs.keys(): # we ignore CAN IDs not in our list continue - idIndex = ids.index(id) #parsedLine = parseCan(id, line.split(' ')[0][4:20]) - previous = lastMsg[idIndex] + previous = msgs[id] parsedLine = parseCan(id, line[4:20], previous) if previous == parsedLine: # ignore messages that haven't changed since we last saw them @@ -85,7 +86,7 @@ def main(data): linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log mins = int(linetime / (1000*60)) secs = linetime % 60000 / 1000 - lastMsg[idIndex] = parsedLine # store the latest line to compare with for next time + msgs[id] = parsedLine # store the latest line to compare with for next time print('\t' + YELLOW + str(mins).zfill(3) + ':', end='') # print the number of minutes: if secs < 10: print('0', end='') From 95ff160ab33b80079f09fc3561aeb4ea3de43485 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:18:16 -0700 Subject: [PATCH 08/11] chargeparse: only justify once --- charger/chargeparse.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index f99eef8..64ab709 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -74,9 +74,10 @@ def main(data): continue print(str(id) + '\t', end='') # print(parsedLine+';'+str(len(previous))+':'+str(len(parsedLine))) + previous_justified = previous.ljust(len(parsedLine)) for i,c in enumerate(parsedLine): # print character by character, colored according to same or changed - if previous.ljust(len(parsedLine))[i] == c: + if previous_justified[i] == c: print(RESET + c, end='') else: print(RED + c, end='') From ab80739fda9e6506173c2b15911e44b88c269121 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:22:45 -0700 Subject: [PATCH 09/11] chargeparse: can_id instead of just id No longer shadowing id() --- charger/chargeparse.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 64ab709..7e9e243 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -9,15 +9,15 @@ CHGPH1_vBat = 0.0 # in case we want to tag this data onto some other ID for reference -def parseCan(id, data, previousMsg): +def parseCan(can_id, data, previousMsg): global CHGPH1_vBat - if id==530: + if can_id==530: BMS_contactorState = int(data[5],16) # lower 4 bits of third byte BMS_state = int(data[4],16) # high 4 bits of third byte BMS_contactorStateText = {6:"BMS_CTRSET_CLEANING",5:"BMS_CTRSET_WELD",4:"BMS_CTRSET_SNA",3:"BMS_CTRSET_OPENING",2:"BMS_CTRSET_CLOSED",1:"BMS_CTRSET_PRECHARGE",0:"BMS_CTRSET_OPEN"} BMS_stateText = {15:"BMS_SNA",8:"BMS_WELD",7:"BMS_FAULT",6:"BMS_CLEARFAULT",5:"BMS_CHARGERVOLTAGE",4:"BMS_FASTCHARGE",3:"BMS_CHARGER",2:"BMS_SUPPORT",1:"BMS_DRIVE",0:"BMS_STANDBY"} message = 'BMS_contactorState:'+BMS_contactorStateText.get(BMS_contactorState,' ').ljust(20) + ' BMS_state:' + BMS_stateText.get(BMS_state,' ').ljust(18) - elif id==546: + elif can_id==546: BMS_chargeCommand = int(data[2:4]+data[0:2],16) * 0.001 #: 0|16@1+ (0.001,0) [0|40] "kW" CHG "BMS Commanded AC power"; BMS_chargeVoltageLimit = int(data[6:8]+data[4:6],16) * 0.01 #: 16|16@1+ (0.01,0) [0|600] "V" CHG "BMS Pack voltage limit"; BMS_chargeLineCurrentLimit = int(data[11]+data[8:10],16) % 512 * 0.16666 #: 32|9@1+ (0.16666,0) [0|85.16] "A" CHG "BMS Line current limit"; @@ -29,23 +29,23 @@ def parseCan(id, data, previousMsg): message += ' BMS_chgVLimitMode' if int(data[10],16) & 1 else ''# : 44|1@1+ (1,0) [0|0] 16 "" CHG "Tells the charger to either follow the BMS_chargeLimit or to track the pack voltage to prevent current spikes"; #BMS_chargeFC_statusCode : 48|4@1+ (1,0) [0|0] "" CHG 15 "PT_FC_STATUS_NODATA" 14 "PT_FC_STATUS_MALFUNCTION" 13 "PT_FC_STATUS_NOTCOMPATIBLE" 6 "PT_FC_STATUS_EXT_ISOACTIVE" 5 "PT_FC_STATUS_INT_ISOACTIVE" 4 "PT_FC_STATUS_UTILITY" 3 "PT_FC_STATUS_SHUTDOWN" 2 "PT_FC_STATUS_PRELIMITEXCEEDED" 1 "PT_FC_STATUS_READY" 0 "PT_FC_STATUS_NOTREADY_SNA" ; #BMS_chargeFC_type : 52|3@1+ (1,0) [0|7] "" GTW,CHG 7 "PT_FC_TYPE_SNA" 6 "PT_FC_TYPE_OTHER" 3 "PT_FC_TYPE_CC_EVSE" 2 "PT_FC_TYPE_CHINAMO" 1 "PT_FC_TYPE_CHADEMO" 0 "PT_FC_TYPE_SUPERCHARGER" ; - elif id==770: + elif can_id==770: BMS_socMin = (int(data[3]+data[0:2],16) & 1023) * 0.1 # "BMS State Of Charge (SOC). This is the minimum displayed brick SOC. This is NOT cell SOC" message = ('BMS_socMin:%.0f' % BMS_socMin)+'%'+' CHGPH1_vBat:%.0f' % CHGPH1_vBat message = previousMsg # a hack to prevent printing anything - elif id==924: # didn't see this at all in the 2018-4-9 capture + elif can_id==924: # didn't see this at all in the 2018-4-9 capture CC_currentLimit_PT = int(data[0:2],16) * 0.5 # "A" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" CC_pilotState_PT = int(data[3],16) & 3 #: 8|2@1+ (1,0) [0|3] "" CHG,GTW CC_pilotState_PTText = {3:"PT_CC_PILOT_STATE_SNA",2:"PT_CC_PILOT_STATE_FAULTED",1:"PT_CC_PILOT_STATE_IDLE",0:"PT_CC_PILOT_STATE_READY"} CC_numPhases_PT = int(data[3],16) >> 2 #: 10|2@1+ (1,0) [0|3] "" CHG,GTW CC_lineVoltage_PT = int(data[7]+data[4:6],16) & 511 #: 16|9@1+ (1,0) [0|510] "V" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" message = ('CC_currentLimit_PT:%.0f' % CC_currentLimit_PT)+' CC_pilotState_PT:'+CC_pilotState_PTText.get(CC_pilotState_PT,' ').ljust(25) - elif id==930: + elif can_id==930: message = 'BMS_fullChargeComplete:'+str(int(data[2],16) & 1) #: 12|1@1+ (1,0) [0|0] "" CP,GTW "This bit indicates if the BMS is fully charged" message += ' BMS_fastChargerPresent:'+str(int(data[2],16) & 4) #: 14|1@1+ (1,0) [0|0] "" CP,GTW "TRUE when the fast charger Status Message has been received within the last 1 second" message += ' BMS_fcContactorCloseRequest:'+str(int(data[2],16) & 8) #: 15|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "1 if the charger should close the FC contactors" message += ' BMS_fcContactorPwrIsOn:'+str(int(data[6:8],16) & 16) #: 28|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "This bit indicates if the BMShas powered the FC Contactor Power line which is used by the charger to diagnose its h/w" - elif id==551: + elif can_id==551: CHGPH1_vBat = int(data[6:8]+data[4:6],16) * 0.010528564 #: 16|16@1+ (0.010528564,0) [0|690] "V" CHGVI BO_ 551 CHGPH1_HVStatus: 8 CHGPH1 message = previousMsg # a hack to prevent printing anything else: @@ -62,17 +62,17 @@ def main(data): if line.find('CAN') == 0: # swallow the init lines from ks_can2serial.ino continue - id = int(line.split(':')[0], 16) - if id not in msgs.keys(): + can_id = int(line.split(':')[0], 16) + if can_id not in msgs.keys(): # we ignore CAN IDs not in our list continue - #parsedLine = parseCan(id, line.split(' ')[0][4:20]) - previous = msgs[id] - parsedLine = parseCan(id, line[4:20], previous) + #parsedLine = parseCan(can_id, line.split(' ')[0][4:20]) + previous = msgs[can_id] + parsedLine = parseCan(can_id, line[4:20], previous) if previous == parsedLine: # ignore messages that haven't changed since we last saw them continue - print(str(id) + '\t', end='') + print(str(can_id) + '\t', end='') # print(parsedLine+';'+str(len(previous))+':'+str(len(parsedLine))) previous_justified = previous.ljust(len(parsedLine)) for i,c in enumerate(parsedLine): @@ -87,7 +87,7 @@ def main(data): linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log mins = int(linetime / (1000*60)) secs = linetime % 60000 / 1000 - msgs[id] = parsedLine # store the latest line to compare with for next time + msgs[can_id] = parsedLine # store the latest line to compare with for next time print('\t' + YELLOW + str(mins).zfill(3) + ':', end='') # print the number of minutes: if secs < 10: print('0', end='') From 2c432eba51dd1e9ea653b84a31abe11d4cee3396 Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:45:07 -0700 Subject: [PATCH 10/11] chargeparse: tidy up print calls --- charger/chargeparse.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 7e9e243..65853de 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -72,8 +72,10 @@ def main(data): if previous == parsedLine: # ignore messages that haven't changed since we last saw them continue + print(str(can_id) + '\t', end='') # print(parsedLine+';'+str(len(previous))+':'+str(len(parsedLine))) + previous_justified = previous.ljust(len(parsedLine)) for i,c in enumerate(parsedLine): # print character by character, colored according to same or changed @@ -81,17 +83,17 @@ def main(data): print(RESET + c, end='') else: print(RED + c, end='') - for i in range(len(parsedLine),128): - # pad data with spaces - print(' ', end='') + + pad = ' ' * (128 - len(parsedLine)) + print(pad, end='') + + msgs[can_id] = parsedLine # store the latest line to compare with for next time linetime = int(line[:-1].split(' ')[1]) # get the time in milliseconds from the log mins = int(linetime / (1000*60)) secs = linetime % 60000 / 1000 - msgs[can_id] = parsedLine # store the latest line to compare with for next time - print('\t' + YELLOW + str(mins).zfill(3) + ':', end='') # print the number of minutes: - if secs < 10: - print('0', end='') - print(str(secs) + RESET) # print the number of seconds (a float) and ANSI RESET + minutes, seconds = str(mins).zfill(3), str(secs) + seconds = '0' + seconds if secs < 10 else seconds + print('\t' + YELLOW + minutes + ':' + seconds + RESET) if __name__ == '__main__': import argparse From 028947dfc7460b897870e8c79d9dfe7f3aa2904c Mon Sep 17 00:00:00 2001 From: eenblam Date: Fri, 7 Sep 2018 16:50:21 -0700 Subject: [PATCH 11/11] Move long comments to separate lines --- charger/chargeparse.py | 51 ++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/charger/chargeparse.py b/charger/chargeparse.py index 65853de..2ca6333 100755 --- a/charger/chargeparse.py +++ b/charger/chargeparse.py @@ -18,35 +18,52 @@ def parseCan(can_id, data, previousMsg): BMS_stateText = {15:"BMS_SNA",8:"BMS_WELD",7:"BMS_FAULT",6:"BMS_CLEARFAULT",5:"BMS_CHARGERVOLTAGE",4:"BMS_FASTCHARGE",3:"BMS_CHARGER",2:"BMS_SUPPORT",1:"BMS_DRIVE",0:"BMS_STANDBY"} message = 'BMS_contactorState:'+BMS_contactorStateText.get(BMS_contactorState,' ').ljust(20) + ' BMS_state:' + BMS_stateText.get(BMS_state,' ').ljust(18) elif can_id==546: - BMS_chargeCommand = int(data[2:4]+data[0:2],16) * 0.001 #: 0|16@1+ (0.001,0) [0|40] "kW" CHG "BMS Commanded AC power"; - BMS_chargeVoltageLimit = int(data[6:8]+data[4:6],16) * 0.01 #: 16|16@1+ (0.01,0) [0|600] "V" CHG "BMS Pack voltage limit"; - BMS_chargeLineCurrentLimit = int(data[11]+data[8:10],16) % 512 * 0.16666 #: 32|9@1+ (0.16666,0) [0|85.16] "A" CHG "BMS Line current limit"; + #: 0|16@1+ (0.001,0) [0|40] "kW" CHG "BMS Commanded AC power"; + BMS_chargeCommand = int(data[2:4]+data[0:2],16) * 0.001 + #: 16|16@1+ (0.01,0) [0|600] "V" CHG "BMS Pack voltage limit"; + BMS_chargeVoltageLimit = int(data[6:8]+data[4:6],16) * 0.01 + #: 32|9@1+ (0.16666,0) [0|85.16] "A" CHG "BMS Line current limit"; + BMS_chargeLineCurrentLimit = int(data[11]+data[8:10],16) % 512 * 0.16666 message = 'BMS_chargeCommand:'+('%.0f' % BMS_chargeCommand).rjust(2)+'kW BMS_chargeVoltageLimit:'+('%.0f' % BMS_chargeVoltageLimit).rjust(3)+'V BMS_chargeLineCurrentLimit:'+('%.0f' % BMS_chargeLineCurrentLimit).rjust(2)+'A '+data[10:12] - BMS_chargeEnable = (int(data[10],16) & 6) >> 1 #: 45|2@1+ (1,0) [0|0] 32 "" CP,CHG "BMS Charge Enable"; + #: 45|2@1+ (1,0) [0|0] 32 "" CP,CHG "BMS Charge Enable"; + BMS_chargeEnable = (int(data[10],16) & 6) >> 1 message += ' BMS_chargeEnable:'+str(BMS_chargeEnable) - message += ' BMS_chargeClearFaults' if int(data[11],16) & 4 else ''# : 42|1@1+ (1,0) [0|0] aka 4 "" CHG "BMS Clear Faults"; - message += ' BMS_fcRequest' if int(data[11],16) & 8 else ''#: 43|1@1+ (1,0) [0|0] 8 "" CP,CHG "The BMS requests the charger to enable the FC sequence and turn on the BMS FC CAN Relay."; - message += ' BMS_chgVLimitMode' if int(data[10],16) & 1 else ''# : 44|1@1+ (1,0) [0|0] 16 "" CHG "Tells the charger to either follow the BMS_chargeLimit or to track the pack voltage to prevent current spikes"; + # : 42|1@1+ (1,0) [0|0] aka 4 "" CHG "BMS Clear Faults"; + message += ' BMS_chargeClearFaults' if int(data[11],16) & 4 else '' + #: 43|1@1+ (1,0) [0|0] 8 "" CP,CHG "The BMS requests the charger to enable the FC sequence and turn on the BMS FC CAN Relay."; + message += ' BMS_fcRequest' if int(data[11],16) & 8 else '' + # : 44|1@1+ (1,0) [0|0] 16 "" CHG "Tells the charger to either follow the BMS_chargeLimit or to track the pack voltage to prevent current spikes"; + message += ' BMS_chgVLimitMode' if int(data[10],16) & 1 else '' #BMS_chargeFC_statusCode : 48|4@1+ (1,0) [0|0] "" CHG 15 "PT_FC_STATUS_NODATA" 14 "PT_FC_STATUS_MALFUNCTION" 13 "PT_FC_STATUS_NOTCOMPATIBLE" 6 "PT_FC_STATUS_EXT_ISOACTIVE" 5 "PT_FC_STATUS_INT_ISOACTIVE" 4 "PT_FC_STATUS_UTILITY" 3 "PT_FC_STATUS_SHUTDOWN" 2 "PT_FC_STATUS_PRELIMITEXCEEDED" 1 "PT_FC_STATUS_READY" 0 "PT_FC_STATUS_NOTREADY_SNA" ; #BMS_chargeFC_type : 52|3@1+ (1,0) [0|7] "" GTW,CHG 7 "PT_FC_TYPE_SNA" 6 "PT_FC_TYPE_OTHER" 3 "PT_FC_TYPE_CC_EVSE" 2 "PT_FC_TYPE_CHINAMO" 1 "PT_FC_TYPE_CHADEMO" 0 "PT_FC_TYPE_SUPERCHARGER" ; elif can_id==770: - BMS_socMin = (int(data[3]+data[0:2],16) & 1023) * 0.1 # "BMS State Of Charge (SOC). This is the minimum displayed brick SOC. This is NOT cell SOC" + # "BMS State Of Charge (SOC). This is the minimum displayed brick SOC. This is NOT cell SOC" + BMS_socMin = (int(data[3]+data[0:2],16) & 1023) * 0.1 message = ('BMS_socMin:%.0f' % BMS_socMin)+'%'+' CHGPH1_vBat:%.0f' % CHGPH1_vBat message = previousMsg # a hack to prevent printing anything elif can_id==924: # didn't see this at all in the 2018-4-9 capture - CC_currentLimit_PT = int(data[0:2],16) * 0.5 # "A" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" - CC_pilotState_PT = int(data[3],16) & 3 #: 8|2@1+ (1,0) [0|3] "" CHG,GTW + # "A" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" + CC_currentLimit_PT = int(data[0:2],16) * 0.5 + #: 8|2@1+ (1,0) [0|3] "" CHG,GTW + CC_pilotState_PT = int(data[3],16) & 3 CC_pilotState_PTText = {3:"PT_CC_PILOT_STATE_SNA",2:"PT_CC_PILOT_STATE_FAULTED",1:"PT_CC_PILOT_STATE_IDLE",0:"PT_CC_PILOT_STATE_READY"} - CC_numPhases_PT = int(data[3],16) >> 2 #: 10|2@1+ (1,0) [0|3] "" CHG,GTW - CC_lineVoltage_PT = int(data[7]+data[4:6],16) & 511 #: 16|9@1+ (1,0) [0|510] "V" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" + #: 10|2@1+ (1,0) [0|3] "" CHG,GTW + CC_numPhases_PT = int(data[3],16) >> 2 + #: 16|9@1+ (1,0) [0|510] "V" CHG,GTW "periodic TEN_SECONDS chargeModeModelS,periodic TEN_SECONDS voltageModeModelS" + CC_lineVoltage_PT = int(data[7]+data[4:6],16) & 511 message = ('CC_currentLimit_PT:%.0f' % CC_currentLimit_PT)+' CC_pilotState_PT:'+CC_pilotState_PTText.get(CC_pilotState_PT,' ').ljust(25) elif can_id==930: - message = 'BMS_fullChargeComplete:'+str(int(data[2],16) & 1) #: 12|1@1+ (1,0) [0|0] "" CP,GTW "This bit indicates if the BMS is fully charged" - message += ' BMS_fastChargerPresent:'+str(int(data[2],16) & 4) #: 14|1@1+ (1,0) [0|0] "" CP,GTW "TRUE when the fast charger Status Message has been received within the last 1 second" - message += ' BMS_fcContactorCloseRequest:'+str(int(data[2],16) & 8) #: 15|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "1 if the charger should close the FC contactors" - message += ' BMS_fcContactorPwrIsOn:'+str(int(data[6:8],16) & 16) #: 28|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "This bit indicates if the BMShas powered the FC Contactor Power line which is used by the charger to diagnose its h/w" + #: 12|1@1+ (1,0) [0|0] "" CP,GTW "This bit indicates if the BMS is fully charged" + message = 'BMS_fullChargeComplete:'+str(int(data[2],16) & 1) + #: 14|1@1+ (1,0) [0|0] "" CP,GTW "TRUE when the fast charger Status Message has been received within the last 1 second" + message += ' BMS_fastChargerPresent:'+str(int(data[2],16) & 4) + #: 15|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "1 if the charger should close the FC contactors" + message += ' BMS_fcContactorCloseRequest:'+str(int(data[2],16) & 8) + #: 28|1@1+ (1,0) [0|0] "" CHG,CHGS,GTW "This bit indicates if the BMShas powered the FC Contactor Power line which is used by the charger to diagnose its h/w" + message += ' BMS_fcContactorPwrIsOn:'+str(int(data[6:8],16) & 16) elif can_id==551: - CHGPH1_vBat = int(data[6:8]+data[4:6],16) * 0.010528564 #: 16|16@1+ (0.010528564,0) [0|690] "V" CHGVI BO_ 551 CHGPH1_HVStatus: 8 CHGPH1 + #: 16|16@1+ (0.010528564,0) [0|690] "V" CHGVI BO_ 551 CHGPH1_HVStatus: 8 CHGPH1 + CHGPH1_vBat = int(data[6:8]+data[4:6],16) * 0.010528564 message = previousMsg # a hack to prevent printing anything else: message = data