首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >CAN总线测试

CAN总线测试
EN

Code Review用户
提问于 2020-06-26 21:34:16
回答 2查看 650关注 0票数 5

我正在创建一个Python3.8脚本,它执行一系列测试,从CAN总线网络读取和写入信息。我正在使用python和cantools包。我已经成功地发送和接收到了具有小功能的数据,没有问题。

我觉得我没有创建合适的"Pythonic“脚本体系结构,它允许我的脚本在模块之间使用所有函数、实例和变量。

Intended架构目标:

  • main.py -包含CAN总线的发送和接收功能,通过位于test_case.py模块中的每个测试用例执行初始化和循环。
  • test_case.py -存储所有测试用例。其中每个测试用例都是一个独立的函数。每个测试用例都必须是一个独立的函数,这样如果需要删除一个测试,或者添加了一个新的测试,脚本就不会中断。此外,可能会有几十个,甚至几百个测试用例。因此,为了保持代码的整洁性,我希望将它们隔离到一个模块中。
  • test_thresholds.py -将保留test_case.py中每个测试用例将引用的所有pass/ will阈值变量。

问题/问题:

  1. main.py实例化CAN总线对象bus = can.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)该对象是发送和接收函数所必需的。因为发送和接收函数都在main.py中,所以直到我尝试在test_case.py模块中执行一个引用main.py中的发送和接收函数的测试用例时,才会出现问题--一旦我试图执行测试用例,就会发生错误,说明从test_case.py模块NameError: name 'bus' is not defined调用的receive()函数--我理解这一点,因为test_case.py不知道bus实例是什么。这个问题也发生在我的can实例中。我的test_case.py中有D27,我知道这很糟糕,但我不确定test_cases.py将如何使用发送和接收函数以及buscan实例How,我可以在模块之间共享这个实例吗?这里的最佳实践是什么?我尝试浏览过关于传递对象的堆栈溢出的几个帖子(我认为这就是我的问题所在),但似乎没有一个能回答我正在寻找的内容。
  2. Is我的架构设计可以接受吗?我刚开始设计更大的脚本,我希望确保我正在有效地/正确地完成它,以便它能够扩展。

<#>注意:我减少了大量代码,以使它在这里更加可读性。如果您尝试它,它可能不会运行。

main.py

代码语言:javascript
运行
复制
import can
import cantools
import test_cases.test_cases  # import all test cases
import time


# sending a single CAN message
def single_send(message):
    try:
        bus.send(message)
    except can.CanError:
        print("Message NOT sent")


# receive a message and decode payload
def receive(message, signal):
    _counter = 0
    try:
        while True:
            msg = bus.recv(1)
            try:
                if msg.arbitration_id == message.arbitration_id:
                    message_data = db.decode_message(msg.arbitration_id, msg.data)
                    signal_data = message_data.get(signal)
                    return signal_data
            except AttributeError:
                _counter += 1
                if _counter == 5:
                    print("CAN Bus InActive")
                    break
    finally:
        if _counter == 5:
            # reports false if message fails to be received
            return False

def main():
    for name, tests in test_cases.test_cases.__dict__.items():
        if name.startswith("tc") and callable(tests):
            tests()


if __name__ == "__main__":
    bus = can.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
    db = cantools.db.load_file('C:\\Users\\tw\\Desktop\\dbc_file.dbc')
    verbose_log = open("verbose_log.txt", "a")
    main()
    bus.shutdown()
    verbose_log.close()

test_case.py

代码语言:javascript
运行
复制
from test_thresholds.test_thresholds import *
from main import *  # to use the single_send and receive functions in main 

def tc_1():
    ct = receive(0x300, 'ct_signal')  # this is where the issue occurs. receive expects the bus instance
    message = can.Message(arbitration_id=0x303, data=1)
    if (ct > ct_min) and (ct < ct_max):
        verbose_log.write("PASS")
    else:
        verbose_log.write("FAIL")

test_thresholds.py

代码语言:javascript
运行
复制
ct_min = 4.2 
ct_max = 5.3
EN

回答 2

Code Review用户

回答已采纳

发布于 2020-06-28 16:01:23

带内差错信令

代码语言:javascript
运行
复制
return signal_data
# ...
# reports false if message fails to be received
return False

是有问题的。您强制调用此代码的人理解返回值至少有两种不同的类型:布尔值或任何“信号数据”。

Python处理此问题的方法是使用异常。与其重新抛出AttributeError,不如抛出您自己的异常类型可能更有意义。

此外,重试计数的逻辑也有点复杂。您应该能够假设,如果循环已经结束而没有返回,那么它就失败了。另外,不要自己增加计数器。换句话说,

代码语言:javascript
运行
复制
for attempt in range(5):
    msg = bus.recv(1)
    try:
        if msg.arbitration_id == message.arbitration_id:
            message_data = db.decode_message(msg.arbitration_id, msg.data)
            signal_data = message_data.get(signal)
            return signal_data
    except AttributeError:
        pass

raise CANBusInactiveError()

我会走得更远。我的猜测是,msg --如果失败--不具有arbitration_id属性。因此,与其试图捕获AttributeError,不如:

  • 呼叫hasattr,或
  • (最好)打给isinstance

上下文管理

把这个:

代码语言:javascript
运行
复制
verbose_log = open("verbose_log.txt", "a")
verbose_log.close()

with中。

硬编码路径

代码语言:javascript
运行
复制
'C:\\Users\\tw\\Desktop\\dbc_file.dbc'

至少应该进入一个常数变量。最好是从命令行参数、conf文件或env var获得它。

票数 3
EN

Code Review用户

发布于 2020-06-28 22:51:17

尚不熟悉的人只能提出一个建议:

去掉这些print语句,改用日志记录模块。还请参阅此处:基本日志教程伐木食谱

  • 能够写入多个目的地:控制台+不同格式的文本文件(如果需要的话)
  • 随意增加或减少详细
  • 保存程序活动的永久记录(和例外!)

很容易错过控制台输出,没有持久的、有时间戳的日志会使跟踪错误或调查事件变得更加困难。

如果您的应用程序是任务关键/无人值守,则可以将日志记录输出发送到专用的log收集器,当发出警告/错误消息或应用程序因某种原因崩溃时,该收集器会生成警报。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/244590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档