diff --git a/.dockerignore b/.dockerignore index f04ae5c..0863ea9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,2 @@ .git .DS_Store -boardesp/esp-open-sdk diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index cdc68e1..50539ba 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -45,26 +45,6 @@ jobs: - name: Build pedal STM bootstub image run: $RUN "cd /tmp/openpilot/panda/board/pedal && make obj/bootstub.bin" - build_esp: - name: build esp - runs-on: ubuntu-16.04 - timeout-minutes: 45 - steps: - - uses: actions/checkout@v2 - - name: Build docker image - run: | - docker pull $(grep -ioP '(?<=^from)\s+\S+' tests/build/Dockerfile.panda_esp) || true - docker pull docker.io/commaai/panda_esp:latest || true - docker build --cache-from docker.io/commaai/panda_esp:latest -t panda_esp -f tests/build/Dockerfile.panda_esp . - - name: Build ESP image - run: docker run --rm panda_esp /bin/sh -c "cd /panda/boardesp && make user1.bin" - - name: Push image - if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' && github.repository == 'commaai/panda' - run: | - docker login -u wmelching -p ${{ secrets.COMMA_DOCKERHUB_TOKEN }} - docker tag panda_esp docker.io/commaai/panda_esp:latest - docker push docker.io/commaai/panda_esp:latest - safety: name: safety runs-on: ubuntu-16.04 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c01ab74..9933cbd 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -18,7 +18,7 @@ repos: exclude: '^(tests/automated)/' args: - --select=F,E112,E113,E304,E501,E502,E701,E702,E703,E71,E72,E731,W191,W6 - - --exclude=python/esptool.py,tests/gmbitbang/* + - --exclude=tests/gmbitbang/* - --max-line-length=160 - --statistics - repo: local diff --git a/Dockerfile b/Dockerfile index fa020ad..65734bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,7 +54,6 @@ RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-instal ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" RUN pyenv install 3.7.3 -RUN pyenv install 2.7.12 RUN pyenv global 3.7.3 RUN pyenv rehash @@ -68,16 +67,6 @@ ENV HOME /home/batman ENV PYTHONPATH /tmp:$PYTHONPATH -COPY ./boardesp/get_sdk_ci.sh /tmp/panda/boardesp/ -COPY ./boardesp/python2_make.py /tmp/panda/boardesp/ - -COPY ./panda_jungle /tmp/panda_jungle - -RUN useradd --system -s /sbin/nologin pandauser -RUN mkdir -p /tmp/panda/boardesp/esp-open-sdk -RUN chown pandauser /tmp/panda/boardesp/esp-open-sdk -USER pandauser -RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh -USER root +RUN cd /tmp && git clone https://github.com/commaai/panda_jungle.git ADD ./panda.tar.gz /tmp/panda diff --git a/Jenkinsfile b/Jenkinsfile index 61068a4..7b8a90e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -14,24 +14,19 @@ pipeline { steps { timeout(time: 60, unit: 'MINUTES') { script { - try { - sh 'cp -R /home/batman/panda_jungle .' - } catch (err) { - echo "Folder already exists" - } sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD' dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}") } } } } - stage('Test Dev Build (no WIFI)') { + stage('Test Dev Build') { steps { lock(resource: "Pandas", inversePrecedence: true, quantity: 1){ timeout(time: 60, unit: 'MINUTES') { script { - sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; SKIPWIFI=1 ./run_automated_tests.sh'" - sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev_nowifi.xml" + sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; ./run_automated_tests.sh'" + sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev.xml" sh "docker rm ${env.DOCKER_NAME}" } } @@ -51,21 +46,6 @@ pipeline { } } } -/* - stage('Test Dev Build (WIFI)') { - steps { - lock(resource: "Pandas", inversePrecedence: true, quantity: 1){ - timeout(time: 60, unit: 'MINUTES') { - script { - sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; ./run_automated_tests.sh'" - sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev.xml" - sh "docker rm ${env.DOCKER_NAME}" - } - } - } - } - } -*/ } post { failure { diff --git a/README.md b/README.md index 290f456..1eea83b 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ -It supports 3x CAN, 2x LIN, and 1x GMLAN. It also charges a phone. On the computer side, it has both USB and Wi-Fi. +It supports 3x CAN, 2x LIN, and 1x GMLAN. It also charges a phone. On the computer side, it has USB. -It uses an [STM32F413](http://www.st.com/en/microcontrollers/stm32f413-423.html?querycriteria=productId=LN2004) for low level stuff and an [ESP8266](https://en.wikipedia.org/wiki/ESP8266) for Wi-Fi. They are connected over high speed SPI, so the panda is actually capable of dumping the full contents of the busses over Wi-Fi, unlike every other dongle on amazon. ELM327 is weak, panda is strong. +It uses an [STM32F413](http://www.st.com/en/microcontrollers/stm32f413-423.html?querycriteria=productId=LN2004). It is 2nd gen hardware, reusing code and parts from the [NEO](https://github.com/commaai/neo) interface board. @@ -56,30 +56,23 @@ As a universal car interface, it should support every reasonable software interf - [User space](https://github.com/commaai/panda/tree/master/python) - [socketcan in kernel](https://github.com/commaai/panda/tree/master/drivers/linux) (alpha) -- [ELM327](https://github.com/commaai/panda/blob/master/boardesp/elm327.c) - [Windows J2534](https://github.com/commaai/panda/tree/master/drivers/windows) ## Directory structure - board -- Code that runs on the STM32 -- boardesp -- Code that runs on the ESP8266 - drivers -- Drivers (not needed for use with python) - python   -- Python userspace library for interfacing with the panda - tests -- Tests and helper programs for panda -## Programming over USB - -[Programming the Board (STM32)](board/README.md) - -[Programming the ESP](boardesp/README.md) +## Programming +See `board/README.md` ## Debugging To print out the serial console from the STM32, run `tests/debug_console.py` -To print out the serial console from the ESP8266, run `PORT=1 tests/debug_console.py` - ## Safety Model When a panda powers up, by default it's in `SAFETY_SILENT` mode. While in `SAFETY_SILENT` mode, the buses are also forced to be silent. In order to send messages, you have to select a safety mode. Currently, setting safety modes is only supported over USB. Some of safety modes (for example `SAFETY_ALLOUTPUT`) are disabled in release firmwares. In order to use them, compile and flash your own build. @@ -100,8 +93,8 @@ These are the [CI regression tests](https://github.com/commaai/panda/actions) we * A recorded drive for each supported car variant is [replayed through the safety logic](https://github.com/commaai/panda/tree/master/tests/safety_replay) to ensure that the behavior remains unchanged. * An internal Hardware-in-the-loop test, which currently only runs on pull requests opened by comma.ai's organization members, verifies the following functionalities: - * compiling the code in various configuration and flashing it both through USB and WiFi. - * Receiving, sending and forwarding CAN messages on all buses, over USB and WiFi. + * compiling the code in various configuration and flashing it both through USB. + * Receiving, sending and forwarding CAN messages on all buses, over USB. In addition, we run the [pylint](https://www.pylint.org/) and [flake8](https://github.com/PyCQA/flake8) linters on all python files within the panda repo. diff --git a/TODO b/TODO deleted file mode 100644 index 4e4a355..0000000 --- a/TODO +++ /dev/null @@ -1,31 +0,0 @@ -** Projects ** - -== ELM327 Emulator == - -Write an elm327 emulator in boardesp/elm327.c and make it work with Torque - -You'll find a start at this in the "elm327" branch. - -== socketcan Kernel Driver == - -Write a kernel driver version of lib/panda.py that exposes the Panda on socketcan and makes it work with those tools. - -You may want to switch to interrupt endpoint first. Should LIN be exposed as a serial interface? - -== Windows J2534 DLL == - -Write a Windows DLL that exposes the J2534 API. - -Will make the Panda work with car diagnostic software. - - -** Refactors ** - -== USB Interrupt Endpoint == - -Switch USB to use an interrupt endpoint instead of a bulk endpoint for can recv - -== WebSocket Support == - -Add CAN streaming over WebSocket to the ELM code in addition to the UDP pipe. - diff --git a/__init__.py b/__init__.py index deeea46..09466dd 100644 --- a/__init__.py +++ b/__init__.py @@ -1,3 +1,3 @@ # flake8: noqa # pylint: skip-file -from .python import Panda, PandaWifiStreaming, PandaDFU, ESPROM, CesantaFlasher, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial +from .python import Panda, PandaWifiStreaming, PandaDFU, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial diff --git a/board/board.h b/board/board.h index 9e250d8..19392c9 100644 --- a/board/board.h +++ b/board/board.h @@ -54,22 +54,10 @@ void detect_board_type(void) { // ///// Configuration detection ///// // bool has_external_debug_serial = 0; -bool is_entering_bootmode = 0; void detect_configuration(void) { // detect if external serial debugging is present has_external_debug_serial = detect_with_pull(GPIOA, 3, PULL_DOWN); - - #ifdef PANDA - if(hw_type == HW_TYPE_WHITE_PANDA) { - // check if the ESP is trying to put me in boot mode - is_entering_bootmode = !detect_with_pull(GPIOB, 0, PULL_UP); - } else { - is_entering_bootmode = 0; - } - #else - is_entering_bootmode = 0; - #endif } // ///// Board functions ///// // diff --git a/board/board_declarations.h b/board/board_declarations.h index 2b7ee87..5fa5ef1 100644 --- a/board/board_declarations.h +++ b/board/board_declarations.h @@ -4,7 +4,7 @@ typedef void (*board_enable_can_transciever)(uint8_t transciever, bool enabled); typedef void (*board_enable_can_transcievers)(bool enabled); typedef void (*board_set_led)(uint8_t color, bool enabled); typedef void (*board_set_usb_power_mode)(uint8_t mode); -typedef void (*board_set_esp_gps_mode)(uint8_t mode); +typedef void (*board_set_gps_mode)(uint8_t mode); typedef void (*board_set_can_mode)(uint8_t mode); typedef void (*board_usb_power_mode_tick)(uint32_t uptime); typedef bool (*board_check_ignition)(void); @@ -23,7 +23,7 @@ struct board { board_enable_can_transcievers enable_can_transcievers; board_set_led set_led; board_set_usb_power_mode set_usb_power_mode; - board_set_esp_gps_mode set_esp_gps_mode; + board_set_gps_mode set_gps_mode; board_set_can_mode set_can_mode; board_usb_power_mode_tick usb_power_mode_tick; board_check_ignition check_ignition; @@ -56,10 +56,10 @@ struct board { #define USB_POWER_CDP 2U #define USB_POWER_DCP 3U -// ESP modes -#define ESP_GPS_DISABLED 0U -#define ESP_GPS_ENABLED 1U -#define ESP_GPS_BOOTMODE 2U +// GPS modes +#define GPS_DISABLED 0U +#define GPS_ENABLED 1U +#define GPS_BOOTMODE 2U // CAN modes #define CAN_MODE_NORMAL 0U @@ -76,4 +76,4 @@ bool board_has_gmlan(void); bool board_has_obd(void); bool board_has_lin(void); bool board_has_rtc(void); -bool board_has_relay(void); \ No newline at end of file +bool board_has_relay(void); diff --git a/board/boards/black.h b/board/boards/black.h index b6ec2f9..bddf381 100644 --- a/board/boards/black.h +++ b/board/boards/black.h @@ -77,24 +77,24 @@ void black_set_usb_power_mode(uint8_t mode) { } } -void black_set_esp_gps_mode(uint8_t mode) { +void black_set_gps_mode(uint8_t mode) { switch (mode) { - case ESP_GPS_DISABLED: + case GPS_DISABLED: // GPS OFF set_gpio_output(GPIOC, 14, 0); set_gpio_output(GPIOC, 5, 0); break; - case ESP_GPS_ENABLED: + case GPS_ENABLED: // GPS ON set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 1); break; - case ESP_GPS_BOOTMODE: + case GPS_BOOTMODE: set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 0); break; default: - puts("Invalid ESP/GPS mode\n"); + puts("Invalid GPS mode\n"); break; } } @@ -175,7 +175,7 @@ void black_init(void) { set_gpio_mode(GPIOC, 3, MODE_ANALOG); // Set default state of GPS - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); // C10: OBD_SBU1_RELAY (harness relay driving output) // C11: OBD_SBU2_RELAY (harness relay driving output) @@ -240,7 +240,7 @@ const board board_black = { .enable_can_transcievers = black_enable_can_transcievers, .set_led = black_set_led, .set_usb_power_mode = black_set_usb_power_mode, - .set_esp_gps_mode = black_set_esp_gps_mode, + .set_gps_mode = black_set_gps_mode, .set_can_mode = black_set_can_mode, .usb_power_mode_tick = black_usb_power_mode_tick, .check_ignition = black_check_ignition, diff --git a/board/boards/common.h b/board/boards/common.h index 040ae39..2f35c34 100644 --- a/board/boards/common.h +++ b/board/boards/common.h @@ -23,7 +23,7 @@ void common_init_gpio(void){ set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS); GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; - // A9,A10: USART 1 for talking to the ESP / GPS + // A9,A10: USART 1 for talking to the GPS set_gpio_alternate(GPIOA, 9, GPIO_AF7_USART1); set_gpio_alternate(GPIOA, 10, GPIO_AF7_USART1); @@ -81,4 +81,4 @@ bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode) { bool ret = get_gpio_input(GPIO, pin); set_gpio_pullup(GPIO, pin, PULL_NONE); return ret; -} \ No newline at end of file +} diff --git a/board/boards/dos.h b/board/boards/dos.h index 0245ab0..d4bfb3f 100644 --- a/board/boards/dos.h +++ b/board/boards/dos.h @@ -65,7 +65,7 @@ void dos_set_usb_power_mode(uint8_t mode) { dos_set_bootkick(mode == USB_POWER_CDP); } -void dos_set_esp_gps_mode(uint8_t mode) { +void dos_set_gps_mode(uint8_t mode) { UNUSED(mode); } @@ -217,7 +217,7 @@ const board board_dos = { .enable_can_transcievers = dos_enable_can_transcievers, .set_led = dos_set_led, .set_usb_power_mode = dos_set_usb_power_mode, - .set_esp_gps_mode = dos_set_esp_gps_mode, + .set_gps_mode = dos_set_gps_mode, .set_can_mode = dos_set_can_mode, .usb_power_mode_tick = dos_usb_power_mode_tick, .check_ignition = dos_check_ignition, diff --git a/board/boards/grey.h b/board/boards/grey.h index dad3295..915c883 100644 --- a/board/boards/grey.h +++ b/board/boards/grey.h @@ -8,22 +8,22 @@ void grey_init(void) { white_grey_common_init(); // Set default state of GPS - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); } -void grey_set_esp_gps_mode(uint8_t mode) { +void grey_set_gps_mode(uint8_t mode) { switch (mode) { - case ESP_GPS_DISABLED: + case GPS_DISABLED: // GPS OFF set_gpio_output(GPIOC, 14, 0); set_gpio_output(GPIOC, 5, 0); break; - case ESP_GPS_ENABLED: + case GPS_ENABLED: // GPS ON set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 1); break; - case ESP_GPS_BOOTMODE: + case GPS_BOOTMODE: set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 0); break; @@ -41,7 +41,7 @@ const board board_grey = { .enable_can_transcievers = white_enable_can_transcievers, .set_led = white_set_led, .set_usb_power_mode = white_set_usb_power_mode, - .set_esp_gps_mode = grey_set_esp_gps_mode, + .set_gps_mode = grey_set_gps_mode, .set_can_mode = white_set_can_mode, .usb_power_mode_tick = white_usb_power_mode_tick, .check_ignition = white_check_ignition, diff --git a/board/boards/pedal.h b/board/boards/pedal.h index 4c9fdb1..22ecb78 100644 --- a/board/boards/pedal.h +++ b/board/boards/pedal.h @@ -35,7 +35,7 @@ void pedal_set_usb_power_mode(uint8_t mode){ puts("Trying to set USB power mode on pedal. This is not supported.\n"); } -void pedal_set_esp_gps_mode(uint8_t mode) { +void pedal_set_gps_mode(uint8_t mode) { UNUSED(mode); puts("Trying to set ESP/GPS mode on pedal. This is not supported.\n"); } @@ -114,7 +114,7 @@ const board board_pedal = { .enable_can_transcievers = pedal_enable_can_transcievers, .set_led = pedal_set_led, .set_usb_power_mode = pedal_set_usb_power_mode, - .set_esp_gps_mode = pedal_set_esp_gps_mode, + .set_gps_mode = pedal_set_gps_mode, .set_can_mode = pedal_set_can_mode, .usb_power_mode_tick = pedal_usb_power_mode_tick, .check_ignition = pedal_check_ignition, diff --git a/board/boards/uno.h b/board/boards/uno.h index 0bd96b9..25fd1d8 100644 --- a/board/boards/uno.h +++ b/board/boards/uno.h @@ -89,21 +89,21 @@ void uno_set_usb_power_mode(uint8_t mode) { } } -void uno_set_esp_gps_mode(uint8_t mode) { +void uno_set_gps_mode(uint8_t mode) { switch (mode) { - case ESP_GPS_DISABLED: + case GPS_DISABLED: // GPS OFF set_gpio_output(GPIOB, 1, 0); set_gpio_output(GPIOC, 5, 0); uno_set_gps_load_switch(false); break; - case ESP_GPS_ENABLED: + case GPS_ENABLED: // GPS ON set_gpio_output(GPIOB, 1, 1); set_gpio_output(GPIOC, 5, 1); uno_set_gps_load_switch(true); break; - case ESP_GPS_BOOTMODE: + case GPS_BOOTMODE: set_gpio_output(GPIOB, 1, 1); set_gpio_output(GPIOC, 5, 0); uno_set_gps_load_switch(true); @@ -196,7 +196,7 @@ void uno_init(void) { set_gpio_mode(GPIOC, 3, MODE_ANALOG); // Set default state of GPS - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); // C10: OBD_SBU1_RELAY (harness relay driving output) // C11: OBD_SBU2_RELAY (harness relay driving output) @@ -283,7 +283,7 @@ const board board_uno = { .enable_can_transcievers = uno_enable_can_transcievers, .set_led = uno_set_led, .set_usb_power_mode = uno_set_usb_power_mode, - .set_esp_gps_mode = uno_set_esp_gps_mode, + .set_gps_mode = uno_set_gps_mode, .set_can_mode = uno_set_can_mode, .usb_power_mode_tick = uno_usb_power_mode_tick, .check_ignition = uno_check_ignition, diff --git a/board/boards/white.h b/board/boards/white.h index 0141fe3..aa4eb8a 100644 --- a/board/boards/white.h +++ b/board/boards/white.h @@ -71,21 +71,21 @@ void white_set_usb_power_mode(uint8_t mode){ } } -void white_set_esp_gps_mode(uint8_t mode) { +void white_set_gps_mode(uint8_t mode) { switch (mode) { - case ESP_GPS_DISABLED: + case GPS_DISABLED: // ESP OFF set_gpio_output(GPIOC, 14, 0); set_gpio_output(GPIOC, 5, 0); break; #ifndef EON - case ESP_GPS_ENABLED: + case GPS_ENABLED: // ESP ON set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 1); break; #endif - case ESP_GPS_BOOTMODE: + case GPS_BOOTMODE: set_gpio_output(GPIOC, 14, 1); set_gpio_output(GPIOC, 5, 0); break; @@ -324,12 +324,8 @@ void white_grey_common_init(void) { void white_init(void) { white_grey_common_init(); - // Set default state of ESP - #ifdef EON - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - #else - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - #endif + // Set ESP off by default + current_board->set_gps_mode(GPS_DISABLED); } const harness_configuration white_harness_config = { @@ -344,7 +340,7 @@ const board board_white = { .enable_can_transcievers = white_enable_can_transcievers, .set_led = white_set_led, .set_usb_power_mode = white_set_usb_power_mode, - .set_esp_gps_mode = white_set_esp_gps_mode, + .set_gps_mode = white_set_gps_mode, .set_can_mode = white_set_can_mode, .usb_power_mode_tick = white_usb_power_mode_tick, .check_ignition = white_check_ignition, diff --git a/board/drivers/uart.h b/board/drivers/uart.h index 4ab791f..e4f23ea 100644 --- a/board/drivers/uart.h +++ b/board/drivers/uart.h @@ -50,8 +50,8 @@ void debug_ring_callback(uart_ring *ring); // ******************************** UART buffers ******************************** -// esp_gps = USART1 -UART_BUFFER(esp_gps, FIFO_SIZE_DMA, FIFO_SIZE_INT, USART1, NULL, true) +// gps = USART1 +UART_BUFFER(gps, FIFO_SIZE_DMA, FIFO_SIZE_INT, USART1, NULL, true) // lin1, K-LINE = UART5 // lin2, L-LINE = USART3 @@ -68,7 +68,7 @@ uart_ring *get_ring_by_number(int a) { ring = &uart_ring_debug; break; case 1: - ring = &uart_ring_esp_gps; + ring = &uart_ring_gps; break; case 2: ring = &uart_ring_lin1; @@ -185,8 +185,8 @@ void uart_interrupt_handler(uart_ring *q) { // Reset IDLE flag UART_READ_DR(q->uart) - if(q == &uart_ring_esp_gps){ - dma_pointer_handler(&uart_ring_esp_gps, DMA2_Stream5->NDTR); + if(q == &uart_ring_gps){ + dma_pointer_handler(&uart_ring_gps, DMA2_Stream5->NDTR); } else { #ifdef DEBUG_UART puts("No IDLE dma_pointer_handler implemented for this UART."); @@ -197,7 +197,7 @@ void uart_interrupt_handler(uart_ring *q) { EXIT_CRITICAL(); } -void USART1_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_esp_gps); } +void USART1_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_gps); } void USART2_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_debug); } void USART3_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin2); } void UART5_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin1); } @@ -219,7 +219,7 @@ void DMA2_Stream5_IRQ_Handler(void) { } // Re-calculate write pointer and reset flags - dma_pointer_handler(&uart_ring_esp_gps, DMA2_Stream5->NDTR); + dma_pointer_handler(&uart_ring_gps, DMA2_Stream5->NDTR); DMA2->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5; EXIT_CRITICAL(); @@ -229,7 +229,7 @@ void DMA2_Stream5_IRQ_Handler(void) { void dma_rx_init(uart_ring *q) { // Initialization is UART-dependent - if(q == &uart_ring_esp_gps){ + if(q == &uart_ring_gps){ // DMA2, stream 5, channel 4 // Disable FIFO mode (enable direct) diff --git a/board/gpio.h b/board/gpio.h index 2b937ec..b50de50 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -64,13 +64,9 @@ void early(void) { if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { #ifdef PANDA - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); + current_board->set_gps_mode(GPS_DISABLED); #endif current_board->set_led(LED_GREEN, 1); jump_to_bootloader(); } - - if (is_entering_bootmode) { - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - } -} \ No newline at end of file +} diff --git a/board/main.c b/board/main.c index 9548474..daf4f20 100644 --- a/board/main.c +++ b/board/main.c @@ -400,24 +400,24 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) // **** 0xd9: set ESP power case 0xd9: if (setup->b.wValue.w == 1U) { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); } else if (setup->b.wValue.w == 2U) { - current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); + current_board->set_gps_mode(GPS_BOOTMODE); } else { - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); + current_board->set_gps_mode(GPS_DISABLED); } break; // **** 0xda: reset ESP, with optional boot mode case 0xda: - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); + current_board->set_gps_mode(GPS_DISABLED); delay(1000000); if (setup->b.wValue.w == 1U) { - current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); + current_board->set_gps_mode(GPS_BOOTMODE); } else { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); } delay(1000000); - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); break; // **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode case 0xdb: @@ -493,7 +493,7 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) } // TODO: Remove this again and fix boardd code to hande the message bursts instead of single chars - if (ur == &uart_ring_esp_gps) { + if (ur == &uart_ring_gps) { dma_pointer_handler(ur, DMA2_Stream5->NDTR); } @@ -796,7 +796,6 @@ int main(void) { puts("Config:\n"); puts(" Board type: "); puts(current_board->board_type); puts("\n"); puts(has_external_debug_serial ? " Real serial\n" : " USB serial\n"); - puts(is_entering_bootmode ? " ESP wants bootmode\n" : " No bootmode\n"); // init board current_board->init(); @@ -812,10 +811,10 @@ int main(void) { } if (board_has_gps()) { - uart_init(&uart_ring_esp_gps, 9600); + uart_init(&uart_ring_gps, 9600); } else { // enable ESP uart - uart_init(&uart_ring_esp_gps, 115200); + uart_init(&uart_ring_gps, 115200); } if(board_has_lin()){ diff --git a/board/power_saving.h b/board/power_saving.h index 3df750c..26503d3 100644 --- a/board/power_saving.h +++ b/board/power_saving.h @@ -32,9 +32,9 @@ void set_power_save_state(int state) { // Switch EPS/GPS if (enable) { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); + current_board->set_gps_mode(GPS_ENABLED); } else { - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); + current_board->set_gps_mode(GPS_DISABLED); } if(board_has_gmlan()){ diff --git a/boardesp/.gitignore b/boardesp/.gitignore deleted file mode 100644 index 75255a5..0000000 --- a/boardesp/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -proxy -*.bin -esp-open-sdk -a.out -cert.h -gitversion.h -esp-open-sdk.dmg -obj/* diff --git a/boardesp/ELM327.md b/boardesp/ELM327.md deleted file mode 100644 index 6453b35..0000000 --- a/boardesp/ELM327.md +++ /dev/null @@ -1,101 +0,0 @@ -ELM327 support for panda -====== -The panda now has basic ELM327 support. - -### What is ELM327? - -ELM327 is a command protocol for interfacing with cars using an OBD-II -port to read [list](standard vehicle diagnostic codes). ELM327 -originally referred to a line of programmable microcontrollers that -implemented the ELM327 command protocol, and are still being -developed. - -ELM327 devices present a shell and commands are sent via a UART. The -official ELM327 chips only support raw UART communication, but most -devices built with the ELM327 devices (official or clones) expose the -UART in a more modern way (Wifi, USB, etc). - -Mechanics use ELM to diagnose vehicles, and reset fault codes in the -car's computer after fixing the issue (turning off the dreaded check -engine light). Car owners can use ELM devices to perform the same -diagnostics in their garage using either a raw terminal to send -commands to the ELM device directly, or using a GUI (like one of -several popular smart phone apps) to translate the OBD error codes -into readable messages. These GUIs also often allow monitoring of the -performance of the car's speed, engine rpm, etc. - -The panda natively supports sending all the important OBD diagnostic -messages, but ELM327 support removes the need for the user to manually -craft CAN or LIN packets using the native panda API, and grants -compatibility with many existing tools. - -[Wikipedia](https://en.wikipedia.org/wiki/ELM327) can provide -additional information. - -### OBD Protocols? - -While the commands that the OBD standard describe are in fact -standard, there are several different protocols that those messages -can be sent and received with. All cars after 1991 support one of -these protocols. Which one depends on the car's year and country, as -legal requirements change over the years. - -The panda supports the most popular/modern of these protocols, and all -but two can be added as needed. Below is a chart of the OBD-II -protocols supported by the panda. - -| Protocol | Support Status | -| --- | --- | -| SAE J1850 PWM (41.6 kbit/s) | Never/Obsolete | -| SAE J1850 VPW (10.4 kbit/s) | Never/Obsolete | -| ISO 9141-2 (5 baud init, 10.4 kbit/s) | Unsupported | -| ISO 14230-4 KWP (5 baud init, 10.4 kbit/s) | Unsupported | -| ISO 14230-4 KWP (fast init, 10.4 kbit/s) | Supported | -| ISO 15765-4 CAN (11 bit ID, 500 kbit/s) | Supported | -| ISO 15765-4 CAN (29 bit ID, 500 kbit/s) | Supported | -| ISO 15765-4 CAN (11 bit ID, 250 kbit/s) | Supported | -| ISO 15765-4 CAN (29 bit ID, 250 kbit/s) | Supported | -| SAE J1939 (250kbps) | Unsupported | - -### The Implementation - -The panda ELM327 implementation is not a full implementation of all -the features of the official ELM327 microcontroller. Like most ELM327 -clones, the panda reports its ELM version as the unreleased version -1.5, despite only implementing commands from protocol version 1.0. - - -### Testing - -These tests require two pandas. One to be tested, and the second to -simulate the vehicle. - -The panda used to simulate the vehicle must be plugged into a USB port -of the testing computer. - -The computer running the tests must be connected to the panda being -tested's wifi network. - -The following command will run the tests (nosetest should work fine -instead of pytest if you still prefer using that). The CANSIMSERIAL -environment variable will force the car simulator to use the correct -panda as the simulator if multiple pandas are attached via usb to the -host computer. - -``` -CANSIMSERIAL=car_sim_panda_serial pytest tests/automated/elm_wifi.py -``` - -A single test can be run by putting the test name after the file name -and two colons, like so: - -``` -CANSIMSERIAL=car_sim_panda_serial pytest tests/automated/elm_wifi.py::test_important_thing -``` - -For more detail, provide the -s (show output) and the -vv (very -verbose) flags. - -``` -CANSIMSERIAL=car_sim_panda_serial pytest -s -vv tests/automated/elm_wifi.py -``` diff --git a/boardesp/Makefile b/boardesp/Makefile deleted file mode 100644 index c713a00..0000000 --- a/boardesp/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -PATH := esp-open-sdk/xtensa-lx106-elf/bin:$(PATH) -CC = esp-open-sdk/xtensa-lx106-elf/bin/xtensa-lx106-elf-gcc -CFLAGS = -Iinclude/ -I. -I../ -mlongcalls -Iesp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/driver_lib/include -std=c99 -DICACHE_FLASH -LDLIBS = -nostdlib -Wl,--start-group -lmain -lnet80211 -lwpa -llwip -lpp -lphy -Wl,--end-group -lgcc -ldriver -Wl,--gc-sections -LDFLAGS = -Teagle.app.v6.ld -OBJCP = esp-open-sdk/xtensa-lx106-elf/bin/xtensa-lx106-elf-objcopy -SDK_BASE = esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20 - -ifeq ($(RELEASE),1) - CERT = ../../pandaextra/certs/releaseesp -else - CERT = ../certs/debugesp - CFLAGS += "-DALLOW_DEBUG" -endif - -flashall: user1.bin user2.bin - ../python/esptool.py write_flash 0 $(SDK_BASE)/bin/boot_v1.5.bin 0x01000 user1.bin 0x81000 user2.bin 0x3FE000 $(SDK_BASE)/bin/blank.bin - -proxy-0x00000.bin: proxy - ../python/esptool.py elf2image $^ - -proxy: proxy.o elm327.o webserver.o sha.o - -obj/proxy.o: proxy.c - $(CC) $(CFLAGS) -c $^ -o $@ - -obj/elm327.o: elm327.c - $(CC) $(CFLAGS) -c $^ -o $@ - -obj/webserver.o: webserver.c obj/cert.h obj/gitversion.h - $(CC) $(CFLAGS) -c $< -o $@ - -obj/cert.h: ../crypto/getcertheader.py - ../crypto/getcertheader.py ../certs/debugesp.pub ../certs/releaseesp.pub > obj/cert.h - -include ../common/version.mk - -obj/sha.o: ../crypto/sha.c - $(CC) $(CFLAGS) -c $^ -o $@ - -obj/rsa.o: ../crypto/rsa.c - $(CC) $(CFLAGS) -c $^ -o $@ - -oldflash: proxy-0x00000.bin - ../python/esptool.py write_flash 0 proxy-0x00000.bin 0x40000 proxy-0x40000.bin - -user1.bin: obj/proxy.o obj/elm327.o obj/webserver.o obj/sha.o obj/rsa.o - $(CC) $(CFLAGS) $^ -o a.out -L$(SDK_BASE)/ld -T$(SDK_BASE)/ld/eagle.app.v6.new.1024.app1.ld $(LDLIBS) - $(OBJCP) --only-section .text -O binary a.out eagle.app.v6.text.bin - $(OBJCP) --only-section .data -O binary a.out eagle.app.v6.data.bin - $(OBJCP) --only-section .rodata -O binary a.out eagle.app.v6.rodata.bin - $(OBJCP) --only-section .irom0.text -O binary a.out eagle.app.v6.irom0text.bin - COMPILE=gcc python2 ./esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/tools/gen_appbin.py a.out 2 0 32 4 0 - rm -f eagle.app.v6.*.bin - mv eagle.app.flash.bin $@ - ../crypto/sign.py $@ $@ $(CERT) - -user2.bin: obj/proxy.o obj/elm327.o obj/webserver.o obj/sha.o obj/rsa.o - $(CC) $(CFLAGS) $^ -o a.out -L$(SDK_BASE)/ld -T$(SDK_BASE)/ld/eagle.app.v6.new.1024.app2.ld $(LDLIBS) - $(OBJCP) --only-section .text -O binary a.out eagle.app.v6.text.bin - $(OBJCP) --only-section .data -O binary a.out eagle.app.v6.data.bin - $(OBJCP) --only-section .rodata -O binary a.out eagle.app.v6.rodata.bin - $(OBJCP) --only-section .irom0.text -O binary a.out eagle.app.v6.irom0text.bin - COMPILE=gcc python2 ./esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/tools/gen_appbin.py a.out 2 0 32 4 0 - rm -f eagle.app.v6.*.bin - mv eagle.app.flash.bin $@ - ../crypto/sign.py $@ $@ $(CERT) - -ota: user1.bin user2.bin - curl http://192.168.0.10/espupdate1 --upload-file user1.bin - curl http://192.168.0.10/espupdate2 --upload-file user2.bin - -clean: - rm -f proxy proxy.o proxy-0x00000.bin proxy-0x40000.bin eagle.app.* user1.bin user2.bin a.out obj/* diff --git a/boardesp/README.md b/boardesp/README.md deleted file mode 100644 index 5a8fab1..0000000 --- a/boardesp/README.md +++ /dev/null @@ -1,22 +0,0 @@ - -Dependencies ------ - -**Debian / Ubuntu** - -``` -./get_sdk.sh -``` - -**Mac** - -``` -./get_sdk_mac.sh -``` - -Programming ------ - -``` -make -``` diff --git a/boardesp/elm327.c b/boardesp/elm327.c deleted file mode 100644 index cec9fd8..0000000 --- a/boardesp/elm327.c +++ /dev/null @@ -1,1578 +0,0 @@ -#include "ets_sys.h" -#include "osapi.h" -#include "gpio.h" -#include "os_type.h" -#include "user_interface.h" -#include "espconn.h" -#include "mem.h" - -#include "driver/uart.h" - -//#define ELM_DEBUG - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -int ICACHE_FLASH_ATTR spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen); - -#define ELM_PORT 35000 - -//Version 1.5 is an invalid version used by many pirate clones -//that only partially support 1.0. -#define IDENT_MSG "ELM327 v1.5\r\r" -#define DEVICE_DESC "Panda\n\n" - -#define SHOW_CONNECTION(msg, p_conn) os_printf("%s %p, proto %p, %d.%d.%d.%d:%d disconnect\r\n", \ - msg, p_conn, (p_conn)->proto.tcp, (p_conn)->proto.tcp->remote_ip[0], \ - (p_conn)->proto.tcp->remote_ip[1], (p_conn)->proto.tcp->remote_ip[2], \ - (p_conn)->proto.tcp->remote_ip[3], (p_conn)->proto.tcp->remote_port) - -const static char hex_lookup[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -typedef struct __attribute__((packed)) { - bool tx : 1; - bool : 1; - bool ext : 1; - uint32_t addr : 29; - - uint8_t len : 4; - uint8_t bus : 8; - uint8_t : 4; //unused - uint16_t ts : 16; - uint8_t data[8]; -} panda_can_msg_t; - -//TODO: Masking is likely unnecessary for these bit fields. Check. -#define panda_get_can_addr(recv) (((recv)->ext) ? ((recv)->addr & 0x1FFFFFFF) :\ - (((recv)->addr >> 18) & 0x7FF)) - -#define PANDA_CAN_FLAG_TRANSMIT 1 -#define PANDA_CAN_FLAG_EXTENDED 4 - -#define PANDA_USB_CAN_WRITE_BUS_NUM 3 -#define PANDA_USB_LIN_WRITE_BUS_NUM 2 - -#define SAFETY_ELM327 3U - -typedef struct _elm_tcp_conn { - struct espconn *conn; - struct _elm_tcp_conn *next; -} elm_tcp_conn_t; - -typedef struct __attribute__((packed)) { - uint8_t len; - uint8_t dat[7]; //mode and data -} elm_can_obd_msg; - -typedef struct __attribute__((packed)) { - uint8_t priority; - uint8_t receiver; - uint8_t sender; - - uint8_t dat[8]; //mode, data, and checksum -} elm_lin_obd_msg; - -typedef struct __attribute__((packed)) { - uint16_t usb_ep_num; - uint16_t payload_len; - - uint8_t serial_port; - //uint8_t msg[8+3]; - elm_lin_obd_msg msg; -} elm_lin_usb_msg; - -static struct espconn elm_conn; -static esp_tcp elm_proto; -static elm_tcp_conn_t *connection_list = NULL; - -static char stripped_msg[0x100]; -static uint16 stripped_msg_len = 0; - -static char in_msg[0x100]; -static uint16 in_msg_len = 0; - -static char rsp_buff[536]; //TCP min MTU -static uint16 rsp_buff_len = 0; - -static uint8_t pandaSendData[0x14] = {0}; -static uint32_t pandaRecvData[0x40] = {0}; -static uint32_t pandaRecvDataDummy[0x40] = {0}; // Used for CAN write operations (no received data) - -#define ELM_MODE_SELECTED_PROTOCOL_DEFAULT 6 -#define ELM_MODE_TIMEOUT_DEFAULT 20; -#define ELM_MODE_KEEPALIVE_PERIOD_DEFAULT (0x92*20) - -static bool elm_mode_echo = true; -static bool elm_mode_linefeed = false; -static bool elm_mode_additional_headers = false; -static bool elm_mode_auto_protocol = true; -static uint8_t elm_selected_protocol = ELM_MODE_SELECTED_PROTOCOL_DEFAULT; -static bool elm_mode_print_spaces = true; -static uint8_t elm_mode_adaptive_timing = 1; -static bool elm_mode_allow_long = false; -static uint16_t elm_mode_timeout = ELM_MODE_TIMEOUT_DEFAULT; -static uint16_t elm_mode_keepalive_period = ELM_MODE_KEEPALIVE_PERIOD_DEFAULT; - -bool lin_bus_initialized = false; - -/*********************************************** - *** ELM CLI response functions *** - *** (for sending data back to the terminal) *** - ***********************************************/ - -// All ELM operations are global, so send data out to all connections -void ICACHE_FLASH_ATTR elm_tcp_tx_flush() { - if(!rsp_buff_len) return; // Was causing small error messages - - for(elm_tcp_conn_t *iter = connection_list; iter != NULL; iter = iter->next){ - int8_t err = espconn_send(iter->conn, rsp_buff, rsp_buff_len); - if(err){ - os_printf(" Wifi %p TX error code %d\n", iter->conn, err); - if(err == ESPCONN_ARG) { - if(iter == connection_list) { - connection_list = iter->next; - } else { - for(elm_tcp_conn_t *iter2 = connection_list; iter2 != NULL; iter2 = iter2->next) - if(iter2->next == iter) { - iter2->next = iter->next; - break; - } - } - os_printf(" deleting orphaned connection. iter: %p; conn: %p\n", iter, iter->conn); - os_free(iter); - } - } - } - rsp_buff_len = 0; -} - -static void ICACHE_FLASH_ATTR elm_append_rsp(const char *data, uint16_t len) { - uint16_t overflow_len = 0; - if(rsp_buff_len + len > sizeof(rsp_buff)) { - overflow_len = rsp_buff_len + len - sizeof(rsp_buff); - len = sizeof(rsp_buff) - rsp_buff_len; - } - if(!elm_mode_linefeed) { - memcpy(rsp_buff + rsp_buff_len, data, len); - rsp_buff_len += len; - } else { - for(int i=0; i < len && rsp_buff_len < sizeof(rsp_buff); i++){ - rsp_buff[rsp_buff_len++] = data[i]; - if(data[i] == '\r' && rsp_buff_len < sizeof(rsp_buff)) - rsp_buff[rsp_buff_len++] = '\n'; - } - } - if(overflow_len) { - os_printf("Packet full, sending\n"); - elm_tcp_tx_flush(); - elm_append_rsp(data + len, overflow_len); - } -} - -#define elm_append_rsp_const(str) elm_append_rsp(str, sizeof(str)-1) - -static void ICACHE_FLASH_ATTR elm_append_rsp_hex_byte(uint8_t num) { - elm_append_rsp(&hex_lookup[num >> 4], 1); - elm_append_rsp(&hex_lookup[num & 0xF], 1); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); -} - -void ICACHE_FLASH_ATTR elm_append_rsp_can_msg_addr(const panda_can_msg_t *recv) { - //Show address - uint32_t addr = panda_get_can_addr(recv); - if(recv->ext){ - elm_append_rsp_hex_byte(addr>>24); - elm_append_rsp_hex_byte(addr>>16); - elm_append_rsp_hex_byte(addr>>8); - elm_append_rsp_hex_byte(addr); - } else { - elm_append_rsp(&hex_lookup[addr>>8], 1); - elm_append_rsp_hex_byte(addr); - } -} - -/*************************************** - *** Panda communication functions *** - *** (for controlling the Panda MCU) *** - ***************************************/ - -static int ICACHE_FLASH_ATTR panda_usbemu_ctrl_write(uint8_t request_type, uint8_t request, - uint16_t value, uint16_t index, uint16_t length) { - //self.sock.send(struct.pack("HHBBHHH", 0, 0, request_type, request, value, index, length)); - *(uint16_t*)(pandaSendData) = 0; - *(uint16_t*)(pandaSendData+2) = 0; - pandaSendData[4] = request_type; - pandaSendData[5] = request; - *(uint16_t*)(pandaSendData+6) = value; - *(uint16_t*)(pandaSendData+8) = index; - *(uint16_t*)(pandaSendData+10) = length; - - int returned_count = spi_comm(pandaSendData, 0x10, pandaRecvData, 0x40); - if(returned_count > 0x40 || returned_count < 0) - return -1; - return returned_count; -} - -#define panda_set_can0_cbaud(cbps) panda_usbemu_ctrl_write(0x40, 0xde, 0, cbps, 0) -#define panda_set_can0_kbaud(kbps) panda_usbemu_ctrl_write(0x40, 0xde, 0, kbps*10, 0) -#define panda_set_safety_mode(mode) panda_usbemu_ctrl_write(0x40, 0xdc, mode, 0, 0) -#define panda_kline_wakeup_pulse() panda_usbemu_ctrl_write(0x40, 0xf0, 0, 0, 0) -#define panda_clear_can_rx() panda_usbemu_ctrl_write(0x40, 0xf1, 0xFFFF, 0, 0) -#define panda_clear_lin_txrx() panda_usbemu_ctrl_write(0x40, 0xf2, 2, 0, 0) - -static int ICACHE_FLASH_ATTR panda_usbemu_can_read(panda_can_msg_t** can_msgs) { - int returned_count = spi_comm((uint8_t *)((const uint16 []){1,0}), 4, pandaRecvData, 0x40); - if(returned_count > 0x40 || returned_count < 0){ - os_printf("CAN read got invalid length\n"); - return -1; - } - *can_msgs = (panda_can_msg_t*)(pandaRecvData+1); - return returned_count/sizeof(panda_can_msg_t); -} - -static int ICACHE_FLASH_ATTR panda_usbemu_can_write(bool ext, uint32_t addr, - char *candata, uint8_t canlen) { - uint32_t rir; - - if(canlen > 8) return 0; - - if(ext || addr >= 0x800){ - rir = (addr << 3) | PANDA_CAN_FLAG_TRANSMIT | PANDA_CAN_FLAG_EXTENDED; - }else{ - rir = (addr << 21) | PANDA_CAN_FLAG_TRANSMIT; - } - - #define MAX_CAN_LEN 8 - - //Wifi USB Wrapper - *(uint16_t*)(pandaSendData) = PANDA_USB_CAN_WRITE_BUS_NUM; //USB Bulk Endpoint ID. - *(uint16_t*)(pandaSendData+2) = MAX_CAN_LEN; - //BULK MESSAGE - *(uint32_t*)(pandaSendData+4) = rir; - *(uint32_t*)(pandaSendData+8) = MAX_CAN_LEN | (0 << 4); //0 is CAN bus number. - //CAN DATA - memcpy(pandaSendData+12, candata, canlen); - memset(pandaSendData+12+canlen, 0, MAX_CAN_LEN-canlen); - for(int i = 12+canlen; i < 20; i++) pandaSendData[i] = 0; //Zero the rest - - /* spi_comm will erase data in the recv buffer even if you are only - * interested in sending data that gets no response (like writing - * can data). This behavior becomes problematic when trying to send - * a can message while processsing received can messages. A dummy - * recv buffer is used here so received data is not overwritten. */ - int returned_count = spi_comm(pandaSendData, 0x14, pandaRecvDataDummy, 0x40); - if(returned_count) - os_printf("ELM Can send expected 0 bytes back from panda. Got %d bytes instead\n", returned_count); - if(returned_count > 0x40) return 0; - return returned_count; -} - -elm_lin_obd_msg lin_last_sent_msg; -uint16_t lin_last_sent_msg_len = 0; -bool lin_await_msg_echo = false; - -static int ICACHE_FLASH_ATTR panda_usbemu_kline_read(uint16_t len) { - int returned_count = panda_usbemu_ctrl_write(0xC0, 0xE0, 2, 0, len); - if(returned_count > len || returned_count < 0){ - os_printf("LIN read got invalid length\n"); - return -1; - } - - #ifdef ELM_DEBUG - if(returned_count) { - os_printf("LIN Received %d bytes\n", returned_count); - os_printf(" Data: "); - for(int i = 0; i < returned_count; i++) - os_printf("%02x ", ((char*)(pandaRecvData+1))[i]); - os_printf("\n"); - } - #endif - return returned_count; -} - -static int ICACHE_FLASH_ATTR panda_usbemu_kline_write(elm_lin_obd_msg *msg) { - elm_lin_usb_msg usb_msg = {}; - - usb_msg.usb_ep_num = PANDA_USB_LIN_WRITE_BUS_NUM; //USB Bulk Endpoint ID. - usb_msg.payload_len = (msg->priority & 0x07) + 4 + 1; //The +1 is for serial_port - usb_msg.serial_port = 2; - memcpy(&usb_msg.msg, msg, sizeof(elm_lin_obd_msg)); - - /* spi_comm will erase data in the recv buffer even if you are only - * interested in sending data that gets no response (like writing - * can data). This behavior becomes problematic when trying to send - * a can message while processsing received can messages. A dummy - * recv buffer is used here so received data is not overwritten. */ - int returned_count = spi_comm((char*)&usb_msg, sizeof(elm_lin_usb_msg), pandaRecvDataDummy, 0x40); - - if(returned_count) - os_printf("ELM LIN send expected 0 bytes back from panda. Got %d bytes instead\n", returned_count); - if(returned_count > 0x40) return 0; - - return returned_count; -} - -/**************************************** - *** Ringbuffer *** - ****************************************/ - -//LIN data is delivered in chunks of arbitrary size. Using a -//ringbuffer to handle it. -uint8_t lin_ringbuff[0x20]; -uint8_t lin_ringbuff_start = 0; -uint8_t lin_ringbuff_end = 0; -#define lin_ringbuff_len \ - (((sizeof(lin_ringbuff) + lin_ringbuff_end) - lin_ringbuff_start)% sizeof(lin_ringbuff)) -#define lin_ringbuff_get(index) (lin_ringbuff[(lin_ringbuff_start + index) % sizeof(lin_ringbuff)]) -#define lin_ringbuff_consume(len) lin_ringbuff_start = ((lin_ringbuff_start + len) % sizeof(lin_ringbuff)) -#define lin_ringbuff_clear()\ - {lin_ringbuff_start = 0; \ - lin_ringbuff_end = 0;} - -int ICACHE_FLASH_ATTR elm_LIN_ringbuff_memcmp(uint8_t *data, uint16_t len) { - if(len > lin_ringbuff_len) return 1; - for(int i = 0; i < len; i++) - if(lin_ringbuff_get(i) != data[i]) return 1; - return 0; // Going with memcpy ret format where 0 means 'equal' -} - -uint16_t ICACHE_FLASH_ATTR elm_LIN_read_into_ringbuff() { - int bytelen = panda_usbemu_kline_read((sizeof(lin_ringbuff) - lin_ringbuff_len) - 1); - if(bytelen < 0) return 0; - for(int j = 0; j < bytelen; j++) { - lin_ringbuff[lin_ringbuff_end % sizeof(lin_ringbuff)] = ((char*)(pandaRecvData+1))[j]; - lin_ringbuff_end = (lin_ringbuff_end + 1) % sizeof(lin_ringbuff); - if(lin_ringbuff_start == lin_ringbuff_end) lin_ringbuff_start++; - } - - #ifdef ELM_DEBUG - if(bytelen){ - os_printf(" RB Data (%d %d %d): ", lin_ringbuff_start, lin_ringbuff_end, lin_ringbuff_len); - for(int i = 0; i < sizeof(lin_ringbuff); i++) - os_printf("%02x ", lin_ringbuff[i]); - os_printf("\n"); - } - #endif - - return bytelen; -} - -/**************************************** - *** String parsing utility functions *** - ****************************************/ - -static int8_t ICACHE_FLASH_ATTR elm_decode_hex_char(char b){ - if(b >= '0' && b <= '9') return b - '0'; - if(b >= 'A' && b <= 'F') return (b - 'A') + 10; - if(b >= 'a' && b <= 'f') return (b - 'a') + 10; - return -1; -} - -static uint8_t ICACHE_FLASH_ATTR elm_decode_hex_byte(const char* data) { - return (elm_decode_hex_char(data[0]) << 4) | elm_decode_hex_char(data[1]); -} - -static bool ICACHE_FLASH_ATTR elm_check_valid_hex_chars(const char* data, uint8_t len) { - for(int i = 0; i < len; i++){ - char b = data[i]; - if(!((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f'))) - return 0; - } - return 1; -} - -static uint16_t ICACHE_FLASH_ATTR elm_strip(const char *data, uint16_t lenin, - char *outbuff, uint16_t outbufflen) { - uint16_t count = 0; - for(uint16_t i = 0; i < lenin; i++) { - if(count >= outbufflen) break; - if(data[i] == ' ') continue; - if(data[i] >= 'a' && data[i] <= 'z'){ - outbuff[count++] = data[i] - ('a' - 'A'); - } else { - outbuff[count++] = data[i]; - } - if(data[i] == '\r') break; - } - return count; -} - -static int ICACHE_FLASH_ATTR elm_msg_find_cr_or_eos(char *data, uint16_t len){ - uint16_t i; - for(i = 0; i < len; i++) - if(data[i] == '\r') { - i++; - break; - } - return i; -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *****************************************************/ - -typedef enum { - AUTO, LIN, CAN11, CAN29, NA -} elm_proto_type_t; - -typedef struct elm_protocol { - bool supported; - elm_proto_type_t type; - uint16_t cbaud; //Centibaud (cbaud * 10 = kbaud) - void (*process_obd)(const struct elm_protocol*, const char*, uint16_t); - //init is used to init and de-init a protocol. Init functions should - //not do things that would leave a new protocol in an invalid state - //after the new protocol's init is called (e.g. No arming timers). - void (*init)(const struct elm_protocol*); - char* name; -} elm_protocol_t; - -static const elm_protocol_t* ICACHE_FLASH_ATTR elm_current_proto(); -void ICACHE_FLASH_ATTR elm_reset_aux_timer(); -static void ICACHE_FLASH_ATTR elm_autodetect_cb(bool); - -static const elm_protocol_t elm_protocols[]; -//(sizeof(elm_protocols)/sizeof(elm_protocol_t)) -#define ELM_PROTOCOL_COUNT 13 - -#define LOOPCOUNT_FULL 4 -static int loopcount = 0; -static volatile os_timer_t elm_timeout; -static volatile os_timer_t elm_proto_aux_timeout; - -static bool is_auto_detecting = false; - -// Used only by elm_timer_cb, so not volatile -static bool did_multimessage = false; -static bool got_msg_this_run = false; -static bool can_tx_worked = false; -static uint8_t elm_msg_mode_ret_filter; -static uint8_t elm_msg_pid_ret_filter; - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> SAE J1850 implementation (Unsupported) *** - *****************************************************/ - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_J1850(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("NO DATA\r\r>"); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> ISO 14230-4 implementation *** - *****************************************************/ - -const char *lin_cmd_backup = NULL; //Holds msg while bus init is done -uint16_t lin_cmd_backup_len = 0; -bool lin_waiting_keepalive_echo = false; - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_LIN5baud(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("BUS INIT: ...ERROR\r\r>"); -} - -bool ICACHE_FLASH_ATTR elm_lin_keepalive_echo() { - if(lin_waiting_keepalive_echo) { - for(int pass = 0; pass < 4 && lin_ringbuff_len < 5; pass++) { - elm_LIN_read_into_ringbuff(); - } - - lin_waiting_keepalive_echo = false; - //keepalive Echo should always come before other message echo. - if(lin_ringbuff_len >= 5 && !elm_LIN_ringbuff_memcmp("\xc1\x33\xf1\x3e\x23", 5)){ - lin_ringbuff_consume(5); - return true; - } else { - os_printf("Keep alive echo failed\n"); - return false; - } - } - return true; -} - -void ICACHE_FLASH_ATTR elm_LINFast_keepalive_timer_cb(void *arg) { - if(!lin_bus_initialized) { - os_printf("WARNING! Elm LIN keepalive timer running while bus is not initialized\n"); - return; - } - if(loopcount) { - os_printf("WARNING! Elm LIN keepalive timer during a tx/rx loop!\n"); - return; - } - if(lin_ringbuff_len) { - os_printf("WARNING! lin_ringbuff_len should be 0 when a keepalive echo is processed.\n"); - return; - } - - if(!elm_lin_keepalive_echo()) { - lin_bus_initialized = false; - return; - } - - elm_lin_obd_msg msg = {}; - - msg.priority = 0xC0 | 1; - msg.receiver = 0x33; - msg.sender = 0xF1; - msg.dat[0] = 0x3E; - msg.dat[1] = msg.dat[0] + msg.priority + msg.receiver + msg.sender; // checksum - - #ifdef ELM_DEBUG - os_printf("Sending LIN KEEPALIVE: Priority: %02x; RecvAddr: %02x; SendAddr: %02x; (%02x); ", - msg.priority, msg.receiver, msg.sender, 1); - for(int i = 0; i < 2; i++) os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - lin_waiting_keepalive_echo = true; - - panda_usbemu_kline_write(&msg); - elm_reset_aux_timer(); -} - -static void ICACHE_FLASH_ATTR elm_init_LINFast(const elm_protocol_t* proto){ - os_timer_disarm(&elm_proto_aux_timeout); - os_timer_setfn(&elm_proto_aux_timeout, (os_timer_func_t *)elm_LINFast_keepalive_timer_cb, proto); - - lin_bus_initialized = false; - lin_await_msg_echo = false; - lin_waiting_keepalive_echo = false; - - lin_cmd_backup = NULL; - lin_cmd_backup_len = 0; - - lin_ringbuff_clear(); - panda_clear_lin_txrx(); -} - -int ICACHE_FLASH_ATTR elm_LINFast_process_echo() { - if(!elm_lin_keepalive_echo()) { - os_printf("Keepalive echo not detected.\n"); - lin_ringbuff_clear(); - return -1; - } - - if(!lin_await_msg_echo) { - os_printf("Echo abort. Nothing waiting echo\n"); - return 1; - } - - for(int i = 0; i < 4; i++){ - if(lin_ringbuff_len < lin_last_sent_msg_len) elm_LIN_read_into_ringbuff(); - - if(lin_ringbuff_len >= lin_last_sent_msg_len){ - #ifdef ELM_DEBUG - os_printf("Got enough data %d\n", lin_last_sent_msg_len); - #endif - if(!elm_LIN_ringbuff_memcmp((uint8_t*)&lin_last_sent_msg, lin_last_sent_msg_len)) { - #ifdef ELM_DEBUG - os_printf("LIN data was sent successfully.\n"); - #endif - lin_ringbuff_consume(lin_last_sent_msg_len); - lin_await_msg_echo = false; - return 1; - } else { - #ifdef ELM_DEBUG - os_printf("Echo not correct.\n"); - os_printf(" RB Data (%d %d %d): ", lin_ringbuff_start, lin_ringbuff_end, lin_ringbuff_len); - for(int i = 0; i < sizeof(lin_ringbuff); i++) - os_printf("%02x ", lin_ringbuff[i]); - os_printf("\n"); - os_printf(" MSG Data (%d): ", lin_last_sent_msg_len); - for(int i = 0; i < lin_last_sent_msg_len; i++) - os_printf("%02x ", ((uint8_t*)&lin_last_sent_msg)[i]); - os_printf("\n"); - #endif - - if(lin_bus_initialized || loopcount == 0 && i == 4) { - lin_ringbuff_clear(); - return -1; - } else { - os_printf("Lin init echo misaligned? Consuming byte (%02x). Retry.\n", lin_ringbuff_get(0)); - lin_ringbuff_consume(1); - continue; - } - } - } - } - - return !lin_await_msg_echo; //true if echo handled -} - -void ICACHE_FLASH_ATTR elm_LINFast_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - #ifdef ELM_DEBUG - os_printf("LIN CB call\n"); - #endif - - if(!lin_bus_initialized) { - os_printf("WARNING: LIN CB called without bus initialized!"); - return; // TODO: shoulnd't ever happen. Handle? - } - - int echo_result = elm_LINFast_process_echo(); - - if(echo_result == -1 || (echo_result == 0 && loopcount == 0)) { - if(!is_auto_detecting){ - elm_append_rsp_const("BUS ERROR\r\r>"); - elm_tcp_tx_flush(); - } - loopcount = 0; - lin_bus_initialized = false; - return; - } - - if(echo_result == 0) { - #ifdef ELM_DEBUG - os_printf("Not ready to process\n"); - #endif - os_timer_arm(&elm_timeout, 30, 0); - return; // Not ready to go on - } - - #ifdef ELM_DEBUG - os_printf("Processing ELM %d\n", lin_ringbuff_len); - #endif - - if(loopcount>0) { - for(int pass = 0; pass < 16 && loopcount; pass++){ - elm_LIN_read_into_ringbuff(); - - while(lin_ringbuff_len > 0){ - //if(lin_ringbuff_len > 0){ - if(lin_ringbuff_get(0) & 0x80 != 0x80){ - os_printf("Resetting LIN bus due to bad first byte.\n"); - loopcount = 0; - lin_bus_initialized = false; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } - return; - } - - uint8_t newmsg_len = 4 + (lin_ringbuff_get(0) & 0x7); - if(lin_ringbuff_len >= newmsg_len) { - #ifdef ELM_DEBUG - os_printf("Processing LIN MSG. BuffLen %d; expect %d. Dat: ", lin_ringbuff_len, newmsg_len); - for(int i = 0; i < newmsg_len; i++) os_printf("%02x ", lin_ringbuff_get(i)); - os_printf("\n"); - #endif - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - - if(!is_auto_detecting){ - if(elm_mode_additional_headers){ - for(int i = 0; i < newmsg_len; i++) elm_append_rsp_hex_byte(lin_ringbuff_get(i)); - } else { - for(int i = 3; i < newmsg_len - 1; i++) elm_append_rsp_hex_byte(lin_ringbuff_get(i)); - } - elm_append_rsp_const("\r"); - } - - lin_ringbuff_consume(newmsg_len); - //elm_reset_aux_timer(); - } else { - break; //Stop consuming data if there is not enough data for the next msg. - } - } - } - os_timer_arm(&elm_timeout, 50, 0); - } else { - bool got_msg_this_run_backup = got_msg_this_run; - if(!got_msg_this_run) { - #ifdef ELM_DEBUG - os_printf(" No data collected\n"); - #endif - if(!is_auto_detecting) { - elm_append_rsp_const("NO DATA\r"); - } - } - got_msg_this_run = false; - - if(!is_auto_detecting) { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(got_msg_this_run_backup); - } - - //TX RX over, resume Keepalive timer - elm_reset_aux_timer(); - } -} - -void ICACHE_FLASH_ATTR elm_LINFast_businit_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - #ifdef ELM_DEBUG - os_printf("LIN INIT CB call\n"); - #endif - - int echo_result = elm_LINFast_process_echo(); - - if(echo_result == -1 || (echo_result == 0 && loopcount == 0)) { - #ifdef ELM_DEBUG - os_printf("Init failed with echo test\n"); - #endif - - loopcount = 0; - lin_bus_initialized = 0; - - if(!is_auto_detecting){ - if(echo_result == -1) - elm_append_rsp_const("BUS ERROR\r\r>"); - else - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - if(echo_result == 0) { - #ifdef ELM_DEBUG - os_printf("Not ready to process\n"); - #endif - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - return; // Not ready to go on - } - - #ifdef ELM_DEBUG - os_printf("Bus init ready to process %d bytes\n", lin_ringbuff_len); - #endif - - if(lin_bus_initialized) return; // TODO: shoulnd't ever happen. Handle? - - if(loopcount>0) { - //Keep waiting for response - for(int i = 0; i < 4; i++){ - elm_LIN_read_into_ringbuff(); - - if(lin_ringbuff_len > 0){ - if(lin_ringbuff_get(0) & 0x80 != 0x80){ - os_printf("Resetting LIN bus due to bad first byte.\n"); - loopcount = 0; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - uint8_t newmsg_len = 4 + (lin_ringbuff_get(0) & 0x7); - if(lin_ringbuff_len < newmsg_len) { - os_printf("Resetting LIN because returned init data was wrong.\n"); - loopcount = 0; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - if(!elm_LIN_ringbuff_memcmp("\x83\xF1\x10\xC1\x8F\xE9\xBD", 7)) { - lin_ringbuff_consume(7); - lin_bus_initialized = true; - //lin_ringbuff_clear(); - - os_printf("BUS INITIALIZED\n"); - - elm_reset_aux_timer(); - - if(!is_auto_detecting) { - elm_append_rsp_const("OK\r"); - - //Do the send that was delayed - if(lin_cmd_backup_len) { - elm_tcp_tx_flush(); - proto->process_obd(proto, lin_cmd_backup, lin_cmd_backup_len); - } else { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } - } else { - #ifdef ELM_DEBUG - os_printf("LIN success. Silent because in autodetect.\n"); - #endif - elm_autodetect_cb(true); - // TODO: Since bus init is good, is it ok to skip sending the '0100' msg? - } - return; - } - } - } - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - } else { - #ifdef ELM_DEBUG - os_printf("Fall through on bus init\n"); - #endif - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - elm_reset_aux_timer(); - } -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_LINFast(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_lin_obd_msg msg = {}; - uint8_t bytelen = (len-1)/2; - if((bytelen > 7 && !elm_mode_allow_long) || bytelen > 8) { - elm_append_rsp_const("?\r\r>"); - return; - } - - os_timer_disarm(&elm_proto_aux_timeout); - - if(!lin_bus_initialized) { - panda_clear_lin_txrx(); - - if(!is_auto_detecting) - elm_append_rsp_const("BUS INIT: "); - - lin_cmd_backup = cmd; - lin_cmd_backup_len = len; - - bytelen = 1; - msg.dat[0] = 0x81; - msg.dat[1] = 0x81; // checksum - - panda_kline_wakeup_pulse(); - } else { - bytelen = MIN(bytelen, 7); - for(int i = 0; i < bytelen; i++){ - msg.dat[i] = elm_decode_hex_byte(&cmd[i*2]); - msg.dat[bytelen] += msg.dat[i]; - } - - elm_msg_mode_ret_filter = msg.dat[0]; - elm_msg_pid_ret_filter = msg.dat[1]; - } - - msg.priority = 0xC0 | bytelen; - msg.receiver = 0x33; - msg.sender = 0xF1; - msg.dat[bytelen] += msg.priority + msg.receiver + msg.sender; // checksum - - #ifdef ELM_DEBUG - os_printf("Sending LIN OBD: Priority: %02x; RecvAddr: %02x; SendAddr: %02x; (%02x); ", - msg.priority, msg.receiver, msg.sender, bytelen); - for(int i = 0; i < 8; i++) os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - lin_last_sent_msg_len = (msg.priority & 0x07) + 4; - memcpy(&lin_last_sent_msg, &msg, lin_last_sent_msg_len); - lin_await_msg_echo = true; - panda_usbemu_kline_write(&msg); - - loopcount = LOOPCOUNT_FULL + 1; - os_timer_disarm(&elm_timeout); - - if(lin_bus_initialized) { - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_LINFast_timer_cb, proto); - elm_LINFast_timer_cb((void*)proto); - } else { - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_LINFast_businit_timer_cb, proto); - elm_LINFast_businit_timer_cb((void*)proto); - } -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> ISO 15765-4 implementation *** - *****************************************************/ - -void ICACHE_FLASH_ATTR elm_ISO15765_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - if(loopcount>0) { - for(int pass = 0; pass < 16 && loopcount; pass++){ - panda_can_msg_t *can_msgs; - int num_can_msgs = panda_usbemu_can_read(&can_msgs); - - #ifdef ELM_DEBUG - if(num_can_msgs) os_printf(" Received %d can messages\n", num_can_msgs); - #endif - - if(num_can_msgs < 0) continue; - if(!num_can_msgs) break; - - for(int i = 0; i < num_can_msgs; i++){ - - panda_can_msg_t *recv = &can_msgs[i]; - - #ifdef ELM_DEBUG - os_printf(" RECV: Bus: %d; Addr: %08x; ext: %d; tx: %d; Len: %d; ", - recv->bus, panda_get_can_addr(recv), recv->ext, recv->tx, recv->len); - for(int j = 0; j < recv->len; j++) os_printf("%02x ", recv->data[j]); - os_printf("Ts: %d\n", recv->ts); - #endif - - if (recv->bus==0 && recv->len == 8 && - ( - (proto->type == CAN11 && !recv->ext && (panda_get_can_addr(recv) & 0x7F8) == 0x7E8) || - (proto->type == CAN29 && recv->ext && (panda_get_can_addr(recv) & 0x1FFFFF00) == 0x18DAF100) - ) - ) { - if(recv->data[0] <= 7 && - recv->data[1] == (0x40|elm_msg_mode_ret_filter) && - recv->data[2] == elm_msg_pid_ret_filter) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - - #ifdef ELM_DEBUG - os_printf(" CAN msg response, index: %d\n", i); - #endif - - if(!is_auto_detecting){ - if(elm_mode_additional_headers){ - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < recv->data[0]+1; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - for(int j = 1; j < recv->data[0]+1; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - - elm_append_rsp_const("\r"); - elm_tcp_tx_flush(); - } - - } else if((recv->data[0] & 0xF0) == 0x10 && - recv->data[2] == (0x40|elm_msg_mode_ret_filter) && - recv->data[3] == elm_msg_pid_ret_filter) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - panda_usbemu_can_write(0, - (proto->type==CAN11) ? - 0x7E0 | (panda_get_can_addr(recv)&0x7) : - (0x18DA00F1 | (((panda_get_can_addr(recv))&0xFF)<<8)), - "\x30\x00\x00", 3); - - did_multimessage = true; - - #ifdef ELM_DEBUG - os_printf(" CAN multimsg start response, index: %d, len %d\n", i, - ((recv->data[0]&0xF)<<8) | recv->data[1]); - #endif - - if(!is_auto_detecting){ - if(!elm_mode_additional_headers) { - elm_append_rsp(&hex_lookup[recv->data[0]&0xF], 1); - elm_append_rsp_hex_byte(recv->data[1]); - elm_append_rsp_const("\r0:"); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); - for(int j = 2; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - - elm_append_rsp_const("\r"); - elm_tcp_tx_flush(); - } - - } else if (did_multimessage && (recv->data[0] & 0xF0) == 0x20) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - #ifdef ELM_DEBUG - os_printf(" CAN multimsg data response, index: %d\n", i); - #endif - - if(!is_auto_detecting){ - if(!elm_mode_additional_headers) { - elm_append_rsp(&hex_lookup[recv->data[0] & 0xF], 1); - elm_append_rsp_const(":"); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); - for(int j = 1; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - elm_append_rsp_const("\r"); - } - } - } else if (recv->bus == 0x80 && recv->len == 8 && - (panda_get_can_addr(recv) == ((proto->type==CAN11) ? 0x7DF : 0x18DB33F1)) - ) { - //Can send receipt - #ifdef ELM_DEBUG - os_printf(" Got CAN tx receipt\n"); - #endif - can_tx_worked = true; - } - } - } - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - } else { - bool got_msg_this_run_backup = got_msg_this_run; - if(did_multimessage) { - os_printf(" End of multi message\n"); - } else if(!got_msg_this_run) { - os_printf(" No data collected\n"); - if(!is_auto_detecting) { - if(can_tx_worked) { - elm_append_rsp_const("NO DATA\r"); - } else { - elm_append_rsp_const("CAN ERROR\r"); - } - } - } - did_multimessage = false; - got_msg_this_run = false; - can_tx_worked = false; - - if(!is_auto_detecting) { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(got_msg_this_run_backup); - } - } -} - -static void ICACHE_FLASH_ATTR elm_init_ISO15765(const elm_protocol_t* proto){ - panda_set_can0_cbaud(proto->cbaud); -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_ISO15765(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_can_obd_msg msg = {}; - msg.len = (len-1)/2; - if((msg.len > 7 && !elm_mode_allow_long) || msg.len > 8) { - elm_append_rsp_const("?\r\r>"); - return; - } - - msg.len = MIN(msg.len, 7); - - for(int i = 0; i < msg.len; i++) - msg.dat[i] = elm_decode_hex_byte(&cmd[i*2]); - - elm_msg_mode_ret_filter = msg.dat[0]; - elm_msg_pid_ret_filter = msg.dat[1]; - - #ifdef ELM_DEBUG - os_printf("Sending CAN OBD: %02x; ", msg.len); - for(int i = 0; i < 7; i++) - os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - panda_clear_can_rx(); - - panda_usbemu_can_write(0, (proto->type==CAN11) ? 0x7DF : 0x18DB33F1, - (uint8_t*)&msg, msg.len+1); - - #ifdef ELM_DEBUG - os_printf("Starting up timer\n"); - #endif - - loopcount = LOOPCOUNT_FULL; - os_timer_disarm(&elm_timeout); - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_ISO15765_timer_cb, proto); - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> Stuf for unsupported CAN protocols *** - *****************************************************/ - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_CANGen(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("NO DATA\r\r>"); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> AUTO Detect implementation *** - *****************************************************/ - -static int elm_autodetect_proto_iter; -static uint16_t elm_staged_auto_msg_len; -static const char* elm_staged_auto_msg; - -static void ICACHE_FLASH_ATTR elm_autodetect_cb(bool proto_worked){ - if(proto_worked) { - os_printf("Autodetect proto success\n"); - is_auto_detecting = false; - elm_selected_protocol = elm_autodetect_proto_iter; - elm_current_proto()->process_obd(elm_current_proto(), - elm_staged_auto_msg, elm_staged_auto_msg_len); - } else { - for(elm_autodetect_proto_iter++; elm_autodetect_proto_iter < ELM_PROTOCOL_COUNT; - elm_autodetect_proto_iter++){ - const elm_protocol_t *proto = &elm_protocols[elm_autodetect_proto_iter]; - if(proto->supported && proto->type != AUTO) { - os_printf("*** AUTO trying '%s'\n", proto->name); - proto->init(proto); - proto->process_obd(proto, "0100\r", 5); // Try sending on the bus - return; - } - } - - //if(elm_autodetect_main()) return; - is_auto_detecting = false; - os_printf("Autodetect failed\n"); - elm_append_rsp_const("UNABLE TO CONNECT\r\r>"); - elm_tcp_tx_flush(); - } -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_AUTO(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("SEARCHING...\r"); - elm_staged_auto_msg_len = len; - elm_staged_auto_msg = cmd; - is_auto_detecting = true; - - elm_autodetect_proto_iter = 0; - elm_autodetect_cb(false); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> Protocol Registry and related functions. *** - *****************************************************/ - -static const elm_protocol_t elm_protocols[] = { - {true, AUTO, 0, elm_process_obd_cmd_AUTO, NULL, "AUTO", }, - {false, NA, 416, elm_process_obd_cmd_J1850, NULL, "SAE J1850 PWM", }, - {false, NA, 104, elm_process_obd_cmd_J1850, NULL, "SAE J1850 VPW", }, - {false, LIN, 104, elm_process_obd_cmd_LIN5baud, NULL, "ISO 9141-2", }, - {false, LIN, 104, elm_process_obd_cmd_LIN5baud, NULL, "ISO 14230-4 (KWP 5BAUD)", }, - {true, LIN, 104, elm_process_obd_cmd_LINFast, NULL, "ISO 14230-4 (KWP FAST)", }, - {true, CAN11, 5000, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 11/500)",}, - {true, CAN29, 5000, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 29/500)",}, - {true, CAN11, 2500, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 11/250)",}, - {true, CAN29, 2500, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 29/250)",}, - {false, CAN29, 2500, elm_process_obd_cmd_CANGen, NULL, "SAE J1939 (CAN 29/250)", }, - {false, CAN11, 1250, elm_process_obd_cmd_CANGen, NULL, "USER1 (CAN 11/125)", }, - {false, CAN11, 500, elm_process_obd_cmd_CANGen, NULL, "USER2 (CAN 11/50)", }, -}; - -static const elm_protocol_t* ICACHE_FLASH_ATTR elm_current_proto() { - return &elm_protocols[elm_selected_protocol]; -} - -void ICACHE_FLASH_ATTR elm_reset_aux_timer() { - os_timer_disarm(&elm_proto_aux_timeout); - if(elm_mode_keepalive_period) - os_timer_arm(&elm_proto_aux_timeout, elm_mode_keepalive_period, 0); -} - -void ICACHE_FLASH_ATTR elm_proto_reinit(const elm_protocol_t *proto) { - if(proto->init) proto->init(proto); -} - -/******************************************* - *** ELM AT command parsing and handling *** - *******************************************/ - -enum at_cmd_ids_t { // FULL ELM 1.0 list - AT_INVALID, //Fake - - AT_AMP1, - AT_AL, - AT_AT0, AT_AT1, AT_AT2, // Added ELM 1.2, expected by Torque - AT_BD, - AT_BI, - AT_CAF0, AT_CAF1, - AT_CF_8, AT_CF_3, - AT_CFC0, AT_CFC1, - AT_CM_8, AT_CM_3, - AT_CP, - AT_CS, - AT_CV, - AT_D, - AT_DP, AT_DPN, - AT_E0, AT_E1, - AT_H0, AT_H1, - AT_I, - AT_IB10, - AT_IB96, - AT_L0, AT_L1, - AT_M0, AT_M1, AT_MA, - AT_MR, - AT_MT, - AT_NL, - AT_PC, - AT_R0, AT_R1, - AT_RV, - AT_S0, AT_S1, // Added ELM 1.3, expected by Torque - AT_SH_6, AT_SH_3, - AT_SPA, AT_SP, - AT_ST, - AT_SW, - AT_TPA, AT_TP, - AT_WM_XYZA, AT_WM_XYZAB, AT_WM_XYZABC, - AT_WS, - AT_Z, -}; - -typedef struct { - char* name; - uint8_t name_len; - uint8_t cmd_len; - enum at_cmd_ids_t id; -} at_cmd_reg_t; - -static const at_cmd_reg_t at_cmd_reg[] = { - {"@1", 2, 2, AT_AMP1}, - {"AL", 2, 2, AT_AL}, - {"AT0", 3, 3, AT_AT0}, // Added ELM 1.2, expected by Torque - {"AT1", 3, 3, AT_AT1}, // Added ELM 1.2, expected by Torque - {"AT2", 3, 3, AT_AT2}, // Added ELM 1.2, expected by Torque - {"DP", 2, 2, AT_DP}, - {"DPN", 3, 3, AT_DPN}, - {"E0", 2, 2, AT_E0}, - {"E1", 2, 2, AT_E1}, - {"H0", 2, 2, AT_H0}, - {"H1", 2, 2, AT_H1}, - {"I", 1, 1, AT_I}, - {"L0", 2, 2, AT_L0}, - {"L1", 2, 2, AT_L1}, - {"M0", 2, 2, AT_M0}, - //{"M1", 2, 2, AT_M1}, - {"NL", 2, 2, AT_NL}, - {"PC", 2, 2, AT_PC}, - {"S0", 2, 2, AT_S0}, // Added ELM 1.3, expected by Torque - {"S1", 2, 2, AT_S1}, // Added ELM 1.3, expected by Torque - {"SP", 2, 3, AT_SP}, - {"SPA", 3, 4, AT_SPA}, - {"ST", 2, 4, AT_ST}, - {"SW", 2, 4, AT_SW}, - {"Z", 1, 1, AT_Z}, -}; -#define AT_CMD_REG_LEN (sizeof(at_cmd_reg)/sizeof(at_cmd_reg_t)) - -static enum at_cmd_ids_t ICACHE_FLASH_ATTR elm_parse_at_cmd(char *cmd, uint16_t len){ - int i; - for(i=0; i7 BYTES) - elm_mode_allow_long = true; - break; - case AT_AT0: //DISABLE ADAPTIVE TIMING - elm_mode_adaptive_timing = 0; - break; - case AT_AT1: //SET ADAPTIVE TIMING TO AUTO1 - elm_mode_adaptive_timing = 1; - break; - case AT_AT2: //SET ADAPTIVE TIMING TO AUTO2 - elm_mode_adaptive_timing = 2; - break; - case AT_DP: //DESCRIBE THE PROTOCOL BY NAME - if(elm_mode_auto_protocol && elm_selected_protocol != 0) - elm_append_rsp_const("AUTO, "); - elm_append_rsp(elm_current_proto()->name, - strlen(elm_current_proto()->name)); - elm_append_rsp_const("\r\r"); - return; - case AT_DPN: //DESCRIBE THE PROTOCOL BY NUMBER - //TODO: Required. Report currently selected protocol - if(elm_mode_auto_protocol) - elm_append_rsp_const("A"); - elm_append_rsp(&hex_lookup[elm_selected_protocol], 1); - elm_append_rsp_const("\r\r"); - return; // Don't display 'OK' - case AT_E0: //ECHO OFF - elm_mode_echo = false; - break; - case AT_E1: //ECHO ON - elm_mode_echo = true; - break; - case AT_H0: //SHOW FULL CAN HEADERS OFF - elm_mode_additional_headers = false; - break; - case AT_H1: //SHOW FULL CAN HEADERS ON - elm_mode_additional_headers = true; - break; - case AT_I: //IDENTIFY SELF - elm_append_rsp_const(IDENT_MSG); - return; - case AT_L0: //LINEFEED OFF - elm_mode_linefeed = false; - break; - case AT_L1: //LINEFEED ON - elm_mode_linefeed = true; - break; - case AT_M0: //DISABLE NONVOLATILE STORAGE - //Memory storage is likely unnecessary - break; - case AT_NL: //DISABLE LONG MESSAGE SUPPORT (>7 BYTES) - elm_mode_allow_long = false; - break; - case AT_PC: //PROTOCOL CANCEL (Stop timers and stuff) - { - //Init functions should idenpotently prepare the protocol to be used. - //Thus, the init function can be used as a protocol cancel function - elm_proto_reinit(elm_current_proto()); - break; - } - case AT_S0: //DISABLE PRINTING SPACES IN ECU RESPONSES - elm_mode_print_spaces = false; - break; - case AT_S1: //ENABLE PRINTING SPACES IN ECU RESPONSES - elm_mode_print_spaces = true; - break; - case AT_SP: //SET PROTOCOL - tmp = elm_decode_hex_char(cmd[2]); - if(tmp == -1 || tmp >= ELM_PROTOCOL_COUNT) { - elm_append_rsp_const("?\r\r"); - return; - } - - //De-Init previous protocol - elm_proto_reinit(elm_current_proto()); - - elm_selected_protocol = tmp; - elm_mode_auto_protocol = (tmp == 0); - - //Init new protocol - elm_proto_reinit(elm_current_proto()); - break; - case AT_SPA: //SET PROTOCOL WITH AUTO FALLBACK - tmp = elm_decode_hex_char(cmd[3]); - if(tmp == -1 || tmp >= ELM_PROTOCOL_COUNT) { - elm_append_rsp_const("?\r\r"); - return; - } - - //De-Init previous protocol - elm_proto_reinit(elm_current_proto()); - - elm_selected_protocol = tmp; - elm_mode_auto_protocol = true; - - //Init new protocol - elm_proto_reinit(elm_current_proto()); - break; - case AT_ST: //SET TIMEOUT - if(!elm_check_valid_hex_chars(&cmd[2], 2)) { - elm_append_rsp_const("?\r\r"); - return; - } - - tmp = elm_decode_hex_byte(&cmd[2]); - //20 for CAN, 4 for LIN - elm_mode_timeout = tmp ? tmp*20 : ELM_MODE_TIMEOUT_DEFAULT; - break; - case AT_SW: //SET WAKEUP TIME INTERVAL - if(!elm_check_valid_hex_chars(&cmd[2], 2)) { - elm_append_rsp_const("?\r\r"); - return; - } - - tmp = elm_decode_hex_byte(&cmd[2]); - elm_mode_keepalive_period = tmp ? MAX(tmp, 0x20) * 20 : 0; - - if(lin_bus_initialized){ - os_timer_disarm(&elm_proto_aux_timeout); - if(elm_mode_keepalive_period) - os_timer_arm(&elm_proto_aux_timeout, elm_mode_keepalive_period, 0); - } - break; - case AT_Z: //RESET - elm_mode_echo = true; - elm_mode_linefeed = false; - elm_mode_additional_headers = false; - elm_mode_auto_protocol = true; - elm_selected_protocol = ELM_MODE_SELECTED_PROTOCOL_DEFAULT; - elm_mode_print_spaces = true; - elm_mode_adaptive_timing = 1; - elm_mode_allow_long = false; - elm_mode_timeout = ELM_MODE_TIMEOUT_DEFAULT; - elm_mode_keepalive_period = ELM_MODE_KEEPALIVE_PERIOD_DEFAULT; - - elm_append_rsp_const("\r\r"); - elm_append_rsp_const(IDENT_MSG); - panda_set_safety_mode(SAFETY_ELM327); - - elm_proto_reinit(elm_current_proto()); - return; - default: - elm_append_rsp_const("?\r\r"); - return; - } - - elm_append_rsp_const("OK\r\r"); -} - -/************************************* - *** Connection and cli management *** - *************************************/ - -static void ICACHE_FLASH_ATTR elm_append_in_msg(char *data, uint16_t len) { - if(in_msg_len + len > sizeof(in_msg)) - len = sizeof(in_msg) - in_msg_len; - memcpy(in_msg + in_msg_len, data, len); - in_msg_len += len; -} - -static int ICACHE_FLASH_ATTR elm_msg_is_at_cmd(char *data, uint16_t len){ - return len >= 4 && data[0] == 'A' && data[1] == 'T'; -} - -static void ICACHE_FLASH_ATTR elm_rx_cb(void *arg, char *data, uint16_t len) { - #ifdef ELM_DEBUG - //os_printf("\nGot ELM Data In: '%s'\n", data); - #endif - - rsp_buff_len = 0; - len = elm_msg_find_cr_or_eos(data, len); - - if(loopcount){ - os_timer_disarm(&elm_timeout); - loopcount = 0; - got_msg_this_run = false; - can_tx_worked = false; - did_multimessage = false; - - os_printf("Interrupting operation, stopping timer. msg len: %d\n", len); - elm_append_rsp_const("STOPPED\r\r>"); - if(len == 1 && data[0] == '\r') { - os_printf("Empty msg source of interrupt.\n"); - elm_tcp_tx_flush(); - return; - } - } - - if(!(len == 1 && data[0] == '\r') && in_msg_len && in_msg[in_msg_len-1] == '\r'){ - in_msg_len = 0; - } - - if(!(len == 1 && data[0] == '\r' && in_msg_len && in_msg[in_msg_len-1] == '\r')) { - // Not Repeating last message - elm_append_in_msg(data, len); //Aim to remove this memcpy - } - if(elm_mode_echo) - elm_append_rsp(in_msg, in_msg_len); - - if(in_msg_len > 0 && in_msg[in_msg_len-1] == '\r') { //Got a full line - stripped_msg_len = elm_strip(in_msg, in_msg_len, stripped_msg, sizeof(stripped_msg)); - - if(elm_msg_is_at_cmd(stripped_msg, stripped_msg_len)) { - elm_process_at_cmd(stripped_msg+2, stripped_msg_len-2); - elm_append_rsp_const(">"); - } else if(elm_check_valid_hex_chars(stripped_msg, stripped_msg_len - 1)) { - elm_current_proto()->process_obd(elm_current_proto(), stripped_msg, stripped_msg_len); - } else { - elm_append_rsp_const("?\r\r>"); - } - } - - elm_tcp_tx_flush(); - - //Just clear the buffer if full with no termination - if(in_msg_len == sizeof(in_msg) && in_msg[in_msg_len-1] != '\r') - in_msg_len = 0; -} - -void ICACHE_FLASH_ATTR elm_tcp_disconnect_cb(void *arg){ - struct espconn *pesp_conn = (struct espconn *)arg; - - elm_tcp_conn_t * prev = NULL; - for(elm_tcp_conn_t *iter = connection_list; iter != NULL; iter=iter->next){ - struct espconn *conn = iter->conn; - //SHOW_CONNECTION("Considering Disconnecting", conn); - if(!memcmp(pesp_conn->proto.tcp->remote_ip, conn->proto.tcp->remote_ip, 4) && - pesp_conn->proto.tcp->remote_port == conn->proto.tcp->remote_port){ - os_printf("Deleting ELM Connection!\n"); - if(prev){ - prev->next = iter->next; - } else { - connection_list = iter->next; - } - os_free(iter); - break; - } - - prev = iter; - } - - if(connection_list == NULL) { - //If all clients are disconnected, reset the protocol (cancels - //keep alive timers). This will not detect inproperly killed - //connections. In this case, periodic events associated with the - //current protocol will continue until a new client attaches, a - //command is sent generating a response (ELM will try to responde - //to the dead connection, and remove it upon error), and finally, - //the new client disconnects. OFC a power cycle is also an option. - elm_proto_reinit(elm_current_proto()); - } -} - -void ICACHE_FLASH_ATTR elm_tcp_connect_cb(void *arg) { - struct espconn *pesp_conn = (struct espconn *)arg; - //SHOW_CONNECTION("New connection", pesp_conn); - espconn_set_opt(&elm_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(pesp_conn, elm_rx_cb); - //Allow several sends to be queued at a time. - espconn_tcp_set_buf_count(pesp_conn, 3); - - bool connection_address_already_there = false; - for(elm_tcp_conn_t *iter2 = connection_list; iter2 != NULL; iter2 = iter2->next) - if(iter2->conn == pesp_conn){connection_address_already_there = true; break;} - - if(connection_address_already_there) { - os_printf("ELM WIFI: Memory reuse of recently killed connection\n"); - } else { - os_printf("ELM WIFI: Adding connection\n"); - elm_tcp_conn_t *newconn = os_malloc(sizeof(elm_tcp_conn_t)); - if(!newconn) { - os_printf("Failed to allocate place for connection\n"); - } else { - newconn->next = connection_list; - newconn->conn = pesp_conn; - connection_list = newconn; - } - } -} - -void ICACHE_FLASH_ATTR elm327_init() { - // control listener - elm_proto.local_port = ELM_PORT; - elm_conn.type = ESPCONN_TCP; - elm_conn.state = ESPCONN_NONE; - elm_conn.proto.tcp = &elm_proto; - espconn_regist_connectcb(&elm_conn, elm_tcp_connect_cb); - espconn_regist_disconcb(&elm_conn, elm_tcp_disconnect_cb); - espconn_accept(&elm_conn); - espconn_regist_time(&elm_conn, 0, 0); // 60s timeout for all connections -} diff --git a/boardesp/get_sdk.sh b/boardesp/get_sdk.sh deleted file mode 100755 index b1e8bf2..0000000 --- a/boardesp/get_sdk.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -sudo apt-get install make unrar-free autoconf automake libtool gcc g++ gperf \ - flex bison texinfo gawk ncurses-dev libexpat-dev python-dev python python-serial \ - sed git unzip bash help2man wget bzip2 -# huh? -sudo apt-get install libtool -sudo apt-get install libtool-bin -git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -cd esp-open-sdk -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -cp ../python2_make.py . -python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' diff --git a/boardesp/get_sdk_ci.sh b/boardesp/get_sdk_ci.sh deleted file mode 100755 index e95b7bd..0000000 --- a/boardesp/get_sdk_ci.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -cd esp-open-sdk -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -cp ../python2_make.py . -python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' diff --git a/boardesp/get_sdk_mac.sh b/boardesp/get_sdk_mac.sh deleted file mode 100755 index c2cfcd5..0000000 --- a/boardesp/get_sdk_mac.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# from http://www.esp8266.com/wiki/doku.php?id=setup-osx-compiler-esp8266 - -brew install gnu-sed --with-default-names -brew tap homebrew/dupes -brew install gperf -brew install grep -brew install autoconf -brew install binutils -brew install gawk -brew install wget -brew install automake -brew install libtool -brew install help2man - -brew uninstall gperf - -hdiutil create esp-open-sdk.dmg -volname "esp-open-sdk" -size 10g -fs "Case-sensitive HFS+" -hdiutil mount esp-open-sdk.dmg -ln -s /Volumes/esp-open-sdk esp-open-sdk -cd esp-open-sdk - -git init -git remote add origin https://github.com/pfalcon/esp-open-sdk.git -git fetch origin -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -git submodule init -git submodule update --recursive - -cp ../python2_make.py . -python2 python2_make.py 'make STANDALONE=y' diff --git a/boardesp/include/espmissingincludes.h b/boardesp/include/espmissingincludes.h deleted file mode 100644 index 51672d3..0000000 --- a/boardesp/include/espmissingincludes.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ESPMISSINGINCLUDES_H -#define ESPMISSINGINCLUDES_H - -#include -#include -#include - - -int strcasecmp(const char *a, const char *b); -#ifndef FREERTOS -#include -#include -//Missing function prototypes in include folders. Gcc will warn on these if we don't define 'em anywhere. -//MOST OF THESE ARE GUESSED! but they seem to swork and shut up the compiler. -typedef struct espconn espconn; - -int atoi(const char *nptr); -void ets_install_putc1(void *routine); -void ets_isr_attach(int intr, void *handler, void *arg); -void ets_isr_mask(unsigned intr); -void ets_isr_unmask(unsigned intr); -int ets_memcmp(const void *s1, const void *s2, size_t n); -void *ets_memcpy(void *dest, const void *src, size_t n); -void *ets_memset(void *s, int c, size_t n); -int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -int ets_str2macaddr(void *, void *); -int ets_strcmp(const char *s1, const char *s2); -char *ets_strcpy(char *dest, const char *src); -size_t ets_strlen(const char *s); -int ets_strncmp(const char *s1, const char *s2, int len); -char *ets_strncpy(char *dest, const char *src, size_t n); -char *ets_strstr(const char *haystack, const char *needle); -void ets_timer_arm_new(os_timer_t *a, int b, int c, int isMstimer); -void ets_timer_disarm(os_timer_t *a); -void ets_timer_setfn(os_timer_t *t, ETSTimerFunc *fn, void *parg); -void ets_update_cpu_frequency(int freqmhz); -void *os_memmove(void *dest, const void *src, size_t n); -int os_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__ ((format (printf, 3, 4))); -int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void uart_div_modify(int no, unsigned int freq); -uint8 wifi_get_opmode(void); -uint32 system_get_time(); -int rand(void); -void ets_bzero(void *s, size_t n); -void ets_delay_us(int ms); - -//Hack: this is defined in SDK 1.4.0 and undefined in 1.3.0. It's only used for this, the symbol itself -//has no meaning here. -#ifndef RC_LIMIT_P2P_11N -//Defs for SDK <1.4.0 -void *pvPortMalloc(size_t xWantedSize); -void *pvPortZalloc(size_t); -void vPortFree(void *ptr); -void *vPortMalloc(size_t xWantedSize); -void pvPortFree(void *ptr); -#else -void *pvPortMalloc(size_t xWantedSize, const char *file, int line); -void *pvPortZalloc(size_t, const char *file, int line); -void vPortFree(void *ptr, const char *file, int line); -void *vPortMalloc(size_t xWantedSize, const char *file, int line); -void pvPortFree(void *ptr, const char *file, int line); -#endif - -//Standard PIN_FUNC_SELECT gives a warning. Replace by a non-warning one. -#ifdef PIN_FUNC_SELECT -#undef PIN_FUNC_SELECT -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ - WRITE_PERI_REG(PIN_NAME, \ - (READ_PERI_REG(PIN_NAME) \ - & (~(PERIPHS_IO_MUX_FUNC< _b ? _a : _b; }) - -char ssid[32]; -char password[] = "testing123"; -int wifi_secure_mode = 0; - -static const int pin = 2; - -// Structure holding the TCP connection information. -struct espconn tcp_conn; -// TCP specific protocol structure. -esp_tcp tcp_proto; - -// interrupt communication on port 1338, UDP! -struct espconn inter_conn; -esp_udp inter_proto; - -uint32_t sendData[0x14] = {0}; -uint32_t recvData[0x40] = {0}; - -static int ICACHE_FLASH_ATTR __spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) { - unsigned int length = 0; - - SpiData spiData; - - spiData.cmd = 2; - spiData.cmdLen = 0; - spiData.addr = NULL; - spiData.addrLen = 0; - - // float boot pin - gpio_output_set(0, 0, 0, (1 << 4)); - - // manual CS pin - gpio_output_set(0, (1 << 5), 0, 0); - memset(sendData, 0xCC, 0x14); - - // wait for ST to respond to CS interrupt - os_delay_us(50); - - // send request - memcpy(((void*)sendData), dat, len); - spiData.data = sendData; - spiData.dataLen = 0x14; - SPIMasterSendData(SpiNum_HSPI, &spiData); - - #define SPI_TIMEOUT 50000 - // give the ST time to be ready, up to 500ms - int i; - for (i = 0; (gpio_input_get() & (1 << 4)) && i < SPI_TIMEOUT; i++) { - os_delay_us(10); - system_soft_wdt_feed(); - } - - // TODO: handle this better - if (i == SPI_TIMEOUT) { - os_printf("ERROR: SPI receive failed\n"); - goto fail; - } - - // blank out recvData - memset(recvData, 0x00, 0x44); - - // receive the length - spiData.data = recvData; - spiData.dataLen = 4; - if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) { - // TODO: Handle gracefully. Maybe fail if len read fails? - os_printf("SPI: Failed to recv length\n"); - goto fail; - } - - length = recvData[0]; - if (length > 0x40) { - os_printf("SPI: BAD LENGTH RECEIVED %x\n", length); - length = 0; - goto fail; - } - - // got response, 0x40 works, 0x44 does not - spiData.data = recvData+1; - spiData.dataLen = (length+3)&(~3); // recvDataLen; - if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) { - // TODO: Handle gracefully. Maybe retry if payload failed. - os_printf("SPI: Failed to recv payload\n"); - length = 0; - goto fail; - } - -fail: - // clear CS - gpio_output_set((1 << 5), 0, 0, 0); - - // set boot pin back - gpio_output_set((1 << 4), 0, (1 << 4), 0); - - return length; -} - -int ICACHE_FLASH_ATTR spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) { - // blink the led during SPI comm - if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & (1 << pin)) { - // set gpio low - gpio_output_set(0, (1 << pin), 0, 0); - } else { - // set gpio high - gpio_output_set((1 << pin), 0, 0, 0); - } - - return __spi_comm(dat, len, recvData, recvDataLen); -} - -static void ICACHE_FLASH_ATTR tcp_rx_cb(void *arg, char *data, uint16_t len) { - // nothing too big - if (len > 0x14) return; - - // do the SPI comm - spi_comm(data, len, recvData, 0x40); - - espconn_send(&tcp_conn, recvData, 0x44); -} - -void ICACHE_FLASH_ATTR tcp_connect_cb(void *arg) { - struct espconn *conn = (struct espconn *)arg; - espconn_set_opt(&tcp_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(conn, tcp_rx_cb); -} - -// must be 0x44, because we can fit 4 more -uint8_t buf[0x44*0x10]; -int queue_send_len = -1; - -void ICACHE_FLASH_ATTR poll_can(void *arg) { - uint8_t timerRecvData[0x44] = {0}; - int i = 0; - int j; - - while (i < 0x40) { - int len = spi_comm("\x01\x00\x00\x00", 4, timerRecvData, 0x40); - if (len == 0) break; - if (len > 0x40) { os_printf("SPI LENGTH ERROR!"); break; } - - // if it sends it, assume it's valid CAN - for (j = 0; j < len; j += 0x10) { - memcpy(buf + i*0x10, (timerRecvData+4)+j, 0x10); - i++; - } - } - - if (i != 0) { - int ret = espconn_sendto(&inter_conn, buf, i*0x10); - if (ret != 0) { - os_printf("send failed: %d\n", ret); - queue_send_len = i*0x10; - } else { - queue_send_len = -1; - } - } -} - -int udp_countdown = 0; - -static volatile os_timer_t udp_callback; -void ICACHE_FLASH_ATTR udp_callback_func(void *arg) { - if (queue_send_len == -1) { - poll_can(NULL); - } else { - int ret = espconn_sendto(&inter_conn, buf, queue_send_len); - if (ret == 0) { - queue_send_len = -1; - } - } - if (udp_countdown > 0) { - os_timer_arm(&udp_callback, 5, 0); - udp_countdown--; - } else { - os_printf("UDP timeout\n"); - } -} - -void ICACHE_FLASH_ATTR inter_recv_cb(void *arg, char *pusrdata, unsigned short length) { - remot_info *premot = NULL; - if (espconn_get_connection_info(&inter_conn,&premot,0) == ESPCONN_OK) { - inter_conn.proto.udp->remote_port = premot->remote_port; - inter_conn.proto.udp->remote_ip[0] = premot->remote_ip[0]; - inter_conn.proto.udp->remote_ip[1] = premot->remote_ip[1]; - inter_conn.proto.udp->remote_ip[2] = premot->remote_ip[2]; - inter_conn.proto.udp->remote_ip[3] = premot->remote_ip[3]; - - - if (udp_countdown == 0) { - os_printf("UDP recv\n"); - udp_countdown = 200*5; - - // start 5 second timer - os_timer_disarm(&udp_callback); - os_timer_setfn(&udp_callback, (os_timer_func_t *)udp_callback_func, NULL); - os_timer_arm(&udp_callback, 5, 0); - } else { - udp_countdown = 200*5; - } - } -} - -void ICACHE_FLASH_ATTR wifi_configure(int secure) { - wifi_secure_mode = secure; - - // start wifi AP - wifi_set_opmode(SOFTAP_MODE); - struct softap_config config = {0}; - wifi_softap_get_config(&config); - strcpy(config.ssid, ssid); - if (wifi_secure_mode == 0) strcat(config.ssid, "-pair"); - strcpy(config.password, password); - config.ssid_len = strlen(config.ssid); - config.authmode = wifi_secure_mode ? AUTH_WPA2_PSK : AUTH_OPEN; - config.beacon_interval = 100; - config.max_connection = 4; - wifi_softap_set_config(&config); - - if (wifi_secure_mode) { - // setup tcp server - tcp_proto.local_port = 1337; - tcp_conn.type = ESPCONN_TCP; - tcp_conn.state = ESPCONN_NONE; - tcp_conn.proto.tcp = &tcp_proto; - espconn_regist_connectcb(&tcp_conn, tcp_connect_cb); - espconn_accept(&tcp_conn); - espconn_regist_time(&tcp_conn, 60, 0); // 60s timeout for all connections - - // setup inter server - inter_proto.local_port = 1338; - const char udp_remote_ip[4] = {255, 255, 255, 255}; - os_memcpy(inter_proto.remote_ip, udp_remote_ip, 4); - inter_proto.remote_port = 1338; - - inter_conn.type = ESPCONN_UDP; - inter_conn.proto.udp = &inter_proto; - - espconn_regist_recvcb(&inter_conn, inter_recv_cb); - espconn_create(&inter_conn); - } -} - -void ICACHE_FLASH_ATTR wifi_init() { - // default ssid and password - memset(ssid, 0, 32); - os_sprintf(ssid, "panda-%08x-BROKEN", system_get_chip_id()); - - // fetch secure ssid and password - // update, try 20 times, for 1 second - for (int i = 0; i < 20; i++) { - uint8_t digest[SHA_DIGEST_SIZE]; - char resp[0x20]; - __spi_comm("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", 0xC, recvData, 0x40); - memcpy(resp, recvData+1, 0x20); - - SHA_hash(resp, 0x1C, digest); - if (memcmp(digest, resp+0x1C, 4) == 0) { - // OTP is valid - memcpy(ssid+6, resp, 0x10); - memcpy(password, resp+0x10, 10); - break; - } - os_delay_us(50000); - } - os_printf("Finished getting SID\n"); - os_printf(ssid); - os_printf("\n"); - - // set IP - wifi_softap_dhcps_stop(); //stop DHCP before setting static IP - struct ip_info ip_config; - IP4_ADDR(&ip_config.ip, 192, 168, 0, 10); - IP4_ADDR(&ip_config.gw, 0, 0, 0, 0); - IP4_ADDR(&ip_config.netmask, 255, 255, 255, 0); - wifi_set_ip_info(SOFTAP_IF, &ip_config); - int stupid_gateway = 0; - wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &stupid_gateway); - wifi_softap_dhcps_start(); - - wifi_configure(0); -} - -#define LOOP_PRIO 2 -#define QUEUE_SIZE 1 -static os_event_t my_queue[QUEUE_SIZE]; -void loop(); - -void ICACHE_FLASH_ATTR web_init(); -void ICACHE_FLASH_ATTR elm327_init(); - -void ICACHE_FLASH_ATTR user_init() { - // init gpio subsystem - gpio_init(); - - // configure UART TXD to be GPIO1, set as output - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); - gpio_output_set(0, 0, (1 << pin), 0); - - // configure SPI - SpiAttr hSpiAttr; - hSpiAttr.bitOrder = SpiBitOrder_MSBFirst; - hSpiAttr.speed = SpiSpeed_10MHz; - hSpiAttr.mode = SpiMode_Master; - hSpiAttr.subMode = SpiSubMode_0; - - // TODO: is one of these CS? - WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); // configure io to spi mode - SPIInit(SpiNum_HSPI, &hSpiAttr); - //SPICsPinSelect(SpiNum_HSPI, SpiPinCS_1); - - // configure UART TXD to be GPIO1, set as output - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5); - gpio_output_set(0, 0, (1 << 5), 0); - gpio_output_set((1 << 5), 0, 0, 0); - - // uart init - uart_init(BIT_RATE_115200, BIT_RATE_115200); - - // led init - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); - gpio_output_set(0, (1 << pin), (1 << pin), 0); - - os_printf("hello\n"); - - // needs SPI - wifi_init(); - - // support ota upgrades - elm327_init(); - web_init(); - - // set gpio high, so LED is off by default - for (int i = 0; i < 5; i++) { - gpio_output_set(0, (1 << pin), 0, 0); - os_delay_us(50000); - gpio_output_set((1 << pin), 0, 0, 0); - os_delay_us(50000); - } - - // jump to OS - system_os_task(loop, LOOP_PRIO, my_queue, QUEUE_SIZE); - system_os_post(LOOP_PRIO, 0, 0); -} - -void ICACHE_FLASH_ATTR loop(os_event_t *events) { - system_os_post(LOOP_PRIO, 0, 0); -} - diff --git a/boardesp/python2_make.py b/boardesp/python2_make.py deleted file mode 100644 index 85bee34..0000000 --- a/boardesp/python2_make.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python2 -import os -import sys -os.system(sys.argv[1]) diff --git a/boardesp/user_config.h b/boardesp/user_config.h deleted file mode 100644 index e69de29..0000000 diff --git a/boardesp/webserver.c b/boardesp/webserver.c deleted file mode 100644 index b1a5146..0000000 --- a/boardesp/webserver.c +++ /dev/null @@ -1,380 +0,0 @@ -#include "stdlib.h" -#include "ets_sys.h" -#include "osapi.h" -#include "gpio.h" -#include "mem.h" -#include "os_type.h" -#include "user_interface.h" -#include "espconn.h" -#include "upgrade.h" - -#include "crypto/rsa.h" -#include "crypto/sha.h" - -#include "obj/gitversion.h" -#include "obj/cert.h" - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define espconn_send_string(conn, x) espconn_send(conn, x, strlen(x)) - -#define MAX_RESP 0x800 -char resp[MAX_RESP]; -char pageheader[] = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n" -"\n" -"\n" -"\n" -"Panda\n" -"\n" -"\n" -"
This is your comma.ai panda\n\n"
-"It's open source. Find the code here\n";
-
-char pagefooter[] = "
\n" -"\n" -"\n"; - -char OK_header[] = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n"; - -static struct espconn web_conn; -static esp_tcp web_proto; -extern char ssid[]; -extern int wifi_secure_mode; - -char *st_firmware; -int real_content_length, content_length = 0; -char *st_firmware_ptr; -LOCAL os_timer_t ota_reboot_timer; - -#define FIRMWARE_SIZE 503808 - -typedef struct { - uint16_t ep; - uint16_t extra_len; - union { - struct { - uint8_t request_type; - uint8_t request; - uint16_t value; - uint16_t index; - uint16_t length; - } control; - uint8_t data[0x10]; - } u; -} usb_msg; - -int ICACHE_FLASH_ATTR usb_cmd(int ep, int len, int request, - int value, int index, char *data) { - usb_msg usb = {0}; - - usb.ep = ep; - usb.extra_len = (ep == 0) ? 0 : len; - if (ep == 0) { - usb.u.control.request_type = 0xc0; - usb.u.control.request = request; - usb.u.control.value = value; - usb.u.control.index = index; - } else { - memcpy(&usb.u.data, data, usb.extra_len); - } - - uint32_t recv[0x44/4]; - spi_comm(&usb, sizeof(usb), recv, 0x40); - - return recv[0]; -} - - -void ICACHE_FLASH_ATTR st_flash() { - if (st_firmware != NULL) { - // boot mode - os_printf("st_flash: enter boot mode\n"); - st_set_boot_mode(1); - - // echo - os_printf("st_flash: wait for echo\n"); - for (int i = 0; i < 10; i++) { - os_printf(" attempt: %d\n", i); - if (usb_cmd(0, 0, 0xb0, 0, 0, NULL) > 0) break; - } - - // unlock flash - os_printf("st_flash: unlock flash\n"); - usb_cmd(0, 0, 0xb1, 0, 0, NULL); - - // erase sector 1 - os_printf("st_flash: erase sector 1\n"); - usb_cmd(0, 0, 0xb2, 1, 0, NULL); - - if (real_content_length >= 16384) { - // erase sector 2 - os_printf("st_flash: erase sector 2\n"); - usb_cmd(0, 0, 0xb2, 2, 0, NULL); - } - - // real content length will always be 0x10 aligned - os_printf("st_flash: flashing\n"); - for (int i = 0; i < real_content_length; i += 0x10) { - int rl = MIN(0x10, real_content_length-i); - usb_cmd(2, rl, 0, 0, 0, &st_firmware[i]); - system_soft_wdt_feed(); - } - - // reboot into normal mode - os_printf("st_flash: rebooting\n"); - usb_cmd(0, 0, 0xd8, 0, 0, NULL); - - // done with this - os_free(st_firmware); - st_firmware = NULL; - } -} - -typedef enum { - NOT_STARTED, - CONNECTION_ESTABLISHED, - RECEIVING_HEADER, - RECEIVING_ST_FIRMWARE, - RECEIVING_ESP_FIRMWARE, - REBOOTING, - ERROR -} web_state_t; - -web_state_t state = NOT_STARTED; -int esp_address, esp_address_erase_limit, start_address; - -void ICACHE_FLASH_ATTR hexdump(char *data, int len) { - int i; - for (i=0;isecure it"); - } - - ets_strcat(resp,"\nSet USB Mode:" - "" - "" - "\n"); - - ets_strcat(resp, pagefooter); - - espconn_send_string(&web_conn, resp); - espconn_disconnect(conn); - } else if (memcmp(data, "GET /secure", 11) == 0 && !wifi_secure_mode) { - wifi_configure(1); - } else if (memcmp(data, "GET /set_property?usb_mode=", 27) == 0 && wifi_secure_mode) { - char mode_value = data[27] - '0'; - if (mode_value >= '\x00' && mode_value <= '\x02') { - memset(resp, 0, MAX_RESP); - char set_usb_mode_packet[] = "\x00\x00\x00\x00\x40\xE6\x00\x00\x00\x00\x40\x00"; - set_usb_mode_packet[6] = mode_value; - uint32_t recvData[1]; - spi_comm(set_usb_mode_packet, 0xC, recvData, 0); - os_sprintf(resp, "%sUSB Mode set to %02x\n\n", OK_header, mode_value); - espconn_send_string(&web_conn, resp); - espconn_disconnect(conn); - } - } else if (memcmp(data, "PUT /stupdate ", 14) == 0 && wifi_secure_mode) { - os_printf("init st firmware\n"); - char *cl = strstr(data, "Content-Length: "); - if (cl != NULL) { - // get content length - cl += strlen("Content-Length: "); - content_length = skip_atoi(&cl); - os_printf("with content length %d\n", content_length); - - // should be small enough to fit in RAM - real_content_length = (content_length+0xF)&(~0xF); - st_firmware_ptr = st_firmware = os_malloc(real_content_length); - memset(st_firmware, 0, real_content_length); - state = RECEIVING_ST_FIRMWARE; - } - - } else if (((memcmp(data, "PUT /espupdate1 ", 16) == 0) || - (memcmp(data, "PUT /espupdate2 ", 16) == 0)) && wifi_secure_mode) { - // 0x1000 = user1.bin - // 0x81000 = user2.bin - // 0x3FE000 = blank.bin - os_printf("init esp firmware\n"); - char *cl = strstr(data, "Content-Length: "); - if (cl != NULL) { - // get content length - cl += strlen("Content-Length: "); - content_length = skip_atoi(&cl); - os_printf("with content length %d\n", content_length); - - // setup flashing - uint8_t current = system_upgrade_userbin_check(); - if (data[14] == '2' && current == UPGRADE_FW_BIN1) { - os_printf("flashing boot2.bin\n"); - state = RECEIVING_ESP_FIRMWARE; - esp_address = 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; - } else if (data[14] == '1' && current == UPGRADE_FW_BIN2) { - os_printf("flashing boot1.bin\n"); - state = RECEIVING_ESP_FIRMWARE; - esp_address = 4*1024; - } else { - espconn_send_string(&web_conn, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\nwrong!\n"); - espconn_disconnect(conn); - } - esp_address_erase_limit = esp_address; - start_address = esp_address; - } - } else { - espconn_send_string(&web_conn, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n404 Not Found!\n"); - espconn_disconnect(conn); - } - } else if (state == RECEIVING_ST_FIRMWARE) { - os_printf("receiving st firmware: %d/%d\n", len, content_length); - memcpy(st_firmware_ptr, data, MIN(content_length, len)); - st_firmware_ptr += len; - content_length -= len; - - if (content_length <= 0 && real_content_length > 1000) { - state = NOT_STARTED; - os_printf("done!\n"); - espconn_send_string(&web_conn, "HTTP/1.0 200 OK\nContent-Type: text/html\n\nsuccess!\n"); - espconn_disconnect(conn); - - // reboot - os_printf("Scheduling st_flash in 100ms.\n"); - os_timer_disarm(&ota_reboot_timer); - os_timer_setfn(&ota_reboot_timer, (os_timer_func_t *)st_flash, NULL); - os_timer_arm(&ota_reboot_timer, 100, 0); - } - } else if (state == RECEIVING_ESP_FIRMWARE) { - if ((esp_address+len) < (start_address + FIRMWARE_SIZE)) { - os_printf("receiving esp firmware: %d/%d -- 0x%x - 0x%x\n", len, content_length, - esp_address, esp_address_erase_limit); - content_length -= len; - while (esp_address_erase_limit < (esp_address + len)) { - os_printf("erasing 0x%X\n", esp_address_erase_limit); - spi_flash_erase_sector(esp_address_erase_limit / SPI_FLASH_SEC_SIZE); - esp_address_erase_limit += SPI_FLASH_SEC_SIZE; - } - SpiFlashOpResult res = spi_flash_write(esp_address, data, len); - if (res != SPI_FLASH_RESULT_OK) { - os_printf("flash fail @ 0x%x\n", esp_address); - } - esp_address += len; - - if (content_length == 0) { - - char digest[SHA_DIGEST_SIZE]; - uint32_t rsa[RSANUMBYTES/4]; - uint32_t dat[0x80/4]; - int ll; - spi_flash_read(esp_address-RSANUMBYTES, rsa, RSANUMBYTES); - - // 32-bit aligned accesses only - SHA_CTX ctx; - SHA_init(&ctx); - for (ll = start_address; ll < esp_address-RSANUMBYTES; ll += 0x80) { - spi_flash_read(ll, dat, 0x80); - SHA_update(&ctx, dat, MIN((esp_address-RSANUMBYTES)-ll, 0x80)); - } - memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); - - if (RSA_verify(&releaseesp_rsa_key, rsa, RSANUMBYTES, digest, SHA_DIGEST_SIZE) || - #ifdef ALLOW_DEBUG - RSA_verify(&debugesp_rsa_key, rsa, RSANUMBYTES, digest, SHA_DIGEST_SIZE) - #else - false - #endif - ) { - os_printf("RSA verify success!\n"); - espconn_send_string(&web_conn, "HTTP/1.0 200 OK\nContent-Type: text/html\n\nsuccess!\n"); - system_upgrade_flag_set(UPGRADE_FLAG_FINISH); - - // reboot - os_printf("Scheduling reboot.\n"); - os_timer_disarm(&ota_reboot_timer); - os_timer_setfn(&ota_reboot_timer, (os_timer_func_t *)system_upgrade_reboot, NULL); - os_timer_arm(&ota_reboot_timer, 2000, 0); - } else { - os_printf("RSA verify FAILURE\n"); - espconn_send_string(&web_conn, "HTTP/1.0 500 Internal Server Error\nContent-Type: text/html\n\nrsa verify fail\n"); - } - espconn_disconnect(conn); - } - } - } -} - -void ICACHE_FLASH_ATTR web_tcp_connect_cb(void *arg) { - state = CONNECTION_ESTABLISHED; - struct espconn *conn = (struct espconn *)arg; - espconn_set_opt(&web_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(conn, web_rx_cb); -} - -void ICACHE_FLASH_ATTR web_init() { - web_proto.local_port = 80; - web_conn.type = ESPCONN_TCP; - web_conn.state = ESPCONN_NONE; - web_conn.proto.tcp = &web_proto; - espconn_regist_connectcb(&web_conn, web_tcp_connect_cb); - espconn_accept(&web_conn); -} - diff --git a/certs/debugesp b/certs/debugesp deleted file mode 100644 index 789beaa..0000000 --- a/certs/debugesp +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5E -LQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA6 -6f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9QIDAQAB -AoGADaUn+HRef9BaWMvd4G6uMHI54cwJYbj8NpDfKjExQqnuw5bqWnWRQmiSnwbJ -DC7kj3zE/LBAuj890ot3q1CAWqh47ZICZfoX9Qbi5TpvIHFCGy6YkOliF6iIQhR2 -4+zNKTAA0zNKskOM25PdI+grK1Ni/bEofSA6TrqvEwsmxnkCQQDVp9FUUor2Bo/h -/3oAIP51LTw7vfpztYbJr+BDV63czV2DLXzSwzeNrwH4sA3oy1mjUgMBBgAarNGE -DYlc4H5jAkEAw3UCHzzXPlxkw2QGp7nBly5y3p80Uqc31NuYz8rdX/U8KTngi2No -Ft/SGCEXNpeYbToj+WK3RJJ2Ey0mK8+IxwJAcpGd/5CPsaQNLcw4WK9Yo+8Q2Jxk -G/4gfDCSmqn+smNxnLEcuUwzkwdgkEGgA9BfjeOhdsAH+EXpx90WZrZ/LwJBAK0k -jq+rTqUQZbZsejTEKYjJ/bnV4BzDwoKN0Q1pkLc7X4LJoW74rTFuLgdv8MdMfRtt -IIb/eoeFEpGkMicnHesCQHgR7BTUGBM6Uxam7RCdsgVsxoHBma21E/44ivWUMZzN -3oVt0mPnjS4speOlqwED5pCJ7yw7jwLPFMs8kNxuIKU= ------END RSA PRIVATE KEY----- diff --git a/certs/debugesp.pub b/certs/debugesp.pub deleted file mode 100644 index 3afcf39..0000000 --- a/certs/debugesp.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5ELQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA66f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9Q== batman@y840 diff --git a/certs/releaseesp.pub b/certs/releaseesp.pub deleted file mode 100644 index 1d1d54b..0000000 --- a/certs/releaseesp.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDN4pVyGuJJSde1l3Fjay8qPxog09DsAJZtYPk+armoYO1L6YKReUTcMNyHQYZZMZFmhCdgjCgTIF2QYWMoP4KSe8l6JF04YPP51dIgefc6UXjtlSI8Pyutr0v9xXjSfsVm3RAJxDSHgzs9AoMsluKCL+LhAR1nd7cuHXITJ80O4w== batman@y840 diff --git a/docs/panda_wifi_setup.md b/docs/panda_wifi_setup.md deleted file mode 100644 index 4e9c80c..0000000 --- a/docs/panda_wifi_setup.md +++ /dev/null @@ -1,16 +0,0 @@ -# Connecting to White Panda via Wi-Fi - -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) - -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) - -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) - - ### If you need your White Panda's Wi-Fi Password - - * 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) - * Also ensure that you are connected to your White Panda's Wi-Fi pairing network - -4. Connect to your White Panda's default Wi-Fi network (this should be the Wi-Fi network WITHOUT the "-pair" at the end) - -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. \ No newline at end of file diff --git a/python/__init__.py b/python/__init__.py index 21b2fd5..d5d21c1 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -10,7 +10,6 @@ import traceback import subprocess import sys from .dfu import PandaDFU # pylint: disable=import-error -from .esptool import ESPROM, CesantaFlasher # noqa pylint: disable=import-error from .flash_release import flash_release # noqa pylint: disable=import-error from .update import ensure_st_up_to_date # noqa pylint: disable=import-error from .serial import PandaSerial # noqa pylint: disable=import-error diff --git a/python/esptool.py b/python/esptool.py deleted file mode 100755 index 4a7dabf..0000000 --- a/python/esptool.py +++ /dev/null @@ -1,1317 +0,0 @@ -#!/usr/bin/env python -# NB: Before sending a PR to change the above line to '#!/usr/bin/env python3', please read https://github.com/themadinventor/esptool/issues/21 -# -# ESP8266 ROM Bootloader Utility -# https://github.com/themadinventor/esptool -# -# Copyright (C) 2014-2016 Fredrik Ahlberg, Angus Gratton, other contributors as noted. -# -# This program is free software; you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation; either version 2 of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin -# Street, Fifth Floor, Boston, MA 02110-1301 USA. - -# pylint: skip-file -# flake8: noqa - -import argparse -import hashlib -import inspect -import json -import os -#import serial -import struct -import subprocess -import sys -import tempfile -import time -#import traceback -import usb1 - -__version__ = "1.2" - -class FakePort(object): - def __init__(self, serial=None): - from panda import Panda - self.panda = Panda(serial) - - # will only work on new st, old ones will stay @ 921600 - self.baudrate = 230400 - - @property - def baudrate(self): - return self.baudrate - - @baudrate.setter - def baudrate(self, x): - print("set baud to", x) - self.panda.set_uart_baud(1, x) - - def write(self, buf): - SEND_STEP = 0x20 - for i in range(0, len(buf), SEND_STEP): - self.panda.serial_write(1, buf[i:i+SEND_STEP]) - - def flushInput(self): - self.panda.serial_clear(1) - - def flushOutput(self): - self.panda.serial_clear(1) - - def read(self, llen): - ret = self.panda._handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xe0, 1, 0, 1) - if ret == '': - time.sleep(0.1) - ret = self.panda._handle.controlRead(usb1.TYPE_VENDOR | usb1.RECIPIENT_DEVICE, 0xe0, 1, 0, 1) - return str(ret) - - def reset(self): - self.panda.esp_reset(1) - - def inWaiting(self): - return False - -class ESPROM(object): - # These are the currently known commands supported by the ROM - ESP_FLASH_BEGIN = 0x02 - ESP_FLASH_DATA = 0x03 - ESP_FLASH_END = 0x04 - ESP_MEM_BEGIN = 0x05 - ESP_MEM_END = 0x06 - ESP_MEM_DATA = 0x07 - ESP_SYNC = 0x08 - ESP_WRITE_REG = 0x09 - ESP_READ_REG = 0x0a - - # Maximum block sized for RAM and Flash writes, respectively. - ESP_RAM_BLOCK = 0x1800 - ESP_FLASH_BLOCK = 0x400 - - # Default baudrate. The ROM auto-bauds, so we can use more or less whatever we want. - ESP_ROM_BAUD = 115200 - - # First byte of the application image - ESP_IMAGE_MAGIC = 0xe9 - - # Initial state for the checksum routine - ESP_CHECKSUM_MAGIC = 0xef - - # OTP ROM addresses - ESP_OTP_MAC0 = 0x3ff00050 - ESP_OTP_MAC1 = 0x3ff00054 - ESP_OTP_MAC3 = 0x3ff0005c - - # Flash sector size, minimum unit of erase. - ESP_FLASH_SECTOR = 0x1000 - - def __init__(self, port=None, baud=ESP_ROM_BAUD): - self._port = FakePort(port) - self._slip_reader = slip_reader(self._port) - - """ Read a SLIP packet from the serial port """ - def read(self): - return next(self._slip_reader) - - """ Write bytes to the serial port while performing SLIP escaping """ - def write(self, packet): - buf = '\xc0' \ - + (packet.replace('\xdb','\xdb\xdd').replace('\xc0','\xdb\xdc')) \ - + '\xc0' - self._port.write(buf) - - """ Calculate checksum of a blob, as it is defined by the ROM """ - @staticmethod - def checksum(data, state=ESP_CHECKSUM_MAGIC): - for b in data: - state ^= ord(b) - return state - - """ Send a request and read the response """ - def command(self, op=None, data=None, chk=0): - if op is not None: - pkt = struct.pack('> 16) & 0xff, (mac3 >> 8) & 0xff, mac3 & 0xff) - elif ((mac1 >> 16) & 0xff) == 0: - oui = (0x18, 0xfe, 0x34) - elif ((mac1 >> 16) & 0xff) == 1: - oui = (0xac, 0xd0, 0x74) - else: - raise FatalError("Unknown OUI") - return oui + ((mac1 >> 8) & 0xff, mac1 & 0xff, (mac0 >> 24) & 0xff) - - """ Read Chip ID from OTP ROM - see http://esp8266-re.foogod.com/wiki/System_get_chip_id_%28IoT_RTOS_SDK_0.9.9%29 """ - def chip_id(self): - id0 = self.read_reg(self.ESP_OTP_MAC0) - id1 = self.read_reg(self.ESP_OTP_MAC1) - return (id0 >> 24) | ((id1 & 0xffffff) << 8) - - """ Read SPI flash manufacturer and device id """ - def flash_id(self): - self.flash_begin(0, 0) - self.write_reg(0x60000240, 0x0, 0xffffffff) - self.write_reg(0x60000200, 0x10000000, 0xffffffff) - flash_id = self.read_reg(0x60000240) - return flash_id - - """ Abuse the loader protocol to force flash to be left in write mode """ - def flash_unlock_dio(self): - # Enable flash write mode - self.flash_begin(0, 0) - # Reset the chip rather than call flash_finish(), which would have - # write protected the chip again (why oh why does it do that?!) - self.mem_begin(0,0,0,0x40100000) - self.mem_finish(0x40000080) - - """ Perform a chip erase of SPI flash """ - def flash_erase(self): - # Trick ROM to initialize SFlash - self.flash_begin(0, 0) - - # This is hacky: we don't have a custom stub, instead we trick - # the bootloader to jump to the SPIEraseChip() routine and then halt/crash - # when it tries to boot an unconfigured system. - self.mem_begin(0,0,0,0x40100000) - self.mem_finish(0x40004984) - - # Yup - there's no good way to detect if we succeeded. - # It it on the other hand unlikely to fail. - - def run_stub(self, stub, params, read_output=True): - stub = dict(stub) - stub['code'] = unhexify(stub['code']) - if 'data' in stub: - stub['data'] = unhexify(stub['data']) - - if stub['num_params'] != len(params): - raise FatalError('Stub requires %d params, %d provided' - % (stub['num_params'], len(params))) - - params = struct.pack('<' + ('I' * stub['num_params']), *params) - pc = params + stub['code'] - - # Upload - self.mem_begin(len(pc), 1, len(pc), stub['params_start']) - self.mem_block(pc, 0) - if 'data' in stub: - self.mem_begin(len(stub['data']), 1, len(stub['data']), stub['data_start']) - self.mem_block(stub['data'], 0) - self.mem_finish(stub['entry']) - - if read_output: - print('Stub executed, reading response:') - while True: - p = self.read() - print(hexify(p)) - if p == '': - return - - -class ESPBOOTLOADER(object): - """ These are constants related to software ESP bootloader, working with 'v2' image files """ - - # First byte of the "v2" application image - IMAGE_V2_MAGIC = 0xea - - # First 'segment' value in a "v2" application image, appears to be a constant version value? - IMAGE_V2_SEGMENT = 4 - - -def LoadFirmwareImage(filename): - """ Load a firmware image, without knowing what kind of file (v1 or v2) it is. - - Returns a BaseFirmwareImage subclass, either ESPFirmwareImage (v1) or OTAFirmwareImage (v2). - """ - with open(filename, 'rb') as f: - magic = ord(f.read(1)) - f.seek(0) - if magic == ESPROM.ESP_IMAGE_MAGIC: - return ESPFirmwareImage(f) - elif magic == ESPBOOTLOADER.IMAGE_V2_MAGIC: - return OTAFirmwareImage(f) - else: - raise FatalError("Invalid image magic number: %d" % magic) - - -class BaseFirmwareImage(object): - """ Base class with common firmware image functions """ - def __init__(self): - self.segments = [] - self.entrypoint = 0 - - def add_segment(self, addr, data, pad_to=4): - """ Add a segment to the image, with specified address & data - (padded to a boundary of pad_to size) """ - # Data should be aligned on word boundary - l = len(data) - if l % pad_to: - data += b"\x00" * (pad_to - l % pad_to) - if l > 0: - self.segments.append((addr, len(data), data)) - - def load_segment(self, f, is_irom_segment=False): - """ Load the next segment from the image file """ - (offset, size) = struct.unpack(' 0x40200000 or offset < 0x3ffe0000 or size > 65536: - raise FatalError('Suspicious segment 0x%x, length %d' % (offset, size)) - segment_data = f.read(size) - if len(segment_data) < size: - raise FatalError('End of file reading segment 0x%x, length %d (actual length %d)' % (offset, size, len(segment_data))) - segment = (offset, size, segment_data) - self.segments.append(segment) - return segment - - def save_segment(self, f, segment, checksum=None): - """ Save the next segment to the image file, return next checksum value if provided """ - (offset, size, data) = segment - f.write(struct.pack(' 16: - raise FatalError('Invalid firmware image magic=%d segments=%d' % (magic, segments)) - - for i in range(segments): - self.load_segment(load_file) - self.checksum = self.read_checksum(load_file) - - def save(self, filename): - with open(filename, 'wb') as f: - self.write_v1_header(f, self.segments) - checksum = ESPROM.ESP_CHECKSUM_MAGIC - for segment in self.segments: - checksum = self.save_segment(f, segment, checksum) - self.append_checksum(f, checksum) - - -class OTAFirmwareImage(BaseFirmwareImage): - """ 'Version 2' firmware image, segments loaded by software bootloader stub - (ie Espressif bootloader or rboot) - """ - def __init__(self, load_file=None): - super(OTAFirmwareImage, self).__init__() - self.version = 2 - if load_file is not None: - (magic, segments, first_flash_mode, first_flash_size_freq, first_entrypoint) = struct.unpack(' 16: - raise FatalError('Invalid V2 second header magic=%d segments=%d' % (magic, segments)) - - # load all the usual segments - for _ in range(segments): - self.load_segment(load_file) - self.checksum = self.read_checksum(load_file) - - def save(self, filename): - with open(filename, 'wb') as f: - # Save first header for irom0 segment - f.write(struct.pack(' 0: - esp._port.baudrate = baud_rate - # Read the greeting. - p = esp.read() - if p != 'OHAI': - raise FatalError('Failed to connect to the flasher (got %s)' % hexify(p)) - - def flash_write(self, addr, data, show_progress=False): - assert addr % self._esp.ESP_FLASH_SECTOR == 0, 'Address must be sector-aligned' - assert len(data) % self._esp.ESP_FLASH_SECTOR == 0, 'Length must be sector-aligned' - sys.stdout.write('Writing %d @ 0x%x... ' % (len(data), addr)) - sys.stdout.flush() - self._esp.write(struct.pack(' length: - raise FatalError('Read more than expected') - p = self._esp.read() - if len(p) != 16: - raise FatalError('Expected digest, got: %s' % hexify(p)) - expected_digest = hexify(p).upper() - digest = hashlib.md5(data).hexdigest().upper() - print() - if digest != expected_digest: - raise FatalError('Digest mismatch: expected %s, got %s' % (expected_digest, digest)) - p = self._esp.read() - if len(p) != 1: - raise FatalError('Expected status, got: %s' % hexify(p)) - status_code = struct.unpack(', ) or a single -# argument. - -def load_ram(esp, args): - image = LoadFirmwareImage(args.filename) - - print('RAM boot...') - for (offset, size, data) in image.segments: - print('Downloading %d bytes at %08x...' % (size, offset), end=' ') - sys.stdout.flush() - esp.mem_begin(size, div_roundup(size, esp.ESP_RAM_BLOCK), esp.ESP_RAM_BLOCK, offset) - - seq = 0 - while len(data) > 0: - esp.mem_block(data[0:esp.ESP_RAM_BLOCK], seq) - data = data[esp.ESP_RAM_BLOCK:] - seq += 1 - print('done!') - - print('All segments done, executing at %08x' % image.entrypoint) - esp.mem_finish(image.entrypoint) - - -def read_mem(esp, args): - print('0x%08x = 0x%08x' % (args.address, esp.read_reg(args.address))) - - -def write_mem(esp, args): - esp.write_reg(args.address, args.value, args.mask, 0) - print('Wrote %08x, mask %08x to %08x' % (args.value, args.mask, args.address)) - - -def dump_mem(esp, args): - f = open(args.filename, 'wb') - for i in range(args.size / 4): - d = esp.read_reg(args.address + (i * 4)) - f.write(struct.pack('> 16 - args.flash_size = {18: '2m', 19: '4m', 20: '8m', 21: '16m', 22: '32m'}.get(size_id) - if args.flash_size is None: - print('Warning: Could not auto-detect Flash size (FlashID=0x%x, SizeID=0x%x), defaulting to 4m' % (flash_id, size_id)) - args.flash_size = '4m' - else: - print('Auto-detected Flash size:', args.flash_size) - - -def write_flash(esp, args): - detect_flash_size(esp, args) - flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode] - flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40, '16m-c1': 0x50, '32m-c1':0x60, '32m-c2':0x70}[args.flash_size] - flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq] - flash_params = struct.pack('BB', flash_mode, flash_size_freq) - - flasher = CesantaFlasher(esp, args.baud) - - for address, argfile in args.addr_filename: - image = argfile.read() - argfile.seek(0) # rewind in case we need it again - if address + len(image) > int(args.flash_size.split('m')[0]) * (1 << 17): - print('WARNING: Unlikely to work as data goes beyond end of flash. Hint: Use --flash_size') - # Fix sflash config data. - if address == 0 and image[0] == '\xe9': - print('Flash params set to 0x%02x%02x' % (flash_mode, flash_size_freq)) - image = image[0:2] + flash_params + image[4:] - # Pad to sector size, which is the minimum unit of writing (erasing really). - if len(image) % esp.ESP_FLASH_SECTOR != 0: - image += '\xff' * (esp.ESP_FLASH_SECTOR - (len(image) % esp.ESP_FLASH_SECTOR)) - t = time.time() - flasher.flash_write(address, image, not args.no_progress) - t = time.time() - t - print('\rWrote %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...' - % (len(image), address, t, len(image) / t * 8 / 1000)) - print('Leaving...') - if args.verify: - print('Verifying just-written flash...') - _verify_flash(flasher, args, flash_params) - flasher.boot_fw() - - -def image_info(args): - image = LoadFirmwareImage(args.filename) - print('Image version: %d' % image.version) - print(('Entry point: %08x' % image.entrypoint) if image.entrypoint != 0 else 'Entry point not set') - print('%d segments' % len(image.segments)) - print() - checksum = ESPROM.ESP_CHECKSUM_MAGIC - for (idx, (offset, size, data)) in enumerate(image.segments): - if image.version == 2 and idx == 0: - print('Segment 1: %d bytes IROM0 (no load address)' % size) - else: - print('Segment %d: %5d bytes at %08x' % (idx + 1, size, offset)) - checksum = ESPROM.checksum(data, checksum) - print() - print('Checksum: %02x (%s)' % (image.checksum, 'valid' if image.checksum == checksum else 'invalid!')) - - -def make_image(args): - image = ESPFirmwareImage() - if len(args.segfile) == 0: - raise FatalError('No segments specified') - if len(args.segfile) != len(args.segaddr): - raise FatalError('Number of specified files does not match number of specified addresses') - for (seg, addr) in zip(args.segfile, args.segaddr): - data = open(seg, 'rb').read() - image.add_segment(addr, data) - image.entrypoint = args.entrypoint - image.save(args.output) - - -def elf2image(args): - e = ELFFile(args.input) - if args.version == '1': - image = ESPFirmwareImage() - else: - image = OTAFirmwareImage() - irom_data = e.load_section('.irom0.text') - if len(irom_data) == 0: - raise FatalError(".irom0.text section not found in ELF file - can't create V2 image.") - image.add_segment(0, irom_data, 16) - image.entrypoint = e.get_entry_point() - for section, start in ((".text", "_text_start"), (".data", "_data_start"), (".rodata", "_rodata_start")): - data = e.load_section(section) - image.add_segment(e.get_symbol_addr(start), data) - - image.flash_mode = {'qio':0, 'qout':1, 'dio':2, 'dout': 3}[args.flash_mode] - image.flash_size_freq = {'4m':0x00, '2m':0x10, '8m':0x20, '16m':0x30, '32m':0x40, '16m-c1': 0x50, '32m-c1':0x60, '32m-c2':0x70}[args.flash_size] - image.flash_size_freq += {'40m':0, '26m':1, '20m':2, '80m': 0xf}[args.flash_freq] - - irom_offs = e.get_symbol_addr("_irom0_text_start") - 0x40200000 - - if args.version == '1': - if args.output is None: - args.output = args.input + '-' - image.save(args.output + "0x00000.bin") - data = e.load_section(".irom0.text") - if irom_offs < 0: - raise FatalError('Address of symbol _irom0_text_start in ELF is located before flash mapping address. Bad linker script?') - if (irom_offs & 0xFFF) != 0: # irom0 isn't flash sector aligned - print("WARNING: irom0 section offset is 0x%08x. ELF is probably linked for 'elf2image --version=2'" % irom_offs) - with open(args.output + "0x%05x.bin" % irom_offs, "wb") as f: - f.write(data) - f.close() - else: # V2 OTA image - if args.output is None: - args.output = "%s-0x%05x.bin" % (os.path.splitext(args.input)[0], irom_offs & ~(ESPROM.ESP_FLASH_SECTOR - 1)) - image.save(args.output) - - -def read_mac(esp, args): - mac = esp.read_mac() - print('MAC: %s' % ':'.join(['%02x' % x for x in mac])) - - -def chip_id(esp, args): - chipid = esp.chip_id() - print('Chip ID: 0x%08x' % chipid) - - -def erase_flash(esp, args): - flasher = CesantaFlasher(esp, args.baud) - print('Erasing flash (this may take a while)...') - t = time.time() - flasher.flash_erase_chip() - t = time.time() - t - print('Erase took %.1f seconds' % t) - - -def run(esp, args): - esp.run() - - -def flash_id(esp, args): - flash_id = esp.flash_id() - esp.flash_finish(False) - print('Manufacturer: %02x' % (flash_id & 0xff)) - print('Device: %02x%02x' % ((flash_id >> 8) & 0xff, (flash_id >> 16) & 0xff)) - - -def read_flash(esp, args): - flasher = CesantaFlasher(esp, args.baud) - t = time.time() - data = flasher.flash_read(args.address, args.size, not args.no_progress) - t = time.time() - t - print('\rRead %d bytes at 0x%x in %.1f seconds (%.1f kbit/s)...' - % (len(data), args.address, t, len(data) / t * 8 / 1000)) - open(args.filename, 'wb').write(data) - - -def _verify_flash(flasher, args, flash_params=None): - differences = False - for address, argfile in args.addr_filename: - image = argfile.read() - argfile.seek(0) # rewind in case we need it again - if address == 0 and image[0] == '\xe9' and flash_params is not None: - image = image[0:2] + flash_params + image[4:] - image_size = len(image) - print('Verifying 0x%x (%d) bytes @ 0x%08x in flash against %s...' % (image_size, image_size, address, argfile.name)) - # Try digest first, only read if there are differences. - digest, _ = flasher.flash_digest(address, image_size) - digest = hexify(digest).upper() - expected_digest = hashlib.md5(image).hexdigest().upper() - if digest == expected_digest: - print('-- verify OK (digest matched)') - continue - else: - differences = True - if getattr(args, 'diff', 'no') != 'yes': - print('-- verify FAILED (digest mismatch)') - continue - - flash = flasher.flash_read(address, image_size) - assert flash != image - diff = [i for i in range(image_size) if flash[i] != image[i]] - print('-- verify FAILED: %d differences, first @ 0x%08x' % (len(diff), address + diff[0])) - for d in diff: - print(' %08x %02x %02x' % (address + d, ord(flash[d]), ord(image[d]))) - if differences: - raise FatalError("Verify failed.") - - -def verify_flash(esp, args, flash_params=None): - flasher = CesantaFlasher(esp) - _verify_flash(flasher, args, flash_params) - - -def version(args): - print(__version__) - -# -# End of operations functions -# - - -def main(): - parser = argparse.ArgumentParser(description='esptool.py v%s - ESP8266 ROM Bootloader Utility' % __version__, prog='esptool') - - parser.add_argument( - '--port', '-p', - help='Serial port device', - default=os.environ.get('ESPTOOL_PORT', None)) - - parser.add_argument( - '--baud', '-b', - help='Serial port baud rate used when flashing/reading', - type=arg_auto_int, - default=os.environ.get('ESPTOOL_BAUD', ESPROM.ESP_ROM_BAUD)) - - subparsers = parser.add_subparsers( - dest='operation', - help='Run esptool {command} -h for additional help') - - parser_load_ram = subparsers.add_parser( - 'load_ram', - help='Download an image to RAM and execute') - parser_load_ram.add_argument('filename', help='Firmware image') - - parser_dump_mem = subparsers.add_parser( - 'dump_mem', - help='Dump arbitrary memory to disk') - parser_dump_mem.add_argument('address', help='Base address', type=arg_auto_int) - parser_dump_mem.add_argument('size', help='Size of region to dump', type=arg_auto_int) - parser_dump_mem.add_argument('filename', help='Name of binary dump') - - parser_read_mem = subparsers.add_parser( - 'read_mem', - help='Read arbitrary memory location') - parser_read_mem.add_argument('address', help='Address to read', type=arg_auto_int) - - parser_write_mem = subparsers.add_parser( - 'write_mem', - help='Read-modify-write to arbitrary memory location') - parser_write_mem.add_argument('address', help='Address to write', type=arg_auto_int) - parser_write_mem.add_argument('value', help='Value', type=arg_auto_int) - parser_write_mem.add_argument('mask', help='Mask of bits to write', type=arg_auto_int) - - def add_spi_flash_subparsers(parent, auto_detect=False): - """ Add common parser arguments for SPI flash properties """ - parent.add_argument('--flash_freq', '-ff', help='SPI Flash frequency', - choices=['40m', '26m', '20m', '80m'], - default=os.environ.get('ESPTOOL_FF', '40m')) - parent.add_argument('--flash_mode', '-fm', help='SPI Flash mode', - choices=['qio', 'qout', 'dio', 'dout'], - default=os.environ.get('ESPTOOL_FM', 'qio')) - choices = ['4m', '2m', '8m', '16m', '32m', '16m-c1', '32m-c1', '32m-c2'] - default = '4m' - if auto_detect: - default = 'detect' - choices.insert(0, 'detect') - parent.add_argument('--flash_size', '-fs', help='SPI Flash size in Mbit', type=str.lower, - choices=choices, - default=os.environ.get('ESPTOOL_FS', default)) - - parser_write_flash = subparsers.add_parser( - 'write_flash', - help='Write a binary blob to flash') - parser_write_flash.add_argument('addr_filename', metavar='
', help='Address followed by binary filename, separated by space', - action=AddrFilenamePairAction) - add_spi_flash_subparsers(parser_write_flash, auto_detect=True) - parser_write_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") - parser_write_flash.add_argument('--verify', help='Verify just-written data (only necessary if very cautious, data is already CRCed', action='store_true') - - subparsers.add_parser( - 'run', - help='Run application code in flash') - - parser_image_info = subparsers.add_parser( - 'image_info', - help='Dump headers from an application image') - parser_image_info.add_argument('filename', help='Image file to parse') - - parser_make_image = subparsers.add_parser( - 'make_image', - help='Create an application image from binary files') - parser_make_image.add_argument('output', help='Output image file') - parser_make_image.add_argument('--segfile', '-f', action='append', help='Segment input file') - parser_make_image.add_argument('--segaddr', '-a', action='append', help='Segment base address', type=arg_auto_int) - parser_make_image.add_argument('--entrypoint', '-e', help='Address of entry point', type=arg_auto_int, default=0) - - parser_elf2image = subparsers.add_parser( - 'elf2image', - help='Create an application image from ELF file') - parser_elf2image.add_argument('input', help='Input ELF file') - parser_elf2image.add_argument('--output', '-o', help='Output filename prefix (for version 1 image), or filename (for version 2 single image)', type=str) - parser_elf2image.add_argument('--version', '-e', help='Output image version', choices=['1','2'], default='1') - add_spi_flash_subparsers(parser_elf2image) - - subparsers.add_parser( - 'read_mac', - help='Read MAC address from OTP ROM') - - subparsers.add_parser( - 'chip_id', - help='Read Chip ID from OTP ROM') - - subparsers.add_parser( - 'flash_id', - help='Read SPI flash manufacturer and device ID') - - parser_read_flash = subparsers.add_parser( - 'read_flash', - help='Read SPI flash content') - parser_read_flash.add_argument('address', help='Start address', type=arg_auto_int) - parser_read_flash.add_argument('size', help='Size of region to dump', type=arg_auto_int) - parser_read_flash.add_argument('filename', help='Name of binary dump') - parser_read_flash.add_argument('--no-progress', '-p', help='Suppress progress output', action="store_true") - - parser_verify_flash = subparsers.add_parser( - 'verify_flash', - help='Verify a binary blob against flash') - parser_verify_flash.add_argument('addr_filename', help='Address and binary file to verify there, separated by space', - action=AddrFilenamePairAction) - parser_verify_flash.add_argument('--diff', '-d', help='Show differences', - choices=['no', 'yes'], default='no') - - subparsers.add_parser( - 'erase_flash', - help='Perform Chip Erase on SPI flash') - - subparsers.add_parser( - 'version', help='Print esptool version') - - # internal sanity check - every operation matches a module function of the same name - for operation in list(subparsers.choices.keys()): - assert operation in globals(), "%s should be a module function" % operation - - args = parser.parse_args() - - print('esptool.py v%s' % __version__) - - # operation function can take 1 arg (args), 2 args (esp, arg) - # or be a member function of the ESPROM class. - - operation_func = globals()[args.operation] - operation_args,_,_,_ = inspect.getargspec(operation_func) - if operation_args[0] == 'esp': # operation function takes an ESPROM connection object - initial_baud = min(ESPROM.ESP_ROM_BAUD, args.baud) # don't sync faster than the default baud rate - esp = ESPROM(args.port, initial_baud) - esp.connect() - operation_func(esp, args) - else: - operation_func(args) - - -class AddrFilenamePairAction(argparse.Action): - """ Custom parser class for the address/filename pairs passed as arguments """ - def __init__(self, option_strings, dest, nargs='+', **kwargs): - super(AddrFilenamePairAction, self).__init__(option_strings, dest, nargs, **kwargs) - - def __call__(self, parser, namespace, values, option_string=None): - # validate pair arguments - pairs = [] - for i in range(0,len(values),2): - try: - address = int(values[i],0) - except ValueError: - raise argparse.ArgumentError(self,'Address "%s" must be a number' % values[i]) - try: - argfile = open(values[i + 1], 'rb') - except IOError as e: - raise argparse.ArgumentError(self, e) - except IndexError: - raise argparse.ArgumentError(self,'Must be pairs of an address and the binary filename to write there') - pairs.append((address, argfile)) - setattr(namespace, self.dest, pairs) - -# This is "wrapped" stub_flasher.c, to be loaded using run_stub. -_CESANTA_FLASHER_STUB = """\ -{"code_start": 1074790404, "code": "080000601C000060000000601000006031FCFF71FCFF\ -81FCFFC02000680332D218C020004807404074DCC48608005823C0200098081BA5A9239245005803\ -1B555903582337350129230B446604DFC6F3FF21EEFFC0200069020DF0000000010078480040004A\ -0040B449004012C1F0C921D911E901DD0209312020B4ED033C2C56C2073020B43C3C56420701F5FF\ -C000003C4C569206CD0EEADD860300202C4101F1FFC0000056A204C2DCF0C02DC0CC6CCAE2D1EAFF\ -0606002030F456D3FD86FBFF00002020F501E8FFC00000EC82D0CCC0C02EC0C73DEB2ADC46030020\ -2C4101E1FFC00000DC42C2DCF0C02DC056BCFEC602003C5C8601003C6C4600003C7C08312D0CD811\ -C821E80112C1100DF0000C180000140010400C0000607418000064180000801800008C1800008418\ -0000881800009018000018980040880F0040A80F0040349800404C4A0040740F0040800F0040980F\ -00400099004012C1E091F5FFC961CD0221EFFFE941F9310971D9519011C01A223902E2D1180C0222\ -6E1D21E4FF31E9FF2AF11A332D0F42630001EAFFC00000C030B43C2256A31621E1FF1A2228022030\ -B43C3256B31501ADFFC00000DD023C4256ED1431D6FF4D010C52D90E192E126E0101DDFFC0000021\ -D2FF32A101C020004802303420C0200039022C0201D7FFC00000463300000031CDFF1A333803D023\ -C03199FF27B31ADC7F31CBFF1A3328030198FFC0000056C20E2193FF2ADD060E000031C6FF1A3328\ -030191FFC0000056820DD2DD10460800000021BEFF1A2228029CE231BCFFC020F51A33290331BBFF\ -C02C411A332903C0F0F4222E1D22D204273D9332A3FFC02000280E27B3F721ABFF381E1A2242A400\ -01B5FFC00000381E2D0C42A40001B3FFC0000056120801B2FFC00000C02000280EC2DC0422D2FCC0\ -2000290E01ADFFC00000222E1D22D204226E1D281E22D204E7B204291E860000126E012198FF32A0\ -042A21C54C003198FF222E1D1A33380337B202C6D6FF2C02019FFFC000002191FF318CFF1A223A31\ -019CFFC00000218DFF1C031A22C549000C02060300003C528601003C624600003C72918BFF9A1108\ -71C861D851E841F83112C1200DF00010000068100000581000007010000074100000781000007C10\ -0000801000001C4B0040803C004091FDFF12C1E061F7FFC961E941F9310971D9519011C01A662906\ -21F3FFC2D1101A22390231F2FF0C0F1A33590331EAFFF26C1AED045C2247B3028636002D0C016DFF\ -C0000021E5FF41EAFF2A611A4469040622000021E4FF1A222802F0D2C0D7BE01DD0E31E0FF4D0D1A\ -3328033D0101E2FFC00000561209D03D2010212001DFFFC000004D0D2D0C3D01015DFFC0000041D5\ -FFDAFF1A444804D0648041D2FF1A4462640061D1FF106680622600673F1331D0FF10338028030C43\ -853A002642164613000041CAFF222C1A1A444804202FC047328006F6FF222C1A273F3861C2FF222C\ -1A1A6668066732B921BDFF3D0C1022800148FFC0000021BAFF1C031A2201BFFFC000000C02460300\ -5C3206020000005C424600005C5291B7FF9A110871C861D851E841F83112C1200DF0B0100000C010\ -0000D010000012C1E091FEFFC961D951E9410971F931CD039011C0ED02DD0431A1FF9C1422A06247\ -B302062D0021F4FF1A22490286010021F1FF1A223902219CFF2AF12D0F011FFFC00000461C0022D1\ -10011CFFC0000021E9FFFD0C1A222802C7B20621E6FF1A22F8022D0E3D014D0F0195FFC000008C52\ -22A063C6180000218BFF3D01102280F04F200111FFC00000AC7D22D1103D014D0F010DFFC0000021\ -D6FF32D110102280010EFFC0000021D3FF1C031A220185FFC00000FAEEF0CCC056ACF821CDFF317A\ -FF1A223A310105FFC0000021C9FF1C031A22017CFFC000002D0C91C8FF9A110871C861D851E841F8\ -3112C1200DF0000200600000001040020060FFFFFF0012C1E00C02290131FAFF21FAFF026107C961\ -C02000226300C02000C80320CC10564CFF21F5FFC02000380221F4FF20231029010C432D010163FF\ -C0000008712D0CC86112C1200DF00080FE3F8449004012C1D0C9A109B17CFC22C1110C13C51C0026\ -1202463000220111C24110B68202462B0031F5FF3022A02802A002002D011C03851A0066820A2801\ -32210105A6FF0607003C12C60500000010212032A01085180066A20F2221003811482105B3FF2241\ -10861A004C1206FDFF2D011C03C5160066B20E280138114821583185CFFF06F7FF005C1286F5FF00\ -10212032A01085140066A20D2221003811482105E1FF06EFFF0022A06146EDFF45F0FFC6EBFF0000\ -01D2FFC0000006E9FF000C022241100C1322C110C50F00220111060600000022C1100C13C50E0022\ -011132C2FA303074B6230206C8FF08B1C8A112C1300DF0000000000010404F484149007519031027\ -000000110040A8100040BC0F0040583F0040CC2E00401CE20040D83900408000004021F4FF12C1E0\ -C961C80221F2FF097129010C02D951C91101F4FFC0000001F3FFC00000AC2C22A3E801F2FFC00000\ -21EAFFC031412A233D0C01EFFFC000003D0222A00001EDFFC00000C1E4FF2D0C01E8FFC000002D01\ -32A004450400C5E7FFDD022D0C01E3FFC00000666D1F4B2131DCFF4600004B22C0200048023794F5\ -31D9FFC0200039023DF08601000001DCFFC000000871C861D85112C1200DF000000012C1F0026103\ -01EAFEC00000083112C1100DF000643B004012C1D0E98109B1C9A1D991F97129013911E2A0C001FA\ -FFC00000CD02E792F40C0DE2A0C0F2A0DB860D00000001F4FFC00000204220E71240F7921C226102\ -01EFFFC0000052A0DC482157120952A0DD571205460500004D0C3801DA234242001BDD3811379DC5\ -C6000000000C0DC2A0C001E3FFC00000C792F608B12D0DC8A1D891E881F87112C1300DF00000", "\ -entry": 1074792180, "num_params": 1, "params_start": 1074790400, "data": "FE0510\ -401A0610403B0610405A0610407A061040820610408C0610408C061040", "data_start": 10736\ -43520} -""" - -if __name__ == '__main__': - try: - main() - except FatalError as e: - print('\nA fatal error occurred: %s' % e) - sys.exit(2) diff --git a/python/flash_release.py b/python/flash_release.py index 961a83a..f8862bd 100755 --- a/python/flash_release.py +++ b/python/flash_release.py @@ -7,7 +7,7 @@ import json import io def flash_release(path=None, st_serial=None): - from panda import Panda, PandaDFU, ESPROM, CesantaFlasher + from panda import Panda, PandaDFU from zipfile import ZipFile def status(x): @@ -43,9 +43,6 @@ def flash_release(path=None, st_serial=None): code_boot_15 = zf.read("boot_v1.5.bin") code_boot_15 = code_boot_15[0:2] + "\x00\x30" + code_boot_15[4:] - code_user1 = zf.read("user1.bin") - code_user2 = zf.read("user2.bin") - # enter DFU mode status("1. Entering DFU mode") panda = Panda(st_serial) @@ -64,29 +61,8 @@ def flash_release(path=None, st_serial=None): panda.flash(code=code_panda) panda.close() - # flashing ESP - if panda.is_white(): - status("4. Flashing ESP (slow!)") - - def align(x, sz=0x1000): - x + "\xFF" * ((sz - len(x)) % sz) - - esp = ESPROM(st_serial) - esp.connect() - flasher = CesantaFlasher(esp, 230400) - flasher.flash_write(0x0, align(code_boot_15), True) - flasher.flash_write(0x1000, align(code_user1), True) - flasher.flash_write(0x81000, align(code_user2), True) - flasher.flash_write(0x3FE000, "\xFF" * 0x1000) - flasher.boot_fw() - del flasher - del esp - time.sleep(1) - else: - status("4. No ESP in non-white panda") - # check for connection - status("5. Verifying version") + status("4. Verifying version") panda = Panda(st_serial) my_version = panda.get_version() print("dongle id: %s" % panda.get_serial()[0]) diff --git a/run_automated_tests.sh b/run_automated_tests.sh index e876c67..6bfdcf5 100755 --- a/run_automated_tests.sh +++ b/run_automated_tests.sh @@ -6,11 +6,7 @@ else TESTSUITE_NAME="Panda_Test-DEV" fi -if [ ! -z "${SKIPWIFI}" ] || [ -f "/EON" ]; then - TEST_SCRIPTS=$(ls tests/automated/$1*.py | grep -v wifi) -else - TEST_SCRIPTS=$(ls tests/automated/$1*.py) -fi +TEST_SCRIPTS=$(ls tests/automated/$1*.py) IFS=$'\n' for NAME in $(nmcli --fields NAME con show | grep panda | awk '{$1=$1};1') diff --git a/tests/all_wifi_test.py b/tests/all_wifi_test.py deleted file mode 100755 index b1ca79c..0000000 --- a/tests/all_wifi_test.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python3 -import requests -import json -from .automated.helpers import _connect_wifi # pylint: disable=import-error -from panda import Panda -from nose.tools import assert_equal - -if __name__ == "__main__": - print("Fetching latest firmware from github.com/commaai/panda-artifacts") - r = requests.get("https://raw.githubusercontent.com/commaai/panda-artifacts/master/latest.json") - latest_version = json.loads(r.text)['version'] - - for p in Panda.list(): - dongle_id, pw = Panda(p).get_serial() - print(dongle_id, pw) - assert(dongle_id.isalnum()) - _connect_wifi(dongle_id, pw) - - r = requests.get("http://192.168.0.10/") - print(r.text) - wifi_dongle_id = r.text.split("ssid: panda-")[1].split("
")[0] - st_version = r.text.split("st version:")[1].strip().split("
")[0] - esp_version = r.text.split("esp version:")[1].strip().split("
")[0] - - assert_equal(str(dongle_id), wifi_dongle_id) - assert_equal(latest_version, st_version) - assert_equal(latest_version, esp_version) diff --git a/tests/automated/7_can_loopback.py b/tests/automated/4_can_loopback.py similarity index 100% rename from tests/automated/7_can_loopback.py rename to tests/automated/4_can_loopback.py diff --git a/tests/automated/4_wifi.py b/tests/automated/4_wifi.py deleted file mode 100644 index 15b8dc6..0000000 --- a/tests/automated/4_wifi.py +++ /dev/null @@ -1,60 +0,0 @@ -import time -from panda import Panda -from .helpers import reset_pandas, connect_wifi, test_white, test_all_pandas, panda_type_to_serial, panda_connect_and_init -import requests - -# Reset the pandas before running tests -def aaaa_reset_before_tests(): - reset_pandas() - -@test_all_pandas -@panda_connect_and_init -def test_get_serial(p): - print(p.get_serial()) - -@test_all_pandas -@panda_connect_and_init -def test_get_serial_in_flash_mode(p): - p.reset(enter_bootstub=True) - assert(p.bootstub) - print(p.get_serial()) - p.reset() - -@test_white -@panda_type_to_serial -def test_connect_wifi(serials=None): - connect_wifi(serials[0]) - -@test_white -@panda_type_to_serial -def test_flash_wifi(serials=None): - connect_wifi(serials[0]) - assert Panda.flash_ota_wifi(release=False), "OTA Wifi Flash Failed" - connect_wifi(serials[0]) - -@test_white -@panda_type_to_serial -def test_wifi_flash_st(serials=None): - connect_wifi(serials[0]) - assert Panda.flash_ota_st(), "OTA ST Flash Failed" - connected = False - st = time.time() - while not connected and (time.time() - st) < 20: - try: - p = Panda(serial=serials[0]) - p.get_serial() - connected = True - except: - time.sleep(1) - - if not connected: - assert False, "Panda failed to connect on USB after flashing" - -@test_white -@panda_type_to_serial -def test_webpage_fetch(serials=None): - connect_wifi(serials[0]) - r = requests.get("http://192.168.0.10/") - print(r.text) - - assert "This is your comma.ai panda" in r.text diff --git a/tests/automated/8_gps.py b/tests/automated/5_gps.py similarity index 100% rename from tests/automated/8_gps.py rename to tests/automated/5_gps.py diff --git a/tests/automated/5_wifi_functionality.py b/tests/automated/5_wifi_functionality.py deleted file mode 100644 index f467400..0000000 --- a/tests/automated/5_wifi_functionality.py +++ /dev/null @@ -1,69 +0,0 @@ -import time -from panda import Panda -from .helpers import start_heartbeat_thread, reset_pandas, time_many_sends, connect_wifi, test_white, panda_type_to_serial - -# Reset the pandas before running tests -def aaaa_reset_before_tests(): - reset_pandas() - -@test_white -@panda_type_to_serial -def test_get_serial_wifi(serials=None): - connect_wifi(serials[0]) - - p = Panda("WIFI") - print(p.get_serial()) - -@test_white -@panda_type_to_serial -def test_throughput(serials=None): - connect_wifi(serials[0]) - p = Panda(serials[0]) - - # Start heartbeat - start_heartbeat_thread(p) - - # enable output mode - p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - - # enable CAN loopback mode - p.set_can_loopback(True) - - p = Panda("WIFI") - - for speed in [100, 250, 500, 750, 1000]: - # set bus 0 speed to speed - p.set_can_speed_kbps(0, speed) - time.sleep(0.1) - - comp_kbps = time_many_sends(p, 0) - - # bit count from https://en.wikipedia.org/wiki/CAN_bus - saturation_pct = (comp_kbps / speed) * 100.0 - #assert_greater(saturation_pct, 80) - #assert_less(saturation_pct, 100) - - print("WIFI loopback 100 messages at speed %d, comp speed is %.2f, percent %.2f" % (speed, comp_kbps, saturation_pct)) - -@test_white -@panda_type_to_serial -def test_recv_only(serials=None): - connect_wifi(serials[0]) - p = Panda(serials[0]) - - # Start heartbeat - start_heartbeat_thread(p) - - p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - - p.set_can_loopback(True) - pwifi = Panda("WIFI") - - # TODO: msg_count=1000 drops packets, is this fixable? - for msg_count in [10, 100, 200]: - speed = 500 - p.set_can_speed_kbps(0, speed) - comp_kbps = time_many_sends(p, 0, pwifi, msg_count) - saturation_pct = (comp_kbps / speed) * 100.0 - - print("HT WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) diff --git a/tests/automated/6_wifi_udp.py b/tests/automated/6_wifi_udp.py deleted file mode 100644 index bee5130..0000000 --- a/tests/automated/6_wifi_udp.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys -import time -from .helpers import start_heartbeat_thread, reset_pandas, time_many_sends, connect_wifi, test_white, panda_type_to_serial -from panda import Panda, PandaWifiStreaming -from nose.tools import assert_less, assert_greater - -# Reset the pandas before running tests -def aaaa_reset_before_tests(): - reset_pandas() - -@test_white -@panda_type_to_serial -def test_udp_doesnt_drop(serials=None): - connect_wifi(serials[0]) - - p = Panda(serials[0]) - - # Start heartbeat - start_heartbeat_thread(p) - - p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - p.set_can_loopback(True) - - pwifi = PandaWifiStreaming() - while 1: - if len(pwifi.can_recv()) == 0: - break - - for msg_count in [1, 100]: - saturation_pcts = [] - for i in range({1: 0x80, 100: 0x20}[msg_count]): - pwifi.kick() - - speed = 500 - p.set_can_speed_kbps(0, speed) - comp_kbps = time_many_sends(p, 0, pwifi, msg_count=msg_count, msg_id=0x100 + i) - saturation_pct = (comp_kbps / speed) * 100.0 - - if msg_count == 1: - sys.stdout.write(".") - sys.stdout.flush() - else: - print("UDP WIFI loopback %d messages at speed %d, comp speed is %.2f, percent %.2f" % (msg_count, speed, comp_kbps, saturation_pct)) - assert_greater(saturation_pct, 20) # sometimes the wifi can be slow... - assert_less(saturation_pct, 100) - saturation_pcts.append(saturation_pct) - if len(saturation_pcts) > 0: - assert_greater(sum(saturation_pcts) / len(saturation_pcts), 60) - - time.sleep(5) - usb_ok_cnt = 0 - REQ_USB_OK_CNT = 500 - st = time.time() - msg_id = 0x1bb - bus = 0 - last_missing_msg = 0 - while usb_ok_cnt < REQ_USB_OK_CNT and (time.time() - st) < 40: - p.can_send(msg_id, "message", bus) - time.sleep(0.01) - r = [1] - missing = True - while len(r) > 0: - r = p.can_recv() - r = [x for x in r if x[3] == bus and x[0] == msg_id] - if len(r) > 0: - missing = False - usb_ok_cnt += len(r) - if missing: - last_missing_msg = time.time() - et = time.time() - st - last_missing_msg = last_missing_msg - st - print("waited {} for panda to recv can on usb, {} msgs, last missing at {}".format(et, usb_ok_cnt, last_missing_msg)) - assert usb_ok_cnt >= REQ_USB_OK_CNT, "Unable to recv can on USB after UDP" diff --git a/tests/automated/helpers.py b/tests/automated/helpers.py index dbe9e72..671e43b 100644 --- a/tests/automated/helpers.py +++ b/tests/automated/helpers.py @@ -8,7 +8,6 @@ from panda_jungle import PandaJungle # pylint: disable=import-error from nose.tools import assert_equal from parameterized import parameterized, param from .timeout import run_with_timeout -from .wifi_helpers import _connect_wifi SPEED_NORMAL = 500 SPEED_GMLAN = 33.3 @@ -70,13 +69,6 @@ test_uno = parameterized([ param(panda_type=Panda.HW_TYPE_UNO) ]) -def connect_wifi(serial=None): - p = Panda(serial=serial) - p.set_esp_power(True) - dongle_id, pw = p.get_serial() - assert(dongle_id.isalnum()) - _connect_wifi(dongle_id, pw) - def time_many_sends(p, bus, p_recv=None, msg_count=100, msg_id=None, two_pandas=False): if p_recv == None: p_recv = p diff --git a/tests/automated/wifi_helpers.py b/tests/automated/wifi_helpers.py deleted file mode 100644 index f92aee9..0000000 --- a/tests/automated/wifi_helpers.py +++ /dev/null @@ -1,90 +0,0 @@ -import os -import sys -import time -import subprocess -import requests -from panda import Panda -FNULL = open(os.devnull, 'w') -def _connect_wifi(dongle_id, pw, insecure_okay=False): - ssid = "panda-" + dongle_id - - r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) - if not r: - # Can already ping, try connecting on wifi - try: - p = Panda("WIFI") - p.get_serial() - print("Already connected") - return - except: - pass - - print("WIFI: connecting to %s" % ssid) - - while 1: - if sys.platform == "darwin": - os.system("networksetup -setairportnetwork en0 %s %s" % (ssid, pw)) - else: - wlan_interface = subprocess.check_output(["sh", "-c", "iw dev | awk '/Interface/ {print $2}'"]).strip().decode('utf8') - cnt = 0 - MAX_TRIES = 10 - while cnt < MAX_TRIES: - print("WIFI: scanning %d" % cnt) - os.system("iwlist %s scanning > /dev/null" % wlan_interface) - os.system("nmcli device wifi rescan") - wifi_networks = [x.decode("utf8") for x in subprocess.check_output(["nmcli", "dev", "wifi", "list"]).split(b"\n")] - wifi_scan = [x for x in wifi_networks if ssid in x] - if len(wifi_scan) != 0: - break - time.sleep(0.1) - # MAX_TRIES tries, ~10 seconds max - cnt += 1 - assert cnt < MAX_TRIES - if "-pair" in wifi_scan[0]: - os.system("nmcli d wifi connect %s-pair" % (ssid)) - connect_cnt = 0 - MAX_TRIES = 100 - while connect_cnt < MAX_TRIES: - connect_cnt += 1 - r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) - if r: - print("Waiting for panda to ping...") - time.sleep(0.5) - else: - break - if insecure_okay: - break - # fetch webpage - print("connecting to insecure network to secure") - try: - r = requests.get("http://192.168.0.10/") - except requests.ConnectionError: - r = requests.get("http://192.168.0.10/") - assert r.status_code == 200 - - print("securing") - try: - r = requests.get("http://192.168.0.10/secure", timeout=0.01) - except requests.exceptions.Timeout: - print("timeout http request to secure") - pass - else: - ret = os.system("nmcli d wifi connect %s password %s" % (ssid, pw)) - if os.WEXITSTATUS(ret) == 0: - #check ping too - ping_ok = False - connect_cnt = 0 - MAX_TRIES = 10 - while connect_cnt < MAX_TRIES: - connect_cnt += 1 - r = subprocess.call(["ping", "-W", "4", "-c", "1", "192.168.0.10"], stdout=FNULL, stderr=subprocess.STDOUT) - if r: - print("Waiting for panda to ping...") - time.sleep(0.1) - else: - ping_ok = True - break - if ping_ok: - break - - # TODO: confirm that it's connected to the right panda diff --git a/tests/build/Dockerfile.panda_esp b/tests/build/Dockerfile.panda_esp deleted file mode 100644 index c4b4927..0000000 --- a/tests/build/Dockerfile.panda_esp +++ /dev/null @@ -1,23 +0,0 @@ -FROM ubuntu:16.04 - -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 python3 python3-pip - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN pip3 install pycryptodome==3.9.8 - -# Build esp toolchain -RUN mkdir -p /panda/boardesp -WORKDIR /panda/boardesp -RUN git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -WORKDIR /panda/boardesp/esp-open-sdk -RUN git checkout 03f5e898a059451ec5f3de30e7feff30455f7ce -COPY ./boardesp/python2_make.py /panda/boardesp/esp-open-sdk -RUN python2 python2_make.py "CT_ALLOW_BUILD_AS_ROOT_SURE=1 make STANDALONE=y" - -COPY . /panda - -WORKDIR /panda diff --git a/tests/disable_esp.py b/tests/disable_esp.py deleted file mode 100755 index 1194c2e..0000000 --- a/tests/disable_esp.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env python3 -from panda import Panda -Panda().set_esp_power(False) diff --git a/tests/elm_wifi.py b/tests/elm_wifi.py deleted file mode 100644 index 0e0ef52..0000000 --- a/tests/elm_wifi.py +++ /dev/null @@ -1,669 +0,0 @@ -# flake8: noqa - -import os -import sys -import time -import socket -import select -import struct - -sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) -sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..", "..")) -from panda import Panda -from panda.tests import elm_car_simulator - -def elm_connect(): - s = socket.create_connection(("192.168.0.10", 35000)) - s.setblocking(0) - return s - -def read_or_fail(s): - ready = select.select([s], [], [], 4) - assert ready[0], "Socket did not receive data within the timeout duration." - return s.recv(1000) - -def sendrecv(s, dat): - s.send(dat) - return read_or_fail(s) - -def send_compare(s, dat, ret, timeout=4): - s.send(dat) - res = b'' - while ret.startswith(res) and ret != res: - print("Waiting") - ready = select.select([s], [], [], timeout) - if not ready[0]: - print("current recv data:", repr(res)) - break - res += s.recv(1000) - #print("final recv data: '%s'" % repr(res)) - assert ret == res # , "Data does not agree (%s) (%s)"%(repr(ret), repr(res)) - -def sync_reset(s): - s.send("ATZ\r") - res = b'' - while not res.endswith("ELM327 v1.5\r\r>"): - res += read_or_fail(s) - print("Reset response is '%s'" % repr(res)) - -def test_reset(): - s = socket.create_connection(("192.168.0.10", 35000)) - s.setblocking(0) - - try: - sync_reset(s) - finally: - s.close() - -def test_elm_cli(): - s = elm_connect() - - try: - sync_reset(s) - - send_compare(s, b'ATI\r', b'ATI\rELM327 v1.5\r\r>') - - #Test Echo Off - #Expected to be misimplimentation, but this is how the reference device behaved. - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Here is the odd part - send_compare(s, b'ATE0\r', b'OK\r\r>') # Should prob show this immediately - send_compare(s, b'ATI\r', b'ELM327 v1.5\r\r>') - - #Test Newline On - send_compare(s, b'ATL1\r', b'OK\r\n\r\n>') - send_compare(s, b'ATI\r', b'ELM327 v1.5\r\n\r\n>') - send_compare(s, b'ATL0\r', b'OK\r\r>') - send_compare(s, b'ATI\r', b'ELM327 v1.5\r\r>') - - send_compare(s, b'ATI\r', b'ELM327 v1.5\r\r>') # Test repeat command no echo - send_compare(s, b'\r', b'ELM327 v1.5\r\r>') - - send_compare(s, b'aTi\r', b'ELM327 v1.5\r\r>') # Test different case - - send_compare(s, b' a T i\r', b'ELM327 v1.5\r\r>') # Test with white space - - send_compare(s, b'ATCATHAT\r', b'?\r\r>') # Test Invalid AT command - - send_compare(s, b'01 00 00 00 00 00 00 00\r', b'?\r\r>') # Test Invalid (too long) OBD command - send_compare(s, b'01 GZ\r', b'?\r\r>') # Test Invalid (Non hex chars) OBD command - finally: - s.close() - -def test_elm_setget_protocol(): - s = elm_connect() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - - send_compare(s, b'ATSP0\r', b"OK\r\r>") # Set auto - send_compare(s, b'ATDP\r', b"AUTO\r\r>") - send_compare(s, b'ATDPN\r', b"A0\r\r>") - - send_compare(s, b'ATSP6\r', b"OK\r\r>") # Set protocol - send_compare(s, b'ATDP\r', b"ISO 15765-4 (CAN 11/500)\r\r>") - send_compare(s, b'ATDPN\r', b"6\r\r>") - - send_compare(s, b'ATSPA6\r', b"OK\r\r>") # Set auto with protocol default - send_compare(s, b'ATDP\r', b"AUTO, ISO 15765-4 (CAN 11/500)\r\r>") - send_compare(s, b'ATDPN\r', b"A6\r\r>") - - send_compare(s, b'ATSP7\r', b"OK\r\r>") - send_compare(s, b'ATDP\r', b"ISO 15765-4 (CAN 29/500)\r\r>") - send_compare(s, b'ATDPN\r', b"7\r\r>") # Test Does not accept invalid protocols - send_compare(s, b'ATSPD\r', b"?\r\r>") - send_compare(s, b'ATDP\r', b"ISO 15765-4 (CAN 29/500)\r\r>") - send_compare(s, b'ATDPN\r', b"7\r\r>") - finally: - s.close() - -def test_elm_protocol_failure(): - s = elm_connect() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"SEARCHING...\rUNABLE TO CONNECT\r\r>", timeout=10) - - send_compare(s, b'ATSP1\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"NO DATA\r\r>") - - send_compare(s, b'ATSP2\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"NO DATA\r\r>") - - send_compare(s, b'ATSP3\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"BUS INIT: ...ERROR\r\r>") - - send_compare(s, b'ATSP4\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"BUS INIT: ...ERROR\r\r>") - - send_compare(s, b'ATSP5\r', b"OK\r\r>") - send_compare(s, b'0100\r', b"BUS INIT: ERROR\r\r>") - - #send_compare(s, b'ATSP6\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSP7\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSP8\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSP9\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSPA\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSPB\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - # - #send_compare(s, b'ATSPC\r', b"OK\r\r>") - #send_compare(s, b'0100\r', b"NO DATA\r\r>") - finally: - s.close() - -def test_elm_protocol_autodetect_ISO14230_KWP_FAST(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, can=False) # , silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATH0\r', b'OK\r\r>') # Headers ON - send_compare(s, b'ATS0\r', b"OK\r\r>") - - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'010D\r', b"SEARCHING...\r410D53\r\r>", timeout=10) - send_compare(s, b'ATDPN\r', b"A5\r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_basic_send_lin(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, can=False) # , silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP5\r', b"ATSP5\rOK\r\r>") # Set Proto - - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'0100\r', b"BUS INIT: OK\r41 00 FF FF FF FE \r\r>") - send_compare(s, b'010D\r', b"41 0D 53 \r\r>") - - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces Off - send_compare(s, b'0100\r', b"4100FFFFFFFE\r\r>") - send_compare(s, b'010D\r', b"410D53\r\r>") - - send_compare(s, b'ATH1\r', b'OK\r\r>') # Spaces Off Headers On - send_compare(s, b'0100\r', b"86F1104100FFFFFFFEC3\r\r>") - send_compare(s, b'010D\r', b"83F110410D5325\r\r>") - - send_compare(s, b'ATS1\r', b'OK\r\r>') # Spaces On Headers On - send_compare(s, b'0100\r', b"86 F1 10 41 00 FF FF FF FE C3 \r\r>") - send_compare(s, b'010D\r', b"83 F1 10 41 0D 53 25 \r\r>") - - send_compare(s, b'1F00\r', b"NO DATA\r\r>") # Unhandled msg, no response. - - # Repeat last check to see if it still works after NO DATA was received - send_compare(s, b'0100\r', b"86 F1 10 41 00 FF FF FF FE C3 \r\r>") - send_compare(s, b'010D\r', b"83 F1 10 41 0D 53 25 \r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_send_lin_multiline_msg(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, can=False) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATSP5\r', b"OK\r\r>") # Set Proto - - send_compare(s, b'0902\r', # headers OFF, Spaces ON - b"BUS INIT: OK\r" - b"49 02 01 00 00 00 31 \r" - b"49 02 02 44 34 47 50 \r" - b"49 02 03 30 30 52 35 \r" - b"49 02 04 35 42 31 32 \r" - b"49 02 05 33 34 35 36 \r\r>") - - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'0902\r', # Headers OFF, Spaces OFF - b"49020100000031\r" - b"49020244344750\r" - b"49020330305235\r" - b"49020435423132\r" - b"49020533343536\r\r>") - - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - send_compare(s, b'0902\r', # Headers ON, Spaces OFF - b"87F1104902010000003105\r" - b"87F11049020244344750E4\r" - b"87F11049020330305235BD\r" - b"87F11049020435423132B1\r" - b"87F11049020533343536AA\r\r>") - - send_compare(s, b'ATS1\r', b'OK\r\r>') # Spaces ON - send_compare(s, b'0902\r', # Headers ON, Spaces ON - b"87 F1 10 49 02 01 00 00 00 31 05 \r" - b"87 F1 10 49 02 02 44 34 47 50 E4 \r" - b"87 F1 10 49 02 03 30 30 52 35 BD \r" - b"87 F1 10 49 02 04 35 42 31 32 B1 \r" - b"87 F1 10 49 02 05 33 34 35 36 AA \r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_send_lin_multiline_msg_throughput(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, can=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP5\r', b"ATSP5\rOK\r\r>") # Set Proto - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH0\r', b'OK\r\r>') # Headers OFF - - send_compare(s, b'09fc\r', # headers OFF, Spaces OFF - b"BUS INIT: OK\r" + - b''.join((b'49FC' + hex(num + 1)[2:].upper().zfill(2) + - b'AAAA' + hex(num + 1)[2:].upper().zfill(4) + b'\r' - for num in range(80))) + - b"\r>", - timeout=10 - ) - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_panda_safety_mode_KWPFast(): - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - p_car = Panda(serial) # Configure this so the messages will send - p_car.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - p_car.kline_drain() - - p_elm = Panda("WIFI") - p_elm.set_safety_mode(Panda.SAFETY_ELM327) - - def get_checksum(dat): - result = 0 - result += sum(map(ord, dat)) if isinstance(b'dat', str) else sum(dat) - return struct.pack("B", result % 0x100) - - def timed_recv_check(p, bus, goodmsg): - t = time.time() - msg = bytearray() - - while time.time() - t < 0.5 and len(msg) != len(goodmsg): - msg += p._handle.controlRead(Panda.REQUEST_OUT, 0xe0, bus, 0, len(goodmsg) - len(msg)) - #print("Received", repr(msg)) - if msg == goodmsg: - return True - time.sleep(0.01) - return False - - def kline_send(p, x, bus=2): - p.kline_drain(bus=bus) - p._handle.bulkWrite(2, bytes([bus]) + x) - return timed_recv_check(p, bus, x) - - def did_send(priority, toaddr, fromaddr, dat, bus=2, checkbyte=None): - msgout = struct.pack("BBB", priority | len(dat), toaddr, fromaddr) + dat - msgout += get_checksum(msgout) if checkbyte is None else checkbyte - print("Sending", hex(priority), hex(toaddr), hex(fromaddr), repr(msgout)) - - if not kline_send(p_elm, msgout, bus=bus): - return False - return timed_recv_check(p_car, bus, msgout) - - assert not did_send(0xC0, 0x33, 0xF1, b'\x01\x0F', bus=3) # wrong bus - assert not did_send(0xC0, 0x33, 0xF1, b'') # wrong length - assert not did_send(0xB0, 0x33, 0xF1, b'\x01\x0E') # bad priority - assert not did_send(0xC0, 0x00, 0xF1, b'\x01\x0D') # bad addr - assert not did_send(0xC0, 0x33, 0x00, b'\x01\x0C') # bad addr - - assert did_send(0xC0, 0x33, 0xF1, b'\x01\x0B') # good! (obd func req) - -def test_elm_lin_keepalive(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, can=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP5\r', b"ATSP5\rOK\r\r>") # Set Proto - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH0\r', b'OK\r\r>') # Headers OFF - - send_compare(s, b'0100\r', b"BUS INIT: OK\r4100FFFFFFFE\r\r>") - assert sim.lin_active - time.sleep(6) - assert sim.lin_active - - send_compare(s, b'ATPC\r', b"OK\r\r>") # STOP KEEPALIVE - assert sim.lin_active - time.sleep(6) - assert not sim.lin_active - - finally: - sim.stop() - sim.join() - s.close() - -#//////////// -def test_elm_protocol_autodetect_ISO15765(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - send_compare(s, b'ATS0\r', b"OK\r\r>") - - sim.can_mode_11b() - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'010D\r', b"SEARCHING...\r7E803410D53\r\r>", timeout=10) - send_compare(s, b'ATDPN\r', b"A6\r\r>") - - sim.can_mode_29b() - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'010D\r', b"SEARCHING...\r18DAF11003410D53\r\r>", timeout=10) - send_compare(s, b'ATDPN\r', b"A7\r\r>") - - sim.change_can_baud(250) - - sim.can_mode_11b() - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'010D\r', b"SEARCHING...\r7E803410D53\r\r>", timeout=10) - send_compare(s, b'ATDPN\r', b"A8\r\r>") - - sim.can_mode_29b() - send_compare(s, b'ATSP0\r', b"OK\r\r>") - send_compare(s, b'010D\r', b"SEARCHING...\r18DAF11003410D53\r\r>", timeout=10) - send_compare(s, b'ATDPN\r', b"A9\r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_basic_send_can(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP6\r', b"ATSP6\rOK\r\r>") # Set Proto - - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'0100\r', b"41 00 FF FF FF FE \r\r>") - send_compare(s, b'010D\r', b"41 0D 53 \r\r>") - - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces Off - send_compare(s, b'0100\r', b"4100FFFFFFFE\r\r>") - send_compare(s, b'010D\r', b"410D53\r\r>") - - send_compare(s, b'ATH1\r', b'OK\r\r>') # Spaces Off Headers On - send_compare(s, b'0100\r', b"7E8064100FFFFFFFE\r\r>") - send_compare(s, b'010D\r', b"7E803410D53\r\r>") - - send_compare(s, b'ATS1\r', b'OK\r\r>') # Spaces On Headers On - send_compare(s, b'0100\r', b"7E8 06 41 00 FF FF FF FE \r\r>") - send_compare(s, b'010D\r', b"7E8 03 41 0D 53 \r\r>") - - send_compare(s, b'1F00\r', b"NO DATA\r\r>") # Unhandled msg, no response. - - # Repeat last check to see if it still works after NO DATA was received - send_compare(s, b'0100\r', b"7E8 06 41 00 FF FF FF FE \r\r>") - send_compare(s, b'010D\r', b"7E8 03 41 0D 53 \r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_send_can_multimsg(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS1\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - - send_compare(s, b'ATSP6\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/500) - sim.can_add_extra_noise(b'\x03\x41\x0D\xFA', addr=0x7E9) # Inject message into the stream - send_compare(s, b'010D\r', - b"7E8 03 41 0D 53 \r" - b"7E9 03 41 0D FA \r\r>") # Check it was ignored. - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_can_check_mode_pid(): - """The ability to correctly filter out messages with the wrong PID is not - implemented correctly in the reference device.""" - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH0\r', b'OK\r\r>') # Headers OFF - - send_compare(s, b'ATSP6\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/500) - sim.can_add_extra_noise(b'\x03\x41\x0E\xFA') # Inject message into the stream - send_compare(s, b'010D\r', b"410D53\r\r>") # Check it was ignored. - send_compare(s, b'0100\r', b"4100FFFFFFFE\r\r>") # Check it was ignored again. - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_send_can_multiline_msg(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP6\r', b"ATSP6\rOK\r\r>") # Set Proto - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - - send_compare(s, b'0902\r', # headers OFF, Spaces ON - b"014 \r" - b"0: 49 02 01 31 44 34 \r" - b"1: 47 50 30 30 52 35 35 \r" - b"2: 42 31 32 33 34 35 36 \r\r>") - - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'0902\r', # Headers OFF, Spaces OFF - b"014\r" - b"0:490201314434\r" - b"1:47503030523535\r" - b"2:42313233343536\r\r>") - - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - send_compare(s, b'0902\r', # Headers ON, Spaces OFF - b"7E81014490201314434\r" - b"7E82147503030523535\r" - b"7E82242313233343536\r\r>") - - send_compare(s, b'ATS1\r', b'OK\r\r>') # Spaces ON - send_compare(s, b'0902\r', # Headers ON, Spaces ON - b"7E8 10 14 49 02 01 31 44 34 \r" - b"7E8 21 47 50 30 30 52 35 35 \r" - b"7E8 22 42 31 32 33 34 35 36 \r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_send_can_multiline_msg_throughput(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATSP6\r', b"ATSP6\rOK\r\r>") # Set Proto - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - - rows = 584 - send_compare(s, b'09ff\r', # headers ON, Spaces OFF - ("7E8" + "1" + hex((rows * 7) + 6)[2:].upper().zfill(3) + "49FF01" + "AA0000\r" + - "".join( - ("7E82" + hex((num + 1) % 0x10)[2:].upper() + ("AA" * 5) + - hex(num + 1)[2:].upper().zfill(4) + "\r" for num in range(rows)) - ) + "\r>").encode(), - timeout=10 - ) - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_interrupted_obd_cmd_resets_state(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False, silent=True) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - s.send(b"09fd\r") - ready = select.select([s], [], [], 4) - assert ready[0], "Socket did not receive data within the timeout duration." - s.send(b"ATI\r") - - assert b"236\r0:49FD01AAAAAA\r" in s.recv(10000) - - #Will likely have to be improved to scan for STOPPED if the FW gets more responsive. - ready = select.select([s], [], [], 4) - assert ready[0], "Socket did not receive data within the timeout duration." - - assert b"STOPPED" in s.recv(10000) - - sim.set_enable(False) - send_compare(s, b'09fd\r', b"NO DATA\r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_can_baud(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - sim = elm_car_simulator.ELMCarSimulator(serial, lin=False) - sim.start() - - try: - sync_reset(s) - send_compare(s, b'ATE0\r', b'ATE0\rOK\r\r>') # Echo OFF - send_compare(s, b'ATS0\r', b'OK\r\r>') # Spaces OFF - send_compare(s, b'ATH1\r', b'OK\r\r>') # Headers ON - - send_compare(s, b'ATSP6\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/500) - send_compare(s, b'0100\r', b"7E8064100FFFFFFFE\r\r>") - - send_compare(s, b'ATSP8\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/250) - send_compare(s, b'0100\r', b"CAN ERROR\r\r>") - - sim.change_can_baud(250) - - send_compare(s, b'ATSP6\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/500) - send_compare(s, b'0100\r', b"CAN ERROR\r\r>") - - send_compare(s, b'ATSP8\r', b"OK\r\r>") # Set Proto ISO 15765-4 (CAN 11/250) - send_compare(s, b'0100\r', b"7E8064100FFFFFFFE\r\r>") - finally: - sim.stop() - sim.join() - s.close() - -def test_elm_panda_safety_mode_ISO15765(): - s = elm_connect() - serial = os.getenv("CANSIMSERIAL") if os.getenv("CANSIMSERIAL") else None - p_car = Panda(serial) # Configure this so the messages will send - p_car.set_can_speed_kbps(0, 500) - p_car.set_safety_mode(Panda.SAFETY_ALLOUTPUT) - - p_elm = Panda("WIFI") - p_elm.set_safety_mode(Panda.SAFETY_ELM327) - - #sim = elm_car_simulator.ELMCarSimulator(serial, lin=False) - #sim.start() - - def did_send(p, addr, dat, bus): - p.can_send(addr, dat, bus) - t = time.time() - while time.time() - t < 0.5: - msg = p.can_recv() - for addrin, _, datin, busin in msg: - if (0x80 | bus) == busin and addr == addrin and datin == dat: - return True - time.sleep(0.01) - return False - - try: - sync_reset(s) # Reset elm (which requests the ELM327 safety mode) - - #29 bit - assert not did_send(p_elm, 0x18DB33F1, b'\x02\x01\x00\x00\x00\x00\x00\x00', 1) # wrong canid - assert not did_send(p_elm, 0x18DB33F1, b'\x02\x01\x00', 0) # wrong length - assert not did_send(p_elm, 0x10000000, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr - assert not did_send(p_elm, 0x18DAF133, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr (phy addr) - assert not did_send(p_elm, 0x18DAF000, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr - assert not did_send(p_elm, 0x18DAF1F3, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr! (phys rsp to elm) - - assert did_send(p_elm, 0x18DB33F1, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # good! (obd func req) - assert did_send(p_elm, 0x18DA10F1, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # good! (phys response) - - #11 bit - assert not did_send(p_elm, 0X7DF, b'\x02\x01\x00\x00\x00\x00\x00\x00', 1) # wrong canid - assert not did_send(p_elm, 0X7DF, b'\x02\x01\x00', 0) # wrong length - assert not did_send(p_elm, 0xAA, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr - assert not did_send(p_elm, 0x7DA, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr (phy addr) - assert not did_send(p_elm, 0x7E8, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # bad addr (sending 'response') - - assert did_send(p_elm, 0x7DF, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # good! (obd func req) - assert did_send(p_elm, 0x7E1, b'\x02\x01\x00\x00\x00\x00\x00\x00', 0) # good! (phys response) - - finally: - s.close()