├── .circleci └── config.yml ├── .dockerignore ├── .gitignore ├── Dockerfile ├── Jenkinsfile ├── LICENSE ├── README.md ├── TODO ├── UPDATING.md ├── VERSION ├── __init__.py ├── board ├── Makefile ├── README.md ├── __init__.py ├── board.h ├── board_declarations.h ├── boards │ ├── black.h │ ├── common.h │ ├── grey.h │ ├── pedal.h │ ├── uno.h │ └── white.h ├── bootstub.c ├── build.mk ├── config.h ├── crc.h ├── critical.h ├── drivers │ ├── adc.h │ ├── can.h │ ├── clock.h │ ├── dac.h │ ├── fan.h │ ├── gmlan_alt.h │ ├── harness.h │ ├── interrupts.h │ ├── llcan.h │ ├── llgpio.h │ ├── pwm.h │ ├── registers.h │ ├── rtc.h │ ├── spi.h │ ├── timer.h │ ├── uart.h │ └── usb.h ├── faults.h ├── get_sdk.sh ├── get_sdk_mac.sh ├── gpio.h ├── inc │ ├── cmsis_compiler.h │ ├── cmsis_gcc.h │ ├── cmsis_version.h │ ├── core_cm3.h │ ├── core_cm4.h │ ├── mpu_armv7.h │ ├── stm32f205xx.h │ ├── stm32f2xx.h │ ├── stm32f2xx_hal_def.h │ ├── stm32f2xx_hal_gpio_ex.h │ ├── stm32f413xx.h │ ├── stm32f4xx.h │ ├── stm32f4xx_hal_def.h │ ├── stm32f4xx_hal_gpio_ex.h │ ├── system_stm32f2xx.h │ └── system_stm32f4xx.h ├── libc.h ├── main.c ├── main_declarations.h ├── obj │ └── .placeholder ├── pedal │ ├── .gitignore │ ├── Makefile │ ├── README │ ├── main.c │ ├── main_declarations.h │ └── obj │ │ └── .gitkeep ├── power_saving.h ├── provision.h ├── safety.h ├── safety │ ├── safety_cadillac.h │ ├── safety_chrysler.h │ ├── safety_defaults.h │ ├── safety_elm327.h │ ├── safety_ford.h │ ├── safety_gm.h │ ├── safety_gm_ascm.h │ ├── safety_honda.h │ ├── safety_hyundai.h │ ├── safety_mazda.h │ ├── safety_nissan.h │ ├── safety_subaru.h │ ├── safety_tesla.h │ ├── safety_toyota.h │ └── safety_volkswagen.h ├── safety_declarations.h ├── spi_flasher.h ├── startup_stm32f205xx.s ├── startup_stm32f413xx.s ├── stm32_flash.ld ├── tests │ └── test_rsa.c └── tools │ ├── dfu-util-aarch64 │ ├── dfu-util-aarch64-linux │ ├── dfu-util-x86_64-linux │ └── enter_download_mode.py ├── boardesp ├── .gitignore ├── ELM327.md ├── Makefile ├── README.md ├── elm327.c ├── get_sdk.sh ├── get_sdk_ci.sh ├── get_sdk_mac.sh ├── include │ └── espmissingincludes.h ├── obj │ └── .placeholder ├── proxy.c ├── python2_make.py ├── user_config.h └── webserver.c ├── buy.png ├── certs ├── debug ├── debug.pub ├── debugesp ├── debugesp.pub ├── release.pub └── releaseesp.pub ├── common └── version.mk ├── crypto ├── getcertheader.py ├── hash-internal.h ├── rsa.c ├── rsa.h ├── sha.c ├── sha.h ├── sign.py └── stdint.h ├── docs ├── guide.pdf └── panda_wifi_setup.md ├── drivers ├── linux │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── dkms.conf │ ├── panda.c │ └── test │ │ ├── Makefile │ │ ├── main.c │ │ └── run.sh └── windows │ ├── .gitignore │ ├── ECUsim CLI │ ├── ECUsim CLI.cpp │ ├── ECUsim CLI.vcxproj │ ├── ECUsim CLI.vcxproj.filters │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h │ ├── ECUsim DLL │ ├── ECUsim DLL.vcxproj │ ├── ECUsim DLL.vcxproj.filters │ ├── ECUsim.cpp │ ├── ECUsim.h │ ├── dllmain.cpp │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h │ ├── README.md │ ├── docs │ ├── Message_Size.png │ ├── RxBits_defs.jpg │ ├── RxBits_valid.png │ ├── bus_init_signla.png │ ├── connection_flags.png │ ├── iso15765_ioctls.png │ ├── message_send.png │ ├── msg_filter_passfail.png │ ├── other notes.txt │ ├── read_msg_flags.png │ ├── reginfo.txt │ ├── start_msg_filter.png │ ├── start_msg_filter2.png │ ├── start_msg_filter3.png │ ├── start_msg_filter4.png │ └── timeout_info.txt │ ├── panda Driver Package │ ├── panda Driver Package.vcxproj │ ├── panda Driver Package.vcxproj.filters │ └── panda.inf │ ├── panda.ico │ ├── panda.sln │ ├── panda │ ├── dllmain.cpp │ ├── main.cpp │ ├── panda.ico │ ├── panda.rc │ ├── panda.vcxproj │ ├── panda.vcxproj.filters │ ├── resource.h │ ├── stdafx.cpp │ └── stdafx.h │ ├── pandaJ2534DLL Test │ ├── ECUsim_tests.cpp │ ├── Loader4.cpp │ ├── Loader4.h │ ├── TestHelpers.cpp │ ├── TestHelpers.h │ ├── Timer.cpp │ ├── Timer.h │ ├── j2534_tests.cpp │ ├── pandaJ2534DLL Test.vcxproj │ ├── pandaJ2534DLL Test.vcxproj.filters │ ├── panda_tests.cpp │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h │ ├── pandaJ2534DLL │ ├── Action.h │ ├── J2534Connection.cpp │ ├── J2534Connection.h │ ├── J2534Connection_CAN.cpp │ ├── J2534Connection_CAN.h │ ├── J2534Connection_ISO15765.cpp │ ├── J2534Connection_ISO15765.h │ ├── J2534Frame.h │ ├── J2534MessageFilter.cpp │ ├── J2534MessageFilter.h │ ├── J2534_v0404.h │ ├── J2534register_x64.reg │ ├── MessagePeriodic.cpp │ ├── MessagePeriodic.h │ ├── MessageRx.h │ ├── MessageTx.h │ ├── MessageTxTimeout.cpp │ ├── MessageTxTimeout.h │ ├── MessageTx_CAN.cpp │ ├── MessageTx_CAN.h │ ├── MessageTx_ISO15765.cpp │ ├── MessageTx_ISO15765.h │ ├── PandaJ2534Device.cpp │ ├── PandaJ2534Device.h │ ├── Timer.cpp │ ├── Timer.h │ ├── constants_ISO15765.h │ ├── dllmain.cpp │ ├── dllmain.h │ ├── pandaJ2534DLL.cpp │ ├── pandaJ2534DLL.rc │ ├── pandaJ2534DLL.vcxproj │ ├── pandaJ2534DLL.vcxproj.filters │ ├── resource.h │ ├── stdafx.cpp │ ├── stdafx.h │ ├── synchronize.h │ └── targetver.h │ ├── panda_install.nsi │ ├── panda_playground │ ├── ReadMe.txt │ ├── panda_playground.cpp │ ├── panda_playground.vcxproj │ ├── panda_playground.vcxproj.filters │ ├── stdafx.cpp │ ├── stdafx.h │ └── targetver.h │ ├── panda_remove.ico │ ├── panda_shared │ ├── device.cpp │ ├── device.h │ ├── panda.cpp │ ├── panda.h │ ├── panda_shared.vcxitems │ └── targetver.h │ ├── redist │ ├── .gitignore │ ├── README.md │ └── vscruntimeinfo.nsh.sample │ └── test certs │ ├── commaaiCertStore.pvk │ └── commaaicert.cer ├── examples ├── __init__.py ├── can_bit_transition.md ├── can_bit_transition.py ├── can_logger.py ├── can_unique.md ├── can_unique.py ├── get_panda_password.py ├── query_fw_versions.py ├── query_vin_and_stats.py └── tesla_tester.py ├── panda.png ├── python ├── __init__.py ├── dfu.py ├── esptool.py ├── flash_release.py ├── isotp.py ├── serial.py ├── uds.py └── update.py ├── release ├── .gitignore ├── make_release.sh └── ota_release.sh ├── requirements.txt ├── run_automated_tests.sh ├── setup.cfg ├── setup.py └── tests ├── __init__.py ├── all_wifi_test.py ├── automated ├── 0_builds.py ├── 1_program.py ├── 2_health.py ├── 3_usb_to_can.py ├── 4_wifi.py ├── 5_wifi_functionality.py ├── 6_wifi_udp.py ├── 7_can_loopback.py ├── 8_gps.py ├── __init__.py ├── helpers.py ├── timeout.py └── wifi_helpers.py ├── black_loopback_test.py ├── black_white_loopback_test.py ├── black_white_relay_endurance.py ├── black_white_relay_test.py ├── build └── Dockerfile ├── can_printer.py ├── debug_console.py ├── development └── register_hashmap_spread.py ├── disable_esp.py ├── echo.py ├── elm_car_simulator.py ├── elm_throughput.py ├── elm_wifi.py ├── fan_test.py ├── flashing_loop.sh ├── get_version.py ├── gmbitbang ├── recv.py ├── rigol.py ├── test.py ├── test_one.py └── test_packer.c ├── gps_stability_test.py ├── health_test.py ├── ir_test.py ├── language ├── Dockerfile ├── LICENSE ├── list.txt └── test_language.py ├── linter_python ├── .pylintrc ├── Dockerfile ├── flake8_panda.sh └── pylint_panda.sh ├── location_listener.py ├── loopback_test.py ├── misra ├── .gitignore ├── Dockerfile ├── coverage_table ├── suppressions.txt └── test_misra.sh ├── pedal └── enter_canloader.py ├── read_st_flash.sh ├── read_winusb_descriptors.py ├── rtc_test.py ├── safety ├── Dockerfile ├── Makefile ├── __init__.py ├── common.py ├── libpandasafety_py.py ├── test.c ├── test.sh ├── test_cadillac.py ├── test_chrysler.py ├── test_gm.py ├── test_honda.py ├── test_hyundai.py ├── test_nissan.py ├── test_subaru.py ├── test_toyota.py ├── test_volkswagen_mqb.py └── test_volkswagen_pq.py ├── safety_replay ├── Dockerfile ├── __init__.py ├── helpers.py ├── install_capnp.sh ├── replay_drive.py ├── requirements_extra.txt └── test_safety_replay.py ├── spam_can.py ├── standalone_test.py ├── throughput_test.py └── tucan_loopback.py /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | .DS_Store 3 | boardesp/esp-open-sdk 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .*.swp 3 | .*.swo 4 | *.o 5 | *.so 6 | *.d 7 | *.dump 8 | a.out 9 | *~ 10 | .#* 11 | dist/ 12 | pandacan.egg-info/ 13 | board/obj/ 14 | examples/output.csv 15 | .DS_Store 16 | .vscode 17 | nosetests.xml 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | ENV PYTHONUNBUFFERED 1 3 | 4 | RUN apt-get update && apt-get install -y \ 5 | autoconf \ 6 | automake \ 7 | bash \ 8 | bison \ 9 | bzip2 \ 10 | curl \ 11 | dfu-util \ 12 | flex \ 13 | g++ \ 14 | gawk \ 15 | gcc \ 16 | git \ 17 | gperf \ 18 | help2man \ 19 | iputils-ping \ 20 | libbz2-dev \ 21 | libexpat-dev \ 22 | libffi-dev \ 23 | libssl-dev \ 24 | libstdc++-arm-none-eabi-newlib \ 25 | libtool \ 26 | libtool-bin \ 27 | libusb-1.0-0 \ 28 | locales \ 29 | make \ 30 | ncurses-dev \ 31 | network-manager \ 32 | python-dev \ 33 | python-serial \ 34 | sed \ 35 | texinfo \ 36 | unrar-free \ 37 | unzip \ 38 | wget \ 39 | build-essential \ 40 | python-dev \ 41 | python-pip \ 42 | screen \ 43 | vim \ 44 | wget \ 45 | wireless-tools \ 46 | zlib1g-dev 47 | 48 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 49 | ENV LANG en_US.UTF-8 50 | ENV LANGUAGE en_US:en 51 | ENV LC_ALL en_US.UTF-8 52 | 53 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 54 | 55 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 56 | RUN pyenv install 3.7.3 57 | RUN pyenv install 2.7.12 58 | RUN pyenv global 3.7.3 59 | RUN pyenv rehash 60 | 61 | RUN pip install --upgrade pip==18.0 62 | 63 | COPY requirements.txt /tmp/ 64 | RUN pip install -r /tmp/requirements.txt 65 | 66 | RUN mkdir -p /home/batman 67 | ENV HOME /home/batman 68 | 69 | ENV PYTHONPATH /tmp:$PYTHONPATH 70 | 71 | COPY ./boardesp/get_sdk_ci.sh /tmp/panda/boardesp/ 72 | COPY ./boardesp/python2_make.py /tmp/panda/boardesp/ 73 | 74 | COPY ./panda_jungle /tmp/panda_jungle 75 | 76 | RUN useradd --system -s /sbin/nologin pandauser 77 | RUN mkdir -p /tmp/panda/boardesp/esp-open-sdk 78 | RUN chown pandauser /tmp/panda/boardesp/esp-open-sdk 79 | USER pandauser 80 | RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh 81 | USER root 82 | 83 | ADD ./panda.tar.gz /tmp/panda 84 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016, Comma.ai, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | ** Projects ** 2 | 3 | == ELM327 Emulator == 4 | 5 | Write an elm327 emulator in boardesp/elm327.c and make it work with Torque 6 | 7 | You'll find a start at this in the "elm327" branch. 8 | 9 | == socketcan Kernel Driver == 10 | 11 | Write a kernel driver version of lib/panda.py that exposes the Panda on socketcan and makes it work with those tools. 12 | 13 | You may want to switch to interrupt endpoint first. Should LIN be exposed as a serial interface? 14 | 15 | == Windows J2534 DLL == 16 | 17 | Write a Windows DLL that exposes the J2534 API. 18 | 19 | Will make the Panda work with car diagnostic software. 20 | 21 | 22 | ** Refactors ** 23 | 24 | == USB Interrupt Endpoint == 25 | 26 | Switch USB to use an interrupt endpoint instead of a bulk endpoint for can recv 27 | 28 | == WebSocket Support == 29 | 30 | Add CAN streaming over WebSocket to the ELM code in addition to the UDP pipe. 31 | 32 | -------------------------------------------------------------------------------- /UPDATING.md: -------------------------------------------------------------------------------- 1 | # Updating your panda 2 | 3 | Panda should update automatically via the [openpilot](http://openpilot.comma.ai/). 4 | 5 | On Linux or Mac OSX, you can manually update it using: 6 | ``` 7 | sudo pip install --upgrade pandacan` 8 | PYTHONPATH="" sudo python -c "import panda; panda.flash_release()"` 9 | ``` 10 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | v1.7.4 -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from .python import Panda, PandaWifiStreaming, PandaDFU, ESPROM, CesantaFlasher, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial # noqa: F401 2 | -------------------------------------------------------------------------------- /board/Makefile: -------------------------------------------------------------------------------- 1 | PROJ_NAME = panda 2 | CFLAGS = -g -Wall -Wextra -Wstrict-prototypes -Werror 3 | 4 | CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 5 | CFLAGS += -mhard-float -DSTM32F4 -DSTM32F413xx -mfpu=fpv4-sp-d16 -fsingle-precision-constant 6 | STARTUP_FILE = startup_stm32f413xx 7 | 8 | include build.mk 9 | -------------------------------------------------------------------------------- /board/README.md: -------------------------------------------------------------------------------- 1 | Dependencies 2 | -------- 3 | 4 | **Mac** 5 | 6 | ``` 7 | xcode-select --install 8 | ./get_sdk_mac.sh 9 | ``` 10 | 11 | **Debian / Ubuntu** 12 | 13 | ``` 14 | ./get_sdk.sh 15 | ``` 16 | 17 | 18 | Programming 19 | ---- 20 | 21 | **Panda** 22 | 23 | ``` 24 | make 25 | ``` 26 | 27 | Troubleshooting 28 | ---- 29 | 30 | If your panda will not flash and is quickly blinking a single Green LED, use: 31 | ``` 32 | make recover 33 | ``` 34 | 35 | 36 | [dfu-util](http://github.com/dsigma/dfu-util.git) for flashing 37 | -------------------------------------------------------------------------------- /board/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/__init__.py -------------------------------------------------------------------------------- /board/board_declarations.h: -------------------------------------------------------------------------------- 1 | // ******************** Prototypes ******************** 2 | typedef void (*board_init)(void); 3 | typedef void (*board_enable_can_transciever)(uint8_t transciever, bool enabled); 4 | typedef void (*board_enable_can_transcievers)(bool enabled); 5 | typedef void (*board_set_led)(uint8_t color, bool enabled); 6 | typedef void (*board_set_usb_power_mode)(uint8_t mode); 7 | typedef void (*board_set_esp_gps_mode)(uint8_t mode); 8 | typedef void (*board_set_can_mode)(uint8_t mode); 9 | typedef void (*board_usb_power_mode_tick)(uint32_t uptime); 10 | typedef bool (*board_check_ignition)(void); 11 | typedef uint32_t (*board_read_current)(void); 12 | typedef void (*board_set_ir_power)(uint8_t percentage); 13 | typedef void (*board_set_fan_power)(uint8_t percentage); 14 | typedef void (*board_set_phone_power)(bool enabled); 15 | 16 | struct board { 17 | const char *board_type; 18 | const harness_configuration *harness_config; 19 | board_init init; 20 | board_enable_can_transciever enable_can_transciever; 21 | board_enable_can_transcievers enable_can_transcievers; 22 | board_set_led set_led; 23 | board_set_usb_power_mode set_usb_power_mode; 24 | board_set_esp_gps_mode set_esp_gps_mode; 25 | board_set_can_mode set_can_mode; 26 | board_usb_power_mode_tick usb_power_mode_tick; 27 | board_check_ignition check_ignition; 28 | board_read_current read_current; 29 | board_set_ir_power set_ir_power; 30 | board_set_fan_power set_fan_power; 31 | board_set_phone_power set_phone_power; 32 | }; 33 | 34 | // ******************* Definitions ******************** 35 | // These should match the enums in cereal/log.capnp and __init__.py 36 | #define HW_TYPE_UNKNOWN 0U 37 | #define HW_TYPE_WHITE_PANDA 1U 38 | #define HW_TYPE_GREY_PANDA 2U 39 | #define HW_TYPE_BLACK_PANDA 3U 40 | #define HW_TYPE_PEDAL 4U 41 | #define HW_TYPE_UNO 5U 42 | 43 | // LED colors 44 | #define LED_RED 0U 45 | #define LED_GREEN 1U 46 | #define LED_BLUE 2U 47 | 48 | // USB power modes (from cereal.log.health) 49 | #define USB_POWER_NONE 0U 50 | #define USB_POWER_CLIENT 1U 51 | #define USB_POWER_CDP 2U 52 | #define USB_POWER_DCP 3U 53 | 54 | // ESP modes 55 | #define ESP_GPS_DISABLED 0U 56 | #define ESP_GPS_ENABLED 1U 57 | #define ESP_GPS_BOOTMODE 2U 58 | 59 | // CAN modes 60 | #define CAN_MODE_NORMAL 0U 61 | #define CAN_MODE_GMLAN_CAN2 1U 62 | #define CAN_MODE_GMLAN_CAN3 2U 63 | #define CAN_MODE_OBD_CAN2 3U 64 | 65 | // ********************* Globals ********************** 66 | uint8_t usb_power_mode = USB_POWER_NONE; 67 | 68 | // ************ Board function prototypes ************* 69 | bool board_has_gps(void); 70 | bool board_has_gmlan(void); 71 | bool board_has_obd(void); 72 | bool board_has_lin(void); 73 | bool board_has_rtc(void); 74 | bool board_has_relay(void); -------------------------------------------------------------------------------- /board/boards/grey.h: -------------------------------------------------------------------------------- 1 | // ////////// // 2 | // Grey Panda // 3 | // ////////// // 4 | 5 | // Most hardware functionality is similar to white panda 6 | 7 | void grey_init(void) { 8 | white_grey_common_init(); 9 | 10 | // Set default state of GPS 11 | current_board->set_esp_gps_mode(ESP_GPS_ENABLED); 12 | } 13 | 14 | void grey_set_esp_gps_mode(uint8_t mode) { 15 | switch (mode) { 16 | case ESP_GPS_DISABLED: 17 | // GPS OFF 18 | set_gpio_output(GPIOC, 14, 0); 19 | set_gpio_output(GPIOC, 5, 0); 20 | break; 21 | case ESP_GPS_ENABLED: 22 | // GPS ON 23 | set_gpio_output(GPIOC, 14, 1); 24 | set_gpio_output(GPIOC, 5, 1); 25 | break; 26 | case ESP_GPS_BOOTMODE: 27 | set_gpio_output(GPIOC, 14, 1); 28 | set_gpio_output(GPIOC, 5, 0); 29 | break; 30 | default: 31 | puts("Invalid ESP/GPS mode\n"); 32 | break; 33 | } 34 | } 35 | 36 | const board board_grey = { 37 | .board_type = "Grey", 38 | .harness_config = &white_harness_config, 39 | .init = grey_init, 40 | .enable_can_transciever = white_enable_can_transciever, 41 | .enable_can_transcievers = white_enable_can_transcievers, 42 | .set_led = white_set_led, 43 | .set_usb_power_mode = white_set_usb_power_mode, 44 | .set_esp_gps_mode = grey_set_esp_gps_mode, 45 | .set_can_mode = white_set_can_mode, 46 | .usb_power_mode_tick = white_usb_power_mode_tick, 47 | .check_ignition = white_check_ignition, 48 | .read_current = white_read_current, 49 | .set_fan_power = white_set_fan_power, 50 | .set_ir_power = white_set_ir_power, 51 | .set_phone_power = white_set_phone_power 52 | }; -------------------------------------------------------------------------------- /board/build.mk: -------------------------------------------------------------------------------- 1 | CFLAGS += -I inc -I ../ -nostdlib -fno-builtin -std=gnu11 -Os 2 | 3 | CFLAGS += -Tstm32_flash.ld 4 | 5 | DFU_UTIL = "dfu-util" 6 | 7 | # Compile fast charge (DCP) only not on EON 8 | ifeq (,$(wildcard /EON)) 9 | BUILDER = DEV 10 | else 11 | CFLAGS += "-DEON" 12 | BUILDER = EON 13 | DFU_UTIL = "tools/dfu-util-aarch64" 14 | endif 15 | 16 | CC = arm-none-eabi-gcc 17 | OBJCOPY = arm-none-eabi-objcopy 18 | OBJDUMP = arm-none-eabi-objdump 19 | 20 | ifeq ($(RELEASE),1) 21 | CERT = ../../pandaextra/certs/release 22 | else 23 | # enable the debug cert 24 | CERT = ../certs/debug 25 | CFLAGS += "-DALLOW_DEBUG" 26 | endif 27 | 28 | 29 | DEPDIR = generated_dependencies 30 | $(shell mkdir -p -m 777 $(DEPDIR) >/dev/null) 31 | DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td 32 | POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@ 33 | 34 | # this no longer pushes the bootstub 35 | flash: obj/$(PROJ_NAME).bin 36 | PYTHONPATH=../ python3 -c "from python import Panda; Panda().flash('obj/$(PROJ_NAME).bin')" 37 | 38 | ota: obj/$(PROJ_NAME).bin 39 | curl http://192.168.0.10/stupdate --upload-file $< 40 | 41 | bin: obj/$(PROJ_NAME).bin 42 | 43 | # this flashes everything 44 | recover: obj/bootstub.$(PROJ_NAME).bin obj/$(PROJ_NAME).bin 45 | -PYTHONPATH=../ python3 -c "from python import Panda; Panda().reset(enter_bootloader=True)" 46 | sleep 1.0 47 | $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin 48 | $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.$(PROJ_NAME).bin 49 | 50 | include ../common/version.mk 51 | 52 | obj/cert.h: ../crypto/getcertheader.py 53 | ../crypto/getcertheader.py ../certs/debug.pub ../certs/release.pub > $@ 54 | 55 | obj/%.$(PROJ_NAME).o: %.c obj/gitversion.h obj/cert.h $(DEPDIR)/%.d 56 | $(CC) $(DEPFLAGS) $(CFLAGS) -o $@ -c $< 57 | $(POSTCOMPILE) 58 | 59 | obj/%.$(PROJ_NAME).o: ../crypto/%.c 60 | $(CC) $(CFLAGS) -o $@ -c $< 61 | 62 | obj/$(STARTUP_FILE).o: $(STARTUP_FILE).s 63 | $(CC) $(CFLAGS) -o $@ -c $< 64 | 65 | obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o 66 | # hack 67 | $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ 68 | $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin 69 | SETLEN=1 ../crypto/sign.py obj/code.bin $@ $(CERT) 70 | @BINSIZE=$$(du -b "obj/$(PROJ_NAME).bin" | cut -f 1) ; \ 71 | if [ $$BINSIZE -ge 49152 ]; then echo "ERROR obj/$(PROJ_NAME).bin is too big!"; exit 1; fi; 72 | 73 | obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o 74 | $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ 75 | $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ 76 | 77 | $(DEPDIR)/%.d: ; 78 | .PRECIOUS: $(DEPDIR)/%.d 79 | 80 | include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(wildcard *.c)))) 81 | 82 | clean: 83 | @$(RM) obj/* 84 | @rm -rf $(DEPDIR) 85 | -------------------------------------------------------------------------------- /board/config.h: -------------------------------------------------------------------------------- 1 | #ifndef PANDA_CONFIG_H 2 | #define PANDA_CONFIG_H 3 | 4 | //#define DEBUG 5 | //#define DEBUG_UART 6 | //#define DEBUG_USB 7 | //#define DEBUG_SPI 8 | //#define DEBUG_FAULTS 9 | 10 | #ifdef STM32F4 11 | #define PANDA 12 | #include "stm32f4xx.h" 13 | #else 14 | #include "stm32f2xx.h" 15 | #endif 16 | 17 | #define USB_VID 0xbbaaU 18 | 19 | #ifdef BOOTSTUB 20 | #define USB_PID 0xddeeU 21 | #else 22 | #define USB_PID 0xddccU 23 | #endif 24 | 25 | #include 26 | #define NULL ((void*)0) 27 | #define COMPILE_TIME_ASSERT(pred) ((void)sizeof(char[1 - (2 * ((int)(!(pred))))])) 28 | 29 | #define MIN(a,b) \ 30 | ({ __typeof__ (a) _a = (a); \ 31 | __typeof__ (b) _b = (b); \ 32 | (_a < _b) ? _a : _b; }) 33 | 34 | #define MAX(a,b) \ 35 | ({ __typeof__ (a) _a = (a); \ 36 | __typeof__ (b) _b = (b); \ 37 | (_a > _b) ? _a : _b; }) 38 | 39 | #define ABS(a) \ 40 | ({ __typeof__ (a) _a = (a); \ 41 | (_a > 0) ? _a : (-_a); }) 42 | 43 | #define MAX_RESP_LEN 0x40U 44 | 45 | // Around (1Mbps / 8 bits/byte / 12 bytes per message) 46 | #define CAN_INTERRUPT_RATE 12000U 47 | 48 | #endif 49 | 50 | -------------------------------------------------------------------------------- /board/crc.h: -------------------------------------------------------------------------------- 1 | uint8_t crc_checksum(uint8_t *dat, int len, const uint8_t poly) { 2 | uint8_t crc = 0xFF; 3 | int i, j; 4 | for (i = len - 1; i >= 0; i--) { 5 | crc ^= dat[i]; 6 | for (j = 0; j < 8; j++) { 7 | if ((crc & 0x80U) != 0U) { 8 | crc = (uint8_t)((crc << 1) ^ poly); 9 | } 10 | else { 11 | crc <<= 1; 12 | } 13 | } 14 | } 15 | return crc; 16 | } 17 | -------------------------------------------------------------------------------- /board/critical.h: -------------------------------------------------------------------------------- 1 | // ********************* Critical section helpers ********************* 2 | volatile bool interrupts_enabled = false; 3 | 4 | void enable_interrupts(void) { 5 | interrupts_enabled = true; 6 | __enable_irq(); 7 | } 8 | 9 | void disable_interrupts(void) { 10 | interrupts_enabled = false; 11 | __disable_irq(); 12 | } 13 | 14 | uint8_t global_critical_depth = 0U; 15 | #define ENTER_CRITICAL() \ 16 | __disable_irq(); \ 17 | global_critical_depth += 1U; 18 | 19 | #define EXIT_CRITICAL() \ 20 | global_critical_depth -= 1U; \ 21 | if ((global_critical_depth == 0U) && interrupts_enabled) { \ 22 | __enable_irq(); \ 23 | } 24 | -------------------------------------------------------------------------------- /board/drivers/adc.h: -------------------------------------------------------------------------------- 1 | // ACCEL1 = ADC10 2 | // ACCEL2 = ADC11 3 | // VOLT_S = ADC12 4 | // CURR_S = ADC13 5 | 6 | #define ADCCHAN_ACCEL0 10 7 | #define ADCCHAN_ACCEL1 11 8 | #define ADCCHAN_VOLTAGE 12 9 | #define ADCCHAN_CURRENT 13 10 | 11 | void adc_init(void) { 12 | register_set(&(ADC->CCR), ADC_CCR_TSVREFE | ADC_CCR_VBATE, 0xC30000U); 13 | register_set(&(ADC1->CR2), ADC_CR2_ADON, 0xFF7F0F03U); 14 | register_set(&(ADC1->SMPR1), ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13, 0x7FFFFFFU); 15 | } 16 | 17 | uint32_t adc_get(unsigned int channel) { 18 | // Select channel 19 | register_set(&(ADC1->JSQR), (channel << 15U), 0x3FFFFFU); 20 | 21 | // Start conversion 22 | ADC1->SR &= ~(ADC_SR_JEOC); 23 | ADC1->CR2 |= ADC_CR2_JSWSTART; 24 | while (!(ADC1->SR & ADC_SR_JEOC)); 25 | 26 | return ADC1->JDR1; 27 | } 28 | 29 | uint32_t adc_get_voltage(void) { 30 | // REVC has a 10, 1 (1/11) voltage divider 31 | // Here is the calculation for the scale (s) 32 | // ADCV = VIN_S * (1/11) * (4095/3.3) 33 | // RETVAL = ADCV * s = VIN_S*1000 34 | // s = 1000/((4095/3.3)*(1/11)) = 8.8623046875 35 | 36 | // Avoid needing floating point math, so output in mV 37 | return (adc_get(ADCCHAN_VOLTAGE) * 8862U) / 1000U; 38 | } 39 | -------------------------------------------------------------------------------- /board/drivers/clock.h: -------------------------------------------------------------------------------- 1 | void clock_init(void) { 2 | // enable external oscillator 3 | register_set_bits(&(RCC->CR), RCC_CR_HSEON); 4 | while ((RCC->CR & RCC_CR_HSERDY) == 0); 5 | 6 | // divide things 7 | register_set(&(RCC->CFGR), RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4, 0xFF7FFCF3U); 8 | 9 | // 16mhz crystal 10 | register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE, 0x7F437FFFU); 11 | 12 | // start PLL 13 | register_set_bits(&(RCC->CR), RCC_CR_PLLON); 14 | while ((RCC->CR & RCC_CR_PLLRDY) == 0); 15 | 16 | // Configure Flash prefetch, Instruction cache, Data cache and wait state 17 | // *** without this, it breaks *** 18 | register_set(&(FLASH->ACR), FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS, 0x1F0FU); 19 | 20 | // switch to PLL 21 | register_set_bits(&(RCC->CFGR), RCC_CFGR_SW_PLL); 22 | while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); 23 | 24 | // *** running on PLL *** 25 | } 26 | 27 | void watchdog_init(void) { 28 | // setup watchdog 29 | IWDG->KR = 0x5555U; 30 | register_set(&(IWDG->PR), 0x0U, 0x7U); // divider/4 31 | 32 | // 0 = 0.125 ms, let's have a 50ms watchdog 33 | register_set(&(IWDG->RLR), (400U-1U), 0xFFFU); 34 | IWDG->KR = 0xCCCCU; 35 | } 36 | 37 | void watchdog_feed(void) { 38 | IWDG->KR = 0xAAAAU; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /board/drivers/dac.h: -------------------------------------------------------------------------------- 1 | void puth(unsigned int i); 2 | void puts(const char *a); 3 | 4 | void dac_init(void) { 5 | // No buffers required since we have an opamp 6 | register_set(&(DAC->DHR12R1), 0U, 0xFFFU); 7 | register_set(&(DAC->DHR12R2), 0U, 0xFFFU); 8 | register_set(&(DAC->CR), DAC_CR_EN1 | DAC_CR_EN2, 0x3FFF3FFFU); 9 | } 10 | 11 | void dac_set(int channel, uint32_t value) { 12 | if (channel == 0) { 13 | register_set(&(DAC->DHR12R1), value, 0xFFFU); 14 | } else if (channel == 1) { 15 | register_set(&(DAC->DHR12R2), value, 0xFFFU); 16 | } else { 17 | puts("Failed to set DAC: invalid channel value: 0x"); puth(value); puts("\n"); 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /board/drivers/fan.h: -------------------------------------------------------------------------------- 1 | void fan_set_power(uint8_t percentage){ 2 | pwm_set(TIM3, 3, percentage); 3 | } 4 | 5 | uint16_t fan_tach_counter = 0U; 6 | uint16_t fan_rpm = 0U; 7 | 8 | // Can be way more acurate than this, but this is probably good enough for our purposes. 9 | 10 | // Call this every second 11 | void fan_tick(void){ 12 | // 4 interrupts per rotation 13 | fan_rpm = fan_tach_counter * 15U; 14 | fan_tach_counter = 0U; 15 | } 16 | 17 | // TACH interrupt handler 18 | void EXTI2_IRQ_Handler(void) { 19 | volatile unsigned int pr = EXTI->PR & (1U << 2); 20 | if ((pr & (1U << 2)) != 0U) { 21 | fan_tach_counter++; 22 | } 23 | EXTI->PR = (1U << 2); 24 | } 25 | 26 | void fan_init(void){ 27 | // 5000RPM * 4 tach edges / 60 seconds 28 | REGISTER_INTERRUPT(EXTI2_IRQn, EXTI2_IRQ_Handler, 700U, FAULT_INTERRUPT_RATE_TACH) 29 | 30 | // Init PWM speed control 31 | pwm_init(TIM3, 3); 32 | 33 | // Init TACH interrupt 34 | register_set(&(SYSCFG->EXTICR[0]), SYSCFG_EXTICR1_EXTI2_PD, 0xF00U); 35 | register_set_bits(&(EXTI->IMR), (1U << 2)); 36 | register_set_bits(&(EXTI->RTSR), (1U << 2)); 37 | register_set_bits(&(EXTI->FTSR), (1U << 2)); 38 | NVIC_EnableIRQ(EXTI2_IRQn); 39 | } -------------------------------------------------------------------------------- /board/drivers/llgpio.h: -------------------------------------------------------------------------------- 1 | #define MODE_INPUT 0 2 | #define MODE_OUTPUT 1 3 | #define MODE_ALTERNATE 2 4 | #define MODE_ANALOG 3 5 | 6 | #define PULL_NONE 0 7 | #define PULL_UP 1 8 | #define PULL_DOWN 2 9 | 10 | #define OUTPUT_TYPE_PUSH_PULL 0U 11 | #define OUTPUT_TYPE_OPEN_DRAIN 1U 12 | 13 | void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { 14 | ENTER_CRITICAL(); 15 | uint32_t tmp = GPIO->MODER; 16 | tmp &= ~(3U << (pin * 2U)); 17 | tmp |= (mode << (pin * 2U)); 18 | register_set(&(GPIO->MODER), tmp, 0xFFFFFFFFU); 19 | EXIT_CRITICAL(); 20 | } 21 | 22 | void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) { 23 | ENTER_CRITICAL(); 24 | if (enabled) { 25 | register_set_bits(&(GPIO->ODR), (1U << pin)); 26 | } else { 27 | register_clear_bits(&(GPIO->ODR), (1U << pin)); 28 | } 29 | set_gpio_mode(GPIO, pin, MODE_OUTPUT); 30 | EXIT_CRITICAL(); 31 | } 32 | 33 | void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type){ 34 | ENTER_CRITICAL(); 35 | if(output_type == OUTPUT_TYPE_OPEN_DRAIN) { 36 | register_set_bits(&(GPIO->OTYPER), (1U << pin)); 37 | } else { 38 | register_clear_bits(&(GPIO->OTYPER), (1U << pin)); 39 | } 40 | EXIT_CRITICAL(); 41 | } 42 | 43 | void set_gpio_alternate(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { 44 | ENTER_CRITICAL(); 45 | uint32_t tmp = GPIO->AFR[pin >> 3U]; 46 | tmp &= ~(0xFU << ((pin & 7U) * 4U)); 47 | tmp |= mode << ((pin & 7U) * 4U); 48 | register_set(&(GPIO->AFR[pin >> 3]), tmp, 0xFFFFFFFFU); 49 | set_gpio_mode(GPIO, pin, MODE_ALTERNATE); 50 | EXIT_CRITICAL(); 51 | } 52 | 53 | void set_gpio_pullup(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { 54 | ENTER_CRITICAL(); 55 | uint32_t tmp = GPIO->PUPDR; 56 | tmp &= ~(3U << (pin * 2U)); 57 | tmp |= (mode << (pin * 2U)); 58 | register_set(&(GPIO->PUPDR), tmp, 0xFFFFFFFFU); 59 | EXIT_CRITICAL(); 60 | } 61 | 62 | int get_gpio_input(GPIO_TypeDef *GPIO, unsigned int pin) { 63 | return (GPIO->IDR & (1U << pin)) == (1U << pin); 64 | } 65 | 66 | -------------------------------------------------------------------------------- /board/drivers/pwm.h: -------------------------------------------------------------------------------- 1 | #define PWM_COUNTER_OVERFLOW 2000U // To get ~50kHz 2 | 3 | // TODO: Implement for 32-bit timers 4 | 5 | void pwm_init(TIM_TypeDef *TIM, uint8_t channel){ 6 | // Enable timer and auto-reload 7 | register_set(&(TIM->CR1), TIM_CR1_CEN | TIM_CR1_ARPE, 0x3FU); 8 | 9 | // Set channel as PWM mode 1 and enable output 10 | switch(channel){ 11 | case 1U: 12 | register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE)); 13 | register_set_bits(&(TIM->CCER), TIM_CCER_CC1E); 14 | break; 15 | case 2U: 16 | register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE)); 17 | register_set_bits(&(TIM->CCER), TIM_CCER_CC2E); 18 | break; 19 | case 3U: 20 | register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE)); 21 | register_set_bits(&(TIM->CCER), TIM_CCER_CC3E); 22 | break; 23 | case 4U: 24 | register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE)); 25 | register_set_bits(&(TIM->CCER), TIM_CCER_CC4E); 26 | break; 27 | default: 28 | break; 29 | } 30 | 31 | // Set max counter value 32 | register_set(&(TIM->ARR), PWM_COUNTER_OVERFLOW, 0xFFFFU); 33 | 34 | // Update registers and clear counter 35 | TIM->EGR |= TIM_EGR_UG; 36 | } 37 | 38 | void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage){ 39 | uint16_t comp_value = (((uint16_t) percentage * PWM_COUNTER_OVERFLOW) / 100U); 40 | switch(channel){ 41 | case 1U: 42 | register_set(&(TIM->CCR1), comp_value, 0xFFFFU); 43 | break; 44 | case 2U: 45 | register_set(&(TIM->CCR2), comp_value, 0xFFFFU); 46 | break; 47 | case 3U: 48 | register_set(&(TIM->CCR3), comp_value, 0xFFFFU); 49 | break; 50 | case 4U: 51 | register_set(&(TIM->CCR4), comp_value, 0xFFFFU); 52 | break; 53 | default: 54 | break; 55 | } 56 | } -------------------------------------------------------------------------------- /board/drivers/timer.h: -------------------------------------------------------------------------------- 1 | void timer_init(TIM_TypeDef *TIM, int psc) { 2 | register_set(&(TIM->PSC), (psc-1), 0xFFFFU); 3 | register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU); 4 | register_set(&(TIM->CR1), TIM_CR1_CEN, 0x3FU); 5 | TIM->SR = 0; 6 | } 7 | 8 | -------------------------------------------------------------------------------- /board/faults.h: -------------------------------------------------------------------------------- 1 | #define FAULT_STATUS_NONE 0U 2 | #define FAULT_STATUS_TEMPORARY 1U 3 | #define FAULT_STATUS_PERMANENT 2U 4 | 5 | // Fault types 6 | #define FAULT_RELAY_MALFUNCTION (1U << 0) 7 | #define FAULT_UNUSED_INTERRUPT_HANDLED (1U << 1) 8 | #define FAULT_INTERRUPT_RATE_CAN_1 (1U << 2) 9 | #define FAULT_INTERRUPT_RATE_CAN_2 (1U << 3) 10 | #define FAULT_INTERRUPT_RATE_CAN_3 (1U << 4) 11 | #define FAULT_INTERRUPT_RATE_TACH (1U << 5) 12 | #define FAULT_INTERRUPT_RATE_GMLAN (1U << 6) 13 | #define FAULT_INTERRUPT_RATE_INTERRUPTS (1U << 7) 14 | #define FAULT_INTERRUPT_RATE_SPI_DMA (1U << 8) 15 | #define FAULT_INTERRUPT_RATE_SPI_CS (1U << 9) 16 | #define FAULT_INTERRUPT_RATE_UART_1 (1U << 10) 17 | #define FAULT_INTERRUPT_RATE_UART_2 (1U << 11) 18 | #define FAULT_INTERRUPT_RATE_UART_3 (1U << 12) 19 | #define FAULT_INTERRUPT_RATE_UART_5 (1U << 13) 20 | #define FAULT_INTERRUPT_RATE_UART_DMA (1U << 14) 21 | #define FAULT_INTERRUPT_RATE_USB (1U << 15) 22 | #define FAULT_INTERRUPT_RATE_TIM1 (1U << 16) 23 | #define FAULT_INTERRUPT_RATE_TIM3 (1U << 17) 24 | #define FAULT_REGISTER_DIVERGENT (1U << 18) 25 | 26 | // Permanent faults 27 | #define PERMANENT_FAULTS 0U 28 | 29 | uint8_t fault_status = FAULT_STATUS_NONE; 30 | uint32_t faults = 0U; 31 | 32 | void fault_occurred(uint32_t fault) { 33 | faults |= fault; 34 | if((PERMANENT_FAULTS & fault) != 0U){ 35 | puts("Permanent fault occurred: 0x"); puth(fault); puts("\n"); 36 | fault_status = FAULT_STATUS_PERMANENT; 37 | } else { 38 | puts("Temporary fault occurred: 0x"); puth(fault); puts("\n"); 39 | fault_status = FAULT_STATUS_TEMPORARY; 40 | } 41 | } 42 | 43 | void fault_recovered(uint32_t fault) { 44 | if((PERMANENT_FAULTS & fault) == 0U){ 45 | faults &= ~fault; 46 | } else { 47 | puts("Cannot recover from a permanent fault!\n"); 48 | } 49 | } -------------------------------------------------------------------------------- /board/get_sdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo apt-get install gcc-arm-none-eabi python-pip 3 | sudo pip install libusb1 pycrypto requests 4 | -------------------------------------------------------------------------------- /board/get_sdk_mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Need formula for gcc 3 | sudo easy_install pip 4 | /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 5 | brew tap ArmMbed/homebrew-formulae 6 | brew install python dfu-util arm-none-eabi-gcc 7 | pip install --user libusb1 pycrypto requests 8 | -------------------------------------------------------------------------------- /board/gpio.h: -------------------------------------------------------------------------------- 1 | // Early bringup 2 | #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef 3 | #define ENTER_SOFTLOADER_MAGIC 0xdeadc0de 4 | #define BOOT_NORMAL 0xdeadb111 5 | 6 | extern void *g_pfnVectors; 7 | extern uint32_t enter_bootloader_mode; 8 | 9 | void jump_to_bootloader(void) { 10 | // do enter bootloader 11 | enter_bootloader_mode = 0; 12 | void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)0x1fff0004)); 13 | 14 | // jump to bootloader 15 | bootloader(); 16 | 17 | // reset on exit 18 | enter_bootloader_mode = BOOT_NORMAL; 19 | NVIC_SystemReset(); 20 | } 21 | 22 | void early(void) { 23 | // Reset global critical depth 24 | global_critical_depth = 0; 25 | 26 | // Init register and interrupt tables 27 | init_registers(); 28 | 29 | // neccesary for DFU flashing on a non-power cycled white panda 30 | enable_interrupts(); 31 | 32 | // after it's been in the bootloader, things are initted differently, so we reset 33 | if ((enter_bootloader_mode != BOOT_NORMAL) && 34 | (enter_bootloader_mode != ENTER_BOOTLOADER_MAGIC) && 35 | (enter_bootloader_mode != ENTER_SOFTLOADER_MAGIC)) { 36 | enter_bootloader_mode = BOOT_NORMAL; 37 | NVIC_SystemReset(); 38 | } 39 | 40 | // if wrong chip, reboot 41 | volatile unsigned int id = DBGMCU->IDCODE; 42 | #ifdef STM32F4 43 | if ((id & 0xFFFU) != 0x463U) { 44 | enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; 45 | } 46 | #else 47 | if ((id & 0xFFFU) != 0x411U) { 48 | enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; 49 | } 50 | #endif 51 | 52 | // setup interrupt table 53 | SCB->VTOR = (uint32_t)&g_pfnVectors; 54 | 55 | // early GPIOs float everything 56 | RCC->AHB1ENR = RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; 57 | 58 | GPIOA->MODER = 0; GPIOB->MODER = 0; GPIOC->MODER = 0; 59 | GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0; 60 | GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0; 61 | 62 | detect_configuration(); 63 | detect_board_type(); 64 | 65 | if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { 66 | #ifdef PANDA 67 | current_board->set_esp_gps_mode(ESP_GPS_DISABLED); 68 | #endif 69 | current_board->set_led(LED_GREEN, 1); 70 | jump_to_bootloader(); 71 | } 72 | 73 | if (is_entering_bootmode) { 74 | enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; 75 | } 76 | } -------------------------------------------------------------------------------- /board/inc/cmsis_version.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************//** 2 | * @file cmsis_version.h 3 | * @brief CMSIS Core(M) Version definitions 4 | * @version V5.0.3 5 | * @date 24. June 2019 6 | ******************************************************************************/ 7 | /* 8 | * Copyright (c) 2009-2019 ARM Limited. All rights reserved. 9 | * 10 | * SPDX-License-Identifier: Apache-2.0 11 | * 12 | * Licensed under the Apache License, Version 2.0 (the License); you may 13 | * not use this file except in compliance with the License. 14 | * You may obtain a copy of the License at 15 | * 16 | * www.apache.org/licenses/LICENSE-2.0 17 | * 18 | * Unless required by applicable law or agreed to in writing, software 19 | * distributed under the License is distributed on an AS IS BASIS, WITHOUT 20 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | * See the License for the specific language governing permissions and 22 | * limitations under the License. 23 | */ 24 | 25 | #if defined ( __ICCARM__ ) 26 | #pragma system_include /* treat file as system include file for MISRA check */ 27 | #elif defined (__clang__) 28 | #pragma clang system_header /* treat file as system include file */ 29 | #endif 30 | 31 | #ifndef __CMSIS_VERSION_H 32 | #define __CMSIS_VERSION_H 33 | 34 | /* CMSIS Version definitions */ 35 | #define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ 36 | #define __CM_CMSIS_VERSION_SUB ( 3U) /*!< [15:0] CMSIS Core(M) sub version */ 37 | #define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ 38 | __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ 39 | #endif 40 | 41 | -------------------------------------------------------------------------------- /board/inc/stm32f205xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/inc/stm32f205xx.h -------------------------------------------------------------------------------- /board/inc/stm32f2xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/inc/stm32f2xx.h -------------------------------------------------------------------------------- /board/inc/stm32f4xx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/inc/stm32f4xx.h -------------------------------------------------------------------------------- /board/libc.h: -------------------------------------------------------------------------------- 1 | // **** libc **** 2 | 3 | void delay(int a) { 4 | volatile int i; 5 | for (i = 0; i < a; i++); 6 | } 7 | 8 | void *memset(void *str, int c, unsigned int n) { 9 | uint8_t *s = str; 10 | for (unsigned int i = 0; i < n; i++) { 11 | *s = c; 12 | s++; 13 | } 14 | return str; 15 | } 16 | 17 | void *memcpy(void *dest, const void *src, unsigned int n) { 18 | uint8_t *d = dest; 19 | const uint8_t *s = src; 20 | for (unsigned int i = 0; i < n; i++) { 21 | *d = *s; 22 | d++; 23 | s++; 24 | } 25 | return dest; 26 | } 27 | 28 | int memcmp(const void * ptr1, const void * ptr2, unsigned int num) { 29 | int ret = 0; 30 | const uint8_t *p1 = ptr1; 31 | const uint8_t *p2 = ptr2; 32 | for (unsigned int i = 0; i < num; i++) { 33 | if (*p1 != *p2) { 34 | ret = -1; 35 | break; 36 | } 37 | p1++; 38 | p2++; 39 | } 40 | return ret; 41 | } 42 | 43 | -------------------------------------------------------------------------------- /board/main_declarations.h: -------------------------------------------------------------------------------- 1 | // ******************** Prototypes ******************** 2 | void puts(const char *a); 3 | void puth(unsigned int i); 4 | void puth2(unsigned int i); 5 | typedef struct board board; 6 | typedef struct harness_configuration harness_configuration; 7 | void can_flip_buses(uint8_t bus1, uint8_t bus2); 8 | void can_set_obd(uint8_t harness_orientation, bool obd); 9 | 10 | // ********************* Globals ********************** 11 | uint8_t hw_type = 0; 12 | const board *current_board; 13 | bool is_enumerated = 0; 14 | uint32_t heartbeat_counter = 0; 15 | uint32_t uptime_cnt = 0; 16 | -------------------------------------------------------------------------------- /board/obj/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/obj/.placeholder -------------------------------------------------------------------------------- /board/pedal/.gitignore: -------------------------------------------------------------------------------- 1 | obj/* 2 | -------------------------------------------------------------------------------- /board/pedal/Makefile: -------------------------------------------------------------------------------- 1 | # :set noet 2 | PROJ_NAME = comma 3 | 4 | CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -Werror -std=gnu11 -DPEDAL 5 | CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 6 | CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx 7 | CFLAGS += -I ../inc -I ../ -I ../../ -nostdlib -fno-builtin 8 | CFLAGS += -T../stm32_flash.ld 9 | 10 | STARTUP_FILE = startup_stm32f205xx 11 | 12 | CC = arm-none-eabi-gcc 13 | OBJCOPY = arm-none-eabi-objcopy 14 | OBJDUMP = arm-none-eabi-objdump 15 | DFU_UTIL = "dfu-util" 16 | 17 | # pedal only uses the debug cert 18 | CERT = ../../certs/debug 19 | CFLAGS += "-DALLOW_DEBUG" 20 | 21 | canflash: obj/$(PROJ_NAME).bin 22 | ../../tests/pedal/enter_canloader.py $< 23 | 24 | usbflash: obj/$(PROJ_NAME).bin 25 | ../../tests/pedal/enter_canloader.py; sleep 0.5 26 | PYTHONPATH=../../ python -c "from python import Panda; p = [x for x in [Panda(x) for x in Panda.list()] if x.bootstub]; assert(len(p)==1); p[0].flash('obj/$(PROJ_NAME).bin', reconnect=False)" 27 | 28 | recover: obj/bootstub.bin obj/$(PROJ_NAME).bin 29 | ../../tests/pedal/enter_canloader.py --recover; sleep 0.5 30 | $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin 31 | $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.bin 32 | 33 | include ../../common/version.mk 34 | 35 | obj/cert.h: ../../crypto/getcertheader.py 36 | ../../crypto/getcertheader.py ../../certs/debug.pub ../../certs/release.pub > $@ 37 | 38 | obj/main.o: main.c ../*.h 39 | mkdir -p obj 40 | $(CC) $(CFLAGS) -o $@ -c $< 41 | 42 | obj/bootstub.o: ../bootstub.c ../*.h obj/gitversion.h obj/cert.h 43 | mkdir -p obj 44 | mkdir -p ../obj 45 | cp obj/gitversion.h ../obj/gitversion.h 46 | cp obj/cert.h ../obj/cert.h 47 | $(CC) $(CFLAGS) -o $@ -c $< 48 | 49 | obj/$(STARTUP_FILE).o: ../$(STARTUP_FILE).s 50 | $(CC) $(CFLAGS) -o $@ -c $< 51 | 52 | obj/%.o: ../../crypto/%.c 53 | $(CC) $(CFLAGS) -o $@ -c $< 54 | 55 | obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.o 56 | # hack 57 | $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ 58 | $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin 59 | SETLEN=1 ../../crypto/sign.py obj/code.bin $@ $(CERT) 60 | 61 | obj/bootstub.bin: obj/$(STARTUP_FILE).o obj/bootstub.o obj/sha.o obj/rsa.o 62 | $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ 63 | $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ 64 | 65 | clean: 66 | rm -f obj/* 67 | 68 | -------------------------------------------------------------------------------- /board/pedal/README: -------------------------------------------------------------------------------- 1 | This is the firmware for the comma pedal. It borrows a lot from panda. 2 | 3 | The comma pedal is a gas pedal interceptor for Honda/Acura. It allows you to "virtually" press the pedal. 4 | 5 | This is the open source software. Note that it is not ready to use yet. 6 | 7 | == Test Plan == 8 | 9 | * Startup 10 | ** Confirm STATE_FAULT_STARTUP 11 | * Timeout 12 | ** Send value 13 | ** Confirm value is output 14 | ** Stop sending messages 15 | ** Confirm value is passthru after 100ms 16 | ** Confirm STATE_FAULT_TIMEOUT 17 | * Random values 18 | ** Send random 6 byte messages 19 | ** Confirm random values cause passthru 20 | ** Confirm STATE_FAULT_BAD_CHECKSUM 21 | * Same message lockout 22 | ** Send same message repeated 23 | ** Confirm timeout behavior 24 | * Don't set enable 25 | ** Confirm no output 26 | * Set enable and values 27 | ** Confirm output 28 | 29 | -------------------------------------------------------------------------------- /board/pedal/main_declarations.h: -------------------------------------------------------------------------------- 1 | // ******************** Prototypes ******************** 2 | void puts(const char *a); 3 | void puth(unsigned int i); 4 | void puth2(unsigned int i); 5 | typedef struct board board; 6 | typedef struct harness_configuration harness_configuration; 7 | 8 | // ********************* Globals ********************** 9 | uint8_t hw_type = 0; 10 | const board *current_board; 11 | bool is_enumerated = 0; -------------------------------------------------------------------------------- /board/pedal/obj/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/pedal/obj/.gitkeep -------------------------------------------------------------------------------- /board/power_saving.h: -------------------------------------------------------------------------------- 1 | // WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes. 2 | // See rule: CoU_3 3 | 4 | #define POWER_SAVE_STATUS_DISABLED 0 5 | #define POWER_SAVE_STATUS_ENABLED 1 6 | 7 | int power_save_status = POWER_SAVE_STATUS_DISABLED; 8 | 9 | void set_power_save_state(int state) { 10 | 11 | bool is_valid_state = (state == POWER_SAVE_STATUS_ENABLED) || (state == POWER_SAVE_STATUS_DISABLED); 12 | if (is_valid_state && (state != power_save_status)) { 13 | bool enable = false; 14 | if (state == POWER_SAVE_STATUS_ENABLED) { 15 | puts("enable power savings\n"); 16 | if (board_has_gps()) { 17 | char UBLOX_SLEEP_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; 18 | uart_ring *ur = get_ring_by_number(1); 19 | for (unsigned int i = 0; i < sizeof(UBLOX_SLEEP_MSG) - 1U; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i])); 20 | } 21 | } else { 22 | puts("disable power savings\n"); 23 | if (board_has_gps()) { 24 | char UBLOX_WAKE_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; 25 | uart_ring *ur = get_ring_by_number(1); 26 | for (unsigned int i = 0; i < sizeof(UBLOX_WAKE_MSG) - 1U; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); 27 | } 28 | enable = true; 29 | } 30 | 31 | current_board->enable_can_transcievers(enable); 32 | 33 | // Switch EPS/GPS 34 | if (enable) { 35 | current_board->set_esp_gps_mode(ESP_GPS_ENABLED); 36 | } else { 37 | current_board->set_esp_gps_mode(ESP_GPS_DISABLED); 38 | } 39 | 40 | if(board_has_gmlan()){ 41 | // turn on GMLAN 42 | set_gpio_output(GPIOB, 14, enable); 43 | set_gpio_output(GPIOB, 15, enable); 44 | } 45 | 46 | if(board_has_lin()){ 47 | // turn on LIN 48 | set_gpio_output(GPIOB, 7, enable); 49 | set_gpio_output(GPIOA, 14, enable); 50 | } 51 | 52 | // Switch off IR when in power saving 53 | if(!enable){ 54 | current_board->set_ir_power(0U); 55 | } 56 | 57 | power_save_status = state; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /board/provision.h: -------------------------------------------------------------------------------- 1 | #define PROVISION_CHUNK_LEN 0x20 2 | 3 | // WiFi SSID = 0x0 - 0x10 4 | // WiFi password = 0x10 - 0x1C 5 | // SHA1 checksum = 0x1C - 0x20 6 | 7 | void get_provision_chunk(uint8_t *resp) { 8 | (void)memcpy(resp, (uint8_t *)0x1fff79e0, PROVISION_CHUNK_LEN); 9 | if (memcmp(resp, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 0x20) == 0) { 10 | (void)memcpy(resp, "unprovisioned\x00\x00\x00testing123\x00\x00\xa3\xa6\x99\xec", 0x20); 11 | } 12 | } 13 | 14 | uint8_t chunk[PROVISION_CHUNK_LEN]; 15 | bool is_provisioned(void) { 16 | (void)memcpy(chunk, (uint8_t *)0x1fff79e0, PROVISION_CHUNK_LEN); 17 | return (memcmp(chunk, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff", 0x20) != 0); 18 | } 19 | 20 | -------------------------------------------------------------------------------- /board/safety/safety_defaults.h: -------------------------------------------------------------------------------- 1 | int default_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { 2 | UNUSED(to_push); 3 | return true; 4 | } 5 | 6 | // *** no output safety mode *** 7 | 8 | static void nooutput_init(int16_t param) { 9 | UNUSED(param); 10 | controls_allowed = false; 11 | relay_malfunction = false; 12 | } 13 | 14 | static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { 15 | UNUSED(to_send); 16 | return false; 17 | } 18 | 19 | static int nooutput_tx_lin_hook(int lin_num, uint8_t *data, int len) { 20 | UNUSED(lin_num); 21 | UNUSED(data); 22 | UNUSED(len); 23 | return false; 24 | } 25 | 26 | static int default_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { 27 | UNUSED(bus_num); 28 | UNUSED(to_fwd); 29 | return -1; 30 | } 31 | 32 | const safety_hooks nooutput_hooks = { 33 | .init = nooutput_init, 34 | .rx = default_rx_hook, 35 | .tx = nooutput_tx_hook, 36 | .tx_lin = nooutput_tx_lin_hook, 37 | .fwd = default_fwd_hook, 38 | }; 39 | 40 | // *** all output safety mode *** 41 | 42 | static void alloutput_init(int16_t param) { 43 | UNUSED(param); 44 | controls_allowed = true; 45 | relay_malfunction = false; 46 | } 47 | 48 | static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { 49 | UNUSED(to_send); 50 | return true; 51 | } 52 | 53 | static int alloutput_tx_lin_hook(int lin_num, uint8_t *data, int len) { 54 | UNUSED(lin_num); 55 | UNUSED(data); 56 | UNUSED(len); 57 | return true; 58 | } 59 | 60 | const safety_hooks alloutput_hooks = { 61 | .init = alloutput_init, 62 | .rx = default_rx_hook, 63 | .tx = alloutput_tx_hook, 64 | .tx_lin = alloutput_tx_lin_hook, 65 | .fwd = default_fwd_hook, 66 | }; 67 | -------------------------------------------------------------------------------- /board/safety/safety_elm327.h: -------------------------------------------------------------------------------- 1 | static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { 2 | 3 | int tx = 1; 4 | int addr = GET_ADDR(to_send); 5 | int len = GET_LEN(to_send); 6 | 7 | //All ISO 15765-4 messages must be 8 bytes long 8 | if (len != 8) { 9 | tx = 0; 10 | } 11 | 12 | //Check valid 29 bit send addresses for ISO 15765-4 13 | //Check valid 11 bit send addresses for ISO 15765-4 14 | if ((addr != 0x18DB33F1) && ((addr & 0x1FFF00FF) != 0x18DA00F1) && 15 | ((addr & 0x1FFFFF00) != 0x700)) { 16 | tx = 0; 17 | } 18 | return tx; 19 | } 20 | 21 | static int elm327_tx_lin_hook(int lin_num, uint8_t *data, int len) { 22 | int tx = 1; 23 | if (lin_num != 0) { 24 | tx = 0; //Only operate on LIN 0, aka serial 2 25 | } 26 | if ((len < 5) || (len > 11)) { 27 | tx = 0; //Valid KWP size 28 | } 29 | if (!(((data[0] & 0xF8U) == 0xC0U) && ((data[0] & 0x07U) != 0U) && 30 | (data[1] == 0x33U) && (data[2] == 0xF1U))) { 31 | tx = 0; //Bad msg 32 | } 33 | return tx; 34 | } 35 | 36 | const safety_hooks elm327_hooks = { 37 | .init = nooutput_init, 38 | .rx = default_rx_hook, 39 | .tx = elm327_tx_hook, 40 | .tx_lin = elm327_tx_lin_hook, 41 | .fwd = default_fwd_hook, 42 | }; 43 | -------------------------------------------------------------------------------- /board/safety/safety_gm_ascm.h: -------------------------------------------------------------------------------- 1 | // BUS 0 is on the LKAS module (ASCM) side 2 | // BUS 2 is on the actuator (EPS) side 3 | 4 | static int gm_ascm_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { 5 | 6 | int bus_fwd = -1; 7 | 8 | if (bus_num == 0) { 9 | int addr = GET_ADDR(to_fwd); 10 | bus_fwd = 2; 11 | // do not propagate lkas messages from ascm to actuators, unless supercruise is on 12 | // block 0x152 and 0x154, which are the lkas command from ASCM1 and ASCM2 13 | // block 0x315 and 0x2cb, which are the brake and accel commands from ASCM1 14 | //if ((addr == 0x152) || (addr == 0x154) || (addr == 0x315) || (addr == 0x2cb)) { 15 | if ((addr == 0x152) || (addr == 0x154)) { 16 | bool supercruise_on = (GET_BYTE(to_fwd, 4) & 0x10) != 0; // bit 36 17 | if (!supercruise_on) { 18 | bus_fwd = -1; 19 | } 20 | } 21 | if ((addr == 0x151) || (addr == 0x153) || (addr == 0x314)) { 22 | // on the chassis bus, the OBDII port is on the module side, so we need to read 23 | // the lkas messages sent by openpilot (put on unused 0x151 ane 0x153 addrs) and send it to 24 | // the actuator as 0x152 and 0x154 25 | uint32_t fwd_addr = addr + 1; 26 | to_fwd->RIR = (fwd_addr << 21) | (to_fwd->RIR & 0x1fffff); 27 | } 28 | } 29 | 30 | if (bus_num == 2) { 31 | bus_fwd = 0; 32 | } 33 | 34 | return bus_fwd; 35 | } 36 | 37 | const safety_hooks gm_ascm_hooks = { 38 | .init = nooutput_init, 39 | .rx = default_rx_hook, 40 | .tx = alloutput_tx_hook, 41 | .tx_lin = nooutput_tx_lin_hook, 42 | .fwd = gm_ascm_fwd_hook, 43 | }; 44 | -------------------------------------------------------------------------------- /board/stm32_flash.ld: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/stm32_flash.ld -------------------------------------------------------------------------------- /board/tests/test_rsa.c: -------------------------------------------------------------------------------- 1 | /* 2 | gcc -DTEST_RSA test_rsa.c ../crypto/rsa.c ../crypto/sha.c && ./a.out 3 | */ 4 | 5 | #include 6 | #include 7 | 8 | #define MAX_LEN 0x40000 9 | char buf[MAX_LEN]; 10 | 11 | #include "../crypto/sha.h" 12 | #include "../crypto/rsa.h" 13 | #include "../obj/cert.h" 14 | 15 | int main() { 16 | FILE *f = fopen("../obj/panda.bin", "rb"); 17 | int tlen = fread(buf, 1, MAX_LEN, f); 18 | fclose(f); 19 | printf("read %d\n", tlen); 20 | uint32_t *_app_start = (uint32_t *)buf; 21 | 22 | int len = _app_start[0]; 23 | char digest[SHA_DIGEST_SIZE]; 24 | SHA_hash(&_app_start[1], len-4, digest); 25 | printf("SHA hash done\n"); 26 | 27 | if (!RSA_verify(&rsa_key, ((void*)&_app_start[0]) + len, RSANUMBYTES, digest, SHA_DIGEST_SIZE)) { 28 | printf("RSA fail\n"); 29 | } else { 30 | printf("RSA match!!!\n"); 31 | } 32 | 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /board/tools/dfu-util-aarch64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/tools/dfu-util-aarch64 -------------------------------------------------------------------------------- /board/tools/dfu-util-aarch64-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/tools/dfu-util-aarch64-linux -------------------------------------------------------------------------------- /board/tools/dfu-util-x86_64-linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/board/tools/dfu-util-x86_64-linux -------------------------------------------------------------------------------- /board/tools/enter_download_mode.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | import sys 5 | import time 6 | import usb1 7 | 8 | def enter_download_mode(device): 9 | handle = device.open() 10 | handle.claimInterface(0) 11 | 12 | try: 13 | handle.controlWrite(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xd1, 0, 0, b'') 14 | except (usb1.USBErrorIO, usb1.USBErrorPipe): 15 | print("Device download mode enabled.") 16 | time.sleep(1) 17 | else: 18 | print("Device failed to enter download mode.") 19 | sys.exit(1) 20 | 21 | def find_first_panda(context=None): 22 | context = context or usb1.USBContext() 23 | for device in context.getDeviceList(skip_on_error=True): 24 | if device.getVendorID() == 0xbbaa and device.getProductID()&0xFF00 == 0xdd00: 25 | return device 26 | 27 | if __name__ == "__main__": 28 | panda_dev = find_first_panda() 29 | if panda_dev == None: 30 | print("no device found") 31 | sys.exit(0) 32 | print("found device") 33 | enter_download_mode(panda_dev) 34 | -------------------------------------------------------------------------------- /boardesp/.gitignore: -------------------------------------------------------------------------------- 1 | proxy 2 | *.bin 3 | esp-open-sdk 4 | a.out 5 | cert.h 6 | gitversion.h 7 | esp-open-sdk.dmg 8 | obj/* 9 | -------------------------------------------------------------------------------- /boardesp/README.md: -------------------------------------------------------------------------------- 1 | 2 | Dependencies 3 | ----- 4 | 5 | **Debian / Ubuntu** 6 | 7 | ``` 8 | ./get_sdk.sh 9 | ``` 10 | 11 | **Mac** 12 | 13 | ``` 14 | ./get_sdk_mac.sh 15 | ``` 16 | 17 | Programming 18 | ----- 19 | 20 | ``` 21 | make 22 | ``` 23 | -------------------------------------------------------------------------------- /boardesp/get_sdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sudo apt-get install make unrar-free autoconf automake libtool gcc g++ gperf \ 3 | flex bison texinfo gawk ncurses-dev libexpat-dev python-dev python python-serial \ 4 | sed git unzip bash help2man wget bzip2 5 | # huh? 6 | sudo apt-get install libtool 7 | sudo apt-get install libtool-bin 8 | git clone --recursive https://github.com/pfalcon/esp-open-sdk.git 9 | cd esp-open-sdk 10 | git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec 11 | cp ../python2_make.py . 12 | python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' 13 | -------------------------------------------------------------------------------- /boardesp/get_sdk_ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | git clone --recursive https://github.com/pfalcon/esp-open-sdk.git 3 | cd esp-open-sdk 4 | git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec 5 | cp ../python2_make.py . 6 | python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' 7 | -------------------------------------------------------------------------------- /boardesp/get_sdk_mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # from http://www.esp8266.com/wiki/doku.php?id=setup-osx-compiler-esp8266 4 | 5 | brew install gnu-sed --with-default-names 6 | brew tap homebrew/dupes 7 | brew install gperf 8 | brew install grep 9 | brew install autoconf 10 | brew install binutils 11 | brew install gawk 12 | brew install wget 13 | brew install automake 14 | brew install libtool 15 | brew install help2man 16 | 17 | brew uninstall gperf 18 | 19 | hdiutil create esp-open-sdk.dmg -volname "esp-open-sdk" -size 10g -fs "Case-sensitive HFS+" 20 | hdiutil mount esp-open-sdk.dmg 21 | ln -s /Volumes/esp-open-sdk esp-open-sdk 22 | cd esp-open-sdk 23 | 24 | git init 25 | git remote add origin https://github.com/pfalcon/esp-open-sdk.git 26 | git fetch origin 27 | git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec 28 | git submodule init 29 | git submodule update --recursive 30 | 31 | cp ../python2_make.py . 32 | python2 python2_make.py 'make STANDALONE=y' 33 | -------------------------------------------------------------------------------- /boardesp/obj/.placeholder: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/boardesp/obj/.placeholder -------------------------------------------------------------------------------- /boardesp/python2_make.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | import os 3 | import sys 4 | os.system(sys.argv[1]) 5 | -------------------------------------------------------------------------------- /boardesp/user_config.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/boardesp/user_config.h -------------------------------------------------------------------------------- /buy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/buy.png -------------------------------------------------------------------------------- /certs/debug: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXQIBAAKBgQC948lnRo4x44Rd7Y8bQAML4aKDC4XRx958fHV8K6+FbCaP1Z42 3 | U2kX0yygak0LjoDutpgObmGHZA+Iz3HeUD6VGjr/teN24vPk+A95cRsjt8rgmGQ9 4 | 6HNjaNgjR+gl1F9XxFimMzir82Xpl1ekTueJNXa7ia5HVH1nFdiksOKHGQIDAQAB 5 | AoGAQuPw2I6EHJLW1/eNB75e1FqhUqRGeYV8nEGDaUBCTi+wzc4kM2LijF/5QnDv 6 | vvht9qkfm0XK2VSoHDtnEzcVM/l1ksb68n4R/1nUooAWY6cQI7dCSk/A6yS1EJFg 7 | BXsgGbT/65khw9pzBW2zVtMVcVNWFayqfCO1I9WcDdA1x1kCQQDfrhoZTZNoDEUE 8 | JKM4fiUdWr1h3Aw8KLJFFexSWeGDwo+qqnujYcKWkHa9qaH1RG5x8Kir9s9Oi4Js 9 | mzKwov8fAkEA2VPJPWxJ4vVQpXle6wC1nyoL7s739yxMWFcabvkzDDhlIVBNdVJd 10 | gZKsFWV7QnVNdDMjn9D27FwKu3i2D+kKxwJBANp1SMojqO765MEKI1t+YDNONx6H 11 | cm+i85Fjuv4nCIjOEdCGVuCYDxtMFpxgO2y3HAMuHx5sm8XDnWsDHLvFRdMCQD7V 12 | XqWHnYUk8AAnqy2+ssQl3/VXmZG5GQmhhV74Za3u0C5ljT+SZL6FrYMyKAT67T3f 13 | WzllrT6BDglNyTWoZxkCQQCt0XSoGM3603GGYNt6AUlGSgtXSo/2Px7odGUtQoKA 14 | FH9q6FVMYpQJ38spZxIGufZJmLP8LLg6YIWJj1F+akxr 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /certs/debug.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC948lnRo4x44Rd7Y8bQAML4aKDC4XRx958fHV8K6+FbCaP1Z42U2kX0yygak0LjoDutpgObmGHZA+Iz3HeUD6VGjr/teN24vPk+A95cRsjt8rgmGQ96HNjaNgjR+gl1F9XxFimMzir82Xpl1ekTueJNXa7ia5HVH1nFdiksOKHGQ== batman@y840 2 | -------------------------------------------------------------------------------- /certs/debugesp: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICXAIBAAKBgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5E 3 | LQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA6 4 | 6f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9QIDAQAB 5 | AoGADaUn+HRef9BaWMvd4G6uMHI54cwJYbj8NpDfKjExQqnuw5bqWnWRQmiSnwbJ 6 | DC7kj3zE/LBAuj890ot3q1CAWqh47ZICZfoX9Qbi5TpvIHFCGy6YkOliF6iIQhR2 7 | 4+zNKTAA0zNKskOM25PdI+grK1Ni/bEofSA6TrqvEwsmxnkCQQDVp9FUUor2Bo/h 8 | /3oAIP51LTw7vfpztYbJr+BDV63czV2DLXzSwzeNrwH4sA3oy1mjUgMBBgAarNGE 9 | DYlc4H5jAkEAw3UCHzzXPlxkw2QGp7nBly5y3p80Uqc31NuYz8rdX/U8KTngi2No 10 | Ft/SGCEXNpeYbToj+WK3RJJ2Ey0mK8+IxwJAcpGd/5CPsaQNLcw4WK9Yo+8Q2Jxk 11 | G/4gfDCSmqn+smNxnLEcuUwzkwdgkEGgA9BfjeOhdsAH+EXpx90WZrZ/LwJBAK0k 12 | jq+rTqUQZbZsejTEKYjJ/bnV4BzDwoKN0Q1pkLc7X4LJoW74rTFuLgdv8MdMfRtt 13 | IIb/eoeFEpGkMicnHesCQHgR7BTUGBM6Uxam7RCdsgVsxoHBma21E/44ivWUMZzN 14 | 3oVt0mPnjS4speOlqwED5pCJ7yw7jwLPFMs8kNxuIKU= 15 | -----END RSA PRIVATE KEY----- 16 | -------------------------------------------------------------------------------- /certs/debugesp.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5ELQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA66f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9Q== batman@y840 2 | -------------------------------------------------------------------------------- /certs/release.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDGN9GU2nOc0kKq6vdZI5qUMzHt234ngqofrgCFFxL0D2Whex0zACp9gar0HZp+bvtpoSgU/Ev8wexNKr+A9QTradljiuxi5ctrOra9k+wxqNj63Wrcu4+wU5UnJEVf/buV4jCOFffMT8z3PO4imt8LzHuEIC/m/ASKVYyvuvBRQQ== batman@y840 2 | -------------------------------------------------------------------------------- /certs/releaseesp.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDN4pVyGuJJSde1l3Fjay8qPxog09DsAJZtYPk+armoYO1L6YKReUTcMNyHQYZZMZFmhCdgjCgTIF2QYWMoP4KSe8l6JF04YPP51dIgefc6UXjtlSI8Pyutr0v9xXjSfsVm3RAJxDSHgzs9AoMsluKCL+LhAR1nd7cuHXITJ80O4w== batman@y840 2 | -------------------------------------------------------------------------------- /common/version.mk: -------------------------------------------------------------------------------- 1 | ifeq ($(RELEASE),1) 2 | BUILD_TYPE = "RELEASE" 3 | else 4 | BUILD_TYPE = "DEBUG" 5 | endif 6 | 7 | SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) 8 | 9 | ifneq ($(wildcard $(SELF_DIR)/../.git/HEAD),) 10 | obj/gitversion.h: $(SELF_DIR)/../VERSION $(SELF_DIR)/../.git/HEAD $(SELF_DIR)/../.git/index 11 | echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-$(shell git rev-parse --short=8 HEAD)-$(BUILD_TYPE)\";" > $@ 12 | else 13 | ifneq ($(wildcard $(SELF_DIR)/../../.git/modules/panda/HEAD),) 14 | obj/gitversion.h: $(SELF_DIR)/../VERSION $(SELF_DIR)/../../.git/modules/panda/HEAD $(SELF_DIR)/../../.git/modules/panda/index 15 | echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-$(shell git rev-parse --short=8 HEAD)-$(BUILD_TYPE)\";" > $@ 16 | else 17 | obj/gitversion.h: $(SELF_DIR)/../VERSION 18 | echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-unknown-$(BUILD_TYPE)\";" > $@ 19 | endif 20 | endif 21 | -------------------------------------------------------------------------------- /crypto/getcertheader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | from Crypto.PublicKey import RSA 4 | 5 | def egcd(a, b): 6 | if a == 0: 7 | return (b, 0, 1) 8 | else: 9 | g, y, x = egcd(b % a, a) 10 | return (g, x - (b // a) * y, y) 11 | 12 | def modinv(a, m): 13 | g, x, y = egcd(a, m) 14 | if g != 1: 15 | raise Exception('modular inverse does not exist') 16 | else: 17 | return x % m 18 | 19 | def to_c_string(x): 20 | mod = (hex(x)[2:-1].rjust(0x100, '0')) 21 | hh = ''.join('\\x'+mod[i:i+2] for i in range(0, 0x100, 2)) 22 | return hh 23 | 24 | def to_c_uint32(x): 25 | nums = [] 26 | for i in range(0x20): 27 | nums.append(x%(2**32)) 28 | x //= (2**32) 29 | return "{"+'U,'.join(map(str, nums))+"U}" 30 | 31 | for fn in sys.argv[1:]: 32 | rsa = RSA.importKey(open(fn).read()) 33 | rr = pow(2**1024, 2, rsa.n) 34 | n0inv = 2**32 - modinv(rsa.n, 2**32) 35 | 36 | cname = fn.split("/")[-1].split(".")[0] + "_rsa_key" 37 | 38 | print('RSAPublicKey '+cname+' = {.len = 0x20,') 39 | print(' .n0inv = %dU,' % n0inv) 40 | print(' .n = %s,' % to_c_uint32(rsa.n)) 41 | print(' .rr = %s,' % to_c_uint32(rr)) 42 | print(' .exponent = %d,' % rsa.e) 43 | print('};') 44 | 45 | 46 | -------------------------------------------------------------------------------- /crypto/hash-internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2007 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 28 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 29 | 30 | #include "stdint.h" 31 | 32 | #ifdef __cplusplus 33 | extern "C" { 34 | #endif // __cplusplus 35 | 36 | struct HASH_CTX; // forward decl 37 | 38 | typedef struct HASH_VTAB { 39 | void (* const init)(struct HASH_CTX*); 40 | void (* const update)(struct HASH_CTX*, const void*, int); 41 | const uint8_t* (* const final)(struct HASH_CTX*); 42 | const uint8_t* (* const hash)(const void*, int, uint8_t*); 43 | int size; 44 | } HASH_VTAB; 45 | 46 | typedef struct HASH_CTX { 47 | const HASH_VTAB * f; 48 | uint64_t count; 49 | uint8_t buf[64]; 50 | uint32_t state[8]; // upto SHA2 51 | } HASH_CTX; 52 | 53 | #define HASH_init(ctx) (ctx)->f->init(ctx) 54 | #define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len) 55 | #define HASH_final(ctx) (ctx)->f->final(ctx) 56 | #define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest) 57 | #define HASH_size(ctx) (ctx)->f->size 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif // __cplusplus 62 | 63 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ 64 | -------------------------------------------------------------------------------- /crypto/rsa.h: -------------------------------------------------------------------------------- 1 | /* rsa.h 2 | ** 3 | ** Copyright 2008, The Android Open Source Project 4 | ** 5 | ** Redistribution and use in source and binary forms, with or without 6 | ** modification, are permitted provided that the following conditions are met: 7 | ** * Redistributions of source code must retain the above copyright 8 | ** notice, this list of conditions and the following disclaimer. 9 | ** * Redistributions in binary form must reproduce the above copyright 10 | ** notice, this list of conditions and the following disclaimer in the 11 | ** documentation and/or other materials provided with the distribution. 12 | ** * Neither the name of Google Inc. nor the names of its contributors may 13 | ** be used to endorse or promote products derived from this software 14 | ** without specific prior written permission. 15 | ** 16 | ** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 17 | ** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 | ** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 | ** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 | ** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 | ** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | ** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 | ** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 29 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 30 | 31 | #include "stdint.h" 32 | 33 | #ifdef __cplusplus 34 | extern "C" { 35 | #endif 36 | 37 | #define RSANUMBYTES 128 /* 1024 bit key length */ 38 | #define RSANUMWORDS (RSANUMBYTES / sizeof(uint32_t)) 39 | 40 | typedef struct RSAPublicKey { 41 | int len; /* Length of n[] in number of uint32_t */ 42 | uint32_t n0inv; /* -1 / n[0] mod 2^32 */ 43 | uint32_t n[RSANUMWORDS]; /* modulus as little endian array */ 44 | uint32_t rr[RSANUMWORDS]; /* R^2 as little endian array */ 45 | int exponent; /* 3 or 65537 */ 46 | } RSAPublicKey; 47 | 48 | int RSA_verify(const RSAPublicKey *key, 49 | const uint8_t* signature, 50 | const int len, 51 | const uint8_t* hash, 52 | const int hash_len); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_RSA_H_ 59 | -------------------------------------------------------------------------------- /crypto/sha.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2005 The Android Open Source Project 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are met: 6 | * * Redistributions of source code must retain the above copyright 7 | * notice, this list of conditions and the following disclaimer. 8 | * * Redistributions in binary form must reproduce the above copyright 9 | * notice, this list of conditions and the following disclaimer in the 10 | * documentation and/or other materials provided with the distribution. 11 | * * Neither the name of Google Inc. nor the names of its contributors may 12 | * be used to endorse or promote products derived from this software 13 | * without specific prior written permission. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR 16 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 18 | * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 19 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 24 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | #ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 27 | #define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 28 | 29 | #include "hash-internal.h" 30 | 31 | #ifdef __cplusplus 32 | extern "C" { 33 | #endif // __cplusplus 34 | 35 | typedef HASH_CTX SHA_CTX; 36 | 37 | void SHA_init(SHA_CTX* ctx); 38 | void SHA_update(SHA_CTX* ctx, const void* data, int len); 39 | const uint8_t* SHA_final(SHA_CTX* ctx); 40 | 41 | // Convenience method. Returns digest address. 42 | // NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes. 43 | const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest); 44 | 45 | #define SHA_DIGEST_SIZE 20 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif // __cplusplus 50 | 51 | #endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ 52 | -------------------------------------------------------------------------------- /crypto/sign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import struct 5 | import hashlib 6 | from Crypto.PublicKey import RSA 7 | import binascii 8 | 9 | # increment this to make new hardware not run old versions 10 | VERSION = 2 11 | 12 | rsa = RSA.importKey(open(sys.argv[3]).read()) 13 | 14 | with open(sys.argv[1], "rb") as f: 15 | dat = f.read() 16 | 17 | print("signing", len(dat), "bytes") 18 | 19 | with open(sys.argv[2], "wb") as f: 20 | if os.getenv("SETLEN") is not None: 21 | # add the version at the end 22 | dat += b"VERS" + struct.pack("I", VERSION) 23 | # add the length at the beginning 24 | x = struct.pack("I", len(dat)) + dat[4:] 25 | # mock signature of dat[4:] 26 | dd = hashlib.sha1(dat[4:]).digest() 27 | else: 28 | x = dat 29 | dd = hashlib.sha1(dat).digest() 30 | 31 | print("hash:", str(binascii.hexlify(dd), "utf-8")) 32 | dd = b"\x00\x01" + b"\xff"*0x69 + b"\x00" + dd 33 | rsa_out = pow(int.from_bytes(dd, byteorder='big', signed=False), rsa.d, rsa.n) 34 | sig = (hex(rsa_out)[2:].rjust(0x100, '0')) 35 | x += binascii.unhexlify(sig) 36 | f.write(x) 37 | 38 | -------------------------------------------------------------------------------- /crypto/stdint.h: -------------------------------------------------------------------------------- 1 | #define uint8_t unsigned char 2 | #define uint32_t unsigned int 3 | #define int64_t long long 4 | #define uint64_t unsigned long long 5 | -------------------------------------------------------------------------------- /docs/guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/docs/guide.pdf -------------------------------------------------------------------------------- /docs/panda_wifi_setup.md: -------------------------------------------------------------------------------- 1 | # Connecting to White Panda via Wi-Fi 2 | 3 | 1. First connect to your White Panda's Wi-Fi pairing network (this should be the Wi-Fi network WITH the "-pair" at the end) 4 | 5 | 2. Now in your favorite web browser go to this address **192.168.0.10** (this should open a web interface to interact with the White Panda) 6 | 7 | 3. Inside the web interface enable secured mode by clinking the **secure it** link/button (this should make the White Panda's Wi-Fi network visible) 8 | 9 | ### If you need your White Panda's Wi-Fi Password 10 | 11 | * Run the **get_panda_password.py** script in found in **examples/** (Must have panda paw for this step because you need to connect White Panda via USB to retrive the Wi-Fi password) 12 | * Also ensure that you are connected to your White Panda's Wi-Fi pairing network 13 | 14 | 4. Connect to your White Panda's default Wi-Fi network (this should be the Wi-Fi network WITHOUT the "-pair" at the end) 15 | 16 | 5. Your White Panda is now connected to Wi-Fi you can test this by running this line of code `python -c 'from panda import Panda; panda = Panda("WIFI")'` in your terminal of choice. -------------------------------------------------------------------------------- /drivers/linux/.gitignore: -------------------------------------------------------------------------------- 1 | .*.cmd 2 | *.ko 3 | .tmp_versions 4 | Module.symvers 5 | modules.order 6 | *.mod.c 7 | -------------------------------------------------------------------------------- /drivers/linux/Makefile: -------------------------------------------------------------------------------- 1 | VERSION=0.0.1 2 | obj-m+=panda.o 3 | 4 | link: 5 | sudo dkms add `pwd` 6 | 7 | build: 8 | sudo dkms build panda/$(VERSION) 9 | 10 | install: 11 | sudo dkms install panda/$(VERSION) 12 | 13 | all: build install 14 | 15 | uninstall: 16 | sudo dkms uninstall panda/$(VERSION) 17 | sudo dkms remove panda/$(VERSION) --all 18 | 19 | -------------------------------------------------------------------------------- /drivers/linux/README.md: -------------------------------------------------------------------------------- 1 | Installs the panda linux kernel driver using DKMS. 2 | 3 | This will allow the panda to work with tools such as `can-utils` 4 | 5 | prerequisites: 6 | - `apt-get install dkms gcc linux-headers-$(uname -r) make sudo` 7 | 8 | installation: 9 | - `make link` (only needed the first time. It will report an error on subsequent attempts to link) 10 | - `make all` 11 | - `make install` 12 | 13 | uninstall: 14 | - `make uninstall` 15 | 16 | usage: 17 | 18 | You will need to bring it up using `sudo ifconfig can0 up` or 19 | `sudo ip link set dev can0 up`, depending on your platform. 20 | -------------------------------------------------------------------------------- /drivers/linux/dkms.conf: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="panda" 2 | PACKAGE_VERSION="0.0.1" 3 | BUILT_MODULE_NAME[0]="panda" 4 | DEST_MODULE_LOCATION[0]="/kernel/drivers/net/panda/" 5 | AUTOINSTALL="yes" 6 | 7 | -------------------------------------------------------------------------------- /drivers/linux/test/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc main.c -o cantest -pthread -lpthread 3 | -------------------------------------------------------------------------------- /drivers/linux/test/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | sudo ifconfig can0 up 3 | make 4 | ./cantest 5 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim CLI/ECUsim CLI.cpp: -------------------------------------------------------------------------------- 1 | // ECUsim CLI.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "ECUsim DLL\ECUsim.h" 6 | 7 | std::unique_ptr sim; 8 | 9 | BOOL CtrlHandler(DWORD fdwCtrlType) 10 | { 11 | if (fdwCtrlType != CTRL_C_EVENT) return FALSE; 12 | 13 | sim->stop(); 14 | sim->join(); 15 | 16 | return(TRUE); 17 | } 18 | 19 | int main(int argc, // Number of strings in array argv 20 | char *argv[], // Array of command-line argument strings 21 | char *envp[]) // Array of environment variable strings 22 | { 23 | 24 | int count; 25 | 26 | // Display each command-line argument. 27 | std::cout << "\nCommand-line arguments:\n"; 28 | for (count = 0; count < argc; count++) 29 | std::cout << " argv[" << count << "] " << argv[count] << "\n"; 30 | 31 | SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE); 32 | 33 | sim.reset(new ECUsim("", 500000)); 34 | sim->join(); 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | 29 | 30 | Source Files 31 | 32 | 33 | Source Files 34 | 35 | 36 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim CLI/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ECUsim CLI.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim CLI/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #include 11 | #include 12 | 13 | 14 | 15 | // TODO: reference additional headers your program requires here 16 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim CLI/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | 32 | 33 | Source Files 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/ECUsim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "panda_shared/panda.h" 5 | #include 6 | 7 | // The following ifdef block is the standard way of creating macros which make exporting 8 | // from a DLL simpler. All files within this DLL are compiled with the ECUSIMDLL_EXPORTS 9 | // symbol defined on the command line. This symbol should not be defined on any project 10 | // that uses this DLL. This way any other project whose source files include this file see 11 | // ECUSIMDLL_API functions as being imported from a DLL, whereas this DLL sees symbols 12 | // defined with this macro as being exported. 13 | #ifdef ECUSIMDLL_EXPORTS 14 | #define ECUSIMDLL_API __declspec(dllexport) 15 | #else 16 | #define ECUSIMDLL_API __declspec(dllimport) 17 | #endif 18 | 19 | // This class is exported from the ECUsim DLL.dll 20 | class ECUSIMDLL_API ECUsim { 21 | public: 22 | ECUsim(std::string sn, unsigned long can_baud, bool ext_addr = FALSE); 23 | ECUsim(panda::Panda && p, unsigned long can_baud, bool ext_addr = FALSE); 24 | ~ECUsim(); 25 | 26 | void stop(); 27 | void join(); 28 | 29 | // Flag determines if verbose output is enabled 30 | volatile bool verbose; 31 | BOOL ext_addr; 32 | private: 33 | std::unique_ptr panda; 34 | 35 | static DWORD WINAPI _canthreadBootstrap(LPVOID This); 36 | DWORD can_recv_thread_function(); 37 | 38 | BOOL _can_addr_matches(panda::PANDA_CAN_MSG & msg); 39 | 40 | void _CAN_process_msg(panda::PANDA_CAN_MSG & msg); 41 | 42 | std::string process_obd_msg(UCHAR mode, UCHAR pid, bool& return_data); 43 | 44 | HANDLE thread_can; 45 | volatile bool doloop; 46 | std::queue can_multipart_data; 47 | 48 | BOOL can11b_enabled; 49 | BOOL can29b_enabled; 50 | }; 51 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ECUsim DLL.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | 15 | 16 | // TODO: reference additional headers your program requires here 17 | -------------------------------------------------------------------------------- /drivers/windows/ECUsim DLL/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /drivers/windows/docs/Message_Size.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/Message_Size.png -------------------------------------------------------------------------------- /drivers/windows/docs/RxBits_defs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/RxBits_defs.jpg -------------------------------------------------------------------------------- /drivers/windows/docs/RxBits_valid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/RxBits_valid.png -------------------------------------------------------------------------------- /drivers/windows/docs/bus_init_signla.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/bus_init_signla.png -------------------------------------------------------------------------------- /drivers/windows/docs/connection_flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/connection_flags.png -------------------------------------------------------------------------------- /drivers/windows/docs/iso15765_ioctls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/iso15765_ioctls.png -------------------------------------------------------------------------------- /drivers/windows/docs/message_send.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/message_send.png -------------------------------------------------------------------------------- /drivers/windows/docs/msg_filter_passfail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/msg_filter_passfail.png -------------------------------------------------------------------------------- /drivers/windows/docs/other notes.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/other notes.txt -------------------------------------------------------------------------------- /drivers/windows/docs/read_msg_flags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/read_msg_flags.png -------------------------------------------------------------------------------- /drivers/windows/docs/reginfo.txt: -------------------------------------------------------------------------------- 1 | #32 bit: HKEY_LOCAL_MACHINE\SOFTWARE\PassThruSupport 2 | #64 bit: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\PassThruSupport 3 | -------------------------------------------------------------------------------- /drivers/windows/docs/start_msg_filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/start_msg_filter.png -------------------------------------------------------------------------------- /drivers/windows/docs/start_msg_filter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/start_msg_filter2.png -------------------------------------------------------------------------------- /drivers/windows/docs/start_msg_filter3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/start_msg_filter3.png -------------------------------------------------------------------------------- /drivers/windows/docs/start_msg_filter4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/docs/start_msg_filter4.png -------------------------------------------------------------------------------- /drivers/windows/docs/timeout_info.txt: -------------------------------------------------------------------------------- 1 | From focum information on NI hardware: https://forums.ni.com/t5/Automotive-and-Embedded-Networks/15765-2-with-NI-products/td-p/1454256 2 | 3 | ///////////////////////////////////////////////////////////////////// 4 | Timeout Diag Command is the timeout in milliseconds the master 5 | waits for the response to a diagnostic request message. The default is 6 | 1000 ms. 7 | 8 | Timeout FC (Bs) is the timeout in milliseconds the master waits 9 | for a Flow Control frame after sending a First Frame or the last 10 | Consecutive Frame of a block. The default is 250 ms. 11 | 12 | Timeout CF (Cr) is the timeout in milliseconds the master waits 13 | for a Consecutive Frame in a multiframe response. The default is 14 | 250 ms. 15 | 16 | Receive Block Size (BS) is the number of Consecutive Frames the 17 | slave sends in one block before waiting for the next Flow Control 18 | frame. A value of 0 (default) means all Consecutive Frames are sent 19 | in one run without interruption. 20 | 21 | Wait Time CF (STmin) defines the minimum time for the slave to 22 | wait between sending two Consecutive Frames of a block. Values 23 | from 0 to 127 are wait times in milliseconds. Values 241 to 249 24 | (Hex F1 to F9) mean wait times of 100 μs to 900 μs, respectively. 25 | All other values are reserved. The default is 5 ms. 26 | 27 | Max Wait Frames (N_WFTmax) is the maximum number of WAIT 28 | frames the master accepts before terminating the connection. The 29 | default is 10. 30 | 31 | 32 | There are no defined lower limits for these values; you can specify any 33 | value down to 0. However, as you correctly pointed out, the timing is 34 | done by Windows, and will be subject to the jitter introduced by the OS 35 | which can easily be in the order of 10s of milliseconds. It is however 36 | hard to give more accurate numbers as the actual jitter is dependent on 37 | the workload of the computer 38 | ///////////////////////////////////////////////////////////////////// 39 | 40 | J2534 04.04 does not appear to have default adjustable parameters for 41 | the timeout related fields. For now, these default values shall be used 42 | in the Panda J2534 implementation. 43 | -------------------------------------------------------------------------------- /drivers/windows/panda Driver Package/panda Driver Package.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {8E41214B-6785-4CFE-B992-037D68949A14} 6 | inf;inv;inx;mof;mc; 7 | 8 | 9 | 10 | 11 | Driver Files 12 | 13 | 14 | -------------------------------------------------------------------------------- /drivers/windows/panda Driver Package/panda.inf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda Driver Package/panda.inf -------------------------------------------------------------------------------- /drivers/windows/panda.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda.ico -------------------------------------------------------------------------------- /drivers/windows/panda/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "stdafx.h" 3 | 4 | BOOL APIENTRY DllMain( HMODULE hModule, 5 | DWORD ul_reason_for_call, 6 | LPVOID lpReserved 7 | ) 8 | { 9 | switch (ul_reason_for_call) 10 | { 11 | case DLL_PROCESS_ATTACH: 12 | case DLL_THREAD_ATTACH: 13 | case DLL_THREAD_DETACH: 14 | case DLL_PROCESS_DETACH: 15 | break; 16 | } 17 | return TRUE; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /drivers/windows/panda/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include 4 | 5 | LONG __cdecl 6 | _tmain( 7 | LONG Argc, 8 | LPTSTR * Argv 9 | ) 10 | /*++ 11 | 12 | Routine description: 13 | 14 | Sample program that communicates with a USB device using WinUSB 15 | 16 | --*/ 17 | { 18 | DEVICE_DATA deviceData; 19 | HRESULT hr; 20 | USB_DEVICE_DESCRIPTOR deviceDesc; 21 | BOOL bResult; 22 | BOOL noDevice; 23 | ULONG lengthReceived; 24 | 25 | UNREFERENCED_PARAMETER(Argc); 26 | UNREFERENCED_PARAMETER(Argv); 27 | 28 | // 29 | // Find a device connected to the system that has WinUSB installed using our 30 | // INF 31 | // 32 | hr = OpenDevice(&deviceData, &noDevice); 33 | 34 | if (FAILED(hr)) { 35 | 36 | if (noDevice) { 37 | 38 | printf(_T("Device not connected or driver not installed\n")); 39 | 40 | } else { 41 | 42 | printf(_T("Failed looking for device, HRESULT 0x%x\n"), hr); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | // 49 | // Get device descriptor 50 | // 51 | bResult = WinUsb_GetDescriptor(deviceData.WinusbHandle, 52 | USB_DEVICE_DESCRIPTOR_TYPE, 53 | 0, 54 | 0, 55 | (PBYTE) &deviceDesc, 56 | sizeof(deviceDesc), 57 | &lengthReceived); 58 | 59 | if (FALSE == bResult || lengthReceived != sizeof(deviceDesc)) { 60 | 61 | printf(_T("Error among LastError %d or lengthReceived %d\n"), 62 | FALSE == bResult ? GetLastError() : 0, 63 | lengthReceived); 64 | CloseDevice(&deviceData); 65 | return 0; 66 | } 67 | 68 | // 69 | // Print a few parts of the device descriptor 70 | // 71 | printf(_T("Device found: VID_%04X&PID_%04X; bcdUsb %04X; path: %s\n"), 72 | deviceDesc.idVendor, 73 | deviceDesc.idProduct, 74 | deviceDesc.bcdUSB, 75 | deviceData.DevicePath); 76 | 77 | CloseDevice(&deviceData); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /drivers/windows/panda/panda.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda/panda.ico -------------------------------------------------------------------------------- /drivers/windows/panda/panda.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda/panda.rc -------------------------------------------------------------------------------- /drivers/windows/panda/panda.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | 26 | 27 | Source Files 28 | 29 | 30 | Source Files 31 | 32 | 33 | 34 | 35 | Resource Files 36 | 37 | 38 | 39 | 40 | Resource Files 41 | 42 | 43 | -------------------------------------------------------------------------------- /drivers/windows/panda/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda/resource.h -------------------------------------------------------------------------------- /drivers/windows/panda/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // panda.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/panda/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #ifndef WIN32_LEAN_AND_MEAN 11 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 12 | #endif 13 | // Windows Header Files: 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/Loader4.h: -------------------------------------------------------------------------------- 1 | // Loader4.h 2 | // (c) 2005 National Control Systems, Inc. 3 | // Portions (c) 2004 Drew Technologies, Inc. 4 | 5 | // This program is free software; you can redistribute it and/or 6 | // modify it under the terms of the GNU General Public License 7 | // as published by the Free Software Foundation; either version 2 8 | // of the License, or any later version. 9 | 10 | // This program is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | 15 | // You should have received a copy of the GNU General Public License 16 | // along with this program; if not, write to: 17 | // the Free Software Foundation, Inc. 18 | // 51 Franklin Street, Fifth Floor 19 | // Boston, MA 02110-1301, USA 20 | 21 | // National Control Systems, Inc. 22 | // 10737 Hamburg Rd 23 | // Hamburg, MI 48139 24 | // 810-231-2901 25 | 26 | // Drew Technologies, Inc. 27 | // 7012 E.M -36, Suite 3B 28 | // Whitmore Lake, MI 48189 29 | // 810-231-3171 30 | 31 | #include "pandaJ2534DLL/J2534_v0404.h" 32 | 33 | //Other Functions 34 | long WINAPI LoadJ2534Dll(char *); 35 | long WINAPI UnloadJ2534Dll(); 36 | 37 | // NCS Returns of any functions not found 38 | #define ERR_NO_PTOPEN 0x0001 39 | #define ERR_NO_PTCLOSE 0x0002 40 | #define ERR_NO_PTCONNECT 0x0004 41 | #define ERR_NO_PTDISCONNECT 0x0008 42 | #define ERR_NO_PTREADMSGS 0x0010 43 | #define ERR_NO_PTWRITEMSGS 0x0020 44 | #define ERR_NO_PTSTARTPERIODICMSG 0x0040 45 | #define ERR_NO_PTSTOPPERIODICMSG 0x0080 46 | #define ERR_NO_PTSTARTMSGFILTER 0x0100 47 | #define ERR_NO_PTSTOPMSGFILTER 0x0200 48 | #define ERR_NO_PTSETPROGRAMMINGVOLTAGE 0x0400 49 | #define ERR_NO_PTREADVERSION 0x0800 50 | #define ERR_NO_PTGETLASTERROR 0x1000 51 | #define ERR_NO_PTIOCTL 0x2000 52 | #define ERR_NO_FUNCTIONS 0x3fff 53 | #define ERR_NO_DLL -1 54 | #define ERR_WRONG_DLL_VER -2 55 | #define ERR_FUNC_MISSING -3 56 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Timer.h" 3 | 4 | 5 | Timer::Timer() 6 | { 7 | reset(); 8 | } 9 | 10 | // gets the time elapsed from construction. 11 | unsigned long long /*milliseconds*/ Timer::getTimePassed(){ 12 | // get the new time 13 | auto end = std::chrono::time_point_cast(clock::now()); 14 | 15 | // return the difference of the times 16 | return (end - start).count(); 17 | } 18 | 19 | void Timer::reset() { 20 | start = std::chrono::time_point_cast(clock::now()); 21 | } -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/Timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //Copied from https://stackoverflow.com/a/31488113 5 | 6 | class Timer 7 | { 8 | using clock = std::chrono::steady_clock; 9 | using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >; 10 | public: 11 | Timer(); 12 | 13 | // gets the time elapsed from construction. 14 | unsigned long long /*milliseconds*/ getTimePassed(); 15 | 16 | void reset(); 17 | 18 | private: 19 | time_point_type start; 20 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | Header Files 38 | 39 | 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // pandaJ2534DLL Test.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 6 | // Windows Header Files: 7 | #include 8 | #include 9 | 10 | // Headers for CppUnitTest 11 | #include "CppUnitTest.h" 12 | #include //Used for formatting in TestHelpers.cpp 13 | #include 14 | #include 15 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL Test/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/Action.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "J2534Frame.h" 5 | 6 | class J2534Connection; 7 | 8 | /** 9 | An Action represents a unit of work that can be scheduled for execution at a later time. 10 | Actions are not guaranteed to be run at their specified time, but a best effort is made. 11 | An Action will never execute early, but can execute later depending on what is in the 12 | queus. 13 | Many different operations are based on this base class. Instead of making a thread, 14 | consider if the work can be offloaded to the Task Queue. 15 | */ 16 | class Action 17 | { 18 | public: 19 | Action( 20 | std::weak_ptr connection, 21 | std::chrono::microseconds delay 22 | ) : connection(connection), delay(delay) { }; 23 | 24 | Action( 25 | std::weak_ptr connection 26 | ) : connection(connection), delay(std::chrono::microseconds(0)) { }; 27 | 28 | //The function called by the task runner when this action is to be invoked. 29 | virtual void execute() = 0; 30 | 31 | //Reschedule this Action for now(). 32 | void scheduleImmediate() { 33 | expire = std::chrono::steady_clock::now(); 34 | } 35 | 36 | //Reschedule this Action relative to its last expiration time. 37 | void scheduleDelay() { 38 | expire += this->delay; 39 | } 40 | 41 | //Reschedule this action {delay} after now(). 42 | void scheduleImmediateDelay() { 43 | expire = std::chrono::steady_clock::now() + this->delay; 44 | } 45 | 46 | //Reschedule this Action based on a specific base time. 47 | void schedule(std::chrono::time_point starttine, BOOL adddelayed) { 48 | this->expire = starttine; 49 | if (adddelayed) 50 | expire += this->delay; 51 | } 52 | 53 | std::weak_ptr connection; 54 | std::chrono::microseconds delay; 55 | //The timestamp at which point this Action is ready to be executed. 56 | std::chrono::time_point expire; 57 | }; 58 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534Connection_CAN.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "J2534Connection_CAN.h" 3 | #include "MessageTx_CAN.h" 4 | #include "Timer.h" 5 | 6 | J2534Connection_CAN::J2534Connection_CAN( 7 | std::shared_ptr panda_dev, 8 | unsigned long ProtocolID, 9 | unsigned long Flags, 10 | unsigned long BaudRate 11 | ) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate) { 12 | this->port = 0; 13 | 14 | if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000) 15 | throw ERR_INVALID_BAUDRATE; 16 | 17 | panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate/100); 18 | }; 19 | 20 | unsigned long J2534Connection_CAN::validateTxMsg(PASSTHRU_MSG* msg) { 21 | if ((msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen() || 22 | (val_is_29bit(msg->TxFlags) != this->_is_29bit() && !check_bmask(this->Flags, CAN_ID_BOTH)))) 23 | return ERR_INVALID_MSG; 24 | return STATUS_NOERROR; 25 | } 26 | 27 | std::shared_ptr J2534Connection_CAN::parseMessageTx(PASSTHRU_MSG& msg) { 28 | return std::dynamic_pointer_cast(std::make_shared(shared_from_this(), msg)); 29 | } 30 | 31 | void J2534Connection_CAN::setBaud(unsigned long BaudRate) { 32 | if (auto panda_dev = this->getPandaDev()) { 33 | if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000) 34 | throw ERR_NOT_SUPPORTED; 35 | 36 | panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100)); 37 | return J2534Connection::setBaud(BaudRate); 38 | } else { 39 | throw ERR_DEVICE_NOT_CONNECTED; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534Connection_CAN.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "J2534Connection.h" 4 | #include "panda_shared/panda.h" 5 | 6 | #define val_is_29bit(num) check_bmask(num, CAN_29BIT_ID) 7 | 8 | class J2534Connection_CAN : public J2534Connection { 9 | public: 10 | J2534Connection_CAN( 11 | std::shared_ptr panda_dev, 12 | unsigned long ProtocolID, 13 | unsigned long Flags, 14 | unsigned long BaudRate 15 | ); 16 | 17 | virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg); 18 | 19 | virtual std::shared_ptr parseMessageTx(PASSTHRU_MSG& pMsg); 20 | 21 | virtual void setBaud(unsigned long baud); 22 | 23 | virtual unsigned long getMinMsgLen() { 24 | return 4; 25 | } 26 | 27 | virtual unsigned long getMaxMsgLen() { 28 | return 12; 29 | } 30 | 31 | virtual unsigned long getMaxMsgSingleFrameLen() { 32 | return 12; 33 | } 34 | 35 | virtual bool isProtoCan() { 36 | return TRUE; 37 | } 38 | 39 | bool _is_29bit() { 40 | return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID; 41 | } 42 | 43 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534Connection_ISO15765.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "J2534Connection.h" 4 | #include "J2534Connection_CAN.h" 5 | #include "MessageTx_ISO15765.h" 6 | #include "MessageRx.h" 7 | 8 | class MessageTx_ISO15765; 9 | 10 | typedef struct { 11 | std::string dispatched_msg; 12 | std::string remaining_payload; 13 | } PRESTAGED_WRITE; 14 | 15 | class J2534Connection_ISO15765 : public J2534Connection { 16 | public: 17 | J2534Connection_ISO15765( 18 | std::shared_ptr panda_dev, 19 | unsigned long ProtocolID, 20 | unsigned long Flags, 21 | unsigned long BaudRate 22 | ); 23 | 24 | virtual long PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG * pMaskMsg, PASSTHRU_MSG * pPatternMsg, PASSTHRU_MSG * pFlowControlMsg, unsigned long * pFilterID); 25 | 26 | int get_matching_out_fc_filter_id(const std::string & msgdata, unsigned long flags, unsigned long flagmask); 27 | 28 | int get_matching_in_fc_filter_id(const J2534Frame& msg, unsigned long flagmask); 29 | 30 | virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg); 31 | 32 | virtual std::shared_ptr parseMessageTx(PASSTHRU_MSG& msg); 33 | 34 | virtual void processMessage(const J2534Frame& msg); 35 | 36 | virtual void setBaud(unsigned long baud); 37 | 38 | virtual void processIOCTLSetConfig(unsigned long Parameter, unsigned long Value); 39 | 40 | virtual unsigned long processIOCTLGetConfig(unsigned long Parameter); 41 | 42 | virtual unsigned long getMinMsgLen() { 43 | return 4; 44 | } 45 | 46 | virtual unsigned long getMaxMsgLen() { 47 | return 4099; 48 | }; 49 | 50 | virtual unsigned long getMaxMsgSingleFrameLen() { 51 | return 11; 52 | } 53 | 54 | virtual bool _is_29bit() { 55 | return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID; 56 | } 57 | 58 | virtual bool isProtoCan() { 59 | return TRUE; 60 | } 61 | 62 | private: 63 | std::array, 10> rxConversations; 64 | unsigned int wftMax; 65 | }; 66 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534Frame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "J2534_v0404.h" 3 | #include "panda_shared/panda.h" 4 | 5 | /*A move convenient container for J2534 Messages than the static buffer provided by default.*/ 6 | class J2534Frame { 7 | public: 8 | J2534Frame(unsigned long ProtocolID, unsigned long RxStatus=0, unsigned long TxFlags=0, unsigned long Timestamp=0) : 9 | ProtocolID(ProtocolID), RxStatus(RxStatus), TxFlags(TxFlags), Timestamp(Timestamp), ExtraDataIndex(0), Data("") { }; 10 | 11 | J2534Frame(const panda::PANDA_CAN_MSG& msg_in) { 12 | ProtocolID = CAN; 13 | ExtraDataIndex = msg_in.len + 4; 14 | Data.reserve(msg_in.len + 4); 15 | Data += msg_in.addr >> 24; 16 | Data += (msg_in.addr >> 16) & 0xFF; 17 | Data += (msg_in.addr >> 8) & 0xFF; 18 | Data += msg_in.addr & 0xFF; 19 | Data += std::string((char*)&msg_in.dat, msg_in.len); 20 | Timestamp = msg_in.recv_time; 21 | RxStatus = (msg_in.addr_29b ? CAN_29BIT_ID : 0) | 22 | (msg_in.is_receipt ? TX_MSG_TYPE : 0); 23 | } 24 | 25 | J2534Frame(const PASSTHRU_MSG& msg) { 26 | this->ProtocolID = msg.ProtocolID; 27 | this->RxStatus = msg.RxStatus; 28 | this->TxFlags = msg.TxFlags; 29 | this->Timestamp = msg.Timestamp; 30 | this->ExtraDataIndex = msg.ExtraDataIndex; 31 | this->Data = std::string((const char*)msg.Data, msg.DataSize); 32 | } 33 | 34 | J2534Frame() { 35 | this->ProtocolID = 0; 36 | this->RxStatus = 0; 37 | this->TxFlags = 0; 38 | this->Timestamp = 0; 39 | this->ExtraDataIndex = 0; 40 | } 41 | 42 | unsigned long ProtocolID; 43 | unsigned long RxStatus; 44 | unsigned long TxFlags; 45 | unsigned long Timestamp; 46 | unsigned long ExtraDataIndex; 47 | std::string Data; 48 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534MessageFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "J2534_v0404.h" 3 | #include "J2534Connection.h" 4 | #include "J2534Frame.h" 5 | 6 | typedef enum { 7 | FILTER_RESULT_BLOCK, 8 | FILTER_RESULT_NEUTRAL, 9 | FILTER_RESULT_PASS, 10 | FILTER_RESULT_NOMATCH = FILTER_RESULT_BLOCK, 11 | FILTER_RESULT_MATCH = FILTER_RESULT_PASS, 12 | } FILTER_RESULT; 13 | 14 | //Forward declare 15 | class J2534Connection; 16 | 17 | /* Represents a J2534 Message Filter created by PassThruStartMsgFilter. 18 | 19 | J2534 uses filters to sort out messages in a simple and sane way. Except for 20 | flow control filters. J2534 v04.04 uses filters to manage 'conversations' in 21 | protocols that support flow control like ISO15765. The whole solution is a 22 | hack, and J2534 v05.00 greatly simplifies this concept. But we are using 23 | v04.04 so, here we are. 24 | */ 25 | class J2534MessageFilter { 26 | public: 27 | J2534MessageFilter( 28 | J2534Connection *const conn, 29 | unsigned int filtertype, 30 | PASSTHRU_MSG *pMaskMsg, 31 | PASSTHRU_MSG *pPatternMsg, 32 | PASSTHRU_MSG *pFlowControlMsg 33 | ); 34 | 35 | bool J2534MessageFilter::operator ==(const J2534MessageFilter &b) const; 36 | 37 | FILTER_RESULT check(const J2534Frame& msg); 38 | std::string get_flowctrl(); 39 | 40 | unsigned long flags; 41 | J2534Connection *const conn; 42 | private: 43 | unsigned int filtertype; 44 | std::string maskMsg; 45 | std::string patternMsg; 46 | std::string flowCtrlMsg; 47 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/J2534register_x64.reg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/pandaJ2534DLL/J2534register_x64.reg -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessagePeriodic.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "MessagePeriodic.h" 3 | #include "J2534Connection.h" 4 | 5 | MessagePeriodic::MessagePeriodic( 6 | std::chrono::microseconds delay, 7 | std::shared_ptr msg 8 | ) : Action(msg->connection, delay), msg(msg), runyet(FALSE), active(TRUE) { }; 9 | 10 | void MessagePeriodic::execute() { 11 | if (!this->active) return; 12 | if (this->runyet) { 13 | if (msg->isFinished()) { 14 | msg->reset(); 15 | msg->execute(); 16 | } 17 | } else { 18 | this->runyet = TRUE; 19 | msg->execute(); 20 | } 21 | 22 | if (auto conn_sp = this->connection.lock()) { 23 | if (auto panda_dev_sp = conn_sp->getPandaDev()) { 24 | //Scheduling must be relative to now incase there was a long stall that 25 | //would case it to be super far behind and try to catch up forever. 26 | this->scheduleImmediateDelay(); 27 | panda_dev_sp->insertActionIntoTaskList(shared_from_this()); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessagePeriodic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Action.h" 3 | #include "MessageTx.h" 4 | 5 | class J2534Connection; 6 | 7 | /* A message that is resent on a given period. Created with calls to PassThruStartPeriodicMessage. 8 | 9 | Instead of making each J2534 protocol implementation have to implement periodic message 10 | functionality, this class takes a message to be sent, and passes along the execute call 11 | to the message, then reschedules itself. 12 | */ 13 | class MessagePeriodic : public Action, public std::enable_shared_from_this 14 | { 15 | public: 16 | MessagePeriodic( 17 | std::chrono::microseconds delay, 18 | std::shared_ptr msg 19 | ); 20 | 21 | virtual void execute(); 22 | 23 | void cancel() { 24 | this->active = FALSE; 25 | } 26 | 27 | protected: 28 | std::shared_ptr msg; 29 | 30 | private: 31 | BOOL runyet; 32 | BOOL active; 33 | }; 34 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageRx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class MessageRx 4 | { 5 | public: 6 | MessageRx( 7 | unsigned long size, 8 | std::string piece, 9 | unsigned long rxFlags, 10 | std::shared_ptr filter 11 | ) : expected_size(size & 0xFFF), flags(rxFlags) { 12 | msg.reserve(expected_size); 13 | msg = piece; 14 | next_part = 1; 15 | }; 16 | 17 | bool rx_add_frame(uint8_t pci_byte, unsigned int max_packet_size, const std::string piece) { 18 | if ((pci_byte & 0x0F) != this->next_part) { 19 | //TODO: Maybe this should instantly fail the transaction. 20 | return TRUE; 21 | } 22 | 23 | this->next_part = (this->next_part + 1) % 0x10; 24 | unsigned int payload_len = min(expected_size - msg.size(), max_packet_size); 25 | if (piece.size() < payload_len) { 26 | //A frame was received that could have held more data. 27 | //No examples of this protocol show that happening, so 28 | //it will be assumed that it is grounds to reset rx. 29 | return FALSE; 30 | } 31 | msg += piece.substr(0, payload_len); 32 | 33 | return TRUE; 34 | } 35 | 36 | unsigned int bytes_remaining() { 37 | return this->expected_size - this->msg.size(); 38 | } 39 | 40 | bool is_ready() { 41 | return this->msg.size() == this->expected_size; 42 | } 43 | 44 | bool flush_result(std::string& final_msg) { 45 | if (this->msg.size() == this->expected_size) { 46 | final_msg = this->msg; 47 | return TRUE; 48 | } 49 | return FALSE; 50 | } 51 | 52 | uint8_t getNextConsecutiveFrameId() { 53 | return this->next_part++; 54 | } 55 | 56 | std::weak_ptr filter; 57 | unsigned long flags; 58 | unsigned long expected_size; 59 | std::string msg; 60 | unsigned char next_part; 61 | }; 62 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Action.h" 3 | #include "J2534Frame.h" 4 | 5 | class J2534Connection; 6 | 7 | class MessageTx : public Action, public std::enable_shared_from_this 8 | { 9 | public: 10 | MessageTx( 11 | std::weak_ptr connection_in, 12 | PASSTHRU_MSG& to_send 13 | ) : Action(connection_in), fullmsg(to_send) { }; 14 | 15 | virtual BOOL checkTxReceipt(J2534Frame frame) = 0; 16 | 17 | virtual BOOL isFinished() = 0; 18 | 19 | virtual BOOL txReady() = 0; 20 | 21 | virtual void reset() = 0; 22 | 23 | protected: 24 | J2534Frame fullmsg; 25 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTxTimeout.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "J2534Connection.h" 3 | #include "MessageTxTimeout.h" 4 | 5 | MessageTxTimeoutable::MessageTxTimeoutable( 6 | std::weak_ptr connection, 7 | PASSTHRU_MSG& to_send 8 | ) : MessageTx(connection, to_send), recvCount(0) { }; 9 | 10 | void MessageTxTimeoutable::scheduleTimeout(std::chrono::microseconds timeoutus) { 11 | if (auto conn_sp = this->connection.lock()) { 12 | if (auto panda_dev_sp = conn_sp->getPandaDev()) { 13 | auto timeoutobj = std::make_shared(std::static_pointer_cast(shared_from_this()), timeoutus); 14 | panda_dev_sp->scheduleAction(std::static_pointer_cast(timeoutobj), TRUE); 15 | } 16 | } 17 | } 18 | 19 | void MessageTxTimeoutable::scheduleTimeout(unsigned long timeoutus) { 20 | scheduleTimeout(std::chrono::microseconds(timeoutus)); 21 | } 22 | 23 | 24 | 25 | MessageTxTimeout::MessageTxTimeout( 26 | std::shared_ptr msg, 27 | std::chrono::microseconds timeout 28 | ) : Action(msg->connection), msg(msg), lastRecvCount(msg->getRecvCount()) { 29 | delay = timeout; 30 | }; 31 | 32 | MessageTxTimeout::MessageTxTimeout( 33 | std::shared_ptr msg, 34 | unsigned long timeout 35 | ) : MessageTxTimeout(msg, std::chrono::microseconds(timeout * 1000)) { }; 36 | 37 | void MessageTxTimeout::execute() { 38 | if (auto msg_sp = this->msg.lock()) { 39 | if (msg_sp->getRecvCount() == this->lastRecvCount) { 40 | msg_sp->onTimeout(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTxTimeout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "Action.h" 3 | #include "MessageTx.h" 4 | 5 | class MessageTxTimeout; 6 | 7 | /* A special type of MessageTx for multipart messages that supports being canceled with a timeout.*/ 8 | class MessageTxTimeoutable : public MessageTx 9 | { 10 | public: 11 | MessageTxTimeoutable( 12 | std::weak_ptr connection, 13 | PASSTHRU_MSG& to_send 14 | ); 15 | 16 | unsigned long getRecvCount() { 17 | return recvCount; 18 | } 19 | 20 | virtual void onTimeout() = 0; 21 | 22 | protected: 23 | unsigned long recvCount; 24 | 25 | void scheduleTimeout(std::chrono::microseconds timeoutus); 26 | 27 | void scheduleTimeout(unsigned long timeoutus); 28 | }; 29 | 30 | 31 | /* An Action that cancels MessageTxTimeoutableif the Timeout Actoin executes 32 | before the MessageTxTimeoutableif renews its timeout. 33 | */ 34 | class MessageTxTimeout : public Action 35 | { 36 | public: 37 | MessageTxTimeout( 38 | std::shared_ptr msg, 39 | std::chrono::microseconds timeout 40 | ); 41 | 42 | MessageTxTimeout( 43 | std::shared_ptr msg, 44 | unsigned long timeout 45 | ); 46 | 47 | virtual void execute(); 48 | 49 | private: 50 | std::weak_ptr msg; 51 | unsigned long lastRecvCount; 52 | }; 53 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTx_CAN.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "MessageTx_CAN.h" 3 | #include "J2534Connection_CAN.h" 4 | 5 | MessageTx_CAN::MessageTx_CAN( 6 | std::shared_ptr connection_in, 7 | PASSTHRU_MSG& to_send 8 | ) : MessageTx(connection_in, to_send), sentyet(FALSE), txInFlight(FALSE) {}; 9 | 10 | void MessageTx_CAN::execute() { 11 | uint32_t addr = ((uint8_t)fullmsg.Data[0]) << 24 | ((uint8_t)fullmsg.Data[1]) << 16 | 12 | ((uint8_t)fullmsg.Data[2]) << 8 | ((uint8_t)fullmsg.Data[3]); 13 | 14 | if (auto conn_sp = std::static_pointer_cast(this->connection.lock())) { 15 | if (auto panda_dev_sp = conn_sp->getPandaDev()) { 16 | auto payload = fullmsg.Data.substr(4); 17 | if (panda_dev_sp->panda->can_send(addr, check_bmask(this->fullmsg.TxFlags, CAN_29BIT_ID), 18 | (const uint8_t*)payload.c_str(), (uint8_t)payload.size(), panda::PANDA_CAN1) == FALSE) { 19 | return; 20 | } 21 | this->txInFlight = TRUE; 22 | this->sentyet = TRUE; 23 | panda_dev_sp->txMsgsAwaitingEcho.push(shared_from_this()); 24 | } 25 | } 26 | } 27 | 28 | //Returns TRUE if receipt is consumed by the msg, FALSE otherwise. 29 | BOOL MessageTx_CAN::checkTxReceipt(J2534Frame frame) { 30 | if (txReady()) return FALSE; 31 | if (frame.Data == fullmsg.Data && ((this->fullmsg.TxFlags & CAN_29BIT_ID) == (frame.RxStatus & CAN_29BIT_ID))) { 32 | txInFlight = FALSE; 33 | if (auto conn_sp = std::static_pointer_cast(this->connection.lock())) 34 | if (conn_sp->loopback) 35 | conn_sp->addMsgToRxQueue(frame); 36 | return TRUE; 37 | } 38 | return FALSE; 39 | } 40 | 41 | void MessageTx_CAN::reset() { 42 | sentyet = FALSE; 43 | txInFlight = FALSE; 44 | } 45 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTx_CAN.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "MessageTx.h" 4 | 5 | class J2534Connection; 6 | 7 | class MessageTx_CAN : public MessageTx 8 | { 9 | public: 10 | MessageTx_CAN( 11 | std::shared_ptr connection_in, 12 | PASSTHRU_MSG& to_send 13 | ); 14 | 15 | virtual void execute(); 16 | 17 | //Returns TRUE if receipt is consumed by the msg, FALSE otherwise. 18 | virtual BOOL checkTxReceipt(J2534Frame frame); 19 | 20 | virtual BOOL isFinished() { 21 | return !txInFlight && sentyet; 22 | }; 23 | 24 | virtual BOOL txReady() { 25 | return !sentyet; 26 | }; 27 | 28 | virtual void reset(); 29 | 30 | private: 31 | BOOL sentyet; 32 | BOOL txInFlight; 33 | }; 34 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/MessageTx_ISO15765.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "MessageTxTimeout.h" 3 | #include "J2534Connection_ISO15765.h" 4 | 5 | class J2534Connection_ISO15765; 6 | 7 | /** 8 | A specialized message type that can handle J2534 single and multi 9 | frame (with flow control) writes. 10 | */ 11 | class MessageTx_ISO15765 : public MessageTxTimeoutable 12 | { 13 | public: 14 | MessageTx_ISO15765( 15 | std::shared_ptr connection, 16 | PASSTHRU_MSG& to_send, 17 | std::shared_ptr filter 18 | ); 19 | 20 | unsigned int addressLength(); 21 | 22 | virtual void execute(); 23 | 24 | virtual BOOL checkTxReceipt(J2534Frame frame); 25 | 26 | virtual BOOL isFinished(); 27 | 28 | virtual BOOL txReady(); 29 | 30 | virtual void reset(); 31 | 32 | virtual void onTimeout(); 33 | 34 | //Functions for ISO15765 flow control 35 | 36 | void MessageTx_ISO15765::flowControlContinue(uint8_t block_size, std::chrono::microseconds separation_time); 37 | void MessageTx_ISO15765::flowControlWait(unsigned long N_WFTmax); 38 | void MessageTx_ISO15765::flowControlAbort(); 39 | 40 | std::shared_ptr filter; 41 | unsigned long frames_sent; 42 | unsigned long consumed_count; 43 | uint8_t block_size; 44 | unsigned long CANid; 45 | std::string data_prefix; 46 | std::string payload; 47 | BOOL isMultipart; 48 | std::vector framePayloads; 49 | BOOL txInFlight; 50 | BOOL sendAll; 51 | unsigned int numWaitFrames; 52 | BOOL didtimeout; 53 | BOOL issuspended; 54 | }; 55 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/PandaJ2534Device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "J2534_v0404.h" 8 | #include "panda_shared/panda.h" 9 | #include "synchronize.h" 10 | #include "Action.h" 11 | #include "MessageTx.h" 12 | #include "J2534Connection.h" 13 | 14 | class J2534Connection; 15 | class Action; 16 | class MessageTx; 17 | 18 | /** 19 | Class representing a physical panda adapter. Instances are created by 20 | PassThruOpen in the J2534 API. A Device can create one or more 21 | J2534Connections. 22 | */ 23 | class PandaJ2534Device { 24 | public: 25 | PandaJ2534Device(std::unique_ptr new_panda); 26 | 27 | ~PandaJ2534Device(); 28 | 29 | static std::shared_ptr openByName(std::string sn); 30 | 31 | DWORD closeChannel(unsigned long ChannelID); 32 | DWORD addChannel(std::shared_ptr& conn, unsigned long* channel_id); 33 | 34 | std::unique_ptr panda; 35 | std::vector> connections; 36 | 37 | //Place the Action in the task queue based on the Action's expiration time, 38 | //then signal the thread that processes actions. 39 | void insertActionIntoTaskList(std::shared_ptr action); 40 | 41 | void scheduleAction(std::shared_ptr msg, BOOL startdelayed=FALSE); 42 | 43 | void registerConnectionTx(std::shared_ptr conn); 44 | 45 | //Resume sending messages from the provided Connection's TX queue. 46 | void unstallConnectionTx(std::shared_ptr conn); 47 | 48 | //Cleans up several queues after a message completes, is canceled, or otherwise goes away. 49 | void removeConnectionTopAction(std::shared_ptr conn, std::shared_ptr msg); 50 | 51 | //Messages that have been sent on the wire will be echoed by the panda when 52 | //transmission is complete. This tracks what is still waiting to hear an echo. 53 | std::queue> txMsgsAwaitingEcho; 54 | 55 | private: 56 | HANDLE thread_kill_event; 57 | 58 | HANDLE can_recv_handle; 59 | static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) { 60 | return ((PandaJ2534Device*)This)->can_recv_thread(); 61 | } 62 | DWORD can_recv_thread(); 63 | 64 | HANDLE can_process_handle; 65 | static DWORD WINAPI _can_process_threadBootstrap(LPVOID This) { 66 | return ((PandaJ2534Device*)This)->can_process_thread(); 67 | } 68 | DWORD can_process_thread(); 69 | 70 | HANDLE flow_control_wakeup_event; 71 | HANDLE flow_control_thread_handle; 72 | static DWORD WINAPI _msg_tx_threadBootstrap(LPVOID This) { 73 | return ((PandaJ2534Device*)This)->msg_tx_thread(); 74 | } 75 | DWORD msg_tx_thread(); 76 | std::list> task_queue; 77 | Mutex task_queue_mutex; 78 | 79 | std::queue> ConnTxQueue; 80 | std::set> ConnTxSet; 81 | Mutex connTXSet_mutex; 82 | BOOL txInProgress; 83 | }; 84 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/Timer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Timer.h" 3 | 4 | 5 | Timer::Timer() 6 | { 7 | start = std::chrono::time_point_cast(clock::now()); 8 | } 9 | 10 | // gets the time elapsed from construction. 11 | unsigned long long /*milliseconds*/ Timer::getTimePassed(){ 12 | // get the new time 13 | auto end = std::chrono::time_point_cast(clock::now()); 14 | 15 | // return the difference of the times 16 | return (end - start).count(); 17 | } -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/Timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | //Copied from https://stackoverflow.com/a/31488113 5 | 6 | class Timer 7 | { 8 | using clock = std::chrono::steady_clock; 9 | using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >; 10 | public: 11 | Timer(); 12 | 13 | // gets the time elapsed from construction. 14 | unsigned long long /*milliseconds*/ getTimePassed(); 15 | 16 | private: 17 | time_point_type start; 18 | }; -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/constants_ISO15765.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define msg_is_extaddr(msg) check_bmask(msg->TxFlags, ISO15765_ADDR_TYPE) 4 | #define msg_is_padded(msg) check_bmask(msg->TxFlags, ISO15765_FRAME_PAD) 5 | 6 | #define FRAME_SINGLE 0x00 7 | #define FRAME_FIRST 0x10 8 | #define FRAME_CONSEC 0x20 9 | #define FRAME_FLOWCTRL 0x30 10 | 11 | #define FLOWCTRL_CONTINUE 0 12 | #define FLOWCTRL_WAIT 1 13 | #define FLOWCTRL_ABORT 2 14 | 15 | #define msg_get_type(msg, addrlen) ((msg).Data[addrlen] & 0xF0) 16 | 17 | #define is_single(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_SINGLE) 18 | #define is_first(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_FIRST) 19 | #define is_consecutive(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_CONSEC) 20 | #define is_flowctrl(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_FLOWCTRL) -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/dllmain.cpp: -------------------------------------------------------------------------------- 1 | // dllmain.cpp : Defines the entry point for the DLL application. 2 | #include "dllmain.h" 3 | 4 | HMODULE thisdll; 5 | 6 | BOOL APIENTRY DllMain( HMODULE hModule, 7 | DWORD ul_reason_for_call, 8 | LPVOID lpReserved 9 | ) 10 | { 11 | thisdll = hModule; 12 | 13 | switch (ul_reason_for_call) 14 | { 15 | case DLL_PROCESS_ATTACH: 16 | case DLL_THREAD_ATTACH: 17 | case DLL_THREAD_DETACH: 18 | case DLL_PROCESS_DETACH: 19 | break; 20 | } 21 | return TRUE; 22 | } 23 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/dllmain.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdafx.h" 3 | 4 | extern HMODULE thisdll; 5 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/pandaJ2534DLL.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.rc -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/resource.h: -------------------------------------------------------------------------------- 1 | //{{NO_DEPENDENCIES}} 2 | // Microsoft Visual C++ generated include file. 3 | // Used by pandaJ2534DLL.rc 4 | 5 | // Next default values for new objects 6 | // 7 | #ifdef APSTUDIO_INVOKED 8 | #ifndef APSTUDIO_READONLY_SYMBOLS 9 | #define _APS_NEXT_RESOURCE_VALUE 101 10 | #define _APS_NEXT_COMMAND_VALUE 40001 11 | #define _APS_NEXT_CONTROL_VALUE 1001 12 | #define _APS_NEXT_SYMED_VALUE 101 13 | #endif 14 | #endif 15 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // pandaJ2534DLL.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "targetver.h" 4 | 5 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 6 | // Windows Header Files: 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/synchronize.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define WIN32_LEAN_AND_MEAN 3 | #include 4 | 5 | //Inspired/directly copied from https://www.codeproject.com/Articles/12362/A-quot-synchronized-quot-statement-for-C-like-in-J 6 | //Enables easier synchronization 7 | class Mutex { 8 | public: 9 | Mutex() { 10 | InitializeCriticalSectionAndSpinCount(&critSection, 0x00000400); 11 | //InitializeCriticalSection(&critSection); 12 | } 13 | 14 | ~Mutex() { 15 | DeleteCriticalSection(&critSection); 16 | } 17 | 18 | void lock() { 19 | EnterCriticalSection(&critSection); 20 | } 21 | 22 | void unlock() { 23 | LeaveCriticalSection(&critSection); 24 | } 25 | 26 | private: 27 | CRITICAL_SECTION critSection; 28 | }; 29 | 30 | //Synchronization Controller Object 31 | class Lock { 32 | public: 33 | Lock(Mutex &m) : mutex(m), locked(TRUE) { 34 | m.lock(); 35 | } 36 | 37 | ~Lock() { 38 | mutex.unlock(); 39 | } 40 | 41 | operator bool() const { 42 | return locked; 43 | } 44 | 45 | void setUnlock() { 46 | locked = FALSE; 47 | } 48 | 49 | private: 50 | Mutex& mutex; 51 | bool locked; 52 | }; 53 | 54 | //A useful shorthand for locking and unlocking a mutex over a scope. 55 | //CAUTION, implemented with a for loop, so break/continue are consumed. 56 | #define synchronized(M) for(Lock M##_lock = M; M##_lock; M##_lock.setUnlock()) 57 | -------------------------------------------------------------------------------- /drivers/windows/pandaJ2534DLL/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | 10 | #define WINVER _WIN32_WINNT_WIN7 11 | #define _WIN32_WINNT _WIN32_WINNT_WIN7 12 | 13 | #include 14 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | CONSOLE APPLICATION : panda_playground Project Overview 3 | ======================================================================== 4 | 5 | AppWizard has created this panda_playground application for you. 6 | 7 | This file contains a summary of what you will find in each of the files that 8 | make up your panda_playground application. 9 | 10 | 11 | panda_playground.vcxproj 12 | This is the main project file for VC++ projects generated using an Application Wizard. 13 | It contains information about the version of Visual C++ that generated the file, and 14 | information about the platforms, configurations, and project features selected with the 15 | Application Wizard. 16 | 17 | panda_playground.vcxproj.filters 18 | This is the filters file for VC++ projects generated using an Application Wizard. 19 | It contains information about the association between the files in your project 20 | and the filters. This association is used in the IDE to show grouping of files with 21 | similar extensions under a specific node (for e.g. ".cpp" files are associated with the 22 | "Source Files" filter). 23 | 24 | panda_playground.cpp 25 | This is the main application source file. 26 | 27 | ///////////////////////////////////////////////////////////////////////////// 28 | Other standard files: 29 | 30 | StdAfx.h, StdAfx.cpp 31 | These files are used to build a precompiled header (PCH) file 32 | named panda_playground.pch and a precompiled types file named StdAfx.obj. 33 | 34 | ///////////////////////////////////////////////////////////////////////////// 35 | Other notes: 36 | 37 | AppWizard uses "TODO:" comments to indicate parts of the source code you 38 | should add to or customize. 39 | 40 | ///////////////////////////////////////////////////////////////////////////// 41 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/panda_playground.cpp: -------------------------------------------------------------------------------- 1 | // panda_playground.cpp : Defines the entry point for the console application. 2 | // 3 | 4 | #include "stdafx.h" 5 | #include "pandaJ2534DLL Test\Loader4.h" 6 | #include "ECUsim DLL\ECUsim.h" 7 | #include 8 | 9 | 10 | int _tmain(int Argc, _TCHAR *Argv) { 11 | UNREFERENCED_PARAMETER(Argc); 12 | UNREFERENCED_PARAMETER(Argv); 13 | 14 | ECUsim sim("", 500000); 15 | 16 | //if (LoadJ2534Dll("C:\\WINDOWS\\SysWOW64\\op20pt32.dll") != 0) { 17 | if (LoadJ2534Dll("pandaJ2534.dll") != 0) { 18 | auto err = GetLastError(); 19 | return 1; 20 | } 21 | unsigned long did, cid, fid; 22 | PassThruOpen("", &did); 23 | PassThruConnect(did, ISO15765, CAN_29BIT_ID, 500000, &cid); 24 | 25 | PASSTHRU_MSG mask, pattern, flow; 26 | 27 | memcpy(mask.Data, "\xff\xff\xff\xff", 4); 28 | mask.DataSize = 4; 29 | mask.ProtocolID = ISO15765; 30 | mask.TxFlags = CAN_29BIT_ID; 31 | mask.ExtraDataIndex = 0; 32 | mask.RxStatus = 0; 33 | 34 | ////////////////////////18//DA//F1//EF 35 | memcpy(pattern.Data, "\x18\xda\xf1\xef", 4); 36 | pattern.DataSize = 4; 37 | pattern.ProtocolID = ISO15765; 38 | pattern.TxFlags = CAN_29BIT_ID; 39 | pattern.ExtraDataIndex = 0; 40 | pattern.RxStatus = 0; 41 | 42 | memcpy(flow.Data, "\x18\xda\xef\xf1", 4); 43 | flow.DataSize = 4; 44 | flow.ProtocolID = ISO15765; 45 | flow.TxFlags = CAN_29BIT_ID; 46 | flow.ExtraDataIndex = 0; 47 | flow.RxStatus = 0; 48 | 49 | auto res = PassThruStartMsgFilter(cid, FLOW_CONTROL_FILTER, &mask, &pattern, &flow, &fid); 50 | if (res != STATUS_NOERROR) 51 | return 1; 52 | 53 | SCONFIG_LIST list; 54 | SCONFIG config; 55 | config.Parameter = LOOPBACK; 56 | config.Value = 0; 57 | list.ConfigPtr = &config; 58 | list.NumOfParams = 1; 59 | 60 | res = PassThruIoctl(cid, SET_CONFIG, &list, NULL); 61 | if (res != STATUS_NOERROR) 62 | return 1; 63 | 64 | PASSTHRU_MSG outmsg; 65 | memcpy(outmsg.Data, "\x18\xda\xef\xf1""\xAA\xBB\xCC\xDD\xEE\xFF\x11\x22\x33\x44", 4 + 10); 66 | outmsg.DataSize = 4 + 10; 67 | outmsg.ProtocolID = ISO15765; 68 | outmsg.TxFlags = CAN_29BIT_ID; 69 | outmsg.ExtraDataIndex = 0; 70 | outmsg.RxStatus = 0; 71 | 72 | unsigned long msgoutcount = 1; 73 | 74 | res = PassThruWriteMsgs(cid, &outmsg, &msgoutcount, 0); 75 | if (res != STATUS_NOERROR) 76 | return 1; 77 | 78 | PASSTHRU_MSG inmsg[8]; 79 | unsigned long msgincount = 8; 80 | 81 | res = PassThruReadMsgs(cid, inmsg, &msgincount, 1000); 82 | if (res != STATUS_NOERROR) 83 | return 1; 84 | 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/panda_playground.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | 35 | 36 | Source Files 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // panda_playground.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #include "targetver.h" 9 | 10 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 11 | // Windows Header Files: 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | -------------------------------------------------------------------------------- /drivers/windows/panda_playground/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /drivers/windows/panda_remove.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/panda_remove.ico -------------------------------------------------------------------------------- /drivers/windows/panda_shared/device.h: -------------------------------------------------------------------------------- 1 | #ifndef __PANDA_DEVICE 2 | #define __PANDA_DEVICE 3 | 4 | // 5 | // Define below GUIDs 6 | // 7 | #include 8 | #include 9 | 10 | #if defined(UNICODE) 11 | #define _tcout std::wcout 12 | #define tstring std::wstring 13 | #else 14 | #define _tcout std::cout 15 | #define tstring std::string 16 | #endif 17 | 18 | // 19 | // Device Interface GUID. 20 | // Used by all WinUsb devices that this application talks to. 21 | // Must match "DeviceInterfaceGUIDs" registry value specified in the INF file. 22 | // cce5291c-a69f-4995-a4c2-2ae57a51ade9 23 | // 24 | DEFINE_GUID(GUID_DEVINTERFACE_panda, 25 | 0xcce5291c,0xa69f,0x4995,0xa4,0xc2,0x2a,0xe5,0x7a,0x51,0xad,0xe9); 26 | 27 | tstring GetLastErrorAsString(); 28 | 29 | namespace panda { 30 | std::unordered_map __declspec(dllexport) detect_pandas(); 31 | } 32 | #endif 33 | -------------------------------------------------------------------------------- /drivers/windows/panda_shared/panda_shared.vcxitems: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | $(MSBuildAllProjects);$(MSBuildThisFileFullPath) 5 | true 6 | {0c843279-68c7-4679-ae51-9bc463d50d1c} 7 | 8 | 9 | 10 | %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /drivers/windows/panda_shared/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | 10 | #define WINVER _WIN32_WINNT_WIN7 11 | #define _WIN32_WINNT _WIN32_WINNT_WIN7 12 | 13 | #include 14 | -------------------------------------------------------------------------------- /drivers/windows/redist/.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | vscruntimeinfo.nsh 3 | -------------------------------------------------------------------------------- /drivers/windows/redist/README.md: -------------------------------------------------------------------------------- 1 | When building the installer, please put the relevant vc_redist.x86.exe file into this folder. 2 | Make sure that the uninstall registry key is correct in the panda_install.nsi file. 3 | 4 | Here is a list of the VC runtime downloads: https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads 5 | An list of the registry keys has been maintained here: https://stackoverflow.com/a/34209692/627525 6 | 7 | Copy vscruntimeinfo.nsh.sample to vscruntimeinfo.nsh and edit it for your version of Visual Studio. -------------------------------------------------------------------------------- /drivers/windows/redist/vscruntimeinfo.nsh.sample: -------------------------------------------------------------------------------- 1 | ;NOTE! The panda software requires a VC runtime to be installed in order to work. 2 | ;This installer must be bundled with the appropriate runtime installer, and have 3 | ;the installation registry key set so the installer can tell if the runtime is 4 | ;already installed. 5 | 6 | ;Here is a list of the VC runtime downloads: https://support.microsoft.com/en-us/help/2977003/the-latest-supported-visual-c-downloads 7 | ;An list of the registry keys has been maintained here: https://stackoverflow.com/a/34209692/627525 8 | 9 | 10 | ;Microsoft Visual C++ 2015-2019 Redistributable (x86) - 14.24.28127 11 | !define VCRuntimeRegKey "Installer\Dependencies\VC,redist.x86,x86,14.24,bundle" 12 | !define VCRuntimeSetupPath "redist\" 13 | !define VCRuntimeSetupFile "vc_redist.x86.exe" -------------------------------------------------------------------------------- /drivers/windows/test certs/commaaiCertStore.pvk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/test certs/commaaiCertStore.pvk -------------------------------------------------------------------------------- /drivers/windows/test certs/commaaicert.cer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/drivers/windows/test certs/commaaicert.cer -------------------------------------------------------------------------------- /examples/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/examples/__init__.py -------------------------------------------------------------------------------- /examples/can_bit_transition.md: -------------------------------------------------------------------------------- 1 | # How to use can_bit_transition.py to reverse engineer a single bit field 2 | 3 | Let's say our goal is to find a brake pedal signal (caused by your foot pressing the brake pedal vs adaptive cruise control braking). 4 | 5 | The following process will allow you to quickly find bits that are always 0 during a period of time (when you know you were not pressing the brake with your foot) and always 1 in a different period of time (when you know you were pressing the brake with your foot). 6 | 7 | Open up a drive in cabana where you can find a place you used the brake pedal and another place where you did not use the brake pedal (and you can identify when you were on the brake pedal and when you were not). You may want to go out for a drive and put something in front of the camera after you put your foot on the brake and take it away before you take your foot off the brake so you can easily identify exactly when you had your foot on the brake based on the video in cabana. This is critical because this script needs the brake signal to always be high the entire time for one of the time frames. A 10 second time frame worked well for me. 8 | 9 | I found a drive where I knew I was not pressing the brake between timestamp 50.0 thru 65.0 and I was pressing the brake between timestamp 69.0 thru 79.0. Determine what the timestamps are in cabana by plotting any message and putting your mouse over the plot at the location you want to discover the timestamp. The tool tip on mouse hover has the format: timestamp: value 10 | 11 | Now download the log from cabana (Save Log button) and run the script passing in the timestamps 12 | (replace csv file name with cabana log you downloaded and time ranges with your own) 13 | ``` 14 | ./can_bit_transition.py ./honda_crv_ex_2017_can-1520354796875.csv 50.0-65.0 69.0-79.0 15 | ``` 16 | 17 | The script will output bits that were always low in the first time range and always high in the second time range (and vice versa) 18 | ``` 19 | id 17c 0 -> 1 at byte 4 bitmask 1 20 | id 17c 0 -> 1 at byte 6 bitmask 32 21 | id 221 1 -> 0 at byte 0 bitmask 4 22 | id 1be 0 -> 1 at byte 0 bitmask 16 23 | ``` 24 | 25 | Now I go back to cabana and graph the above bits by searching for the message by id, double clicking on the appropriate bit, and then selecting "show plot". I already knew that message id 0x17c is both user brake and adaptive cruise control braking combined, so I plotted one of those signals along side 0x221 and 0x1be. By replaying a drive I could see that 0x221 was not a brake signal (when high at random times that did not correspond to braking). Next I looked at 0x1be and I found it was the brake pedal signal I was looking for (went high whenever I pressed the brake pedal and did not go high when adaptive cruise control was braking). -------------------------------------------------------------------------------- /examples/can_logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import csv 4 | import sys 5 | from panda import Panda 6 | 7 | def can_logger(): 8 | 9 | try: 10 | print("Trying to connect to Panda over USB...") 11 | p = Panda() 12 | 13 | except AssertionError: 14 | print("USB connection failed. Trying WiFi...") 15 | 16 | try: 17 | p = Panda("WIFI") 18 | except: 19 | print("WiFi connection timed out. Please make sure your Panda is connected and try again.") 20 | sys.exit(0) 21 | 22 | try: 23 | outputfile = open('output.csv', 'w') 24 | csvwriter = csv.writer(outputfile) 25 | #Write Header 26 | csvwriter.writerow(['Bus', 'MessageID', 'Message', 'MessageLength']) 27 | print("Writing csv file output.csv. Press Ctrl-C to exit...\n") 28 | 29 | bus0_msg_cnt = 0 30 | bus1_msg_cnt = 0 31 | bus2_msg_cnt = 0 32 | 33 | while True: 34 | can_recv = p.can_recv() 35 | 36 | for address, _, dat, src in can_recv: 37 | csvwriter.writerow([str(src), str(hex(address)), f"0x{dat.hex()}", len(dat)]) 38 | 39 | if src == 0: 40 | bus0_msg_cnt += 1 41 | elif src == 1: 42 | bus1_msg_cnt += 1 43 | elif src == 2: 44 | bus2_msg_cnt += 1 45 | 46 | print(f"Message Counts... Bus 0: {bus0_msg_cnt} Bus 1: {bus1_msg_cnt} Bus 2: {bus2_msg_cnt}", end='\r') 47 | 48 | except KeyboardInterrupt: 49 | print(f"\nNow exiting. Final message Counts... Bus 0: {bus0_msg_cnt} Bus 1: {bus1_msg_cnt} Bus 2: {bus2_msg_cnt}") 50 | outputfile.close() 51 | 52 | if __name__ == "__main__": 53 | can_logger() 54 | -------------------------------------------------------------------------------- /examples/get_panda_password.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | from panda import Panda 4 | 5 | def get_panda_password(): 6 | 7 | try: 8 | print("Trying to connect to Panda over USB...") 9 | p = Panda() 10 | 11 | except AssertionError: 12 | print("USB connection failed") 13 | sys.exit(0) 14 | 15 | wifi = p.get_serial() 16 | #print('[%s]' % ', '.join(map(str, wifi))) 17 | print("SSID: " + wifi[0]) 18 | print("Password: " + wifi[1]) 19 | 20 | if __name__ == "__main__": 21 | get_panda_password() 22 | -------------------------------------------------------------------------------- /examples/query_vin_and_stats.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | import struct 4 | from panda import Panda 5 | from hexdump import hexdump 6 | from panda.python.isotp import isotp_send, isotp_recv 7 | 8 | # 0x7e0 = Toyota 9 | # 0x18DB33F1 for Honda? 10 | 11 | 12 | def get_current_data_for_pid(pid): 13 | # 01 xx = Show current data 14 | isotp_send(panda, b"\x01"+ bytes([pid]), 0x7e0) 15 | return isotp_recv(panda, 0x7e8) 16 | 17 | def get_supported_pids(): 18 | ret = [] 19 | pid = 0 20 | while 1: 21 | supported = struct.unpack(">I", get_current_data_for_pid(pid)[2:])[0] 22 | for i in range(1+pid, 0x21+pid): 23 | if supported & 0x80000000: 24 | ret.append(i) 25 | supported <<= 1 26 | pid += 0x20 27 | if pid not in ret: 28 | break 29 | return ret 30 | 31 | if __name__ == "__main__": 32 | panda = Panda() 33 | panda.set_safety_mode(Panda.SAFETY_ELM327) 34 | panda.can_clear(0) 35 | 36 | # 09 02 = Get VIN 37 | isotp_send(panda, b"\x09\x02", 0x7df) 38 | ret = isotp_recv(panda, 0x7e8) 39 | hexdump(ret) 40 | print("VIN: %s" % "".join(map(chr, ret[:2]))) 41 | 42 | # 03 = get DTCS 43 | isotp_send(panda, b"\x03", 0x7e0) 44 | dtcs = isotp_recv(panda, 0x7e8) 45 | print("DTCs:", "".join(map(chr, dtcs[:2]))) 46 | 47 | supported_pids = get_supported_pids() 48 | print("Supported PIDs:",supported_pids) 49 | 50 | while 1: 51 | speed = struct.unpack(">B", get_current_data_for_pid(13)[2:])[0] # kph 52 | rpm = struct.unpack(">H", get_current_data_for_pid(12)[2:])[0]/4.0 # revs 53 | throttle = struct.unpack(">B", get_current_data_for_pid(17)[2:])[0]/255.0 * 100 # percent 54 | temp = struct.unpack(">B", get_current_data_for_pid(5)[2:])[0] - 40 # degrees C 55 | load = struct.unpack(">B", get_current_data_for_pid(4)[2:])[0]/255.0 * 100 # percent 56 | print("%d KPH, %d RPM, %.1f%% Throttle, %d deg C, %.1f%% load" % (speed, rpm, throttle, temp, load)) 57 | time.sleep(0.2) 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /examples/tesla_tester.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import binascii 4 | from panda import Panda 5 | 6 | def tesla_tester(): 7 | 8 | try: 9 | print("Trying to connect to Panda over USB...") 10 | p = Panda() 11 | 12 | except AssertionError: 13 | print("USB connection failed. Trying WiFi...") 14 | 15 | try: 16 | p = Panda("WIFI") 17 | except: 18 | print("WiFi connection timed out. Please make sure your Panda is connected and try again.") 19 | sys.exit(0) 20 | 21 | body_bus_speed = 125 # Tesla Body busses (B, BF) are 125kbps, rest are 500kbps 22 | body_bus_num = 1 # My TDC to OBD adapter has PT on bus0 BDY on bus1 and CH on bus2 23 | p.set_can_speed_kbps(body_bus_num, body_bus_speed) 24 | 25 | # Now set the panda from its default of SAFETY_SILENT (read only) to SAFETY_ALLOUTPUT 26 | # Careful, as this will let us send any CAN messages we want (which could be very bad!) 27 | print("Setting Panda to output mode...") 28 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 29 | 30 | # BDY 0x248 is the MCU_commands message, which includes folding mirrors, opening the trunk, frunk, setting the cars lock state and more. For our test, we will edit the 3rd byte, which is MCU_lockRequest. 0x01 will lock, 0x02 will unlock: 31 | print("Unlocking Tesla...") 32 | p.can_send(0x248, b"\x00\x00\x02\x00\x00\x00\x00\x00", body_bus_num) 33 | 34 | #Or, we can set the first byte, MCU_frontHoodCommand + MCU_liftgateSwitch, to 0x01 to pop the frunk, or 0x04 to open/close the trunk (0x05 should open both) 35 | print("Opening Frunk...") 36 | p.can_send(0x248, b"\x01\x00\x00\x00\x00\x00\x00\x00", body_bus_num) 37 | 38 | #Back to safety... 39 | print("Disabling output on Panda...") 40 | p.set_safety_mode(Panda.SAFETY_SILENT) 41 | 42 | print("Reading VIN from 0x568. This is painfully slow and can take up to 3 minutes (1 minute per message; 3 messages needed for full VIN)...") 43 | 44 | vin = {} 45 | while True: 46 | #Read the VIN 47 | can_recv = p.can_recv() 48 | for address, _, dat, src in can_recv: 49 | if src == body_bus_num: 50 | if address == 1384: #0x568 is VIN 51 | vin_index = int(binascii.hexlify(dat)[:2]) #first byte is the index, 00, 01, 02 52 | vin_string = binascii.hexlify(dat)[2:] #rest of the string is the actual VIN data 53 | vin[vin_index] = vin_string.decode("hex") 54 | print("Got VIN index " + str(vin_index) + " data " + vin[vin_index]) 55 | #if we have all 3 parts of the VIN, print it and break out of our while loop 56 | if 0 in vin and 1 in vin and 2 in vin: 57 | print("VIN: " + vin[0] + vin[1] + vin[2][:3]) 58 | break 59 | 60 | if __name__ == "__main__": 61 | tesla_tester() 62 | -------------------------------------------------------------------------------- /panda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/panda.png -------------------------------------------------------------------------------- /python/serial.py: -------------------------------------------------------------------------------- 1 | # mimic a python serial port 2 | class PandaSerial(object): 3 | def __init__(self, panda, port, baud): 4 | self.panda = panda 5 | self.port = port 6 | self.panda.set_uart_parity(self.port, 0) 7 | self.panda.set_uart_baud(self.port, baud) 8 | self.buf = b"" 9 | 10 | def read(self, l=1): 11 | tt = self.panda.serial_read(self.port) 12 | if len(tt) > 0: 13 | #print "R: ", tt.encode("hex") 14 | self.buf += tt 15 | ret = self.buf[0:l] 16 | self.buf = self.buf[l:] 17 | return ret 18 | 19 | def write(self, dat): 20 | #print "W: ", dat.encode("hex") 21 | #print ' pigeon_send("' + ''.join(map(lambda x: "\\x%02X" % ord(x), dat)) + '");' 22 | return self.panda.serial_write(self.port, dat) 23 | 24 | def close(self): 25 | pass 26 | 27 | 28 | -------------------------------------------------------------------------------- /python/update.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import time 4 | 5 | def ensure_st_up_to_date(): 6 | from panda import Panda, PandaDFU, BASEDIR 7 | 8 | with open(os.path.join(BASEDIR, "VERSION")) as f: 9 | repo_version = f.read() 10 | 11 | repo_version += "-EON" if os.path.isfile('/EON') else "-DEV" 12 | 13 | panda = None 14 | panda_dfu = None 15 | 16 | while 1: 17 | # break on normal mode Panda 18 | panda_list = Panda.list() 19 | if len(panda_list) > 0: 20 | panda = Panda(panda_list[0]) 21 | break 22 | 23 | # flash on DFU mode Panda 24 | panda_dfu = PandaDFU.list() 25 | if len(panda_dfu) > 0: 26 | panda_dfu = PandaDFU(panda_dfu[0]) 27 | panda_dfu.recover() 28 | 29 | print("waiting for board...") 30 | time.sleep(1) 31 | 32 | if panda.bootstub or not panda.get_version().startswith(repo_version): 33 | panda.flash() 34 | 35 | if panda.bootstub: 36 | panda.recover() 37 | 38 | assert(not panda.bootstub) 39 | version = str(panda.get_version()) 40 | print("%s should be %s" % (version, repo_version)) 41 | assert(version.startswith(repo_version)) 42 | 43 | if __name__ == "__main__": 44 | ensure_st_up_to_date() 45 | 46 | -------------------------------------------------------------------------------- /release/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | -------------------------------------------------------------------------------- /release/make_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -d "../../pandaextra" ]; then 4 | echo "No release cert found, cannot build release." 5 | echo "You probably aren't looking to do this anyway." 6 | exit 7 | fi 8 | 9 | export RELEASE=1 10 | export BUILDER=DEV 11 | 12 | # make ST + bootstub 13 | pushd . 14 | cd ../board 15 | make clean 16 | make obj/panda.bin 17 | make obj/bootstub.panda.bin 18 | popd 19 | 20 | # make ESP 21 | pushd . 22 | cd ../boardesp 23 | make clean 24 | make user1.bin 25 | make user2.bin 26 | popd 27 | 28 | # make release 29 | mkdir obj 30 | make -f ../common/version.mk 31 | make obj/gitversion.h 32 | RELEASE_NAME=$(python -c "import sys;sys.stdout.write(open('obj/gitversion.h').read().split('\"')[1])") 33 | echo -en $RELEASE_NAME > /tmp/version 34 | rm -rf obj 35 | 36 | # make zip file 37 | pushd . 38 | cd .. 39 | zip -j release/panda-$RELEASE_NAME.zip ~/one/panda/board/obj/bootstub.panda.bin ~/one/panda/board/obj/panda.bin ~/one/panda/boardesp/user?.bin ~/one/panda/boardesp/esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/bin/boot_v1.5.bin /tmp/version 40 | popd 41 | 42 | -------------------------------------------------------------------------------- /release/ota_release.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mkdir -p /tmp/panda_firmware 3 | unzip -o $1 -d /tmp/panda_firmware 4 | 5 | curl http://192.168.0.10/ 6 | 7 | echo "flashing user1" 8 | curl http://192.168.0.10/espupdate1 --upload-file /tmp/panda_firmware/user1.bin 9 | echo "flashing user2" 10 | curl http://192.168.0.10/espupdate2 --upload-file /tmp/panda_firmware/user2.bin 11 | echo "waiting 10s for reboot" 12 | sleep 10 13 | echo "flashing st" 14 | curl http://192.168.0.10/stupdate --upload-file /tmp/panda_firmware/panda.bin 15 | sleep 2 16 | curl http://192.168.0.10/ 17 | echo "done" 18 | 19 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | libusb1 == 1.6.6 2 | numpy==1.17.2 3 | hexdump>=3.3 4 | pycrypto==2.6.1 5 | tqdm>=4.14.0 6 | nose 7 | parameterized 8 | requests 9 | flake8==3.7.9 10 | pylint==2.4.3 11 | cffi==1.11.4 12 | crcmod 13 | -------------------------------------------------------------------------------- /run_automated_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | TEST_FILENAME=${TEST_FILENAME:-nosetests.xml} 3 | if [ -f "/EON" ]; then 4 | TESTSUITE_NAME="Panda_Test-EON" 5 | else 6 | TESTSUITE_NAME="Panda_Test-DEV" 7 | fi 8 | 9 | if [ ! -z "${SKIPWIFI}" ] || [ -f "/EON" ]; then 10 | TEST_SCRIPTS=$(ls tests/automated/$1*.py | grep -v wifi) 11 | else 12 | TEST_SCRIPTS=$(ls tests/automated/$1*.py) 13 | fi 14 | 15 | IFS=$'\n' 16 | for NAME in $(nmcli --fields NAME con show | grep panda | awk '{$1=$1};1') 17 | do 18 | nmcli connection delete "$NAME" 19 | done 20 | 21 | PYTHONPATH="." $(which nosetests) -v --with-xunit --xunit-file=./$TEST_FILENAME --xunit-testsuite-name=$TESTSUITE_NAME -s $TEST_SCRIPTS 22 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_wheel] 2 | universal=1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | 3 | """ 4 | Panda CAN Controller Dongle 5 | ~~~~~ 6 | 7 | Setup 8 | ````` 9 | 10 | $ pip install . # or python setup.py install 11 | """ 12 | 13 | import codecs 14 | import os 15 | import re 16 | from setuptools import setup 17 | 18 | here = os.path.abspath(os.path.dirname(__file__)) 19 | 20 | def read(*parts): 21 | """Taken from pypa pip setup.py: 22 | intentionally *not* adding an encoding option to open, See: 23 | https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690 24 | """ 25 | return codecs.open(os.path.join(here, *parts), 'r').read() 26 | 27 | 28 | def find_version(*file_paths): 29 | version_file = read(*file_paths) 30 | version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", 31 | version_file, re.M) 32 | if version_match: 33 | return version_match.group(1) 34 | raise RuntimeError("Unable to find version string.") 35 | 36 | setup( 37 | name='pandacan', 38 | version=find_version("python", "__init__.py"), 39 | url='https://github.com/commaai/panda', 40 | author='comma.ai', 41 | author_email='', 42 | packages=[ 43 | 'panda', 44 | ], 45 | package_dir = {'panda': 'python'}, 46 | platforms='any', 47 | license='MIT', 48 | install_requires=[ 49 | 'libusb1 == 1.6.6', 50 | 'hexdump >= 3.3', 51 | 'pycrypto >= 2.6.1', 52 | 'tqdm >= 4.14.0', 53 | 'requests' 54 | ], 55 | ext_modules = [], 56 | description="Code powering the comma.ai panda", 57 | long_description='See https://github.com/commaai/panda', 58 | classifiers=[ 59 | 'Development Status :: 2 - Pre-Alpha', 60 | "Natural Language :: English", 61 | "Programming Language :: Python :: 2", 62 | "Programming Language :: Python :: 3", 63 | "Topic :: System :: Hardware", 64 | ], 65 | ) 66 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/tests/__init__.py -------------------------------------------------------------------------------- /tests/all_wifi_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import requests 3 | import json 4 | from .automated.helpers import _connect_wifi 5 | from panda import Panda 6 | from nose.tools import assert_equal 7 | 8 | if __name__ == "__main__": 9 | print("Fetching latest firmware from github.com/commaai/panda-artifacts") 10 | r = requests.get("https://raw.githubusercontent.com/commaai/panda-artifacts/master/latest.json") 11 | latest_version = json.loads(r.text)['version'] 12 | 13 | for p in Panda.list(): 14 | dongle_id, pw = Panda(p).get_serial() 15 | print(dongle_id, pw) 16 | assert(dongle_id.isalnum()) 17 | _connect_wifi(dongle_id, pw) 18 | 19 | r = requests.get("http://192.168.0.10/") 20 | print(r.text) 21 | wifi_dongle_id = r.text.split("ssid: panda-")[1].split("
")[0] 22 | st_version = r.text.split("st version:")[1].strip().split("
")[0] 23 | esp_version = r.text.split("esp version:")[1].strip().split("
")[0] 24 | 25 | assert_equal(str(dongle_id), wifi_dongle_id) 26 | assert_equal(latest_version, st_version) 27 | assert_equal(latest_version, esp_version) 28 | 29 | 30 | -------------------------------------------------------------------------------- /tests/automated/0_builds.py: -------------------------------------------------------------------------------- 1 | from panda import build_st 2 | 3 | def test_build_panda(): 4 | build_st("obj/panda.bin") 5 | 6 | def test_build_bootstub_panda(): 7 | build_st("obj/bootstub.panda.bin") 8 | 9 | -------------------------------------------------------------------------------- /tests/automated/1_program.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from nose.tools import assert_equal 4 | 5 | from panda import Panda, BASEDIR 6 | from .helpers import reset_pandas, test_all_pandas, panda_connect_and_init 7 | 8 | 9 | # Reset the pandas before flashing them 10 | def aaaa_reset_before_tests(): 11 | reset_pandas() 12 | 13 | 14 | @test_all_pandas 15 | @panda_connect_and_init 16 | def test_recover(p): 17 | assert p.recover(timeout=30) 18 | 19 | 20 | @test_all_pandas 21 | @panda_connect_and_init 22 | def test_flash(p): 23 | p.flash() 24 | 25 | 26 | @test_all_pandas 27 | @panda_connect_and_init 28 | def test_get_signature(p): 29 | fn = os.path.join(BASEDIR, "board/obj/panda.bin") 30 | 31 | firmware_sig = Panda.get_signature_from_firmware(fn) 32 | panda_sig = p.get_signature() 33 | 34 | assert_equal(panda_sig, firmware_sig) 35 | -------------------------------------------------------------------------------- /tests/automated/2_health.py: -------------------------------------------------------------------------------- 1 | import time 2 | from panda_jungle import PandaJungle # pylint: disable=import-error 3 | from .helpers import panda_jungle, reset_pandas, test_all_pandas, test_all_gen2_pandas, panda_connect_and_init 4 | 5 | # Reset the pandas before running tests 6 | def aaaa_reset_before_tests(): 7 | reset_pandas() 8 | 9 | @test_all_pandas 10 | @panda_connect_and_init 11 | def test_ignition(p): 12 | try: 13 | # Set harness orientation to #2, since the ignition line is on the wrong SBU bus :/ 14 | panda_jungle.set_harness_orientation(PandaJungle.HARNESS_ORIENTATION_2) 15 | reset_pandas() 16 | p.reconnect() 17 | panda_jungle.set_ignition(False) 18 | time.sleep(2) 19 | assert p.health()['ignition_line'] == False 20 | panda_jungle.set_ignition(True) 21 | time.sleep(2) 22 | assert p.health()['ignition_line'] == True 23 | finally: 24 | panda_jungle.set_harness_orientation(PandaJungle.HARNESS_ORIENTATION_1) 25 | 26 | @test_all_gen2_pandas 27 | @panda_connect_and_init 28 | def test_orientation_detection(p): 29 | seen_orientations = [] 30 | for i in range(3): 31 | panda_jungle.set_harness_orientation(i) 32 | reset_pandas() 33 | p.reconnect() 34 | detected_harness_orientation = p.health()['car_harness_status'] 35 | if (i == 0 and detected_harness_orientation != 0) or detected_harness_orientation in seen_orientations: 36 | assert False 37 | seen_orientations.append(detected_harness_orientation) 38 | 39 | 40 | @test_all_pandas 41 | @panda_connect_and_init 42 | def test_voltage(p): 43 | voltage = p.health()['voltage'] 44 | assert ((voltage > 10000) and (voltage < 14000)) -------------------------------------------------------------------------------- /tests/automated/4_wifi.py: -------------------------------------------------------------------------------- 1 | import time 2 | from panda import Panda 3 | from .helpers import reset_pandas, connect_wifi, test_white, test_all_pandas, panda_type_to_serial, panda_connect_and_init 4 | import requests 5 | 6 | # Reset the pandas before running tests 7 | def aaaa_reset_before_tests(): 8 | reset_pandas() 9 | 10 | @test_all_pandas 11 | @panda_connect_and_init 12 | def test_get_serial(p): 13 | print(p.get_serial()) 14 | 15 | @test_all_pandas 16 | @panda_connect_and_init 17 | def test_get_serial_in_flash_mode(p): 18 | p.reset(enter_bootstub=True) 19 | assert(p.bootstub) 20 | print(p.get_serial()) 21 | p.reset() 22 | 23 | @test_white 24 | @panda_type_to_serial 25 | def test_connect_wifi(serials=None): 26 | connect_wifi(serials[0]) 27 | 28 | @test_white 29 | @panda_type_to_serial 30 | def test_flash_wifi(serials=None): 31 | connect_wifi(serials[0]) 32 | assert Panda.flash_ota_wifi(release=False), "OTA Wifi Flash Failed" 33 | connect_wifi(serials[0]) 34 | 35 | @test_white 36 | @panda_type_to_serial 37 | def test_wifi_flash_st(serials=None): 38 | connect_wifi(serials[0]) 39 | assert Panda.flash_ota_st(), "OTA ST Flash Failed" 40 | connected = False 41 | st = time.time() 42 | while not connected and (time.time() - st) < 20: 43 | try: 44 | p = Panda(serial=serials[0]) 45 | p.get_serial() 46 | connected = True 47 | except: 48 | time.sleep(1) 49 | 50 | if not connected: 51 | assert False, "Panda failed to connect on USB after flashing" 52 | 53 | @test_white 54 | @panda_type_to_serial 55 | def test_webpage_fetch(serials=None): 56 | connect_wifi(serials[0]) 57 | r = requests.get("http://192.168.0.10/") 58 | print(r.text) 59 | 60 | assert "This is your comma.ai panda" in r.text 61 | -------------------------------------------------------------------------------- /tests/automated/5_wifi_functionality.py: -------------------------------------------------------------------------------- 1 | import time 2 | from panda import Panda 3 | from .helpers import start_heartbeat_thread, reset_pandas, time_many_sends, connect_wifi, test_white, panda_type_to_serial 4 | 5 | # Reset the pandas before running tests 6 | def aaaa_reset_before_tests(): 7 | reset_pandas() 8 | 9 | @test_white 10 | @panda_type_to_serial 11 | def test_get_serial_wifi(serials=None): 12 | connect_wifi(serials[0]) 13 | 14 | p = Panda("WIFI") 15 | print(p.get_serial()) 16 | 17 | @test_white 18 | @panda_type_to_serial 19 | def test_throughput(serials=None): 20 | connect_wifi(serials[0]) 21 | p = Panda(serials[0]) 22 | 23 | # Start heartbeat 24 | start_heartbeat_thread(p) 25 | 26 | # enable output mode 27 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 28 | 29 | # enable CAN loopback mode 30 | p.set_can_loopback(True) 31 | 32 | p = Panda("WIFI") 33 | 34 | for speed in [100,250,500,750,1000]: 35 | # set bus 0 speed to speed 36 | p.set_can_speed_kbps(0, speed) 37 | time.sleep(0.1) 38 | 39 | comp_kbps = time_many_sends(p, 0) 40 | 41 | # bit count from https://en.wikipedia.org/wiki/CAN_bus 42 | saturation_pct = (comp_kbps/speed) * 100.0 43 | #assert_greater(saturation_pct, 80) 44 | #assert_less(saturation_pct, 100) 45 | 46 | print("WIFI loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct)) 47 | 48 | @test_white 49 | @panda_type_to_serial 50 | def test_recv_only(serials=None): 51 | connect_wifi(serials[0]) 52 | p = Panda(serials[0]) 53 | 54 | # Start heartbeat 55 | start_heartbeat_thread(p) 56 | 57 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 58 | 59 | p.set_can_loopback(True) 60 | pwifi = Panda("WIFI") 61 | 62 | # TODO: msg_count=1000 drops packets, is this fixable? 63 | for msg_count in [10,100,200]: 64 | speed = 500 65 | p.set_can_speed_kbps(0, speed) 66 | comp_kbps = time_many_sends(p, 0, pwifi, msg_count) 67 | saturation_pct = (comp_kbps/speed) * 100.0 68 | 69 | print("HT WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) 70 | -------------------------------------------------------------------------------- /tests/automated/6_wifi_udp.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | from .helpers import start_heartbeat_thread, reset_pandas, time_many_sends, connect_wifi, test_white, panda_type_to_serial 4 | from panda import Panda, PandaWifiStreaming 5 | from nose.tools import assert_less, assert_greater 6 | 7 | # Reset the pandas before running tests 8 | def aaaa_reset_before_tests(): 9 | reset_pandas() 10 | 11 | @test_white 12 | @panda_type_to_serial 13 | def test_udp_doesnt_drop(serials=None): 14 | connect_wifi(serials[0]) 15 | 16 | p = Panda(serials[0]) 17 | 18 | # Start heartbeat 19 | start_heartbeat_thread(p) 20 | 21 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 22 | p.set_can_loopback(True) 23 | 24 | pwifi = PandaWifiStreaming() 25 | while 1: 26 | if len(pwifi.can_recv()) == 0: 27 | break 28 | 29 | for msg_count in [1, 100]: 30 | saturation_pcts = [] 31 | for i in range({1: 0x80, 100: 0x20}[msg_count]): 32 | pwifi.kick() 33 | 34 | speed = 500 35 | p.set_can_speed_kbps(0, speed) 36 | comp_kbps = time_many_sends(p, 0, pwifi, msg_count=msg_count, msg_id=0x100+i) 37 | saturation_pct = (comp_kbps/speed) * 100.0 38 | 39 | if msg_count == 1: 40 | sys.stdout.write(".") 41 | sys.stdout.flush() 42 | else: 43 | print("UDP WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) 44 | assert_greater(saturation_pct, 20) #sometimes the wifi can be slow... 45 | assert_less(saturation_pct, 100) 46 | saturation_pcts.append(saturation_pct) 47 | if len(saturation_pcts) > 0: 48 | assert_greater(sum(saturation_pcts)/len(saturation_pcts), 60) 49 | 50 | time.sleep(5) 51 | usb_ok_cnt = 0 52 | REQ_USB_OK_CNT = 500 53 | st = time.time() 54 | msg_id = 0x1bb 55 | bus = 0 56 | last_missing_msg = 0 57 | while usb_ok_cnt < REQ_USB_OK_CNT and (time.time() - st) < 40: 58 | p.can_send(msg_id, "message", bus) 59 | time.sleep(0.01) 60 | r = [1] 61 | missing = True 62 | while len(r) > 0: 63 | r = p.can_recv() 64 | r = [x for x in r if x[3] == bus and x[0] == msg_id] 65 | if len(r) > 0: 66 | missing = False 67 | usb_ok_cnt += len(r) 68 | if missing: 69 | last_missing_msg = time.time() 70 | et = time.time() - st 71 | last_missing_msg = last_missing_msg - st 72 | print("waited {} for panda to recv can on usb, {} msgs, last missing at {}".format(et, usb_ok_cnt, last_missing_msg)) 73 | assert usb_ok_cnt >= REQ_USB_OK_CNT, "Unable to recv can on USB after UDP" 74 | -------------------------------------------------------------------------------- /tests/automated/8_gps.py: -------------------------------------------------------------------------------- 1 | import time 2 | from panda import PandaSerial 3 | from .helpers import reset_pandas, test_all_gps_pandas, panda_connect_and_init 4 | 5 | # Reset the pandas before running tests 6 | def aaaa_reset_before_tests(): 7 | reset_pandas() 8 | 9 | @test_all_gps_pandas 10 | @panda_connect_and_init 11 | def test_gps_version(p): 12 | serial = PandaSerial(p, 1, 9600) 13 | # Reset and check twice to make sure the enabling works 14 | for i in range(2): 15 | # Reset GPS 16 | p.set_esp_power(0) 17 | time.sleep(0.5) 18 | p.set_esp_power(1) 19 | time.sleep(1) 20 | 21 | # Read startup message and check if version is contained 22 | dat = serial.read(0x1000) # Read one full panda DMA buffer. This should include the startup message 23 | assert b'HPG 1.40ROV' in dat -------------------------------------------------------------------------------- /tests/automated/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/tests/automated/__init__.py -------------------------------------------------------------------------------- /tests/automated/timeout.py: -------------------------------------------------------------------------------- 1 | import time 2 | from multiprocessing import Process 3 | 4 | # Note: this does not return any return values of the function, just the exit status 5 | INTERVAL = 0.1 6 | def run_with_timeout(timeout, fn, *kwargs): 7 | def runner(fn, kwargs): 8 | try: 9 | fn(*kwargs) 10 | except Exception as e: 11 | print(e) 12 | raise e 13 | 14 | process = Process(target=runner, args=(fn, kwargs)) 15 | process.start() 16 | 17 | counter = 0 18 | while process.is_alive(): 19 | time.sleep(INTERVAL) 20 | counter+=1 21 | if (counter * INTERVAL) > timeout: 22 | process.terminate() 23 | raise TimeoutError("Function timed out!") 24 | if process.exitcode != 0: 25 | raise RuntimeError("Test failed with exit code: ", str(process.exitcode)) -------------------------------------------------------------------------------- /tests/build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y gcc-arm-none-eabi libnewlib-arm-none-eabi python python-pip gcc g++ git autoconf gperf bison flex automake texinfo wget help2man gawk libtool libtool-bin ncurses-dev unzip unrar-free libexpat-dev sed bzip2 locales curl zlib1g-dev libffi-dev libssl-dev 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 2.7.12 14 | RUN pyenv install 3.7.3 15 | RUN pyenv global 3.7.3 16 | RUN pyenv rehash 17 | 18 | RUN pip install pycrypto==2.6.1 19 | 20 | # Build esp toolchain 21 | RUN mkdir -p /panda/boardesp 22 | WORKDIR /panda/boardesp 23 | RUN git clone --recursive https://github.com/pfalcon/esp-open-sdk.git 24 | WORKDIR /panda/boardesp/esp-open-sdk 25 | RUN git checkout 03f5e898a059451ec5f3de30e7feff30455f7ce 26 | COPY ./boardesp/python2_make.py /panda/boardesp/esp-open-sdk 27 | RUN python2 python2_make.py "CT_ALLOW_BUILD_AS_ROOT_SURE=1 make STANDALONE=y" 28 | 29 | COPY . /panda 30 | 31 | WORKDIR /panda 32 | -------------------------------------------------------------------------------- /tests/can_printer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import time 6 | from collections import defaultdict 7 | import binascii 8 | 9 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 10 | from panda import Panda 11 | 12 | # fake 13 | def sec_since_boot(): 14 | return time.time() 15 | 16 | def can_printer(): 17 | p = Panda() 18 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 19 | 20 | start = sec_since_boot() 21 | lp = sec_since_boot() 22 | msgs = defaultdict(list) 23 | canbus = int(os.getenv("CAN", 0)) 24 | while True: 25 | can_recv = p.can_recv() 26 | for address, _, dat, src in can_recv: 27 | if src == canbus: 28 | msgs[address].append(dat) 29 | 30 | if sec_since_boot() - lp > 0.1: 31 | dd = chr(27) + "[2J" 32 | dd += "%5.2f\n" % (sec_since_boot() - start) 33 | for k,v in sorted(zip(list(msgs.keys()), [binascii.hexlify(x[-1]) for x in list(msgs.values())])): 34 | dd += "%s(%6d) %s\n" % ("%04X(%4d)" % (k,k),len(msgs[k]), v) 35 | print(dd) 36 | lp = sec_since_boot() 37 | 38 | if __name__ == "__main__": 39 | can_printer() 40 | -------------------------------------------------------------------------------- /tests/debug_console.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import time 6 | import select 7 | 8 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 9 | from panda import Panda 10 | 11 | setcolor = ["\033[1;32;40m", "\033[1;31;40m"] 12 | unsetcolor = "\033[00m" 13 | 14 | if __name__ == "__main__": 15 | while True: 16 | try: 17 | port_number = int(os.getenv("PORT", 0)) 18 | claim = os.getenv("CLAIM") is not None 19 | 20 | serials = Panda.list() 21 | if os.getenv("SERIAL"): 22 | serials = [x for x in serials if x==os.getenv("SERIAL")] 23 | 24 | pandas = list([Panda(x, claim=claim) for x in serials]) 25 | 26 | if not len(pandas): 27 | sys.exit("no pandas found") 28 | 29 | if os.getenv("BAUD") is not None: 30 | for panda in pandas: 31 | panda.set_uart_baud(port_number, int(os.getenv("BAUD"))) 32 | 33 | while True: 34 | for i, panda in enumerate(pandas): 35 | while True: 36 | ret = panda.serial_read(port_number) 37 | if len(ret) > 0: 38 | sys.stdout.write(setcolor[i] + ret.decode('ascii') + unsetcolor) 39 | sys.stdout.flush() 40 | else: 41 | break 42 | if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []): 43 | ln = sys.stdin.readline() 44 | if claim: 45 | panda.serial_write(port_number, ln) 46 | time.sleep(0.01) 47 | except Exception: 48 | print("panda disconnected!") 49 | time.sleep(0.5); 50 | -------------------------------------------------------------------------------- /tests/development/register_hashmap_spread.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import matplotlib.pyplot as plt # pylint: disable=import-error 3 | 4 | HASHING_PRIME = 23 5 | REGISTER_MAP_SIZE = 0x3FF 6 | BYTES_PER_REG = 4 7 | 8 | # From ST32F413 datasheet 9 | REGISTER_ADDRESS_REGIONS = [ 10 | (0x40000000, 0x40007FFF), 11 | (0x40010000, 0x400107FF), 12 | (0x40011000, 0x400123FF), 13 | (0x40012C00, 0x40014BFF), 14 | (0x40015000, 0x400153FF), 15 | (0x40015800, 0x40015BFF), 16 | (0x40016000, 0x400167FF), 17 | (0x40020000, 0x40021FFF), 18 | (0x40023000, 0x400233FF), 19 | (0x40023800, 0x40023FFF), 20 | (0x40026000, 0x400267FF), 21 | (0x50000000, 0x5003FFFF), 22 | (0x50060000, 0x500603FF), 23 | (0x50060800, 0x50060BFF), 24 | (0x50060800, 0x50060BFF), 25 | (0xE0000000, 0xE00FFFFF) 26 | ] 27 | 28 | def hash(reg_addr): 29 | return (((reg_addr >> 16) ^ ((((reg_addr + 1) & 0xFFFF) * HASHING_PRIME) & 0xFFFF)) & REGISTER_MAP_SIZE) 30 | 31 | # Calculate hash for each address 32 | hashes = [] 33 | double_hashes = [] 34 | for (start_addr, stop_addr) in REGISTER_ADDRESS_REGIONS: 35 | for addr in range(start_addr, stop_addr+1, BYTES_PER_REG): 36 | h = hash(addr) 37 | hashes.append(h) 38 | double_hashes.append(hash(h)) 39 | 40 | # Make histograms 41 | plt.subplot(2, 1, 1) 42 | plt.hist(hashes, bins=REGISTER_MAP_SIZE) 43 | plt.title("Number of collisions per hash") 44 | plt.xlabel("Address") 45 | 46 | plt.subplot(2, 1, 2) 47 | plt.hist(double_hashes, bins=REGISTER_MAP_SIZE) 48 | plt.title("Number of collisions per double hash") 49 | plt.xlabel("Address") 50 | plt.show() 51 | -------------------------------------------------------------------------------- /tests/disable_esp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from panda import Panda 3 | Panda().set_esp_power(False) 4 | 5 | -------------------------------------------------------------------------------- /tests/echo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import time 5 | import _thread 6 | 7 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 8 | from panda import Panda 9 | 10 | # This script is intended to be used in conjunction with the echo_loopback_test.py test script from panda jungle. 11 | # It sends a reversed response back for every message received containing b"test". 12 | 13 | def heartbeat_thread(p): 14 | while True: 15 | try: 16 | p.send_heartbeat() 17 | time.sleep(1) 18 | except: 19 | break 20 | 21 | # Resend every CAN message that has been received on the same bus, but with the data reversed 22 | if __name__ == "__main__": 23 | p = Panda() 24 | _thread.start_new_thread(heartbeat_thread, (p,)) 25 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 26 | p.set_power_save(False) 27 | 28 | while True: 29 | incoming = p.can_recv() 30 | for message in incoming: 31 | address, notused, data, bus = message 32 | if b'test' in data: 33 | p.can_send(address, data[::-1], bus) 34 | 35 | 36 | -------------------------------------------------------------------------------- /tests/elm_throughput.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import socket 4 | import threading 5 | import select 6 | 7 | class Reader(threading.Thread): 8 | def __init__(self, s, *args, **kwargs): 9 | super(Reader, self).__init__(*args, **kwargs) 10 | self._s = s 11 | self.__stop = False 12 | 13 | def stop(self): 14 | self.__stop = True 15 | 16 | def run(self): 17 | while not self.__stop: 18 | s.recv(1000) 19 | 20 | def read_or_fail(s): 21 | ready = select.select([s], [], [], 4) 22 | assert ready[0], "Socket did not receive data within the timeout duration." 23 | return s.recv(1000) 24 | 25 | def send_msg(s, msg): 26 | s.send(msg) 27 | res = b'' 28 | while not res.endswith(">"): 29 | res += read_or_fail(s) 30 | return res 31 | 32 | if __name__ == "__main__": 33 | s = socket.create_connection(("192.168.0.10", 35000)) 34 | #t1 = Reader(s) 35 | #t1.start() 36 | send_msg(s, b"ATZ\r") 37 | send_msg(s, b"ATL1\r") 38 | print(send_msg(s, b"ATE0\r")) 39 | print(send_msg(s, b"ATS0\r")) 40 | print(send_msg(s, b"ATSP6\r")) 41 | 42 | print("\nLOOP\n") 43 | 44 | while True: 45 | print(send_msg(s, b"0100\r")) 46 | print(send_msg(s, b"010d\r")) 47 | -------------------------------------------------------------------------------- /tests/fan_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import time 5 | 6 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 7 | from panda import Panda 8 | 9 | power = 0 10 | if __name__ == "__main__": 11 | p = Panda() 12 | while True: 13 | p.set_fan_power(power) 14 | time.sleep(5) 15 | print("Power: ", power, "RPM: ", str(p.get_fan_rpm())) 16 | power += 10 17 | power %=100 18 | -------------------------------------------------------------------------------- /tests/flashing_loop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | cd ../board 3 | make clean 4 | 5 | while true; do 6 | make ota 7 | sleep 10 8 | done 9 | 10 | -------------------------------------------------------------------------------- /tests/get_version.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from panda import Panda 3 | 4 | if __name__ == "__main__": 5 | for p in Panda.list(): 6 | pp = Panda(p) 7 | print("%s: %s" % (pp.get_serial()[0], pp.get_version())) 8 | 9 | 10 | -------------------------------------------------------------------------------- /tests/gmbitbang/recv.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from panda import Panda 3 | 4 | p = Panda() 5 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 6 | p.set_gmlan(bus=2) 7 | #p.can_send(0xaaa, b"\x00\x00", bus=3) 8 | last_add = None 9 | while 1: 10 | ret = p.can_recv() 11 | if len(ret) > 0: 12 | add = ret[0][0] 13 | if last_add is not None and add != last_add + 1: 14 | print("MISS: ", last_add, add) 15 | last_add = add 16 | print(ret) 17 | -------------------------------------------------------------------------------- /tests/gmbitbang/rigol.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # pylint: skip-file 3 | import numpy as np 4 | import visa 5 | import matplotlib.pyplot as plt 6 | 7 | resources = visa.ResourceManager() 8 | print(resources.list_resources()) 9 | 10 | scope = resources.open_resource('USB0::0x1AB1::0x04CE::DS1ZA184652242::INSTR', timeout=2000, chunk_size=1024000) 11 | print(scope.query('*IDN?').strip()) 12 | 13 | #voltscale = scope.ask_for_values(':CHAN1:SCAL?')[0] 14 | #voltoffset = scope.ask_for_values(":CHAN1:OFFS?")[0] 15 | 16 | #scope.write(":STOP") 17 | scope.write(":WAV:POIN:MODE RAW") 18 | scope.write(":WAV:DATA? CHAN1")[10:] 19 | rawdata = scope.read_raw() 20 | data = np.frombuffer(rawdata, 'B') 21 | print(data.shape) 22 | 23 | s1 = data[0:650] 24 | s2 = data[650:] 25 | s1i = np.argmax(s1 > 100) 26 | s2i = np.argmax(s2 > 100) 27 | s1 = s1[s1i:] 28 | s2 = s2[s2i:] 29 | 30 | plt.plot(s1) 31 | plt.plot(s2) 32 | plt.show() 33 | #data = (data - 130.0 - voltoffset/voltscale*25) / 25 * voltscale 34 | 35 | print(data) 36 | 37 | -------------------------------------------------------------------------------- /tests/gmbitbang/test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | from panda import Panda 4 | 5 | p1 = Panda('380016000551363338383037') 6 | p2 = Panda('430026000951363338383037') 7 | 8 | # this is a test, no safety 9 | p1.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 10 | p2.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 11 | 12 | # get versions 13 | print(p1.get_version()) 14 | print(p2.get_version()) 15 | 16 | # this sets bus 2 to actually be GMLAN 17 | p2.set_gmlan(bus=2) 18 | 19 | # send w bitbang then without 20 | #iden = 123 21 | iden = 18000 22 | #dat = "\x01\x02" 23 | dat = "\x01\x02\x03\x04\x05\x06\x07\x08" 24 | while 1: 25 | iden += 1 26 | p1.set_gmlan(bus=None) 27 | p1.can_send(iden, dat, bus=3) 28 | #p1.set_gmlan(bus=2) 29 | #p1.can_send(iden, dat, bus=3) 30 | time.sleep(0.01) 31 | print(p2.can_recv()) 32 | #exit(0) 33 | 34 | -------------------------------------------------------------------------------- /tests/gmbitbang/test_one.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | from panda import Panda 4 | 5 | p = Panda() 6 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 7 | 8 | # hack anything on bus 9 | p.set_gmlan(bus=2) 10 | time.sleep(0.1) 11 | while len(p.can_recv()) > 0: 12 | print("clearing") 13 | time.sleep(0.1) 14 | print("cleared") 15 | p.set_gmlan(bus=None) 16 | 17 | iden = 18000 18 | dat = "\x01\x02\x03\x04\x05\x06\x07\x08" 19 | while 1: 20 | iden += 1 21 | p.can_send(iden, dat, bus=3) 22 | time.sleep(0.01) 23 | 24 | -------------------------------------------------------------------------------- /tests/gmbitbang/test_packer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct { 5 | uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ 6 | uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ 7 | uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ 8 | uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ 9 | } CAN_FIFOMailBox_TypeDef; 10 | 11 | #include "../../board/drivers/canbitbang.h" 12 | 13 | int main() { 14 | char out[300]; 15 | CAN_FIFOMailBox_TypeDef to_bang = {0}; 16 | to_bang.RIR = 20 << 21; 17 | to_bang.RDTR = 1; 18 | to_bang.RDLR = 1; 19 | 20 | int len = get_bit_message(out, &to_bang); 21 | printf("T:"); 22 | for (int i = 0; i < len; i++) { 23 | printf("%d", out[i]); 24 | } 25 | printf("\n"); 26 | printf("R:0000010010100000100010000010011110111010100111111111111111"); 27 | printf("\n"); 28 | return 0; 29 | } 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /tests/health_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | from panda import Panda 4 | 5 | if __name__ == "__main__": 6 | panda_serials = Panda.list() 7 | pandas = [] 8 | for ps in panda_serials: 9 | pandas.append(Panda(serial=ps)) 10 | if len(pandas) == 0: 11 | print("No pandas connected") 12 | assert False 13 | 14 | while True: 15 | for panda in pandas: 16 | print(panda.health()) 17 | print("\n") 18 | time.sleep(0.5) 19 | 20 | -------------------------------------------------------------------------------- /tests/ir_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import time 5 | 6 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 7 | from panda import Panda 8 | 9 | power = 0 10 | if __name__ == "__main__": 11 | p = Panda() 12 | while True: 13 | p.set_ir_power(power) 14 | print("Power: ", str(power)) 15 | time.sleep(1) 16 | power += 10 17 | power %=100 18 | -------------------------------------------------------------------------------- /tests/language/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y make python python-pip locales curl git zlib1g-dev libffi-dev bzip2 libssl-dev 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 3.7.3 14 | RUN pyenv global 3.7.3 15 | RUN pyenv rehash 16 | 17 | COPY . /panda 18 | -------------------------------------------------------------------------------- /tests/language/test_language.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import subprocess 4 | import sys 5 | 6 | checked_ext = ["h", "c", "py", "pyx", "cpp", "hpp", "md", "mk"] 7 | 8 | if __name__ == "__main__": 9 | with open("list.txt", 'r') as handle: 10 | 11 | suffix_cmd = " " 12 | for i in checked_ext: 13 | suffix_cmd += "--include \*." + i + " " 14 | 15 | found_bad_language = False 16 | for line in handle: 17 | line = line.rstrip('\n').rstrip(" ") 18 | try: 19 | cmd = "cd ../../; grep -R -i -w " + suffix_cmd + " '" + line + "'" 20 | res = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) 21 | print(res) 22 | found_bad_language = True 23 | except subprocess.CalledProcessError: 24 | pass 25 | if found_bad_language: 26 | sys.exit("Failed: found bad language") 27 | else: 28 | print("Success") 29 | -------------------------------------------------------------------------------- /tests/linter_python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y make python python-pip locales curl git zlib1g-dev libffi-dev bzip2 libssl-dev 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 3.7.3 14 | RUN pyenv global 3.7.3 15 | RUN pyenv rehash 16 | 17 | COPY requirements.txt /tmp/ 18 | RUN pip install -r /tmp/requirements.txt 19 | COPY . /panda 20 | -------------------------------------------------------------------------------- /tests/linter_python/flake8_panda.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | RESULT=$(python3 -m flake8 --select=F $(find ../../ -type f | grep -v "/boardesp/" | grep -v "/cppcheck/" | grep "\.py$")) 4 | if [[ $RESULT ]]; then 5 | echo "Pyflakes found errors in the code. Please fix and try again" 6 | echo "$RESULT" 7 | exit 1 8 | fi 9 | -------------------------------------------------------------------------------- /tests/linter_python/pylint_panda.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | python3 -m pylint --disable=R,C,W $(find ../../ -type f | grep -v "/boardesp/" | grep -v "/cppcheck/" | grep "\.py$") 4 | 5 | exit_status=$? 6 | (( res = exit_status & 3 )) 7 | 8 | if [[ $res != 0 ]]; then 9 | echo "Pylint found errors in the code. Please fix and try again" 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /tests/location_listener.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import time 4 | import sys 5 | 6 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 7 | from panda import Panda, PandaSerial 8 | 9 | def add_nmea_checksum(msg): 10 | d = msg[1:] 11 | cs = 0 12 | for i in d: 13 | cs ^= ord(i) 14 | return msg + "*%02X" % cs 15 | 16 | if __name__ == "__main__": 17 | panda = Panda() 18 | ser = PandaSerial(panda, 1, 9600) 19 | 20 | # power cycle by toggling reset 21 | print("resetting") 22 | panda.set_esp_power(0) 23 | time.sleep(0.5) 24 | panda.set_esp_power(1) 25 | time.sleep(0.5) 26 | print("done") 27 | print(ser.read(1024)) 28 | 29 | # upping baud rate 30 | baudrate = 460800 31 | 32 | print("upping baud rate") 33 | msg = str.encode(add_nmea_checksum("$PUBX,41,1,0007,0003,%d,0" % baudrate)+"\r\n") 34 | print(msg) 35 | ser.write(msg) 36 | time.sleep(0.1) # needs a wait for it to actually send 37 | 38 | # new panda serial 39 | ser = PandaSerial(panda, 1, baudrate) 40 | 41 | while True: 42 | ret = ser.read(1024) 43 | if len(ret) > 0: 44 | sys.stdout.write(ret.decode('ascii', 'ignore')) 45 | sys.stdout.flush() 46 | #print str(ret).encode("hex") 47 | 48 | -------------------------------------------------------------------------------- /tests/misra/.gitignore: -------------------------------------------------------------------------------- 1 | cppcheck/ 2 | -------------------------------------------------------------------------------- /tests/misra/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y clang make python python-pip git curl locales zlib1g-dev libffi-dev bzip2 libssl-dev libbz2-dev libusb-1.0-0 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 3.7.3 14 | RUN pyenv global 3.7.3 15 | RUN pyenv rehash 16 | 17 | COPY requirements.txt /tmp/ 18 | RUN pip install -r /tmp/requirements.txt 19 | COPY . /panda 20 | -------------------------------------------------------------------------------- /tests/misra/suppressions.txt: -------------------------------------------------------------------------------- 1 | # Advisory: casting from void pointer to type pointer is ok. Done by STM libraries as well 2 | misra.11.4 3 | # Advisory: casting from void pointer to type pointer is ok. Done by STM libraries as well 4 | misra.11.5 5 | # Advisory: as stated in the Misra document, use of goto statements in accordance to 15.2 and 15.3 is ok 6 | misra.15.1 7 | # Advisory: union types can be used 8 | misra.19.2 9 | # Required: it's ok re-defining potentially reserved Macro names. Not likely to cause confusion 10 | misra.21.1 11 | -------------------------------------------------------------------------------- /tests/misra/test_misra.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | mkdir /tmp/misra || true 4 | git clone https://github.com/danmar/cppcheck.git || true 5 | cd cppcheck 6 | git fetch 7 | git checkout e46191e6e809272d8b34feca8999ee413f716b80 8 | make -j4 9 | cd ../../../ 10 | 11 | # generate coverage matrix 12 | python tests/misra/cppcheck/addons/misra.py -generate-table > tests/misra/coverage_table 13 | 14 | printf "\nPANDA CODE\n" 15 | tests/misra/cppcheck/cppcheck -DPANDA -UPEDAL -DCAN3 -DUID_BASE -DEON \ 16 | --suppressions-list=tests/misra/suppressions.txt \ 17 | --dump --enable=all --inline-suppr --force \ 18 | board/main.c 2>/tmp/misra/cppcheck_output.txt 19 | 20 | python tests/misra/cppcheck/addons/misra.py board/main.c.dump 2> /tmp/misra/misra_output.txt || true 21 | 22 | # strip (information) lines 23 | cppcheck_output=$( cat /tmp/misra/cppcheck_output.txt | grep -v ": information: " ) || true 24 | misra_output=$( cat /tmp/misra/misra_output.txt | grep -v ": information: " ) || true 25 | 26 | 27 | printf "\nPEDAL CODE\n" 28 | tests/misra/cppcheck/cppcheck -UPANDA -DPEDAL -UCAN3 \ 29 | --suppressions-list=tests/misra/suppressions.txt \ 30 | -I board/ --dump --enable=all --inline-suppr --force \ 31 | board/pedal/main.c 2>/tmp/misra/cppcheck_pedal_output.txt 32 | 33 | python tests/misra/cppcheck/addons/misra.py board/pedal/main.c.dump 2> /tmp/misra/misra_pedal_output.txt || true 34 | 35 | # strip (information) lines 36 | cppcheck_pedal_output=$( cat /tmp/misra/cppcheck_pedal_output.txt | grep -v ": information: " ) || true 37 | misra_pedal_output=$( cat /tmp/misra/misra_pedal_output.txt | grep -v ": information: " ) || true 38 | 39 | if [[ -n "$misra_output" ]] || [[ -n "$cppcheck_output" ]] 40 | then 41 | echo "Failed! found Misra violations in panda code:" 42 | echo "$misra_output" 43 | echo "$cppcheck_output" 44 | exit 1 45 | fi 46 | 47 | if [[ -n "$misra_pedal_output" ]] || [[ -n "$cppcheck_pedal_output" ]] 48 | then 49 | echo "Failed! found Misra violations in pedal code:" 50 | echo "$misra_pedal_output" 51 | echo "$cppcheck_pedal_output" 52 | exit 1 53 | fi 54 | 55 | echo "Success" 56 | -------------------------------------------------------------------------------- /tests/pedal/enter_canloader.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import time 3 | import struct 4 | import argparse 5 | import signal 6 | from panda import Panda 7 | 8 | class CanHandle(object): 9 | def __init__(self, p): 10 | self.p = p 11 | 12 | def transact(self, dat): 13 | #print "W:",dat.encode("hex") 14 | self.p.isotp_send(1, dat, 0, recvaddr=2) 15 | 16 | def _handle_timeout(signum, frame): 17 | # will happen on reset 18 | raise Exception("timeout") 19 | 20 | signal.signal(signal.SIGALRM, _handle_timeout) 21 | signal.alarm(1) 22 | try: 23 | ret = self.p.isotp_recv(2, 0, sendaddr=1) 24 | finally: 25 | signal.alarm(0) 26 | 27 | #print "R:",ret.encode("hex") 28 | return ret 29 | 30 | def controlWrite(self, request_type, request, value, index, data, timeout=0): 31 | # ignore data in reply, panda doesn't use it 32 | return self.controlRead(request_type, request, value, index, 0, timeout) 33 | 34 | def controlRead(self, request_type, request, value, index, length, timeout=0): 35 | dat = struct.pack("HHBBHHH", 0, 0, request_type, request, value, index, length) 36 | return self.transact(dat) 37 | 38 | def bulkWrite(self, endpoint, data, timeout=0): 39 | if len(data) > 0x10: 40 | raise ValueError("Data must not be longer than 0x10") 41 | dat = struct.pack("HH", endpoint, len(data))+data 42 | return self.transact(dat) 43 | 44 | def bulkRead(self, endpoint, length, timeout=0): 45 | dat = struct.pack("HH", endpoint, 0) 46 | return self.transact(dat) 47 | 48 | if __name__ == "__main__": 49 | parser = argparse.ArgumentParser(description='Flash pedal over can') 50 | parser.add_argument('--recover', action='store_true') 51 | parser.add_argument("fn", type=str, nargs='?', help="flash file") 52 | args = parser.parse_args() 53 | 54 | p = Panda() 55 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 56 | 57 | while 1: 58 | if len(p.can_recv()) == 0: 59 | break 60 | 61 | if args.recover: 62 | p.can_send(0x200, b"\xce\xfa\xad\xde\x1e\x0b\xb0\x02", 0) 63 | exit(0) 64 | else: 65 | p.can_send(0x200, b"\xce\xfa\xad\xde\x1e\x0b\xb0\x0a", 0) 66 | 67 | if args.fn: 68 | time.sleep(0.1) 69 | print("flashing", args.fn) 70 | code = open(args.fn, "rb").read() 71 | Panda.flash_static(CanHandle(p), code) 72 | 73 | print("can flash done") 74 | 75 | 76 | -------------------------------------------------------------------------------- /tests/read_st_flash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -f /tmp/dump_bootstub 3 | rm -f /tmp/dump_main 4 | dfu-util -a 0 -s 0x08000000 -U /tmp/dump_bootstub 5 | dfu-util -a 0 -s 0x08004000 -U /tmp/dump_main 6 | 7 | -------------------------------------------------------------------------------- /tests/read_winusb_descriptors.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from panda import Panda 3 | from hexdump import hexdump 4 | 5 | DEBUG = False 6 | 7 | if __name__ == "__main__": 8 | p = Panda() 9 | 10 | len = p._handle.controlRead(Panda.REQUEST_IN, 0x06, 3 << 8 | 238, 0, 1) 11 | print('Microsoft OS String Descriptor') 12 | dat = p._handle.controlRead(Panda.REQUEST_IN, 0x06, 3 << 8 | 238, 0, len[0]) 13 | if DEBUG: print('LEN: {}'.format(hex(len[0]))) 14 | hexdump("".join(map(chr, dat))) 15 | 16 | ms_vendor_code = dat[16] 17 | if DEBUG: print('MS_VENDOR_CODE: {}'.format(hex(len[0]))) 18 | 19 | print('\nMicrosoft Compatible ID Feature Descriptor') 20 | len = p._handle.controlRead(Panda.REQUEST_IN, ms_vendor_code, 0, 4, 1) 21 | if DEBUG: print('LEN: {}'.format(hex(len[0]))) 22 | dat = p._handle.controlRead(Panda.REQUEST_IN, ms_vendor_code, 0, 4, len[0]) 23 | hexdump("".join(map(chr, dat))) 24 | 25 | print('\nMicrosoft Extended Properties Feature Descriptor') 26 | len = p._handle.controlRead(Panda.REQUEST_IN, ms_vendor_code, 0, 5, 1) 27 | if DEBUG: print('LEN: {}'.format(hex(len[0]))) 28 | dat = p._handle.controlRead(Panda.REQUEST_IN, ms_vendor_code, 0, 5, len[0]) 29 | hexdump("".join(map(chr, dat))) 30 | -------------------------------------------------------------------------------- /tests/rtc_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | import datetime 5 | 6 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 7 | from panda import Panda 8 | 9 | if __name__ == "__main__": 10 | p = Panda() 11 | 12 | p.set_datetime(datetime.datetime.now()) 13 | print(p.get_datetime()) 14 | -------------------------------------------------------------------------------- /tests/safety/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y clang make python python-pip git curl locales zlib1g-dev libffi-dev bzip2 libssl-dev libbz2-dev libusb-1.0-0 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 3.7.3 14 | RUN pyenv global 3.7.3 15 | RUN pyenv rehash 16 | 17 | COPY requirements.txt /tmp/ 18 | RUN pip install -r /tmp/requirements.txt 19 | 20 | COPY . /panda 21 | -------------------------------------------------------------------------------- /tests/safety/Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | CCFLAGS = -O3 -fPIC -DPANDA -I. 3 | 4 | .PHONY: all 5 | all: libpandasafety.so 6 | 7 | libpandasafety.so: test.o 8 | $(CC) -shared -o '$@' $^ -lm 9 | 10 | test.o: test.c 11 | @echo "[ CC ] $@" 12 | $(CC) $(CCFLAGS) -MMD -c -I../../board -o '$@' '$<' 13 | 14 | .PHONY: clean 15 | clean: 16 | rm -f libpandasafety.so test.o test.d 17 | 18 | -include test.d 19 | -------------------------------------------------------------------------------- /tests/safety/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/tests/safety/__init__.py -------------------------------------------------------------------------------- /tests/safety/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Loop over all hardware types: 4 | # HW_TYPE_UNKNOWN 0U 5 | # HW_TYPE_WHITE_PANDA 1U 6 | # HW_TYPE_GREY_PANDA 2U 7 | # HW_TYPE_BLACK_PANDA 3U 8 | # HW_TYPE_PEDAL 4U 9 | # HW_TYPE_UNO 5U 10 | 11 | # Make sure test fails if one HW_TYPE fails 12 | set -e 13 | 14 | for hw_type in 0 1 2 3 4 5 15 | do 16 | echo "Testing HW_TYPE: $hw_type" 17 | HW_TYPE=$hw_type python -m unittest discover . 18 | done 19 | -------------------------------------------------------------------------------- /tests/safety_replay/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get install -y make clang python python-pip git libarchive-dev libusb-1.0-0 locales curl zlib1g-dev libffi-dev bzip2 libssl-dev libbz2-dev 4 | 5 | RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen 6 | ENV LANG en_US.UTF-8 7 | ENV LANGUAGE en_US:en 8 | ENV LC_ALL en_US.UTF-8 9 | 10 | RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash 11 | 12 | ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" 13 | RUN pyenv install 3.7.3 14 | RUN pyenv global 3.7.3 15 | RUN pyenv rehash 16 | 17 | COPY requirements.txt /tmp/ 18 | RUN pip install -r /tmp/requirements.txt 19 | COPY tests/safety_replay/requirements_extra.txt requirements_extra.txt 20 | RUN pip install -r requirements_extra.txt 21 | COPY tests/safety_replay/install_capnp.sh install_capnp.sh 22 | RUN ./install_capnp.sh 23 | 24 | RUN mkdir /openpilot 25 | WORKDIR /openpilot 26 | RUN git clone https://github.com/commaai/cereal.git || true 27 | WORKDIR /openpilot/cereal 28 | RUN git pull && git checkout 35040fe6bb9ebc31d38e98faa64d5ec4093ce3d5 29 | COPY . /openpilot/panda 30 | 31 | WORKDIR /openpilot/panda/tests/safety_replay 32 | RUN git clone https://github.com/commaai/openpilot-tools.git tools || true 33 | WORKDIR tools 34 | RUN git checkout d69c6bc85f221766305ec53956e9a1d3bf283160 35 | -------------------------------------------------------------------------------- /tests/safety_replay/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wocsor/panda/0c2c1494908916ce776f1eb047947329e9887049/tests/safety_replay/__init__.py -------------------------------------------------------------------------------- /tests/safety_replay/install_capnp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | apt-get install -y autoconf curl libtool 4 | curl -O https://capnproto.org/capnproto-c++-0.6.1.tar.gz 5 | tar xvf capnproto-c++-0.6.1.tar.gz 6 | cd capnproto-c++-0.6.1 7 | ./configure --prefix=/usr/local CPPFLAGS=-DPIC CFLAGS=-fPIC CXXFLAGS=-fPIC LDFLAGS=-fPIC --disable-shared --enable-static 8 | make -j4 9 | make install 10 | 11 | -------------------------------------------------------------------------------- /tests/safety_replay/replay_drive.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | from panda.tests.safety import libpandasafety_py 6 | from panda.tests.safety_replay.helpers import package_can_msg, init_segment 7 | from tools.lib.logreader import LogReader # pylint: disable=import-error 8 | 9 | # replay a drive to check for safety violations 10 | def replay_drive(lr, safety_mode, param): 11 | safety = libpandasafety_py.libpandasafety 12 | 13 | err = safety.set_safety_hooks(safety_mode, param) 14 | assert err == 0, "invalid safety mode: %d" % safety_mode 15 | 16 | if "SEGMENT" in os.environ: 17 | init_segment(safety, lr, mode) 18 | 19 | rx_tot, rx_invalid, tx_tot, tx_blocked, tx_controls, tx_controls_blocked = 0, 0, 0, 0, 0, 0 20 | blocked_addrs = set() 21 | invalid_addrs = set() 22 | start_t = None 23 | 24 | for msg in lr: 25 | if start_t is None: 26 | start_t = msg.logMonoTime 27 | safety.set_timer(((msg.logMonoTime // 1000)) % 0xFFFFFFFF) 28 | 29 | if msg.which() == 'sendcan': 30 | for canmsg in msg.sendcan: 31 | to_send = package_can_msg(canmsg) 32 | sent = safety.safety_tx_hook(to_send) 33 | if not sent: 34 | tx_blocked += 1 35 | tx_controls_blocked += safety.get_controls_allowed() 36 | blocked_addrs.add(canmsg.address) 37 | 38 | if "DEBUG" in os.environ: 39 | print("blocked bus %d msg %d at %f" % (canmsg.src, canmsg.address, (msg.logMonoTime - start_t)/(1e9))) 40 | tx_controls += safety.get_controls_allowed() 41 | tx_tot += 1 42 | elif msg.which() == 'can': 43 | for canmsg in msg.can: 44 | # ignore msgs we sent 45 | if canmsg.src >= 128: 46 | continue 47 | to_push = package_can_msg(canmsg) 48 | recv = safety.safety_rx_hook(to_push) 49 | if not recv: 50 | rx_invalid += 1 51 | invalid_addrs.add(canmsg.address) 52 | rx_tot += 1 53 | 54 | print("\nRX") 55 | print("total rx msgs:", rx_tot) 56 | print("invalid rx msgs:", rx_invalid) 57 | print("invalid addrs:", invalid_addrs) 58 | print("\nTX") 59 | print("total openpilot msgs:", tx_tot) 60 | print("total msgs with controls allowed:", tx_controls) 61 | print("blocked msgs:", tx_blocked) 62 | print("blocked with controls allowed:", tx_controls_blocked) 63 | print("blocked addrs:", blocked_addrs) 64 | 65 | return tx_controls_blocked == 0 and rx_invalid == 0 66 | 67 | if __name__ == "__main__": 68 | mode = int(sys.argv[2]) 69 | param = 0 if len(sys.argv) < 4 else int(sys.argv[3]) 70 | lr = LogReader(sys.argv[1]) 71 | 72 | print("replaying drive %s with safety mode %d and param %d" % (sys.argv[1], mode, param)) 73 | 74 | replay_drive(lr, mode, param) 75 | 76 | -------------------------------------------------------------------------------- /tests/safety_replay/requirements_extra.txt: -------------------------------------------------------------------------------- 1 | aenum 2 | subprocess32 3 | libarchive 4 | pycapnp 5 | -------------------------------------------------------------------------------- /tests/safety_replay/test_safety_replay.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import requests 5 | 6 | from panda import Panda 7 | from replay_drive import replay_drive 8 | from tools.lib.logreader import LogReader # pylint: disable=import-error 9 | 10 | BASE_URL = "https://commadataci.blob.core.windows.net/openpilotci/" 11 | 12 | # (route, safety mode, param) 13 | logs = [ 14 | ("2425568437959f9d|2019-12-22--16-24-37.bz2", Panda.SAFETY_HONDA_NIDEC, 0), # HONDA.CIVIC (fcw presents: 0x1FA blocked as expected) 15 | ("38bfd238edecbcd7|2019-06-07--10-15-25.bz2", Panda.SAFETY_TOYOTA, 66), # TOYOTA.PRIUS 16 | ("f89c604cf653e2bf|2018-09-29--13-46-50.bz2", Panda.SAFETY_GM, 0), # GM.VOLT 17 | ("0375fdf7b1ce594d|2019-05-21--20-10-33.bz2", Panda.SAFETY_HONDA_BOSCH_GIRAFFE, 1), # HONDA.ACCORD 18 | ("02ec6bea180a4d36|2019-04-17--11-21-35.bz2", Panda.SAFETY_HYUNDAI, 0), # HYUNDAI.SANTA_FE 19 | ("6fb4948a7ebe670e|2019-11-12--00-35-53.bz2", Panda.SAFETY_CHRYSLER, 0), # CHRYSLER.PACIFICA_2018_HYBRID 20 | ("791340bc01ed993d|2019-04-08--10-26-00.bz2", Panda.SAFETY_SUBARU, 0), # SUBARU.IMPREZA 21 | ("76b83eb0245de90e|2020-03-05--19-16-05.bz2", Panda.SAFETY_VOLKSWAGEN_MQB, 0), # VOLKSWAGEN.GOLF (MK7) 22 | ("d12cd943127f267b|2020-03-27--15-57-18.bz2", Panda.SAFETY_VOLKSWAGEN_PQ, 0), # 2009 VW Passat R36 (B6), supporting OP port not yet upstreamed 23 | ("fbbfa6af821552b9|2020-03-03--08-09-43.bz2", Panda.SAFETY_NISSAN, 0), # NISSAN.XTRAIL 24 | ] 25 | 26 | if __name__ == "__main__": 27 | for route, _, _ in logs: 28 | if not os.path.isfile(route): 29 | with open(route, "wb") as f: 30 | f.write(requests.get(BASE_URL + route).content) 31 | 32 | failed = [] 33 | for route, mode, param in logs: 34 | lr = LogReader(route) 35 | 36 | print("\nreplaying %s with safety mode %d and param %s" % (route, mode, param)) 37 | if not replay_drive(lr, mode, int(param)): 38 | failed.append(route) 39 | 40 | for f in failed: 41 | print("\n**** failed on %s ****" % f) 42 | assert len(failed) == 0, "\nfailed on %d logs" % len(failed) 43 | 44 | -------------------------------------------------------------------------------- /tests/spam_can.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import random 6 | 7 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 8 | from panda import Panda 9 | 10 | def get_test_string(): 11 | return b"test"+os.urandom(10) 12 | 13 | if __name__ == "__main__": 14 | p = Panda() 15 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 16 | 17 | print("Spamming all buses...") 18 | while True: 19 | at = random.randint(1, 2000) 20 | st = get_test_string()[0:8] 21 | bus = random.randint(0, 2) 22 | p.can_send(at, st, bus) 23 | #print("Sent message on bus: ", bus) 24 | -------------------------------------------------------------------------------- /tests/standalone_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import sys 4 | import struct 5 | import time 6 | 7 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 8 | from panda import Panda 9 | 10 | if __name__ == "__main__": 11 | if os.getenv("WIFI") is not None: 12 | p = Panda("WIFI") 13 | else: 14 | p = Panda() 15 | print(p.get_serial()) 16 | print(p.health()) 17 | 18 | t1 = time.time() 19 | for i in range(100): 20 | p.get_serial() 21 | t2 = time.time() 22 | print("100 requests took %.2f ms" % ((t2-t1)*1000)) 23 | 24 | p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 25 | 26 | a = 0 27 | while True: 28 | # flood 29 | msg = b"\xaa"*4 + struct.pack("I", a) 30 | p.can_send(0xaa, msg, 0) 31 | p.can_send(0xaa, msg, 1) 32 | p.can_send(0xaa, msg, 4) 33 | time.sleep(0.01) 34 | 35 | dat = p.can_recv() 36 | if len(dat) > 0: 37 | print(dat) 38 | a += 1 39 | -------------------------------------------------------------------------------- /tests/throughput_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import sys 5 | import struct 6 | import time 7 | from tqdm import tqdm 8 | 9 | sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) 10 | from panda import Panda, PandaWifiStreaming 11 | 12 | # test throughput between USB and wifi 13 | 14 | if __name__ == "__main__": 15 | print(Panda.list()) 16 | p_out = Panda("108018800f51363038363036") 17 | print(p_out.get_serial()) 18 | #p_in = Panda("02001b000f51363038363036") 19 | p_in = Panda("WIFI") 20 | print(p_in.get_serial()) 21 | 22 | p_in = PandaWifiStreaming() 23 | 24 | #while True: 25 | # p_in.can_recv() 26 | #sys.exit(0) 27 | 28 | p_out.set_safety_mode(Panda.SAFETY_ALLOUTPUT) 29 | 30 | set_out, set_in = set(), set() 31 | 32 | # drain 33 | p_out.can_recv() 34 | p_in.can_recv() 35 | 36 | BATCH_SIZE = 16 37 | for a in tqdm(list(range(0, 10000, BATCH_SIZE))): 38 | for b in range(0, BATCH_SIZE): 39 | msg = b"\xaa"*4 + struct.pack("I", a+b) 40 | if a%1 == 0: 41 | p_out.can_send(0xaa, msg, 0) 42 | 43 | dat_out, dat_in = p_out.can_recv(), p_in.can_recv() 44 | if len(dat_in) != 0: 45 | print(len(dat_in)) 46 | 47 | num_out = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_out] 48 | num_in = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_in] 49 | 50 | set_in.update(num_in) 51 | set_out.update(num_out) 52 | 53 | # swag 54 | print("waiting for packets") 55 | time.sleep(2.0) 56 | dat_in = p_in.can_recv() 57 | print(len(dat_in)) 58 | num_in = [struct.unpack("I", i[4:])[0] for _, _, i, _ in dat_in] 59 | set_in.update(num_in) 60 | 61 | if len(set_out - set_in): 62 | print("MISSING %d" % len(set_out - set_in)) 63 | if len(set_out - set_in) < 256: 64 | print(list(map(hex, sorted(list(set_out - set_in))))) 65 | --------------------------------------------------------------------------------