diff --git a/release/files_common b/release/files_common index 2b88a9d8c8..b84e93fbb5 100644 --- a/release/files_common +++ b/release/files_common @@ -91,6 +91,8 @@ selfdrive/boardd/boardd_setup.py selfdrive/boardd/can_list_to_can_capnp.cc selfdrive/boardd/panda.cc selfdrive/boardd/panda.h +selfdrive/boardd/pigeon.cc +selfdrive/boardd/pigeon.h selfdrive/car/__init__.py selfdrive/car/car_helpers.py @@ -211,6 +213,8 @@ selfdrive/common/visionimg.cc selfdrive/common/visionimg.h selfdrive/common/spinner.c selfdrive/common/spinner.h +selfdrive/common/gpio.cc +selfdrive/common/gpio.h selfdrive/controls/__init__.py diff --git a/selfdrive/boardd/SConscript b/selfdrive/boardd/SConscript index 0ccbe6bd24..94e630a641 100644 --- a/selfdrive/boardd/SConscript +++ b/selfdrive/boardd/SConscript @@ -1,6 +1,6 @@ Import('env', 'common', 'cereal', 'messaging', 'cython_dependencies') -env.Program('boardd', ['boardd.cc', 'panda.cc'], LIBS=['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']) +env.Program('boardd', ['boardd.cc', 'panda.cc', 'pigeon.cc'], LIBS=['usb-1.0', common, cereal, messaging, 'pthread', 'zmq', 'capnp', 'kj']) env.Library('libcan_list_to_can_capnp', ['can_list_to_can_capnp.cc']) env.Command(['boardd_api_impl.so', 'boardd_api_impl.cpp'], diff --git a/selfdrive/boardd/boardd.cc b/selfdrive/boardd/boardd.cc index a3bb2b0b4c..e1b275dd3e 100644 --- a/selfdrive/boardd/boardd.cc +++ b/selfdrive/boardd/boardd.cc @@ -28,6 +28,7 @@ #include "messaging.hpp" #include "panda.h" +#include "pigeon.h" #define MAX_IR_POWER 0.5f @@ -43,8 +44,6 @@ const float VBATT_START_CHARGING = 11.5; const float VBATT_PAUSE_CHARGING = 11.0; #endif -namespace { - Panda * panda = NULL; std::atomic safety_setter_thread_running(false); volatile sig_atomic_t do_exit = 0; @@ -468,82 +467,13 @@ void hardware_control_thread() { } } -#define pigeon_send(x) _pigeon_send(x, sizeof(x)-1) -void _pigeon_send(const char *dat, int len) { - unsigned char a[0x20+1]; - a[0] = 1; - for (int i=0; iusb_bulk_write(2, a, ll+1); - } -} - -void pigeon_set_power(int power) { - panda->usb_write(0xd9, power, 0); -} - -void pigeon_set_baud(int baud) { - panda->usb_write(0xe2, 1, 0); - panda->usb_write(0xe4, 1, baud/300); -} - -void pigeon_init() { - usleep(1000*1000); - LOGW("panda GPS start"); - - // power off pigeon - pigeon_set_power(0); - usleep(100*1000); - - // 9600 baud at init - pigeon_set_baud(9600); - - // power on pigeon - pigeon_set_power(1); - usleep(500*1000); - - // baud rate upping - pigeon_send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"); - usleep(100*1000); - - // set baud rate to 460800 - pigeon_set_baud(460800); - usleep(100*1000); - - // init from ubloxd - // To generate this data, run test/ubloxd.py with the print statements enabled in the write function in panda/python/serial.py - pigeon_send("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"); - pigeon_send("\xB5\x62\x06\x3E\x00\x00\x44\xD2"); - pigeon_send("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"); - pigeon_send("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"); - pigeon_send("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"); - pigeon_send("\xB5\x62\x06\x00\x00\x00\x06\x18"); - pigeon_send("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"); - pigeon_send("\xB5\x62\x06\x00\x01\x00\x02\x09\x23"); - pigeon_send("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"); - pigeon_send("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"); - pigeon_send("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"); - pigeon_send("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"); - pigeon_send("\xB5\x62\x06\x24\x00\x00\x2A\x84"); - pigeon_send("\xB5\x62\x06\x23\x00\x00\x29\x81"); - pigeon_send("\xB5\x62\x06\x1E\x00\x00\x24\x72"); - pigeon_send("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"); - pigeon_send("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"); - pigeon_send("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"); - pigeon_send("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"); - - LOGW("panda GPS on"); -} - -static void pigeon_publish_raw(PubMaster &pm, unsigned char *dat, int alen) { +static void pigeon_publish_raw(PubMaster &pm, std::string dat) { // create message capnp::MallocMessageBuilder msg; cereal::Event::Builder event = msg.initRoot(); event.setLogMonoTime(nanos_since_boot()); - auto ublox_raw = event.initUbloxRaw(alen); - memcpy(ublox_raw.begin(), dat, alen); + auto ublox_raw = event.initUbloxRaw(dat.length()); + memcpy(ublox_raw.begin(), dat.data(), dat.length()); pm.send("ubloxRaw", msg); } @@ -555,38 +485,33 @@ void pigeon_thread() { // ubloxRaw = 8042 PubMaster pm({"ubloxRaw"}); - // run at ~100hz - unsigned char dat[0x1000]; - uint64_t cnt = 0; +#ifdef QCOM2 + Pigeon * pigeon = Pigeon::connect("/dev/ttyHS0"); +#else + Pigeon * pigeon = Pigeon::connect(panda); +#endif - pigeon_init(); + pigeon->init(); while (!do_exit && panda->connected) { - int alen = 0; - while (alen < 0xfc0) { - int len = panda->usb_read(0xe0, 1, 0, dat+alen, 0x40); - if (len <= 0) break; - - //printf("got %d\n", len); - alen += len; - } - if (alen > 0) { - if (dat[0] == (char)0x00){ + std::string recv = pigeon->receive(); + if (recv.length() > 0) { + if (recv[0] == (char)0x00){ LOGW("received invalid ublox message, resetting panda GPS"); - pigeon_init(); + pigeon->init(); } else { - pigeon_publish_raw(pm, dat, alen); + pigeon_publish_raw(pm, recv); } } - // 10ms + // 10ms - 100 Hz usleep(10*1000); - cnt++; } -} + delete pigeon; } + int main() { int err; LOGW("starting boardd"); @@ -606,6 +531,8 @@ int main() { fake_send = true; } + panda_set_power(true); + while (!do_exit){ std::vector threads; threads.push_back(std::thread(can_health_thread)); diff --git a/selfdrive/boardd/panda.cc b/selfdrive/boardd/panda.cc index 5820fa4004..52cf1e0b71 100644 --- a/selfdrive/boardd/panda.cc +++ b/selfdrive/boardd/panda.cc @@ -2,10 +2,33 @@ #include #include +#include + #include "common/swaglog.h" +#include "common/gpio.h" #include "panda.h" +void panda_set_power(bool power){ +#ifdef QCOM2 + int err = 0; + err += gpio_init(GPIO_STM_RST_N, true); + err += gpio_init(GPIO_STM_BOOT0, true); + err += gpio_init(GPIO_HUB_RST_N, true); + + err += gpio_set(GPIO_STM_RST_N, false); + + // TODO: set hub somewhere else + err += gpio_set(GPIO_HUB_RST_N, true); + err += gpio_set(GPIO_STM_BOOT0, false); + + usleep(100*1000); // 100 ms + + err += gpio_set(GPIO_STM_RST_N, power); + assert(err == 0); +#endif +} + Panda::Panda(){ int err; @@ -39,8 +62,10 @@ Panda::Panda(){ is_pigeon = (hw_type == cereal::HealthData::HwType::GREY_PANDA) || (hw_type == cereal::HealthData::HwType::BLACK_PANDA) || - (hw_type == cereal::HealthData::HwType::UNO); - has_rtc = (hw_type == cereal::HealthData::HwType::UNO); + (hw_type == cereal::HealthData::HwType::UNO) || + (hw_type == cereal::HealthData::HwType::DOS); + has_rtc = (hw_type == cereal::HealthData::HwType::UNO) || + (hw_type == cereal::HealthData::HwType::DOS); return; diff --git a/selfdrive/boardd/panda.h b/selfdrive/boardd/panda.h index 3586cda74f..c3e2dc981e 100644 --- a/selfdrive/boardd/panda.h +++ b/selfdrive/boardd/panda.h @@ -34,6 +34,9 @@ struct __attribute__((packed)) health_t { uint8_t power_save_enabled; }; + +void panda_set_power(bool power); + class Panda { private: libusb_context *ctx = NULL; diff --git a/selfdrive/boardd/pigeon.cc b/selfdrive/boardd/pigeon.cc new file mode 100644 index 0000000000..4ec7ebf8ce --- /dev/null +++ b/selfdrive/boardd/pigeon.cc @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include + +#include "common/swaglog.h" +#include "common/gpio.h" + +#include "pigeon.h" + +// Termios on macos doesn't define all baud rate constants +#ifndef B460800 +#define B460800 0010004 +#endif + +using namespace std::string_literals; + + +Pigeon * Pigeon::connect(Panda * p){ + PandaPigeon * pigeon = new PandaPigeon(); + pigeon->connect(p); + + return pigeon; +} + +Pigeon * Pigeon::connect(const char * tty){ + TTYPigeon * pigeon = new TTYPigeon(); + pigeon->connect(tty); + + return pigeon; +} + +void Pigeon::init() { + usleep(1000*1000); + LOGW("panda GPS start"); + + // power off pigeon + set_power(0); + usleep(100*1000); + + // 9600 baud at init + set_baud(9600); + + // power on pigeon + set_power(1); + usleep(500*1000); + + // baud rate upping + send("\x24\x50\x55\x42\x58\x2C\x34\x31\x2C\x31\x2C\x30\x30\x30\x37\x2C\x30\x30\x30\x33\x2C\x34\x36\x30\x38\x30\x30\x2C\x30\x2A\x31\x35\x0D\x0A"s); + usleep(100*1000); + + // set baud rate to 460800 + set_baud(460800); + usleep(100*1000); + + // init from ubloxd + // To generate this data, run test/ubloxd.py with the print statements enabled in the write function in panda/python/serial.py + send("\xB5\x62\x06\x00\x14\x00\x03\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x01\x00\x00\x00\x00\x00\x1E\x7F"s); + send("\xB5\x62\x06\x3E\x00\x00\x44\xD2"s); + send("\xB5\x62\x06\x00\x14\x00\x00\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x19\x35"s); + send("\xB5\x62\x06\x00\x14\x00\x01\x00\x00\x00\xC0\x08\x00\x00\x00\x08\x07\x00\x01\x00\x01\x00\x00\x00\x00\x00\xF4\x80"s); + send("\xB5\x62\x06\x00\x14\x00\x04\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1D\x85"s); + send("\xB5\x62\x06\x00\x00\x00\x06\x18"s); + send("\xB5\x62\x06\x00\x01\x00\x01\x08\x22"s); + send("\xB5\x62\x06\x00\x01\x00\x02\x09\x23"s); + send("\xB5\x62\x06\x00\x01\x00\x03\x0A\x24"s); + send("\xB5\x62\x06\x08\x06\x00\x64\x00\x01\x00\x00\x00\x79\x10"s); + send("\xB5\x62\x06\x24\x24\x00\x05\x00\x04\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x5A\x63"s); + send("\xB5\x62\x06\x1E\x14\x00\x00\x00\x00\x00\x01\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x3C\x37"s); + send("\xB5\x62\x06\x24\x00\x00\x2A\x84"s); + send("\xB5\x62\x06\x23\x00\x00\x29\x81"s); + send("\xB5\x62\x06\x1E\x00\x00\x24\x72"s); + send("\xB5\x62\x06\x01\x03\x00\x01\x07\x01\x13\x51"s); + send("\xB5\x62\x06\x01\x03\x00\x02\x15\x01\x22\x70"s); + send("\xB5\x62\x06\x01\x03\x00\x02\x13\x01\x20\x6C"s); + send("\xB5\x62\x06\x01\x03\x00\x0A\x09\x01\x1E\x70"s); + + LOGW("panda GPS on"); +} + +void PandaPigeon::connect(Panda * p) { + panda = p; +} + +void PandaPigeon::set_baud(int baud) { + panda->usb_write(0xe2, 1, 0); + panda->usb_write(0xe4, 1, baud/300); +} + +void PandaPigeon::send(std::string s) { + int len = s.length(); + const char * dat = s.data(); + + unsigned char a[0x20+1]; + a[0] = 1; + for (int i=0; iusb_bulk_write(2, a, ll+1); + } +} + +std::string PandaPigeon::receive() { + std::string r; + + while (true){ + unsigned char dat[0x40]; + int len = panda->usb_read(0xe0, 1, 0, dat, sizeof(dat)); + if (len <= 0 || r.length() > 0x1000) break; + r.append((char*)dat, len); + } + + return r; +} + +void PandaPigeon::set_power(bool power) { + panda->usb_write(0xd9, power, 0); +} + +PandaPigeon::~PandaPigeon(){ +} + +void handle_tty_issue(int err, const char func[]) { + LOGE_100("tty error %d \"%s\" in %s", err, strerror(err), func); +} + +void TTYPigeon::connect(const char * tty) { + pigeon_tty_fd = open(tty, O_RDWR); + if (pigeon_tty_fd < 0){ + handle_tty_issue(errno, __func__); + assert(pigeon_tty_fd >= 0); + } + assert(tcgetattr(pigeon_tty_fd, &pigeon_tty) == 0); + + // configure tty + pigeon_tty.c_cflag &= ~PARENB; // disable parity + pigeon_tty.c_cflag &= ~CSTOPB; // single stop bit + pigeon_tty.c_cflag |= CS8; // 8 bits per byte + pigeon_tty.c_cflag &= ~CRTSCTS; // no RTS/CTS flow control + pigeon_tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines + pigeon_tty.c_lflag &= ~ICANON; // disable canonical mode + pigeon_tty.c_lflag &= ~ISIG; // disable interpretation of INTR, QUIT and SUSP + pigeon_tty.c_iflag &= ~(IXON | IXOFF | IXANY); // turn off software flow ctrl + pigeon_tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // disable any special handling of received bytes + pigeon_tty.c_oflag &= ~OPOST; // prevent special interpretation of output bytes + pigeon_tty.c_oflag &= ~ONLCR; // prevent conversion of newline to carriage return/line feed + + // configure blocking behavior + pigeon_tty.c_cc[VMIN] = 0; // min amount of characters returned + pigeon_tty.c_cc[VTIME] = 0; // max blocking time in s/10 (0=inf) + + assert(tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty) == 0); +} + +void TTYPigeon::set_baud(int baud){ + speed_t baud_const = 0; + switch(baud){ + case 9600: + baud_const = B9600; + break; + case 460800: + baud_const = B460800; + break; + default: + assert(false); + } + + // make sure everything is tx'ed before changing baud + assert(tcdrain(pigeon_tty_fd) == 0); + + // change baud + assert(tcgetattr(pigeon_tty_fd, &pigeon_tty) == 0); + assert(cfsetspeed(&pigeon_tty, baud_const) == 0); + assert(tcsetattr(pigeon_tty_fd, TCSANOW, &pigeon_tty) == 0); + + // flush + assert(tcflush(pigeon_tty_fd, TCIOFLUSH) == 0); +} + +void TTYPigeon::send(std::string s) { + int len = s.length(); + const char * dat = s.data(); + + int err = write(pigeon_tty_fd, dat, len); + if(err < 0) { handle_tty_issue(err, __func__); } + err = tcdrain(pigeon_tty_fd); + if(err < 0) { handle_tty_issue(err, __func__); } +} + +std::string TTYPigeon::receive() { + std::string r; + + while (true){ + char dat[0x40]; + int len = read(pigeon_tty_fd, dat, sizeof(dat)); + if(len < 0) { + handle_tty_issue(len, __func__); + } else if (len == 0 || r.length() > 0x1000){ + break; + } else { + r.append(dat, len); + } + + } + return r; +} + +void TTYPigeon::set_power(bool power){ +#ifdef QCOM2 + int err = 0; + err += gpio_init(GPIO_UBLOX_RST_N, true); + err += gpio_init(GPIO_UBLOX_SAFEBOOT_N, true); + err += gpio_init(GPIO_UBLOX_PWR_EN, true); + + err += gpio_set(GPIO_UBLOX_RST_N, power); + err += gpio_set(GPIO_UBLOX_SAFEBOOT_N, power); + err += gpio_set(GPIO_UBLOX_PWR_EN, power); + assert(err == 0); +#endif +} + +TTYPigeon::~TTYPigeon(){ + close(pigeon_tty_fd); +} diff --git a/selfdrive/boardd/pigeon.h b/selfdrive/boardd/pigeon.h new file mode 100644 index 0000000000..667ac70610 --- /dev/null +++ b/selfdrive/boardd/pigeon.h @@ -0,0 +1,43 @@ +#pragma once +#include +#include + + +#include "panda.h" + +class Pigeon { + public: + static Pigeon* connect(Panda * p); + static Pigeon* connect(const char * tty); + virtual ~Pigeon(){}; + + void init(); + virtual void set_baud(int baud) = 0; + virtual void send(std::string s) = 0; + virtual std::string receive() = 0; + virtual void set_power(bool power) = 0; +}; + +class PandaPigeon : public Pigeon { + Panda * panda = NULL; +public: + ~PandaPigeon(); + void connect(Panda * p); + void set_baud(int baud); + void send(std::string s); + std::string receive(); + void set_power(bool power); +}; + + +class TTYPigeon : public Pigeon { + int pigeon_tty_fd = -1; + struct termios pigeon_tty; +public: + ~TTYPigeon(); + void connect(const char* tty); + void set_baud(int baud); + void send(std::string s); + std::string receive(); + void set_power(bool power); +}; diff --git a/selfdrive/common/SConscript b/selfdrive/common/SConscript index 8ecf786ffe..0ba5b1abcc 100644 --- a/selfdrive/common/SConscript +++ b/selfdrive/common/SConscript @@ -5,7 +5,7 @@ if SHARED: else: fxn = env.Library -_common = fxn('common', ['params.cc', 'swaglog.cc', 'util.c', 'cqueue.c'], LIBS="json11") +_common = fxn('common', ['params.cc', 'swaglog.cc', 'util.c', 'cqueue.c', 'gpio.cc'], LIBS="json11") _visionipc = fxn('visionipc', ['visionipc.c', 'ipc.c']) files = [ @@ -42,4 +42,3 @@ else: _gpucommon = fxn('gpucommon', files, CPPDEFINES=defines, LIBS=_gpu_libs) Export('_common', '_visionipc', '_gpucommon', '_gpu_libs') - diff --git a/selfdrive/common/gpio.cc b/selfdrive/common/gpio.cc new file mode 100644 index 0000000000..7b080b0c50 --- /dev/null +++ b/selfdrive/common/gpio.cc @@ -0,0 +1,75 @@ +#include "gpio.h" +#include +#include +#include + +// We assume that all pins have already been exported on boot, +// and that we have permission to write to them. + +int gpio_init(int pin_nr, bool output){ + int ret = 0; + int fd, tmp; + + char pin_dir_path[50]; + int pin_dir_path_len = snprintf(pin_dir_path, sizeof(pin_dir_path), + "/sys/class/gpio/gpio%d/direction", pin_nr); + if(pin_dir_path_len <= 0){ + ret = -1; + goto cleanup; + } + + fd = open(pin_dir_path, O_WRONLY); + if(fd == -1){ + ret = -1; + goto cleanup; + } + if(output){ + tmp = write(fd, "out", 3); + if(tmp != 3){ + ret = -1; + goto cleanup; + } + } else { + tmp = write(fd, "in", 2); + if(tmp != 2){ + ret = -1; + goto cleanup; + } + } + +cleanup: + if(fd >= 0){ + close(fd); + } + return ret; +} + +int gpio_set(int pin_nr, bool high){ + int ret = 0; + int fd, tmp; + + char pin_val_path[50]; + int pin_val_path_len = snprintf(pin_val_path, sizeof(pin_val_path), + "/sys/class/gpio/gpio%d/value", pin_nr); + if(pin_val_path_len <= 0){ + ret = -1; + goto cleanup; + } + + fd = open(pin_val_path, O_WRONLY); + if(fd == -1){ + ret = -1; + goto cleanup; + } + tmp = write(fd, high ? "1" : "0", 1); + if(tmp != 1){ + ret = -1; + goto cleanup; + } + +cleanup: + if(fd >= 0){ + close(fd); + } + return ret; +} diff --git a/selfdrive/common/gpio.h b/selfdrive/common/gpio.h new file mode 100644 index 0000000000..479b4f7e06 --- /dev/null +++ b/selfdrive/common/gpio.h @@ -0,0 +1,35 @@ +#ifndef GPIO_H +#define GPIO_H + +#include + +// Pin definitions +#ifdef QCOM2 + #define GPIO_HUB_RST_N 30 + #define GPIO_UBLOX_RST_N 32 + #define GPIO_UBLOX_SAFEBOOT_N 33 + #define GPIO_UBLOX_PWR_EN 34 + #define GPIO_STM_RST_N 124 + #define GPIO_STM_BOOT0 134 +#else + #define GPIO_HUB_RST_N 0 + #define GPIO_UBLOX_RST_N 0 + #define GPIO_UBLOX_SAFEBOOT_N 0 + #define GPIO_UBLOX_PWR_EN 0 + #define GPIO_STM_RST_N 0 + #define GPIO_STM_BOOT0 0 +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +int gpio_init(int pin_nr, bool output); +int gpio_set(int pin_nr, bool high); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif diff --git a/selfdrive/debug/dump.py b/selfdrive/debug/dump.py index cfdb387b91..112ca96a93 100755 --- a/selfdrive/debug/dump.py +++ b/selfdrive/debug/dump.py @@ -61,4 +61,11 @@ if __name__ == "__main__": print("{} = {}".format(".".join(value), item)) print("") else: - print(evt) + try: + print(evt) + except UnicodeDecodeError: + w = evt.which() + s = f"( logMonoTime {evt.logMonoTime} \n {w} = " + s += str(evt.__getattr__(w)) + s += f"\n valid = {evt.valid} )" + print(s)