├── .gitattributes ├── .gitignore ├── .travis.yml ├── ESP32LapTimer ├── .gitignore ├── ESP32LapTimer.ino ├── data │ ├── GetStaticVars.js │ ├── RFsymbol.svg │ ├── UpdateStatusVars.js │ ├── assets │ │ └── css │ │ │ ├── images │ │ │ ├── overlay1.png │ │ │ ├── overlay2.png │ │ │ ├── overlay3.svg │ │ │ └── overlay4.svg │ │ │ ├── main.css │ │ │ └── slider.css │ ├── err.html │ ├── flag.svg │ ├── index.html │ ├── index_.html │ ├── jquery-3.3.1.min.js │ ├── menu.html │ ├── redirect.html │ └── updateIndexVals.js ├── platformio.ini └── src │ ├── ADC.cpp │ ├── ADC.h │ ├── Beeper.cpp │ ├── Beeper.h │ ├── Bluetooth.cpp │ ├── Bluetooth.h │ ├── Buttons.cpp │ ├── Buttons.h │ ├── Calibration.cpp │ ├── Calibration.h │ ├── Comms.cpp │ ├── Comms.h │ ├── CrashDetection.cpp │ ├── CrashDetection.h │ ├── ESP32LapTimer.cpp │ ├── Filter.h │ ├── Font.h │ ├── HardwareConfig.cpp │ ├── HardwareConfig.h │ ├── Laptime.cpp │ ├── Laptime.h │ ├── OLED.cpp │ ├── OLED.h │ ├── Output.cpp │ ├── Output.h │ ├── RX5808.cpp │ ├── RX5808.h │ ├── Screensaver.h │ ├── Serial.cpp │ ├── Serial.h │ ├── TCP.cpp │ ├── TCP.h │ ├── Timer.cpp │ ├── Timer.h │ ├── TimerWebServer.cpp │ ├── TimerWebServer.h │ ├── UDP.cpp │ ├── UDP.h │ ├── Utils.cpp │ ├── Utils.h │ ├── Watchdog.c │ ├── Watchdog.h │ ├── Wireless.cpp │ ├── Wireless.h │ ├── crc.c │ ├── crc.h │ ├── settings_eeprom.cpp │ ├── settings_eeprom.h │ └── targets │ ├── config_default.h │ ├── config_old.h │ ├── config_ttgo_lora_v1.h │ ├── config_wroom.h │ └── target.h ├── LICENSE ├── README.md ├── _config.yml ├── bin └── ESP32LapTimer.ino.esp32.bin ├── data ├── laptimer comparison.pdf └── laptimer comparison.xlsx ├── gather_releases.sh ├── img ├── Comparison1.png ├── Comparison2.png ├── HardwareImage2.png ├── PCBv1.jpg ├── hardwareImage1.png ├── schematic2.png ├── vcommport.png └── wiring.png └── pcb ├── JyeSmith ├── PCBV2.1 │ ├── Gerber-2.1.zip │ ├── PCB-2.1 - Patch Wire.png │ ├── PCB-2.1.png │ └── Schematic-V2.1.png └── PCBV2.2 │ ├── Gerber-2.2.zip │ ├── PCB-2.2.png │ └── Schematic-V2.2.png └── smeat └── esp32-wroom-timer-v1 ├── .gitignore ├── README.md ├── cern_ohl_v_1_2.txt ├── esp32-wroom-timer-cache.lib ├── esp32-wroom-timer.kicad_pcb ├── esp32-wroom-timer.pdf ├── esp32-wroom-timer.pro ├── esp32-wroom-timer.sch └── img ├── esp32-wroom-timer_bottom.png ├── esp32-wroom-timer_top.png ├── pic_1.jpg └── pic_2.jpg /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | sudo: false 4 | cache: 5 | directories: 6 | - "~/.platformio" 7 | install: 8 | - pip install -U platformio 9 | - pio update 10 | script: 11 | - pushd ESP32LapTimer && pio run && pio run -t buildfs && popd 12 | before_deploy: 13 | - ./gather_releases.sh ./ESP32LapTimer/.pio/build /tmp/esp32timer_firmware firmware.bin 14 | - ./gather_releases.sh ./ESP32LapTimer/.pio/build /tmp/esp32timer_firmware spiffs.bin 15 | deploy: 16 | provider: releases 17 | file_glob: true 18 | api_key: $GH_TOKEN 19 | file: /tmp/esp32timer_firmware/* 20 | skip_cleanup: true 21 | on: 22 | tags: true 23 | -------------------------------------------------------------------------------- /ESP32LapTimer/.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | .vscode 3 | -------------------------------------------------------------------------------- /ESP32LapTimer/ESP32LapTimer.ino: -------------------------------------------------------------------------------- 1 | /* 2 | We moved our build system to platformio. Take a look at the readme to see on how to use the new system. 3 | 4 | You are still able to use the Arduino IDE as you used to, but you won't be able to see the any other files. If you want to change the configuration you need to use an external editor. 5 | */ 6 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/GetStaticVars.js: -------------------------------------------------------------------------------- 1 | requestData(); // get intial data straight away 2 | var StatusData; 3 | function requestData() { 4 | 5 | var xhr = new XMLHttpRequest(); 6 | xhr.open('GET', 'StaticVars'); 7 | 8 | xhr.onload = function() { 9 | if (xhr.status === 200) { 10 | if (xhr.responseText) { // if the returned data is not null, update the values 11 | StatusData = JSON.parse(JSON.stringify(xhr.responseText)); 12 | var data = JSON.parse(StatusData); //yeah not sure why I need to do this twice, but otherwise it doesn't work.... 13 | document.getElementById("NumRXs").selectedIndex = parseInt(data.NumRXs); 14 | document.getElementById("ADCVBATmode").selectedIndex = parseInt(data.ADCVBATmode); 15 | document.getElementById("RXFilter").selectedIndex = parseInt(data.RXFilter); 16 | document.getElementById('ADCcalibValue').value = parseFloat(data.ADCcalibValue); 17 | document.getElementById('RSSIthreshold').value = updateRSSIThreshold(parseInt(data.RSSIthreshold)) 18 | document.getElementById('WiFiProtocol').value = parseInt(data.WiFiProtocol); 19 | document.getElementById('WiFiChannel').value = parseInt(data.WiFiChannel); 20 | document.getElementById('displayTimeout').value = Math.floor(parseInt(data.displayTimeout) / 1000); 21 | 22 | createBandChannel(data.NumRXs) 23 | updateBandChannel(data) 24 | } 25 | }else{requestData() } 26 | }; 27 | 28 | xhr.send(); 29 | } 30 | function updateRSSIThreshold(rssi){ 31 | var result = rssi / 12; 32 | return Math.floor(result) 33 | } 34 | function createBandChannel(numRXs) { 35 | numRXs = numRXs +1; 36 | for(var i=1;i<=numRXs;i++){ // GENERATE HTML 37 | $("#bandChannel").append('
'); 38 | $("#RX"+i).append('RX '+i+''); 39 | $("#RX"+i).append(''); 40 | $("#table"+i).append(''); 41 | $("#table"+i).append(''); 42 | $("#table"+i).append('') 54 | $("#table"+i).append(''); 55 | $("#table"+i).append('') 66 | $("#table"+i).append(''); 67 | $("#bandChannel").append(''); 68 | } 69 | } 70 | function updateBandChannel(data){ 71 | max = data.NumRXs + 1 72 | for(var i=0;i 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | image/svg+xml 19 | 20 | 21 | 22 | 23 | Openclipart 24 | 25 | 26 | Wireless/WiFi symbol 27 | 2008-03-08T19:15:09 28 | Wireless symobol for creating network schmatic 29 | http://openclipart.org/detail/17423/wireless/wifi-symbol-by-ispyisail-17423 30 | 31 | 32 | ispyisail 33 | 34 | 35 | 36 | 37 | access point 38 | clip art 39 | clipart 40 | icon 41 | image 42 | media 43 | network 44 | png 45 | public domain 46 | router 47 | svg 48 | wifi 49 | wireless 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/UpdateStatusVars.js: -------------------------------------------------------------------------------- 1 | requestData(); // get intial data straight away 2 | var StatusData; 3 | 4 | // request data updates every 5000 milliseconds 5 | setInterval(requestData, 500); 6 | 7 | function requestData() { 8 | 9 | var xhr = new XMLHttpRequest(); 10 | xhr.open('GET', 'StatusVars'); 11 | 12 | xhr.onload = function() { 13 | if (xhr.status === 200) { 14 | 15 | if (xhr.responseText) { // if the returned data is not null, update the values 16 | 17 | StatusData = JSON.parse(JSON.stringify(xhr.responseText)); 18 | var data = JSON.parse(StatusData); 19 | 20 | document.getElementById("Var_VBAT").innerText = data.Var_VBAT.toFixed(2); 21 | document.getElementById("Var_WifiClients").innerText = data.Var_WifiClients; 22 | document.getElementById("Var_CurrMode").innerText = data.Var_CurrMode; 23 | 24 | } else { // a problem occurred 25 | 26 | document.getElementById("Var_VBAT").innerText = "?"; 27 | document.getElementById("Var_WifiClients").innerText = "?"; 28 | document.getElementById("Var_CurrMode").innerText = "?"; 29 | } 30 | } else { 31 | console.log('Request failed. Returned status of ' + xhr.status); 32 | 33 | document.getElementById("Var_VBAT").innerText = "?"; 34 | document.getElementById("Var_WifiClients").innerText = "?"; 35 | document.getElementById("Var_CurrMode").innerText = "?"; 36 | 37 | } 38 | }; 39 | 40 | xhr.send(); 41 | } 42 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/assets/css/images/overlay1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/ESP32LapTimer/data/assets/css/images/overlay1.png -------------------------------------------------------------------------------- /ESP32LapTimer/data/assets/css/images/overlay2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/ESP32LapTimer/data/assets/css/images/overlay2.png -------------------------------------------------------------------------------- /ESP32LapTimer/data/assets/css/images/overlay3.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/assets/css/images/overlay4.svg: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/assets/css/slider.css: -------------------------------------------------------------------------------- 1 | .slider { 2 | -webkit-appearance: none; 3 | width: 100%; 4 | height: 15px; 5 | border-radius: 5px; 6 | background: #d3d3d3; 7 | outline: none; 8 | opacity: 0.7; 9 | -webkit-transition: .2s; 10 | transition: opacity .2s; 11 | } 12 | 13 | .slider::-webkit-slider-thumb { 14 | -webkit-appearance: none; 15 | appearance: none; 16 | width: 25px; 17 | height: 25px; 18 | border-radius: 50%; 19 | background: #4CAF50; 20 | cursor: pointer; 21 | } 22 | 23 | .slider::-moz-range-thumb { 24 | width: 25px; 25 | height: 25px; 26 | border-radius: 50%; 27 | background: #4CAF50; 28 | cursor: pointer; 29 | } 30 | 31 | .collapse{ 32 | cursor: zoom-in; 33 | display: block; 34 | } 35 | .collapse + input{ 36 | display: none; /* hide the checkboxes */ 37 | } 38 | .collapse + input + div{ 39 | display:none; 40 | } 41 | .collapse + input:checked + div{ 42 | display:block; 43 | } 44 | 45 | .collapse + input{ 46 | display: none; /* hide the checkboxes */ 47 | } 48 | .collapse + input + div{ 49 | display:none; 50 | } 51 | .collapse + input:checked + div{ 52 | display:block; 53 | } -------------------------------------------------------------------------------- /ESP32LapTimer/data/err.html: -------------------------------------------------------------------------------- 1 | You have not uploaded the SPIFFs filesystem!!!, Please install the following plugin.
Place the plugin file here: \"C:\Program Files (x86)\Arduino\tools\ESP32FS\tool\esp32fs.jar\".

Next select Tools > ESP32 Sketch Data Upload.
NOTE: This is a seperate upload to the normal arduino upload!!!

The web interface will not work until you do this. -------------------------------------------------------------------------------- /ESP32LapTimer/data/flag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | imagebot_2 8 | 9 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Chorus32 RF lap Timing System 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 38 | 39 |
40 |
41 | 42 |
43 | 44 |

Status:

45 |
46 |
Band:') 43 | $("#table"+i).append(' Channel:
47 | 48 | 49 | 51 | 52 | 53 |
54 |
VBAT:
55 | 56 | 57 | 58 | 83 | 84 |
85 |
86 | 87 |
88 |
89 |
90 | 91 |

General Configuration

92 |
93 |
Number of Receivers:
94 | 104 |
105 |
Band and channel:
106 |
107 |
108 | 109 |


110 | 112 | 113 | 120 | 121 | 122 |
123 |
124 | 125 |
126 |
127 | 128 |

VBAT Configuration

129 |
130 | VBAT Measurement Mode:
131 | 138 |
139 | ADC calibration Constant:
140 | 141 |
142 |
143 | 144 |
145 |
146 | 147 |
148 |
149 | 150 |

WiFi Configuration

151 |
152 | WiFi Protocol:
153 | 157 |
158 | WiFi Channel (1-13):
159 | 160 |
161 |
162 | 163 |
164 |
165 | 166 |
167 |
168 |
169 | 170 |

Filtering

171 |
172 | RX ADC Filter
173 | 181 |
182 | 183 |
184 |
185 |
186 |
187 | 188 |

Display Settings

189 |
190 | Display timeout in seconds (0 to disable)
191 | 192 |

193 | 194 |
195 |
196 |
197 | 198 |

Calibrate (optional)

199 |
200 | If the values of your different modules differ too much run this calibration with a VTX powered up at 25mW on any channel.
201 | If you ever run this without an active VTX your timer won't work properly and you'll need to recalibrate.

202 |
203 | 204 |
205 |
206 |
207 | 208 |

Reset Eeprom values

209 |
210 |
211 | 212 |
213 | 214 |
215 | 216 |
217 | 218 | Here you can update module firmware, 219 | be careful to upload the correct file as it is possible to brick the timer. A bricked timer will require reflashing with a serial cable 220 |

221 | 222 |

Firmware Update:

223 |
224 | 225 | 226 |
227 | 228 |
229 | 230 | 231 | 232 |
233 |
234 | 235 | 236 |
237 | 238 | 239 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/index_.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Chorus32 RF lap Timing System 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 36 | 37 |
38 |
39 | 40 |
41 | 42 |

Status:

43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 |
Vbat: 3.73VWifi Clients: 1Current Mode: Idle
51 |
52 | 53 |
54 |
55 |
56 |
57 |
58 | 59 |

Filtering

60 |
61 | RX ADC Filter
62 | 69 |
70 | 71 |
72 |
73 | 74 | 75 |
76 | 77 |
78 |
79 | 80 |
81 | 82 |
83 | 84 | Here you can update module firmware, 85 | be careful to upload the correct file as it is possible to brick the timer. A bricked timer will require reflashing with a serial cable 86 |

87 | 88 |

Firmware Update:

89 |
90 | 91 | 92 |
93 |
94 | 95 |
96 | 97 | 98 | 99 |
100 |
101 | 102 | 103 |
104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/menu.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Drop-Down Select Box Example 6 | 38 | 39 | 40 | 41 | 57 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/redirect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |

Settings Applied, redirecting to homepage....

