I've been using python-can and cantools to transmit and receive CAN bus messages without any issue. But when I begin transmitting periodic messages while also trying to receive messages there seems to be some error. I'm not sure if there is a problem with how I am doing it or if it is simply not possible to perform simultaneous transmit and receive. When I attempt to do so, receive()
returns with NoneType and I know this is incorrect because I have another device logging and reporting that the signal I am looking for does exist on the bus.
Is it possible to send and transmit simultaneously on the same bus using python-can?
Traceback:
line 51, in tc_1
if sig_min <= sig <= sig_max:
TypeError: '<=' not supported between instances of 'float' and 'NoneType'
Code:
tc_1()
calls on receive()
to look for a specific message on the bus and also calls on periodic_send()
to periodically send messages on the bus. The error occurs right after I call periodic_send()
and while I am trying to look for a message on the bus. It seems like once I start sending messages receive()
returns None. I know this isn't a timeout issue as the error occurs in a few seconds and my timeout is 15 seconds. And I don't get the issue if I comment out periodic_send()
.
def tc_1(bus, num):
message = can.Message(arbitration_id=0x300)
sig = receive(bus, message, 'sig')
if sig is not None:
sig = float(sig)
logging.info('Test Case #{}.0 - PASS'.format(num))
if sig_min <= sig <= sig_max:
logging.info('Test Case #{}.1 - PASS'.format(num))
close_relay = can.Message(arbitration_id=0x303, data=[1])
periodic_send(bus, close_relay, 0.01)
then = time.time()
print('Entering while loop for sig to go low...')
while type(sig) == float and sig > sig_max:
# Refresh sig message instance
### THIS IS WHERE THE PROBLEM OCCURS ###
sig = receive(bus, message, 'sig')
if sig is not None:
sig = float(sig)
print('while loop, pwr_en = {:.3f}'.format(sig))
now = time.time()
# Timeout if sig does not transition low
if now > (then + relay_switch_time):
break
# Verify the active voltage state of power enable
if sig_min <= sig <= sig_max:
print('PASS')
else:
print('FAIL')
else:
print('FAIL')
else:
print('FAIL')
# Final clean-up and restore
bus.stop_all_periodic_tasks()
def receive(bus, message, signal):
# include dbc file
db = cantools.db.load_file(dbc_path)
msg = bus.recv(timeout=15)
if msg is None:
logging.warning("Failed to detect bus activity. Timeout occurred")
if msg is not None and 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
def periodic_send(bus, message, period):
try:
bus.send_periodic(message, period)
except can.CanError:
print("Message NOT sent")
finally:
return
Research
In the docs they mention the class can.ThreadSafeBus()
and that it "assumes that both send() and _recv_internal() of the underlying bus instance can be called simultaneously" The leads me to think I must use this class of bus instance in order to tx/rx messages at the same time. But I see the word threading and get a little intimidated.
UPDATE 1:
After some testing, it looks like the can.Bus instance can simultaneously transmit and receive messages. Its not actually "simultaneous" but there is no issue if you attempt to transmit and receive at the same time.
The issue that I am running into seems to be in how I am implementing the transmit and receive. Sometimes receive()
returns None
(see code below) and this becomes problematic when using that return value as in in a compare statement which results with: TypeError: '<=' not supported between instances of 'float' and 'NoneType'
1593644420.403561 - sig: 4.7067000000000005
1593644420.4893048 - sig: 4.752400000000001
1593644420.5660996 - sig: None
1593644420.7276666 - sig: 4.752400000000001
1593644420.8034878 - sig: 4.752400000000001
1593644420.8912296 - sig: 4.7067000000000005
1593644420.9899697 - sig: 4.752400000000001
1593644421.0677896 - sig: None
1593644421.2223675 - sig: 1.0053
1593644421.3011339 - sig: 0.31980000000000003
1593644421.3919268 - sig: 0.0913