diff --git a/CMakeLists.txt b/CMakeLists.txt index 612709f..ed2a2f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ -# The following lines of boilerplate have to be in your project's CMakeLists -# in this exact order for cmake to work correctly -cmake_minimum_required(VERSION 3.5) - -include($ENV{IDF_PATH}/tools/cmake/project.cmake) -project(can2http) - -# Create a SPIFFS image from the contents of the 'csv' FLASH_IN_PROJECT indicates that -# the generated image should be flashed when the entire project is flashed to -# the target with 'idf.py -p PORT flash -spiffs_create_partition_image(storage csv FLASH_IN_PROJECT) +# The following lines of boilerplate have to be in your project's CMakeLists +# in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(can2http) + +# Create a SPIFFS image from the contents of the 'csv' FLASH_IN_PROJECT indicates that +# the generated image should be flashed when the entire project is flashed to +# the target with 'idf.py -p PORT flash +spiffs_create_partition_image(storage csv FLASH_IN_PROJECT) diff --git a/LICENSE b/LICENSE index 3d55d6b..68e40e8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2024 PrincessPi3 and nopnop2002 - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2024 PrincessPi3 and nopnop2002 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 30f5914..1de7362 100644 --- a/README.md +++ b/README.md @@ -1,289 +1,289 @@ -# Sillyfilly-CAN -A fork of [esp-idf-can2http](https://github.com/nopnop2002/esp-idf-can2http) - -A CAN bus tool built for the esp32. It has a builtin web interface and works with nearly any CAN transceiver like the [N65HVD230](https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO/) or the [TJA1050](https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/) - -## Hardware needed -* esp32(-X) (My favorite esp32)[https://www.amazon.com/Espressif-ESP32-S3-DevKitC-1-N32R8V-Development-Board/dp/B09R4GSDJM] -* CAN transceiver like the [N65HVD230](https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO/) or the [TJA1050](https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/) -some jumper wires -* Jumper wires - -## Optional -* [ODB2 pigtail](https://www.amazon.com/iKKEGOL-Connector-Diagnostic-Extension-Pigtail/dp/B0828YHWFG/) - -## Installation -1) install [esp-idf](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html#installation) if not installed on your computer already -2) open esp-idf terminal -3) plug in your esp32 to computer via USB cable -4) Run these commands: -``` -git clone https://github.com/PrincessPi3/Sillyfilly-CAN.git -cd Sillyfilly-CAN -idf.py set-target esp32s3 # example idf.py set-target -idf.py menuconfig -``` -5) Under "Sillyfilly-CAN Configuration" set your settings like wifi and CRX and CTX pins. -6) Wire transceiver to the pins: CRX->RX, CTX-TX, GND->GND -7) run this command -```idf.py flash monitor # ctrl+] to exit monitor``` - can be one of 'esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61' - -# Original README.md -# esp-idf-can2http -CANbus to http bridge using esp32. -It's purpose is to be a bridge between a CAN-Bus and a HTTP-Server. - -![slide0001](https://user-images.githubusercontent.com/6020549/125031346-7ae6ec80-e0c7-11eb-8d8a-f419154d277c.jpg) -![slide0002](https://user-images.githubusercontent.com/6020549/125031353-7d494680-e0c7-11eb-8382-df74fab44737.jpg) -![slide0003](https://user-images.githubusercontent.com/6020549/125031358-7e7a7380-e0c7-11eb-9880-07c42a1a7d64.jpg) - - -# Software requirement -ESP-IDF V4.4/V5.x. -ESP-IDF V5.1 is required when using ESP32C6. - -# Hardware requirements -- SN65HVD23x CAN-BUS Transceiver -SN65HVD23x series has 230/231/232. -They differ in standby/sleep mode functionality. -Other features are the same. - -- Termination resistance -I used 150 ohms. - -# Wireing -|SN65HVD23x||ESP32|ESP32-S2/S3|ESP32-C3/C6|| -|:-:|:-:|:-:|:-:|:-:|:-:| -|D(CTX)|--|GPIO21|GPIO17|GPIO0|(*1)| -|GND|--|GND|GND|GND|| -|Vcc|--|3.3V|3.3V|3.3V|| -|R(CRX)|--|GPIO22|GPIO18|GPIO1|(*1)| -|Vref|--|N/C|N/C|N/C|| -|CANL|--||||To CAN Bus| -|CANH|--||||To CAN Bus| -|RS|--|GND|GND|GND|(*2)| - -(*1) You can change using menuconfig. But it may not work with other GPIOs. - -(*2) N/C for SN65HVD232 - - - -# Test Circuit -``` - +-----------+ +-----------+ +-----------+ - | Atmega328 | | Atmega328 | | ESP32 | - | | | | | | - | Transmit | | Receive | | 21 22 | - +-----------+ +-----------+ +-----------+ - | | | | | | - +-----------+ +-----------+ | | - | | | | | | - | MCP2515 | | MCP2515 | | | - | | | | | | - +-----------+ +-----------+ | | - | | | | | | - +-----------+ +-----------+ +-----------+ - | | | | | D R | - | MCP2551 | | MCP2551 | | VP230 | - | H L | | H L | | H L | - +-----------+ +-----------+ +-----------+ - | | | | | | - +--^^^--+ | | +--^^^--+ - | R1 | | | | R2 | - |---+-------|-------+-------|-------+-------|---| BackBorn H - | | | - | | | - | | | - |-----------+---------------+---------------+---| BackBorn L - - +--^^^--+:Terminaror register - R1:120 ohms - R2:150 ohms(Not working at 120 ohms) -``` - -__NOTE__ -3V CAN Trasnceviers like VP230 are fully interoperable with 5V CAN trasnceviers like MCP2551. -Check [here](http://www.ti.com/lit/an/slla337/slla337.pdf). - - -# Installation -``` -git clone https://github.com/nopnop2002/esp-idf-can2http -cd esp-idf-can2http -idf.py set-target {esp32/esp32s2/esp32s3/esp32c3/esp32c6} -idf.py menuconfig -idf.py flash -``` - -# Configuration -![config-main](https://user-images.githubusercontent.com/6020549/123870635-92a6ce00-d96d-11eb-9b67-7b6a26e95fbd.jpg) -![config-app](https://user-images.githubusercontent.com/6020549/123870638-94709180-d96d-11eb-94da-b4860148be6a.jpg) - -## CAN Setting -![config-can](https://user-images.githubusercontent.com/6020549/160263252-f2a10f2b-a970-44bf-ab9c-22ae7baa4ab5.jpg) - -## WiFi Setting -![config-wifi-1](https://user-images.githubusercontent.com/6020549/125028704-73254900-e0c3-11eb-9a44-25482d7a08be.jpg) - -You can use static IP. -![config-wifi-2](https://user-images.githubusercontent.com/6020549/125028738-80423800-e0c3-11eb-984f-9dc4f892bdb6.jpg) - -You can connect using mDNS. -![config-wifi-3](https://user-images.githubusercontent.com/6020549/125028763-89cba000-e0c3-11eb-921d-9baca5ec58d4.jpg) - -## External HTTP Server Setting -The External HTTP Server receives CAN Bus received data. -![config-http](https://user-images.githubusercontent.com/6020549/160263251-1b1a4771-a5f0-43f2-b75e-572fa6904ac9.jpg) - -__Note__ -The Built-in HTTP Server receives CAN Bus transmittion data. - -# Definition from CANbus to HTTP -When CANbus data is received, it is sent by HTTP POST according to csv/can2http.csv. -The file can2http.csv has three columns. -In the first column you need to specify the CAN Frame type. -The CAN frame type is either S(Standard frame) or E(Extended frame). -In the second column you have to specify the CAN-ID as a __hexdecimal number__. -In the last column you have to specify the HTTP-POST-Path of external HTTP server. -Each CAN-ID is allowed to appear only once in the whole file. - -``` -S,101,/post -E,101,/post -S,103,/post -E,103,/post -``` - -When a CAN frame with ID 0x101 is received, POST with the 'canid':257. -When a CAN frame with ID 0x103 is received, POST with the 'canid':259. - -POST Parameter Example: -CAN-ID is a decimal number, not a hexadecimal number. - -``` -{"canid":257, "frame": "standard", "data": [16, 17, 18]} -{"canid":257, "frame": "extended", "data": [16, 17, 18]} -{"canid":259, "frame": "standard", "data": [16, 17, 18]} -{"canid":259, "frame": "extended", "data": [16, 17, 18]} -``` - -__CAN messages not registered in csv/can2http.csv are discarded and not POSTed to HTTP.__ - -# Definition from HTTP to CANbus -Not exist. -You can send any CAN-ID. - - -# Send CANBus frame using curl -CAN-ID is specified in __decimal number__. -``` -$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send -twai send successfully - -$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "extended", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send -twai send successfully -``` - -CANBus reception using UNO. - -![send_standard](https://user-images.githubusercontent.com/6020549/125029834-2c385300-e0c5-11eb-8f25-f3af82e90038.jpg) - -![send_extended](https://user-images.githubusercontent.com/6020549/125029930-5558e380-e0c5-11eb-951b-baee58e66d18.jpg) - - ---- - -# HTTP Server Using Tornado -``` -cd $HOME -sudo apt install python3-pip python3-setuptools -python3 -m pip install -U pip -python3 -m pip install -U wheel -python3 -m pip install tornado -git clone https://github.com/nopnop2002/esp-idf-can2http -cd esp-idf-can2http -cd tornado -python3 can.py -``` - -You can specify the number of lines to display and the port number. -The default port number is 8000 and the default number of display lines is 20. -Redisplay every 5 seconds. -![can2http-tornado](https://user-images.githubusercontent.com/6020549/202159913-74fab7ef-d95c-4774-8432-ceceac24af4e.jpg) - - -# HTTP Server Using Flask -``` -cd $HOME -sudo apt install python3-pip python3-setuptools -python3 -m pip install -U pip -python3 -m pip install -U wheel -python3 -m pip install -U Werkzeug -python3 -m pip install flask -git clone https://github.com/nopnop2002/esp-idf-can2http -cd esp-idf-can2http -cd flask -python3 can.py -``` - -You can specify the number of lines to display and the port number. -The default port number is 8000 and the default number of display lines is 20. -Redisplay every 5 seconds. -![can2http-flask](https://user-images.githubusercontent.com/6020549/202165156-dea58ea4-cbb8-4e35-bdc8-a19e5be575e7.jpg) - - -# Brows received data Using Tornado/Flask -Open your browser and put the Server's IP in the address bar. - -![can2http-browser](https://user-images.githubusercontent.com/6020549/202160043-0ca6e869-f6bc-4319-b8db-48a8fe9b1c5f.jpg) - -# Visualize CAN-Frame - -## Using python -There is a lot of information on the internet about the Python + visualization library. -- [matplotlib](https://matplotlib.org/) -- [seaborn](https://seaborn.pydata.org/index.html) -- [bokeh](https://bokeh.org/) -- [plotly](https://plotly.com/python/) - -## Using node.js -There is a lot of information on the internet about the node.js + __real time__ visualization library. -- [epoch](https://epochjs.github.io/epoch/real-time/) -- [plotly](https://plotly.com/javascript/streaming/) -- [chartjs-plugin-streaming](https://nagix.github.io/chartjs-plugin-streaming/1.9.0/) - -# Troubleshooting -There is a module of SN65HVD230 like this. -![SN65HVD230-1](https://user-images.githubusercontent.com/6020549/80897499-4d204e00-8d34-11ea-80c9-3dc41b1addab.JPG) - -There is a __120 ohms__ terminating resistor on the left side. -![SN65HVD230-22](https://user-images.githubusercontent.com/6020549/89281044-74185400-d684-11ea-9f55-830e0e9e6424.JPG) - -I have removed the terminating resistor. -And I used a external resistance of __150 ohms__. -A transmission fail is fixed. -![SN65HVD230-33](https://user-images.githubusercontent.com/6020549/89280710-f7857580-d683-11ea-9b36-12e36910e7d9.JPG) - -If the transmission fails, these are the possible causes. -- There is no receiving app on CanBus. -- The speed does not match the receiver. -- There is no terminating resistor on the CanBus. -- There are three terminating resistors on the CanBus. -- The resistance value of the terminating resistor is incorrect. -- Stub length in CAN bus is too long. See [here](https://e2e.ti.com/support/interface-group/interface/f/interface-forum/378932/iso1050-can-bus-stub-length). - -# Reference -https://github.com/nopnop2002/esp-idf-candump - -https://github.com/nopnop2002/esp-idf-can2mqtt - -https://github.com/nopnop2002/esp-idf-can2usb - -https://github.com/nopnop2002/esp-idf-can2websocket - -https://github.com/nopnop2002/esp-idf-can2socket - -https://github.com/nopnop2002/esp-idf-CANBus-Monitor - +# Sillyfilly-CAN +A fork of [esp-idf-can2http](https://github.com/nopnop2002/esp-idf-can2http) + +A CAN bus tool built for the esp32. It has a builtin web interface and works with nearly any CAN transceiver like the [N65HVD230](https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO/) or the [TJA1050](https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/) + +## Hardware needed +* esp32(-X) (My favorite esp32)[https://www.amazon.com/Espressif-ESP32-S3-DevKitC-1-N32R8V-Development-Board/dp/B09R4GSDJM] +* CAN transceiver like the [N65HVD230](https://www.amazon.com/SN65HVD230-CAN-Board-Communication-Development/dp/B00KM6XMXO/) or the [TJA1050](https://www.amazon.com/Comimark-Transceiver-TJA1050-Controller-Schnittstelle/dp/B07W4VZ2F2/) +some jumper wires +* Jumper wires + +## Optional +* [ODB2 pigtail](https://www.amazon.com/iKKEGOL-Connector-Diagnostic-Extension-Pigtail/dp/B0828YHWFG/) + +## Installation +1) install [esp-idf](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html#installation) if not installed on your computer already +2) open esp-idf terminal +3) plug in your esp32 to computer via USB cable +4) Run these commands: +``` +git clone https://github.com/PrincessPi3/Sillyfilly-CAN.git +cd Sillyfilly-CAN +idf.py set-target esp32s3 # example idf.py set-target +idf.py menuconfig +``` +5) Under "Sillyfilly-CAN Configuration" set your settings like wifi and CRX and CTX pins. +6) Wire transceiver to the pins: CRX->RX, CTX-TX, GND->GND +7) run this command +```idf.py flash monitor # ctrl+] to exit monitor``` + can be one of 'esp32', 'esp32s2', 'esp32c3', 'esp32s3', 'esp32c2', 'esp32c6', 'esp32h2', 'esp32p4', 'esp32c5', 'esp32c61' + +# Original README.md +# esp-idf-can2http +CANbus to http bridge using esp32. +It's purpose is to be a bridge between a CAN-Bus and a HTTP-Server. + +![slide0001](https://user-images.githubusercontent.com/6020549/125031346-7ae6ec80-e0c7-11eb-8d8a-f419154d277c.jpg) +![slide0002](https://user-images.githubusercontent.com/6020549/125031353-7d494680-e0c7-11eb-8382-df74fab44737.jpg) +![slide0003](https://user-images.githubusercontent.com/6020549/125031358-7e7a7380-e0c7-11eb-9880-07c42a1a7d64.jpg) + + +# Software requirement +ESP-IDF V4.4/V5.x. +ESP-IDF V5.1 is required when using ESP32C6. + +# Hardware requirements +- SN65HVD23x CAN-BUS Transceiver +SN65HVD23x series has 230/231/232. +They differ in standby/sleep mode functionality. +Other features are the same. + +- Termination resistance +I used 150 ohms. + +# Wireing +|SN65HVD23x||ESP32|ESP32-S2/S3|ESP32-C3/C6|| +|:-:|:-:|:-:|:-:|:-:|:-:| +|D(CTX)|--|GPIO21|GPIO17|GPIO0|(*1)| +|GND|--|GND|GND|GND|| +|Vcc|--|3.3V|3.3V|3.3V|| +|R(CRX)|--|GPIO22|GPIO18|GPIO1|(*1)| +|Vref|--|N/C|N/C|N/C|| +|CANL|--||||To CAN Bus| +|CANH|--||||To CAN Bus| +|RS|--|GND|GND|GND|(*2)| + +(*1) You can change using menuconfig. But it may not work with other GPIOs. + +(*2) N/C for SN65HVD232 + + + +# Test Circuit +``` + +-----------+ +-----------+ +-----------+ + | Atmega328 | | Atmega328 | | ESP32 | + | | | | | | + | Transmit | | Receive | | 21 22 | + +-----------+ +-----------+ +-----------+ + | | | | | | + +-----------+ +-----------+ | | + | | | | | | + | MCP2515 | | MCP2515 | | | + | | | | | | + +-----------+ +-----------+ | | + | | | | | | + +-----------+ +-----------+ +-----------+ + | | | | | D R | + | MCP2551 | | MCP2551 | | VP230 | + | H L | | H L | | H L | + +-----------+ +-----------+ +-----------+ + | | | | | | + +--^^^--+ | | +--^^^--+ + | R1 | | | | R2 | + |---+-------|-------+-------|-------+-------|---| BackBorn H + | | | + | | | + | | | + |-----------+---------------+---------------+---| BackBorn L + + +--^^^--+:Terminaror register + R1:120 ohms + R2:150 ohms(Not working at 120 ohms) +``` + +__NOTE__ +3V CAN Trasnceviers like VP230 are fully interoperable with 5V CAN trasnceviers like MCP2551. +Check [here](http://www.ti.com/lit/an/slla337/slla337.pdf). + + +# Installation +``` +git clone https://github.com/nopnop2002/esp-idf-can2http +cd esp-idf-can2http +idf.py set-target {esp32/esp32s2/esp32s3/esp32c3/esp32c6} +idf.py menuconfig +idf.py flash +``` + +# Configuration +![config-main](https://user-images.githubusercontent.com/6020549/123870635-92a6ce00-d96d-11eb-9b67-7b6a26e95fbd.jpg) +![config-app](https://user-images.githubusercontent.com/6020549/123870638-94709180-d96d-11eb-94da-b4860148be6a.jpg) + +## CAN Setting +![config-can](https://user-images.githubusercontent.com/6020549/160263252-f2a10f2b-a970-44bf-ab9c-22ae7baa4ab5.jpg) + +## WiFi Setting +![config-wifi-1](https://user-images.githubusercontent.com/6020549/125028704-73254900-e0c3-11eb-9a44-25482d7a08be.jpg) + +You can use static IP. +![config-wifi-2](https://user-images.githubusercontent.com/6020549/125028738-80423800-e0c3-11eb-984f-9dc4f892bdb6.jpg) + +You can connect using mDNS. +![config-wifi-3](https://user-images.githubusercontent.com/6020549/125028763-89cba000-e0c3-11eb-921d-9baca5ec58d4.jpg) + +## External HTTP Server Setting +The External HTTP Server receives CAN Bus received data. +![config-http](https://user-images.githubusercontent.com/6020549/160263251-1b1a4771-a5f0-43f2-b75e-572fa6904ac9.jpg) + +__Note__ +The Built-in HTTP Server receives CAN Bus transmittion data. + +# Definition from CANbus to HTTP +When CANbus data is received, it is sent by HTTP POST according to csv/can2http.csv. +The file can2http.csv has three columns. +In the first column you need to specify the CAN Frame type. +The CAN frame type is either S(Standard frame) or E(Extended frame). +In the second column you have to specify the CAN-ID as a __hexdecimal number__. +In the last column you have to specify the HTTP-POST-Path of external HTTP server. +Each CAN-ID is allowed to appear only once in the whole file. + +``` +S,101,/post +E,101,/post +S,103,/post +E,103,/post +``` + +When a CAN frame with ID 0x101 is received, POST with the 'canid':257. +When a CAN frame with ID 0x103 is received, POST with the 'canid':259. + +POST Parameter Example: +CAN-ID is a decimal number, not a hexadecimal number. + +``` +{"canid":257, "frame": "standard", "data": [16, 17, 18]} +{"canid":257, "frame": "extended", "data": [16, 17, 18]} +{"canid":259, "frame": "standard", "data": [16, 17, 18]} +{"canid":259, "frame": "extended", "data": [16, 17, 18]} +``` + +__CAN messages not registered in csv/can2http.csv are discarded and not POSTed to HTTP.__ + +# Definition from HTTP to CANbus +Not exist. +You can send any CAN-ID. + + +# Send CANBus frame using curl +CAN-ID is specified in __decimal number__. +``` +$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send +twai send successfully + +$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "extended", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send +twai send successfully +``` + +CANBus reception using UNO. + +![send_standard](https://user-images.githubusercontent.com/6020549/125029834-2c385300-e0c5-11eb-8f25-f3af82e90038.jpg) + +![send_extended](https://user-images.githubusercontent.com/6020549/125029930-5558e380-e0c5-11eb-951b-baee58e66d18.jpg) + + +--- + +# HTTP Server Using Tornado +``` +cd $HOME +sudo apt install python3-pip python3-setuptools +python3 -m pip install -U pip +python3 -m pip install -U wheel +python3 -m pip install tornado +git clone https://github.com/nopnop2002/esp-idf-can2http +cd esp-idf-can2http +cd tornado +python3 can.py +``` + +You can specify the number of lines to display and the port number. +The default port number is 8000 and the default number of display lines is 20. +Redisplay every 5 seconds. +![can2http-tornado](https://user-images.githubusercontent.com/6020549/202159913-74fab7ef-d95c-4774-8432-ceceac24af4e.jpg) + + +# HTTP Server Using Flask +``` +cd $HOME +sudo apt install python3-pip python3-setuptools +python3 -m pip install -U pip +python3 -m pip install -U wheel +python3 -m pip install -U Werkzeug +python3 -m pip install flask +git clone https://github.com/nopnop2002/esp-idf-can2http +cd esp-idf-can2http +cd flask +python3 can.py +``` + +You can specify the number of lines to display and the port number. +The default port number is 8000 and the default number of display lines is 20. +Redisplay every 5 seconds. +![can2http-flask](https://user-images.githubusercontent.com/6020549/202165156-dea58ea4-cbb8-4e35-bdc8-a19e5be575e7.jpg) + + +# Brows received data Using Tornado/Flask +Open your browser and put the Server's IP in the address bar. + +![can2http-browser](https://user-images.githubusercontent.com/6020549/202160043-0ca6e869-f6bc-4319-b8db-48a8fe9b1c5f.jpg) + +# Visualize CAN-Frame + +## Using python +There is a lot of information on the internet about the Python + visualization library. +- [matplotlib](https://matplotlib.org/) +- [seaborn](https://seaborn.pydata.org/index.html) +- [bokeh](https://bokeh.org/) +- [plotly](https://plotly.com/python/) + +## Using node.js +There is a lot of information on the internet about the node.js + __real time__ visualization library. +- [epoch](https://epochjs.github.io/epoch/real-time/) +- [plotly](https://plotly.com/javascript/streaming/) +- [chartjs-plugin-streaming](https://nagix.github.io/chartjs-plugin-streaming/1.9.0/) + +# Troubleshooting +There is a module of SN65HVD230 like this. +![SN65HVD230-1](https://user-images.githubusercontent.com/6020549/80897499-4d204e00-8d34-11ea-80c9-3dc41b1addab.JPG) + +There is a __120 ohms__ terminating resistor on the left side. +![SN65HVD230-22](https://user-images.githubusercontent.com/6020549/89281044-74185400-d684-11ea-9f55-830e0e9e6424.JPG) + +I have removed the terminating resistor. +And I used a external resistance of __150 ohms__. +A transmission fail is fixed. +![SN65HVD230-33](https://user-images.githubusercontent.com/6020549/89280710-f7857580-d683-11ea-9b36-12e36910e7d9.JPG) + +If the transmission fails, these are the possible causes. +- There is no receiving app on CanBus. +- The speed does not match the receiver. +- There is no terminating resistor on the CanBus. +- There are three terminating resistors on the CanBus. +- The resistance value of the terminating resistor is incorrect. +- Stub length in CAN bus is too long. See [here](https://e2e.ti.com/support/interface-group/interface/f/interface-forum/378932/iso1050-can-bus-stub-length). + +# Reference +https://github.com/nopnop2002/esp-idf-candump + +https://github.com/nopnop2002/esp-idf-can2mqtt + +https://github.com/nopnop2002/esp-idf-can2usb + +https://github.com/nopnop2002/esp-idf-can2websocket + +https://github.com/nopnop2002/esp-idf-can2socket + +https://github.com/nopnop2002/esp-idf-CANBus-Monitor + diff --git a/csv/can2http.csv b/csv/can2http.csv index e4e8e53..85dec13 100644 --- a/csv/can2http.csv +++ b/csv/can2http.csv @@ -1,11 +1,11 @@ -#The file can2http.csv has three columns. -#In the first column you need to specify the CAN Frame type. -#The CAN frame type is either S(Standard frame) or E(Extended frame). -#In the second column you have to specify the CAN-ID as a __hexdecimal number__. -#In the last column you have to specify the PATH of external web server. -#Each CAN-ID is allowed to appear only once in the whole file. - -S,101,/post -E,101,/post -S,103,/post -E,103,/post +#The file can2http.csv has three columns. +#In the first column you need to specify the CAN Frame type. +#The CAN frame type is either S(Standard frame) or E(Extended frame). +#In the second column you have to specify the CAN-ID as a __hexdecimal number__. +#In the last column you have to specify the PATH of external web server. +#Each CAN-ID is allowed to appear only once in the whole file. + +S,101,/post +E,101,/post +S,103,/post +E,103,/post diff --git a/csv/index.html b/csv/index.html index 06686de..0ae228e 100644 --- a/csv/index.html +++ b/csv/index.html @@ -1,79 +1,79 @@ -

