使用Python控制CAN总线

CAN总线是在汽车电子领域广泛应用的一种通讯方式,市面上有很多公司提供不同的将CAN转为USB的设备,使用这些设备电脑就能够借由USB通过CAN总线跟汽车ECU进行交流,通常来说,Vector 的设备受众最广,功能最全面,兼容性最好,但是好东西的唯一缺点就是贵,因此市面上其他的设备厂商才有了用武之地,Value CAN, PCAN, TSCAN 等。

在测试中有时可能需要通过CAN发送单一的报文,这时python通过设备进行总线通讯就有了用武之地。

python中可用于CAN的库有 python-can python-ics 待更新。。。

例如使用 Value CAN 发送诊断报文

import ics
import ctypes

enable_print_message = False
enable_use_server = True

# Helper Functions ##########################################################
def dev_name(device):
    if int("AA0000", 36) < device.SerialNumber < int("ZZZZZZ", 36):
        return device.Name + " " + ics.base36enc(device.SerialNumber)
    else:
        return device.Name + " " + str(device.SerialNumber)

def print_message(msg):
    if not enable_print_message:
        if isinstance(msg, ics.SpyMessage):
            print('\tArbID: {}\tData: {}'.format(hex(msg.ArbIDOrHeader), [hex(x) for x in msg.Data]))
        return
    print('\t' + str(type(msg)))
    for attribute in dir(msg):
        if attribute.startswith("_"):
            continue
        length = len(attribute)
        if attribute == 'data':
            print("\t\t{}:{}{}".format(attribute, " "*(30-length), msg.data[:msg.num_bytes]))
        else:
            value = getattr(msg, attribute)
            try:
                value = hex(value)
            except:
                pass
            print("\t\t{}:{}{}".format(attribute, " "*(30-length), value))
    print()

def open_device(index=0):
    device = None
    if enable_use_server:
        # ics.open_device() won't open a device if we have handles open already
        # so we need to find them and specify which ones to connect to.
        devices = ics.find_devices()
        print("Opening Device {} (Open Client handles: {})...".format(dev_name(devices[index]), devices[index].NumberOfClients))
        ics.open_device(devices[index])
        device = devices[index]
    else:
        print("Opening Device...")
        device = ics.open_device()
    print("Opened Device %s." % dev_name(device))
    return device

# Iso15765 Fuctions #########################################################
def transmit_iso15765_msg(device, netid=ics.NETID_HSCAN, is_canfd=False):
    number_of_bytes = 64
    msg = ics.st_cm_iso157652_tx_message.st_cm_iso157652_tx_message()
    msg.id = 0x7E0
    msg.vs_netid = netid
    msg.num_bytes = number_of_bytes
    msg.padding = 0xAA
    # Flow Control
    msg.fc_id = 0x7E8
    msg.fc_id_mask = 0xFFF
    msg.flowControlExtendedAddress = 0xFE
    msg.fs_timeout = 0x10 # ms
    msg.fs_wait = 0x3000 # ms
    msg.blockSize = 0
    msg.stMin = 0
    # paddingEnable
    msg.paddingEnable = 1
    # CANFD: Enable + BRS
    if is_canfd:
        msg.iscanFD = 1
        msg.isBRSEnabled = 1
    # tx_dl
    msg.tx_dl = 1
    # Data
    my_data = [x for x in range(number_of_bytes)]
    msg.data = (ctypes.c_ubyte*len(msg.data))(*my_data)

    # Transmit the message
    print("Transmitting iso15765 message on {}...".format(dev_name(device)))
    ics.iso15765_transmit_message(device, netid, msg, 3000)
    # Wait for the messages to be transmitted, this can be calculated a lot better but works here.
    time.sleep((((number_of_bytes/8)*msg.fs_timeout)/1000.0)+0.5)
    #print_message(msg)
    print("Transmitted iso15765 message on {}.".format(dev_name(device)))

def setup_rx_iso15765_msg(device, netid=ics.NETID_HSCAN, is_canfd=False):
    msg = ics.st_cm_iso157652_rx_message.st_cm_iso157652_rx_message()

    msg.id = 0x7E0
    msg.vs_netid = netid
    msg.padding = 0xAA
    msg.id_mask = 0xFFF
    msg.fc_id = 0x7E8
    msg.blockSize = 100
    msg.stMin = 10
    msg.cf_timeout = 1000
    # enableFlowControlTransmission = 1
    msg.enableFlowControlTransmission = 1
    # paddingEnable
    msg.paddingEnable = 1
    # CANFD: Enable + BRS
    if is_canfd:
        msg.iscanFD = 1
        msg.isBRSEnabled = 1
    print_message(msg)
    print("Setting up iso15765 message on {}...".format(dev_name(device)))
    ics.iso15765_receive_message(device, netid, msg)
    print("Setup iso15765 message on {}.".format(dev_name(device)))
    

def get_iso15765_msgs(device):
    msgs, error_count = ics.get_messages(device)
    print("Received {} messages with {} errors.".format(len(msgs), error_count))
    for i, m in enumerate(msgs):
        print('Message #{}\t'.format(i+1), end='')
        print_message(m)
    
if __name__ == "__main__":
    import time
    netid = ics.NETID_HSCAN
    
    tx_device = open_device(0)
    rx_device = open_device(1)
    
    ics.iso15765_enable_networks(tx_device, netid)
    ics.iso15765_enable_networks(rx_device, netid)
    setup_rx_iso15765_msg(rx_device)
    transmit_iso15765_msg(tx_device)
    get_iso15765_msgs(rx_device)
    
    ics.iso15765_disable_networks(tx_device)
    ics.iso15765_disable_networks(rx_device)
参考链接

Git-hub_ISO_15765

听懂汽车的语言 – 使用Python控制CAN总线

posted @ 2022-03-16 13:05  可乐芬达  阅读(3696)  评论(0编辑  收藏  举报