10 | -------------------------------------------------------------------------------- /ESP32LapTimer/data/updateIndexVals.js: -------------------------------------------------------------------------------- 1 | SelectElement("leaveCode", valueToSelect) 2 | 3 | function SelectElement(id, valueToSelect) 4 | { 5 | var element = document.getElementById(id); 6 | element.value = valueToSelect; 7 | } -------------------------------------------------------------------------------- /ESP32LapTimer/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [env] 12 | platform = espressif32 @ ~3.5.0 13 | board = esp32dev 14 | framework = arduino 15 | monitor_speed = 115200 16 | lib_deps = 17 | https://github.com/ThingPulse/esp8266-oled-ssd1306 18 | https://github.com/adafruit/Adafruit_INA219.git 19 | https://github.com/me-no-dev/ESPAsyncTCP 20 | https://github.com/me-no-dev/ESPAsyncWebServer 21 | 22 | [env:BOARD_DEFAULT] 23 | build_flags = 24 | -D BOARD=BOARD_DEFAULT 25 | 26 | [env:BOARD_TTGO_LORA] 27 | build_flags = 28 | -D BOARD=BOARD_TTGO_LORA 29 | 30 | [env:BOARD_OLD] 31 | build_flags = 32 | -D BOARD=BOARD_OLD 33 | 34 | [env:BOARD_WROOM] 35 | build_flags = 36 | -D BOARD=BOARD_WROOM 37 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/ADC.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | ////Functions to Read RSSI from ADCs////// 19 | #include 20 | #include 21 | #include 22 | 23 | #include 24 | #include 25 | 26 | #include "HardwareConfig.h" 27 | #include "Comms.h" 28 | #include "settings_eeprom.h" 29 | #include "ADC.h" 30 | #include "Timer.h" 31 | #include "Output.h" 32 | #include "Calibration.h" 33 | #include "Laptime.h" 34 | #include "Utils.h" 35 | 36 | static Adafruit_INA219 ina219; // A0+A1=GND 37 | 38 | static uint32_t LastADCcall; 39 | 40 | static esp_adc_cal_characteristics_t adc_chars; 41 | 42 | static int RSSIthresholds[MAX_NUM_RECEIVERS]; 43 | static uint16_t ADCReadingsRAW[MAX_NUM_RECEIVERS]; 44 | static unsigned int VbatReadingSmooth; 45 | static int ADCvalues[MAX_NUM_RECEIVERS]; 46 | static uint16_t adcLoopCounter = 0; 47 | 48 | static FilterBeLp2_10HZ Filter_10HZ[6] = {FilterBeLp2_10HZ(), FilterBeLp2_10HZ(), FilterBeLp2_10HZ(), FilterBeLp2_10HZ(), FilterBeLp2_10HZ(), FilterBeLp2_10HZ()}; 49 | static FilterBeLp2_20HZ Filter_20HZ[6] = {FilterBeLp2_20HZ(), FilterBeLp2_20HZ(), FilterBeLp2_20HZ(), FilterBeLp2_20HZ(), FilterBeLp2_20HZ(), FilterBeLp2_20HZ()}; 50 | static FilterBeLp2_50HZ Filter_50HZ[6] = {FilterBeLp2_50HZ(), FilterBeLp2_50HZ(), FilterBeLp2_50HZ(), FilterBeLp2_50HZ(), FilterBeLp2_50HZ(), FilterBeLp2_50HZ()}; 51 | static FilterBeLp2_100HZ Filter_100HZ[6] = {FilterBeLp2_100HZ(), FilterBeLp2_100HZ(), FilterBeLp2_100HZ(), FilterBeLp2_100HZ(), FilterBeLp2_100HZ(), FilterBeLp2_100HZ()}; 52 | 53 | static float VBATcalibration; 54 | static float mAReadingFloat; 55 | static float VbatReadingFloat; 56 | 57 | static adc1_channel_t ADC_PINS[MAX_NUM_RECEIVERS] = {ADC1, ADC2, ADC3, ADC4, ADC5, ADC6}; 58 | 59 | static uint16_t multisample_adc1(adc1_channel_t channel, uint8_t samples) { 60 | uint32_t val = 0; 61 | for(uint8_t i = 0; i < samples; ++i) { 62 | val += adc1_get_raw(channel); 63 | } 64 | return val/samples; 65 | } 66 | 67 | void ConfigureADC() { 68 | 69 | adc1_config_width(ADC_WIDTH_BIT_12); 70 | 71 | for(int i = 0; i < MAX_NUM_RECEIVERS; i++) { 72 | adc1_config_channel_atten(ADC_PINS[i], ADC_ATTEN_6db); 73 | } 74 | 75 | //since the reference voltage can range from 1000mV to 1200mV we are using 1100mV as a default 76 | esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_6db, ADC_WIDTH_BIT_12, 1100, &adc_chars); 77 | 78 | ina219.begin(); 79 | ReadVBAT_INA219(); 80 | 81 | } 82 | 83 | void IRAM_ATTR nbADCread( void * pvParameters ) { 84 | static uint8_t current_adc = 0; 85 | if(current_adc == 0) ++adcLoopCounter; // only count adc number 0 to get the frequency per module 86 | 87 | uint32_t now = micros(); 88 | LastADCcall = now; 89 | adc1_channel_t channel = ADC_PINS[MIN(current_adc, MAX_NUM_RECEIVERS - 1)]; 90 | 91 | if(LIKELY(isInRaceMode())) { 92 | ADCReadingsRAW[current_adc] = adc1_get_raw(channel); 93 | } else { 94 | // multisample when not in race mode (for threshold calibration etc) 95 | ADCReadingsRAW[current_adc] = multisample_adc1(channel, 10); 96 | } 97 | 98 | // Applying calibration 99 | if (LIKELY(!isCalibrating())) { 100 | uint16_t rawRSSI = constrain(ADCReadingsRAW[current_adc], EepromSettings.RxCalibrationMin[current_adc], EepromSettings.RxCalibrationMax[current_adc]); 101 | ADCReadingsRAW[current_adc] = map(rawRSSI, EepromSettings.RxCalibrationMin[current_adc], EepromSettings.RxCalibrationMax[current_adc], RSSI_ADC_READING_MIN, RSSI_ADC_READING_MAX); 102 | } 103 | 104 | switch (getRXADCfilter()) { 105 | case LPF_10Hz: 106 | ADCvalues[current_adc] = Filter_10HZ[current_adc].step(ADCReadingsRAW[current_adc]); 107 | break; 108 | case LPF_20Hz: 109 | ADCvalues[current_adc] = Filter_20HZ[current_adc].step(ADCReadingsRAW[current_adc]); 110 | break; 111 | case LPF_50Hz: 112 | ADCvalues[current_adc] = Filter_50HZ[current_adc].step(ADCReadingsRAW[current_adc]); 113 | break; 114 | case LPF_100Hz: 115 | ADCvalues[current_adc] = Filter_100HZ[current_adc].step(ADCReadingsRAW[current_adc]); 116 | break; 117 | } 118 | 119 | if (LIKELY(isInRaceMode() > 0)) { 120 | CheckRSSIthresholdExceeded(current_adc); 121 | } 122 | current_adc = (current_adc + 1) % MAX_NUM_RECEIVERS; 123 | } 124 | 125 | 126 | void ReadVBAT_INA219() { 127 | setVbatFloat(ina219.getBusVoltage_V() + (ina219.getShuntVoltage_mV() / 1000)); 128 | mAReadingFloat = ina219.getCurrent_mA(); 129 | } 130 | 131 | void IRAM_ATTR CheckRSSIthresholdExceeded(uint8_t node) { 132 | uint32_t CurrTime = millis(); 133 | if ( ADCvalues[node] > RSSIthresholds[node]) { 134 | if (CurrTime > (getMinLapTime() + getLaptime(node))) { 135 | addLap(node, CurrTime); 136 | } 137 | } 138 | } 139 | 140 | uint16_t getRSSI(uint8_t index) { 141 | if(index < MAX_NUM_RECEIVERS) { 142 | return ADCvalues[index]; 143 | } 144 | return 0; 145 | } 146 | 147 | void setRSSIThreshold(uint8_t node, uint16_t threshold) { 148 | if(node < MAX_NUM_RECEIVERS) { 149 | RSSIthresholds[node] = threshold; 150 | } 151 | } 152 | 153 | uint16_t getRSSIThreshold(uint8_t node){ 154 | return RSSIthresholds[node]; 155 | } 156 | 157 | uint16_t getADCLoopCount() { 158 | return adcLoopCounter; 159 | } 160 | 161 | void setADCLoopCount(uint16_t count) { 162 | adcLoopCounter = count; 163 | } 164 | 165 | void setVbatCal(float calibration) { 166 | VBATcalibration = calibration; 167 | } 168 | 169 | float getMaFloat() { 170 | return mAReadingFloat; 171 | } 172 | 173 | float getVbatFloat(bool force_read){ 174 | static uint32_t last_voltage_update = 0; 175 | if((millis() - last_voltage_update) > VOLTAGE_UPDATE_INTERVAL_MS || force_read) { 176 | switch (getADCVBATmode()) { 177 | case ADC_CH5: 178 | VbatReadingSmooth = esp_adc_cal_raw_to_voltage(adc1_get_raw(ADC5), &adc_chars); 179 | setVbatFloat(VbatReadingSmooth / 1000.0 * VBATcalibration); 180 | break; 181 | case ADC_CH6: 182 | VbatReadingSmooth = esp_adc_cal_raw_to_voltage(adc1_get_raw(ADC6), &adc_chars); 183 | setVbatFloat(VbatReadingSmooth / 1000.0 * VBATcalibration); 184 | break; 185 | case INA219: 186 | ReadVBAT_INA219(); 187 | default: 188 | break; 189 | } 190 | last_voltage_update = millis(); 191 | } 192 | return VbatReadingFloat; 193 | } 194 | 195 | void setVbatFloat(float val){ 196 | VbatReadingFloat = val; 197 | } 198 | 199 | void setVBATcalibration(float val) { 200 | VBATcalibration = val; 201 | } 202 | 203 | float getVBATcalibration() { 204 | return VBATcalibration; 205 | } 206 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/ADC.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | #include 22 | 23 | #include "HardwareConfig.h" 24 | #include "Filter.h" 25 | 26 | void ConfigureADC(); 27 | void IRAM_ATTR CheckRSSIthresholdExceeded(uint8_t node); 28 | void ReadVBAT_INA219(); 29 | void IRAM_ATTR nbADCread( void * pvParameters ); 30 | 31 | uint16_t getRSSI(uint8_t index); 32 | void setRSSIThreshold(uint8_t node, uint16_t threshold); 33 | uint16_t getRSSIThreshold(uint8_t node); 34 | uint16_t getADCLoopCount(); 35 | void setADCLoopCount(uint16_t count); 36 | 37 | void setVbatCal(float calibration); 38 | float getMaFloat(); 39 | 40 | float getVbatFloat(bool force_read = false); 41 | void setVbatFloat(float val); 42 | 43 | float getVBATcalibration(); 44 | void setVBATcalibration(float val); 45 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Beeper.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Beeper.h" 19 | 20 | #include "Timer.h" 21 | #include "HardwareConfig.h" 22 | 23 | #include 24 | 25 | static Timer beeperTimer = Timer(50); 26 | 27 | void beep() { 28 | digitalWrite(BEEPER, HIGH); 29 | delay(50); 30 | digitalWrite(BEEPER, LOW); 31 | beeperTimer.reset(); 32 | } 33 | 34 | void doubleBeep() { 35 | int i=0; 36 | for (i=0; i<=1; i++) { 37 | digitalWrite(BEEPER, HIGH); 38 | delay(50); 39 | digitalWrite(BEEPER, LOW); 40 | delay(50); 41 | } 42 | } 43 | 44 | void chirps() { 45 | int i = 0; 46 | for (i = 0; i <=5; i++) { 47 | digitalWrite(BEEPER, HIGH); 48 | delay(10); 49 | digitalWrite(BEEPER, LOW); 50 | delay(10); 51 | } 52 | } 53 | 54 | void fiveBeep() { 55 | int i=0; 56 | for (i=0; i<=4; i++) { 57 | digitalWrite(BEEPER, HIGH); 58 | delay(100); 59 | digitalWrite(BEEPER, LOW); 60 | delay(50); 61 | } 62 | } 63 | 64 | void beeperUpdate() { 65 | if (beeperTimer.hasTicked()) { 66 | digitalWrite(BEEPER, LOW); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Beeper.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __BEEPER_H__ 19 | #define __BEEPER_H__ 20 | 21 | void beep(); 22 | void doubleBeep(); 23 | void chirps(); 24 | void fiveBeep(); 25 | void beeperUpdate(); 26 | 27 | #endif // __BEEPER_H__ 28 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Bluetooth.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Bluetooth.h" 19 | 20 | #include "Output.h" 21 | #include "HardwareConfig.h" 22 | 23 | #include 24 | 25 | #define BLUETOOTH_BUFFER_SIZE 255 26 | 27 | static uint8_t BluetootBuffIn[BLUETOOTH_BUFFER_SIZE]; 28 | static int BluetootBuffInPointer = 0; 29 | 30 | static BluetoothSerial SerialBT; 31 | 32 | void bluetooth_init(void* output) { 33 | SerialBT.begin(BLUETOOTH_NAME); 34 | } 35 | 36 | void bluetooth_update(void* output) { 37 | if (SerialBT.available()) { 38 | if(BluetootBuffInPointer >= BLUETOOTH_BUFFER_SIZE - 1) { 39 | Serial.println("Bluetooth input buffer full! Reseting..."); 40 | BluetootBuffInPointer = 0; 41 | } 42 | BluetootBuffIn[BluetootBuffInPointer] = SerialBT.read(); 43 | if (BluetootBuffIn[BluetootBuffInPointer] == '\n') { 44 | output_t* out = (output_t*)output; 45 | out->handle_input_callback(BluetootBuffIn, BluetootBuffInPointer + 1); 46 | BluetootBuffInPointer = 0; 47 | } else { 48 | BluetootBuffInPointer++; 49 | } 50 | } 51 | } 52 | 53 | void bluetooth_send_packet(void* output, uint8_t* buf, uint32_t size) { 54 | if (SerialBT.hasClient()) { 55 | SerialBT.write(buf, size); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Bluetooth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __BLUETOOTH_H__ 19 | #define __BLUETOOTH_H__ 20 | 21 | 22 | #include "BluetoothSerial.h" 23 | 24 | #if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED) 25 | #error Bluetooth is not enabled! Please run `make menuconfig` to and enable it 26 | #endif 27 | 28 | void bluetooth_update(void* output); 29 | void bluetooth_send_packet(void* output, uint8_t* buf, uint32_t size); 30 | void bluetooth_init(void* output); 31 | 32 | #endif // __BLUETOOTH_H__ 33 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Buttons.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "HardwareConfig.h" 19 | #ifdef USE_BUTTONS 20 | #include "Buttons.h" 21 | 22 | #include "Timer.h" 23 | #include "Beeper.h" 24 | #include "OLED.h" 25 | #include "Calibration.h" 26 | #include "settings_eeprom.h" 27 | #include "TimerWebServer.h" 28 | #include "CrashDetection.h" 29 | 30 | #include 31 | #include 32 | 33 | #define newButtonDeBounce 40 34 | 35 | static bool buttonOneTouched = false; 36 | static bool buttonTwoTouched = false; 37 | 38 | static long buttonLongPressTime = 800; // How long to hold before a longtouch is registered 39 | 40 | // Timers to keep track of when the buttons were pressed 41 | static long buttonTimer1 = 0; 42 | static long buttonTimer2 = 0; 43 | static long touchedTime1 = 0; 44 | static long touchedTime2 = 0; 45 | 46 | // These are for the value of the capacitive touch. 47 | static uint8_t touch1; 48 | static uint8_t touch2; 49 | 50 | // Bools to help with debounce and long touch 51 | static bool buttonActive1 = false; 52 | static bool longPressActive1 = false; 53 | static bool buttonPressed1 = false; 54 | static bool buttonActive2 = false; 55 | static bool longPressActive2 = false; 56 | static bool buttonPressed2 = false; 57 | 58 | void newButtonSetup() { 59 | #ifdef USE_NORMAL_BUTTONS 60 | pinMode(BUTTON1, INPUT_PULLUP); 61 | pinMode(BUTTON2, INPUT_PULLUP); 62 | #else 63 | touch_pad_filter_start(BUTTON1); 64 | touch_pad_set_filter_period(BUTTON1); 65 | touch_pad_filter_start(BUTTON2); 66 | touch_pad_set_filter_period(BUTTON2); 67 | #endif 68 | } 69 | 70 | void newButtonUpdate() { 71 | #ifdef USE_NORMAL_BUTTONS 72 | touch1 = (digitalRead(BUTTON1)) ? 100 : 0; 73 | touch2 = (digitalRead(BUTTON2)) ? 100 : 0; 74 | #else 75 | touch1 = touchRead(BUTTON1); // Read the state of button 1 76 | touch2 = touchRead(BUTTON2); // Read the state of button 2 77 | #endif 78 | 79 | // BUTTON 1 Debounce logic here. Basically, we only read a button touch if 80 | // it stays below threshold for newButtonDebounce, it gets flagged as "pressed". 81 | if (buttonOneTouched == false && touch1 < 70) { 82 | touchedTime1 = millis(); 83 | buttonOneTouched = true; 84 | } else if (buttonOneTouched == true && touch1 < 70) { 85 | if ( millis() - touchedTime1 >= newButtonDeBounce) { 86 | buttonPressed1 = true; 87 | } 88 | } else if (touch1 > 50) { 89 | buttonOneTouched = false; 90 | buttonPressed1 = false; 91 | } 92 | 93 | // BUTTON 2 Debounce logic here. Basically, we only read a button touch if 94 | // it stays below threshol for newButtonDebounce, it gets flagged as "pressed". 95 | if (buttonTwoTouched == false && touch2 < 70) { 96 | touchedTime2 = millis(); 97 | buttonTwoTouched = true; 98 | } else if (buttonTwoTouched == true && touch2 < 70) { 99 | if ( millis() - touchedTime2 >= newButtonDeBounce) { 100 | buttonPressed2 = true; 101 | } 102 | } else if (touch2 > 50) { 103 | buttonTwoTouched = false; 104 | buttonPressed2 = false; 105 | } 106 | 107 | // BUTTON 1 Logic Here 108 | if (buttonPressed1) { 109 | if (buttonActive1 == false) { 110 | buttonActive1 = true; 111 | buttonTimer1 = millis(); 112 | } 113 | if ((millis() - buttonTimer1 > buttonLongPressTime) && (longPressActive1 == false)) { 114 | Serial.println("Button 1 Long Press."); 115 | // vvv BUTTON 1 LONG press between these comments vvv 116 | oledInjectInput(0, BUTTON_LONG); 117 | // ^^^ BUTTON 1 LONG press between these comments ^^^ 118 | longPressActive1 = true; 119 | } 120 | } else { 121 | if (buttonActive1 == true) { 122 | if (longPressActive1 == true) { 123 | longPressActive1 = false; 124 | } else { 125 | Serial.println("Button 1 Short press."); 126 | // vvv BUTTON 1 SHORT press between these comments vvv 127 | oledInjectInput(0, BUTTON_SHORT); 128 | // ^^^ BUTTON 1 SHORT press between these comments ^^^ 129 | } 130 | buttonActive1 = false; 131 | } 132 | } 133 | 134 | // BUTTON 2 Logic here 135 | if (buttonPressed2) { 136 | if (buttonActive2 == false) { 137 | buttonActive2 = true; 138 | buttonTimer2 = millis(); 139 | } 140 | if ((millis() - buttonTimer2 > buttonLongPressTime) && (longPressActive2 == false)) { 141 | Serial.println("Button 2 Long Press."); 142 | // vvv BUTTON 2 LONG press between these comments vvv 143 | 144 | oledInjectInput(1, BUTTON_LONG); 145 | 146 | // ^^^ BUTTON 2 LONG press between these comments ^^^ 147 | longPressActive2 = true; 148 | } 149 | } else { 150 | if (buttonActive2 == true) { 151 | if (longPressActive2 == true) { 152 | longPressActive2 = false; 153 | } else { 154 | Serial.println("Button 2 Short press."); 155 | // vvv BUTTON 2 SHORT press between these comments vvv 156 | oledInjectInput(1, BUTTON_SHORT); 157 | // ^^^ BUTTON 2 SHORT press between these comments ^^^ 158 | } 159 | buttonActive2 = false; 160 | } 161 | } 162 | 163 | if (longPressActive1 && longPressActive2) { 164 | // Long press on both buttons gets you here 165 | delay(200); 166 | chirps(); 167 | delay(1000); 168 | Serial.println("RESET"); 169 | fiveBeep(); 170 | EepromSettings.defaults(); 171 | delay(100); 172 | restart_esp(); 173 | } 174 | } 175 | 176 | #endif // USE_BUTTONS 177 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Buttons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __BUTTONS_H__ 19 | #define __BUTTONS_H__ 20 | 21 | void newButtonSetup(); 22 | void newButtonUpdate(); 23 | 24 | #endif // __BUTTONS_H__ 25 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Calibration.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Calibration.h" 19 | 20 | #include "ADC.h" 21 | #include "HardwareConfig.h" 22 | #include "RX5808.h" 23 | #include "settings_eeprom.h" 24 | #include "OLED.h" 25 | #include "Timer.h" 26 | #include "Utils.h" 27 | 28 | static int calibrationFreqIndex = 0; 29 | static bool isCurrentlyCalibrating = false; 30 | static Timer calibrationTimer = Timer(50); 31 | 32 | bool isCalibrating() { 33 | return isCurrentlyCalibrating; 34 | } 35 | 36 | void rssiCalibration() { 37 | for (uint8_t i = 0; i < getNumReceivers(); i++) { 38 | EepromSettings.RxCalibrationMin[i] = 5000; 39 | EepromSettings.RxCalibrationMax[i] = 0; 40 | } 41 | 42 | isCurrentlyCalibrating = true; 43 | calibrationFreqIndex = 0; 44 | setModuleFrequencyAll(channelFreqTable[calibrationFreqIndex]); 45 | setRXADCfilter(LPF_10Hz); 46 | calibrationTimer.reset(); 47 | } 48 | 49 | void rssiCalibrationUpdate() { 50 | if (UNLIKELY(isCurrentlyCalibrating && calibrationTimer.hasTicked())) { 51 | for (uint8_t i = 0; i < getNumReceivers(); i++) { 52 | if (getRSSI(i) < EepromSettings.RxCalibrationMin[i]) 53 | EepromSettings.RxCalibrationMin[i] = getRSSI(i); 54 | 55 | if (getRSSI(i) > EepromSettings.RxCalibrationMax[i]) 56 | EepromSettings.RxCalibrationMax[i] = getRSSI(i); 57 | } 58 | calibrationFreqIndex++; 59 | if (calibrationFreqIndex < 8*8) { // 8*8 = 8 bands * 8 channels = total number of freq in channelFreqTable. 60 | setModuleFrequencyAll(channelFreqTable[calibrationFreqIndex]); 61 | calibrationTimer.reset(); 62 | 63 | } else { 64 | for (int i = 0; i < getNumReceivers(); i++) { 65 | setModuleChannelBand(i); 66 | // Prevent min > max 67 | EepromSettings.RxCalibrationMax[i] = MAX(EepromSettings.RxCalibrationMax[i], EepromSettings.RxCalibrationMin[i] + 1); 68 | } 69 | isCurrentlyCalibrating = false; 70 | setSaveRequired(); 71 | setDisplayScreenNumber(0); 72 | setRXADCfilter(EepromSettings.RXADCfilter); 73 | } 74 | } 75 | } 76 | 77 | int getcalibrationFreqIndex() { 78 | return calibrationFreqIndex; 79 | } 80 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Calibration.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __CALIBRATION_H__ 19 | #define __CALIBRATION_H__ 20 | 21 | bool isCalibrating(); 22 | void rssiCalibration(); 23 | void rssiCalibrationUpdate(); 24 | int getcalibrationFreqIndex(); 25 | 26 | #endif // __CALIBRATION_H__ 27 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Comms.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __COMMS_H__ 19 | #define __COMMS_H__ 20 | 21 | #include "HardwareConfig.h" 22 | 23 | #include 24 | #include 25 | 26 | void HandleSerialRead(); 27 | void HandleServerUDP(); 28 | void SendCurrRSSIloop(); 29 | void IRAM_ATTR sendLap(uint8_t Lap, uint8_t NodeAddr); 30 | void commsSetup(); 31 | void thresholdModeStep(); 32 | void handleSerialControlInput(char *controlData, uint8_t ControlByte, uint8_t NodeAddr, uint8_t length); 33 | bool isInRaceMode(); 34 | 35 | #endif // __COMMS_H__ 36 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/CrashDetection.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "CrashDetection.h" 19 | 20 | #include 21 | #include 22 | 23 | // positive values indicate a crashing system. negative values a manual reboot loop 24 | RTC_NOINIT_ATTR static int crash_count = 0; 25 | 26 | bool is_crash_mode() { 27 | return (crash_count > MAX_CRASH_COUNT) || (crash_count < -MAX_CRASH_COUNT); 28 | } 29 | 30 | void init_crash_detection() { 31 | // crash reason is not sw reset, so not a crash! 32 | if(rtc_get_reset_reason(0) != 12) { 33 | crash_count = 0; 34 | } else { 35 | ++crash_count; 36 | } 37 | } 38 | 39 | int get_crash_count() { 40 | return crash_count; 41 | } 42 | 43 | void reset_crash_count() { 44 | crash_count = 0; 45 | } 46 | 47 | void restart_esp() { 48 | --crash_count; 49 | ESP.restart(); 50 | } 51 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/CrashDetection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef _CRASHDETECTION_H_ 19 | #define _CRASHDETECTION_H_ 20 | 21 | #define MAX_CRASH_COUNT 5 22 | 23 | bool is_crash_mode(); 24 | void init_crash_detection(); 25 | void restart_esp(); 26 | int get_crash_count(); 27 | void reset_crash_count(); 28 | 29 | #endif // _CRASHDETECTION_H_ 30 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/ESP32LapTimer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | #include "Comms.h" 24 | #include "ADC.h" 25 | #include "HardwareConfig.h" 26 | #include "RX5808.h" 27 | #include "Bluetooth.h" 28 | #include "settings_eeprom.h" 29 | #ifdef OLED 30 | #include "OLED.h" 31 | #endif 32 | #include "TimerWebServer.h" 33 | #include "Beeper.h" 34 | #include "Calibration.h" 35 | #include "Output.h" 36 | #ifdef USE_BUTTONS 37 | #include "Buttons.h" 38 | #endif 39 | #include "Watchdog.h" 40 | #include "Utils.h" 41 | #include "Laptime.h" 42 | #include "Wireless.h" 43 | 44 | #include "CrashDetection.h" 45 | #ifdef USE_ARDUINO_OTA 46 | #include 47 | #endif 48 | 49 | //#define BluetoothEnabled //uncomment this to use bluetooth (experimental, ble + wifi appears to cause issues) 50 | 51 | static TaskHandle_t adc_task_handle = NULL; 52 | 53 | void IRAM_ATTR adc_read() { 54 | BaseType_t xHigherPriorityTaskWoken = pdFALSE; 55 | /* un-block the interrupt processing task now */ 56 | vTaskNotifyGiveFromISR(adc_task_handle, &xHigherPriorityTaskWoken); 57 | if(xHigherPriorityTaskWoken) { 58 | portYIELD_FROM_ISR(); 59 | } 60 | } 61 | 62 | void IRAM_ATTR adc_task(void* args) { 63 | watchdog_add_task(); 64 | while(42) { 65 | ulTaskNotifyTake(pdTRUE, portMAX_DELAY); 66 | nbADCread(NULL); 67 | watchdog_feed(); 68 | } 69 | } 70 | 71 | void setup() { 72 | init_crash_detection(); 73 | 74 | Serial.begin(115200); 75 | Serial.println("Booting...."); 76 | #ifdef USE_ARDUINO_OTA 77 | if(is_crash_mode()) { 78 | log_e("Detected crashing. Starting ArduinoOTA only!"); 79 | InitWifiAP(); 80 | ArduinoOTA.begin(); 81 | return; 82 | } 83 | #endif 84 | #ifdef OLED 85 | oledSetup(); 86 | #endif 87 | #ifdef USE_BUTTONS 88 | newButtonSetup(); 89 | #endif 90 | 91 | EepromSettings.setup(); 92 | 93 | delay(500); 94 | InitHardwarePins(); 95 | ConfigureADC(); 96 | 97 | InitSPI(); 98 | //PowerDownAll(); // Powers down all RX5808's 99 | delay(250); 100 | 101 | InitWifi(); 102 | 103 | InitWebServer(); 104 | 105 | if (!EepromSettings.SanityCheck()) { 106 | EepromSettings.defaults(); 107 | Serial.println("Detected That EEPROM corruption has occured.... \n Resetting EEPROM to Defaults...."); 108 | } 109 | 110 | setRXADCfilter(EepromSettings.RXADCfilter); 111 | setADCVBATmode(EepromSettings.ADCVBATmode); 112 | setVbatCal(EepromSettings.VBATcalibration); 113 | commsSetup(); 114 | init_outputs(); 115 | 116 | for (int i = 0; i < getNumReceivers(); i++) { 117 | setRSSIThreshold(i, EepromSettings.RSSIthresholds[i]); 118 | } 119 | 120 | xTaskCreatePinnedToCore(adc_task, "ADCreader", 4096, NULL, 1, &adc_task_handle, 0); 121 | hw_timer_t* adc_task_timer = timerBegin(0, 8, true); 122 | timerAttachInterrupt(adc_task_timer, &adc_read, true); 123 | timerAlarmWrite(adc_task_timer, 1667, true); // 6khz -> 1khz per adc channel 124 | timerAlarmEnable(adc_task_timer); 125 | 126 | //SelectivePowerUp(); 127 | 128 | // inits modules with defaults. Loops 10 times because some Rx modules dont initiate correctly. 129 | for (int i = 0; i < getNumReceivers()*10; i++) { 130 | setModuleChannelBand(i % getNumReceivers()); 131 | } 132 | 133 | //beep(); 134 | } 135 | 136 | void loop() { 137 | #ifdef USE_ARDUINO_OTA 138 | ArduinoOTA.handle(); 139 | if(is_crash_mode()) return; 140 | #endif 141 | if(millis() > CRASH_COUNT_RESET_TIME_MS) { 142 | reset_crash_count(); 143 | } 144 | rssiCalibrationUpdate(); 145 | // touchMonitor(); // A function to monitor capacitive touch values, defined in buttons.ino 146 | 147 | // if (shouldReboot) { //checks if reboot is needed 148 | // Serial.println("Rebooting..."); 149 | // delay(100); 150 | // ESP.restart(); 151 | // } 152 | #ifdef USE_BUTTONS 153 | newButtonUpdate(); 154 | #endif 155 | #ifdef OLED 156 | // We need to pause the OLED during update otherwise we crash due to I2C 157 | if(!isUpdating()) { 158 | OLED_CheckIfUpdateReq(); 159 | } 160 | #endif 161 | sendNewLaps(); 162 | update_outputs(); 163 | SendCurrRSSIloop(); 164 | 165 | #ifdef WIFI_MODE_ACCESSPOINT 166 | handleDNSRequests(); 167 | #endif 168 | 169 | EepromSettings.save(); 170 | beeperUpdate(); 171 | if(UNLIKELY(!isInRaceMode())) { 172 | thresholdModeStep(); 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Filter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #pragma once 19 | 20 | //http://www.schwietering.com/jayduino/filtuino/index.php 21 | 22 | 23 | //Low pass bessel filter order=2 alpha1=0.01 24 | class FilterBeLp2_10HZ 25 | { 26 | public: 27 | FilterBeLp2_10HZ() 28 | { 29 | v[0]=0.0; 30 | v[1]=0.0; 31 | } 32 | private: 33 | float v[3]; 34 | public: 35 | float step(float x) //class II 36 | { 37 | v[0] = v[1]; 38 | v[1] = v[2]; 39 | v[2] = (1.492279154364811733e-3 * x) 40 | + (-0.87068345511128286685 * v[0]) 41 | + (1.86471433849382361991 * v[1]); 42 | return 43 | (v[0] + v[2]) 44 | +2 * v[1]; 45 | } 46 | }; 47 | 48 | 49 | //Low pass bessel filter order=2 alpha1=0.02, ie 20hz at 1000hz sample rate 50 | class FilterBeLp2_20HZ 51 | { 52 | public: 53 | FilterBeLp2_20HZ() 54 | { 55 | v[0] = 0.0; 56 | v[1] = 0.0; 57 | } 58 | private: 59 | double v[3]; 60 | public: 61 | double step(double x) //class II 62 | { 63 | v[0] = v[1]; 64 | v[1] = v[2]; 65 | v[2] = (5.593440209108096160e-3 * x) 66 | + (-0.75788377219702429688 * v[0]) 67 | + (1.73551001136059190877 * v[1]); 68 | return 69 | (v[0] + v[2]) 70 | + 2 * v[1]; 71 | } 72 | }; 73 | 74 | //Low pass bessel filter order=2 alpha1=0.05 75 | class FilterBeLp2_50HZ 76 | { 77 | public: 78 | FilterBeLp2_50HZ() 79 | { 80 | v[0]=0.0; 81 | v[1]=0.0; 82 | } 83 | private: 84 | float v[3]; 85 | public: 86 | float step(float x) //class II 87 | { 88 | v[0] = v[1]; 89 | v[1] = v[2]; 90 | v[2] = (2.921062558939069298e-2 * x) 91 | + (-0.49774398476624526211 * v[0]) 92 | + (1.38090148240868249019 * v[1]); 93 | return 94 | (v[0] + v[2]) 95 | +2 * v[1]; 96 | } 97 | }; 98 | 99 | 100 | //Low pass bessel filter order=2 alpha1=0.1 101 | class FilterBeLp2_100HZ 102 | { 103 | public: 104 | FilterBeLp2_100HZ() 105 | { 106 | v[0]=0.0; 107 | v[1]=0.0; 108 | } 109 | private: 110 | float v[3]; 111 | public: 112 | float step(float x) //class II 113 | { 114 | v[0] = v[1]; 115 | v[1] = v[2]; 116 | v[2] = (9.053999669813994622e-2 * x) 117 | + (-0.24114073878907091308 * v[0]) 118 | + (0.87898075199651115597 * v[1]); 119 | return 120 | (v[0] + v[2]) 121 | +2 * v[1]; 122 | } 123 | }; 124 | 125 | 126 | //Low pass bessel filter order=2 alpha1=0.0002 127 | class FilterBeLp2Slow 128 | { 129 | public: 130 | FilterBeLp2Slow() 131 | { 132 | v[0] = 0.0; 133 | v[1] = 0.0; 134 | } 135 | private: 136 | double v[3]; 137 | public: 138 | double step(double x) //class II 139 | { 140 | v[0] = v[1]; 141 | v[1] = v[2]; 142 | v[2] = (6.378909348514483213e-7 * x) 143 | + (-0.99723520262946085957 * v[0]) 144 | + (1.99723265106572145378 * v[1]); 145 | return 146 | (v[0] + v[2]) 147 | + 2 * v[1]; 148 | } 149 | }; 150 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/HardwareConfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | /////define Pins////// 19 | #include "HardwareConfig.h" 20 | 21 | #include 22 | 23 | uint8_t CS_PINS[MAX_NUM_RECEIVERS] = {CS1, CS2, CS3, CS4, CS5, CS6}; 24 | 25 | void InitHardwarePins() { 26 | 27 | pinMode(SCK, OUTPUT); 28 | pinMode(MOSI, OUTPUT); 29 | for(int i = 0; i < MAX_NUM_RECEIVERS; i++) { 30 | pinMode(CS_PINS[i], OUTPUT); 31 | digitalWrite(CS_PINS[i], HIGH); 32 | } 33 | //pinMode(MISO, INPUT); 34 | pinMode(BEEPER, OUTPUT); 35 | digitalWrite(BEEPER, LOW); 36 | } 37 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/HardwareConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include 21 | 22 | /// These are all the available targets 23 | #define BOARD_DEFAULT 1 24 | #define BOARD_OLD 2 25 | #define BOARD_TTGO_LORA 3 26 | #define BOARD_WROOM 4 27 | 28 | ///Define the board used here 29 | ///For jye's PCB v2.x the value doesn't need to be changed 30 | ///If you are using v1 of jye's PCB or used the wiring diagram you'll need to change this to "BOARD_OLD" 31 | ///To define your own custom board take a look at the "targets" directory 32 | #ifndef BOARD 33 | #define BOARD BOARD_DEFAULT 34 | #endif 35 | 36 | /// If your setup doesn't use an OLED remove or comment the following line 37 | #define OLED 38 | 39 | // Selects the wifi mode to operate in. 40 | // One of these must be uncommented. 41 | // 42 | #define WIFI_MODE_ACCESSPOINT 43 | // For now the AP name needs to be defined regardless of mode. 44 | #define WIFI_AP_NAME "Chorus32 LapTimer" 45 | 46 | // When in client mode you also need to specify the 47 | // ssid and password. 48 | //#define WIFI_MODE_CLIENT 49 | // For now the ssid and password needs to be defined regardless of mode 50 | #define WIFI_SSID "testnetwork" 51 | #define WIFI_PASSWORD "testpassword" 52 | 53 | /// Enables Bluetooth support. Disabled by default. If you enable it you might need to change the partition scheme to "Huge APP" 54 | //#define USE_BLUETOOTH 55 | // For now the bluetooth name needs to be defined regardless of if it's enabled or not 56 | #define BLUETOOTH_NAME WIFI_AP_NAME 57 | /// Outputs all messages on the serial port. Used to use Livetime via USB 58 | #define USE_SERIAL_OUTPUT 59 | 60 | // Enable TCP support. Currently this needs a special version of the app: https://github.com/Smeat/Chorus-RF-Laptimer/releases/tag/tcp_support 61 | //#define USE_TCP 62 | 63 | // Enables the ArduinoOTA service. It allows flashing over WiFi and enters an emergency mode if a crashloop is detected. 64 | //#define USE_ARDUINO_OTA 65 | 66 | // BELOW ARE THE ADVANCED SETTINGS! ONLY CHANGE THEM IF YOU KNOW WHAT YOUR ARE DOING! 67 | 68 | #define EEPROM_VERSION_NUMBER 9 // Increment when eeprom struct modified 69 | #define MAX_NUM_RECEIVERS 6 70 | #define VOLTAGE_UPDATE_INTERVAL_MS 1000 // interval of the battery voltage reading 71 | #define MIN_TUNE_TIME 30000 // value in micro seconds 72 | #define MAX_UDP_CLIENTS 5 73 | #define MAX_TCP_CLIENTS 5 74 | #define MAX_LAPS_NUM 100 // Maximum number of supported laps per pilot 75 | // 800 and 2700 are about average min max raw values 76 | #define RSSI_ADC_READING_MAX 2700 77 | #define RSSI_ADC_READING_MIN 800 78 | // defines the time after which the crash loop detection assumes the operation is stable 79 | #define CRASH_COUNT_RESET_TIME_MS 300000 80 | 81 | #include "targets/target.h" // Needs to be at the bottom 82 | 83 | void InitHardwarePins(); 84 | extern uint8_t CS_PINS[MAX_NUM_RECEIVERS]; 85 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Laptime.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Laptime.h" 19 | 20 | #include 21 | #include 22 | 23 | #include "HardwareConfig.h" 24 | #include "settings_eeprom.h" 25 | #include "Comms.h" 26 | 27 | static volatile uint32_t LapTimes[MAX_NUM_RECEIVERS][MAX_LAPS_NUM]; 28 | static volatile int lap_counter[MAX_NUM_RECEIVERS] = {0, 0, 0, 0, 0, 0}; //Keep track of what lap we are up too 29 | static int last_lap_sent[MAX_NUM_RECEIVERS]; 30 | 31 | static uint32_t MinLapTime = 5000; //this is in millis 32 | static uint32_t start_time = 0; 33 | 34 | void resetLaptimes() { 35 | for (int i = 0; i < getNumReceivers(); ++i) { 36 | lap_counter[i] = 0; 37 | last_lap_sent[i] = 0; 38 | } 39 | } 40 | 41 | void sendNewLaps() { 42 | for (int i = 0; i < getNumReceivers(); ++i) { 43 | int laps_to_send = lap_counter[i] - last_lap_sent[i]; 44 | if(laps_to_send > 0) { 45 | for(int j = 0; j < laps_to_send; ++j) { 46 | sendLap(lap_counter[i] - j, i); 47 | } 48 | last_lap_sent[i] += laps_to_send; 49 | } 50 | } 51 | } 52 | 53 | uint32_t getLaptime(uint8_t receiver, uint8_t lap) { 54 | return LapTimes[receiver][lap]; 55 | } 56 | 57 | uint32_t getLaptime(uint8_t receiver) { 58 | return getLaptime(receiver, lap_counter[receiver]); 59 | } 60 | 61 | uint32_t getLaptimeRel(uint8_t receiver, uint8_t lap) { 62 | if(lap == 1) { 63 | return getLaptime(receiver, lap) - start_time; 64 | } else if(lap == 0) { 65 | return 0; 66 | } 67 | return getLaptime(receiver, lap) - getLaptime(receiver, lap - 1); 68 | } 69 | 70 | uint32_t getLaptimeRelToStart(uint8_t receiver, uint8_t lap) { 71 | return getLaptime(receiver, lap) - start_time; 72 | } 73 | 74 | uint32_t getLaptimeRel(uint8_t receiver) { 75 | return getLaptimeRel(receiver, lap_counter[receiver]); 76 | } 77 | 78 | uint8_t addLap(uint8_t receiver, uint32_t time) { 79 | lap_counter[receiver] = lap_counter[receiver] + 1; 80 | LapTimes[receiver][lap_counter[receiver]] = time; 81 | return lap_counter[receiver]; 82 | } 83 | 84 | uint32_t getMinLapTime() { 85 | return MinLapTime; 86 | } 87 | 88 | void setMinLapTime(uint32_t time) { 89 | MinLapTime = time; 90 | } 91 | 92 | uint8_t getCurrentLap(uint8_t receiver) { 93 | return lap_counter[receiver]; 94 | } 95 | 96 | void startRaceLap() { 97 | resetLaptimes(); 98 | start_time = millis(); 99 | } 100 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Laptime.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __LAPTIME_H__ 19 | #define __LAPTIME_H__ 20 | 21 | #include 22 | 23 | void resetLaptimes(); 24 | void addLap(uint8_t receiver); 25 | uint32_t getMinLapTime(); 26 | void setMinLapTime(uint32_t time); 27 | uint32_t getLaptime(uint8_t receiver); 28 | uint32_t getLaptime(uint8_t receiver, uint8_t lap); 29 | uint32_t getLaptimeRel(uint8_t receiver, uint8_t lap); 30 | uint32_t getLaptimeRelToStart(uint8_t receiver, uint8_t lap); 31 | uint32_t getLaptimeRel(uint8_t receiver); 32 | void startRaceLap(); 33 | 34 | 35 | /** 36 | * Adds a lap to the pool and returns the current lap id 37 | */ 38 | uint8_t addLap(uint8_t receiver, uint32_t time); 39 | /// Laps begin at 1. lap 0 is always 0 40 | uint8_t getCurrentLap(uint8_t receiver); 41 | 42 | /// Sends unsent laps to the output queue 43 | void sendNewLaps(); 44 | 45 | #endif // __LAPTIME_H__ 46 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/OLED.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "OLED.h" 19 | 20 | #include 21 | #include "SSD1306.h" 22 | #include "Font.h" 23 | #include "Timer.h" 24 | #include "Screensaver.h" 25 | #include "ADC.h" 26 | #include "settings_eeprom.h" 27 | #include "RX5808.h" 28 | #include "Calibration.h" 29 | #include "TimerWebServer.h" 30 | #include "Utils.h" 31 | 32 | static uint8_t oledRefreshTime = 50; 33 | static uint32_t last_input_ms = 0; 34 | static bool display_standby_status = false; 35 | 36 | static Timer oledTimer = Timer(oledRefreshTime); 37 | 38 | static SSD1306 display(0x3c, 21, 22); // 21 and 22 are default pins 39 | 40 | typedef struct oled_page_s { 41 | void* data; 42 | void (*init)(void* data); 43 | void (*draw_page)(void* data); 44 | void (*process_input)(void* data, uint8_t index, uint8_t type); 45 | } oled_page_t; 46 | 47 | static struct rxPageData_s { 48 | uint8_t currentPilotNumber; 49 | } rxPageData; 50 | 51 | 52 | 53 | oled_page_t oled_pages[] = { 54 | {NULL, NULL, summary_page_update, next_page_input}, 55 | {NULL, NULL, adc_page_update, next_page_input}, 56 | {NULL, NULL, calib_page_update, calib_page_input}, 57 | {NULL, NULL, airplane_page_update, airplane_page_input}, 58 | {&rxPageData, rx_page_init, rx_page_update, rx_page_input} 59 | }; 60 | 61 | #define NUM_OLED_PAGES (sizeof(oled_pages)/sizeof(oled_pages[0])) 62 | 63 | static uint8_t current_page = 0; 64 | 65 | static void oledNextPage() { 66 | current_page = (current_page + 1) % NUM_OLED_PAGES; 67 | } 68 | 69 | void oledSetup(void) { 70 | display.init(); 71 | display.flipScreenVertically(); 72 | display.clear(); 73 | display.drawFastImage(0, 0, 128, 64, ChorusLaptimerLogo_Screensaver); 74 | display.display(); 75 | display.setFont(Dialog_plain_9); 76 | 77 | for(uint8_t i = 0; i < NUM_OLED_PAGES; ++i) { 78 | if(oled_pages[i].init) { 79 | oled_pages[i].init(oled_pages[i].data); 80 | } 81 | } 82 | last_input_ms = millis(); 83 | } 84 | 85 | void OLED_CheckIfUpdateReq() { 86 | if (oledTimer.hasTicked()) { 87 | if(millis() - last_input_ms > getDisplayTimeout() && getDisplayTimeout() != 0) { 88 | if(!display_standby_status) { 89 | display.displayOff(); // going in standby 90 | display_standby_status = true; 91 | } 92 | } else if(display_standby_status) { 93 | display.displayOn(); 94 | display_standby_status = false; 95 | } 96 | if(!display_standby_status) { 97 | if(oled_pages[current_page].draw_page) { 98 | display.clear(); 99 | oled_pages[current_page].draw_page(oled_pages[current_page].data); 100 | display.display(); 101 | } 102 | } 103 | oledTimer.reset(); 104 | } 105 | } 106 | 107 | void oledInjectInput(uint8_t index, uint8_t type) { 108 | if(!display_standby_status) { 109 | if(oled_pages[current_page].process_input) { 110 | oled_pages[current_page].process_input(oled_pages[current_page].data, index, type); 111 | } 112 | } else { // turn display on again 113 | display.displayOn(); 114 | } 115 | last_input_ms = millis(); 116 | } 117 | 118 | void next_page_input(void* data, uint8_t index, uint8_t type) { 119 | (void)data; 120 | if(index == 0 && type == BUTTON_SHORT) { 121 | oledNextPage(); 122 | } 123 | } 124 | 125 | void rx_page_init(void* data) { 126 | rxPageData_s* my_data = (rxPageData_s*) data; 127 | my_data->currentPilotNumber = 0; 128 | } 129 | 130 | void rx_page_input(void* data, uint8_t index, uint8_t type) { 131 | rxPageData_s* my_data = (rxPageData_s*) data; 132 | if(index == 0 && type == BUTTON_SHORT) { 133 | ++my_data->currentPilotNumber; 134 | if(my_data->currentPilotNumber >= getNumReceivers()) { 135 | oledNextPage(); 136 | my_data->currentPilotNumber = 0; 137 | } 138 | } 139 | else if(index == 1 && type == BUTTON_SHORT) { 140 | incrementRxFrequency(my_data->currentPilotNumber); 141 | } 142 | else if(index == 1 && type == BUTTON_LONG) { 143 | incrementRxBand(my_data->currentPilotNumber); 144 | } 145 | } 146 | 147 | void rx_page_update(void* data) { 148 | // Gather Data 149 | rxPageData_s* my_data = (rxPageData_s*) data; 150 | uint8_t frequencyIndex = getRXChannel(my_data->currentPilotNumber) + (8 * getRXBand(my_data->currentPilotNumber)); 151 | uint16_t frequency = channelFreqTable[frequencyIndex]; 152 | 153 | // Display things 154 | display.setTextAlignment(TEXT_ALIGN_LEFT); 155 | display.setFont(ArialMT_Plain_16); 156 | display.drawString(0, 0, "Settings for RX" + String(my_data->currentPilotNumber + 1)); 157 | display.drawString(0, 18, getBandLabel(getRXBand(my_data->currentPilotNumber)) + String(getRXChannel(my_data->currentPilotNumber) + 1) + " - " + frequency); 158 | if (getRSSI(my_data->currentPilotNumber) < 600) { 159 | display.drawProgressBar(48, 35, 120 - 42, 8, map(600, 600, 3500, 0, 85)); 160 | } else { 161 | display.drawProgressBar(48, 35, 120 - 42, 8, map(getRSSI(my_data->currentPilotNumber), 600, 3500, 0, 85)); 162 | } 163 | display.setFont(Dialog_plain_9); 164 | display.drawString(0,35, "RSSI: " + String(getRSSI(my_data->currentPilotNumber) / 12)); 165 | display.drawVerticalLine(45 + map(getRSSIThreshold(my_data->currentPilotNumber), 600, 3500, 0, 85), 35, 8); // line to show the RSSIthresholds 166 | display.drawString(0,46, "Btn2 SHORT - Channel."); 167 | display.drawString(0,55, "Btn2 LONG - Band."); 168 | } 169 | 170 | void summary_page_update(void* data) { 171 | // Display on time 172 | display.setTextAlignment(TEXT_ALIGN_LEFT); 173 | // Hours 174 | if (millis() / 3600000 < 10) { 175 | display.drawString(0, 0, "0" + String(millis() / 3600000) + ":"); 176 | } else { 177 | display.drawString(0, 0, String(millis() / 3600000) + ":"); 178 | } 179 | // Mins 180 | if (millis() % 3600000 / 60000 < 10) { 181 | display.drawString(18, 0, "0" + String(millis() % 3600000 / 60000) + ":"); 182 | } else { 183 | display.drawString(18, 0, String(millis() % 3600000 / 60000) + ":"); 184 | } 185 | // Seconds 186 | if (millis() % 60000 / 1000 < 10) { 187 | display.drawString(36, 0, "0" + String(millis() % 60000 / 1000)); 188 | } else { 189 | display.drawString(36, 0, String(millis() % 60000 / 1000)); 190 | } 191 | 192 | // Voltage 193 | if (getADCVBATmode() != 0) { 194 | display.setTextAlignment(TEXT_ALIGN_RIGHT); 195 | display.drawString(127, 0, String(getVbatFloat(), 2) + "V"); 196 | } 197 | 198 | if (getADCVBATmode() == INA219) { 199 | display.drawString(90, 0, String(getMaFloat()/1000, 2) + "A"); 200 | } 201 | 202 | // Rx modules 203 | display.setTextAlignment(TEXT_ALIGN_LEFT); 204 | #define RSSI_BAR_LENGTH (127 - 42) 205 | #define RSSI_BAR_HEIGHT 8 206 | #define RSSI_BAR_X_OFFSET 40 207 | for (int i = 0; i < getNumReceivers(); i++) { 208 | display.drawString(0, 9 + i * 9, getBandLabel(getRXBand(i)) + String(getRXChannel(i) + 1) + ", " + String(getRSSI(i) / 12)); 209 | display.drawProgressBar(RSSI_BAR_X_OFFSET, 10 + i * 9, RSSI_BAR_LENGTH, RSSI_BAR_HEIGHT, map(getRSSI(i), RSSI_ADC_READING_MIN, RSSI_ADC_READING_MAX, 0, 100)); 210 | display.drawVerticalLine(RSSI_BAR_X_OFFSET + map(MAX(getRSSIThreshold(i), RSSI_ADC_READING_MIN), RSSI_ADC_READING_MIN, RSSI_ADC_READING_MAX, 0, RSSI_BAR_LENGTH), 10 + i * 9, RSSI_BAR_HEIGHT); // line to show the RSSIthresholds 211 | } 212 | } 213 | 214 | void adc_page_update(void* data) { 215 | display.setTextAlignment(TEXT_ALIGN_LEFT); 216 | display.drawString(0, 0, "ADC loop " + String(getADCLoopCount() * (1000.0 / oledRefreshTime)) + " Hz"); 217 | setADCLoopCount(0); 218 | display.drawString(0, 9, String(getMaFloat()) + " mA"); 219 | } 220 | 221 | void calib_page_update(void* data) { 222 | display.setTextAlignment(TEXT_ALIGN_LEFT); 223 | display.drawString(0, 0, "Frequency - " + String(channelFreqTable[getcalibrationFreqIndex()]) + "Hz"); 224 | display.drawString(0, 9, "Min = " + String(EepromSettings.RxCalibrationMin[0]) + ", Max = " + String(EepromSettings.RxCalibrationMax[0])); 225 | display.drawString(0, 18, "Min = " + String(EepromSettings.RxCalibrationMin[1]) + ", Max = " + String(EepromSettings.RxCalibrationMax[1])); 226 | display.drawString(0, 27, "Min = " + String(EepromSettings.RxCalibrationMin[2]) + ", Max = " + String(EepromSettings.RxCalibrationMax[2])); 227 | display.drawString(0, 36, "Min = " + String(EepromSettings.RxCalibrationMin[3]) + ", Max = " + String(EepromSettings.RxCalibrationMax[3])); 228 | display.drawString(0, 45, "Min = " + String(EepromSettings.RxCalibrationMin[4]) + ", Max = " + String(EepromSettings.RxCalibrationMax[4])); 229 | display.drawString(0, 54, "Min = " + String(EepromSettings.RxCalibrationMin[5]) + ", Max = " + String(EepromSettings.RxCalibrationMax[5])); 230 | } 231 | 232 | void calib_page_input(void* data, uint8_t index, uint8_t type) { 233 | (void)data; 234 | if(index == 1 && type == BUTTON_SHORT) { 235 | rssiCalibration(); 236 | } 237 | else { 238 | next_page_input(data, index, type); 239 | } 240 | } 241 | 242 | void airplane_page_update(void* data) { 243 | display.setTextAlignment(TEXT_ALIGN_LEFT); 244 | display.drawString(0, 0, "Airplane Mode Settings:"); 245 | display.drawString(0, 15, "Long Press Button 2 to"); 246 | display.drawString(0, 26, "toggle Airplane mode."); 247 | if (!isAirplaneModeOn()) { 248 | display.drawString(0, 42, "Airplane Mode: OFF"); 249 | display.drawString(0, 51, "WiFi: ON | Draw: " + String(getMaFloat()/1000, 2) + "A"); 250 | } else { 251 | display.drawString(0, 42, "Airplane Mode: ON"); 252 | display.drawString(0, 51, "WiFi: OFF | Draw: " + String(getMaFloat()/1000, 2) + "A"); 253 | } 254 | } 255 | 256 | void airplane_page_input(void* data, uint8_t index, uint8_t type) { 257 | if(index == 1 && type == BUTTON_LONG) { 258 | toggleAirplaneMode(); 259 | } else { 260 | next_page_input(data, index, type); 261 | } 262 | } 263 | 264 | void incrementRxFrequency(uint8_t currentRXNumber) { 265 | uint8_t currentRXChannel = getRXChannel(currentRXNumber); 266 | uint8_t currentRXBand = getRXBand(currentRXNumber); 267 | currentRXChannel++; 268 | if (currentRXChannel >= 8) { 269 | //currentRXBand++; 270 | currentRXChannel = 0; 271 | } 272 | if (currentRXBand >= 7 && currentRXChannel >= 2) { 273 | currentRXBand = 0; 274 | currentRXChannel = 0; 275 | } 276 | setModuleChannelBand(currentRXChannel,currentRXBand,currentRXNumber); 277 | } 278 | void incrementRxBand(uint8_t currentRXNumber) { 279 | uint8_t currentRXChannel = getRXChannel(currentRXNumber); 280 | uint8_t currentRXBand = getRXBand(currentRXNumber); 281 | currentRXBand++; 282 | if (currentRXBand >= 8) { 283 | currentRXBand = 0; 284 | } 285 | setModuleChannelBand(currentRXChannel,currentRXBand,currentRXNumber); 286 | } 287 | 288 | void setDisplayScreenNumber(uint16_t num) { 289 | if(num < NUM_OLED_PAGES) { 290 | current_page = num; 291 | } 292 | } 293 | 294 | uint16_t getDisplayScreenNumber() { 295 | return current_page; 296 | } 297 | 298 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/OLED.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __OLED_H__ 19 | #define __OLED_H__ 20 | 21 | #include 22 | 23 | enum button_press { 24 | BUTTON_SHORT, 25 | BUTTON_LONG 26 | }; 27 | 28 | void oledSetup(); 29 | void OLED_CheckIfUpdateReq(); 30 | void setDisplayScreenNumber(uint16_t num); 31 | uint16_t getDisplayScreenNumber(); 32 | void incrementRxFrequency(uint8_t currentRXNumber); 33 | void incrementRxBand(uint8_t currentRXNumber); 34 | 35 | void setNumberOfOledScreens(uint8_t num); 36 | uint8_t getNumberOfOledScreens(); 37 | 38 | void setNumberOfBaseScreens(uint8_t num); 39 | uint8_t getNumberOfBaseScreens(); 40 | 41 | void rx_page_update(void* data); 42 | void rx_page_input(void* data, uint8_t index, uint8_t type); 43 | void rx_page_init(void* data); 44 | 45 | void summary_page_update(void* data); 46 | void adc_page_update(void* data); 47 | void calib_page_update(void* data); 48 | void calib_page_input(void* data, uint8_t index, uint8_t type); 49 | 50 | void airplane_page_update(void* data); 51 | void airplane_page_input(void* data, uint8_t index, uint8_t type); 52 | 53 | void oledInjectInput(uint8_t index, uint8_t type); 54 | void next_page_input(void* data, uint8_t index, uint8_t type); 55 | 56 | 57 | #endif // __OLED_H__ 58 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Output.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Output.h" 19 | 20 | #include "Comms.h" 21 | #include "UDP.h" 22 | #include "Serial.h" 23 | #ifdef USE_BLUETOOTH 24 | #include "Bluetooth.h" 25 | #endif 26 | #ifdef USE_TCP 27 | #include "TCP.h" 28 | #endif 29 | #ifdef USE_WEBSOCKET_OUTPUT 30 | #include "TimerWebServer.h" 31 | #endif 32 | 33 | #include 34 | 35 | #define MAX_OUTPUT_BUFFER_SIZE 1500 36 | 37 | static uint8_t output_buffer[MAX_OUTPUT_BUFFER_SIZE]; 38 | static int output_buffer_pos = 0; //Keep track of where we are in the Queue 39 | 40 | static SemaphoreHandle_t queue_semaphore = NULL; 41 | 42 | // TODO: define this somewhere else! 43 | static output_t outputs[] = { 44 | {NULL, udp_init, udp_send_packet, udp_update, output_input_callback}, 45 | #ifdef USE_SERIAL_OUTPUT 46 | {NULL, serial_init, serial_send_packet, serial_update, output_input_callback}, 47 | #endif // USE_SERIAL_OUTPUT 48 | #ifdef USE_BLUETOOTH 49 | {NULL, bluetooth_init, bluetooth_send_packet, bluetooth_update, output_input_callback}, 50 | #endif // USE_BLUETOOTH 51 | #ifdef USE_TCP 52 | {NULL, tcp_init, tcp_send_packet, tcp_update, output_input_callback}, 53 | #endif // USE_TCP 54 | #ifdef USE_WEBSOCKET_OUTPUT 55 | {NULL, NULL, send_websocket, read_websocket, output_input_callback}, 56 | #endif // USE_WEBSOCKET_OUTPUT 57 | }; 58 | 59 | #define OUTPUT_SIZE (sizeof(outputs)/sizeof(outputs[0])) 60 | 61 | bool IRAM_ATTR addToSendQueue(uint8_t item) { 62 | if(xSemaphoreTake(queue_semaphore, portMAX_DELAY)) { 63 | if(output_buffer_pos >= MAX_OUTPUT_BUFFER_SIZE) { 64 | xSemaphoreGive(queue_semaphore); 65 | return false; 66 | } 67 | output_buffer[output_buffer_pos++] = item; 68 | xSemaphoreGive(queue_semaphore); 69 | return true; 70 | } 71 | return false; 72 | } 73 | 74 | uint8_t IRAM_ATTR addToSendQueue(uint8_t * buff, uint32_t length) { 75 | for (int i = 0; i < length; ++i) { 76 | if(!addToSendQueue(buff[i])) { 77 | return i; 78 | } 79 | } 80 | return length; 81 | } 82 | 83 | void update_outputs() { 84 | // First update all inputs before sending new stuff 85 | for(int i = 0; i < OUTPUT_SIZE; ++i) { 86 | if(outputs[i].update){ 87 | outputs[i].update(&outputs[i]); 88 | } 89 | } 90 | if(xSemaphoreTake(queue_semaphore, portMAX_DELAY)) { 91 | if(output_buffer_pos > 0) { 92 | // Send current buffer to all configured outputs 93 | for(int i = 0; i < OUTPUT_SIZE; ++i) { 94 | if(outputs[i].sendPacket) { 95 | outputs[i].sendPacket(&outputs[i], output_buffer, output_buffer_pos); 96 | } 97 | } 98 | output_buffer_pos = 0; 99 | } 100 | xSemaphoreGive(queue_semaphore); 101 | } 102 | } 103 | 104 | void init_outputs() { 105 | queue_semaphore = xSemaphoreCreateMutex(); 106 | for(int i = 0; i < OUTPUT_SIZE; ++i) { 107 | if(outputs[i].init) { 108 | outputs[i].init(&outputs[i]); 109 | } 110 | } 111 | } 112 | 113 | void output_input_callback(uint8_t* buf, uint32_t size) { 114 | for(uint32_t i = 0; i < size; ++i) { 115 | if(buf[i] == '\n') { 116 | i += 1; // include \n 117 | uint8_t ControlPacket = buf[0]; 118 | uint8_t NodeAddr = buf[1]; 119 | handleSerialControlInput((char*)buf, ControlPacket, NodeAddr, i); 120 | // We move the buf pointer and adjust the size, so we can begin from i=0 again 121 | buf = buf + i; 122 | size -= i; 123 | i = 0; 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Output.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __OUTPUT_H__ 19 | #define __OUTPUT_H__ 20 | 21 | #include 22 | #include 23 | 24 | 25 | typedef struct output_s { 26 | void* data; 27 | void (*init)(void* output); 28 | void (*sendPacket)(void* output, uint8_t* buf, uint32_t size); 29 | void (*update)(void* output); 30 | void (*handle_input_callback)(uint8_t* buf, uint32_t size); 31 | } output_t; 32 | 33 | /** 34 | * \return true if the item has been added to the queue 35 | */ 36 | bool IRAM_ATTR addToSendQueue(uint8_t item); 37 | 38 | /** 39 | * \return the number of items added to the queue 40 | */ 41 | uint8_t IRAM_ATTR addToSendQueue(uint8_t * buff, uint32_t length); 42 | 43 | void update_outputs(); 44 | void init_outputs(); 45 | 46 | 47 | void output_input_callback(uint8_t* buf, uint32_t size); 48 | 49 | 50 | #endif // __OUTPUT_H__ 51 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/RX5808.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #define SPI_ADDRESS_SYNTH_B 0x01 19 | #define SPI_ADDRESS_POWER 0x0A 20 | #define SPI_ADDRESS_STATE 0x0F 21 | 22 | #define PowerDownState 0b11111111111111111111 23 | #define DefaultPowerState 0b00010000110000010011 24 | 25 | #define ResetReg 0b00000000000000000000 26 | #define StandbyReg 0b00000000000000000010 27 | #define PowerOnReg 0b00000000000000000001 28 | 29 | #include "RX5808.h" 30 | 31 | #include "HardwareConfig.h" 32 | #include "settings_eeprom.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | static volatile uint8_t RXBand[MAX_NUM_RECEIVERS]; 40 | static volatile uint8_t RXChannel[MAX_NUM_RECEIVERS]; 41 | 42 | void InitSPI() { 43 | SPI.begin(VRX_SCK, VRX_MISO, VRX_MOSI); 44 | delay(200); 45 | } 46 | 47 | void rxWrite(uint8_t addressBits, uint32_t dataBits, uint8_t CSpin) { 48 | 49 | uint32_t data = addressBits | (1 << 4) | (dataBits << 5); 50 | SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0)); 51 | digitalWrite(CSpin, LOW); 52 | SPI.transferBits(data, NULL, 25); 53 | 54 | digitalWrite(CSpin, HIGH); 55 | delayMicroseconds(MIN_TUNE_TIME); 56 | SPI.endTransaction(); 57 | 58 | } 59 | 60 | void rxWriteNode(uint8_t node, uint8_t addressBits, uint32_t dataBits) { 61 | if (node < MAX_NUM_RECEIVERS) { 62 | rxWrite(addressBits, dataBits, CS_PINS[node]); 63 | } 64 | } 65 | 66 | void rxWriteAll(uint8_t addressBits, uint32_t dataBits) { 67 | 68 | uint32_t data = addressBits | (1 << 4) | (dataBits << 5); 69 | SPI.beginTransaction(SPISettings(1000000, LSBFIRST, SPI_MODE0)); 70 | for(int i = 0; i < MAX_NUM_RECEIVERS; i++) { 71 | digitalWrite(CS_PINS[i], LOW); 72 | } 73 | 74 | SPI.transferBits(data, NULL, 25); 75 | 76 | for(int i = 0; i < MAX_NUM_RECEIVERS; i++) { 77 | digitalWrite(CS_PINS[i], HIGH); 78 | } 79 | 80 | delayMicroseconds(MIN_TUNE_TIME); 81 | 82 | SPI.endTransaction(); 83 | 84 | } 85 | 86 | void RXstandBy(uint8_t NodeAddr) { 87 | rxWriteNode(NodeAddr, SPI_ADDRESS_STATE, StandbyReg); 88 | } 89 | 90 | void RXpowerOn(uint8_t NodeAddr) { 91 | rxWriteNode(NodeAddr, SPI_ADDRESS_STATE, PowerOnReg); 92 | } 93 | 94 | void RXreset(uint8_t NodeAddr) { 95 | rxWriteNode(NodeAddr, SPI_ADDRESS_STATE, ResetReg); 96 | } 97 | 98 | 99 | void PowerDownAll() { 100 | //for (int i = 0; i < getNumReceivers(); i++) { 101 | //rxWrite(SPI_ADDRESS_POWER, PowerDownState, i); 102 | //RXstandBy(i); 103 | //delay(100); 104 | //} 105 | rxWriteAll(SPI_ADDRESS_POWER, PowerDownState); 106 | } 107 | 108 | void RXPowerDown(uint8_t NodeAddr) { 109 | rxWriteNode(NodeAddr, SPI_ADDRESS_POWER, PowerDownState); 110 | } 111 | 112 | void PowerUpAll() { 113 | for (int i = 0; i < getNumReceivers(); i++) { 114 | rxWrite(SPI_ADDRESS_POWER, DefaultPowerState, i); 115 | } 116 | } 117 | 118 | void RXPowerUp(uint8_t NodeAddr) { 119 | rxWriteNode(NodeAddr, SPI_ADDRESS_POWER, DefaultPowerState); 120 | } 121 | 122 | void SelectivePowerUp() { //powerup only the RXs that have been requested 123 | for (int i = 0; i < getNumReceivers(); i++) { 124 | RXreset(i); 125 | //RXstandBy(i); 126 | delay(50); 127 | RXpowerOn(i); 128 | //PowerUp(i); 129 | rxWrite(SPI_ADDRESS_POWER, DefaultPowerState, i); 130 | // 131 | // Serial.print("Power up: "); 132 | // Serial.println(i); 133 | } 134 | } 135 | 136 | uint16_t getSynthRegisterBFreq(uint16_t f) { 137 | return ((((f - 479) / 2) / 32) << 7) | (((f - 479) / 2) % 32); 138 | } 139 | 140 | 141 | void setChannel(uint8_t channel, uint8_t NodeAddr) { 142 | Serial.println(channel); 143 | 144 | if (channel <= 7) { 145 | Serial.println("setChannel"); 146 | RXChannel[NodeAddr] = channel; 147 | uint8_t band = RXBand[NodeAddr]; 148 | uint16_t SetFreq = setModuleChannelBand(channel, band, NodeAddr); 149 | (void)SetFreq; 150 | } 151 | } 152 | 153 | void setBand(uint8_t band, uint8_t NodeAddr) { 154 | Serial.println(band); 155 | 156 | if (band <= MAX_BAND) { 157 | Serial.println("setBand"); 158 | RXBand[NodeAddr] = band; 159 | uint8_t channel = RXChannel[NodeAddr]; 160 | uint16_t SetFreq = setModuleChannelBand(channel, band, NodeAddr); 161 | (void)SetFreq; 162 | } 163 | } 164 | 165 | uint16_t setModuleChannelBand(uint8_t NodeAddr) { 166 | Serial.println("setModuleChannelBand"); 167 | Serial.print(RXChannel[NodeAddr]); 168 | Serial.print(","); 169 | Serial.println(RXBand[NodeAddr]); 170 | 171 | uint8_t index = RXChannel[NodeAddr] + (8 * RXBand[NodeAddr]); 172 | Serial.println(index); 173 | uint16_t frequency = channelFreqTable[index]; 174 | return setModuleFrequency(frequency, NodeAddr); 175 | } 176 | 177 | uint16_t setModuleChannelBand(uint8_t channel, uint8_t band, uint8_t NodeAddr) { 178 | Serial.println("setModuleChannelBand"); 179 | Serial.print(channel); 180 | Serial.print(","); 181 | Serial.println(band); 182 | 183 | uint8_t index = channel + (8 * band); 184 | Serial.println(index); 185 | uint16_t frequency = channelFreqTable[index]; 186 | RXBand[NodeAddr] = band; 187 | RXChannel[NodeAddr] = channel; 188 | return setModuleFrequency(frequency, NodeAddr); 189 | } 190 | 191 | uint16_t setModuleFrequency(uint16_t frequency, uint8_t NodeAddr) { 192 | rxWriteNode(NodeAddr, SPI_ADDRESS_SYNTH_B, getSynthRegisterBFreq(frequency)); 193 | return frequency; 194 | } 195 | 196 | uint16_t setModuleFrequencyAll(uint16_t frequency) { 197 | rxWriteAll(SPI_ADDRESS_SYNTH_B, getSynthRegisterBFreq(frequency)); 198 | return frequency; 199 | } 200 | 201 | String getBandLabel(int band) { 202 | switch (band) { 203 | case 0: 204 | return "R"; 205 | break; 206 | case 1: 207 | return "A"; 208 | break; 209 | case 2: 210 | return "B"; 211 | break; 212 | case 3: 213 | return "E"; 214 | break; 215 | case 4: 216 | return "F"; 217 | break; 218 | case 5: 219 | return "D"; 220 | break; 221 | case 6: 222 | return "X"; 223 | break; 224 | case 7: 225 | return "XX"; 226 | break; 227 | default: 228 | return ""; 229 | break; 230 | } 231 | } 232 | 233 | void setRXBand(uint8_t node, uint8_t band) { 234 | RXBand[node] = band; 235 | } 236 | uint8_t getRXBand(uint8_t node) { 237 | return RXBand[node]; 238 | } 239 | 240 | void setRXChannel(uint8_t node, uint8_t channel) { 241 | RXChannel[node] = channel; 242 | } 243 | 244 | uint8_t getRXChannel(uint8_t node) { 245 | return RXChannel[node]; 246 | } 247 | 248 | uint16_t getFrequencyFromBandChannel(uint8_t band, uint8_t channel) { 249 | if(channel >= 8 || band > MAX_BAND) { 250 | return 0; 251 | } 252 | uint8_t index = channel + (8 * band); 253 | uint16_t frequency = channelFreqTable[index]; 254 | return frequency; 255 | } 256 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/RX5808.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef HEADER_RX5808 19 | #define HEADER_RX5808 20 | 21 | #include 22 | 23 | #include 24 | 25 | #define MAX_BAND 7 26 | 27 | //// Channels to send to the SPI registers 28 | //const uint16_t channelTable[] PROGMEM = { 29 | // // Channel 1 - 8 30 | // 0x281D, 0x288F, 0x2902, 0x2914, 0x2987, 0x2999, 0x2A0C, 0x2A1E, // Raceband 31 | // 0x2A05, 0x299B, 0x2991, 0x2987, 0x291D, 0x2913, 0x2909, 0x289F, // Band A 32 | // 0x2903, 0x290C, 0x2916, 0x291F, 0x2989, 0x2992, 0x299C, 0x2A05, // Band B 33 | // 0x2895, 0x288B, 0x2881, 0x2817, 0x2A0F, 0x2A19, 0x2A83, 0x2A8D, // Band E 34 | // 0x2906, 0x2910, 0x291A, 0x2984, 0x298E, 0x2998, 0x2A02, 0x2A0C, // Band F / Airwave 35 | // 0x2609, 0x261C, 0x268E, 0x2701, 0x2713, 0x2786, 0x2798, 0x280B, // Band D / 5.3 36 | // 0x248f, 0x2499, 0x2503, 0x250d, 0x2909, 0x2913, 0x291d, 0x2987, //connex 37 | // 0x2991, 0x299b, 0x299b, 0x299b, 0x299b, 0x299b, 0x299b, 0x299b //even more connex, last 6 unused!!! 38 | //}; 39 | // 40 | //// Channels' MHz Values. Just for reference. Not used in code. 41 | 42 | const uint16_t channelFreqTable[] = { 43 | // // Channel 1 - 8 44 | 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917, // Raceband 45 | 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725, // Band A 46 | 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866, // Band B 47 | 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945, // Band E 48 | 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880, // Band F / Airwave 49 | 5362, 5399, 5436, 5473, 5510, 5547, 5584, 5621, // Band D / 5.3 50 | 5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805, // connex 51 | 5825, 5845, 5845, 5845, 5845, 5845, 5845, 5845 // even more connex, last 6 unused!!! 52 | }; 53 | 54 | //uint16_t BandChannelFreqTable[8][8] = { 55 | // // // Channel 1 - 8 56 | // {5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917}, // Raceband 57 | // {5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725}, // Band A 58 | // {5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866}, // Band B 59 | // {5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945}, // Band E 60 | // {5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880}, // Band F / Airwave 61 | // {5362, 5399, 5436, 5473, 5510, 5547, 5584, 5621}, // Band D / 5.3 62 | // {5180, 5200, 5220, 5240, 5745, 5765, 5785, 5805}, // connex 63 | // {5825, 5845, 5845, 5845, 5845, 5845, 5845, 5845} 64 | // // even more connex, last 6 unused!!! 65 | //}; 66 | 67 | uint16_t setModuleChannel(uint8_t channel, uint8_t band); 68 | 69 | void InitSPI(); 70 | void SetDefaultRegs(); 71 | uint16_t setModuleChannelBand(uint8_t NodeAddr); 72 | uint16_t setModuleChannelBand(uint8_t channel, uint8_t band, uint8_t NodeAddr); 73 | uint16_t setModuleFrequencyAll(uint16_t frequency); 74 | uint16_t setModuleFrequency(uint16_t frequency, uint8_t NodeAddr); 75 | String getBandLabel(int band); 76 | 77 | void setRXBand(uint8_t node, uint8_t band); 78 | uint8_t getRXBand(uint8_t node); 79 | 80 | void setRXChannel(uint8_t node, uint8_t channel); 81 | uint8_t getRXChannel(uint8_t node); 82 | 83 | uint16_t getFrequencyFromBandChannel(uint8_t band, uint8_t channel); 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Screensaver.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef SCREENSAVER_h 19 | #define SCREENSAVER_h 20 | //------------------------------------------------------------------------------ 21 | // File generated by LCD Assistant 22 | // http://en.radzio.dxp.pl/bitmap_converter/ 23 | // How to; 24 | // https://github.com/ThingPulse/esp8266-oled-ssd1306/issues/53#issuecomment-354174183 25 | //------------------------------------------------------------------------------ 26 | 27 | const uint8_t ChorusLaptimerLogo_Screensaver[] PROGMEM = { 28 | //const unsigned char ChorusLaptimerLogo_Screensaver [] = { 29 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 30 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 31 | 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 32 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 33 | 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x01, 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0xFC, 0x1F, 0x00, 0x00, 0x00, 0x00, 35 | 0x00, 0xFE, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x07, 0xFF, 36 | 0x0F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x3F, 0xF8, 0x7F, 0x00, 0x00, 0x00, 37 | 0x80, 0xFF, 0x3F, 0xC1, 0xFF, 0x03, 0x00, 0x00, 0xC0, 0xFF, 0x1F, 0x08, 38 | 0xFE, 0x1F, 0x00, 0x00, 0xC0, 0xFF, 0x0F, 0x40, 0xF0, 0xFF, 0x00, 0x00, 39 | 0xE0, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x07, 0x00, 0xF0, 0xFF, 0x07, 0x00, 40 | 0x1C, 0xFC, 0x7F, 0x00, 0xF0, 0xFF, 0x03, 0x00, 0x7C, 0xE0, 0xFF, 0x03, 41 | 0xF0, 0xFF, 0x01, 0x00, 0xFE, 0x87, 0xFF, 0x3F, 0xC0, 0xFF, 0x01, 0x00, 42 | 0xFF, 0x1F, 0xFC, 0x3F, 0x00, 0xFE, 0x00, 0x80, 0xFF, 0xFF, 0xE0, 0x1F, 43 | 0x00, 0xF0, 0x00, 0xC0, 0xFF, 0xFF, 0x01, 0x1F, 0x00, 0x00, 0x00, 0xC0, 44 | 0xFF, 0x7F, 0x00, 0x08, 0x04, 0x80, 0x01, 0xE0, 0xFF, 0x3F, 0x00, 0x00, 45 | 0x04, 0xC0, 0x0F, 0xF0, 0xFF, 0x1F, 0x00, 0x00, 0x04, 0xC0, 0x7F, 0xF0, 46 | 0xFF, 0x0F, 0x00, 0x00, 0x04, 0xC0, 0xFF, 0xF9, 0xFF, 0x07, 0x00, 0x00, 47 | 0x04, 0xE0, 0xFF, 0xF7, 0xFF, 0x03, 0x00, 0x00, 0x04, 0xE0, 0xFF, 0x83, 48 | 0xFF, 0x01, 0x00, 0x00, 0x04, 0xE0, 0xFF, 0x03, 0xFC, 0x00, 0x00, 0x00, 49 | 0x00, 0xE0, 0xFF, 0x01, 0xF0, 0x00, 0x00, 0x00, 0x20, 0xE0, 0xFF, 0x01, 50 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 51 | 0x00, 0xE4, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x00, 52 | 0x90, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x07, 0x00, 0x00, 53 | 0x80, 0x03, 0xFC, 0x00, 0xC8, 0x07, 0x00, 0x00, 0x80, 0x3F, 0x70, 0x00, 54 | 0xE0, 0x07, 0x00, 0x00, 0x80, 0xFF, 0x87, 0x00, 0xF4, 0x07, 0x00, 0x00, 55 | 0x80, 0xFF, 0x47, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x00, 0xFC, 0x07, 0x00, 56 | 0xB0, 0x07, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x80, 0xC2, 0x07, 0x00, 0x00, 57 | 0x00, 0x00, 0x03, 0x80, 0xF3, 0x07, 0x00, 0x00, 0x10, 0x00, 0x0C, 0xC0, 58 | 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xC0, 0xFF, 0x03, 0x00, 0x00, 59 | 0x00, 0x00, 0xFE, 0xE3, 0xFF, 0x03, 0x00, 0x00, 0x04, 0x00, 0xFF, 0xFF, 60 | 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x0F, 0xFF, 0x01, 0x00, 0x00, 61 | 0x04, 0x80, 0xFF, 0x07, 0xF0, 0x00, 0x00, 0x00, 0x20, 0xC0, 0xFF, 0x07, 62 | 0xC0, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 63 | 0x00, 0xF0, 0xFF, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 64 | 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x7F, 0xF8, 0x0F, 65 | 0x00, 0x00, 0x30, 0x00, 0x90, 0xF3, 0xF8, 0x0F, 0x00, 0x00, 0x40, 0x00, 66 | 0x80, 0xC1, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x02, 0x84, 0xC1, 0x00, 0x0C, 67 | 0x00, 0x00, 0x00, 0x10, 0x80, 0xE3, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x80, 68 | 0x80, 0x73, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 69 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 70 | 0x80, 0xFF, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xF0, 0x0F, 71 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x00, 72 | 0x00, 0x0C, 0x18, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xF8, 0x07, 73 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xF0, 0x0F, 0x00, 0x00, 0x00, 0x00, 74 | 0x80, 0xFF, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x0C, 75 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 76 | 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0xF8, 0x0F, 77 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 78 | 0x80, 0x7F, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x80, 0xE1, 0xB8, 0x01, 79 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xC1, 0xF0, 0x01, 0x00, 0x00, 0x00, 0x00, 80 | 0x80, 0xC1, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x00, 0x00, 81 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 82 | 0x00, 0x3E, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 83 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 84 | 0x80, 0xFF, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x18, 0x00, 85 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x0D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 86 | 0x80, 0x1D, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3D, 0x00, 0x00, 87 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 88 | 0x80, 0xE7, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF8, 0x0F, 89 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 90 | 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0xF8, 0x0F, 91 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 92 | 0x00, 0xC0, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x07, 93 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 94 | 0x80, 0x7F, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0xF8, 0x01, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 96 | 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xF8, 0x0F, 97 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 98 | 0x80, 0xCD, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCD, 0xF8, 0x0F, 99 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 100 | 0x80, 0x7B, 0xD8, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7B, 0xD8, 0x0C, 101 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x0C, 0x00, 0x00, 0x00, 0x00, 102 | 0x00, 0x21, 0xD8, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 103 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 104 | 0x80, 0xCC, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCF, 0xF8, 0x0F, 105 | 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 106 | 0x00, 0x7B, 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x03, 107 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xF8, 0x0F, 0x00, 0x00, 0x00, 0x00, 108 | 0x80, 0xE3, 0xF0, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF3, 0x60, 0x0C, 109 | 0x00, 0x00, 0x00, 0x00, 0x80, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 110 | 0x80, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xCF, 0x00, 0x00, 111 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 112 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 113 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 114 | 0x00, 0x00, 0x00, 0x00, }; 115 | #endif 116 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Serial.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Serial.h" 19 | 20 | #include "Output.h" 21 | 22 | #include 23 | #include 24 | 25 | #define SERIAL_INPUT_BUF 50 26 | 27 | static uint8_t SerialBuffIn[SERIAL_INPUT_BUF]; 28 | static uint8_t current_pos = 0; 29 | 30 | void serial_update(void* output) { 31 | while (Serial.available() > 0) { 32 | char rc = Serial.read(); 33 | SerialBuffIn[current_pos] = rc; 34 | ++current_pos; 35 | // Found packet, so handle it 36 | if(rc == '\n') { 37 | output_t* out = (output_t*)output; 38 | out->handle_input_callback(SerialBuffIn, current_pos); 39 | current_pos = 0; 40 | } else if(current_pos >= SERIAL_INPUT_BUF) { 41 | // we are overflowing, so we just discard the current buffer which should just be garbage 42 | current_pos = 0; 43 | } 44 | } 45 | } 46 | 47 | void serial_init(void* output) { 48 | (void)output; 49 | } 50 | 51 | void serial_send_packet(void* output, uint8_t* buf, uint32_t size) { 52 | (void) output; 53 | Serial.write(buf, size); 54 | } 55 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __SERIAL_H__ 19 | #define __SERIAL_H__ 20 | 21 | #include 22 | 23 | void serial_init(void* output); 24 | void serial_update(void* output); 25 | void serial_send_packet(void* output, uint8_t* buf, uint32_t size); 26 | 27 | #endif // __SERIAL_H__ 28 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/TCP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "TCP.h" 19 | 20 | #include "HardwareConfig.h" 21 | #include "Output.h" 22 | 23 | #include 24 | #include 25 | 26 | static int tcp_server = -1; 27 | 28 | #define TCP_BUF_LEN 1500 29 | static uint8_t packetBuffer[TCP_BUF_LEN]; 30 | 31 | static int tcpClients[MAX_TCP_CLIENTS]; 32 | 33 | void tcp_init(void* output) { 34 | if ((tcp_server=socket(AF_INET, SOCK_STREAM, 0)) == -1){ 35 | return; 36 | } 37 | 38 | int yes = 1; 39 | if (setsockopt(tcp_server,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) { 40 | close(tcp_server); 41 | tcp_server = -1; 42 | return; 43 | } 44 | 45 | struct sockaddr_in addr; 46 | memset((char *) &addr, 0, sizeof(addr)); 47 | addr.sin_family = AF_INET; 48 | addr.sin_port = htons(9000); 49 | addr.sin_addr.s_addr = INADDR_ANY; 50 | if(bind(tcp_server , (struct sockaddr*)&addr, sizeof(addr)) == -1){ 51 | close(tcp_server); 52 | tcp_server = -1; 53 | return; 54 | } 55 | fcntl(tcp_server, F_SETFL, O_NONBLOCK); 56 | listen(tcp_server, MAX_TCP_CLIENTS); 57 | for(int i = 0; i < MAX_TCP_CLIENTS; ++i) { 58 | tcpClients[i] = -1; 59 | } 60 | log_i("Created tcp socket"); 61 | } 62 | 63 | void IRAM_ATTR tcp_send_packet(void* output, uint8_t* buf, uint32_t size) { 64 | if(tcp_server < 0) return; 65 | if (buf != NULL && size != 0) { 66 | for(int i = 0; i < MAX_TCP_CLIENTS; ++i) { 67 | if(tcpClients[i] >= 0) { 68 | ::send(tcpClients[i], buf, size, 0); 69 | } 70 | } 71 | } 72 | } 73 | 74 | void IRAM_ATTR tcp_update(void* output) { 75 | if(tcp_server < 0) return; 76 | // check for new connections 77 | struct sockaddr_storage clientAddress; 78 | socklen_t size = sizeof(clientAddress); 79 | int new_socket = accept(tcp_server, (struct sockaddr*)&clientAddress, &size); 80 | if(new_socket > 0) { // new client 81 | int i = 0; 82 | for(i = 0; i < MAX_TCP_CLIENTS; ++i) { 83 | if(tcpClients[i] < 0) { // free spot 84 | tcpClients[i] = new_socket; 85 | fcntl(new_socket, F_SETFL, O_NONBLOCK); 86 | log_d("Got new tcp client!"); 87 | break; 88 | } 89 | } 90 | // No space for the new client found 91 | if(i == MAX_TCP_CLIENTS) { 92 | log_w("Got new tcp client, but no free space is available!"); 93 | ::close(new_socket); 94 | } 95 | } 96 | // Receive the data and remove broken connections 97 | for(int i = 0; i < MAX_TCP_CLIENTS; ++i) { 98 | if(tcpClients[i] >= 0) { 99 | int len = recv(tcpClients[i], packetBuffer, TCP_BUF_LEN - 1, 0); 100 | if (len == 0){ // client shut down 101 | log_d("Removed tcp client due to len == 0"); 102 | tcpClients[i] = -1; 103 | } else if (len < 0) { // other error 104 | if(errno != EWOULDBLOCK && errno != EAGAIN) { 105 | log_d("tcp error: %d", errno); 106 | // Remove client on all other errors just in case 107 | close(tcpClients[i]); 108 | tcpClients[i] = -1; 109 | } 110 | } else { // got new data 111 | output_t* out = (output_t*)output; 112 | packetBuffer[len] = 0; 113 | out->handle_input_callback(packetBuffer, len); 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/TCP.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __TCP_H__ 19 | #define __TCP_H__ 20 | 21 | #include "Output.h" 22 | 23 | #include 24 | #include 25 | 26 | void IRAM_ATTR tcp_send_packet(void* output, uint8_t* buf, uint32_t size); 27 | void tcp_init(void* output); 28 | void IRAM_ATTR tcp_update(void* output); 29 | 30 | #endif // __TCP_H__ 31 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Timer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include 19 | #include "Timer.h" 20 | 21 | 22 | Timer::Timer(uint16_t delay) { 23 | this->delay = delay; 24 | this->nextTick = millis() + this->delay; 25 | this->ticked = false; 26 | } 27 | 28 | bool Timer::hasTicked() { 29 | if (this->ticked) 30 | return true; 31 | 32 | if (millis() >= this->nextTick) { 33 | this->ticked = true; 34 | return true; 35 | } 36 | 37 | return false; 38 | } 39 | 40 | void Timer::reset() { 41 | this->nextTick = millis() + this->delay; 42 | this->ticked = false; 43 | } 44 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef TIMER_H 19 | #define TIMER_H 20 | 21 | 22 | #include 23 | 24 | 25 | class Timer { 26 | private: 27 | uint32_t nextTick; 28 | uint16_t delay; 29 | bool ticked; 30 | 31 | public: 32 | Timer(uint16_t delay); 33 | bool hasTicked(); 34 | void reset(); 35 | }; 36 | 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/TimerWebServer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #pragma once 19 | 20 | void InitWebServer(); 21 | 22 | bool isAirplaneModeOn(); 23 | void toggleAirplaneMode(); 24 | void airplaneModeOff(); 25 | void airplaneModeOn(); 26 | bool isUpdating(); 27 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/UDP.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "UDP.h" 19 | 20 | #include "HardwareConfig.h" 21 | #include "Output.h" 22 | 23 | #include 24 | #include 25 | 26 | static int udp_server = -1; 27 | 28 | #define UDP_BUF_LEN 1500 29 | static uint8_t packetBuffer[UDP_BUF_LEN]; 30 | 31 | static struct udp_source_s { 32 | uint32_t addr; 33 | uint16_t port; 34 | } udpClients[MAX_UDP_CLIENTS]; 35 | 36 | void add_ip_port(uint32_t addr, uint16_t port) { 37 | // if current ip is already known move it to the front. or if on the last entry delete it to make room 38 | for(int i = 0; i < MAX_UDP_CLIENTS; ++i) { 39 | if((udpClients[i].addr == addr && udpClients[i].port == port) || (i+1 == MAX_UDP_CLIENTS)) { 40 | memmove(udpClients + 1, udpClients, i * sizeof(udpClients[0])); 41 | break; 42 | } 43 | } 44 | udpClients[0].addr = addr; 45 | udpClients[0].port = port; 46 | } 47 | 48 | void udp_init(void* output) { 49 | if ((udp_server=socket(AF_INET, SOCK_DGRAM, 0)) == -1){ 50 | return; 51 | } 52 | 53 | int yes = 1; 54 | if (setsockopt(udp_server,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) < 0) { 55 | close(udp_server); 56 | udp_server = -1; 57 | return; 58 | } 59 | 60 | struct sockaddr_in addr; 61 | memset((char *) &addr, 0, sizeof(addr)); 62 | addr.sin_family = AF_INET; 63 | addr.sin_port = htons(9000); 64 | addr.sin_addr.s_addr = INADDR_ANY; 65 | if(bind(udp_server , (struct sockaddr*)&addr, sizeof(addr)) == -1){ 66 | close(udp_server); 67 | udp_server = -1; 68 | return; 69 | } 70 | fcntl(udp_server, F_SETFL, O_NONBLOCK); 71 | } 72 | 73 | void IRAM_ATTR udp_send_packet(void* output, uint8_t* buf, uint32_t size) { 74 | if(udp_server < 0) return; 75 | if (buf != NULL && size != 0) { 76 | for(int i = 0; i < MAX_UDP_CLIENTS; ++i) { 77 | if(udpClients[i].addr != 0) { 78 | struct sockaddr_in recipient; 79 | recipient.sin_addr.s_addr = udpClients[i].addr; 80 | recipient.sin_family = AF_INET; 81 | recipient.sin_port = udpClients[i].port; 82 | int len = sendto(udp_server, buf, size, 0, (struct sockaddr*) &recipient, sizeof(recipient)); 83 | if(len < 0) { 84 | udpClients[i].addr = 0; 85 | close(udp_server); 86 | udp_init(output); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | void IRAM_ATTR udp_update(void* output) { 94 | if(udp_server < 0) return; 95 | struct sockaddr_in si_other; 96 | int slen = sizeof(si_other) , len; 97 | if ((len = recvfrom(udp_server, packetBuffer, UDP_BUF_LEN - 1, MSG_DONTWAIT, (struct sockaddr *) &si_other, (socklen_t *)&slen)) < 1){ 98 | return; 99 | } 100 | add_ip_port(si_other.sin_addr.s_addr, si_other.sin_port); 101 | packetBuffer[len] = 0; 102 | output_t* out = (output_t*)output; 103 | out->handle_input_callback(packetBuffer, len); 104 | } 105 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/UDP.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __UDP_H__ 19 | #define __UDP_H__ 20 | 21 | #include "Output.h" 22 | 23 | #include 24 | #include 25 | 26 | void IRAM_ATTR udp_send_packet(void* output, uint8_t* buf, uint32_t size); 27 | void udp_init(void* output); 28 | void IRAM_ATTR udp_update(void* output); 29 | 30 | #endif // __UDP_H__ 31 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Utils.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Utils.h" 19 | 20 | #include 21 | #include 22 | 23 | uint8_t IRAM_ATTR HEX_TO_BYTE (uint8_t hi, uint8_t lo) { 24 | return TO_BYTE(hi) * 16 + TO_BYTE(lo); 25 | } 26 | 27 | uint16_t IRAM_ATTR HEX_TO_UINT16 (uint8_t * buf) { 28 | return (HEX_TO_BYTE(buf[0], buf[1]) << 8) + (HEX_TO_BYTE(buf[2], buf[3])); 29 | } 30 | 31 | int32_t IRAM_ATTR HEX_TO_SIGNED_LONG (uint8_t * buf) { 32 | #define LEN 8 33 | int32_t temp = 0; 34 | for (int i = 0; i < LEN; i++) { 35 | temp += TO_BYTE(buf[LEN - 1 - i]) * (int32_t)1 << (i * 4); 36 | } 37 | return temp; 38 | } 39 | 40 | void IRAM_ATTR halfByteToHex(uint8_t *buf, uint8_t val) { 41 | buf[0] = TO_HEX((val & 0x0F)); 42 | } 43 | 44 | void IRAM_ATTR byteToHex(uint8_t *buf, uint8_t val) { 45 | halfByteToHex(buf, val >> 4); 46 | halfByteToHex(&buf[1], val); 47 | } 48 | 49 | void IRAM_ATTR intToHex(uint8_t *buf, uint16_t val) { 50 | byteToHex(buf, val >> 8); 51 | byteToHex(&buf[2], val & 0x00FF); 52 | } 53 | 54 | void IRAM_ATTR longToHex(uint8_t *buf, uint32_t val) { 55 | intToHex(buf, val >> 16); 56 | intToHex(&buf[4], val & 0x0000FFFF); 57 | } 58 | 59 | float fmap(float x, float in_min, float in_max, float out_min, float out_max) 60 | { 61 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; 62 | } 63 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include 19 | #include 20 | 21 | #define TO_BYTE(i) (i <= '9' ? i - 0x30 : i - 0x41 + 10) 22 | #define TO_HEX(i) (i <= 9 ? 0x30 + i : 0x41 + i - 10) 23 | 24 | uint8_t IRAM_ATTR HEX_TO_BYTE (uint8_t hi, uint8_t lo); 25 | uint16_t IRAM_ATTR HEX_TO_UINT16 (uint8_t * buf); 26 | int32_t IRAM_ATTR HEX_TO_SIGNED_LONG (uint8_t * buf); 27 | void IRAM_ATTR halfByteToHex(uint8_t *buf, uint8_t val); 28 | void IRAM_ATTR byteToHex(uint8_t *buf, uint8_t val); 29 | void IRAM_ATTR intToHex(uint8_t *buf, uint16_t val); 30 | void IRAM_ATTR longToHex(uint8_t *buf, uint32_t val); 31 | 32 | float fmap(float x, float in_min, float in_max, float out_min, float out_max); 33 | 34 | #define LIKELY(x) __builtin_expect((x), 1) 35 | #define UNLIKELY(x) __builtin_expect((x), 0) 36 | 37 | #define MAX(a,b) \ 38 | ({ __typeof__ (a) _a = (a); \ 39 | __typeof__ (b) _b = (b); \ 40 | _a > _b ? _a : _b; }) 41 | 42 | #define MIN(a,b) \ 43 | ({ __typeof__ (a) _a = (a); \ 44 | __typeof__ (b) _b = (b); \ 45 | _a < _b ? _a : _b; }) 46 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Watchdog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "Watchdog.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | void watchdog_add_task() { 26 | esp_task_wdt_add(NULL); 27 | } 28 | 29 | void watchdog_feed() { 30 | TIMERG0.wdt_wprotect = TIMG_WDT_WKEY_VALUE; 31 | TIMERG0.wdt_feed = 1; 32 | TIMERG0.wdt_wprotect = 0; 33 | } 34 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Watchdog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __WATCHDOG_H__ 19 | #define __WATCHDOG_H__ 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | 26 | void watchdog_add_task(); 27 | void watchdog_feed(); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | 33 | 34 | #endif // __WATCHDOG_H__ 35 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Wireless.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "TimerWebServer.h" 25 | #include "settings_eeprom.h" 26 | #include "targets/target.h" 27 | 28 | static const uint16_t DNS_PORT = 53; 29 | static IPAddress apIP(192, 168, 4, 1); 30 | static DNSServer dnsServer; 31 | static bool airplaneMode = false; 32 | static uint32_t delayTime = 500; // milliseconds 33 | static uint32_t maxConnectionTime = 60000; // 2 minutes 34 | 35 | static void WiFiEvent(WiFiEvent_t event) { 36 | switch(event) { 37 | case SYSTEM_EVENT_AP_START: 38 | log_i("Setting system hostname"); 39 | WiFi.softAPsetHostname("chorus32"); 40 | break; 41 | case SYSTEM_EVENT_STA_START: 42 | log_i("Setting system hostname"); 43 | WiFi.setHostname("chorus32"); 44 | break; 45 | case SYSTEM_EVENT_STA_DISCONNECTED: 46 | log_i("WiFi network disconnected, retrying..."); 47 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 48 | default: 49 | break; 50 | } 51 | } 52 | 53 | void InitWifiAP() { 54 | WiFi.begin(); 55 | delay( 500 ); // If not used, somethimes following command fails 56 | WiFi.mode( WIFI_AP ); 57 | uint8_t protocol = getWiFiProtocol() ? (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) : (WIFI_PROTOCOL_11B); 58 | ESP_ERROR_CHECK(esp_wifi_set_protocol(WIFI_IF_AP, protocol)); 59 | WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); 60 | uint8_t channel = getWiFiChannel(); 61 | if(channel < 1 || channel > 13) { 62 | channel = 1; 63 | } 64 | log_i("Starting wifi %s on channel %i in mode %s", WIFI_AP_NAME, channel, protocol ? "bgn" : "b"); 65 | WiFi.softAP(WIFI_AP_NAME, NULL, channel); 66 | // if DNSServer is started with "*" for domain name, it will reply with 67 | // provided IP to all DNS request 68 | dnsServer.setErrorReplyCode(DNSReplyCode::NoError); 69 | dnsServer.start(DNS_PORT, "*", apIP); 70 | } 71 | 72 | bool InitWifiClient() { 73 | uint32_t timeWaited = 0; 74 | 75 | WiFi.mode(WIFI_MODE_STA); 76 | 77 | log_i("Connecting to: %s", WIFI_SSID); 78 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 79 | 80 | while(WiFi.status() != WL_CONNECTED) { 81 | if(timeWaited >= maxConnectionTime) { 82 | log_e("Connection timeout"); 83 | return false; 84 | } 85 | 86 | delay(delayTime); 87 | timeWaited = timeWaited + delayTime; 88 | } 89 | 90 | log_i("WiFi connected"); 91 | log_i("IP address: %s", WiFi.localIP().toString().c_str()); 92 | 93 | MDNS.begin("chorus32"); 94 | 95 | log_i("mDNS responder started"); 96 | 97 | return true; 98 | } 99 | 100 | void InitWifi() { 101 | WiFi.onEvent(WiFiEvent); 102 | 103 | #if defined(WIFI_MODE_ACCESSPOINT) 104 | InitWifiAP(); 105 | #elif defined(WIFI_MODE_CLIENT) 106 | if(!InitWifiClient()) { 107 | log_i("Failed to connect to WiFi Network"); 108 | log_i("Starting up in AP mode instead!"); 109 | InitWifiAP(); 110 | } 111 | #endif 112 | } 113 | 114 | void handleDNSRequests() { 115 | dnsServer.processNextRequest(); 116 | } 117 | 118 | void airplaneModeOn() { 119 | // Enable Airplane Mode (WiFi Off) 120 | log_i("Airplane Mode On"); 121 | WiFi.mode(WIFI_OFF); 122 | airplaneMode = true; 123 | } 124 | 125 | void airplaneModeOff() { 126 | // Disable Airplane Mode (WiFi On) 127 | log_i("Airplane Mode OFF"); 128 | InitWifiAP(); 129 | InitWebServer(); 130 | airplaneMode = false; 131 | } 132 | 133 | // Toggle Airplane mode on and off based on current state 134 | void toggleAirplaneMode() { 135 | if (!airplaneMode) { 136 | airplaneModeOn(); 137 | } else { 138 | airplaneModeOff(); 139 | } 140 | } 141 | 142 | bool isAirplaneModeOn() { 143 | return airplaneMode; 144 | } 145 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/Wireless.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef __WIRELESS_H__ 19 | #define __WIRELESS_H__ 20 | 21 | void InitWifiAP(); 22 | void handleDNSRequests(); 23 | void dnsHandleRequests(); 24 | void airplaneModeOn(); 25 | void airplaneModeOff(); 26 | void toggleAirplaneMode(); 27 | bool isAirplaneModeOn(); 28 | bool InitWifiClient(); 29 | void InitWifi(); 30 | 31 | #endif // __WIRELESS_H__ 32 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/crc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include "crc.h" /* include the header file generated with pycrc */ 19 | #include 20 | #include 21 | 22 | 23 | 24 | /** 25 | * Static table used for the table_driven implementation. 26 | */ 27 | static const crc_t crc_table[256] = { 28 | 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 29 | 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 30 | 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 31 | 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 32 | 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 33 | 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 34 | 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, 35 | 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 36 | 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, 37 | 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 38 | 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 39 | 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 40 | 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 41 | 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 42 | 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, 43 | 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 44 | 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 45 | 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 46 | 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 47 | 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 48 | 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 49 | 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 50 | 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 51 | 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 52 | 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 53 | 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 54 | 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 55 | 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 56 | 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 57 | 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 58 | 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 59 | 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d 60 | }; 61 | 62 | 63 | crc_t crc_update(crc_t crc, const void *data, size_t data_len) 64 | { 65 | const unsigned char *d = (const unsigned char *)data; 66 | unsigned int tbl_idx; 67 | 68 | while (data_len--) { 69 | tbl_idx = (crc ^ *d) & 0xff; 70 | crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; 71 | d++; 72 | } 73 | return crc & 0xffffffff; 74 | } 75 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/crc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #ifndef CRC_H 19 | #define CRC_H 20 | 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | 29 | /** 30 | * The definition of the used algorithm. 31 | * 32 | * This is not used anywhere in the generated code, but it may be used by the 33 | * application code to call algorithm-specific code, if desired. 34 | */ 35 | #define CRC_ALGO_TABLE_DRIVEN 1 36 | 37 | 38 | /** 39 | * The type of the CRC values. 40 | * 41 | * This type must be big enough to contain at least 32 bits. 42 | */ 43 | typedef uint_fast32_t crc_t; 44 | 45 | 46 | /** 47 | * Calculate the initial crc value. 48 | * 49 | * \return The initial crc value. 50 | */ 51 | static inline crc_t crc_init(void) 52 | { 53 | return 0xffffffff; 54 | } 55 | 56 | 57 | /** 58 | * Update the crc value with new data. 59 | * 60 | * \param[in] crc The current crc value. 61 | * \param[in] data Pointer to a buffer of \a data_len bytes. 62 | * \param[in] data_len Number of bytes in the \a data buffer. 63 | * \return The updated crc value. 64 | */ 65 | crc_t crc_update(crc_t crc, const void *data, size_t data_len); 66 | 67 | 68 | /** 69 | * Calculate the final crc value. 70 | * 71 | * \param[in] crc The current crc value. 72 | * \return The final crc value. 73 | */ 74 | static inline crc_t crc_finalize(crc_t crc) 75 | { 76 | return crc ^ 0xffffffff; 77 | } 78 | 79 | 80 | #ifdef __cplusplus 81 | } /* closing brace for extern "C" */ 82 | #endif 83 | 84 | #endif /* CRC_H */ 85 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/settings_eeprom.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #include 19 | #include "settings_eeprom.h" 20 | #include "Comms.h" 21 | #include "RX5808.h" 22 | #include "crc.h" 23 | 24 | struct EepromSettingsStruct EepromSettings; 25 | 26 | static bool eepromSaveRequired = false; 27 | 28 | void EepromSettingsStruct::setup() { 29 | EEPROM.begin(512); 30 | this->load(); 31 | } 32 | 33 | void EepromSettingsStruct::load() { 34 | EEPROM.get(0, *this); 35 | Serial.println("EEPROM LOADED"); 36 | 37 | Serial.println(EepromSettings.NumReceivers); 38 | Serial.println(NumReceivers); 39 | 40 | if (this->eepromVersionNumber != EEPROM_VERSION_NUMBER) { 41 | this->defaults(); 42 | Serial.println("EEPROM DEFAULTS LOADED"); 43 | } 44 | } 45 | 46 | bool EepromSettingsStruct::SanityCheck() { 47 | 48 | bool IsGoodEEPROM = true; 49 | 50 | if (EepromSettings.NumReceivers > MAX_NUM_RECEIVERS) { 51 | IsGoodEEPROM = false; 52 | Serial.print("Error: Corrupted EEPROM value NumRecievers: "); 53 | Serial.println(EepromSettings.NumReceivers); 54 | return IsGoodEEPROM; 55 | } 56 | 57 | 58 | if (EepromSettings.RXADCfilter > MaxADCFilter) { 59 | IsGoodEEPROM = false; 60 | Serial.print("Error: Corrupted EEPROM value RXADCfilter: "); 61 | Serial.println(EepromSettings.RXADCfilter); 62 | return IsGoodEEPROM; 63 | } 64 | 65 | if (EepromSettings.ADCVBATmode > MaxVbatMode) { 66 | IsGoodEEPROM = false; 67 | Serial.print("Error: Corrupted EEPROM value ADCVBATmode: "); 68 | Serial.println(EepromSettings.ADCVBATmode); 69 | return IsGoodEEPROM; 70 | } 71 | 72 | if (EepromSettings.VBATcalibration > MaxVBATCalibration) { 73 | IsGoodEEPROM = false; 74 | Serial.print("Error: Corrupted EEPROM value VBATcalibration: "); 75 | Serial.println(EepromSettings.VBATcalibration); 76 | return IsGoodEEPROM; 77 | } 78 | 79 | for (int i = 0; i < EepromSettings.NumReceivers; i++) { 80 | if (EepromSettings.RXBand[i] > MaxBand) { 81 | IsGoodEEPROM = false; 82 | Serial.print("Error: Corrupted EEPROM NODE: "); 83 | Serial.print(i); 84 | Serial.print(" value MaxBand: "); 85 | Serial.println(EepromSettings.RXBand[i]); 86 | return IsGoodEEPROM; 87 | } 88 | 89 | } 90 | 91 | for (int i = 0; i < EepromSettings.NumReceivers; i++) { 92 | if (EepromSettings.RXChannel[i] > MaxChannel) { 93 | IsGoodEEPROM = false; 94 | Serial.print("Error: Corrupted EEPROM NODE: "); 95 | Serial.print(i); 96 | Serial.print(" value RXChannel: "); 97 | Serial.println(EepromSettings.RXChannel[i]); 98 | return IsGoodEEPROM; 99 | } 100 | } 101 | 102 | for (int i = 0; i < EepromSettings.NumReceivers; i++) { 103 | if ((EepromSettings.RXfrequencies[i] > MaxFreq) or (EepromSettings.RXfrequencies[i] < MinFreq)) { 104 | IsGoodEEPROM = false; 105 | Serial.print("Error: Corrupted EEPROM NODE: "); 106 | Serial.print(i); 107 | Serial.print(" value RXfrequencies: "); 108 | Serial.println(EepromSettings.RXfrequencies[i]); 109 | return IsGoodEEPROM; 110 | } 111 | } 112 | 113 | for (int i = 0; i < EepromSettings.NumReceivers; i++) { 114 | if (EepromSettings.RSSIthresholds[i] > MaxThreshold) { 115 | IsGoodEEPROM = false; 116 | Serial.print("Error: Corrupted EEPROM NODE: "); 117 | Serial.print(i); 118 | Serial.print(" value RSSIthresholds: "); 119 | Serial.println(EepromSettings.RSSIthresholds[i]); 120 | return IsGoodEEPROM; 121 | } 122 | } 123 | return IsGoodEEPROM && this->validateCRC(); 124 | } 125 | 126 | void EepromSettingsStruct::save() { 127 | if (eepromSaveRequired) { 128 | this->updateCRC(); 129 | EEPROM.put(0, *this); 130 | EEPROM.commit(); 131 | eepromSaveRequired = false; 132 | Serial.println("EEPROM SAVED"); 133 | } 134 | } 135 | 136 | void EepromSettingsStruct::defaults() { 137 | // We are using a temporary struct since we might have invalid values during setup and core 0 might use them 138 | EepromSettingsStruct settings; 139 | // by setting everything to 0 we guarantee that every variable is initialized 140 | memset(&settings, 0, sizeof(EepromSettingsStruct)); 141 | for(uint8_t i = 0; i < MAX_NUM_RECEIVERS; ++i){ 142 | settings.RxCalibrationMax[i] = RSSI_ADC_READING_MAX; 143 | settings.RxCalibrationMin[i] = RSSI_ADC_READING_MIN; 144 | settings.RSSIthresholds[i] = 2048; 145 | settings.RXBand[i] = 0; 146 | settings.RXChannel[i] = i % 8; 147 | settings.RXfrequencies[i] = getFrequencyFromBandChannel(settings.RXBand[i], settings.RXChannel[i]); 148 | } 149 | 150 | settings.eepromVersionNumber = EEPROM_VERSION_NUMBER; 151 | settings.ADCVBATmode = INA219; 152 | settings.RXADCfilter = LPF_20Hz; 153 | settings.VBATcalibration = 1; 154 | settings.NumReceivers = 6; 155 | settings.WiFiProtocol = 1; 156 | settings.WiFiChannel = 1; 157 | 158 | settings.updateCRC(); 159 | 160 | *this = settings; 161 | 162 | EEPROM.put(0, *this); 163 | EEPROM.commit(); 164 | } 165 | 166 | crc_t EepromSettingsStruct::calcCRC() { 167 | crc_t crc = crc_init(); 168 | crc = crc_update(crc, this, sizeof(*this) - sizeof(this->crc)); 169 | crc = crc_finalize(crc); 170 | return crc; 171 | } 172 | 173 | void EepromSettingsStruct::updateCRC() { 174 | this->crc = this->calcCRC(); 175 | } 176 | 177 | bool EepromSettingsStruct::validateCRC(){ 178 | return this->crc == this->calcCRC(); 179 | } 180 | 181 | RXADCfilter_ getRXADCfilter() { 182 | return EepromSettings.RXADCfilter; 183 | } 184 | 185 | ADCVBATmode_ getADCVBATmode() { 186 | return EepromSettings.ADCVBATmode; 187 | } 188 | 189 | void setRXADCfilter(RXADCfilter_ filter) { 190 | EepromSettings.RXADCfilter = filter; 191 | } 192 | 193 | void setADCVBATmode(ADCVBATmode_ mode) { 194 | EepromSettings.ADCVBATmode = mode; 195 | } 196 | 197 | void setSaveRequired() { 198 | eepromSaveRequired = true; 199 | } 200 | 201 | int getWiFiChannel(){ 202 | return EepromSettings.WiFiChannel; 203 | } 204 | int getWiFiProtocol(){ 205 | return EepromSettings.WiFiProtocol; 206 | } 207 | 208 | uint8_t getNumReceivers() { 209 | return EepromSettings.NumReceivers; 210 | } 211 | 212 | uint32_t getDisplayTimeout() { 213 | return EepromSettings.display_timeout_ms; 214 | } 215 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/settings_eeprom.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #pragma once 19 | 20 | #include "HardwareConfig.h" 21 | #include "crc.h" 22 | 23 | enum RXADCfilter_ {LPF_10Hz, LPF_20Hz, LPF_50Hz, LPF_100Hz}; 24 | enum ADCVBATmode_ {OFF, ADC_CH5, ADC_CH6, INA219}; 25 | 26 | #define MaxChannel 7 27 | #define MaxBand 7 28 | 29 | #define MaxFreq 5945 30 | #define MinFreq 5180 31 | 32 | #define MaxADCFilter 3 33 | #define MaxVbatMode 3 34 | #define MaxVBATCalibration 100.00 35 | #define MaxThreshold 4095 36 | 37 | struct EepromSettingsStruct { 38 | uint16_t eepromVersionNumber; 39 | uint8_t RXBand[MAX_NUM_RECEIVERS]; 40 | uint8_t RXChannel[MAX_NUM_RECEIVERS]; 41 | uint16_t RXfrequencies[MAX_NUM_RECEIVERS]; 42 | int RSSIthresholds[MAX_NUM_RECEIVERS]; 43 | RXADCfilter_ RXADCfilter; 44 | ADCVBATmode_ ADCVBATmode; 45 | float VBATcalibration; 46 | uint8_t NumReceivers; 47 | uint16_t RxCalibrationMin[MAX_NUM_RECEIVERS]; 48 | uint16_t RxCalibrationMax[MAX_NUM_RECEIVERS]; 49 | uint8_t WiFiProtocol; // 0 is b only, 1 is bgn 50 | uint8_t WiFiChannel; 51 | uint32_t display_timeout_ms; 52 | crc_t crc; // This MUST be the last variable! 53 | 54 | 55 | void setup(); 56 | void load(); 57 | void save(); 58 | void defaults(); 59 | bool SanityCheck(); 60 | void updateCRC(); 61 | bool validateCRC(); 62 | crc_t calcCRC(); 63 | }; 64 | 65 | extern EepromSettingsStruct EepromSettings; 66 | 67 | RXADCfilter_ getRXADCfilter(); 68 | ADCVBATmode_ getADCVBATmode(); 69 | 70 | void setRXADCfilter(RXADCfilter_ filter); 71 | void setADCVBATmode(ADCVBATmode_ mode); 72 | 73 | int getWiFiChannel(); 74 | int getWiFiProtocol(); 75 | 76 | uint8_t getNumReceivers(); 77 | uint32_t getDisplayTimeout(); 78 | 79 | void setSaveRequired(); 80 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/targets/config_default.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #define BEEPER 14 19 | 20 | #define LEDs 12 21 | 22 | #define BUTTON1 T7 // 27 23 | #define BUTTON2 T4 // 13 24 | 25 | #define CS1 16 26 | #define CS2 5 27 | #define CS3 4 28 | #define CS4 15 29 | #define CS5 25 30 | #define CS6 26 31 | 32 | #define ADC1 ADC1_CHANNEL_0 33 | #define ADC2 ADC1_CHANNEL_3 34 | #define ADC3 ADC1_CHANNEL_6 35 | #define ADC4 ADC1_CHANNEL_7 36 | #define ADC5 ADC1_CHANNEL_4 37 | #define ADC6 ADC1_CHANNEL_5 38 | 39 | #define ADC1_GPIO 36 40 | #define ADC2_GPIO 39 41 | #define ADC3_GPIO 34 42 | #define ADC4_GPIO 35 43 | #define ADC5_GPIO 32 44 | #define ADC6_GPIO 33 45 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/targets/config_old.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #define BEEPER 23 19 | 20 | #define LEDs 17 21 | 22 | #define BUTTON1 T7 // 27 23 | #define BUTTON2 T4 // 13 24 | 25 | #define VRX_SCK 14 26 | #define VRX_MOSI 12 27 | 28 | #define CS1 16 29 | #define CS2 5 30 | #define CS3 4 31 | #define CS4 15 32 | #define CS5 25 33 | #define CS6 26 34 | 35 | #define ADC1 ADC1_CHANNEL_0 36 | #define ADC2 ADC1_CHANNEL_6 37 | #define ADC3 ADC1_CHANNEL_7 38 | #define ADC4 ADC1_CHANNEL_3 39 | #define ADC5 ADC1_CHANNEL_4 40 | #define ADC6 ADC1_CHANNEL_5 41 | 42 | #define ADC1_GPIO 36 43 | #define ADC2_GPIO 34 44 | #define ADC3_GPIO 35 45 | #define ADC4_GPIO 39 46 | #define ADC5_GPIO 32 47 | #define ADC6_GPIO 33 48 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/targets/config_ttgo_lora_v1.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #define BEEPER 14 19 | 20 | #define LEDs 2 21 | 22 | #define USE_CLASSIC_BUTTONS 23 | 24 | #define BUTTON1 13 25 | #define BUTTON2 12 26 | 27 | #define CS1 16 28 | #define CS2 5 29 | #define CS3 4 30 | #define CS4 15 31 | #define CS5 25 32 | #define CS6 26 33 | 34 | #define ADC1 ADC1_CHANNEL_0 35 | #define ADC2 ADC1_CHANNEL_3 36 | #define ADC3 ADC1_CHANNEL_6 37 | #define ADC4 ADC1_CHANNEL_5 38 | #define ADC5 ADC1_CHANNEL_4 39 | #define ADC6 ADC1_CHANNEL_7 // switched with adc 4 due to xtal 40 | 41 | #define ADC1_GPIO 36 42 | #define ADC2_GPIO 39 43 | #define ADC3_GPIO 34 44 | #define ADC4_GPIO 33 45 | #define ADC5_GPIO 32 46 | #define ADC6_GPIO 35 47 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/targets/config_wroom.h: -------------------------------------------------------------------------------- 1 | #define BEEPER 18 2 | 3 | #define LEDs 16 4 | 5 | #define VRX_SCK 26 6 | #define VRX_MOSI 14 7 | 8 | #define CS1 25 9 | #define CS2 27 10 | #define CS3 13 11 | #define CS4 12 12 | #define CS5 15 13 | #define CS6 2 14 | 15 | #define ADC1 ADC1_CHANNEL_5 16 | #define ADC2 ADC1_CHANNEL_4 17 | #define ADC3 ADC1_CHANNEL_7 18 | #define ADC4 ADC1_CHANNEL_6 19 | #define ADC5 ADC1_CHANNEL_0 20 | #define ADC6 ADC1_CHANNEL_3 21 | 22 | #define ADC1_GPIO 33 23 | #define ADC2_GPIO 32 24 | #define ADC3_GPIO 35 25 | #define ADC4_GPIO 34 26 | #define ADC5_GPIO 36 27 | #define ADC6_GPIO 39 28 | 29 | #define I2C_SDA 23 30 | #define I2C_SCL 22 31 | 32 | #ifdef OLED 33 | #undef OLED 34 | #endif 35 | 36 | // enable arduino ota by default, since there is no USB connector on this board 37 | #ifndef USE_ARDUINO_OTA 38 | #define USE_ARDUINO_OTA 39 | #endif 40 | -------------------------------------------------------------------------------- /ESP32LapTimer/src/targets/target.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of Chorus32-ESP32LapTimer 3 | * (see https://github.com/AlessandroAU/Chorus32-ESP32LapTimer). 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | #if BOARD==BOARD_DEFAULT 19 | #include "config_default.h" 20 | #elif BOARD==BOARD_OLD 21 | #include "config_old.h" 22 | #elif BOARD==BOARD_TTGO_LORA 23 | #include "config_ttgo_lora_v1.h" 24 | #elif BOARD==BOARD_WROOM 25 | #include "config_wroom.h" 26 | #else 27 | #error "Unknown board!" 28 | #endif 29 | 30 | #if defined(BUTTON1) && defined(BUTTON2) 31 | #define USE_BUTTONS 32 | #endif 33 | 34 | // Define unconfigured pins 35 | #ifndef VRX_SCK 36 | #define VRX_SCK -1 37 | #endif 38 | #ifndef VRX_MOSI 39 | #define VRX_MOSI -1 40 | #endif 41 | #ifndef VRX_MISO 42 | #define VRX_MISO -1 43 | #endif 44 | 45 | #if !defined(WIFI_MODE_CLIENT) && !defined(WIFI_MODE_ACCESSPOINT) 46 | #error "No WIFI_MODE selected" 47 | #endif 48 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Chorus32-ESP32Laptimer 2 | 3 | This is an ESP32 port of the popular Chorus RF laptimer (https://github.com/voroshkov/Chorus-RF-Laptimer). Using an ESP32 provides much more processing power than AVR based Arduino boards and also has built in Wifi and Bluetooth networking simplifying connectivity options. 4 | 5 | Compared to the original ChorusRF Lamptimer this ESP32 version only requires one RX module per pilot and a single ESP32 (nodemcu or similar) board. This allows you to connect your Lap timer wirelessly with no extra hardware required. However, due to ADC constraints, we are limited to 6 pilots per device. 6 | 7 | Hardware construction is also simplified as both parts are 3.3v logic and there is no need for level shifting or resistors. 8 | 9 | [Click HERE for a video showing the full setup process to get Chorus32 running on your ESP32 using Arduino IDE.](https://www.youtube.com/watch?v=ip2HUVk_lMs). 10 | 11 | [Click Here for German version Part 1](https://www.youtube.com/watch?v=z8xTfuLECME) [Part 2](https://www.youtube.com/watch?v=7wl0CgA8YnM). 12 | 13 | Updates: 14 | ----- 15 | *Important Notice for Chorus32 users!!!:* 16 | 17 | As of last commit the default pinout has been changed to match that of the PCBs currently being tested. 18 | 19 | For anyone that has built a Chorus32 with original schematics do not worry, your unit will continue working with future updates. However you must change `#define BOARD BOARD_DEFAULT` to `#define BOARD BOARD_OLD` in 'HardwareConfig.h' when compiling. 20 | 21 | Added OLED and VBAT measurement support 22 | Auto RSSI threshold setup is also not implemented, just set thresholds manually for now. 23 | 24 | Added inital webserver configuration portal 25 | https://www.youtube.com/watch?v=BVd2t0yO_5A/0.jpg 26 | 27 | Application Support: 28 | ----- 29 | Chorus32 communicates using the Chorus RF Laptimer API, which is supported by LiveTime. 30 | 31 | LiveTime is an incredibly powerful and feature-rich timing system which runs on Windows. It is, however, quite complex, and likely overkill for most users. 32 | 33 | More information can be found here: https://www.livetimescoring.com/ 34 | 35 | If you are looking for a simpler setup, you can also use the Chorus RF Lap Timer app available for: 36 | 37 | Android: https://play.google.com/store/apps/details?id=app.andrey_voroshkov.chorus_laptimer 38 | 39 | iOS: https://itunes.apple.com/us/app/chorus-rf-laptimer/id1296647206?mt=8 40 | 41 | Serial to UDP bridge. 42 | ----- 43 | 44 | To use this wirelessly with livetime you must use a third party application to a bridge vitural serial port with the UDP connection to the timer. The native ethernet TCP mode does not work at the moment. You can use this free application https://www.netburner.com/download/virtual-comm-port-driver-windows-xp-10/?fbclid=IwAR2W9V_YzjuP5_u9U-nJx1x38beFWNR0eRI59QOyYO_-NSePmTnW14kk7yA 45 | 46 | Configure it like this: 47 | 48 | ![alt text](img/vcommport.png) 49 | 50 | Hardware: 51 | ----- 52 | Construction is easy and only requires some basic point to point wiring of each module to the ESP32 board. 53 | 54 | See HardwareConfig.h for pin assignments, it is possible to change any pin assignments apart from ADC channels. Note that pin assignments are GPIO hardware pin numbers and not pin numbers specific to the particular ESP32 development board you may be using. 55 | 56 | PCB designs are currently being tested 57 | 58 | ![alt text](img/PCBv1.jpg) 59 | 60 | ![alt text](pcb/JyeSmith/PCBV2/Schematic_V2.png) 61 | 62 | Performance: 63 | ----- 64 | The Chorus32 Lap timer was compared to the $600USD ImmersionRC LapRF 8-Way at a local indoor event, arguably the worst conditions due to multipath and reflections. Results are presented below, you can see that the Chorus32 very closely matches the measured lap times of the LapRF. 65 | 66 | ![alt text](img/Comparison1.png) 67 | ![alt text](img/Comparison2.png) 68 | 69 | ## Compiling the project using platformio 70 | 71 | ## Installing 72 | TODO 73 | 74 | ## Compiling and uploading 75 | 76 | ### IDE 77 | TODO 78 | 79 | ### CLI 80 | To upload the code to your timer just run 81 | ``` 82 | pio run -e -t upload 83 | pio run -e -t uploadfs 84 | ``` 85 | Insert the board you are using, which is probably `BOARD_DEFAULT`. To list all valid targets just insert some random string as the board (sorry, I have no idea on how to list them properly). 86 | 87 | To update using the webpage, run the same commands (and ignore the errors about a failed connection). The path to the file you upload should now be `/.pio/build//firmware.bin`. 88 | 89 | ## Compiling the Project using the Arduino IDE (the old way): 90 | 91 | #### Add esp32 to the Arduino IDE 92 | 93 | Navigate to "File -> Preferences" and add "https://dl.espressif.com/dl/package_esp32_index.json" to "Additional Boards Manager URLs". If there is already an entry, just separate them with a ",". 94 | 95 | Now navigate to "Tools -> Board -> Boards Manager..." search for "esp32" and click install. 96 | 97 | #### Data Upload 98 | 99 | To upload the files for the webpage you'll need to download https://github.com/me-no-dev/arduino-esp32fs-plugin/releases/ and extract it in "/tools/". So that you end up with a folder called "ESP32FS" which has a folder "tool" inside of it. 100 | 101 | #### Libraries 102 | 103 | First head to "Sketch -> Include Library -> Manage Libraries" and search for "adafruit ina219" and "ssd1306 esp32" and install them both. Now head to https://github.com/me-no-dev/ESPAsyncWebServer and https://github.com/me-no-dev/AsyncTCP and click on "Clone or download -> Download ZIP". In the Arduino IDE nagivate to "Sketch -> Include Library -> Add .ZIP Library" and add them both. 104 | 105 | #### Flashing 106 | Now hit the upload button (with an arrow to the right) to upload the code to the board. After that upload the webpage data by clicking on "Tools -> ESP32 Sketch Data Upload". This should be done on every update! 107 | 108 | You can edit file "HardwareConfig.h" to specify your board type and for some advanced configuration. 109 | 110 | #### Updating 111 | 112 | For updates either follow the normal flashing procedure or use the web UI. 113 | To use the web UI updater open your Arduino IDE and click the verify button (the most left one). 114 | Depending on your operating system there is a folder named "arduino_build_\" in: 115 | - Linux: /tmp 116 | - Windows: %AppData% 117 | - OSX: No idea, sorry 118 | 119 | Inside that folder should be a file called "ESP32LapTimer.ino.bin", which can be uploaded in the web interface. 120 | 121 | 122 | Library requirements: 123 | ----- 124 | Adafruit_INA219 https://github.com/adafruit/Adafruit_INA219 125 | 126 | ESP8266 AND ESP32 OLED DRIVER FOR SSD1306 DISPLAY https://github.com/ThingPulse/esp8266-oled-ssd1306 127 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /bin/ESP32LapTimer.ino.esp32.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/bin/ESP32LapTimer.ino.esp32.bin -------------------------------------------------------------------------------- /data/laptimer comparison.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/data/laptimer comparison.pdf -------------------------------------------------------------------------------- /data/laptimer comparison.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/data/laptimer comparison.xlsx -------------------------------------------------------------------------------- /gather_releases.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$#" -ne 3 ]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | FILES_DIR=$1 9 | OUTPUT_DIR=$2 10 | FILE_NAME=$3 11 | 12 | FIRMWARE_PATHS=$(find $FILES_DIR -type f -name "$FILE_NAME") 13 | mkdir -p $OUTPUT_DIR 14 | 15 | for path in $FIRMWARE_PATHS 16 | do 17 | BOARD_NAME=$(echo $path | grep -Eo "BOARD_[^/]+") 18 | cp $path ${OUTPUT_DIR}/${BOARD_NAME}_$(basename $path) 19 | done 20 | -------------------------------------------------------------------------------- /img/Comparison1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/Comparison1.png -------------------------------------------------------------------------------- /img/Comparison2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/Comparison2.png -------------------------------------------------------------------------------- /img/HardwareImage2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/HardwareImage2.png -------------------------------------------------------------------------------- /img/PCBv1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/PCBv1.jpg -------------------------------------------------------------------------------- /img/hardwareImage1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/hardwareImage1.png -------------------------------------------------------------------------------- /img/schematic2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/schematic2.png -------------------------------------------------------------------------------- /img/vcommport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/vcommport.png -------------------------------------------------------------------------------- /img/wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/img/wiring.png -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.1/Gerber-2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.1/Gerber-2.1.zip -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.1/PCB-2.1 - Patch Wire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.1/PCB-2.1 - Patch Wire.png -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.1/PCB-2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.1/PCB-2.1.png -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.1/Schematic-V2.1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.1/Schematic-V2.1.png -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.2/Gerber-2.2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.2/Gerber-2.2.zip -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.2/PCB-2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.2/PCB-2.2.png -------------------------------------------------------------------------------- /pcb/JyeSmith/PCBV2.2/Schematic-V2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/JyeSmith/PCBV2.2/Schematic-V2.2.png -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/.gitignore: -------------------------------------------------------------------------------- 1 | # For PCBs designed using KiCad: http://www.kicad-pcb.org/ 2 | # Format documentation: http://kicad-pcb.org/help/file-formats/ 3 | 4 | # Temporary files 5 | *.000 6 | *.bak 7 | *.bck 8 | *.kicad_pcb-bak 9 | *.sch-bak 10 | *~ 11 | _autosave-* 12 | *.tmp 13 | *-rescue.lib 14 | *-save.pro 15 | *-save.kicad_pcb 16 | 17 | # Netlist files (exported from Eeschema) 18 | *.net 19 | 20 | # Autorouter files (exported from Pcbnew) 21 | *.dsn 22 | *.ses 23 | 24 | # Exported BOM files 25 | *.xml 26 | *.csv 27 | -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/README.md: -------------------------------------------------------------------------------- 1 | # Features 2 | - External edge mounted SMA connector for better range 3 | - Uses the esp32-wroom-32u 4 | - To connect the antenna, cut open a U.FL adapter cable and solder one end to the SMA connector 5 | - Integrated buck converter with correct components ;) (those modules from china are all over the place) 6 | - Max input 28V (26V if using ina219) 7 | - Footprint for an optional LoRa module 8 | - Space for 6 RX5808 modules 9 | - Optional ina219 10 | - I don't trust them anymore since one failed for me and put the input voltage on the 3.3V rail 11 | - Limits input voltage to 26V 12 | - Optional Fan with optional temperature sensor 13 | - Beeper 14 | 15 | # Bugs 16 | - Wrong SMA footprint (still fits though) 17 | - Buzzer footprint is a little bit too small for my buzzers 18 | - A vertically mounted XT60 might be better 19 | 20 | # Images 21 | 22 | ![PCB Side 1](img/pic_1.jpg) 23 | 24 | ![PCB Side 2](img/pic_2.jpg) 25 | -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/cern_ohl_v_1_2.txt: -------------------------------------------------------------------------------- 1 | CERN Open Hardware Licence v1.2 2 | 3 | Preamble 4 | 5 | Through this CERN Open Hardware Licence ("CERN OHL") version 1.2, CERN 6 | wishes to provide a tool to foster collaboration and sharing among 7 | hardware designers. The CERN OHL is copyright CERN. Anyone is welcome 8 | to use the CERN OHL, in unmodified form only, for the distribution of 9 | their own Open Hardware designs. Any other right is reserved. Release 10 | of hardware designs under the CERN OHL does not constitute an 11 | endorsement of the licensor or its designs nor does it imply any 12 | involvement by CERN in the development of such designs. 13 | 14 | 1. Definitions 15 | 16 | In this Licence, the following terms have the following meanings: 17 | 18 | “Licence” means this CERN OHL. 19 | 20 | “Documentation” means schematic diagrams, designs, circuit or circuit 21 | board layouts, mechanical drawings, flow charts and descriptive text, 22 | and other explanatory material that is explicitly stated as being made 23 | available under the conditions of this Licence. The Documentation may 24 | be in any medium, including but not limited to computer files and 25 | representations on paper, film, or any other media. 26 | 27 | “Documentation Location” means a location where the Licensor has 28 | placed Documentation, and which he believes will be publicly 29 | accessible for at least three years from the first communication to 30 | the public or distribution of Documentation. 31 | 32 | “Product” means either an entire, or any part of a, device built using 33 | the Documentation or the modified Documentation. 34 | 35 | “Licensee” means any natural or legal person exercising rights under 36 | this Licence. 37 | 38 | “Licensor” means any natural or legal person that creates or modifies 39 | Documentation and subsequently communicates to the public and/ or 40 | distributes the resulting Documentation under the terms and conditions 41 | of this Licence. 42 | 43 | A Licensee may at the same time be a Licensor, and vice versa. 44 | 45 | Use of the masculine gender includes the feminine and neuter genders 46 | and is employed solely to facilitate reading. 47 | 48 | 2. Applicability 49 | 50 | 2.1. This Licence governs the use, copying, modification, 51 | communication to the public and distribution of the Documentation, and 52 | the manufacture and distribution of Products. By exercising any right 53 | granted under this Licence, the Licensee irrevocably accepts these 54 | terms and conditions. 55 | 56 | 2.2. This Licence is granted by the Licensor directly to the Licensee, 57 | and shall apply worldwide and without limitation in time. The Licensee 58 | may assign his licence rights or grant sub-licences. 59 | 60 | 2.3. This Licence does not extend to software, firmware, or code 61 | loaded into programmable devices which may be used in conjunction with 62 | the Documentation, the modified Documentation or with Products, unless 63 | such software, firmware, or code is explicitly expressed to be subject 64 | to this Licence. The use of such software, firmware, or code is 65 | otherwise subject to the applicable licence terms and conditions. 66 | 67 | 3. Copying, modification, communication to the public and distribution 68 | of the Documentation 69 | 70 | 3.1. The Licensee shall keep intact all copyright and trademarks 71 | notices, all notices referring to Documentation Location, and all 72 | notices that refer to this Licence and to the disclaimer of warranties 73 | that are included in the Documentation. He shall include a copy 74 | thereof in every copy of the Documentation or, as the case may be, 75 | modified Documentation, that he communicates to the public or 76 | distributes. 77 | 78 | 3.2. The Licensee may copy, communicate to the public and distribute 79 | verbatim copies of the Documentation, in any medium, subject to the 80 | requirements specified in section 3.1. 81 | 82 | 3.3. The Licensee may modify the Documentation or any portion thereof 83 | provided that upon modification of the Documentation, the Licensee 84 | shall make the modified Documentation available from a Documentation 85 | Location such that it can be easily located by an original Licensor 86 | once the Licensee communicates to the public or distributes the 87 | modified Documentation under section 3.4, and, where required by 88 | section 4.1, by a recipient of a Product. However, the Licensor shall 89 | not assert his rights under the foregoing proviso unless or until a 90 | Product is distributed. 91 | 92 | 3.4. The Licensee may communicate to the public and distribute the 93 | modified Documentation (thereby in addition to being a Licensee also 94 | becoming a Licensor), always provided that he shall: 95 | 96 | a) comply with section 3.1; 97 | 98 | b) cause the modified Documentation to carry prominent notices stating 99 | that the Licensee has modified the Documentation, with the date and 100 | description of the modifications; 101 | 102 | c) cause the modified Documentation to carry a new Documentation 103 | Location notice if the original Documentation provided for one; 104 | 105 | d) make available the modified Documentation at the same level of 106 | abstraction as that of the Documentation, in the preferred format for 107 | making modifications to it (e.g. the native format of the CAD tool as 108 | applicable), and in the event that format is proprietary, in a format 109 | viewable with a tool licensed under an OSI-approved license if the 110 | proprietary tool can create it; and 111 | 112 | e) license the modified Documentation under the terms and conditions 113 | of this Licence or, where applicable, a later version of this Licence 114 | as may be issued by CERN. 115 | 116 | 3.5. The Licence includes a non-exclusive licence to those patents or 117 | registered designs that are held by, under the control of, or 118 | sub-licensable by the Licensor, to the extent necessary to make use of 119 | the rights granted under this Licence. The scope of this section 3.5 120 | shall be strictly limited to the parts of the Documentation or 121 | modified Documentation created by the Licensor. 122 | 123 | 4. Manufacture and distribution of Products 124 | 125 | 4.1. The Licensee may manufacture or distribute Products always 126 | provided that, where such manufacture or distribution requires a 127 | licence under this Licence the Licensee provides to each recipient of 128 | such Products an easy means of accessing a copy of the Documentation 129 | or modified Documentation, as applicable, as set out in section 3. 130 | 131 | 4.2. The Licensee is invited to inform any Licensor who has indicated 132 | his wish to receive this information about the type, quantity and 133 | dates of production of Products the Licensee has (had) manufactured 134 | 135 | 5. Warranty and liability 136 | 137 | 5.1. DISCLAIMER – The Documentation and any modified Documentation are 138 | provided "as is" and any express or implied warranties, including, but 139 | not limited to, implied warranties of merchantability, of satisfactory 140 | quality, non-infringement of third party rights, and fitness for a 141 | particular purpose or use are disclaimed in respect of the 142 | Documentation, the modified Documentation or any Product. The Licensor 143 | makes no representation that the Documentation, modified 144 | Documentation, or any Product, does or will not infringe any patent, 145 | copyright, trade secret or other proprietary right. The entire risk as 146 | to the use, quality, and performance of a Product shall be with the 147 | Licensee and not the Licensor. This disclaimer of warranty is an 148 | essential part of this Licence and a condition for the grant of any 149 | rights granted under this Licence. The Licensee warrants that it does 150 | not act in a consumer capacity. 151 | 152 | 5.2. LIMITATION OF LIABILITY – The Licensor shall have no liability 153 | for direct, indirect, special, incidental, consequential, exemplary, 154 | punitive or other damages of any character including, without 155 | limitation, procurement of substitute goods or services, loss of use, 156 | data or profits, or business interruption, however caused and on any 157 | theory of contract, warranty, tort (including negligence), product 158 | liability or otherwise, arising in any way in relation to the 159 | Documentation, modified Documentation and/or the use, manufacture or 160 | distribution of a Product, even if advised of the possibility of such 161 | damages, and the Licensee shall hold the Licensor(s) free and harmless 162 | from any liability, costs, damages, fees and expenses, including 163 | claims by third parties, in relation to such use. 164 | 165 | 6. General 166 | 167 | 6.1. Except for the rights explicitly granted hereunder, this Licence 168 | does not imply or represent any transfer or assignment of intellectual 169 | property rights to the Licensee. 170 | 171 | 6.2. The Licensee shall not use or make reference to any of the names 172 | (including acronyms and abbreviations), images, or logos under which 173 | the Licensor is known, save in so far as required to comply with 174 | section 3. Any such permitted use or reference shall be factual and 175 | shall in no event suggest any kind of endorsement by the Licensor or 176 | its personnel of the modified Documentation or any Product, or any 177 | kind of implication by the Licensor or its personnel in the 178 | preparation of the modified Documentation or Product. 179 | 180 | 6.3. CERN may publish updated versions of this Licence which retain 181 | the same general provisions as this version, but differ in detail so 182 | far this is required and reasonable. New versions will be published 183 | with a unique version number. 184 | 185 | 6.4. This Licence shall terminate with immediate effect, upon written 186 | notice and without involvement of a court if the Licensee fails to 187 | comply with any of its terms and conditions, or if the Licensee 188 | initiates legal action against Licensor in relation to this 189 | Licence. Section 5 shall continue to apply. 190 | -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/esp32-wroom-timer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/smeat/esp32-wroom-timer-v1/esp32-wroom-timer.pdf -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/esp32-wroom-timer.pro: -------------------------------------------------------------------------------- 1 | update=2019-08-17T20:01:30 CEST 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [cvpcb] 9 | version=1 10 | NetIExt=net 11 | [eeschema] 12 | version=1 13 | LibDir= 14 | [eeschema/libraries] 15 | [pcbnew] 16 | version=1 17 | PageLayoutDescrFile= 18 | LastNetListRead=esp32-wroom-timer.net 19 | CopperLayerCount=2 20 | BoardThickness=1.6 21 | AllowMicroVias=0 22 | AllowBlindVias=0 23 | RequireCourtyardDefinitions=0 24 | ProhibitOverlappingCourtyards=0 25 | MinTrackWidth=0.2 26 | MinViaDiameter=0.45 27 | MinViaDrill=0.3 28 | MinMicroViaDiameter=0.2 29 | MinMicroViaDrill=0.09999999999999999 30 | MinHoleToHole=0.25 31 | TrackWidth1=0.25 32 | TrackWidth2=0.5 33 | TrackWidth3=1 34 | TrackWidth4=2 35 | ViaDiameter1=0.8 36 | ViaDrill1=0.4 37 | dPairWidth1=0.2 38 | dPairGap1=0.25 39 | dPairViaGap1=0.25 40 | SilkLineWidth=0.12 41 | SilkTextSizeV=1 42 | SilkTextSizeH=1 43 | SilkTextSizeThickness=0.15 44 | SilkTextItalic=0 45 | SilkTextUpright=1 46 | CopperLineWidth=0.2 47 | CopperTextSizeV=1.5 48 | CopperTextSizeH=1.5 49 | CopperTextThickness=0.3 50 | CopperTextItalic=0 51 | CopperTextUpright=1 52 | EdgeCutLineWidth=0.05 53 | CourtyardLineWidth=0.05 54 | OthersLineWidth=0.15 55 | OthersTextSizeV=1 56 | OthersTextSizeH=1 57 | OthersTextSizeThickness=0.15 58 | OthersTextItalic=0 59 | OthersTextUpright=1 60 | SolderMaskClearance=0.0508 61 | SolderMaskMinWidth=0.2 62 | SolderPasteClearance=0 63 | SolderPasteRatio=-0 64 | [pcbnew/Layer.F.Cu] 65 | Name=F.Cu 66 | Type=0 67 | Enabled=1 68 | [pcbnew/Layer.In1.Cu] 69 | Name=In1.Cu 70 | Type=0 71 | Enabled=0 72 | [pcbnew/Layer.In2.Cu] 73 | Name=In2.Cu 74 | Type=0 75 | Enabled=0 76 | [pcbnew/Layer.In3.Cu] 77 | Name=In3.Cu 78 | Type=0 79 | Enabled=0 80 | [pcbnew/Layer.In4.Cu] 81 | Name=In4.Cu 82 | Type=0 83 | Enabled=0 84 | [pcbnew/Layer.In5.Cu] 85 | Name=In5.Cu 86 | Type=0 87 | Enabled=0 88 | [pcbnew/Layer.In6.Cu] 89 | Name=In6.Cu 90 | Type=0 91 | Enabled=0 92 | [pcbnew/Layer.In7.Cu] 93 | Name=In7.Cu 94 | Type=0 95 | Enabled=0 96 | [pcbnew/Layer.In8.Cu] 97 | Name=In8.Cu 98 | Type=0 99 | Enabled=0 100 | [pcbnew/Layer.In9.Cu] 101 | Name=In9.Cu 102 | Type=0 103 | Enabled=0 104 | [pcbnew/Layer.In10.Cu] 105 | Name=In10.Cu 106 | Type=0 107 | Enabled=0 108 | [pcbnew/Layer.In11.Cu] 109 | Name=In11.Cu 110 | Type=0 111 | Enabled=0 112 | [pcbnew/Layer.In12.Cu] 113 | Name=In12.Cu 114 | Type=0 115 | Enabled=0 116 | [pcbnew/Layer.In13.Cu] 117 | Name=In13.Cu 118 | Type=0 119 | Enabled=0 120 | [pcbnew/Layer.In14.Cu] 121 | Name=In14.Cu 122 | Type=0 123 | Enabled=0 124 | [pcbnew/Layer.In15.Cu] 125 | Name=In15.Cu 126 | Type=0 127 | Enabled=0 128 | [pcbnew/Layer.In16.Cu] 129 | Name=In16.Cu 130 | Type=0 131 | Enabled=0 132 | [pcbnew/Layer.In17.Cu] 133 | Name=In17.Cu 134 | Type=0 135 | Enabled=0 136 | [pcbnew/Layer.In18.Cu] 137 | Name=In18.Cu 138 | Type=0 139 | Enabled=0 140 | [pcbnew/Layer.In19.Cu] 141 | Name=In19.Cu 142 | Type=0 143 | Enabled=0 144 | [pcbnew/Layer.In20.Cu] 145 | Name=In20.Cu 146 | Type=0 147 | Enabled=0 148 | [pcbnew/Layer.In21.Cu] 149 | Name=In21.Cu 150 | Type=0 151 | Enabled=0 152 | [pcbnew/Layer.In22.Cu] 153 | Name=In22.Cu 154 | Type=0 155 | Enabled=0 156 | [pcbnew/Layer.In23.Cu] 157 | Name=In23.Cu 158 | Type=0 159 | Enabled=0 160 | [pcbnew/Layer.In24.Cu] 161 | Name=In24.Cu 162 | Type=0 163 | Enabled=0 164 | [pcbnew/Layer.In25.Cu] 165 | Name=In25.Cu 166 | Type=0 167 | Enabled=0 168 | [pcbnew/Layer.In26.Cu] 169 | Name=In26.Cu 170 | Type=0 171 | Enabled=0 172 | [pcbnew/Layer.In27.Cu] 173 | Name=In27.Cu 174 | Type=0 175 | Enabled=0 176 | [pcbnew/Layer.In28.Cu] 177 | Name=In28.Cu 178 | Type=0 179 | Enabled=0 180 | [pcbnew/Layer.In29.Cu] 181 | Name=In29.Cu 182 | Type=0 183 | Enabled=0 184 | [pcbnew/Layer.In30.Cu] 185 | Name=In30.Cu 186 | Type=0 187 | Enabled=0 188 | [pcbnew/Layer.B.Cu] 189 | Name=B.Cu 190 | Type=0 191 | Enabled=1 192 | [pcbnew/Layer.B.Adhes] 193 | Enabled=1 194 | [pcbnew/Layer.F.Adhes] 195 | Enabled=1 196 | [pcbnew/Layer.B.Paste] 197 | Enabled=1 198 | [pcbnew/Layer.F.Paste] 199 | Enabled=1 200 | [pcbnew/Layer.B.SilkS] 201 | Enabled=1 202 | [pcbnew/Layer.F.SilkS] 203 | Enabled=1 204 | [pcbnew/Layer.B.Mask] 205 | Enabled=1 206 | [pcbnew/Layer.F.Mask] 207 | Enabled=1 208 | [pcbnew/Layer.Dwgs.User] 209 | Enabled=1 210 | [pcbnew/Layer.Cmts.User] 211 | Enabled=1 212 | [pcbnew/Layer.Eco1.User] 213 | Enabled=1 214 | [pcbnew/Layer.Eco2.User] 215 | Enabled=1 216 | [pcbnew/Layer.Edge.Cuts] 217 | Enabled=1 218 | [pcbnew/Layer.Margin] 219 | Enabled=1 220 | [pcbnew/Layer.B.CrtYd] 221 | Enabled=1 222 | [pcbnew/Layer.F.CrtYd] 223 | Enabled=1 224 | [pcbnew/Layer.B.Fab] 225 | Enabled=1 226 | [pcbnew/Layer.F.Fab] 227 | Enabled=1 228 | [pcbnew/Layer.Rescue] 229 | Enabled=0 230 | [pcbnew/Netclasses] 231 | [pcbnew/Netclasses/Default] 232 | Name=Default 233 | Clearance=0.15 234 | TrackWidth=0.25 235 | ViaDiameter=0.8 236 | ViaDrill=0.4 237 | uViaDiameter=0.3 238 | uViaDrill=0.1 239 | dPairWidth=0.2 240 | dPairGap=0.25 241 | dPairViaGap=0.25 242 | [pcbnew/Netclasses/1] 243 | Name=5v 244 | Clearance=0.15 245 | TrackWidth=0.5 246 | ViaDiameter=0.8 247 | ViaDrill=0.4 248 | uViaDiameter=0.3 249 | uViaDrill=0.1 250 | dPairWidth=0.2 251 | dPairGap=0.25 252 | dPairViaGap=0.25 253 | -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/img/esp32-wroom-timer_bottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/smeat/esp32-wroom-timer-v1/img/esp32-wroom-timer_bottom.png -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/img/esp32-wroom-timer_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/smeat/esp32-wroom-timer-v1/img/esp32-wroom-timer_top.png -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/img/pic_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/smeat/esp32-wroom-timer-v1/img/pic_1.jpg -------------------------------------------------------------------------------- /pcb/smeat/esp32-wroom-timer-v1/img/pic_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlessandroAU/Chorus32-ESP32LapTimer/f72380cb444195d7d6ce85958c1b98609a4471b0/pcb/smeat/esp32-wroom-timer-v1/img/pic_2.jpg --------------------------------------------------------------------------------