summaryrefslogtreecommitdiffstats
path: root/duplo_train/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'duplo_train/src/main.cpp')
-rw-r--r--duplo_train/src/main.cpp349
1 files changed, 349 insertions, 0 deletions
diff --git a/duplo_train/src/main.cpp b/duplo_train/src/main.cpp
new file mode 100644
index 0000000..0922c6e
--- /dev/null
+++ b/duplo_train/src/main.cpp
@@ -0,0 +1,349 @@
1
2#include <Arduino.h>
3#include <Bounce2.h>
4#include <WiFi.h>
5
6#include <esp_wifi.h>
7#include <esp_bt.h>
8#include <soc/soc.h>
9#include <soc/rtc_cntl_reg.h>
10
11#include "myhub.h"
12
13const uint8_t BUTTON_BASE_1 = 25;
14const uint8_t BUTTON_BASE_2 = 22;
15const uint8_t BUTTON_BASE_3 = 26;
16const uint8_t BUTTON_BASE_4 = 18;
17const uint8_t BUTTON_BASE_5 = 33;
18const uint8_t BUTTON_BASE_6 = 5;
19const uint8_t BUTTON_BASE_7 = 19;
20const uint8_t BUTTON_BASE_8 = 23;
21const uint8_t BUTTON_HANDLE_1 = 17;
22const uint8_t BUTTON_HANDLE_2 = 16;
23const uint8_t POTI_THROTTLE = 32;
24
25const int idle_shutdown = 10 * 60 * 1000;
26unsigned long last_scan_start = 0;
27
28Bounce2::Button button_base1 = Bounce2::Button();
29Bounce2::Button button_base2 = Bounce2::Button();
30Bounce2::Button button_base3 = Bounce2::Button();
31Bounce2::Button button_base4 = Bounce2::Button();
32Bounce2::Button button_base5 = Bounce2::Button();
33Bounce2::Button button_base6 = Bounce2::Button();
34Bounce2::Button button_base7 = Bounce2::Button();
35Bounce2::Button button_base8 = Bounce2::Button();
36Bounce2::Button button_handle1 = Bounce2::Button();
37Bounce2::Button button_handle2 = Bounce2::Button();
38
39MyHub myHub;
40
41void color_sensor_callback(void *hub, byte port_number,
42 DeviceType device_type, uint8_t *data)
43{
44 MyHub *myHub = (MyHub *)hub;
45
46 if (device_type == DeviceType::DUPLO_TRAIN_BASE_COLOR_SENSOR)
47 {
48 int color = myHub->parseColor(data);
49 Serial.print("Color: ");
50 Serial.println(color);
51 }
52}
53
54void speedometer_sensor_callback(void *hub, byte port_number,
55 DeviceType device_type, uint8_t *data)
56{
57 MyHub *myHub = (MyHub *)hub;
58
59 if (device_type == DeviceType::DUPLO_TRAIN_BASE_SPEEDOMETER)
60 {
61 int current_speed = myHub->parseSpeedometer(data);
62 Serial.print("speedometer="); Serial.println(current_speed);
63 if (current_speed == 0)
64 {
65 //TODO child has fun with "crashing" the train into things
66 // and the train reacts with the break sound
67 //myHub->stopMotor();
68 myHub->stopMotorWithBreak();
69 }
70 else if (myHub->isMotorStopped())
71 {
72 if (current_speed > 10)
73 myHub->setMotorSpeedLevel(1);
74 else if (current_speed < -10)
75 myHub->setMotorSpeedLevel(-1);
76 }
77 }
78}
79
80#ifdef WIFI_TOGGLE
81enum wifi_enable_state
82 : uint8_t
83{
84 Enable = 0,
85 Disable = 1,
86 None = 2,
87};
88
89hw_timer_t *timer = NULL;
90
91volatile wifi_enable_state wifi_enable = wifi_enable_state::None;
92void IRAM_ATTR on_timer()
93{
94 static volatile int cnt = 0;
95 cnt = (cnt < 15) ? cnt + 1 : 0;
96 if (cnt == 0)
97 wifi_enable = wifi_enable_state::Enable;
98 else if (cnt == 1)
99 wifi_enable = wifi_enable_state::Disable;
100}
101#endif
102
103void controller_deep_sleep()
104{
105 Serial.print("Controller deep sleep enabled");
106
107#ifdef WIFI_TOGGLE
108 WiFi.disconnect(true);
109 WiFi.mode(WIFI_OFF);
110 esp_wifi_stop();
111#endif
112
113 NimBLEDevice::getScan()->stop();
114 NimBLEDevice::deinit();
115 esp_bt_controller_disable();
116
117 // disable brownout detector
118 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
119 //adc_power_release();
120 esp_deep_sleep_start();
121}
122
123void setup()
124{
125 // disable brownout detector
126 // problems with the usb battery?
127 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
128
129 Serial.begin(115200);
130 pinMode(BUILTIN_LED, OUTPUT);
131
132 analogReadResolution(12); //12 bits
133 analogSetAttenuation(ADC_0db); //For all pins
134 analogSetPinAttenuation(POTI_THROTTLE, ADC_11db); //11db attenuation
135
136 button_base1.attach(BUTTON_BASE_1, INPUT_PULLUP);
137 button_base2.attach(BUTTON_BASE_2, INPUT_PULLUP);
138 button_base3.attach(BUTTON_BASE_3, INPUT_PULLUP);
139 button_base4.attach(BUTTON_BASE_4, INPUT_PULLUP);
140 button_base5.attach(BUTTON_BASE_5, INPUT_PULLUP);
141 button_base6.attach(BUTTON_BASE_6, INPUT_PULLUP);
142 button_base7.attach(BUTTON_BASE_7, INPUT_PULLUP);
143 button_base8.attach(BUTTON_BASE_8, INPUT_PULLUP);
144 button_handle1.attach(BUTTON_HANDLE_1, INPUT_PULLUP);
145 button_handle2.attach(BUTTON_HANDLE_2, INPUT_PULLUP);
146
147 button_base1.setPressedState(LOW);
148 button_base2.setPressedState(LOW);
149 button_base3.setPressedState(LOW);
150 button_base4.setPressedState(LOW);
151 button_base5.setPressedState(LOW);
152 button_base6.setPressedState(LOW);
153 button_base7.setPressedState(LOW);
154 button_base8.setPressedState(LOW);
155 button_handle1.setPressedState(LOW);
156 button_handle2.setPressedState(LOW);
157
158 last_scan_start = 0;
159 myHub.init();
160
161 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_DEFAULT);
162 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL0);
163 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL1);
164 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL2);
165 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL3);
166 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL4);
167 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL5);
168 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL6);
169 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL7);
170 NimBLEDevice::setPower(ESP_PWR_LVL_P9, ESP_BLE_PWR_TYPE_CONN_HDL8);
171
172#ifdef WIFI_TOGGLE
173 timer = timerBegin(0, 80, true); // 1 tick = 1/(80MHZ) => x/80 = 1us
174 timerAttachInterrupt(timer, &on_timer, true);
175 timerAlarmWrite(timer, 1000000, true); // 1000000 * 1us = 1sec
176 timerAlarmEnable(timer);
177#endif
178}
179
180void loop()
181{
182 /*
183 * TODO
184 * - color sensor
185 * - throttle
186 */
187 if (!myHub.isConnecting() && !myHub.isConnected())
188 {
189 if (last_scan_start == 0)
190 {
191 delay(1000); // avoid fast-reconnect loops
192 last_scan_start = millis();
193 }
194 if (millis() - last_scan_start > idle_shutdown)
195 (void)controller_deep_sleep(); // never returns
196
197 if (!NimBLEDevice::getScan()->isScanning())
198 {
199 myHub.init();
200 Serial.println("BLE is scanning...");
201 }
202 }
203 else if (myHub.isConnecting())
204 {
205 Serial.println("Duplo Hub found");
206 myHub.connectHub();
207 if (myHub.isConnected())
208 {
209 last_scan_start = 0;
210
211 Serial.println("Connected to Duplo Hub");
212 myHub.onConnect();
213 delay(200);
214
215 // connect speed sensor and activate it for updates
216 myHub.activatePortDevice((byte)DuploTrainHubPort::SPEEDOMETER,
217 speedometer_sensor_callback);
218 delay(200);
219
220 // activate light
221 myHub.activateRgbLight();
222 delay(200);
223
224 // activate speaker
225 myHub.activateBaseSpeaker();
226 delay(200);
227 }
228 else
229 {
230 Serial.println("Failed to connect to Duplo Hub");
231 return;
232 }
233 }
234 else if (myHub.isConnected())
235 {
236 button_base1.update();
237 if (button_base1.pressed())
238 {
239 Serial.println("Button1 pressed");
240 myHub.playSound((byte)DuploTrainBaseSound::STEAM);
241 }
242
243 button_base2.update();
244 if (button_base2.pressed())
245 {
246 Serial.println("Button2 - brake pressed");
247 myHub.stopMotorWithBreak();
248 }
249
250 button_base3.update();
251 if (button_base3.pressed())
252 {
253 Serial.println("Button3 - light color pressed");
254 myHub.cycleLightColor();
255 }
256
257 button_base4.update();
258 if (button_base4.pressed())
259 {
260 Serial.println("Button4 - light toggle pressed");
261 myHub.toggleLight();
262 }
263
264 button_base5.update();
265 if (button_base5.pressed())
266 {
267 Serial.println("Button5 - refill pressed");
268 myHub.playSound((byte)DuploTrainBaseSound::WATER_REFILL);
269 }
270
271 button_base6.update();
272 if (button_base6.pressed())
273 {
274 Serial.println("Button6 - horn pressed");
275 myHub.playSound((byte)DuploTrainBaseSound::HORN);
276 }
277
278 button_base7.update();
279 if (button_base7.pressed())
280 {
281 Serial.println("Button7 - brake pressed");
282 myHub.stopMotorWithBreak();
283 }
284
285 button_base8.update();
286 if (button_base8.pressed())
287 {
288 Serial.println("Button8 pressed");
289 myHub.playSound((byte)DuploTrainBaseSound::STATION_DEPARTURE);
290 }
291
292 button_handle1.update();
293 if (button_handle1.pressed())
294 {
295 Serial.println("Button Handle1 - speed++");
296 myHub.incrMotorSpeed();
297 }
298
299 button_handle2.update();
300 if (button_handle2.pressed())
301 {
302 Serial.println("Button Handle2 - speed--");
303 myHub.decrMotorSpeed();
304 }
305
306 if (myHub.isMotorStopped() && millis() - myHub.millisLastCommand() > idle_shutdown)
307 {
308 myHub.shutDownHub();
309 delay(500);
310 myHub.shutDownHub();
311 delay(500);
312
313 (void)controller_deep_sleep(); // never returns
314 }
315
316#if 0
317 int potValue = analogRead(POTI_THROTTLE);
318 delay(50);
319 int potValue2 = analogRead(POTI_THROTTLE);
320 if (potValue == potValue2) {
321 //if (potValue <= )
322 Serial.print(" pot value "); Serial.println(potValue);
323 }
324 int speedValue = map(potValue, 0, 4095, -2, 2);
325 if (potValue == potValue2 && speed != speedValue)
326 {
327 Serial.print("old speed "); Serial.print(speed);
328 Serial.print(" new speed "); Serial.print(speedValue);
329 Serial.print("New speed "); Serial.println(speedValue * 35);
330 //myHub.setBasicMotorSpeed(motorPort, speedValue * 35);
331 speed = speedValue;
332 }
333 delay(50);
334#endif
335 }
336
337#ifdef WIFI_TOGGLE
338 if (wifi_enable != wifi_enable_state::None)
339 {
340 timerAlarmDisable(timer);
341 Serial.print("new mode ");
342 Serial.println((wifi_enable == wifi_enable_state::Enable) ? "WIFI_STA" : "WIFI_OFF");
343 WiFi.mode((wifi_enable == wifi_enable_state::Enable) ? WIFI_STA : WIFI_OFF);
344 digitalWrite(BUILTIN_LED, (wifi_enable == wifi_enable_state::Enable) ? HIGH : LOW);
345 wifi_enable = wifi_enable_state::None;
346 timerAlarmEnable(timer);
347 }
348#endif
349}