diff --git a/cereal/log.capnp b/cereal/log.capnp index 62ecd1fdd9..ab1c6f7984 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -205,7 +205,7 @@ struct CanData { address @0 :UInt32; busTime @1 :UInt16; dat @2 :Data; - src @3 :Int8; + src @3 :UInt8; } struct ThermalData { diff --git a/panda b/panda index 5409c51041..27a8af1107 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit 5409c51041cfe8f139650a4e0decf4f6d863eb07 +Subproject commit 27a8af11075d92d03c389713694a879905877cf0 diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index 05181b9c62..18deccc100 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -31,11 +31,16 @@ pthread_mutex_t usb_lock; bool spoofing_started = false; bool fake_send = false; +bool loopback_can = false; // double the FIFO size #define RECV_SIZE (0x1000) #define TIMEOUT 0 +#define SAFETY_NOOUTPUT 0x0000 +#define SAFETY_HONDA 0x0001 +#define SAFETY_ALLOUTPUT 0x1337 + bool usb_connect() { int err; @@ -48,22 +53,36 @@ bool usb_connect() { err = libusb_claim_interface(dev_handle, 0); if (err != 0) { return false; } + if(loopback_can) { + libusb_control_transfer(dev_handle, 0xc0, 0xe5, 1, 0, NULL, 0, TIMEOUT); + } + // power off ESP libusb_control_transfer(dev_handle, 0xc0, 0xd9, 0, 0, NULL, 0, TIMEOUT); // forward CAN1 to CAN3...soon //libusb_control_transfer(dev_handle, 0xc0, 0xdd, 1, 2, NULL, 0, TIMEOUT); - + // set UART modes for Honda Accord for (int uart = 2; uart <= 3; uart++) { // 9600 baud - libusb_control_transfer(dev_handle, 0xc0, 0xe1, uart, 9600, NULL, 0, TIMEOUT); + libusb_control_transfer(dev_handle, 0x40, 0xe1, uart, 9600, NULL, 0, TIMEOUT); // even parity - libusb_control_transfer(dev_handle, 0xc0, 0xe2, uart, 1, NULL, 0, TIMEOUT); + libusb_control_transfer(dev_handle, 0x40, 0xe2, uart, 1, NULL, 0, TIMEOUT); // callback 1 - libusb_control_transfer(dev_handle, 0xc0, 0xe3, uart, 1, NULL, 0, TIMEOUT); + libusb_control_transfer(dev_handle, 0x40, 0xe3, uart, 1, NULL, 0, TIMEOUT); } + // TODO: Boardd should be able to set the baud rate + int baud = 500000; + libusb_control_transfer(dev_handle, 0x40, 0xde, 0, 0, + (unsigned char *)&baud, sizeof(baud), TIMEOUT); // CAN1 + libusb_control_transfer(dev_handle, 0x40, 0xde, 1, 0, + (unsigned char *)&baud, sizeof(baud), TIMEOUT); // CAN2 + + // TODO: Boardd should be able to be told which safety model to use + libusb_control_transfer(dev_handle, 0x40, 0xdc, SAFETY_HONDA, 0, NULL, 0, TIMEOUT); + return true; } @@ -90,7 +109,7 @@ void can_recv(void *s) { // do recv pthread_mutex_lock(&usb_lock); - + do { err = libusb_bulk_transfer(dev_handle, 0x81, (uint8_t*)data, RECV_SIZE, &recv, TIMEOUT); if (err != 0) { handle_usb_issue(err, __func__); } @@ -127,13 +146,13 @@ void can_recv(void *s) { canData[i].setBusTime(data[i*4+1] >> 16); int len = data[i*4+1]&0xF; canData[i].setDat(kj::arrayPtr((uint8_t*)&data[i*4+2], len)); - canData[i].setSrc((data[i*4+1] >> 4) & 0xf); + canData[i].setSrc((data[i*4+1] >> 4) & 0xff); } // send to can auto words = capnp::messageToFlatArray(msg); auto bytes = words.asBytes(); - zmq_send(s, bytes.begin(), bytes.size(), 0); + zmq_send(s, bytes.begin(), bytes.size(), 0); } void can_health(void *s) { @@ -181,7 +200,7 @@ void can_health(void *s) { // send to health auto words = capnp::messageToFlatArray(msg); auto bytes = words.asBytes(); - zmq_send(s, bytes.begin(), bytes.size(), 0); + zmq_send(s, bytes.begin(), bytes.size(), 0); } @@ -316,6 +335,10 @@ int main() { fake_send = true; } + if(getenv("BOARDD_LOOPBACK")){ + loopback_can = true; + } + // init libusb err = libusb_init(&ctx); assert(err == 0); @@ -357,4 +380,3 @@ int main() { libusb_close(dev_handle); libusb_exit(ctx); } - diff --git a/selfdrive/boardd/boardd.py b/selfdrive/boardd/boardd.py index 16715119bb..15d1c06dfd 100755 --- a/selfdrive/boardd/boardd.py +++ b/selfdrive/boardd/boardd.py @@ -18,6 +18,10 @@ except Exception: # TODO: rewrite in C to save CPU +SAFETY_NOOUTPUT = 0 +SAFETY_HONDA = 1 +SAFETY_ALLOUTPUT = 0x1337 + # *** serialization functions *** def can_list_to_can_capnp(can_msgs, msgtype='can'): dat = messaging.new_message() @@ -94,6 +98,7 @@ def can_init(): if device.getVendorID() == 0xbbaa and device.getProductID() == 0xddcc: handle = device.open() handle.claimInterface(0) + handle.controlWrite(0x40, 0xdc, SAFETY_HONDA, 0, b'') if handle is None: print "CAN NOT FOUND" @@ -190,4 +195,3 @@ def main(gctx=None): if __name__ == "__main__": main() - diff --git a/selfdrive/boardd/test_boardd_loopback.py b/selfdrive/boardd/test_boardd_loopback.py new file mode 100644 index 0000000000..33ad63659b --- /dev/null +++ b/selfdrive/boardd/test_boardd_loopback.py @@ -0,0 +1,49 @@ +"""Run boardd with the BOARDD_LOOPBACK envvar before running this test.""" + +import os +import random +import zmq +import time + +from selfdrive.boardd.boardd import can_list_to_can_capnp +from selfdrive.messaging import drain_sock, pub_sock, sub_sock +from selfdrive.services import service_list + +def get_test_string(): + return b"test"+os.urandom(10) + +BUS = 0 + +def main(): + context = zmq.Context() + + rcv = sub_sock(context, service_list['can'].port) # port 8006 + snd = pub_sock(context, service_list['sendcan'].port) # port 8017 + time.sleep(0.3) # wait to bind before send/recv + + for _ in range(10): + at = random.randint(1024, 2000) + st = get_test_string()[0:8] + snd.send(can_list_to_can_capnp([[at, 0, st, 0]], msgtype='sendcan').to_bytes()) + time.sleep(0.1) + res = drain_sock(rcv, True) + assert len(res) == 1 + + res = res[0].can + assert len(res) == 2 + + msg0, msg1 = res + + assert msg0.dat == st + assert msg1.dat == st + + assert msg0.address == at + assert msg1.address == at + + assert msg0.src == 0x80 | BUS + assert msg1.src == BUS + + print("Success") + +if __name__ == "__main__": + main()