def receivePackets(self, timeout): packets = [] endTime = time.time() + timeout while 1: if len(packets): self._s.setblocking(0) else: newTimeout = endTime - time.time() if newTimeout < 0: self._s.setblocking(0) else: self._s.settimeout(newTimeout) try: frame = self._s.recvfrom(16)[0] except (socket.timeout, BlockingIOError): break packet = self._decodeFrame(frame) if not self._filterXcp or packet.data[0] == 0xFF or packet.data[ 0] == 0xFE: packets.append(packet) if self._dumpTraffic: print('RX ' + CANInterface.ID(packet.ident).getString() + ' ' + CANInterface.getDataHexString(packet.data)) return packets
def _doTransmit(self, data, ident): if self._dumpTraffic: print('TX ' + CANInterface.ID(ident).getString() + ' ' + CANInterface.getDataHexString(data)) self._setTXTypeByIdent(ident) self._updateBitrateTXType() if self._cfgdHeaderIdent != ident: if ident & 0x80000000: self._runCmdWithCheck( b'ATCP' + bytes('{:02x}'.format((ident >> 24) & 0x1F), 'utf-8')) self._runCmdWithCheck( b'ATSH' + bytes('{:06x}'.format(ident & 0xFFFFFF), 'utf-8')) else: self._runCmdWithCheck(b'ATSH' + bytes('{:03x}'.format(ident & 0x7FF), 'utf-8')) self._cfgdHeaderIdent = ident else: self._io.syncAndGetPrompt( self._intfcTimeout ) # Not synchronized by calling _runCmdWithCheck(), so do it here self._io.write(binascii.hexlify(data) + b'\r')
def receivePackets(self, timeout): assert self._cfgdBitrate != None and self._cfgdFilter != None packets = [] endTime = time.time() + timeout while 1: try: if len(packets): packet = self._io.getReceived(timeout=0) else: newTimeout = endTime - time.time() if newTimeout < 0: packet = self._io.getReceived(timeout=0) else: packet = self._io.getReceived(timeout=newTimeout) except queue.Empty: break if len(packet.data) > 0 and (packet.data[0] == 0xFF or packet.data[0] == 0xFE): packets.append(packet) if self._dumpTraffic: print('RX ' + CANInterface.ID(packet.ident).getString() + ' ' + CANInterface.getDataHexString(packet.data)) return packets
def transmitTo(self, data, ident): if self._dumpTraffic: print('TX ' + CANInterface.ID(ident).getString() + ' ' + CANInterface.getDataHexString(data)) frame = self._buildFrame(data, ident) import binascii print(binascii.hexlify(frame).decode('utf-8')) self._sendFrame(frame)
def transmitTo(self, data, ident): assert self._cfgdBitrate != None if self._dumpTraffic: print('TX ' + CANInterface.ID(ident).getString() + ' ' + CANInterface.getDataHexString(data)) frame = self._build_frame(data, ident) res = self._dll.icsneoTxMessages(self._neoObject, ctypes.byref(frame), self._icsNetId, 1) if res != 1: raise CANInterface.Error()
def receive(self, timeout): assert self._cfgdBitrate != None if self._slaveAddr.resId.raw == 0xFFFFFFFF: return [] packets = [] if timeout != 0: endTime = time.time() + timeout else: endTime = None while 1: if endTime != None: newTimeout = int((endTime - time.time()) * 1000) if newTimeout > 0: self._dll.icsneoWaitForRxMessagesWithTimeOut( self._neoObject, newTimeout) else: break else: endTime = 0 # allow one pass, then return on the next icsMsgs = (_ICSSpyMessage * 20000)() icsNMsgs = ctypes.c_int() icsNErrors = ctypes.c_int() res = self._dll.icsneoGetMessages(self._neoObject, icsMsgs, ctypes.byref(icsNMsgs), ctypes.byref(icsNErrors)) if res != 1: raise CANInterface.Error() for iMsg in range(icsNMsgs.value): if icsMsgs[iMsg].NetworkID == self._icsNetId: ident, data = self._decode_frame(icsMsgs[iMsg]) if len(data ) > 0 and ident == self._slaveAddr.resId.raw and ( data[0] == 0xFF or data[0] == 0xFE): if self._dumpTraffic: print('RX ' + self._slaveAddr.resId.getString() + ' ' + CANInterface.getDataHexString(data)) packets.append(data) if len(packets) != 0: break return packets
def receive(self, timeout): assert self._cfgdBitrate != None and self._cfgdFilter != None if self._slaveAddr.resId.raw == 0xFFFFFFFF: return [] msgs = [] endTime = time.time() + timeout while 1: try: if len(msgs): packet = self._io.getReceived(timeout=0) else: newTimeout = endTime - time.time() if newTimeout < 0: packet = self._io.getReceived(timeout=0) else: packet = self._io.getReceived(timeout=newTimeout) except queue.Empty: break if packet.ident == self._slaveAddr.resId.raw and ( packet.data[0] == 0xFF or packet.data[0] == 0xFE): msgs.append(packet.data) if self._dumpTraffic: print('RX ' + self._slaveAddr.resId.getString() + ' ' + CANInterface.getDataHexString(packet.data)) return msgs
def do_connect(self, cmdLine): 'Connect to an XCP slave: connect' parser = ShellArgParser(prog='connect', description=__doc__) args = parser.parse_args(shlex.split(cmdLine)) slave = CANInterface.XCPSlaveCANAddr(args.commandId, args.responseId) self.interface.connect(slave) self.connection = XCPConnection.Connection(self.interface)
def receive(self, timeout): if self._slaveAddr.resId.raw == 0xFFFFFFFF: return [] msgs = [] endTime = time.time() + timeout while 1: if len(msgs): self._s.setblocking(0) else: newTimeout = endTime - time.time() if newTimeout < 0: self._s.setblocking(0) else: self._s.settimeout(newTimeout) try: frame = self._s.recvfrom(16)[0] except (socket.timeout, BlockingIOError): break packet = self._decodeFrame(frame) if not self._filterXcp or packet.data[0] == 0xFF or packet.data[ 0] == 0xFE: msgs.append(packet.data) if self._dumpTraffic: print('RX ' + self._slaveAddr.resId.getString() + ' ' + CANInterface.getDataHexString(packet.data)) return msgs
def do_interface(self, cmdLine): 'Connect to a CAN interface: connect <device URI>' parser = ShellArgParser(prog='interface', description=__doc__) parser.add_argument('deviceURI', help="CAN device URI", default=None) args = parser.parse_args(shlex.split(cmdLine)) self.interface = CANInterface.MakeInterface(args.deviceURI) self.connection = None
def setBitrate(self, bitrate): print('Setting bitrate ' + str(bitrate)) setBitrateResult = self._dll.icsneoSetBitRate(self._neoObject, bitrate, self._icsNetId) if setBitrateResult != 1: raise CANInterface.Error('Setting bitrate failed') else: self._cfgdBitrate = bitrate
def __init__(self, parsedURL): if not SocketCANSupported(): raise CANInterface.InterfaceNotSupported( 'Socket module does not support CAN') self._s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW) self._slaveAddr = CANInterface.XCPSlaveCANAddr(0xFFFFFFFF, 0xFFFFFFFF) self._dumpTraffic = False if parsedURL.netloc == None or parsedURL.netloc == "": dev = 'can0' else: dev = parsedURL.netloc try: self._s.bind((dev, )) except socket.error: self._s.close() raise CANInterface.ConnectFailed() urlQueryDict = urllib.parse.parse_qs(parsedURL.query) if 'filterxcp' in urlQueryDict: self._filterXcp = (urlQueryDict['filterxcp'][0] != "0") else: self._filterXcp = True
def disconnect(self): self._slaveAddr = CANInterface.XCPSlaveCANAddr(0xFFFFFFFF, 0xFFFFFFFF) self._dumpTraffic = False filt = struct.pack("=II", 0, 0) self._s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, filt)
def _decodeFrame(self, frame): ident, dlc, data = struct.unpack("=IB3x8s", frame) return CANInterface.Packet(ident, data[0:dlc])
def __init__(self, parsedURL): self._icsNetId = None self._cfgdBitrate = None self._dumpTraffic = False self._filter = 0x00000000 self._mask = 0x00000000 if not hasattr(ctypes, 'windll'): raise CANInterface.InterfaceNotSupported('Not a Windows system') try: self._dll = ctypes.windll.icsneo40 except OSError: raise CANInterface.InterfaceNotSupported( 'Loading icsneo40.dll failed') neoDevices = (_ICSNeoDevice * 64)() self._neoObject = None nNeoDevices = ctypes.c_int(64) findResult = self._dll.icsneoFindNeoDevices(0xFFFFFFFF, neoDevices, ctypes.byref(nNeoDevices)) if findResult != 1: raise CANInterface.ConnectFailed('Finding ICS devices failed') splitPath = parsedURL.path.split('/') if len(splitPath) != 3: raise CANInterface.ConnectFailed( 'Invalid ICS device path \'' + parsedURL.path + '\'; path is ics:<devtype>/<dev-index>/<net-id>') try: devTypeMask = _ICS_TYPE_STRING_MASKS[splitPath[0]] except KeyError: raise CANInterface.ConnectFailed('Invalid ICS device type \'' + splitPath[0] + '\'') try: devIdx = int(splitPath[1]) except ValueError: raise CANInterface.ConnectFailed('Invalid ICS device index \'' + splitPath[1] + '\'') try: self._icsNetId = _ICS_NET_IDS[splitPath[2]] except KeyError: raise CANInterface.ConnectFailed('Invalid ICS net id \'' + splitPath[2]) devOfType = [ dev for dev in neoDevices[0:nNeoDevices.value] if dev.DeviceType & devTypeMask ] if len(devOfType) < devIdx + 1: raise CANInterface.ConnectFailed('ICS device of type \'' + splitPath[0] + '\', index ' + str(devIdx) + ' not found') sys.stderr.write('Connecting to ' + _ICSDevTypeStr(neoDevices[0].DeviceType) + ' #' + str(devIdx) + '\n') netIDs = (ctypes.c_ubyte * 64)() for i in range(len(netIDs)): netIDs[i] = i tempNeoObject = ctypes.c_int() openResult = self._dll.icsneoOpenNeoDevice( ctypes.byref(devOfType[devIdx]), ctypes.byref(tempNeoObject), netIDs, 1, 0) if openResult != 1: raise CANInterface.ConnectFailed('Opening ICS device failed') self._neoObject = tempNeoObject.value self.setBitrate(CANInterface.URLBitrate(parsedURL)) self._slaveAddr = CANInterface.XCPSlaveCANAddr(0xFFFFFFFF, 0xFFFFFFFF)
if len(packets): self._s.setblocking(0) else: newTimeout = endTime - time.time() if newTimeout < 0: self._s.setblocking(0) else: self._s.settimeout(newTimeout) try: frame = self._s.recvfrom(16)[0] except (socket.timeout, BlockingIOError): break packet = self._decodeFrame(frame) if not self._filterXcp or packet.data[0] == 0xFF or packet.data[ 0] == 0xFE: packets.append(packet) if self._dumpTraffic: print('RX ' + CANInterface.ID(packet.ident).getString() + ' ' + CANInterface.getDataHexString(packet.data)) return packets def setFilter(self, filt): rfilter = struct.pack('LL', filt[0], filt[1]) self._s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, rfilter) if SocketCANSupported(): CANInterface.addInterface("socketcan", SocketCANInterface)
icsNErrors = ctypes.c_int() res = self._dll.icsneoGetMessages(self._neoObject, icsMsgs, ctypes.byref(icsNMsgs), ctypes.byref(icsNErrors)) if res != 1: raise CANInterface.Error() for iMsg in range(icsNMsgs.value): if icsMsgs[iMsg].NetworkID == self._icsNetId: ident, data = self._decode_frame(icsMsgs[iMsg]) if (ident & self._mask) == self._filter and len(data) > 0 and ( data[0] == 0xFF or data[0] == 0xFE): packets.append(CANInterface.Packet(ident, data)) if self._dumpTraffic: print('RX ' + CANInterface.ID(ident).getString() + ' ' + CANInterface.getDataHexString(data)) if len(packets) != 0: break return packets def setFilter(self, filt): self._filter = filt[0] self._mask = filt[1] if ICSSupported(): CANInterface.addInterface("ics", ICSCANInterface)
def transmit(self, data): if self._dumpTraffic: print('TX ' + self._slaveAddr.cmdId.getString() + ' ' + CANInterface.getDataHexString(data)) frame = self._buildFrame(data, self._slaveAddr.cmdId.raw) self._sendFrame(frame)
if newTimeout < 0: packet = self._io.getReceived(timeout=0) else: packet = self._io.getReceived(timeout=newTimeout) except queue.Empty: break if len(packet.data) > 0 and (packet.data[0] == 0xFF or packet.data[0] == 0xFE): packets.append(packet) if self._dumpTraffic: print('RX ' + CANInterface.ID(packet.ident).getString() + ' ' + CANInterface.getDataHexString(packet.data)) return packets CANInterface.addInterface("elm327", ELM327CANInterface) if __name__ == "__main__": parsedurl = urllib.parse.urlparse( 'elm327:/dev/rfcomm0?debuglog=elm327.log') elm327 = ELM327CANInterface(parsedurl) elm327.setFilter((0x000, 0x80000000)) elm327.transmitTo(b'1234', 0x9FFFFFFF) elm327.transmitTo(b'1234', 0x7FF) time.sleep(1) packets = elm327.receivePackets(1) for packet in packets: print(repr(packet)) elm327.close()
def disconnect(self): self._slaveAddr = CANInterface.XCPSlaveCANAddr(0xFFFFFFFF, 0xFFFFFFFF) self._doSetFilter(self._filter) self._dumpTraffic = False
def __init__(self, parsedURL): self._slaveAddr = None self._port = None self._bitrate = None self._txAddrStd = False self._cfgdBitrate = None self._cfgdTxAddrStd = False self._baudDivisor = None self._baud87Mult = None self._hasSetCSM0 = False self._tcpTimeout = 1.0 self._serialTimeout = 0.2 self._dumpTraffic = False self._cfgdHeaderIdent = None self._filter = None self._cfgdFilter = None self._noCsmQuirk = False self._isSt = False self._io = None urlQueryDict = urllib.parse.parse_qs(parsedURL.query) debugLogfile = None if 'debuglog' in urlQueryDict: if urlQueryDict['debuglog'][0] == 'stdout': debugLogfile = sys.stdout else: debugLogfile = open(urlQueryDict['debuglog'][0], 'w') if len(parsedURL.netloc): # If netloc is present, we're using a TCP connection addr = parsedURL.netloc.split(':') if len(addr) == 1: addr.append(35000) # use default port elif len(addr) != 2: raise CANInterface.Error('Interface address invalid') s = socket.socket() s.create_connection(addr, 0) self._port = SocketAsPort(s) self._intfcTimeout = self._tcpTimeout else: if debugLogfile != None: port = LoggingPort(debugLogfile) else: port = serial.Serial() port.port = parsedURL.path port.open() foundBaud = False for baudRate in self._POSSIBLE_BAUDRATES: if DEBUG: print('Trying ' + str(baudRate)) port.baudrate = baudRate port.interCharTimeout = min(10 / baudRate, 0.0001) port.timeout = 0.05 # Try sending a CR, if we get a prompt then it's probably the right baudrate port.flushInput() port.write(b'\r') response = port.read(16384) if len(response) == 0 or response[-1:] != b'>': port.write(b'\r') response = port.read(16384) if len(response) == 0 or response[-1:] != b'>': continue # Turn off echo, this also serves as a test to make sure we didn't randomly get a > at the end of some gibberish port.flushInput() port.write(b'ATE0\r') response = port.read(16) if not b'OK' in response: continue # If we made contact at baudrate 500k, we're done if baudRate == 500000: foundBaud = True break # Not at 500k, try to change ELM to that port.timeout = 1.28 # Maximum possible timeout for ELM327 port.flushInput() port.write(b'ATBRD08\r') response = port.read(2) if response == b'?\r': # Device does not allow baudrate change, but we found its operating baudrate foundBaud = True break elif response == b'OK': # Device allows baudrate change, try to switch to 500k port.baudrate = 500000 port.flushInput() response = port.read(11) if response[0:6] != b'ELM327': # Baudrate switch unsuccessful, try to recover port.baudrate = baudRate port.write(b'\r') port.flushInput() response = port.read(1024) if len(response) == 0 or response[-1:] != b'>': raise UnexpectedResponse('switching baudrate') # Baudrate switched, send a CR to confirm we're on board port.flushInput() port.write(b'\r') response = port.read(2) if response != b'OK': raise UnexpectedResponse('switching baudrate') foundBaud = True if response == b'ELM327 v1.5': self._noCsmQuirk = True break if not foundBaud: raise SerialError('could not find baudrate') port.timeout = 0 self._port = port self._intfcTimeout = self._serialTimeout self._port.flushInput() # Start the I/O thread, which takes over control of the port self._io = ELM327IO(port) self._runCmdWithCheck(b'ATWS', checkOK=False, closeOnFail=True) # Software reset self._runCmdWithCheck(b'ATE0', closeOnFail=True) # Turn off echo self._runCmdWithCheck(b'ATL0', closeOnFail=True) # Turn off newlines self._runCmdWithCheck(b'ATS0', closeOnFail=True) # Turn off spaces self._runCmdWithCheck(b'ATH1', closeOnFail=True) # Turn on headers self._runCmdWithCheck(b'ATAL', closeOnFail=True) # Allow full length messages try: self._runCmdWithCheck( b'STFCP', closeOnFail=False) # See if this is an ST device self._isSt = True except UnexpectedResponse: pass self.setBitrate(CANInterface.URLBitrate(parsedURL)) self._slaveAddr = CANInterface.XCPSlaveCANAddr(0xFFFFFFFF, 0xFFFFFFFF)
def threadFunc(self): while 1: if self._terminate.is_set(): if DEBUG: print(str(time.time()) + ' ELM327IO(): terminate set') return setPipelineClear = (not self._pipelineClear.is_set()) setPromptReady = False linesRead = self._port.read(4096).translate( None, b'\0').splitlines(keepends=True) if len(linesRead) > 0: if len(self._lines) > 0: self._lines[-1] += linesRead[0] del linesRead[0] for lineRead in linesRead: self._lines.append(lineRead) if self._lines[-1] == self._PROMPT: if DEBUG: print(str(time.time()) + ' promptReady.set()') # Manage the promptReady Event; it's set if and only if there is an incomplete line consisting of a prompt. setPromptReady = True del self._lines[-1] while self._lines: rawLine = self._lines.popleft() if self._EOL in rawLine: line = rawLine.strip(self._EOL) # Is it empty? if len(line) == 0: pass # Does it contain non-hex characters? elif any(x for x in line if x not in b'0123456789ABCDEF'): # Command response or a packet received with errors PutDiscard(self._cmdResp, line) else: # Must be a valid received frame if len(line) % 2 == 1: idLen = 3 mask = 0 else: idLen = 8 mask = 0x80000000 if len(line) >= idLen: ident = int(line[0:idLen], 16) data = binascii.unhexlify(line[idLen:]) packet = CANInterface.Packet( ident | mask, data) PutDiscard(self._receive, packet) else: # Too short to be valid PutDiscard(self._cmdResp, line) else: if rawLine == self._PROMPT: if DEBUG: print(str(time.time()) + ' promptReady.set()') # Manage the promptReady Event; it's set if and only if there is an incomplete line consisting of a prompt. setPromptReady = True else: self._lines.appendleft(rawLine) break if self._timeToSend < time.time() and not self._transmit.empty(): self._port.write(self._transmit.get_nowait()) self._promptReady.clear() self._timeToSend = time.time() + self._ELM_RECOVERY_TIME setPromptReady = False setPipelineClear = False if setPromptReady: self._promptReady.set() if setPipelineClear and self._transmit.empty(): self._pipelineClear.set()
parser.add_argument('-w', help="Warn if slave returns out of range for any parameter", dest="warnNotFound", action="store_true", default=False) args = parser.parse_args() config.loadConfigs(args.configFiles) BoardTypes.SetupBoardTypes() try: boardType = BoardTypes.types[args.targetType] except KeyError: print('Could not find board type ' + str(args.targetType)) sys.exit(1) paramSpec = json.loads(args.paramSpecFile.read()) maxAttempts = 10 with CANInterface.MakeInterface(args.deviceURI) as interface: targetSlaves = boardType.SlaveListFromIdxArg(args.targetID) # If needed, ask the user to pick a slave from the list if len(targetSlaves) == 0: slaves = boardType.GetSlaves(interface) for i in range(0, len(slaves)): print(str(i) + ': ' + slaves[i][0].description() + ', ID ' + str(slaves[i][1])) index = int(input('Slave: ')) if index >= len(slaves): exit targetSlaves = [slaves[index]] for targetSlave in targetSlaves: outFile=OpenOutFile(args.outputFile, targetSlave[1]) if targetSlave[1] != None: sys.stderr.write('Connecting to target addr ' + targetSlave[0].description() + ', ID ' + str(targetSlave[1]) + '\n')
parser.add_argument('size', help='word size', type=int, choices=[1, 2, 4]) parser.add_argument('words', help='number of words to read', type=hexInt, default=1) args = parser.parse_args() if args.size == 1: uploadDelegate = UploadDelegate8() elif args.size == 2: uploadDelegate = UploadDelegate16() elif args.size == 4: uploadDelegate = UploadDelegate32() try: with CANInterface.MakeInterface(args.deviceURI) as interface: slave = CANInterface.XCPSlaveCANAddr(args.commandId, args.responseId) interface.connect(slave) connection = XCPConnection.Connection(interface, readTimeout, writeTimeout) for address in range(args.address, args.address + args.words): pointer = XCPConnection.Pointer(address, args.extension) print(uploadDelegate.upload(connection, pointer)) connection.close() except (OSError, CANInterface.ConnectFailed): try: interface.close() except NameError: pass