Sillyfilly CAN Interface

-
-
- - -
-
-
- -
- - -
-
- - -
- -

TX

-
none yet
-

RX

-
none yet
-
- - \ No newline at end of file diff --git a/flask/can.py b/flask/can.py index 184cbf1..946ad23 100644 --- a/flask/can.py +++ b/flask/can.py @@ -1,80 +1,80 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Simple REST Server - -import os -import sys -import json -import datetime -import argparse -from flask import Flask, request, render_template -app = Flask(__name__) - -database = [] - -@app.route("/") -def root(): - global database - items = [] - for data in database: - #print("{}".format(data)) - datetime = data[0].split() - #print("data={} datetime={}".format(data[0], datetime)) - - items.append({ - "date": datetime[0], - "time": datetime[1], - "id": data[1], - "frame": data[2], - "value": data[3] - }) - #print("items={}".format(items)) - return render_template("index.html", lines=app.config['lines'], items=items) - -#curl -X POST -H "Content-Type: application/json" -d '{"canid":101, "frame":"standard" , "data": [1,2,3,4,5,6,7,8]}' http://192.168.10.43:8000/post -@app.route("/post", methods=["POST"]) -def post(): - function = sys._getframe().f_code.co_name - #print("{}: request={}".format(function, request)) - #print("{}: request.data={}".format(function, request.data)) - dict = json.loads(request.data) - print("{} dict={}".format(function, dict)) - - items = [] - now = datetime.datetime.now() - items.append(now.strftime("%Y/%m/%d %H:%M:%S")) - if ("canid" in dict): - print("{} canid=0x{:x}".format(function, dict['canid'])) - items.append(dict['canid']) - - if ("frame" in dict): - print("{} frame={}".format(function, dict['frame'])) - items.append(dict['frame']) - - if ("data" in dict): - print("{} data length={}".format(function, len(dict['data']))) - print("{} data={}".format(function, dict['data'])) - items.append(dict['data']) - - global database - #print("{} {} {}".format(type(database), len(database), database)) - print("lines={}".format(app.config['lines'])) - #if(len(database) >= 20): - if(len(database) >= app.config['lines']): - database.pop(0) - database.append(items) - - data = json.dumps(['result', 'ok']) - return data - -if __name__ == "__main__": - parser = argparse.ArgumentParser() - parser.add_argument('-port', type=int, default=8000) - parser.add_argument('-lines', type=int, default=20) - args = parser.parse_args() - print("port={}".format(args.port)) - print("lines={}".format(args.lines)) - app.config['lines'] = args.lines - #app.run() - app.run(host='127.0.0.1', port=args.port, debug=True) - +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Simple REST Server + +import os +import sys +import json +import datetime +import argparse +from flask import Flask, request, render_template +app = Flask(__name__) + +database = [] + +@app.route("/") +def root(): + global database + items = [] + for data in database: + #print("{}".format(data)) + datetime = data[0].split() + #print("data={} datetime={}".format(data[0], datetime)) + + items.append({ + "date": datetime[0], + "time": datetime[1], + "id": data[1], + "frame": data[2], + "value": data[3] + }) + #print("items={}".format(items)) + return render_template("index.html", lines=app.config['lines'], items=items) + +#curl -X POST -H "Content-Type: application/json" -d '{"canid":101, "frame":"standard" , "data": [1,2,3,4,5,6,7,8]}' http://192.168.10.43:8000/post +@app.route("/post", methods=["POST"]) +def post(): + function = sys._getframe().f_code.co_name + #print("{}: request={}".format(function, request)) + #print("{}: request.data={}".format(function, request.data)) + dict = json.loads(request.data) + print("{} dict={}".format(function, dict)) + + items = [] + now = datetime.datetime.now() + items.append(now.strftime("%Y/%m/%d %H:%M:%S")) + if ("canid" in dict): + print("{} canid=0x{:x}".format(function, dict['canid'])) + items.append(dict['canid']) + + if ("frame" in dict): + print("{} frame={}".format(function, dict['frame'])) + items.append(dict['frame']) + + if ("data" in dict): + print("{} data length={}".format(function, len(dict['data']))) + print("{} data={}".format(function, dict['data'])) + items.append(dict['data']) + + global database + #print("{} {} {}".format(type(database), len(database), database)) + print("lines={}".format(app.config['lines'])) + #if(len(database) >= 20): + if(len(database) >= app.config['lines']): + database.pop(0) + database.append(items) + + data = json.dumps(['result', 'ok']) + return data + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('-port', type=int, default=8000) + parser.add_argument('-lines', type=int, default=20) + args = parser.parse_args() + print("port={}".format(args.port)) + print("lines={}".format(args.lines)) + app.config['lines'] = args.lines + #app.run() + app.run(host='127.0.0.1', port=args.port, debug=True) + diff --git a/flask/templates/index.html b/flask/templates/index.html index f11c22f..c82f4fc 100644 --- a/flask/templates/index.html +++ b/flask/templates/index.html @@ -1,35 +1,35 @@ - - - - - CAN DATA - - - - Display the latest {{ lines }} records.
- If you want to see more, specify the number of lines at startup.
- - - - - - - - - - - - {% for i in items %} - - - - - - - - {% endfor %} - -
DateTimeIDFrameValue
{{ i.date }}{{ i.time }}{{ i.id }}{{ i.frame }}{{ i.value }}
- - - + + + + + CAN DATA + + + + Display the latest {{ lines }} records.
+ If you want to see more, specify the number of lines at startup.
+ + + + + + + + + + + + {% for i in items %} + + + + + + + + {% endfor %} + +
DateTimeIDFrameValue
{{ i.date }}{{ i.time }}{{ i.id }}{{ i.frame }}{{ i.value }}
+ + + diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 56a880f..c629fec 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ -set(COMPONENT_SRCS "main.c" "http_post.c" "http_server.c" "twai.c") -set(COMPONENT_ADD_INCLUDEDIRS ".") - -register_component() +set(COMPONENT_SRCS "main.c" "http_post.c" "http_server.c" "twai.c") +set(COMPONENT_ADD_INCLUDEDIRS ".") + +register_component() diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 1ceef57..b23e4be 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -1,152 +1,152 @@ -menu "Sillyfilly-CAN Configuration" - - config GPIO_RANGE_MAX - int - default 33 if IDF_TARGET_ESP32 - default 46 if IDF_TARGET_ESP32S2 - default 48 if IDF_TARGET_ESP32S3 - default 19 if IDF_TARGET_ESP32C3 - default 30 if IDF_TARGET_ESP32C6 - - menu "CAN Setting" - - choice CAN_BITRATE - prompt "CAN Bitrate" - default CAN_BITRATE_500 - help - Select the CAN bitrate for the example. - config CAN_BITRATE_25 - bool "BITRATE_25" - help - CAN bitrate is 25 Kbit/s. - config CAN_BITRATE_50 - bool "BITRATE_50" - help - CAN bitrate is 50 Kbit/s. - config CAN_BITRATE_100 - bool "BITRATE_100" - help - CAN bitrate is 100 Kbit/s. - config CAN_BITRATE_125 - bool "BITRATE_125" - help - CAN bitrate is 125 Kbit/s. - config CAN_BITRATE_250 - bool "BITRATE_250" - help - CAN bitrate is 250 Kbit/s. - config CAN_BITRATE_500 - bool "BITRATE_500" - help - CAN bitrate is 500 Kbit/s. - config CAN_BITRATE_800 - bool "BITRATE_800" - help - CAN bitrate is 800 Kbit/s. - config CAN_BITRATE_1000 - bool "BITRATE_1000" - help - CAN bitrate is 1 Mbit/s. - endchoice - - config CTX_GPIO - int "CTX GPIO number" - range 0 GPIO_RANGE_MAX - default 21 if IDF_TARGET_ESP32 - default 17 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 - default 0 # C3 and others - help - GPIO number (IOxx) to CTX. - Some GPIOs are used for other purposes (flash connections, etc.). - GPIOs 35-39 are input-only so cannot be used as outputs. - - config CRX_GPIO - int "CRX GPIO number" - range 0 GPIO_RANGE_MAX - default 22 if IDF_TARGET_ESP32 - default 18 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 - default 1 # C3 and others - help - GPIO number (IOxx) to CRX. - Some GPIOs are used for other purposes (flash connections, etc.). - GPIOs 35-39 are input-only so cannot be used as outputs. - - config ENABLE_PRINT - bool "Output the received CAN FRAME to STDOUT" - default true - help - Output the received CAN FRAME to STDOUT. - - endmenu - - menu "WiFi Setting" - - config ESP_WIFI_SSID - string "WiFi SSID" - default "wifi-name" - help - SSID (network name) to connect to. - - config ESP_WIFI_PASSWORD - string "WiFi Password" - default "wifi-password" - help - WiFi password (WPA or WPA2) to connect to. - - config ESP_MAXIMUM_RETRY - int "Maximum retry" - default 5 - help - Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. - - config MDNS_HOSTNAME - string "mDNS Hostname" - default "esp32-can-server" - help - The mDNS host name used by the ESP32. - - config STATIC_IP - bool "Enable Static IP Address" - default false - help - Enable Static IP Address. - - config STATIC_IP_ADDRESS - depends on STATIC_IP - string "Static IP Address" - default "192.168.10.100" - help - Static IP Address for Station. - - config STATIC_GW_ADDRESS - depends on STATIC_IP - string "Static GW Address" - default "192.168.10.1" - help - Static GW Address for Station. - - config STATIC_NM_ADDRESS - depends on STATIC_IP - string "Static Netmask" - default "255.255.255.0" - help - Static Netmask for Station. - - endmenu - - menu "HTTP Server Setting" - - config WEB_SERVER - string "HTTP Server IP or mDNS" - default "esp32-can-server" - help - The host name or IP address of the HTTP server to use. - - config WEB_PORT - int "HTTP Server Port" - default 8000 - help - HTTP server port to use. - - endmenu -endmenu +menu "Sillyfilly-CAN Configuration" + + config GPIO_RANGE_MAX + int + default 33 if IDF_TARGET_ESP32 + default 46 if IDF_TARGET_ESP32S2 + default 48 if IDF_TARGET_ESP32S3 + default 19 if IDF_TARGET_ESP32C3 + default 30 if IDF_TARGET_ESP32C6 + + menu "CAN Setting" + + choice CAN_BITRATE + prompt "CAN Bitrate" + default CAN_BITRATE_500 + help + Select the CAN bitrate for the example. + config CAN_BITRATE_25 + bool "BITRATE_25" + help + CAN bitrate is 25 Kbit/s. + config CAN_BITRATE_50 + bool "BITRATE_50" + help + CAN bitrate is 50 Kbit/s. + config CAN_BITRATE_100 + bool "BITRATE_100" + help + CAN bitrate is 100 Kbit/s. + config CAN_BITRATE_125 + bool "BITRATE_125" + help + CAN bitrate is 125 Kbit/s. + config CAN_BITRATE_250 + bool "BITRATE_250" + help + CAN bitrate is 250 Kbit/s. + config CAN_BITRATE_500 + bool "BITRATE_500" + help + CAN bitrate is 500 Kbit/s. + config CAN_BITRATE_800 + bool "BITRATE_800" + help + CAN bitrate is 800 Kbit/s. + config CAN_BITRATE_1000 + bool "BITRATE_1000" + help + CAN bitrate is 1 Mbit/s. + endchoice + + config CTX_GPIO + int "CTX GPIO number" + range 0 GPIO_RANGE_MAX + default 21 if IDF_TARGET_ESP32 + default 17 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 0 # C3 and others + help + GPIO number (IOxx) to CTX. + Some GPIOs are used for other purposes (flash connections, etc.). + GPIOs 35-39 are input-only so cannot be used as outputs. + + config CRX_GPIO + int "CRX GPIO number" + range 0 GPIO_RANGE_MAX + default 22 if IDF_TARGET_ESP32 + default 18 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3 + default 1 # C3 and others + help + GPIO number (IOxx) to CRX. + Some GPIOs are used for other purposes (flash connections, etc.). + GPIOs 35-39 are input-only so cannot be used as outputs. + + config ENABLE_PRINT + bool "Output the received CAN FRAME to STDOUT" + default true + help + Output the received CAN FRAME to STDOUT. + + endmenu + + menu "WiFi Setting" + + config ESP_WIFI_SSID + string "WiFi SSID" + default "wifi-name" + help + SSID (network name) to connect to. + + config ESP_WIFI_PASSWORD + string "WiFi Password" + default "wifi-password" + help + WiFi password (WPA or WPA2) to connect to. + + config ESP_MAXIMUM_RETRY + int "Maximum retry" + default 5 + help + Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent. + + config MDNS_HOSTNAME + string "mDNS Hostname" + default "esp32-can-server" + help + The mDNS host name used by the ESP32. + + config STATIC_IP + bool "Enable Static IP Address" + default false + help + Enable Static IP Address. + + config STATIC_IP_ADDRESS + depends on STATIC_IP + string "Static IP Address" + default "192.168.10.100" + help + Static IP Address for Station. + + config STATIC_GW_ADDRESS + depends on STATIC_IP + string "Static GW Address" + default "192.168.10.1" + help + Static GW Address for Station. + + config STATIC_NM_ADDRESS + depends on STATIC_IP + string "Static Netmask" + default "255.255.255.0" + help + Static Netmask for Station. + + endmenu + + menu "HTTP Server Setting" + + config WEB_SERVER + string "HTTP Server IP or mDNS" + default "esp32-can-server" + help + The host name or IP address of the HTTP server to use. + + config WEB_PORT + int "HTTP Server Port" + default 8000 + help + HTTP server port to use. + + endmenu +endmenu diff --git a/main/component.mk b/main/component.mk index b4fa727..af5e65b 100644 --- a/main/component.mk +++ b/main/component.mk @@ -1,4 +1,4 @@ -# -# Main Makefile. This is basically the same as a component makefile. -# -# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) +# +# Main Makefile. This is basically the same as a component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/main/http_post.c b/main/http_post.c index f58360e..600c528 100644 --- a/main/http_post.c +++ b/main/http_post.c @@ -1,199 +1,199 @@ -/* ESP HTTP Client Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_log.h" -#include "esp_system.h" -#include "esp_tls.h" -#include "esp_http_client.h" - -#include "cJSON.h" - -#include "twai.h" - -static const char *TAG = "HTTP"; - -extern QueueHandle_t xQueue_http_client; - -esp_err_t _http_event_handler(esp_http_client_event_t *evt) -{ - static char *output_buffer; // Buffer to store response of http request from event handler - static int output_len; // Stores number of bytes read - switch(evt->event_id) { - case HTTP_EVENT_ERROR: - ESP_LOGD(TAG, "HTTP_EVENT_ERROR"); - break; - case HTTP_EVENT_ON_CONNECTED: - ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); - break; - case HTTP_EVENT_HEADER_SENT: - ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); - break; - case HTTP_EVENT_ON_HEADER: - ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); - break; - case HTTP_EVENT_ON_DATA: - ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); - /* - * Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data. - * However, event handler can also be used in case chunked encoding is used. - */ - if (!esp_http_client_is_chunked_response(evt->client)) { - // If user_data buffer is configured, copy the response into the buffer - if (evt->user_data) { - memcpy(evt->user_data + output_len, evt->data, evt->data_len); - } else { - if (output_buffer == NULL) { - output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client)); - output_len = 0; - if (output_buffer == NULL) { - ESP_LOGE(TAG, "Failed to allocate memory for output buffer"); - return ESP_FAIL; - } - } - memcpy(output_buffer + output_len, evt->data, evt->data_len); - } - output_len += evt->data_len; - } - - break; - case HTTP_EVENT_ON_FINISH: - ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); - if (output_buffer != NULL) { - // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response - // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len); - free(output_buffer); - output_buffer = NULL; - } - output_len = 0; - break; - case HTTP_EVENT_DISCONNECTED: - ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED"); - int mbedtls_err = 0; - esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL); - if (err != 0) { - if (output_buffer != NULL) { - free(output_buffer); - output_buffer = NULL; - } - output_len = 0; - ESP_LOGI(TAG, "Last esp error code: 0x%x", err); - ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err); - } - break; -#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) - case HTTP_EVENT_REDIRECT: - ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT"); - esp_http_client_set_header(evt->client, "From", "user@example.com"); - esp_http_client_set_header(evt->client, "Accept", "text/html"); - break; -#endif - } - return ESP_OK; -} - -#define MAX_HTTP_OUTPUT_BUFFER 2048 - -static void http_rest_with_url(char * path, char * post_data) -{ - ESP_LOGI(TAG, "path=[%s]", path); - char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; - /** - * NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters. - * If host and path parameters are not set, query parameter will be ignored. In such cases, - * query parameter should be specified in URL. - * - * If URL as well as host and path parameters are specified, values of host and path will be considered. - */ -#if 1 - esp_http_client_config_t config = { - .host = CONFIG_WEB_SERVER, - .port = CONFIG_WEB_PORT, - .path = path, - .event_handler = _http_event_handler, - .user_data = local_response_buffer, // Pass address of local buffer to get response - .disable_auto_redirect = true, - }; -#else - // Same as above - esp_http_client_config_t config = { - .url = "http://http-server.local:8000/post", - .event_handler = _http_event_handler, - .user_data = local_response_buffer, // Pass address of local buffer to get response - .disable_auto_redirect = true, - }; -#endif - esp_http_client_handle_t client = esp_http_client_init(&config); - - // POST - // no need to change url - //esp_http_client_set_url(client, "http://192.168.10.43:8000/post"); - esp_http_client_set_method(client, HTTP_METHOD_POST); - esp_http_client_set_header(client, "Content-Type", "application/json"); - esp_http_client_set_post_field(client, post_data, strlen(post_data)); - esp_err_t err = esp_http_client_perform(client); - if (err == ESP_OK) { - ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %lld", - esp_http_client_get_status_code(client), - (int64_t)esp_http_client_get_content_length(client)); - ESP_LOGI(TAG, "local_response_buffer=[%s]", local_response_buffer); - } else { - ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err)); - } - - esp_http_client_cleanup(client); -} - - -void http_client_task(void *pvParameters) -{ - ESP_LOGI(TAG, "Start HTTP Client: connect to http://%s:%d", CONFIG_WEB_SERVER, CONFIG_WEB_PORT); - FRAME_t frameBuf; - while (1) { - xQueueReceive(xQueue_http_client, &frameBuf, portMAX_DELAY); - ESP_LOGI(TAG, "canid=%"PRIx32" ext=%d topic=[%s]", frameBuf.canid, frameBuf.ext, frameBuf.topic); - for(int i=0;i +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "esp_system.h" +#include "esp_tls.h" +#include "esp_http_client.h" + +#include "cJSON.h" + +#include "twai.h" + +static const char *TAG = "HTTP"; + +extern QueueHandle_t xQueue_http_client; + +esp_err_t _http_event_handler(esp_http_client_event_t *evt) +{ + static char *output_buffer; // Buffer to store response of http request from event handler + static int output_len; // Stores number of bytes read + switch(evt->event_id) { + case HTTP_EVENT_ERROR: + ESP_LOGD(TAG, "HTTP_EVENT_ERROR"); + break; + case HTTP_EVENT_ON_CONNECTED: + ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED"); + break; + case HTTP_EVENT_HEADER_SENT: + ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT"); + break; + case HTTP_EVENT_ON_HEADER: + ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value); + break; + case HTTP_EVENT_ON_DATA: + ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len); + /* + * Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data. + * However, event handler can also be used in case chunked encoding is used. + */ + if (!esp_http_client_is_chunked_response(evt->client)) { + // If user_data buffer is configured, copy the response into the buffer + if (evt->user_data) { + memcpy(evt->user_data + output_len, evt->data, evt->data_len); + } else { + if (output_buffer == NULL) { + output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client)); + output_len = 0; + if (output_buffer == NULL) { + ESP_LOGE(TAG, "Failed to allocate memory for output buffer"); + return ESP_FAIL; + } + } + memcpy(output_buffer + output_len, evt->data, evt->data_len); + } + output_len += evt->data_len; + } + + break; + case HTTP_EVENT_ON_FINISH: + ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH"); + if (output_buffer != NULL) { + // Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response + // ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len); + free(output_buffer); + output_buffer = NULL; + } + output_len = 0; + break; + case HTTP_EVENT_DISCONNECTED: + ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED"); + int mbedtls_err = 0; + esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL); + if (err != 0) { + if (output_buffer != NULL) { + free(output_buffer); + output_buffer = NULL; + } + output_len = 0; + ESP_LOGI(TAG, "Last esp error code: 0x%x", err); + ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err); + } + break; +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) + case HTTP_EVENT_REDIRECT: + ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT"); + esp_http_client_set_header(evt->client, "From", "user@example.com"); + esp_http_client_set_header(evt->client, "Accept", "text/html"); + break; +#endif + } + return ESP_OK; +} + +#define MAX_HTTP_OUTPUT_BUFFER 2048 + +static void http_rest_with_url(char * path, char * post_data) +{ + ESP_LOGI(TAG, "path=[%s]", path); + char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; + /** + * NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters. + * If host and path parameters are not set, query parameter will be ignored. In such cases, + * query parameter should be specified in URL. + * + * If URL as well as host and path parameters are specified, values of host and path will be considered. + */ +#if 1 + esp_http_client_config_t config = { + .host = CONFIG_WEB_SERVER, + .port = CONFIG_WEB_PORT, + .path = path, + .event_handler = _http_event_handler, + .user_data = local_response_buffer, // Pass address of local buffer to get response + .disable_auto_redirect = true, + }; +#else + // Same as above + esp_http_client_config_t config = { + .url = "http://http-server.local:8000/post", + .event_handler = _http_event_handler, + .user_data = local_response_buffer, // Pass address of local buffer to get response + .disable_auto_redirect = true, + }; +#endif + esp_http_client_handle_t client = esp_http_client_init(&config); + + // POST + // no need to change url + //esp_http_client_set_url(client, "http://192.168.10.43:8000/post"); + esp_http_client_set_method(client, HTTP_METHOD_POST); + esp_http_client_set_header(client, "Content-Type", "application/json"); + esp_http_client_set_post_field(client, post_data, strlen(post_data)); + esp_err_t err = esp_http_client_perform(client); + if (err == ESP_OK) { + ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %lld", + esp_http_client_get_status_code(client), + (int64_t)esp_http_client_get_content_length(client)); + ESP_LOGI(TAG, "local_response_buffer=[%s]", local_response_buffer); + } else { + ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err)); + } + + esp_http_client_cleanup(client); +} + + +void http_client_task(void *pvParameters) +{ + ESP_LOGI(TAG, "Start HTTP Client: connect to http://%s:%d", CONFIG_WEB_SERVER, CONFIG_WEB_PORT); + FRAME_t frameBuf; + while (1) { + xQueueReceive(xQueue_http_client, &frameBuf, portMAX_DELAY); + ESP_LOGI(TAG, "canid=%"PRIx32" ext=%d topic=[%s]", frameBuf.canid, frameBuf.ext, frameBuf.topic); + for(int i=0;i -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include "esp_log.h" -#include "esp_err.h" -#include "esp_vfs.h" -#include "esp_spiffs.h" -#include "esp_http_server.h" -#include "esp_chip_info.h" -#include "cJSON.h" -#include "driver/twai.h" -#include "twai.h" - -#define SCRATCH_BUFSIZE (1024) - -#define TAG "HTTP_SERVER" - -int pointer = 0; -static char *base_path = "/spiffs"; - -extern QueueHandle_t xQueue_twai_tx; -extern char* twai_string_buf; -extern int twai_allocation_size; -extern char* file_read_buf; -extern int allocation_size; - -typedef struct rest_server_context { - char base_path[ESP_VFS_PATH_MAX + 1]; // Not used in this project - char scratch[SCRATCH_BUFSIZE]; -} rest_server_context_t; - -esp_err_t readFile(char *ifile) { - int c; - ESP_LOGI(TAG, "File read llocated memory confirmed!: %d bytes", allocation_size); - char *spiffspath = "/spiffs"; - int buflen = strlen(spiffspath)+strlen(ifile)+1; - char buf[buflen]; - snprintf(buf, sizeof(buf), "%s%s", spiffspath, ifile); - ESP_LOGI(TAG, "buflen: %d, spiffspath: %s, ifile: %s, buf: %s, base_path: %s",buflen,spiffspath,ifile,buf,base_path); - FILE* f = fopen(buf, "r"); - ESP_LOGI(TAG, "Begin reading file"); - int i = 0; - while ((c = fgetc(f)) != EOF) { - file_read_buf[i] = c; - i++; - }; - file_read_buf[i] = '\0'; - fclose(f); - ESP_LOGI(TAG, "Read File - Iterations: %d", i); - return ESP_OK; -} - -/* Handler for roor get handler */ -esp_err_t root_get_handler(httpd_req_t *req) -{ - ESP_LOGI(TAG, "root_get_handler req->uri=[%s]", req->uri); - readFile("/index.html"); - esp_err_t sendcheck = httpd_resp_send(req, file_read_buf, HTTPD_RESP_USE_STRLEN); - //httpd_resp_sendstr_chunk(req, NULL); - - if(sendcheck == ESP_OK) { - //free(file_read_buf); - memset(twai_string_buf, '\0', allocation_size); - ESP_LOGI(TAG, "malloc freed"); - return ESP_OK; - } else { - return ESP_ERR_HTTPD_RESP_SEND; - } - - return ESP_OK; -} - -static esp_err_t twai_read_handler(httpd_req_t *req) -{ - httpd_resp_sendstr(req, twai_string_buf); - // Buffers returned by cJSON_Print must be freed by the caller. - // Please use the proper API (cJSON_free) rather than directly - //twai_string_buf = {0}; - memset(twai_string_buf, '\0', twai_allocation_size); - return ESP_OK; -} - -/* Handler for getting system information handler */ -// curl 'http://esp32-can-server:8000/api/system/info' | python -m json.tool -static esp_err_t system_info_get_handler(httpd_req_t *req) -{ - ESP_LOGI(TAG, "system_info_get_handler req->uri=[%s]", req->uri); - httpd_resp_set_type(req, "application/json"); - cJSON *root = cJSON_CreateObject(); - esp_chip_info_t chip_info; - esp_chip_info(&chip_info); - cJSON_AddStringToObject(root, "version", IDF_VER); - cJSON_AddNumberToObject(root, "cores", chip_info.cores); - //const char *sys_info = cJSON_Print(root); - char *sys_info = cJSON_Print(root); - httpd_resp_sendstr(req, sys_info); - // Buffers returned by cJSON_Print must be freed by the caller. - // Please use the proper API (cJSON_free) rather than directly calling stdlib free. - cJSON_free(sys_info); - cJSON_Delete(root); - return ESP_OK; -} - - -// Create array -cJSON *Create_array_of_anything(cJSON **objects,int array_num) -{ - cJSON *prev = 0; - cJSON *root; - root = cJSON_CreateArray(); - for (int i=0;ichild=objects[i]; - } else { - prev->next=objects[i]; - objects[i]->prev=prev; - } - prev=objects[i]; - } - return root; -} - -char *JSON_Types(int type) { - if (type == cJSON_Invalid) return ("cJSON_Invalid"); - if (type == cJSON_False) return ("cJSON_False"); - if (type == cJSON_True) return ("cJSON_True"); - if (type == cJSON_NULL) return ("cJSON_NULL"); - if (type == cJSON_Number) return ("cJSON_Number"); - if (type == cJSON_String) return ("cJSON_String"); - if (type == cJSON_Array) return ("cJSON_Array"); - if (type == cJSON_Object) return ("cJSON_Object"); - if (type == cJSON_Raw) return ("cJSON_Raw"); - return NULL; -} - -/* Handler for twai send handler */ -// curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [11, 12, 13, 14]}' http://esp32-server.local:8000/api/twai/send -static esp_err_t twai_send_handler(httpd_req_t *req) -{ - ESP_LOGI(TAG, "twai_send_handler req->uri=[%s]", req->uri); - int total_len = req->content_len; - int cur_len = 0; - char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; - int received = 0; - if (total_len >= SCRATCH_BUFSIZE) { - /* Respond with 500 Internal Server Error */ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); - return ESP_FAIL; - } - while (cur_len < total_len) { - received = httpd_req_recv(req, buf + cur_len, total_len); - if (received <= 0) { - /* Respond with 500 Internal Server Error */ - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); - return ESP_FAIL; - } - cur_len += received; - } - buf[total_len] = '\0'; - ESP_LOGI(TAG, "buf=[%s]", buf); - - - bool parse = true; - cJSON *root = cJSON_Parse(buf); - - // Search canid item - int32_t canid = 0; - cJSON* state = cJSON_GetObjectItem(root, "canid"); - if (state) { - canid = cJSON_GetObjectItem(root, "canid")->valueint; - ESP_LOGI(TAG, "canid=%"PRIx32, canid); - } else { - ESP_LOGE(TAG, "canid item not found"); - parse = false; - } - - // Search frame item - char frameStr[12]; - uint16_t frame = 0; - state = cJSON_GetObjectItem(root, "frame"); - if (state) { - strcpy(frameStr, cJSON_GetObjectItem(root,"frame")->valuestring); - ESP_LOGI(TAG, "frameStr=[%s]", frameStr); - if (strcmp(frameStr, "standard") != 0 && strcmp(frameStr, "extended") != 0 ) { - ESP_LOGE(TAG, "frame item not correct"); - parse = false; - } else { - if (strcmp(frameStr, "standard") == 0) frame = STANDARD_FRAME; - if (strcmp(frameStr, "extended") == 0) frame = EXTENDED_FRAME; - } - } else { - ESP_LOGE(TAG, "frame item not found"); - parse = false; - } - - // Search data item - int16_t data_len; - char data_value[8]; - state = cJSON_GetObjectItem(root, "data"); - if (state) { - cJSON *data_array = cJSON_GetObjectItem(root,"data"); - ESP_LOGI(TAG, "data_array->type=%s", JSON_Types(data_array->type)); - if (data_array->type == cJSON_Array) { - int data_array_size = cJSON_GetArraySize(data_array); - ESP_LOGI(TAG, "data_array_size=%d", data_array_size); - bool data_valid = true; - data_len = data_array_size; - if (data_array_size > 8) { - ESP_LOGW(TAG, "Too many data arrays : %d", data_array_size); - data_len = 8; - } - for (int i=0;itype=%s", JSON_Types(array->type)); - uint16_t data_int = array->valueint; - ESP_LOGI(TAG, "data_int[%d]=%x", i, data_int); - if (data_int <= 0xff) { - data_value[i] = data_int; - } else { - ESP_LOGE(TAG, "Too large data value : %x", data_int); - data_valid = false; - } - } // end for - if (data_valid == false) { - parse = false; - } - } else { - ESP_LOGE(TAG, "data item not array"); - parse = false; - } // end if - - - } else { - ESP_LOGE(TAG, "data item not found"); - parse = false; - } - - cJSON_Delete(root); - - // JSON parse success. Send twai data. - if (parse) { - ESP_LOGI(TAG, "twai_send_handler frame=%d canid=%"PRIx32" data_len=%d", frame, canid, data_len); - ESP_LOG_BUFFER_HEX(TAG, data_value, data_len); - twai_message_t tx_msg; - tx_msg.extd = frame; - tx_msg.ss = 1; - tx_msg.self = 0; - tx_msg.dlc_non_comp = 0; - tx_msg.identifier = canid; - tx_msg.data_length_code = data_len; - for (int i=0;i +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "esp_log.h" +#include "esp_err.h" +#include "esp_vfs.h" +#include "esp_spiffs.h" +#include "esp_http_server.h" +#include "esp_chip_info.h" +#include "cJSON.h" +#include "driver/twai.h" +#include "twai.h" + +#define SCRATCH_BUFSIZE (1024) + +#define TAG "HTTP_SERVER" + +int pointer = 0; +static char *base_path = "/spiffs"; + +extern QueueHandle_t xQueue_twai_tx; +extern char* twai_string_buf; +extern int twai_allocation_size; +extern char* file_read_buf; +extern int allocation_size; + +typedef struct rest_server_context { + char base_path[ESP_VFS_PATH_MAX + 1]; // Not used in this project + char scratch[SCRATCH_BUFSIZE]; +} rest_server_context_t; + +esp_err_t readFile(char *ifile) { + int c; + ESP_LOGI(TAG, "File read llocated memory confirmed!: %d bytes", allocation_size); + char *spiffspath = "/spiffs"; + int buflen = strlen(spiffspath)+strlen(ifile)+1; + char buf[buflen]; + snprintf(buf, sizeof(buf), "%s%s", spiffspath, ifile); + ESP_LOGI(TAG, "buflen: %d, spiffspath: %s, ifile: %s, buf: %s, base_path: %s",buflen,spiffspath,ifile,buf,base_path); + FILE* f = fopen(buf, "r"); + ESP_LOGI(TAG, "Begin reading file"); + int i = 0; + while ((c = fgetc(f)) != EOF) { + file_read_buf[i] = c; + i++; + }; + file_read_buf[i] = '\0'; + fclose(f); + ESP_LOGI(TAG, "Read File - Iterations: %d", i); + return ESP_OK; +} + +/* Handler for roor get handler */ +esp_err_t root_get_handler(httpd_req_t *req) +{ + ESP_LOGI(TAG, "root_get_handler req->uri=[%s]", req->uri); + readFile("/index.html"); + esp_err_t sendcheck = httpd_resp_send(req, file_read_buf, HTTPD_RESP_USE_STRLEN); + //httpd_resp_sendstr_chunk(req, NULL); + + if(sendcheck == ESP_OK) { + //free(file_read_buf); + memset(twai_string_buf, '\0', allocation_size); + ESP_LOGI(TAG, "malloc freed"); + return ESP_OK; + } else { + return ESP_ERR_HTTPD_RESP_SEND; + } + + return ESP_OK; +} + +static esp_err_t twai_read_handler(httpd_req_t *req) +{ + httpd_resp_sendstr(req, twai_string_buf); + // Buffers returned by cJSON_Print must be freed by the caller. + // Please use the proper API (cJSON_free) rather than directly + //twai_string_buf = {0}; + memset(twai_string_buf, '\0', twai_allocation_size); + return ESP_OK; +} + +/* Handler for getting system information handler */ +// curl 'http://esp32-can-server:8000/api/system/info' | python -m json.tool +static esp_err_t system_info_get_handler(httpd_req_t *req) +{ + ESP_LOGI(TAG, "system_info_get_handler req->uri=[%s]", req->uri); + httpd_resp_set_type(req, "application/json"); + cJSON *root = cJSON_CreateObject(); + esp_chip_info_t chip_info; + esp_chip_info(&chip_info); + cJSON_AddStringToObject(root, "version", IDF_VER); + cJSON_AddNumberToObject(root, "cores", chip_info.cores); + //const char *sys_info = cJSON_Print(root); + char *sys_info = cJSON_Print(root); + httpd_resp_sendstr(req, sys_info); + // Buffers returned by cJSON_Print must be freed by the caller. + // Please use the proper API (cJSON_free) rather than directly calling stdlib free. + cJSON_free(sys_info); + cJSON_Delete(root); + return ESP_OK; +} + + +// Create array +cJSON *Create_array_of_anything(cJSON **objects,int array_num) +{ + cJSON *prev = 0; + cJSON *root; + root = cJSON_CreateArray(); + for (int i=0;ichild=objects[i]; + } else { + prev->next=objects[i]; + objects[i]->prev=prev; + } + prev=objects[i]; + } + return root; +} + +char *JSON_Types(int type) { + if (type == cJSON_Invalid) return ("cJSON_Invalid"); + if (type == cJSON_False) return ("cJSON_False"); + if (type == cJSON_True) return ("cJSON_True"); + if (type == cJSON_NULL) return ("cJSON_NULL"); + if (type == cJSON_Number) return ("cJSON_Number"); + if (type == cJSON_String) return ("cJSON_String"); + if (type == cJSON_Array) return ("cJSON_Array"); + if (type == cJSON_Object) return ("cJSON_Object"); + if (type == cJSON_Raw) return ("cJSON_Raw"); + return NULL; +} + +/* Handler for twai send handler */ +// curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [11, 12, 13, 14]}' http://esp32-server.local:8000/api/twai/send +static esp_err_t twai_send_handler(httpd_req_t *req) +{ + ESP_LOGI(TAG, "twai_send_handler req->uri=[%s]", req->uri); + int total_len = req->content_len; + int cur_len = 0; + char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch; + int received = 0; + if (total_len >= SCRATCH_BUFSIZE) { + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long"); + return ESP_FAIL; + } + while (cur_len < total_len) { + received = httpd_req_recv(req, buf + cur_len, total_len); + if (received <= 0) { + /* Respond with 500 Internal Server Error */ + httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value"); + return ESP_FAIL; + } + cur_len += received; + } + buf[total_len] = '\0'; + ESP_LOGI(TAG, "buf=[%s]", buf); + + + bool parse = true; + cJSON *root = cJSON_Parse(buf); + + // Search canid item + int32_t canid = 0; + cJSON* state = cJSON_GetObjectItem(root, "canid"); + if (state) { + canid = cJSON_GetObjectItem(root, "canid")->valueint; + ESP_LOGI(TAG, "canid=%"PRIx32, canid); + } else { + ESP_LOGE(TAG, "canid item not found"); + parse = false; + } + + // Search frame item + char frameStr[12]; + uint16_t frame = 0; + state = cJSON_GetObjectItem(root, "frame"); + if (state) { + strcpy(frameStr, cJSON_GetObjectItem(root,"frame")->valuestring); + ESP_LOGI(TAG, "frameStr=[%s]", frameStr); + if (strcmp(frameStr, "standard") != 0 && strcmp(frameStr, "extended") != 0 ) { + ESP_LOGE(TAG, "frame item not correct"); + parse = false; + } else { + if (strcmp(frameStr, "standard") == 0) frame = STANDARD_FRAME; + if (strcmp(frameStr, "extended") == 0) frame = EXTENDED_FRAME; + } + } else { + ESP_LOGE(TAG, "frame item not found"); + parse = false; + } + + // Search data item + int16_t data_len; + char data_value[8]; + state = cJSON_GetObjectItem(root, "data"); + if (state) { + cJSON *data_array = cJSON_GetObjectItem(root,"data"); + ESP_LOGI(TAG, "data_array->type=%s", JSON_Types(data_array->type)); + if (data_array->type == cJSON_Array) { + int data_array_size = cJSON_GetArraySize(data_array); + ESP_LOGI(TAG, "data_array_size=%d", data_array_size); + bool data_valid = true; + data_len = data_array_size; + if (data_array_size > 8) { + ESP_LOGW(TAG, "Too many data arrays : %d", data_array_size); + data_len = 8; + } + for (int i=0;itype=%s", JSON_Types(array->type)); + uint16_t data_int = array->valueint; + ESP_LOGI(TAG, "data_int[%d]=%x", i, data_int); + if (data_int <= 0xff) { + data_value[i] = data_int; + } else { + ESP_LOGE(TAG, "Too large data value : %x", data_int); + data_valid = false; + } + } // end for + if (data_valid == false) { + parse = false; + } + } else { + ESP_LOGE(TAG, "data item not array"); + parse = false; + } // end if + + + } else { + ESP_LOGE(TAG, "data item not found"); + parse = false; + } + + cJSON_Delete(root); + + // JSON parse success. Send twai data. + if (parse) { + ESP_LOGI(TAG, "twai_send_handler frame=%d canid=%"PRIx32" data_len=%d", frame, canid, data_len); + ESP_LOG_BUFFER_HEX(TAG, data_value, data_len); + twai_message_t tx_msg; + tx_msg.extd = frame; + tx_msg.ss = 1; + tx_msg.self = 0; + tx_msg.dlc_non_comp = 0; + tx_msg.identifier = canid; + tx_msg.data_length_code = data_len; + for (int i=0;i=5.0" +## IDF Component Manager Manifest File +dependencies: + espressif/mdns: + version: "^1.0.3" + rules: + - if: "idf_version >=5.0" diff --git a/main/init_malloci.h b/main/init_malloci.h index 7f517e7..8fa2f4f 100644 --- a/main/init_malloci.h +++ b/main/init_malloci.h @@ -1,8 +1,8 @@ -#define MAX_FILE_SIZE_KB 10 -#define MAX_TWAI_SIZE_KB 5 -#define MALLOCHI_TAG "INIT_MALLOCHI" - -char* file_read_buf; -char* twai_string_buf; -int allocation_size; +#define MAX_FILE_SIZE_KB 10 +#define MAX_TWAI_SIZE_KB 5 +#define MALLOCHI_TAG "INIT_MALLOCHI" + +char* file_read_buf; +char* twai_string_buf; +int allocation_size; int twai_allocation_size; \ No newline at end of file diff --git a/main/main.c b/main/main.c index 6a63b02..5be18ef 100644 --- a/main/main.c +++ b/main/main.c @@ -1,456 +1,456 @@ -/* - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include -#include -#include -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/event_groups.h" -#include "freertos/semphr.h" -#include "esp_system.h" -#include "esp_wifi.h" -#include "esp_event.h" -#include "esp_vfs.h" -#include "nvs_flash.h" -#include "esp_err.h" -#include "esp_log.h" -#include "esp_spiffs.h" -#include "mdns.h" -#include "lwip/dns.h" -#include "driver/twai.h" // Update from V4.2 -#include "twai.h" -#include "init_malloci.h" -#define TAG "MAIN" - -static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); - -#if CONFIG_CAN_BITRATE_25 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS(); -#define BITRATE "Bitrate is 25 Kbit/s" -#elif CONFIG_CAN_BITRATE_50 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_50KBITS(); -#define BITRATE "Bitrate is 50 Kbit/s" -#elif CONFIG_CAN_BITRATE_100 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_100KBITS(); -#define BITRATE "Bitrate is 100 Kbit/s" -#elif CONFIG_CAN_BITRATE_125 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS(); -#define BITRATE "Bitrate is 125 Kbit/s" -#elif CONFIG_CAN_BITRATE_250 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); -#define BITRATE "Bitrate is 250 Kbit/s" -#elif CONFIG_CAN_BITRATE_500 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); -#define BITRATE "Bitrate is 500 Kbit/s" -#elif CONFIG_CAN_BITRATE_800 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_800KBITS(); -#define BITRATE "Bitrate is 800 Kbit/s" -#elif CONFIG_CAN_BITRATE_1000 -static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); -#define BITRATE "Bitrate is 1 Mbit/s" -#endif - -/* FreeRTOS event group to signal when we are connected*/ -static EventGroupHandle_t s_wifi_event_group; - -/* The event group allows multiple bits for each event, but we only care about two events: - * - we are connected to the AP with an IP - * - we failed to connect after the maximum amount of retries */ -#define WIFI_CONNECTED_BIT BIT0 -#define WIFI_FAIL_BIT BIT1 - -static int s_retry_num = 0; -static char *base_path = "/spiffs"; - -QueueHandle_t xQueue_http_client; -QueueHandle_t xQueue_twai_tx; - -TOPIC_t *publish; -int16_t npublish; - -//extern char* twai_string_buf; -//extern esp_err_t init_twai_read_malloc(); - -static void event_handler(void* arg, esp_event_base_t event_base, - int32_t event_id, void* event_data) -{ - if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { - esp_wifi_connect(); - } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { - if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) { - esp_wifi_connect(); - s_retry_num++; - ESP_LOGI(TAG, "retry to connect to the AP"); - } else { - xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); - } - ESP_LOGI(TAG,"connect to the AP fail"); - } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { - ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; - ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); - s_retry_num = 0; - xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); - } -} - -void wifi_init_sta() -{ - s_wifi_event_group = xEventGroupCreate(); - - ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR); - ESP_LOGI(TAG,"ESP_IDF_VERSION %d", ESP_IDF_VERSION); - - ESP_ERROR_CHECK(esp_netif_init()); - ESP_ERROR_CHECK(esp_event_loop_create_default()); - esp_netif_t *netif = esp_netif_create_default_wifi_sta(); - assert(netif); - -#if CONFIG_STATIC_IP - - ESP_LOGI(TAG, "CONFIG_STATIC_IP_ADDRESS=[%s]",CONFIG_STATIC_IP_ADDRESS); - ESP_LOGI(TAG, "CONFIG_STATIC_GW_ADDRESS=[%s]",CONFIG_STATIC_GW_ADDRESS); - ESP_LOGI(TAG, "CONFIG_STATIC_NM_ADDRESS=[%s]",CONFIG_STATIC_NM_ADDRESS); - - /* Stop DHCP client */ - ESP_ERROR_CHECK(esp_netif_dhcpc_stop(netif)); - ESP_LOGI(TAG, "Stop DHCP Services"); - - /* Set STATIC IP Address */ - esp_netif_ip_info_t ip_info; - memset(&ip_info, 0 , sizeof(esp_netif_ip_info_t)); - ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDRESS); - ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_NM_ADDRESS); - ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GW_ADDRESS);; - esp_netif_set_ip_info(netif, &ip_info); - - /* - I referred from here. - https://www.esp32.com/viewtopic.php?t=5380 - if we should not be using DHCP (for example we are using static IP addresses), - then we need to instruct the ESP32 of the locations of the DNS servers manually. - Google publicly makes available two name servers with the addresses of 8.8.8.8 and 8.8.4.4. - */ - - ip_addr_t d; - d.type = IPADDR_TYPE_V4; - d.u_addr.ip4.addr = 0x08080808; //8.8.8.8 dns - dns_setserver(0, &d); - d.u_addr.ip4.addr = 0x08080404; //8.8.4.4 dns - dns_setserver(1, &d); - -#endif // CONFIG_STATIC_IP - - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK(esp_wifi_init(&cfg)); - - ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); - ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); - - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_ESP_WIFI_SSID, - .password = CONFIG_ESP_WIFI_PASSWORD - }, - }; - ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); - ESP_ERROR_CHECK(esp_wifi_start() ); - - ESP_LOGI(TAG, "wifi_init_sta finished."); - - /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum - * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ - EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, - WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, - pdFALSE, - pdFALSE, - portMAX_DELAY); - - /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually - * happened. */ - if (bits & WIFI_CONNECTED_BIT) { - ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); - } else if (bits & WIFI_FAIL_BIT) { - ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); - } else { - ESP_LOGE(TAG, "UNEXPECTED EVENT"); - } - vEventGroupDelete(s_wifi_event_group); -} - -void initialise_mdns(void) -{ - //initialize mDNS - ESP_ERROR_CHECK( mdns_init() ); - //set mDNS hostname (required if you want to advertise services) - ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) ); - ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME); - -#if 0 - //set default mDNS instance name - ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") ); -#endif -} - -esp_err_t mountSPIFFS(char * partition_label, char * base_path) { - ESP_LOGI(TAG, "Initializing SPIFFS file system"); - - esp_vfs_spiffs_conf_t conf = { - .base_path = base_path, - .partition_label = partition_label, - .max_files = 4, - .format_if_mount_failed = true - }; - // Use settings defined above to initialize and mount SPIFFS filesystem. - // Note: esp_vfs_spiffs_register is an all-in-one convenience function. - esp_err_t ret = esp_vfs_spiffs_register(&conf); - - if (ret != ESP_OK) { - if (ret == ESP_FAIL) { - ESP_LOGE(TAG, "Failed to mount or format filesystem"); - } else if (ret == ESP_ERR_NOT_FOUND) { - ESP_LOGE(TAG, "Failed to find SPIFFS partition"); - } else { - ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); - } - return ret; - } - - size_t total = 0, used = 0; - ret = esp_spiffs_info(partition_label, &total, &used); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); - } else { - ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); - DIR* dir = opendir(base_path); - assert(dir != NULL); - while (true) { - struct dirent*pe = readdir(dir); - if (!pe) break; - ESP_LOGI(TAG, "d_name=%s d_ino=%d d_type=%x", pe->d_name,pe->d_ino, pe->d_type); - } - closedir(dir); - } - ESP_LOGI(TAG, "Mount SPIFFS filesystem"); - return ret; -} - - -esp_err_t build_table(TOPIC_t **topics, char *file, int16_t *ntopic) -{ - ESP_LOGI(TAG, "build_table file=%s", file); - char line[128]; - int _ntopic = 0; - - FILE* f = fopen(file, "r"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for reading"); - return ESP_FAIL; - } - while (1){ - if ( fgets(line, sizeof(line) ,f) == 0 ) break; - // strip newline - char* pos = strchr(line, '\n'); - if (pos) { - *pos = '\0'; - } - ESP_LOGD(TAG, "line=[%s]", line); - if (strlen(line) == 0) continue; - if (line[0] == '#') continue; - _ntopic++; - } - fclose(f); - ESP_LOGI(TAG, "build_table _ntopic=%d", _ntopic); - - *topics = calloc(_ntopic, sizeof(TOPIC_t)); - if (*topics == NULL) { - ESP_LOGE(TAG, "Error allocating memory for topic"); - return ESP_ERR_NO_MEM; - } - - f = fopen(file, "r"); - if (f == NULL) { - ESP_LOGE(TAG, "Failed to open file for reading"); - return ESP_FAIL; - } - - char *ptr; - int index = 0; - while (1){ - if ( fgets(line, sizeof(line) ,f) == 0 ) break; - // strip newline - char* pos = strchr(line, '\n'); - if (pos) { - *pos = '\0'; - } - ESP_LOGD(TAG, "line=[%s]", line); - if (strlen(line) == 0) continue; - if (line[0] == '#') continue; - - // Frame type - ptr = strtok(line, ","); - ESP_LOGD(TAG, "ptr=%s", ptr); - if (strcmp(ptr, "S") == 0) { - (*topics+index)->frame = 0; - } else if (strcmp(ptr, "E") == 0) { - (*topics+index)->frame = 1; - } else { - ESP_LOGE(TAG, "This line is invalid [%s]", line); - continue; - } - - // CAN ID - uint32_t canid; - ptr = strtok(NULL, ","); - if(ptr == NULL) continue; - ESP_LOGD(TAG, "ptr=%s", ptr); - canid = strtol(ptr, NULL, 16); - if (canid == 0) { - ESP_LOGE(TAG, "This line is invalid [%s]", line); - continue; - } - (*topics+index)->canid = canid; - - // mqtt topic - char *sp; - ptr = strtok(NULL, ","); - if(ptr == NULL) { - ESP_LOGE(TAG, "This line is invalid [%s]", line); - continue; - } - ESP_LOGD(TAG, "ptr=[%s] strlen=%d", ptr, strlen(ptr)); - sp = strstr(ptr,"#"); - if (sp != NULL) { - ESP_LOGE(TAG, "This line is invalid [%s]", line); - continue; - } - sp = strstr(ptr,"+"); - if (sp != NULL) { - ESP_LOGE(TAG, "This line is invalid [%s]", line); - continue; - } - (*topics+index)->topic = (char *)malloc(strlen(ptr)+1); - strcpy((*topics+index)->topic, ptr); - (*topics+index)->topic_len = strlen(ptr); - index++; - } - fclose(f); - *ntopic = index; - return ESP_OK; -} - -void dump_table(TOPIC_t *topics, int16_t ntopic) -{ - for(int i=0;iframe, (topics+i)->canid, (topics+i)->topic, (topics+i)->topic_len); - } - -} - -esp_err_t init_file_malloc() { - allocation_size = (MAX_FILE_SIZE_KB*1024*sizeof(char)); - file_read_buf = (char*)malloc(allocation_size); - - if (file_read_buf == NULL) { - ESP_LOGE(MALLOCHI_TAG, "File read memory not allocated."); - return ESP_FAIL; - } else { - ESP_LOGI(MALLOCHI_TAG, "File read malloc succeeded! %d bytes allocated", allocation_size); - return ESP_OK; - } - - return ESP_OK; -} - -esp_err_t init_twai_read_malloc() { - twai_allocation_size = (sizeof(char)*1024*MAX_TWAI_SIZE_KB); - twai_string_buf = (char*)malloc(twai_allocation_size); - - if (twai_string_buf == NULL) { - ESP_LOGE(MALLOCHI_TAG, "TWAI memory not allocated."); - return ESP_FAIL; - } else { - ESP_LOGI(MALLOCHI_TAG, "TWAI malloc succeeded! %d bytes allocated", twai_allocation_size); - return ESP_OK; - } - return ESP_OK; -} - -void http_client_task(void *pvParameters); -void http_server_task(void *pvParameters); -void twai_task(void *pvParameters); - -void app_main() -{ - // Initialize NVS - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); - wifi_init_sta(); - initialise_mdns(); - init_twai_read_malloc(); - init_file_malloc(); - - // Install and start TWAI driver - ESP_LOGI(TAG, "%s",BITRATE); - ESP_LOGI(TAG, "CTX_GPIO=%d",CONFIG_CTX_GPIO); - ESP_LOGI(TAG, "CRX_GPIO=%d",CONFIG_CRX_GPIO); - - static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CONFIG_CTX_GPIO, CONFIG_CRX_GPIO, TWAI_MODE_NORMAL); - ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); - ESP_LOGI(TAG, "Driver installed"); - ESP_ERROR_CHECK(twai_start()); - ESP_LOGI(TAG, "Driver started"); - - // Mount SPIFFS - char *partition_label = "storage"; - //char *base_path = "/spiffs"; - ret = mountSPIFFS(partition_label, base_path); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "mountSPIFFS fail"); - while(1) { vTaskDelay(1); } - } - - // Create Queue - xQueue_http_client = xQueueCreate( 10, sizeof(FRAME_t) ); - configASSERT( xQueue_http_client ); - xQueue_twai_tx = xQueueCreate( 10, sizeof(twai_message_t) ); - configASSERT( xQueue_twai_tx ); - - // build publish table - ret = build_table(&publish, "/spiffs/can2http.csv", &npublish); - if (ret != ESP_OK) { - ESP_LOGE(TAG, "build publish table fail"); - while(1) { vTaskDelay(1); } - } - dump_table(publish, npublish); - - /* Get the local IP address */ - //tcpip_adapter_ip_info_t ip_info; - //ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info)); - esp_netif_ip_info_t ip_info; - ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info)); - - char cparam0[64]; - //sprintf(cparam0, "%s", ip4addr_ntoa(&ip_info.ip)); - sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip)); - xTaskCreate(http_server_task, "server", 1024*6, (void *)cparam0, 2, NULL); - - xTaskCreate(http_client_task, "client", 1024*6, NULL, 2, NULL); - xTaskCreate(twai_task, "twai_rx", 1024*6, NULL, 2, NULL); -} +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +#include +#include +#include +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/event_groups.h" +#include "freertos/semphr.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event.h" +#include "esp_vfs.h" +#include "nvs_flash.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_spiffs.h" +#include "mdns.h" +#include "lwip/dns.h" +#include "driver/twai.h" // Update from V4.2 +#include "twai.h" +#include "init_malloci.h" +#define TAG "MAIN" + +static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL(); + +#if CONFIG_CAN_BITRATE_25 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS(); +#define BITRATE "Bitrate is 25 Kbit/s" +#elif CONFIG_CAN_BITRATE_50 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_50KBITS(); +#define BITRATE "Bitrate is 50 Kbit/s" +#elif CONFIG_CAN_BITRATE_100 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_100KBITS(); +#define BITRATE "Bitrate is 100 Kbit/s" +#elif CONFIG_CAN_BITRATE_125 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS(); +#define BITRATE "Bitrate is 125 Kbit/s" +#elif CONFIG_CAN_BITRATE_250 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS(); +#define BITRATE "Bitrate is 250 Kbit/s" +#elif CONFIG_CAN_BITRATE_500 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS(); +#define BITRATE "Bitrate is 500 Kbit/s" +#elif CONFIG_CAN_BITRATE_800 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_800KBITS(); +#define BITRATE "Bitrate is 800 Kbit/s" +#elif CONFIG_CAN_BITRATE_1000 +static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS(); +#define BITRATE "Bitrate is 1 Mbit/s" +#endif + +/* FreeRTOS event group to signal when we are connected*/ +static EventGroupHandle_t s_wifi_event_group; + +/* The event group allows multiple bits for each event, but we only care about two events: + * - we are connected to the AP with an IP + * - we failed to connect after the maximum amount of retries */ +#define WIFI_CONNECTED_BIT BIT0 +#define WIFI_FAIL_BIT BIT1 + +static int s_retry_num = 0; +static char *base_path = "/spiffs"; + +QueueHandle_t xQueue_http_client; +QueueHandle_t xQueue_twai_tx; + +TOPIC_t *publish; +int16_t npublish; + +//extern char* twai_string_buf; +//extern esp_err_t init_twai_read_malloc(); + +static void event_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { + if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) { + esp_wifi_connect(); + s_retry_num++; + ESP_LOGI(TAG, "retry to connect to the AP"); + } else { + xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT); + } + ESP_LOGI(TAG,"connect to the AP fail"); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; + ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip)); + s_retry_num = 0; + xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); + } +} + +void wifi_init_sta() +{ + s_wifi_event_group = xEventGroupCreate(); + + ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR); + ESP_LOGI(TAG,"ESP_IDF_VERSION %d", ESP_IDF_VERSION); + + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + esp_netif_t *netif = esp_netif_create_default_wifi_sta(); + assert(netif); + +#if CONFIG_STATIC_IP + + ESP_LOGI(TAG, "CONFIG_STATIC_IP_ADDRESS=[%s]",CONFIG_STATIC_IP_ADDRESS); + ESP_LOGI(TAG, "CONFIG_STATIC_GW_ADDRESS=[%s]",CONFIG_STATIC_GW_ADDRESS); + ESP_LOGI(TAG, "CONFIG_STATIC_NM_ADDRESS=[%s]",CONFIG_STATIC_NM_ADDRESS); + + /* Stop DHCP client */ + ESP_ERROR_CHECK(esp_netif_dhcpc_stop(netif)); + ESP_LOGI(TAG, "Stop DHCP Services"); + + /* Set STATIC IP Address */ + esp_netif_ip_info_t ip_info; + memset(&ip_info, 0 , sizeof(esp_netif_ip_info_t)); + ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDRESS); + ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_NM_ADDRESS); + ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GW_ADDRESS);; + esp_netif_set_ip_info(netif, &ip_info); + + /* + I referred from here. + https://www.esp32.com/viewtopic.php?t=5380 + if we should not be using DHCP (for example we are using static IP addresses), + then we need to instruct the ESP32 of the locations of the DNS servers manually. + Google publicly makes available two name servers with the addresses of 8.8.8.8 and 8.8.4.4. + */ + + ip_addr_t d; + d.type = IPADDR_TYPE_V4; + d.u_addr.ip4.addr = 0x08080808; //8.8.8.8 dns + dns_setserver(0, &d); + d.u_addr.ip4.addr = 0x08080404; //8.8.4.4 dns + dns_setserver(1, &d); + +#endif // CONFIG_STATIC_IP + + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK(esp_wifi_init(&cfg)); + + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); + + wifi_config_t wifi_config = { + .sta = { + .ssid = CONFIG_ESP_WIFI_SSID, + .password = CONFIG_ESP_WIFI_PASSWORD + }, + }; + ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) ); + ESP_ERROR_CHECK(esp_wifi_start() ); + + ESP_LOGI(TAG, "wifi_init_sta finished."); + + /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum + * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ + EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, + WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, + pdFALSE, + pdFALSE, + portMAX_DELAY); + + /* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually + * happened. */ + if (bits & WIFI_CONNECTED_BIT) { + ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); + } else if (bits & WIFI_FAIL_BIT) { + ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD); + } else { + ESP_LOGE(TAG, "UNEXPECTED EVENT"); + } + vEventGroupDelete(s_wifi_event_group); +} + +void initialise_mdns(void) +{ + //initialize mDNS + ESP_ERROR_CHECK( mdns_init() ); + //set mDNS hostname (required if you want to advertise services) + ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) ); + ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME); + +#if 0 + //set default mDNS instance name + ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") ); +#endif +} + +esp_err_t mountSPIFFS(char * partition_label, char * base_path) { + ESP_LOGI(TAG, "Initializing SPIFFS file system"); + + esp_vfs_spiffs_conf_t conf = { + .base_path = base_path, + .partition_label = partition_label, + .max_files = 4, + .format_if_mount_failed = true + }; + // Use settings defined above to initialize and mount SPIFFS filesystem. + // Note: esp_vfs_spiffs_register is an all-in-one convenience function. + esp_err_t ret = esp_vfs_spiffs_register(&conf); + + if (ret != ESP_OK) { + if (ret == ESP_FAIL) { + ESP_LOGE(TAG, "Failed to mount or format filesystem"); + } else if (ret == ESP_ERR_NOT_FOUND) { + ESP_LOGE(TAG, "Failed to find SPIFFS partition"); + } else { + ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret)); + } + return ret; + } + + size_t total = 0, used = 0; + ret = esp_spiffs_info(partition_label, &total, &used); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret)); + } else { + ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used); + DIR* dir = opendir(base_path); + assert(dir != NULL); + while (true) { + struct dirent*pe = readdir(dir); + if (!pe) break; + ESP_LOGI(TAG, "d_name=%s d_ino=%d d_type=%x", pe->d_name,pe->d_ino, pe->d_type); + } + closedir(dir); + } + ESP_LOGI(TAG, "Mount SPIFFS filesystem"); + return ret; +} + + +esp_err_t build_table(TOPIC_t **topics, char *file, int16_t *ntopic) +{ + ESP_LOGI(TAG, "build_table file=%s", file); + char line[128]; + int _ntopic = 0; + + FILE* f = fopen(file, "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return ESP_FAIL; + } + while (1){ + if ( fgets(line, sizeof(line) ,f) == 0 ) break; + // strip newline + char* pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGD(TAG, "line=[%s]", line); + if (strlen(line) == 0) continue; + if (line[0] == '#') continue; + _ntopic++; + } + fclose(f); + ESP_LOGI(TAG, "build_table _ntopic=%d", _ntopic); + + *topics = calloc(_ntopic, sizeof(TOPIC_t)); + if (*topics == NULL) { + ESP_LOGE(TAG, "Error allocating memory for topic"); + return ESP_ERR_NO_MEM; + } + + f = fopen(file, "r"); + if (f == NULL) { + ESP_LOGE(TAG, "Failed to open file for reading"); + return ESP_FAIL; + } + + char *ptr; + int index = 0; + while (1){ + if ( fgets(line, sizeof(line) ,f) == 0 ) break; + // strip newline + char* pos = strchr(line, '\n'); + if (pos) { + *pos = '\0'; + } + ESP_LOGD(TAG, "line=[%s]", line); + if (strlen(line) == 0) continue; + if (line[0] == '#') continue; + + // Frame type + ptr = strtok(line, ","); + ESP_LOGD(TAG, "ptr=%s", ptr); + if (strcmp(ptr, "S") == 0) { + (*topics+index)->frame = 0; + } else if (strcmp(ptr, "E") == 0) { + (*topics+index)->frame = 1; + } else { + ESP_LOGE(TAG, "This line is invalid [%s]", line); + continue; + } + + // CAN ID + uint32_t canid; + ptr = strtok(NULL, ","); + if(ptr == NULL) continue; + ESP_LOGD(TAG, "ptr=%s", ptr); + canid = strtol(ptr, NULL, 16); + if (canid == 0) { + ESP_LOGE(TAG, "This line is invalid [%s]", line); + continue; + } + (*topics+index)->canid = canid; + + // mqtt topic + char *sp; + ptr = strtok(NULL, ","); + if(ptr == NULL) { + ESP_LOGE(TAG, "This line is invalid [%s]", line); + continue; + } + ESP_LOGD(TAG, "ptr=[%s] strlen=%d", ptr, strlen(ptr)); + sp = strstr(ptr,"#"); + if (sp != NULL) { + ESP_LOGE(TAG, "This line is invalid [%s]", line); + continue; + } + sp = strstr(ptr,"+"); + if (sp != NULL) { + ESP_LOGE(TAG, "This line is invalid [%s]", line); + continue; + } + (*topics+index)->topic = (char *)malloc(strlen(ptr)+1); + strcpy((*topics+index)->topic, ptr); + (*topics+index)->topic_len = strlen(ptr); + index++; + } + fclose(f); + *ntopic = index; + return ESP_OK; +} + +void dump_table(TOPIC_t *topics, int16_t ntopic) +{ + for(int i=0;iframe, (topics+i)->canid, (topics+i)->topic, (topics+i)->topic_len); + } + +} + +esp_err_t init_file_malloc() { + allocation_size = (MAX_FILE_SIZE_KB*1024*sizeof(char)); + file_read_buf = (char*)malloc(allocation_size); + + if (file_read_buf == NULL) { + ESP_LOGE(MALLOCHI_TAG, "File read memory not allocated."); + return ESP_FAIL; + } else { + ESP_LOGI(MALLOCHI_TAG, "File read malloc succeeded! %d bytes allocated", allocation_size); + return ESP_OK; + } + + return ESP_OK; +} + +esp_err_t init_twai_read_malloc() { + twai_allocation_size = (sizeof(char)*1024*MAX_TWAI_SIZE_KB); + twai_string_buf = (char*)malloc(twai_allocation_size); + + if (twai_string_buf == NULL) { + ESP_LOGE(MALLOCHI_TAG, "TWAI memory not allocated."); + return ESP_FAIL; + } else { + ESP_LOGI(MALLOCHI_TAG, "TWAI malloc succeeded! %d bytes allocated", twai_allocation_size); + return ESP_OK; + } + return ESP_OK; +} + +void http_client_task(void *pvParameters); +void http_server_task(void *pvParameters); +void twai_task(void *pvParameters); + +void app_main() +{ + // Initialize NVS + esp_err_t ret = nvs_flash_init(); + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); + wifi_init_sta(); + initialise_mdns(); + init_twai_read_malloc(); + init_file_malloc(); + + // Install and start TWAI driver + ESP_LOGI(TAG, "%s",BITRATE); + ESP_LOGI(TAG, "CTX_GPIO=%d",CONFIG_CTX_GPIO); + ESP_LOGI(TAG, "CRX_GPIO=%d",CONFIG_CRX_GPIO); + + static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CONFIG_CTX_GPIO, CONFIG_CRX_GPIO, TWAI_MODE_NORMAL); + ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config)); + ESP_LOGI(TAG, "Driver installed"); + ESP_ERROR_CHECK(twai_start()); + ESP_LOGI(TAG, "Driver started"); + + // Mount SPIFFS + char *partition_label = "storage"; + //char *base_path = "/spiffs"; + ret = mountSPIFFS(partition_label, base_path); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "mountSPIFFS fail"); + while(1) { vTaskDelay(1); } + } + + // Create Queue + xQueue_http_client = xQueueCreate( 10, sizeof(FRAME_t) ); + configASSERT( xQueue_http_client ); + xQueue_twai_tx = xQueueCreate( 10, sizeof(twai_message_t) ); + configASSERT( xQueue_twai_tx ); + + // build publish table + ret = build_table(&publish, "/spiffs/can2http.csv", &npublish); + if (ret != ESP_OK) { + ESP_LOGE(TAG, "build publish table fail"); + while(1) { vTaskDelay(1); } + } + dump_table(publish, npublish); + + /* Get the local IP address */ + //tcpip_adapter_ip_info_t ip_info; + //ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info)); + esp_netif_ip_info_t ip_info; + ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info)); + + char cparam0[64]; + //sprintf(cparam0, "%s", ip4addr_ntoa(&ip_info.ip)); + sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip)); + xTaskCreate(http_server_task, "server", 1024*6, (void *)cparam0, 2, NULL); + + xTaskCreate(http_client_task, "client", 1024*6, NULL, 2, NULL); + xTaskCreate(twai_task, "twai_rx", 1024*6, NULL, 2, NULL); +} diff --git a/main/twai.c b/main/twai.c index c71990d..b5bb5e9 100644 --- a/main/twai.c +++ b/main/twai.c @@ -1,167 +1,167 @@ -/* TWAI Network Example - - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -#include -#include -#include -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" -#include "esp_err.h" -#include "esp_log.h" -#include "driver/twai.h" // Update from V4.2 -#include "twai.h" -#include "cJSON.h" -//#include "init_malloci.h" - -static const char *TAG = "TWAI"; - -extern QueueHandle_t xQueue_http_client; -extern QueueHandle_t xQueue_twai_tx; - -extern TOPIC_t *publish; -extern int16_t npublish; -int str_iterator = 0; -extern char* twai_string_buf; - -//extern esp_err_t init_twai_read_malloc(); - -void dump_table(TOPIC_t *topics, int16_t ntopic); - -void twai_task(void *pvParameters) -{ - ESP_LOGI(TAG,"task start"); - dump_table(publish, npublish); - twai_message_t rx_msg; - twai_message_t tx_msg; - FRAME_t frameBuf; - char* ftype; - //char* fdata = (char*)malloc(32*sizeof(char)); - //int iterator = 0; - char flags[4]; - char identifier[4]; - while (1) { - esp_err_t ret = twai_receive(&rx_msg, pdMS_TO_TICKS(10)); - if (ret == ESP_OK) { - ESP_LOGD(TAG,"twai_receive identifier=0x%"PRIx32" flags=0x%"PRIx32" data_length_code=%d", - rx_msg.identifier, rx_msg.flags, rx_msg.data_length_code); - - int ext = rx_msg.flags & 0x01; - int rtr = rx_msg.flags & 0x02; - ESP_LOGD(TAG, "ext=%x rtr=%x", ext, rtr); - -#if CONFIG_ENABLE_PRINT - if (ext == STANDARD_FRAME) { - printf("Standard ID: 0x%03"PRIx32, rx_msg.identifier); - } else { - printf("Extended ID: 0x%08"PRIx32, rx_msg.identifier); - } - printf(" DLC: %d Data: ", rx_msg.data_length_code); - - printf("\n"); -#endif -// JSON fun fun fun output for da api - if (ext == STANDARD_FRAME) { - ftype = "STANDARD_FRAME"; - } else { - ftype = "EXTENDED_FRAME"; - } - - cJSON *twai_root = cJSON_CreateObject(); - - int charslen_each = 6; - int data_len_chars = rx_msg.data_length_code*charslen_each; - char tmp_buf[charslen_each+2]; - char fdata[data_len_chars]; - - if (rx_msg.data_length_code != 0) { - for (int i = 0; i < rx_msg.data_length_code; i++) { - snprintf(tmp_buf, charslen_each, "0x%02x ",rx_msg.data[i]); - strcat(fdata, tmp_buf); - } - fdata[strlen(fdata)-1] = '\0'; - cJSON_AddStringToObject(twai_root, "data", fdata); - } - snprintf(flags, sizeof(rx_msg.flags), "0x%"PRIx32, rx_msg.flags); - snprintf(identifier, sizeof(rx_msg.identifier), "0x%"PRIx32, rx_msg.identifier); - - cJSON_AddStringToObject(twai_root, "type", ftype); - cJSON_AddStringToObject(twai_root, "id", identifier); - cJSON_AddStringToObject(twai_root, "flags", flags); - cJSON_AddNumberToObject(twai_root, "ext", ext); - cJSON_AddNumberToObject(twai_root, "rtr", rtr); - cJSON_AddNumberToObject(twai_root, "dlc",rx_msg.data_length_code); - - char *string = cJSON_Print(twai_root); - char br[] = "
\n"; - - strcat(twai_string_buf,string); - strcat(twai_string_buf,br); - - cJSON_free(string); - cJSON_Delete(twai_root); -// end json buffer funssss - - for(int index=0;index +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/queue.h" +#include "freertos/semphr.h" +#include "esp_err.h" +#include "esp_log.h" +#include "driver/twai.h" // Update from V4.2 +#include "twai.h" +#include "cJSON.h" +//#include "init_malloci.h" + +static const char *TAG = "TWAI"; + +extern QueueHandle_t xQueue_http_client; +extern QueueHandle_t xQueue_twai_tx; + +extern TOPIC_t *publish; +extern int16_t npublish; +int str_iterator = 0; +extern char* twai_string_buf; + +//extern esp_err_t init_twai_read_malloc(); + +void dump_table(TOPIC_t *topics, int16_t ntopic); + +void twai_task(void *pvParameters) +{ + ESP_LOGI(TAG,"task start"); + dump_table(publish, npublish); + twai_message_t rx_msg; + twai_message_t tx_msg; + FRAME_t frameBuf; + char* ftype; + //char* fdata = (char*)malloc(32*sizeof(char)); + //int iterator = 0; + char flags[4]; + char identifier[4]; + while (1) { + esp_err_t ret = twai_receive(&rx_msg, pdMS_TO_TICKS(10)); + if (ret == ESP_OK) { + ESP_LOGD(TAG,"twai_receive identifier=0x%"PRIx32" flags=0x%"PRIx32" data_length_code=%d", + rx_msg.identifier, rx_msg.flags, rx_msg.data_length_code); + + int ext = rx_msg.flags & 0x01; + int rtr = rx_msg.flags & 0x02; + ESP_LOGD(TAG, "ext=%x rtr=%x", ext, rtr); + +#if CONFIG_ENABLE_PRINT + if (ext == STANDARD_FRAME) { + printf("Standard ID: 0x%03"PRIx32, rx_msg.identifier); + } else { + printf("Extended ID: 0x%08"PRIx32, rx_msg.identifier); + } + printf(" DLC: %d Data: ", rx_msg.data_length_code); + + printf("\n"); +#endif +// JSON fun fun fun output for da api + if (ext == STANDARD_FRAME) { + ftype = "STANDARD_FRAME"; + } else { + ftype = "EXTENDED_FRAME"; + } + + cJSON *twai_root = cJSON_CreateObject(); + + int charslen_each = 6; + int data_len_chars = rx_msg.data_length_code*charslen_each; + char tmp_buf[charslen_each+2]; + char fdata[data_len_chars]; + + if (rx_msg.data_length_code != 0) { + for (int i = 0; i < rx_msg.data_length_code; i++) { + snprintf(tmp_buf, charslen_each, "0x%02x ",rx_msg.data[i]); + strcat(fdata, tmp_buf); + } + fdata[strlen(fdata)-1] = '\0'; + cJSON_AddStringToObject(twai_root, "data", fdata); + } + snprintf(flags, sizeof(rx_msg.flags), "0x%"PRIx32, rx_msg.flags); + snprintf(identifier, sizeof(rx_msg.identifier), "0x%"PRIx32, rx_msg.identifier); + + cJSON_AddStringToObject(twai_root, "type", ftype); + cJSON_AddStringToObject(twai_root, "id", identifier); + cJSON_AddStringToObject(twai_root, "flags", flags); + cJSON_AddNumberToObject(twai_root, "ext", ext); + cJSON_AddNumberToObject(twai_root, "rtr", rtr); + cJSON_AddNumberToObject(twai_root, "dlc",rx_msg.data_length_code); + + char *string = cJSON_Print(twai_root); + char br[] = "
\n"; + + strcat(twai_string_buf,string); + strcat(twai_string_buf,br); + + cJSON_free(string); + cJSON_Delete(twai_root); +// end json buffer funssss + + for(int index=0;index= 20): - if(len(database) >= options.lines): - database.pop(0) - database.append(items) - - self.write(json.dumps({"result":"ok"})) - -if __name__ == "__main__": - tornado.options.parse_command_line() - print("port={}".format(options.port)) - print("lines={}".format(options.lines)) - app = tornado.web.Application( - handlers=[ - (r"/", IndexHandler), - (r"/post", PostHandler), - ], - template_path=os.path.join(os.getcwd(), "templates"), - debug=True - ) - http_server = tornado.httpserver.HTTPServer(app) - http_server.listen(options.port) - tornado.ioloop.IOLoop.current().start() +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Simple REST Server + +import os +import sys +import json +import datetime +import werkzeug +import tornado.httpserver +import tornado.ioloop +import tornado.options +import tornado.web + +from tornado.options import define, options +define("port", default=8000, help="run on the given port", type=int) +define("lines", default=20, help="number of lines displayed", type=int) + +database = [] + +class IndexHandler(tornado.web.RequestHandler): + def get(self): + global database + items = [] + for data in database: + #print("{}".format(data)) + datetime = data[0].split() + #print("data={} datetime={}".format(data[0], datetime)) + + items.append({ + "date": datetime[0], + "time": datetime[1], + "id": data[1], + "frame": data[2], + "value": data[3] + }) + #print("items={}".format(items)) + self.render("index.html", lines=options.lines, items=items) + +#curl -X POST -H "Content-Type: application/json" -d '{"canid":101, "frame":"standard" , "data": [1,2,3,4,5,6,7,8]}' http://192.168.10.43:8000/post +class PostHandler(tornado.web.RequestHandler): + def post(self): + #print("{}".format(self.request.body)) + function = sys._getframe().f_code.co_name + dict = tornado.escape.json_decode(self.request.body) + print("{} dict={}".format(function, dict)) + + items = [] + now = datetime.datetime.now() + items.append(now.strftime("%Y/%m/%d %H:%M:%S")) + if ("canid" in dict): + print("{} canid=0x{:x}".format(function, dict['canid'])) + items.append(dict['canid']) + + if ("frame" in dict): + print("{} frame={}".format(function, dict['frame'])) + items.append(dict['frame']) + + if ("data" in dict): + print("{} data length={}".format(function, len(dict['data']))) + print("{} data={}".format(function, dict['data'])) + items.append(dict['data']) + + global database + #print("{} {} {}".format(type(database), len(database), database)) + print("lines={}".format(options.lines)) + #if(len(database) >= 20): + if(len(database) >= options.lines): + database.pop(0) + database.append(items) + + self.write(json.dumps({"result":"ok"})) + +if __name__ == "__main__": + tornado.options.parse_command_line() + print("port={}".format(options.port)) + print("lines={}".format(options.lines)) + app = tornado.web.Application( + handlers=[ + (r"/", IndexHandler), + (r"/post", PostHandler), + ], + template_path=os.path.join(os.getcwd(), "templates"), + debug=True + ) + http_server = tornado.httpserver.HTTPServer(app) + http_server.listen(options.port) + tornado.ioloop.IOLoop.current().start() diff --git a/tornado/templates/index.html b/tornado/templates/index.html index a888123..0c41034 100644 --- a/tornado/templates/index.html +++ b/tornado/templates/index.html @@ -1,35 +1,35 @@ - - - - - CAN DATA - - - - Display the latest {{ lines }} records.
- If you want to see more, specify the number of lines at startup.
- - - - - - - - - - - - {% for i in items %} - - - - - - - - {% end %} - -
DateTimeIDFrameValue
{{ i['date'] }}{{ i['time'] }}{{ i['id'] }}{{ i['frame'] }}{{ i['value'] }}
- - - + + + + + CAN DATA + + + + Display the latest {{ lines }} records.
+ If you want to see more, specify the number of lines at startup.
+ + + + + + + + + + + + {% for i in items %} + + + + + + + + {% end %} + +
DateTimeIDFrameValue
{{ i['date'] }}{{ i['time'] }}{{ i['id'] }}{{ i['frame'] }}{{ i['value'] }}
+ + +