Compare commits
458 commits
dmx_cleanu
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62453248a6 | ||
|
|
52c757ac36 | ||
|
|
f5fec0e46b | ||
|
|
009abaff09 | ||
|
|
f34bab8fd8 | ||
|
|
02dc51166e | ||
|
|
1edc2c70fd | ||
|
|
9f9d11ebc9 | ||
|
|
4aef934371 | ||
|
|
c810b4e2a1 | ||
|
|
8feb030e57 | ||
|
|
a48db8f2c2 | ||
|
|
992f57f2f6 | ||
|
|
18d5dbaf48 | ||
|
|
2fcfe4a686 | ||
|
|
900e93f146 | ||
|
|
f80086a15e | ||
|
|
5ad0efac9f | ||
|
|
46c942051d | ||
|
|
4fcd255f87 | ||
|
|
5fbb8d9277 | ||
|
|
8f89fe23c1 | ||
|
|
59fe2fb599 | ||
|
|
318448cc64 | ||
|
|
a011ecf509 | ||
|
|
d0cb33b6fc | ||
|
|
8a376de77e | ||
|
|
ec8fdd1cf6 | ||
|
|
fac7d8155e | ||
|
|
77bd7db8fe | ||
|
|
92ac6f3aa4 | ||
|
|
708341d067 | ||
|
|
015b1f321d | ||
|
|
7057bc7a1f | ||
|
|
5ac9e6cd2e | ||
|
|
4e9c1239de | ||
|
|
d4483b0d1d | ||
|
|
af83bf3cde | ||
|
|
0ef12d6fb2 | ||
|
|
5a18411aee | ||
|
|
3f902f837a | ||
|
|
3a7683e728 | ||
|
|
21ce0d8ae1 | ||
|
|
1daa2d72aa | ||
|
|
2a399b4f0f | ||
|
|
afabe616a2 | ||
|
|
a5a62a1584 | ||
|
|
4f153b0321 | ||
|
|
5b29480e9f | ||
|
|
06ccf1cc75 | ||
|
|
e804e240a6 | ||
|
|
4cf64fda77 | ||
|
|
a616a09177 | ||
|
|
fc5f3391cb | ||
|
|
e4690a4bdc | ||
|
|
53dce06f35 | ||
|
|
8fff1f5508 | ||
|
|
006fa45afc | ||
|
|
0892b2226f | ||
|
|
5e539a6626 | ||
|
|
a2a056457a | ||
|
|
d655c5892c | ||
|
|
c8273475d2 | ||
|
|
11fb234c19 | ||
|
|
667bb38009 | ||
|
|
934ad21830 | ||
|
|
4919e360c9 | ||
|
|
0fa89fd711 | ||
|
|
6a8f7a3841 | ||
|
|
6b2c4ee4f2 | ||
|
|
990b4eee37 | ||
|
|
9af149971f | ||
|
|
1cd99ab0fd | ||
|
|
78373685c1 | ||
|
|
1930a2ff6e | ||
|
|
371bd7ba16 | ||
|
|
20bcb16713 | ||
|
|
83402f3a1f | ||
|
|
4a80a4ac71 | ||
|
|
43d9f48009 | ||
|
|
1da3c7916a | ||
|
|
e44ae3524b | ||
|
|
f8c2b61fea | ||
|
|
f5f0805802 | ||
|
|
b036cc6252 | ||
|
|
d22c263f6f | ||
|
|
895120fd8c | ||
|
|
989db55caf | ||
|
|
c5510041a3 | ||
|
|
5dd86b8c17 | ||
|
|
bef5610af2 | ||
|
|
97cef46969 | ||
|
|
44e4cdd4d5 | ||
|
|
f4eee1ff6a | ||
|
|
0ecae41d6f | ||
|
|
8be7f75668 | ||
|
|
d628b2fa2d | ||
|
|
fc6bad3636 | ||
|
|
99f722ba6b | ||
|
|
be3293915c | ||
|
|
2dfcdd5fa2 | ||
|
|
475f919788 | ||
|
|
06a13af737 | ||
|
|
aada1d7b11 | ||
|
|
9b3ef79216 | ||
|
|
77ca9ce529 | ||
|
|
40573e41a8 | ||
|
|
8c4a1b3307 | ||
|
|
ec4ca90328 | ||
|
|
10b9ab827a | ||
|
|
02d7caf6a2 | ||
|
|
dff0bbb611 | ||
|
|
3c7e161f93 | ||
|
|
78cc309fdd | ||
|
|
6216a8a69e | ||
|
|
572e952434 | ||
|
|
a93818885f | ||
|
|
ea96a5dba3 | ||
|
|
aa83302a9b | ||
|
|
f245bf8838 | ||
|
|
d65ebe2b99 | ||
|
|
632b3f5d2c | ||
|
|
d1484a30b1 | ||
|
|
e579992b2f | ||
|
|
574bf886a5 | ||
|
|
00f6b46aa6 | ||
|
|
7c9ed24d5a | ||
|
|
8776b77ed6 | ||
|
|
064a654ef3 | ||
|
|
069a27ac4e | ||
|
|
6546f20d1e | ||
|
|
be14e2cff6 | ||
|
|
fd3535b6b1 | ||
|
|
cb3a07bb25 | ||
|
|
48a837c8ff | ||
|
|
b74bbaf033 | ||
|
|
e9b900c317 | ||
|
|
3efeca69df | ||
|
|
caffaec092 | ||
|
|
083883fbac | ||
|
|
85eb5522a2 | ||
|
|
31426aeddc | ||
|
|
235f0c4938 | ||
|
|
c6f4f3ad91 | ||
|
|
31240bf5aa | ||
|
|
0b0c4ebbbd | ||
|
|
62512cab4a | ||
|
|
a254b46192 | ||
|
|
60d17f12c8 | ||
|
|
b263b9684b | ||
|
|
2b4475bbc7 | ||
|
|
16145663c1 | ||
|
|
463ac6586b | ||
|
|
82e3a2adca | ||
|
|
f57629a8ae | ||
|
|
edfec3d15f | ||
|
|
8dae72946e | ||
|
|
6994ee09d3 | ||
|
|
d7cdb81494 | ||
|
|
043497405a | ||
|
|
f393f2762d | ||
|
|
dbf2a4301e | ||
|
|
5b4ba29cc2 | ||
|
|
748f988a52 | ||
|
|
d40ddef917 | ||
|
|
736bedf957 | ||
|
|
3d3d29ccc1 | ||
|
|
112721fecd | ||
|
|
57a70ad9e7 | ||
|
|
ebdcc74cf3 | ||
|
|
66e82e79d2 | ||
|
|
054e7c443c | ||
|
|
4d2c3e147c | ||
|
|
1fb7ac8df2 | ||
|
|
cee73a11c7 | ||
|
|
047f53e1ad | ||
|
|
50fff0047f | ||
|
|
15ae874841 | ||
|
|
41de6c47e0 | ||
|
|
64f2cb5c31 | ||
|
|
2c61160dbd | ||
|
|
1be135c607 | ||
|
|
2b0f7263de | ||
|
|
f3c46a4507 | ||
|
|
5a8650418c | ||
|
|
f2ede9c176 | ||
|
|
b793776adb | ||
|
|
177ee7a9b8 | ||
|
|
f476d0a6c6 | ||
|
|
07967a29c7 | ||
|
|
5eff1adaa8 | ||
|
|
5cd01c6116 | ||
|
|
e5c40eb8ce | ||
|
|
9bea106029 | ||
|
|
339e0d7780 | ||
|
|
da3b838314 | ||
|
|
8d0262f1d7 | ||
|
|
ed395b8276 | ||
|
|
8937ea355e | ||
|
|
7a910ab962 | ||
|
|
5df1fe038b | ||
|
|
ec541811cc | ||
|
|
95dbe2c665 | ||
|
|
834f226528 | ||
|
|
f3d3405272 | ||
|
|
bbd38c439e | ||
|
|
d2f16f8b7b | ||
|
|
02768500ad | ||
|
|
a87f6abb0b | ||
|
|
08dc8367c5 | ||
|
|
d1c09dcd61 | ||
|
|
d70fa56444 | ||
|
|
fedcf13bd5 | ||
|
|
63f3cc563a | ||
|
|
7dba79be85 | ||
|
|
b94d8a91fb | ||
|
|
4445aa72a2 | ||
|
|
05c57a9690 | ||
|
|
c9f04bd6c5 | ||
|
|
50d5fe5980 | ||
|
|
114ab9a304 | ||
|
|
e503ce1e93 | ||
|
|
f3b75557cf | ||
|
|
185cad9fad | ||
|
|
eb969fab97 | ||
|
|
0b7aa5dfcb | ||
|
|
84b025b1e7 | ||
|
|
7f89d19b5f | ||
|
|
54ab01fead | ||
|
|
b71c26e514 | ||
|
|
338447c6e7 | ||
|
|
11554113a0 | ||
|
|
531c15cd5f | ||
|
|
d1f5eac58e | ||
|
|
7765812f24 | ||
|
|
2ab43f179b | ||
|
|
f82ee27e21 | ||
|
|
508815e216 | ||
|
|
8d7141d02e | ||
|
|
f56a6fb93f | ||
|
|
f5041994ab | ||
|
|
565f1299d6 | ||
|
|
5efae78d0c | ||
|
|
208b435e98 | ||
|
|
9895057dd5 | ||
|
|
a30d244cf1 | ||
|
|
e467423fac | ||
|
|
f295b8b34d | ||
|
|
af5efebe65 | ||
|
|
afa65ff360 | ||
|
|
c5bec455de | ||
|
|
a9485dfec3 | ||
|
|
5ac268249b | ||
|
|
26d640d90e | ||
|
|
65e75e579f | ||
|
|
c65bf173de | ||
|
|
a92dde9884 | ||
|
|
3cba541938 | ||
|
|
e734c9c961 | ||
|
|
65842cdb9b | ||
|
|
a177c59bcc | ||
|
|
520f77ef0d | ||
|
|
74314751a8 | ||
|
|
198469c7f6 | ||
|
|
d44d654d39 | ||
|
|
37afebbd3f | ||
|
|
4b8feb23bc | ||
|
|
822de1266e | ||
|
|
f5d4123a0b | ||
|
|
7d22755433 | ||
|
|
7622520b69 | ||
|
|
7ca93c2a8e | ||
|
|
b8d94ec2db | ||
|
|
9010f17295 | ||
|
|
c300a38e95 | ||
|
|
fb4eee8158 | ||
|
|
b666b57c4a | ||
|
|
024885ed60 | ||
|
|
b8f605855c | ||
|
|
5fe76b9b3a | ||
|
|
c056b4e249 | ||
|
|
74a8f9c1c5 | ||
|
|
3378ed902d | ||
|
|
4ffdcba741 | ||
|
|
74b401d622 | ||
|
|
9cc428580a | ||
|
|
9288b996c4 | ||
|
|
3f0ed86c37 | ||
|
|
f91a3e6b52 | ||
|
|
6a9015c68e | ||
|
|
da43407a16 | ||
|
|
7edbbf2401 | ||
|
|
42ecec6928 | ||
|
|
3eaa064690 | ||
|
|
b415616277 | ||
|
|
00d5e27de7 | ||
|
|
5cc6a257d3 | ||
|
|
87c04e1c46 | ||
|
|
0cb30f6996 | ||
|
|
e94ba7e31f | ||
|
|
58e89f5b6e | ||
|
|
eca663c40c | ||
|
|
f8cb964c21 | ||
|
|
8140f4286e | ||
|
|
ef00664e14 | ||
|
|
86686fa817 | ||
|
|
c64dfdc9c3 | ||
|
|
6bce301f25 | ||
|
|
8d0ef9d35a | ||
|
|
c9b7193a22 | ||
|
|
8b940c95db | ||
|
|
b49083177b | ||
|
|
3357fefbb0 | ||
|
|
dceed82785 | ||
|
|
0332716490 | ||
|
|
f4d0dc75c2 | ||
|
|
f7e6c1fb3e | ||
|
|
6a9407744a | ||
|
|
70d15e1284 | ||
|
|
166852bff0 | ||
|
|
b7abaf52ee | ||
|
|
2642e48856 | ||
|
|
f94718eb4d | ||
|
|
0ad935f655 | ||
|
|
0f450b0718 | ||
|
|
5239baffaf | ||
|
|
ded8d0098e | ||
|
|
b2a98fe698 | ||
|
|
f9a414ddbc | ||
|
|
2b5fd71ab0 | ||
|
|
071c95b5b7 | ||
|
|
fb932a96ec | ||
|
|
76d2a5ae21 | ||
|
|
389027c9aa | ||
|
|
de887d18ea | ||
|
|
06fcc8e04c | ||
|
|
e05e3f928d | ||
|
|
7c19748b1b | ||
|
|
2ded43760f | ||
|
|
a5dbc3958d | ||
|
|
608253e0c8 | ||
|
|
a38cbfb13d | ||
|
|
b2371f2585 | ||
|
|
72517cf5cd | ||
|
|
564f99c7fb | ||
|
|
c16e76efa1 | ||
|
|
ec671a3ece | ||
|
|
0c2b9353a1 | ||
|
|
05b30667d5 | ||
|
|
2f156c65bc | ||
|
|
94ce0330c9 | ||
|
|
dc254f08db | ||
|
|
0107361db8 | ||
|
|
1f143abc19 | ||
|
|
c604b5d4ee | ||
|
|
1e76acf211 | ||
|
|
b4a7cf88bb | ||
|
|
d2abcbff2e | ||
|
|
3548bd13a4 | ||
|
|
83809937b1 | ||
|
|
aeaceaef7c | ||
|
|
f23741077e | ||
|
|
bd8b9de5e6 | ||
|
|
8636c1f1f2 | ||
|
|
371f7a40a9 | ||
|
|
ef9f2cc230 | ||
|
|
5a20f1cd72 | ||
|
|
923b6f24ce | ||
|
|
f037a7b937 | ||
|
|
65ced5837c | ||
|
|
06dded0371 | ||
|
|
592b33be07 | ||
|
|
53234f9932 | ||
|
|
bedfa656d8 | ||
|
|
9859b44e07 | ||
|
|
7406a2bb4a | ||
|
|
81fa01f589 | ||
|
|
2c78e713b5 | ||
| 7f6f1627b8 | |||
| 72b8e9743f | |||
| 6b9d4d87dc | |||
|
|
f327f68eb6 | ||
|
|
6c91cac0aa | ||
|
|
b38e2c29e3 | ||
| 9ebf8bc0e3 | |||
|
|
4f9be49545 | ||
| cf2f2b01ff | |||
|
|
c45d70e536 | ||
|
|
24261aa88e | ||
|
|
9dce1e3e2b | ||
|
|
75c5023819 | ||
|
|
9a5c2e37f4 | ||
|
|
906e10e481 | ||
|
|
e4aac8bdbb | ||
|
|
77710f445d | ||
|
|
02d49a92e7 | ||
|
|
1082a37124 | ||
|
|
05ca129522 | ||
|
|
2baf7aaa86 | ||
|
|
96fa902545 | ||
|
|
1bebd9ad51 | ||
|
|
e346383916 | ||
|
|
a2e7224702 | ||
|
|
2e54a0214d | ||
|
|
25db1babaa | ||
|
|
c322fbd036 | ||
|
|
f7041992ce | ||
|
|
a326077b38 | ||
|
|
1e54149f1a | ||
|
|
76045d0558 | ||
|
|
a216a61a40 | ||
|
|
0077f024ee | ||
|
|
8f0f5ef420 | ||
|
|
6f3542c9a3 | ||
|
|
1ae1defb25 | ||
|
|
721b62dda9 | ||
|
|
636ec27ada | ||
|
|
a11851d35a | ||
|
|
6b4cece80e | ||
|
|
549f248817 | ||
|
|
c1b20c7f13 | ||
|
|
1b0e08a316 | ||
|
|
82f6997347 | ||
|
|
6827024509 | ||
|
|
68aec70f4a | ||
|
|
15b4cc768b | ||
|
|
9d5ec334d1 | ||
|
|
b287f01401 | ||
|
|
e831125ec9 | ||
|
|
0d6babcecc | ||
|
|
cd29c39cf4 | ||
|
|
9836040c2b | ||
|
|
86866a45d0 | ||
|
|
10c616e797 | ||
|
|
20ee088f11 | ||
|
|
5d759b5fb8 | ||
|
|
0ad7f62f82 | ||
|
|
9f557683eb | ||
|
|
06d7ef1381 | ||
|
|
8e27ae82bd | ||
|
|
8c7957bc3f | ||
|
|
8327a4e941 | ||
|
|
831e2736e4 | ||
| 55eff111ad | |||
|
|
82a6e55c06 | ||
|
|
69502c1caa | ||
|
|
af36141979 | ||
|
|
ed8ea8d82c | ||
|
|
16c13435ec | ||
|
|
8282ba3d45 | ||
|
|
7681d5b70a | ||
| a5cee34e60 | |||
| cb76498965 | |||
| 5a0e281ade | |||
| 4151751dd7 | |||
| a6851c595e | |||
|
|
b35069b3a9 | ||
|
|
02ccc6c1a2 |
735 changed files with 237487 additions and 2281 deletions
4
.github/workflows/arduino_cron.yml
vendored
4
.github/workflows/arduino_cron.yml
vendored
|
|
@ -61,7 +61,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "feather_rp2350", "flora", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "metro_rp2350", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"]
|
||||
arduino-platform: ["cpb", "cpc", "cpx_ada", "esp32", "esp8266", "feather32u4", "feather_esp32c6", "feather_m0_express", "feather_m4_express", "feather_rp2040", "feather_rp2040_adalogger", "feather_rp2350", "flora", "fruit_jam_tinyusb", "funhouse", "gemma", "gemma_m0", "hallowing_m0", "hallowing_m4_tinyusb", "ledglasses_nrf52840", "magtag", "metro_m0", "metro_m0_tinyusb", "metro_m4", "metro_m4_tinyusb", "monster_m4sk", "monster_m4sk_tinyusb", "metro_rp2350", "neokeytrinkey_m0", "neotrellis_m4", "nrf52832", "nrf52840", "pixeltrinkey_m0", "protrinket_5v", "proxlighttrinkey_m0", "pybadge", "pycamera_s3", "pygamer", "pyportal", "qualia_s3_rgb666", "qt2040_trinkey", "qtpy_m0", "qtpy_esp32s2", "rotarytrinkey_m0", "sht4xtrinkey_m0", "slidetrinkey_m0", "trinket_5v", "trinket_m0", "uno"]
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.check-if-needed.outputs.answer == 'true'
|
||||
needs: check-if-needed
|
||||
|
|
@ -97,6 +97,8 @@ jobs:
|
|||
git clone --quiet https://github.com/adafruit/HID /home/runner/Arduino/libraries/HID_Project
|
||||
rm -rf /home/runner/Arduino/libraries/ArduinoHttpClient
|
||||
git clone --quiet https://github.com/arduino-libraries/ArduinoHttpClient.git /home/runner/Arduino/libraries/ArduinoHttpClient
|
||||
git clone --quiet https://github.com/pschatzmann/ESP32-A2DP /home/runner/Arduino/libraries/ESP32-A2DP
|
||||
git clone --quiet https://github.com/pschatzmann/arduino-audio-tools /home/runner/Arduino/libraries/arduino-audio-tools
|
||||
|
||||
- name: test platforms
|
||||
run: python3 ci/build_platform.py ${{ matrix.arduino-platform }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
// SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
|
||||
#define NOID_1 0 // MCP23XXX pin LED is attached to
|
||||
#define NOID_2 4 // MCP23XXX pin LED is attached to
|
||||
|
||||
Adafruit_MCP23X17 mcp;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
Serial.println("8 Channel Solenoid Driver Demo");
|
||||
if (!mcp.begin_I2C()) {
|
||||
Serial.println("Couldn't find MCP23017..");
|
||||
while (1);
|
||||
}
|
||||
mcp.pinMode(NOID_1, OUTPUT);
|
||||
mcp.pinMode(NOID_2, OUTPUT);
|
||||
|
||||
Serial.println("Found MCP23017, looping...");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.println("Solenoid 1!");
|
||||
mcp.digitalWrite(NOID_1, HIGH);
|
||||
delay(500);
|
||||
mcp.digitalWrite(NOID_1, LOW);
|
||||
delay(500);
|
||||
Serial.println("Solenoid 2!");
|
||||
mcp.digitalWrite(NOID_2, HIGH);
|
||||
delay(500);
|
||||
mcp.digitalWrite(NOID_2, LOW);
|
||||
delay(500);
|
||||
Serial.println("Together!");
|
||||
mcp.digitalWrite(NOID_1, HIGH);
|
||||
mcp.digitalWrite(NOID_2, HIGH);
|
||||
delay(1000);
|
||||
mcp.digitalWrite(NOID_1, LOW);
|
||||
mcp.digitalWrite(NOID_2, LOW);
|
||||
delay(2000);
|
||||
Serial.println("Repeat!");
|
||||
Serial.println();
|
||||
delay(500);
|
||||
}
|
||||
38
8_Channel_Solenoid_Driver/CircuitPython/code.py
Normal file
38
8_Channel_Solenoid_Driver/CircuitPython/code.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
from adafruit_mcp230xx.mcp23017 import MCP23017
|
||||
|
||||
i2c = board.STEMMA_I2C()
|
||||
|
||||
mcp = MCP23017(i2c)
|
||||
|
||||
noid_1 = mcp.get_pin(0)
|
||||
noid_2 = mcp.get_pin(4)
|
||||
noid_1.switch_to_output(value=False)
|
||||
noid_2.switch_to_output(value=False)
|
||||
|
||||
while True:
|
||||
noid_1.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_1.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_2.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(0.2)
|
||||
noid_2.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(1)
|
||||
noid_1.value = True
|
||||
noid_2.value = True
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(1)
|
||||
noid_1.value = False
|
||||
noid_2.value = False
|
||||
print(f"Solenoid 1: {noid_1.value}, Solenoid 2: {noid_2.value}")
|
||||
time.sleep(2)
|
||||
43
AS5600_Magnetic_Encoder/code.py
Normal file
43
AS5600_Magnetic_Encoder/code.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# SPDX-FileCopyrightText: Copyright (c) 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""AS5600 Encoder"""
|
||||
import usb_hid
|
||||
import board
|
||||
from adafruit_hid.consumer_control import ConsumerControl
|
||||
from adafruit_hid.consumer_control_code import ConsumerControlCode
|
||||
import adafruit_as5600
|
||||
|
||||
i2c = board.STEMMA_I2C()
|
||||
sensor = adafruit_as5600.AS5600(i2c)
|
||||
enc_inc = ConsumerControlCode.VOLUME_INCREMENT
|
||||
enc_dec = ConsumerControlCode.VOLUME_DECREMENT
|
||||
cc = ConsumerControl(usb_hid.devices)
|
||||
|
||||
last_val = sensor.angle
|
||||
|
||||
THRESHOLD = sensor.max_angle // 2 # default max_angle is 4095
|
||||
# you can change the max_angle. ex: sensor.max_angle = 1000
|
||||
|
||||
MIN_CHANGE = 25 # minimum change to register as movement
|
||||
# increase to make less sensitive, decrease to make more sensitive
|
||||
|
||||
while True:
|
||||
enc_val = sensor.angle
|
||||
if abs(enc_val - last_val) >= MIN_CHANGE or abs(enc_val - last_val) > THRESHOLD:
|
||||
# Calculate the difference
|
||||
diff = enc_val - last_val
|
||||
# Check for wraparound
|
||||
if diff > THRESHOLD:
|
||||
# Wrapped from ~4095 to ~0 (actually turning backwards)
|
||||
cc.send(enc_dec)
|
||||
elif diff < -THRESHOLD:
|
||||
# Wrapped from ~0 to ~4095 (actually turning forwards)
|
||||
cc.send(enc_inc)
|
||||
elif diff > 0:
|
||||
# Normal forward rotation
|
||||
cc.send(enc_inc)
|
||||
else:
|
||||
# Normal backward rotation (diff < 0)
|
||||
cc.send(enc_dec)
|
||||
last_val = enc_val
|
||||
40
Adafruit_DRV8833/arduino/drv8833_onoff/drv8833_onoff.ino
Normal file
40
Adafruit_DRV8833/arduino/drv8833_onoff/drv8833_onoff.ino
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// Basic ON/OFF control of DC motor via DRV8833
|
||||
|
||||
#define AIN1 5
|
||||
#define AIN2 6
|
||||
#define SLP 7
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit DRV8833 DC Motor Example - ON/OFF");
|
||||
|
||||
// configure pins
|
||||
pinMode(AIN1, OUTPUT);
|
||||
pinMode(AIN2, OUTPUT);
|
||||
pinMode(SLP, OUTPUT);
|
||||
|
||||
// enable DRV8833
|
||||
digitalWrite(SLP, HIGH);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//
|
||||
// FORWARD
|
||||
//
|
||||
Serial.println("Forward");
|
||||
digitalWrite(AIN1, HIGH);
|
||||
digitalWrite(AIN2, LOW);
|
||||
delay(1000);
|
||||
|
||||
//
|
||||
// REVERSE
|
||||
//
|
||||
Serial.println("Reverse");
|
||||
digitalWrite(AIN1, LOW);
|
||||
digitalWrite(AIN2, HIGH);
|
||||
delay(1000);
|
||||
}
|
||||
60
Adafruit_DRV8833/arduino/drv8833_pwm/drv8833_pwm.ino
Normal file
60
Adafruit_DRV8833/arduino/drv8833_pwm/drv8833_pwm.ino
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
// PWM speed control of DC motor via DRV8833
|
||||
|
||||
#define AIN1 5
|
||||
#define AIN2 6
|
||||
#define SLP 7
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Adafruit DRV8833 DC Motor Example - PWM");
|
||||
|
||||
// configure pins
|
||||
pinMode(AIN1, OUTPUT);
|
||||
pinMode(AIN2, OUTPUT);
|
||||
pinMode(SLP, OUTPUT);
|
||||
|
||||
// enable DRV8833
|
||||
digitalWrite(SLP, HIGH);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//
|
||||
// FORWARD
|
||||
//
|
||||
Serial.println("Forward");
|
||||
digitalWrite(AIN2, LOW);
|
||||
// ramp speed up
|
||||
Serial.println(" ramping up");
|
||||
for (int duty_cycle=0; duty_cycle<256; duty_cycle++) {
|
||||
analogWrite(AIN1, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
// ramp speed down
|
||||
Serial.println(" ramping down");
|
||||
for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) {
|
||||
analogWrite(AIN1, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
//
|
||||
// REVERSE
|
||||
//
|
||||
Serial.println("Reverse");
|
||||
digitalWrite(AIN1, LOW);
|
||||
// ramp speed up
|
||||
Serial.println(" ramping up");
|
||||
for (int duty_cycle=0; duty_cycle<256; duty_cycle++) {
|
||||
analogWrite(AIN2, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
// ramp speed down
|
||||
Serial.println(" ramping down");
|
||||
for (int duty_cycle=255; duty_cycle>=0; duty_cycle--) {
|
||||
analogWrite(AIN2, duty_cycle);
|
||||
delay(10);
|
||||
}
|
||||
}
|
||||
30
Adafruit_DRV8833/arduino/drv8833_stepper/drv8833_stepper.ino
Normal file
30
Adafruit_DRV8833/arduino/drv8833_stepper/drv8833_stepper.ino
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// SPDX-FileCopyrightText: 2025 lady ada for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Stepper.h>
|
||||
|
||||
// change this to the number of steps on your motor
|
||||
#define STEPS 200
|
||||
|
||||
// create an instance of the stepper class, specifying
|
||||
// the number of steps of the motor and the pins it's
|
||||
// attached to
|
||||
Stepper stepper(STEPS, 4, 5, 6, 7);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(9600);
|
||||
Serial.println("Stepper test!");
|
||||
// set the speed of the motor to 30 RPMs
|
||||
stepper.setSpeed(60);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println("Forward");
|
||||
stepper.step(STEPS);
|
||||
Serial.println("Backward");
|
||||
stepper.step(-STEPS);
|
||||
}
|
||||
37
Adafruit_DRV8833/circuitpython/onoff/code.py
Normal file
37
Adafruit_DRV8833/circuitpython/onoff/code.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
import digitalio
|
||||
|
||||
# Configure pins
|
||||
AIN1 = digitalio.DigitalInOut(board.D5)
|
||||
AIN2 = digitalio.DigitalInOut(board.D6)
|
||||
SLP = digitalio.DigitalInOut(board.D7)
|
||||
|
||||
AIN1.switch_to_output()
|
||||
AIN2.switch_to_output()
|
||||
SLP.switch_to_output()
|
||||
|
||||
# Enable DRV8833
|
||||
SLP.value = True
|
||||
|
||||
# Loop forever
|
||||
while True:
|
||||
#
|
||||
# FORWARD
|
||||
#
|
||||
print("Forward")
|
||||
AIN1.value = True
|
||||
AIN2.value = False
|
||||
time.sleep(1)
|
||||
|
||||
#
|
||||
# REVERSE
|
||||
#
|
||||
print("Reverse")
|
||||
AIN1.value = False
|
||||
AIN2.value = True
|
||||
time.sleep(1)
|
||||
48
Adafruit_DRV8833/circuitpython/pwm/code.py
Normal file
48
Adafruit_DRV8833/circuitpython/pwm/code.py
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
# SPDX-FileCopyrightText: 2025 Carter Nelson for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import time
|
||||
import board
|
||||
import digitalio
|
||||
import pwmio
|
||||
|
||||
# Configure pins
|
||||
AIN1 = pwmio.PWMOut(board.D5, frequency=2000)
|
||||
AIN2 = pwmio.PWMOut(board.D6, frequency=2000)
|
||||
SLP = digitalio.DigitalInOut(board.D7)
|
||||
|
||||
SLP.switch_to_output()
|
||||
|
||||
# Enable DRV8833
|
||||
SLP.value = True
|
||||
|
||||
# Loop forever
|
||||
while True:
|
||||
#
|
||||
# FORWARD
|
||||
#
|
||||
print("Forward")
|
||||
AIN2.duty_cycle = 0
|
||||
print(" ramping up")
|
||||
for duty_cycle in range(0, 65536, 100):
|
||||
AIN1.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
print(" ramping down")
|
||||
for duty_cycle in range(65535, -1, -100):
|
||||
AIN1.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
|
||||
#
|
||||
# REVERSE
|
||||
#
|
||||
print("Reverse")
|
||||
AIN1.duty_cycle = 0
|
||||
print(" ramping up")
|
||||
for duty_cycle in range(0, 65536, 100):
|
||||
AIN2.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
print(" ramping down")
|
||||
for duty_cycle in range(65535, -1, -100):
|
||||
AIN2.duty_cycle = duty_cycle
|
||||
time.sleep(0.01)
|
||||
|
|
@ -109,16 +109,32 @@ void setup() {
|
|||
digitalWrite(ESP32_RESETN, HIGH);
|
||||
pixel.setPixelColor(0, 20, 20, 0); pixel.show();
|
||||
delay(100);
|
||||
|
||||
#if defined(LED_BUILTIN)
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
while (Serial.available()) {
|
||||
#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool
|
||||
#if defined(LED_BUILTIN)
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
#endif
|
||||
#else
|
||||
pixel.setPixelColor(0, 10, 0, 0); pixel.show();
|
||||
#endif
|
||||
SerialESP32.write(Serial.read());
|
||||
}
|
||||
|
||||
while (SerialESP32.available()) {
|
||||
#if defined(ARDUINO_ARCH_RP2040) // Neopixel is blocking and this annoys esptool
|
||||
#if defined(LED_BUILTIN)
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
#endif
|
||||
#else
|
||||
pixel.setPixelColor(0, 0, 0, 10); pixel.show();
|
||||
#endif
|
||||
Serial.write(SerialESP32.read());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,105 @@
|
|||
// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
#include "config.h"
|
||||
#include <Adafruit_BME280.h>
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
|
||||
Adafruit_BME280 bme; // I2C
|
||||
|
||||
AdafruitIO_Feed *temperature = io.feed("temperature");
|
||||
AdafruitIO_Feed *humidity = io.feed("humidity");
|
||||
AdafruitIO_Feed *pressure = io.feed("pressure");
|
||||
float temp, humid, pres;
|
||||
|
||||
Adafruit_NeoPixel pixel(1, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
// wait for serial monitor to open
|
||||
//while(! Serial);
|
||||
|
||||
// turn on neopixel
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, HIGH);
|
||||
pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
|
||||
pixel.setBrightness(10); // not so bright
|
||||
|
||||
pixel.setPixelColor(0, 0xFF0000); // red
|
||||
pixel.show();
|
||||
|
||||
if (! bme.begin()) {
|
||||
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
|
||||
deepSleep();
|
||||
}
|
||||
Serial.println("Found BME280");
|
||||
float temp = bme.readTemperature();
|
||||
float pres = bme.readPressure() / 100.0F;
|
||||
float hum = bme.readHumidity();
|
||||
// shhh time to close your eyes
|
||||
bme.setSampling(Adafruit_BME280::MODE_SLEEP,
|
||||
Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16, Adafruit_BME280::SAMPLING_X16,
|
||||
Adafruit_BME280::FILTER_OFF,
|
||||
Adafruit_BME280::STANDBY_MS_1000);
|
||||
|
||||
Serial.print("Connecting to Adafruit IO");
|
||||
|
||||
pixel.setPixelColor(0, 0xFFFF00); // yellow
|
||||
pixel.show();
|
||||
|
||||
// connect to io.adafruit.com
|
||||
io.connect();
|
||||
|
||||
// wait for a connection
|
||||
while(io.status() < AIO_CONNECTED) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// we are connected
|
||||
pixel.setPixelColor(0, 0x00FF00); // green
|
||||
pixel.show();
|
||||
Serial.println();
|
||||
Serial.println(io.statusText());
|
||||
|
||||
io.run();
|
||||
|
||||
temp = temp * 9.0 / 5.0 + 32;
|
||||
Serial.print("Temperature = ");
|
||||
Serial.print(temp);
|
||||
Serial.println(" *F");
|
||||
temperature->save(temp);
|
||||
|
||||
Serial.print("Pressure = ");
|
||||
Serial.print(pres);
|
||||
Serial.println(" hPa");
|
||||
pressure->save(pres);
|
||||
|
||||
Serial.print("Humidity = ");
|
||||
Serial.print(hum);
|
||||
Serial.println(" %");
|
||||
humidity->save(hum);
|
||||
|
||||
Serial.println();
|
||||
|
||||
deepSleep();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// we never get here!
|
||||
}
|
||||
|
||||
|
||||
void deepSleep() {
|
||||
pinMode(NEOPIXEL_POWER, OUTPUT);
|
||||
digitalWrite(NEOPIXEL_POWER, LOW); // off
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
esp_sleep_enable_timer_wakeup(300000000); // 5 minutes
|
||||
esp_deep_sleep_start();
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// SPDX-FileCopyrightText: 2025 Limor Fried for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
#define IO_USERNAME "your-aio-username"
|
||||
#define IO_KEY "your-aio-token"
|
||||
#define WIFI_SSID "your-wifi-ssid"
|
||||
#define WIFI_PASS "your-wifi-pass"
|
||||
|
||||
#include "AdafruitIO_WiFi.h"
|
||||
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
"""
|
||||
CircuitPython Adafruit IO Example for BME280 and LC709203 Sensors
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import alarm
|
||||
|
|
@ -14,11 +16,21 @@ import adafruit_requests
|
|||
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
|
||||
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
|
||||
|
|
@ -78,9 +90,9 @@ def send_io_data(feed, value):
|
|||
# Wi-Fi connections can have issues! This ensures the code will continue to run.
|
||||
try:
|
||||
# Connect to Wi-Fi
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to {}!".format(secrets["ssid"]))
|
||||
print("IP:", wifi.radio.ipv4_address)
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"IP: {wifi.radio.ipv4_address}")
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
@ -90,12 +102,6 @@ except Exception as e: # pylint: disable=broad-except
|
|||
print(e)
|
||||
go_to_sleep(60)
|
||||
|
||||
# Set your Adafruit IO Username and Key in secrets.py
|
||||
# (visit io.adafruit.com if you need to create an account,
|
||||
# or if you need your Adafruit IO key.)
|
||||
aio_username = secrets["aio_username"]
|
||||
aio_key = secrets["aio_key"]
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ CircuitPython Simple Example for BME280 and LC709203 Sensors
|
|||
"""
|
||||
import time
|
||||
import board
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
from adafruit_bme280 import basic as adafruit_bme280
|
||||
|
||||
# Create sensor objects, using the board's default I2C bus.
|
||||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
# SPDX-FileCopyrightText: Copyright (c) 2025 Tim Cocks for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
CircuitPython example for deep sleep and BME280 sensor sending data
|
||||
to Adafruit IO.
|
||||
"""
|
||||
from os import getenv
|
||||
import time
|
||||
import alarm
|
||||
import board
|
||||
import digitalio
|
||||
import neopixel
|
||||
import wifi
|
||||
|
||||
from adafruit_bme280 import advanced as adafruit_bme280
|
||||
import adafruit_connection_manager
|
||||
import adafruit_requests
|
||||
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError
|
||||
|
||||
|
||||
# enable power to NeoPixels.
|
||||
np_power = digitalio.DigitalInOut(board.NEOPIXEL_POWER)
|
||||
np_power.switch_to_output(value=True)
|
||||
|
||||
# standard LED
|
||||
builtin_led = digitalio.DigitalInOut(board.LED)
|
||||
builtin_led.switch_to_output(value=True)
|
||||
|
||||
# neopixel to use for status
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.1, pixel_order=neopixel.GRB, auto_write=True
|
||||
)
|
||||
status_pixel[0] = 0xFF0000
|
||||
|
||||
# Create sensor object, using the board's default I2C bus.
|
||||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
|
||||
print("Found BME280")
|
||||
# change this to match the location's pressure (hPa) at sea level
|
||||
bme280.sea_level_pressure = 1013.25
|
||||
|
||||
# temperature converted to F
|
||||
temperature = bme280.temperature * 9 / 5 + 32
|
||||
humidity = bme280.relative_humidity
|
||||
pressure = bme280.pressure
|
||||
print("\nTemperature: %0.1f F" % temperature)
|
||||
print("Humidity: %0.1f %%" % humidity)
|
||||
print("Pressure: %0.1f hPa" % pressure)
|
||||
|
||||
bme280.mode = adafruit_bme280.MODE_SLEEP
|
||||
bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
|
||||
bme280.iir_filter = adafruit_bme280.IIR_FILTER_DISABLE
|
||||
bme280.standby_period = adafruit_bme280.STANDBY_TC_1000
|
||||
|
||||
# set status pixel to yellow
|
||||
status_pixel[0] = 0xFFFF00
|
||||
|
||||
print("Connecting to AdafruitIO")
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("WIFI_SSID")
|
||||
password = getenv("WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
print("Connecting to %s" % ssid)
|
||||
wifi.radio.connect(ssid, password)
|
||||
print("Connected to %s!" % ssid)
|
||||
|
||||
# setup socket pool and requests session
|
||||
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
|
||||
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl_context)
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
# set status pixel to green
|
||||
status_pixel[0] = 0x00FF00
|
||||
|
||||
try:
|
||||
# Get the feeds from Adafruit IO
|
||||
temperature_feed = io.get_feed("temperature")
|
||||
humidity_feed = io.get_feed("humidity")
|
||||
pressure_feed = io.get_feed("pressure")
|
||||
|
||||
# send data to the feeds
|
||||
io.send_data(temperature_feed["key"], temperature)
|
||||
io.send_data(humidity_feed["key"], humidity)
|
||||
io.send_data(pressure_feed["key"], pressure)
|
||||
|
||||
except AdafruitIO_RequestError as e:
|
||||
print(e)
|
||||
print(
|
||||
"You must create feeds on AdafruitIO for: temperature, humidity, and pressure"
|
||||
)
|
||||
|
||||
# turn off the neopixel and builtin LED
|
||||
np_power.value = False
|
||||
builtin_led.value = False
|
||||
|
||||
# Create an alarm that will trigger 5 minutes from now.
|
||||
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + (5 * 60))
|
||||
# Exit the program, and then deep sleep until the alarm wakes us.
|
||||
alarm.exit_and_deep_sleep_until_alarms(time_alarm)
|
||||
# Does not return, so we never get here.
|
||||
|
|
@ -3,6 +3,8 @@
|
|||
"""
|
||||
CircuitPython Adafruit IO Example for LC709203 Sensor
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import alarm
|
||||
|
|
@ -13,11 +15,21 @@ import socketpool
|
|||
import adafruit_requests
|
||||
from adafruit_io.adafruit_io import IO_HTTP
|
||||
from adafruit_lc709203f import LC709203F, PackSize
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
|
||||
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
|
||||
|
|
@ -58,9 +70,9 @@ def send_io_data(feed, value):
|
|||
# Wi-Fi connections can have issues! This ensures the code will continue to run.
|
||||
try:
|
||||
# Connect to Wi-Fi
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to {}!".format(secrets["ssid"]))
|
||||
print("IP:", wifi.radio.ipv4_address)
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"IP: {wifi.radio.ipv4_address}")
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
@ -70,12 +82,6 @@ except Exception as e: # pylint: disable=broad-except
|
|||
print(e)
|
||||
go_to_sleep(60)
|
||||
|
||||
# Set your Adafruit IO Username and Key in secrets.py
|
||||
# (visit io.adafruit.com if you need to create an account,
|
||||
# or if you need your Adafruit IO key.)
|
||||
aio_username = secrets["aio_username"]
|
||||
aio_key = secrets["aio_key"]
|
||||
|
||||
# Initialize an Adafruit IO HTTP API object
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
"""
|
||||
CircuitPython GitHub Stars viewer
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import ssl
|
||||
import wifi
|
||||
|
|
@ -13,12 +15,17 @@ from adafruit_display_text import bitmap_label
|
|||
from adafruit_bitmap_font import bitmap_font
|
||||
import adafruit_requests
|
||||
|
||||
# Get WiFi details secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
display = board.DISPLAY
|
||||
|
||||
|
|
@ -38,10 +45,10 @@ group.append(text_area)
|
|||
display.root_group = group
|
||||
|
||||
# Connect to WiFi
|
||||
print("Connecting to %s"%secrets["ssid"])
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print("Connected to %s!"%secrets["ssid"])
|
||||
print("My IP address is", wifi.radio.ipv4_address)
|
||||
print(f"Connecting to {ssid}")
|
||||
wifi.radio.connect(ssid, password)
|
||||
print(f"Connected to {ssid}!")
|
||||
print(f"My IP address is {wifi.radio.ipv4_address}")
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ LOOP = False # Update to True loop WAV playback. False plays once.
|
|||
|
||||
audio = audiobusio.I2SOut(board.A2, board.A1, board.A0)
|
||||
|
||||
with open("chikken.wav", "rb") as wave_file:
|
||||
with open("booploop.wav", "rb") as wave_file:
|
||||
wav = audiocore.WaveFile(wave_file)
|
||||
|
||||
print("Playing wav file!")
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -22,14 +23,22 @@ USE_CELSIUS = False
|
|||
# Interval the sensor publishes to Adafruit IO, in minutes
|
||||
PUBLISH_INTERVAL = 10
|
||||
|
||||
### WiFi ###
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
# AirLift FeatherWing
|
||||
esp32_cs = DigitalInOut(board.D13)
|
||||
|
|
@ -38,8 +47,8 @@ esp32_ready = DigitalInOut(board.D11)
|
|||
|
||||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
|
||||
# Connect to a PM2.5 sensor over UART
|
||||
reset_pin = None
|
||||
|
|
@ -142,7 +151,7 @@ def read_bme(is_celsius=False):
|
|||
|
||||
|
||||
# Create an instance of the Adafruit IO HTTP client
|
||||
io = IO_HTTP(secrets["aio_user"], secrets["aio_key"], wifi)
|
||||
io = IO_HTTP(aio_username, aio_key, wifi)
|
||||
|
||||
# Describes feeds used to hold Adafruit IO data
|
||||
feed_aqi = io.get_feed("air-quality-sensor.aqi")
|
||||
|
|
@ -150,11 +159,11 @@ feed_aqi_category = io.get_feed("air-quality-sensor.category")
|
|||
feed_humidity = io.get_feed("air-quality-sensor.humidity")
|
||||
feed_temperature = io.get_feed("air-quality-sensor.temperature")
|
||||
|
||||
# Set up location metadata from secrets.py file
|
||||
# Set up location metadata from settings.toml file
|
||||
location_metadata = {
|
||||
"lat": secrets["latitude"],
|
||||
"lon": secrets["longitude"],
|
||||
"ele": secrets["elevation"],
|
||||
"lat": getenv("latitude"),
|
||||
"lon": getenv("longitude"),
|
||||
"ele": getenv("elevation"),
|
||||
}
|
||||
|
||||
elapsed_minutes = 0
|
||||
|
|
|
|||
|
|
@ -14,12 +14,19 @@ from adafruit_esp32spi import adafruit_esp32spi_wifimanager
|
|||
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
|
||||
### WiFi ###
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = os.getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = os.getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
secrets = {
|
||||
"ssid" : os.getenv("CIRCUITPY_WIFI_SSID"),
|
||||
"password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"),
|
||||
}
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
|
|
@ -34,19 +41,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_light = neopixel.NeoPixel(
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -14,6 +15,21 @@ from adafruit_esp32spi import adafruit_esp32spi_wifimanager
|
|||
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### Sensor Calibration ###
|
||||
# Appliance power LED's light level, in Lux
|
||||
APPLIANCE_ON_LUX = 30.0
|
||||
|
|
@ -22,13 +38,6 @@ SENSOR_READ_TIME = 10.0
|
|||
|
||||
### WiFi ###
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
esp32_ready = DigitalInOut(board.ESP_BUSY)
|
||||
|
|
@ -42,19 +51,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_light = neopixel.NeoPixel(
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
@ -67,10 +76,10 @@ sensor = adafruit_bh1750.BH1750(i2c)
|
|||
|
||||
### Feeds ###
|
||||
# Set up a feed named Relay for subscribing to the relay feed on Adafruit IO
|
||||
feed_relay = secrets["aio_username"] + "/feeds/relay"
|
||||
feed_relay = f"{aio_username}/feeds/relay"
|
||||
|
||||
# Set up a feed named status for subscribing to the status feed on Adafruit IO
|
||||
feed_status = secrets["aio_username"] + "/feeds/status"
|
||||
feed_status = f"{aio_username}/feeds/status"
|
||||
|
||||
### Code ###
|
||||
|
||||
|
|
@ -122,8 +131,8 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
|
|||
# Set up a MiniMQTT Client
|
||||
client = MQTT.MQTT(
|
||||
broker="io.adafruit.com",
|
||||
username=secrets["aio_username"],
|
||||
password=secrets["aio_key"],
|
||||
username=aio_username,
|
||||
password=aio_key,
|
||||
socket_pool=pool,
|
||||
ssl_context=ssl_context,
|
||||
)
|
||||
|
|
|
|||
27
Adafruit_IO_Reed_Switch/rpi-pico-w112213141.json
Normal file
27
Adafruit_IO_Reed_Switch/rpi-pico-w112213141.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"exportVersion": "1.0.0",
|
||||
"exportedBy": "tyeth_demo",
|
||||
"exportedAt": "2025-05-02T17:08:03.857Z",
|
||||
"exportedFromDevice": {
|
||||
"board": "rpi-pico-w",
|
||||
"firmwareVersion": "1.0.0-beta.100"
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "Reed Switch",
|
||||
"pinName": "D13",
|
||||
"type": "reed_switch",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true,
|
||||
"visualization": {
|
||||
"offLabel": "Open",
|
||||
"offIcon": "fa6:solid:door-open",
|
||||
"onLabel": "Closed",
|
||||
"onIcon": "fa6:regular:door-closed"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
import busio
|
||||
|
|
@ -13,14 +14,22 @@ import neopixel
|
|||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
from adafruit_io.adafruit_io import IO_MQTT
|
||||
|
||||
### WiFi ###
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
### WiFi ###
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
|
|
@ -35,19 +44,19 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
"""Use below for Most Boards"""
|
||||
status_light = neopixel.NeoPixel(
|
||||
status_pixel = neopixel.NeoPixel(
|
||||
board.NEOPIXEL, 1, brightness=0.2
|
||||
) # Uncomment for Most Boards
|
||||
"""Uncomment below for ItsyBitsy M4"""
|
||||
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
|
||||
# Uncomment below for an externally defined RGB LED
|
||||
# import adafruit_rgbled
|
||||
# from adafruit_esp32spi import PWMOut
|
||||
# RED_LED = PWMOut.PWMOut(esp, 26)
|
||||
# GREEN_LED = PWMOut.PWMOut(esp, 27)
|
||||
# BLUE_LED = PWMOut.PWMOut(esp, 25)
|
||||
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
# status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
|
||||
# Set up a pin for controlling the relay
|
||||
power_pin = DigitalInOut(board.D3)
|
||||
|
|
@ -89,11 +98,11 @@ def on_message(client, feed_id, payload):
|
|||
|
||||
def on_relay_msg(client, topic, message):
|
||||
# Method called whenever user/feeds/relay has a new value
|
||||
if message == "morning":
|
||||
print("Morning - turning outlet ON")
|
||||
if message == "1":
|
||||
print("Received 1 - turning outlet ON")
|
||||
power_pin.value = True
|
||||
elif message == "night":
|
||||
print("Night - turning outlet OFF")
|
||||
elif message == "0":
|
||||
print("Received 0 - turning outlet OFF")
|
||||
power_pin.value = False
|
||||
else:
|
||||
print("Unexpected value received on relay feed.")
|
||||
|
|
@ -110,8 +119,8 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
|
|||
# Initialize a new MQTT Client object
|
||||
mqtt_client = MQTT.MQTT(
|
||||
broker="io.adafruit.com",
|
||||
username=secrets["aio_username"],
|
||||
password=secrets["aio_key"],
|
||||
username=aio_username,
|
||||
password=aio_key,
|
||||
socket_pool=pool,
|
||||
ssl_context=ssl_context,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ while True:
|
|||
time.sleep(30)
|
||||
|
||||
# Stepper 1
|
||||
if not st1.isAlive() and int(stepper_start.value):
|
||||
if not st1.is_alive() and int(stepper_start.value):
|
||||
stepper_1_steps = aio.receive(feed_step_1_steps.key)
|
||||
stepper_1_steps = int(stepper_1_steps.value)
|
||||
if stepper_1_steps > 0: # stepper slider is set
|
||||
|
|
@ -125,7 +125,7 @@ while True:
|
|||
st1.start()
|
||||
|
||||
# Stepper 2
|
||||
if not st2.isAlive() and int(stepper_start.value):
|
||||
if not st2.is_alive() and int(stepper_start.value):
|
||||
stepper_2_steps = aio.receive(feed_step_2_steps.key)
|
||||
stepper_2_steps = int(stepper_2_steps.value)
|
||||
if stepper_2_steps > 0: # stepper slider is set
|
||||
|
|
|
|||
83
Adafruit_IO_Template_Emails/rpi-pico-w-potty-training.json
Normal file
83
Adafruit_IO_Template_Emails/rpi-pico-w-potty-training.json
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
{
|
||||
"exportVersion": "1.0.0",
|
||||
"exportedBy": "tyeth",
|
||||
"exportedAt": "2025-06-10T18:13:03.071Z",
|
||||
"exportedFromDevice": {
|
||||
"board": "rpi-pico-w",
|
||||
"firmwareVersion": "1.0.0-beta.100"
|
||||
},
|
||||
"components": [
|
||||
{
|
||||
"name": "💦 Wee Button",
|
||||
"pinName": "D18",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💦 Wee LED",
|
||||
"pinName": "D2",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💩 Poo Button",
|
||||
"pinName": "D19",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "💩 Poo LED",
|
||||
"pinName": "D3",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "❌ Didn't Go Button",
|
||||
"pinName": "D20",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "❌ Didn't Go LED",
|
||||
"pinName": "D4",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "🔔 Tell Adult Button",
|
||||
"pinName": "D21",
|
||||
"type": "push_button",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "INPUT",
|
||||
"period": 0,
|
||||
"pull": "UP",
|
||||
"isPin": true
|
||||
},
|
||||
{
|
||||
"name": "🔔 Tell Adult LED",
|
||||
"pinName": "D5",
|
||||
"type": "led",
|
||||
"mode": "DIGITAL",
|
||||
"direction": "OUTPUT",
|
||||
"isPin": true
|
||||
}
|
||||
]
|
||||
}
|
||||
72
Adafruit_IO_Template_Emails/template.liquid
Normal file
72
Adafruit_IO_Template_Emails/template.liquid
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<b>🌟 Daily Potty Training Report 🌟</b>
|
||||
Hi there! Here's how our little superstar did:
|
||||
---
|
||||
<b>🚽 Successful Wees: {{ vars.wee_progress }}</b>
|
||||
{% for i in (1..vars.wee_progress) %}💧{% endfor %}
|
||||
{% if vars.wee_progress <= 5 -%}
|
||||
Great start! Every success counts, and they're building good habits one wee at a time! 🌱
|
||||
{% elsif vars.wee_progress <= 15 -%}
|
||||
Fantastic progress! They're really getting the hang of this - keep up the amazing work! 🎯
|
||||
{% else -%}
|
||||
SUPERSTAR ALERT! 🌟 Absolutely crushing it with those wee successes! They're a potty champion! 🏆
|
||||
{% endif %}---
|
||||
|
||||
<b>💩 Successful Poos: {{ vars.poo_progress }}</b>
|
||||
{% for i in (1..vars.poo_progress) %}🟤{% endfor %}
|
||||
{% if vars.poo_progress == 0 -%}
|
||||
Poos can be tricky, but they're being so brave! Every try is a step forward! 💪
|
||||
{% elsif vars.poo_progress < 2 -%}
|
||||
Look at them go! They're becoming a real poo pro - that's awesome progress! 🎉
|
||||
{% else -%}
|
||||
POO CHAMPION! 🏅 They've mastered one of the trickiest parts - so proud! 🎊
|
||||
{% endif %}---
|
||||
|
||||
<b>🤝 Told an Adult: {{ vars.informed_progress }}</b>
|
||||
{% for i in (1..vars.informed_progress) %}🗣️{% endfor %}
|
||||
{% if vars.informed_progress <= 5 -%}
|
||||
Communication is key! Keep practicing saying when they need to go - They're doing great! 📢
|
||||
{% elsif vars.informed_progress <= 15 -%}
|
||||
Wonderful communication skills! They're really good at letting us know - that's so helpful! 👏
|
||||
{% else -%}
|
||||
COMMUNICATION SUPERSTAR! 🌟 They're amazing at telling adults - that's such a big kid skill! 🎯
|
||||
{% endif %}---
|
||||
|
||||
<b>👻 Nothing Happened: {{ vars.nothing_progress }}</b>
|
||||
{% for i in (1..vars.nothing_progress) %}⭕{% endfor %}
|
||||
{% if vars.nothing_progress <= 3 -%}
|
||||
That's okay! Trying is what matters, and their body will let them know when it's ready! 🌈
|
||||
{% else -%}
|
||||
So patient and persistent! Even when nothing happens, they keep trying - that's real determination! 💫
|
||||
{% endif %}---
|
||||
|
||||
<b>📊 Daily Summary:</b>
|
||||
{% capture total_tries -%}{{ vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress }}{% endcapture -%}
|
||||
{% capture successes -%}{{ vars.wee_progress | plus: vars.poo_progress }}{% endcapture -%}
|
||||
{% capture success_rate -%}{% if total_tries != "0" -%}{{ successes | times: 100 | divided_by: total_tries }}{% else -%}100{% endif -%}{% endcapture -%}
|
||||
{% capture bar_filled -%}{{ success_rate | divided_by: 10 }}{% endcapture -%}
|
||||
{% capture bar_empty -%}{{ 10 | minus: bar_filled }}{% endcapture -%}
|
||||
Total potty visits: {{ total_tries }}
|
||||
Success rate: {{ success_rate }}% [{%- for i in (1..bar_filled) -%}█{%- endfor -%}{%- for i in (1..bar_empty) -%}░{%- endfor -%}]
|
||||
{%- assign total_events = vars.wee_progress | plus: vars.poo_progress | plus: vars.nothing_progress | plus: vars.informed_progress -%}
|
||||
({{ total_events }} events today )
|
||||
{% if total_events <= 3 %}
|
||||
💝 <b>Today:</b> They're doing such a great job learning! Every day gets a little easier...
|
||||
{% elsif total_events <= 5 %}
|
||||
🌟 <b>Today:</b> Ayee! They're really getting the hang of this potty training thing! Keep it up!
|
||||
{% elsif total_events <= 8 %}
|
||||
🌟 <b>Today:</b> WOW! Look at all that practice! They're becoming such a potty expert.
|
||||
{% else %}
|
||||
🏆 <b>Today:</b> INCREDIBLE DAY! They're absolutely rocking this potty training journey! 🎊🎉
|
||||
{%- endif %}
|
||||
|
||||
Keep being awesome!
|
||||
With love and high-fives! 🙌
|
||||
---
|
||||
{%- assign event_mod = total_events | modulo: 3 %}
|
||||
{% if event_mod == 0 -%}
|
||||
<i>P.S. Remember: Every expert was once a beginner - they're doing brilliantly! 🌟</i>
|
||||
{% elsif event_mod == 1 -%}
|
||||
<i>P.S. Fun fact: Even superheroes had to learn to use the potty! 🦸</i>
|
||||
{% else -%}
|
||||
<i>P.S. Remember: accidents are just practice in disguise! They're doing amazingly! 💕</i>
|
||||
{% endif %}
|
||||
0
Adafruit_NeoPot/Arduino_Rainbow_Pot/.uno.test.only
Normal file
0
Adafruit_NeoPot/Arduino_Rainbow_Pot/.uno.test.only
Normal file
71
Adafruit_NeoPot/Arduino_Rainbow_Pot/Arduino_Rainbow_Pot.ino
Normal file
71
Adafruit_NeoPot/Arduino_Rainbow_Pot/Arduino_Rainbow_Pot.ino
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
int sensorPin = A0; // select the input pin for the potentiometer
|
||||
int neoPixelPin = 4; // select the pin for the LED
|
||||
int sensorValue = 0; // variable to store the value coming from the sensor
|
||||
|
||||
int readings[10];
|
||||
size_t count = 0;
|
||||
|
||||
Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, neoPixelPin, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// Insert an int value at index 0 of an int array, shifting all other elements up.
|
||||
// If the array already contains 'maxCount' elements, the last one is dropped.
|
||||
// 'count' is the number of valid elements currently stored in the array.
|
||||
void insert(int arr[], size_t maxCount, int value, size_t &count){
|
||||
// Determine how many elements we need to shift (cannot exceed the array bounds)
|
||||
size_t shiftCount = (count < maxCount) ? count : maxCount - 1;
|
||||
|
||||
// Shift elements up by one position
|
||||
for (size_t i = shiftCount; i > 0; --i) {
|
||||
arr[i] = arr[i - 1];
|
||||
}
|
||||
|
||||
// Insert the new value at the beginning
|
||||
arr[0] = value;
|
||||
|
||||
// Update the element count
|
||||
if (count < maxCount) {
|
||||
++count; // we added a new element
|
||||
} // else count stays the same – the last element was overwritten
|
||||
}
|
||||
|
||||
// Input an array of 10 or fewer int's, and a count of how many have values
|
||||
// Returns average of the values in the array.
|
||||
int average(int arr[], size_t count){
|
||||
int sum = 0;
|
||||
for(int i = 0; i < 10; i++){
|
||||
sum = sum + arr[i];
|
||||
}
|
||||
return sum / count;
|
||||
}
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
uint32_t Wheel(byte WheelPos) {
|
||||
WheelPos = 255 - WheelPos;
|
||||
if(WheelPos < 85) {
|
||||
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
|
||||
}
|
||||
if(WheelPos < 170) {
|
||||
WheelPos -= 85;
|
||||
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
|
||||
}
|
||||
WheelPos -= 170;
|
||||
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
strip.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
sensorValue = analogRead(sensorPin);
|
||||
insert(readings, 10, sensorValue, count);
|
||||
strip.setPixelColor(0, Wheel(average(readings, count) / 4));
|
||||
strip.show();
|
||||
}
|
||||
36
Adafruit_NeoPot/CircuitPython_Rainbow_Pot/code.py
Normal file
36
Adafruit_NeoPot/CircuitPython_Rainbow_Pot/code.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# SPDX-FileCopyrightText: 2025 Tim Cocks for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""
|
||||
NeoPot NeoPixel Rainbow Demo
|
||||
"""
|
||||
|
||||
import board
|
||||
import analogio
|
||||
import neopixel
|
||||
import rainbowio
|
||||
|
||||
analog_pin = analogio.AnalogIn(board.A0)
|
||||
knob_pixel = neopixel.NeoPixel(board.D4, 1, brightness=0.75, auto_write=True)
|
||||
|
||||
analog_smoothing_buffer = []
|
||||
|
||||
|
||||
def map_range(x, in_min, in_max, out_min, out_max):
|
||||
return (x - in_min) / (in_max - in_min) * out_max - out_min
|
||||
|
||||
|
||||
def average(values):
|
||||
if not values:
|
||||
return 0
|
||||
|
||||
return sum(values) / len(values)
|
||||
|
||||
|
||||
while True:
|
||||
analog_smoothing_buffer.insert(0, analog_pin.value)
|
||||
if len(analog_smoothing_buffer) >= 10:
|
||||
analog_smoothing_buffer.pop(-1)
|
||||
|
||||
knob_pixel[0] = rainbowio.colorwheel(
|
||||
map_range(average(analog_smoothing_buffer), 0, 65525, 0, 255)
|
||||
)
|
||||
|
|
@ -7,6 +7,7 @@ library example esp32spi_simpletest.py:
|
|||
https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI/
|
||||
blob/master/examples/esp32spi_simpletest.py '''
|
||||
|
||||
from os import getenv
|
||||
import board
|
||||
import busio
|
||||
from digitalio import DigitalInOut
|
||||
|
|
@ -14,12 +15,17 @@ import adafruit_connection_manager
|
|||
import adafruit_requests
|
||||
from adafruit_esp32spi import adafruit_esp32spi
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
print("Arduino Nano RP2040 Connect webclient test")
|
||||
|
||||
|
|
@ -51,7 +57,7 @@ for ap in esp.scan_networks():
|
|||
print("Connecting to AP...")
|
||||
while not esp.is_connected:
|
||||
try:
|
||||
esp.connect_AP(secrets["ssid"], secrets["password"])
|
||||
esp.connect_AP(ssid, password)
|
||||
except RuntimeError as e:
|
||||
print("could not connect to AP, retrying: ", e)
|
||||
continue
|
||||
|
|
|
|||
27564
Asteroid_Tracker/Arial-14.bdf
Normal file
27564
Asteroid_Tracker/Arial-14.bdf
Normal file
File diff suppressed because it is too large
Load diff
BIN
Asteroid_Tracker/asteroid.bmp
Normal file
BIN
Asteroid_Tracker/asteroid.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
161
Asteroid_Tracker/code.py
Normal file
161
Asteroid_Tracker/code.py
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
# SPDX-FileCopyrightText: 2025 Liz Clark for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
import os
|
||||
import time
|
||||
import ssl
|
||||
import board
|
||||
import wifi
|
||||
import socketpool
|
||||
import microcontroller
|
||||
import displayio
|
||||
from adafruit_display_text.bitmap_label import Label
|
||||
from adafruit_bitmap_font import bitmap_font
|
||||
import adafruit_imageload
|
||||
from fourwire import FourWire
|
||||
import adafruit_requests
|
||||
from adafruit_gc9a01a import GC9A01A
|
||||
from adafruit_ticks import ticks_ms, ticks_add, ticks_diff
|
||||
|
||||
cad_url = ("https://ssd-api.jpl.nasa.gov/cad.api?"
|
||||
"des=2024%20YR4&body=ALL&"
|
||||
"date-min=2030-01-01&date-max=2060-01-01")
|
||||
sentry_url = "https://ssd-api.jpl.nasa.gov/sentry.api?des=2024%20YR4"
|
||||
# connect to wifi
|
||||
try:
|
||||
wifi.radio.connect(os.getenv('CIRCUITPY_WIFI_SSID'), os.getenv('CIRCUITPY_WIFI_PASSWORD'))
|
||||
except TypeError:
|
||||
print("Could not find WiFi info. Check your settings.toml file!")
|
||||
raise
|
||||
context = ssl.create_default_context()
|
||||
with open("/ssd-api-jpl-nasa-gov-chain.pem", "rb") as certfile:
|
||||
context.load_verify_locations(cadata=certfile.read())
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, context)
|
||||
|
||||
spi = board.SPI()
|
||||
tft_cs = board.TX
|
||||
tft_dc = board.RX
|
||||
tft_reset = None
|
||||
|
||||
displayio.release_displays()
|
||||
|
||||
display_bus = FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_reset)
|
||||
display = GC9A01A(display_bus, width=240, height=240, auto_refresh=False)
|
||||
|
||||
main_group = displayio.Group()
|
||||
display.root_group = main_group
|
||||
|
||||
bitmap_bg, palette_bg = adafruit_imageload.load("/earth_bg.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
grid_bg = displayio.TileGrid(bitmap_bg, pixel_shader=palette_bg)
|
||||
main_group.append(grid_bg)
|
||||
|
||||
font = bitmap_font.load_font('/Arial-14.bdf')
|
||||
name_area = Label(font, text="2024 YR4", color=0xFFFFFF, background_color=0x000000)
|
||||
name_area.anchored_position = (display.width / 2, 0)
|
||||
name_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
date_area = Label(font, text="2032-12-22", color=0xFFFFFF, background_color=0x000000)
|
||||
date_area.anchored_position = (display.width / 2, name_area.height+10)
|
||||
date_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
moon_area = Label(font, text="Moon: ", color=0xFFFFFF, background_color=0x000000)
|
||||
moon_area.anchored_position = (display.width / 2, name_area.height+10 + date_area.height+5)
|
||||
moon_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
earth_area = Label(font, text="Earth: ", color=0xFFFFFF, background_color=0x000000)
|
||||
earth_area.anchored_position = (display.width / 2, name_area.height+10 +
|
||||
moon_area.height+5 +
|
||||
date_area.height + 5)
|
||||
earth_area.anchor_point = (0.5, 0.0)
|
||||
|
||||
impact_area = Label(font, text="Earth Impact: 0.0000%", color=0xFFFFFF, background_color=0x000000)
|
||||
impact_area.anchored_position = (display.width / 2, name_area.height+10 +
|
||||
moon_area.height+5 +
|
||||
earth_area.height + 5 +
|
||||
date_area.height + 5)
|
||||
impact_area.anchor_point = (0.5, 0.0)
|
||||
main_group.append(impact_area)
|
||||
main_group.append(earth_area)
|
||||
main_group.append(moon_area)
|
||||
main_group.append(date_area)
|
||||
main_group.append(name_area)
|
||||
|
||||
bit_asteroid, pal_asteroid = adafruit_imageload.load("/asteroid.bmp",
|
||||
bitmap=displayio.Bitmap,
|
||||
palette=displayio.Palette)
|
||||
|
||||
asteroid = displayio.TileGrid(bit_asteroid, pixel_shader=pal_asteroid,
|
||||
x = 25, y=100)
|
||||
pal_asteroid.make_transparent(0)
|
||||
main_group.append(asteroid)
|
||||
|
||||
def diagonal_travel(bitmap_object, start_x=-59, start_y=-59, end_x=240, end_y=240, delay=0.01):
|
||||
# Set initial position
|
||||
bitmap_object.x = start_x
|
||||
bitmap_object.y = start_y
|
||||
|
||||
# Calculate total movement distance
|
||||
distance_x = end_x - start_x
|
||||
distance_y = end_y - start_y
|
||||
|
||||
# Calculate number of steps (use the larger distance)
|
||||
steps = max(abs(distance_x), abs(distance_y)) // 1
|
||||
|
||||
# Calculate step size for each axis to maintain diagonal movement
|
||||
step_x = distance_x / steps
|
||||
step_y = distance_y / steps
|
||||
|
||||
# Animate the movement
|
||||
for i in range(steps + 1):
|
||||
# Update position
|
||||
bitmap_object.x = int(start_x + (step_x * i))
|
||||
bitmap_object.y = int(start_y + (step_y * i))
|
||||
display.refresh()
|
||||
# Pause to control animation speed
|
||||
time.sleep(delay)
|
||||
|
||||
def au_to_miles(au):
|
||||
# 1 AU = 92,955,807 miles
|
||||
miles_per_au = 92955807
|
||||
|
||||
return au * miles_per_au
|
||||
|
||||
timer_clock = ticks_ms()
|
||||
timer = 3600 * 1000
|
||||
first_run = True
|
||||
|
||||
while True:
|
||||
try:
|
||||
if first_run or ticks_diff(ticks_ms(), timer_clock) >= timer:
|
||||
sentry_response = requests.get(sentry_url)
|
||||
sentry_json = sentry_response.json()
|
||||
impact = sentry_json['summary']['ip']
|
||||
sentry_response.close()
|
||||
overall_ip = float(impact) * 100
|
||||
cad_response = requests.get(cad_url)
|
||||
cad_json = cad_response.json()
|
||||
earth_distance = au_to_miles(float(cad_json['data'][0][4]))
|
||||
earth_area.text = f"{cad_json['data'][0][10]}: {int(earth_distance)} mi"
|
||||
moon_distance = au_to_miles(float(cad_json['data'][1][4]))
|
||||
moon_area.text = f"{cad_json['data'][1][10]}: {int(moon_distance)} mi"
|
||||
date = cad_json['data'][0][3]
|
||||
date = date.split()
|
||||
date_area.text = f"{date[0]}"
|
||||
cad_response.close()
|
||||
impact_area.text = f"Earth Impact: {overall_ip:.4f}%"
|
||||
display.refresh()
|
||||
timer_clock = ticks_add(timer_clock, timer)
|
||||
diagonal_travel(asteroid, start_x=-45, start_y=300, end_x=300, end_y=-45)
|
||||
time.sleep(0.1)
|
||||
# pylint: disable=broad-except
|
||||
except Exception as e:
|
||||
print("Error:\n", str(e))
|
||||
print("Resetting microcontroller in 10 seconds")
|
||||
time.sleep(10)
|
||||
microcontroller.reset()
|
||||
BIN
Asteroid_Tracker/earth_bg.bmp
Normal file
BIN
Asteroid_Tracker/earth_bg.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 57 KiB |
109
Asteroid_Tracker/ssd-api-jpl-nasa-gov-chain.pem
Normal file
109
Asteroid_Tracker/ssd-api-jpl-nasa-gov-chain.pem
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIHRjCCBS6gAwIBAgIQV82HcwAIb4tFlHpCQCtGuzANBgkqhkiG9w0BAQsFADBR
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSgwJgYDVQQD
|
||||
DB9FbnRydXN0IE9WIFRMUyBJc3N1aW5nIFJTQSBDQSAxMB4XDTI1MDIwNTE0MDkw
|
||||
MloXDTI2MDMwMzE0MTg1OFoweDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
|
||||
b3JuaWExETAPBgNVBAcMCFBhc2FkZW5hMSIwIAYDVQQKDBlKZXQgUHJvcHVsc2lv
|
||||
biBMYWJvcmF0b3J5MR0wGwYDVQQDDBRzc2QtYXBpLmpwbC5uYXNhLmdvdjCCASIw
|
||||
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKXzsG9/H8CQzmmu1vwdM1RYrziS
|
||||
8dzCuw2fqOJXfvOEB+jbZZGIPDvUXCqug0Gb+Z5MsbAdwxT8RsKRuWl/xgRZWr/Y
|
||||
mtafmEIf3QeKy3/Hu2uUS1GQjTkfmY/3cj6szXJDF4YAC3lngFVWftmGrXhA1Dmm
|
||||
WqApxguIf2XPjetKjcX1TMdC5XyQ/lsy/vJTX+S8G9HRk+OhO45kAf8AvVeCWCOa
|
||||
XQ7jpEVBd610RGgD972XNazhoYtL2QKBm6GrSkx1rW/7aiPU0QLbkCoTJIno1yHn
|
||||
nlYKVYWn0V1uG2vcuChhebX6WOHp7U6KAcaKVbTvaTxv8whi+t4gjcJRbgECAwEA
|
||||
AaOCAvEwggLtMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUaA1FyjXC55ob8LOE
|
||||
3dXafwuJwREwaAYIKwYBBQUHAQEEXDBaMDYGCCsGAQUFBzAChipodHRwOi8vY2Vy
|
||||
dC5zc2wuY29tL0VudHJ1c3QtT1ZUTFMtSS1SMS5jZXIwIAYIKwYBBQUHMAGGFGh0
|
||||
dHA6Ly9vY3Nwcy5zc2wuY29tMB8GA1UdEQQYMBaCFHNzZC1hcGkuanBsLm5hc2Eu
|
||||
Z292MCMGA1UdIAQcMBowCAYGZ4EMAQICMA4GDCsGAQQBgqkwAQMBAjAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAgYIKwYBBQUHAwEwOwYDVR0fBDQwMjAwoC6gLIYqaHR0cDov
|
||||
L2NybHMuc3NsLmNvbS9FbnRydXN0LU9WVExTLUktUjEuY3JsMB0GA1UdDgQWBBQ9
|
||||
28d7XB5zNhW4Z/FiFGVefv8TpDAOBgNVHQ8BAf8EBAMCBaAwggF/BgorBgEEAdZ5
|
||||
AgQCBIIBbwSCAWsBaQB3AJaXZL9VWJet90OHaDcIQnfp8DrV9qTzNm5GpD8PyqnG
|
||||
AAABlNZ6jp0AAAQDAEgwRgIhAM/xkbmguT7NTj3lc6p/F3Um9y7fDhYjzHhWvyDc
|
||||
HIaQAiEAmRCNTCoJAOFtiXFseiUANEn16Wr3rW5cAUiAJ3mQPewAdwDLOPcViXyE
|
||||
oURfW8Hd+8lu8ppZzUcKaQWFsMsUwxRY5wAAAZTWeo6SAAAEAwBIMEYCIQCExfjt
|
||||
QsfbwEpS8cI3YNcXOAW3fMiAh6vOW2wD88iruwIhALfInWVFlobCtQYXLtXq2iqe
|
||||
HO083hp/cD0oDIChPD9SAHUAZBHEbKQS7KeJHKICLgC8q08oB9QeNSer6v7VA8l9
|
||||
zfAAAAGU1nqOzgAABAMARjBEAiBTSQczvVZCJ41l+JiC9n8fOkuYNf8jQ1uG5rKy
|
||||
M/g6IwIgK7YZziGBfBHHKYR8e+IyitJktRevFehnGPEwbMNOO1wwDQYJKoZIhvcN
|
||||
AQELBQADggIBAGCVD/1ROYGTKPhFeDUFiPjW7JKagsmldnWdtYQ7ran5Ozd8Hkju
|
||||
XaEi/sDed8wHv1Bf8lesHd3dz2KlaefLVBknntOMSC7fxr7cvkHHgJyJbWtrOESF
|
||||
JTuy13CdbIHZTxSRtVErCqumUC4omAOfffoGEMlcKvLlIK1NtZTibPsmeUVceMjI
|
||||
1iZ6OeAOQfZHwlHk49r1zN2D41/5NOT6hpg1bP+rwp/ZhRpT0cB0Q+PBF/GeRCJp
|
||||
fyLWng/yfILPl2EZoo2RJ0FbdM7VhxGK9359CbKpIPDrZAqagTafEvzRoL9afBAo
|
||||
n/fht0RCmHiz56vmYo4a742Hwr1Hgempgx+UBlTluf7UGEJ3ju9JEgM/wY+Zc9wm
|
||||
HyBcQjzPFcDMGGJo/cQwPNYOI06LePpvGiWLe/8WvW+MSPk19JEQj4uOf02Yowzj
|
||||
1LXFvSzTase6AjrjiOPd57rgmwUKju+/ouX5qyOBbB4dKJ1Q7pOvb2wR+yF/2Mro
|
||||
YJS73WJVK64mk6aletwcL0uy+vZiZlesBWIiERPR915NiDEeEYSXYtmwu0XhiS8b
|
||||
jxpMbXIEuhRtA3c8WeqKCbuSnQs+8SMaYpHZ3QgwCreBWl25J5J4nPtW3tPgINkG
|
||||
gKDVZyGsOJE4t/sQs7zoQAf4rX7eY+U4w+6CIE7XAkACI7Mug6kXOJZJ
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGVjCCBD6gAwIBAgIQb+Y+3l/BwDr7bXqFvToVbTANBgkqhkiG9w0BAQsFADBO
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
|
||||
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTI0MDgyMjE3NTMzOFoX
|
||||
DTI3MDgyMjE3NTMzN1owUTELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
|
||||
b3JhdGlvbjEoMCYGA1UEAwwfRW50cnVzdCBPViBUTFMgSXNzdWluZyBSU0EgQ0Eg
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKCL+NvDMIL3efFuNaQc
|
||||
aYwzFpZQd/B6gkTd0s+Cu5jFu3Iw5qxis7xsRQWf739+ohRm42PYEiH7IjErxQAw
|
||||
+jbLstW7HP7UaTDoYSN/IZ5mG0wHF/QLlAyXsGz9hNPPE31CN8xfA4JFH8jaQftN
|
||||
QJJnRgWKFys3LK/U2YWbOkx4M50XHFsEDkAuwkt11vEzveJkglfd2O9srAhMsz21
|
||||
YciZed5VQRncdFbY0hh/hbs9n9eRkmg/ItDOmvKbWiljXP7Pigl9mMJWfnqEJaUd
|
||||
tt4FzpiizghGgTwGytDAUH7GxtiLdf3F/Vs5UhRUdEQEnm5Y1OVdjLb3CZpTc3vw
|
||||
XViwO/jG7b64Ancehrrpagbj8yVXGk4Vh8Rj4nf99whmGGP+z9+9T5DXaWTF2xt9
|
||||
PCbviJaIotT3XO7J2VGZyxnV85us4WVY7/vpCQgUEajsglaFW53UCD3uzuBUR3lW
|
||||
YDWZvd7wiPg5wWhA6DXL//MKVQ0dvUJ03AI+zxUvYCDyhBPOEx9ojRgF7HOvq+wG
|
||||
EvX6kV34e5ZLaeR0Wr8iaUq8Wl9oPB0vxuZdJMT4ewNHjLB6IFJY4cszBQBPmxMx
|
||||
jnRkaDb7B/dlS/I2sjTyxB/n+CwbHbuiwkKqVVQpbYws7cmrkUjLQklqFO1xJrVI
|
||||
Me3bAHHqOZeMfUYCo5gxrPCLAgMBAAGjggErMIIBJzASBgNVHRMBAf8ECDAGAQH/
|
||||
AgEAMB8GA1UdIwQYMBaAFPsuN+7jhHonLs0ZNbEzfP/UREK5MEwGCCsGAQUFBwEB
|
||||
BEAwPjA8BggrBgEFBQcwAoYwaHR0cDovL2NlcnQuc3NsLmNvbS9TU0xjb20tVExT
|
||||
LVJvb3QtMjAyMi1SU0EuY2VyMBEGA1UdIAQKMAgwBgYEVR0gADAdBgNVHSUEFjAU
|
||||
BggrBgEFBQcDAgYIKwYBBQUHAwEwQQYDVR0fBDowODA2oDSgMoYwaHR0cDovL2Ny
|
||||
bHMuc3NsLmNvbS9TU0xjb20tVExTLVJvb3QtMjAyMi1SU0EuY3JsMB0GA1UdDgQW
|
||||
BBRoDUXKNcLnmhvws4Td1dp/C4nBETAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN
|
||||
AQELBQADggIBABNdeusuCgNkxuATfOU8MHWeX7BYQA77yRx/fdV5rEMOdIRMRH/J
|
||||
Ar7qQ+RH9SY4tqAwkfsKBNhgqZnjzeYOMmOVRTlOQpKJwMwZbX5M1IvuF45EF5BO
|
||||
dwRBIMAqSxLzFV4CAS1LUEptuA6SGMC6thY4TdQoHN1YR5A/tFmPj9ASDxlqE7Wc
|
||||
7ZkeL1R8NAKNbcYGPEUXAy9NMiIwwnTqJqQSQXAquf8rhOiOfqWoghMU1xUQ4VgO
|
||||
aPPCbHCanTLWLLo6MEcHuVNdYvtTUmxixuTcqU2E+XfzUH0qoOskiwxAXncRaM+H
|
||||
7diEROecsP9PQFui/ll7QmiEE4goazA72Mvk1IsL7+2gI9BrUgWGxGLOoCcJqvUg
|
||||
Z/8K6N5UJZKXnjOL+tjQVk8qCcF818vuOtOvSAQUeOjSdb1QjaM18Fc62qyclga8
|
||||
FIxqs4UPJg7ozHrCkPBUXb1MlUu0yf0Y9i8R9woh6S0k4TZGZKKKdxmS7QnF4D6M
|
||||
Rr60DDCwdUKP5dMmqPsWd2qaBxlaS3wacNqjhdt0DbXmEOz18BRiKbRxaZ4sDxn9
|
||||
O8XngqHUi9j5bulLTfQSqxDXuMwG0WjkqgkJaCujQ1zIZ7sSIcfGzBevRSy1R32Y
|
||||
Wp1i1vr3oWsj+Cw9gr8FPEw/pPcW7GWfoJvpiHVQ99u7+vUqjQQ13ieL
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
|
||||
MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
|
||||
DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
|
||||
DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
|
||||
b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
|
||||
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
|
||||
L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
|
||||
t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
|
||||
S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
|
||||
PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
|
||||
L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
|
||||
R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
|
||||
dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
|
||||
+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
|
||||
d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
|
||||
AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
|
||||
gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
|
||||
BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
|
||||
NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
|
||||
hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
|
||||
QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
|
||||
R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
|
||||
DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
|
||||
P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
|
||||
lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
|
||||
bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
|
||||
AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
|
||||
r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
|
||||
Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
|
||||
98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
|
||||
-----END CERTIFICATE-----
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import json
|
||||
import board
|
||||
|
|
@ -38,15 +39,20 @@ nau7802 = NAU7802(board.STEMMA_I2C(), address=0x2A, active_channels=2)
|
|||
nau7802.gain = 128
|
||||
enabled = nau7802.enable(True)
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
print("Connecting to WiFi...")
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
wifi.radio.connect(ssid, password)
|
||||
|
||||
print("Connected to WiFi!")
|
||||
# check system time
|
||||
|
|
@ -65,7 +71,7 @@ else:
|
|||
esp = None
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
device = IoTCentralDevice(
|
||||
pool, esp, secrets['id_scope'], secrets['device_id'], secrets['device_primary_key']
|
||||
pool, esp, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key")
|
||||
)
|
||||
display.fill(0)
|
||||
display.print("DIALING*")
|
||||
|
|
@ -191,6 +197,8 @@ avg_oz = []
|
|||
values = []
|
||||
val_offset = 0
|
||||
avg_values = []
|
||||
the_ounces = 0
|
||||
the_grams = 0
|
||||
|
||||
# initial reading from the scale
|
||||
for w in range(5):
|
||||
|
|
|
|||
0
Bluetooth_Lumon_Speaker/.esp32.test.only
Normal file
0
Bluetooth_Lumon_Speaker/.esp32.test.only
Normal file
44
Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino
Normal file
44
Bluetooth_Lumon_Speaker/Bluetooth_Lumon_Speaker.ino
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: 2020 Phil Schatzmann
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/*
|
||||
Streaming Music from Bluetooth
|
||||
|
||||
Copyright (C) 2020 Phil Schatzmann
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// ==> Example which shows how to use the built in ESP32 I2S >= 3.0.0
|
||||
|
||||
#include "ESP_I2S.h"
|
||||
#include "BluetoothA2DPSink.h"
|
||||
|
||||
const uint8_t I2S_SCK = 8; /* Audio data bit clock */
|
||||
const uint8_t I2S_WS = 7; /* Audio data left and right clock */
|
||||
const uint8_t I2S_SDOUT = 14; /* ESP32 audio data output (to speakers) */
|
||||
I2SClass i2s;
|
||||
|
||||
BluetoothA2DPSink a2dp_sink(i2s);
|
||||
|
||||
void setup() {
|
||||
i2s.setPins(I2S_SCK, I2S_WS, I2S_SDOUT);
|
||||
if (!i2s.begin(I2S_MODE_STD, 44100, I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO, I2S_STD_SLOT_BOTH)) {
|
||||
Serial.println("Failed to initialize I2S!");
|
||||
while (1); // do nothing
|
||||
}
|
||||
|
||||
a2dp_sink.start("Lumon Industries Speaker");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
}
|
||||
0
Bluetooth_Unified_Keyboard_Bridge/.pico_rp2040.test.only
Normal file
0
Bluetooth_Unified_Keyboard_Bridge/.pico_rp2040.test.only
Normal file
0
Bluetooth_Unified_Keyboard_Bridge/.pico_rp2350.test.only
Normal file
0
Bluetooth_Unified_Keyboard_Bridge/.pico_rp2350.test.only
Normal file
|
|
@ -0,0 +1,730 @@
|
|||
// SPDX-FileCopyrightText: 2025 John Park for Adafruit Industries
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
// made with assistance from Claude Sonnet 4
|
||||
//
|
||||
// Unified Bluetooth HID Bridge - BT Classic & BLE
|
||||
// put keyboard in pairing mode, then press reset or BOOT button
|
||||
// slow blinks mean scanning
|
||||
// fast blinks mean keyboard detected, press a keyboard key to connect
|
||||
|
||||
// === CONFIGURATION ===
|
||||
#define DEBUG_MODE false // Set to false to reduce serial output
|
||||
#define BLINK_MODE true // Set to false for solid LED (no keypress blinks)
|
||||
#define SCAN_MODE "Both" // Options: "BT_Classic", "BLE", "Both"
|
||||
|
||||
// Include both Bluetooth stacks
|
||||
extern "C" {
|
||||
#include "btstack.h"
|
||||
}
|
||||
#include <BluetoothHCI.h>
|
||||
#include <BluetoothHIDMaster.h>
|
||||
#include <Keyboard.h>
|
||||
#include <Mouse.h>
|
||||
|
||||
// Connection state management
|
||||
typedef enum {
|
||||
INIT,
|
||||
SCANNING_CLASSIC,
|
||||
CLASSIC_CONNECTING,
|
||||
CLASSIC_CONNECTED,
|
||||
SCANNING_BLE,
|
||||
BLE_CONNECTED,
|
||||
BOTH_FAILED,
|
||||
DISCONNECTED
|
||||
} connection_state_t;
|
||||
|
||||
connection_state_t connection_state = INIT;
|
||||
|
||||
// BT Classic components
|
||||
BluetoothHCI hci;
|
||||
bd_addr_t target_keyboard_addr;
|
||||
bool target_keyboard_found = false;
|
||||
uint16_t hid_control_cid = 0;
|
||||
uint16_t hid_interrupt_cid = 0;
|
||||
static btstack_packet_callback_registration_t hci_event_callback_registration;
|
||||
|
||||
// BLE components
|
||||
BluetoothHIDMaster ble_hid;
|
||||
HIDKeyStream keystream;
|
||||
|
||||
// Shared state tracking
|
||||
static uint8_t last_modifiers = 0;
|
||||
static uint8_t last_keys[6] = {0};
|
||||
bool keyPressed[256] = {0}; // Track which keys are currently pressed
|
||||
|
||||
// LED management
|
||||
unsigned long ledTimer = 0;
|
||||
bool ledState = false;
|
||||
unsigned long ledOffTime = 0;
|
||||
bool ledBlinking = false;
|
||||
int pairingBlinks = 0;
|
||||
unsigned long pairingBlinkTimer = 0;
|
||||
|
||||
// Timing management
|
||||
unsigned long lastScan = 0;
|
||||
unsigned long stateStartTime = 0;
|
||||
const unsigned long CLASSIC_SCAN_TIMEOUT = 10000; // 10 seconds
|
||||
const unsigned long BLE_SCAN_TIMEOUT = 15000; // 15 seconds
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
delay(3000);
|
||||
|
||||
Serial.println("=== UNIFIED BLUETOOTH HID BRIDGE ===");
|
||||
Serial.printf("Scan mode: %s\n", SCAN_MODE);
|
||||
Serial.println("Put your Bluetooth device in pairing mode now");
|
||||
|
||||
// Initialize LED
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
Serial.println("LED initialized");
|
||||
|
||||
// Initialize USB HID
|
||||
Keyboard.begin();
|
||||
Mouse.begin();
|
||||
Serial.println("USB HID initialized");
|
||||
|
||||
// Start with LED blinking to show we're alive
|
||||
ledTimer = millis();
|
||||
ledState = true;
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
Serial.println("Starting Bluetooth stack initialization...");
|
||||
|
||||
// Choose scan mode based on user setting
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
Serial.println("BT Classic only mode");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = millis();
|
||||
initAndScanClassic();
|
||||
} else if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
Serial.println("BLE only mode");
|
||||
connection_state = SCANNING_BLE;
|
||||
stateStartTime = millis();
|
||||
initAndScanBLE();
|
||||
} else {
|
||||
Serial.println("Both protocols mode - trying Classic first");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = millis();
|
||||
initAndScanClassic();
|
||||
}
|
||||
}
|
||||
|
||||
void initAndScanClassic() {
|
||||
Serial.println("\n=== INITIALIZING BT CLASSIC STACK ===");
|
||||
|
||||
// Initialize HCI for Classic
|
||||
l2cap_init();
|
||||
sm_init();
|
||||
gap_set_default_link_policy_settings(LM_LINK_POLICY_ENABLE_SNIFF_MODE | LM_LINK_POLICY_ENABLE_ROLE_SWITCH);
|
||||
hci_set_master_slave_policy(HCI_ROLE_MASTER);
|
||||
hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR);
|
||||
|
||||
Serial.println("BTStack components initialized");
|
||||
|
||||
hci.install();
|
||||
hci.begin();
|
||||
Serial.println("HCI installed and started");
|
||||
|
||||
// Register BTStack event handler
|
||||
hci_event_callback_registration.callback = &classic_packet_handler;
|
||||
hci_add_event_handler(&hci_event_callback_registration);
|
||||
Serial.println("Event handler registered");
|
||||
|
||||
// Turn on Bluetooth
|
||||
hci_power_control(HCI_POWER_ON);
|
||||
Serial.println("Bluetooth power ON");
|
||||
|
||||
delay(2000); // Give it time to initialize
|
||||
|
||||
Serial.println("Starting BT Classic device scan...");
|
||||
scanForClassicDevices();
|
||||
}
|
||||
|
||||
void scanForClassicDevices() {
|
||||
Serial.println("Scanning for BT Classic devices...");
|
||||
|
||||
auto devices = hci.scan(BluetoothHCI::any_cod);
|
||||
|
||||
Serial.printf("Classic scan completed. Found %d devices:\n", devices.size());
|
||||
|
||||
if (devices.size() == 0) {
|
||||
Serial.println("No Classic devices found. Will try BLE after timeout.");
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("Address | RSSI | Class | Name");
|
||||
Serial.println("------------------|------|----------|------------------");
|
||||
|
||||
for (auto device : devices) {
|
||||
uint32_t cod = device.deviceClass();
|
||||
uint8_t majorClass = (cod >> 8) & 0x1F;
|
||||
uint8_t minorClass = (cod >> 2) & 0x3F;
|
||||
|
||||
Serial.printf("%s | %4d | %08lx | %s",
|
||||
device.addressString(), device.rssi(), cod, device.name());
|
||||
|
||||
// Look for HID keyboards in Classic scan
|
||||
if (majorClass == 5 && (minorClass & 0x10)) { // HID Keyboard
|
||||
Serial.print(" [HID KEYBOARD] *** CONNECTING ***");
|
||||
|
||||
// We found a Classic keyboard!
|
||||
const char* addrStr = device.addressString();
|
||||
sscanf(addrStr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
|
||||
&target_keyboard_addr[0], &target_keyboard_addr[1], &target_keyboard_addr[2],
|
||||
&target_keyboard_addr[3], &target_keyboard_addr[4], &target_keyboard_addr[5]);
|
||||
target_keyboard_found = true;
|
||||
|
||||
Serial.printf("\nFound Classic HID keyboard: %s\n", device.name());
|
||||
Serial.printf("Address: %s\n", device.addressString());
|
||||
|
||||
// Start Classic connection
|
||||
connection_state = CLASSIC_CONNECTING;
|
||||
stateStartTime = millis();
|
||||
startClassicConnection();
|
||||
|
||||
Serial.println();
|
||||
return; // Exit the loop - we found our keyboard
|
||||
} else {
|
||||
// Show device type for debugging
|
||||
switch (majorClass) {
|
||||
case 1: Serial.print(" [Computer]"); break;
|
||||
case 2: Serial.print(" [Phone]"); break;
|
||||
case 3: Serial.print(" [Network]"); break;
|
||||
case 4: Serial.print(" [Audio/Video]"); break;
|
||||
case 5: Serial.print(" [HID Device]"); break;
|
||||
default: Serial.printf(" [Class:%d]", majorClass); break;
|
||||
}
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
Serial.println("No HID keyboards found in Classic scan.");
|
||||
}
|
||||
|
||||
void fallbackToBLE() {
|
||||
Serial.println("\n=== FALLING BACK TO BLE ===");
|
||||
connection_state = SCANNING_BLE;
|
||||
stateStartTime = millis();
|
||||
initAndScanBLE();
|
||||
}
|
||||
|
||||
void initAndScanBLE() {
|
||||
Serial.println("Initializing BLE stack...");
|
||||
|
||||
// Setup the HID key to ASCII conversion
|
||||
keystream.begin();
|
||||
Serial.println("KeyStream initialized");
|
||||
|
||||
// Setup BLE callbacks
|
||||
setupBLECallbacks();
|
||||
Serial.println("BLE callbacks configured");
|
||||
|
||||
// Start BLE HID master
|
||||
ble_hid.begin(true);
|
||||
Serial.println("BLE HID master started");
|
||||
|
||||
// Start BLE connection attempt
|
||||
ble_hid.connectBLE();
|
||||
Serial.println("BLE connection initiated - waiting for device...");
|
||||
Serial.println("(BLE devices will be detected on first keypress)");
|
||||
}
|
||||
|
||||
void setupBLECallbacks() {
|
||||
// BLE Mouse callbacks
|
||||
ble_hid.onMouseMove([](void *cbdata, int dx, int dy, int dw) {
|
||||
(void) cbdata;
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Mouse: X:%d Y:%d Wheel:%d\n", dx, dy, dw);
|
||||
}
|
||||
Mouse.move(dx, dy);
|
||||
if (dw != 0) Mouse.move(0, 0, dw);
|
||||
blinkOnActivity();
|
||||
});
|
||||
|
||||
ble_hid.onMouseButton([](void *cbdata, int butt, bool down) {
|
||||
(void) cbdata;
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Mouse: Button %d %s\n", butt, down ? "DOWN" : "UP");
|
||||
}
|
||||
if (down) {
|
||||
if (butt == 1) Mouse.press(MOUSE_LEFT);
|
||||
else if (butt == 2) Mouse.press(MOUSE_RIGHT);
|
||||
else if (butt == 3) Mouse.press(MOUSE_MIDDLE);
|
||||
} else {
|
||||
if (butt == 1) Mouse.release(MOUSE_LEFT);
|
||||
else if (butt == 2) Mouse.release(MOUSE_RIGHT);
|
||||
else if (butt == 3) Mouse.release(MOUSE_MIDDLE);
|
||||
}
|
||||
blinkOnActivity();
|
||||
});
|
||||
|
||||
// BLE Keyboard callbacks
|
||||
ble_hid.onKeyDown([](void *cbdata, int key) {
|
||||
handleBLEKey(key, true);
|
||||
}, (void *)true);
|
||||
|
||||
ble_hid.onKeyUp([](void *cbdata, int key) {
|
||||
handleBLEKey(key, false);
|
||||
}, (void *)false);
|
||||
}
|
||||
|
||||
void startClassicConnection() {
|
||||
if (!target_keyboard_found) {
|
||||
Serial.println("ERROR: No Classic target keyboard found");
|
||||
fallbackToBLE();
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.println("=== STARTING CLASSIC HID CONNECTION ===");
|
||||
Serial.println("Creating L2CAP Control channel...");
|
||||
|
||||
// Create control channel first
|
||||
l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_CONTROL,
|
||||
48, &hid_control_cid);
|
||||
}
|
||||
|
||||
void handleBLEKey(int key, bool state) {
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("BLE Keyboard: %02x %s\n", key, state ? "DOWN" : "UP");
|
||||
}
|
||||
|
||||
if (key >= 256) return; // Bounds check
|
||||
|
||||
// Check if this is the first BLE key press (connection detection)
|
||||
if (connection_state == SCANNING_BLE) {
|
||||
Serial.printf("\n*** BLE KEYBOARD DETECTED ON FIRST KEYPRESS ***\n");
|
||||
Serial.printf("=== BLE DEVICE CONNECTED ===\n");
|
||||
Serial.printf("Ready to forward BLE input to USB.\n");
|
||||
Serial.printf("========================\n");
|
||||
|
||||
connection_state = BLE_CONNECTED;
|
||||
celebrationBlinks(8); // 4 blinks for BLE
|
||||
|
||||
// After celebration, LED will go solid (handled in LED patterns)
|
||||
}
|
||||
|
||||
// Forward the key to USB
|
||||
forwardBLEKeyToUSB(key, state);
|
||||
blinkOnActivity();
|
||||
}
|
||||
|
||||
void classic_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
|
||||
UNUSED(size);
|
||||
|
||||
if (packet_type == HCI_EVENT_PACKET) {
|
||||
uint8_t event = hci_event_packet_get_type(packet);
|
||||
|
||||
switch (event) {
|
||||
case BTSTACK_EVENT_STATE:
|
||||
if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
|
||||
Serial.println("Classic BTstack ready");
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_OPENED:
|
||||
{
|
||||
uint16_t cid = l2cap_event_channel_opened_get_local_cid(packet);
|
||||
uint16_t psm = l2cap_event_channel_opened_get_psm(packet);
|
||||
uint8_t status = l2cap_event_channel_opened_get_status(packet);
|
||||
|
||||
if (status) {
|
||||
Serial.printf("Classic L2CAP connection failed, status 0x%02x\n", status);
|
||||
handleClassicConnectionError(status);
|
||||
return;
|
||||
}
|
||||
|
||||
Serial.printf("Classic L2CAP channel opened: CID=0x%04x, PSM=0x%04x\n", cid, psm);
|
||||
|
||||
if (psm == BLUETOOTH_PSM_HID_CONTROL) {
|
||||
hid_control_cid = cid;
|
||||
Serial.println("Classic HID Control channel established");
|
||||
Serial.println("Creating L2CAP Interrupt channel...");
|
||||
|
||||
// Create interrupt channel
|
||||
l2cap_create_channel(&classic_packet_handler, target_keyboard_addr, BLUETOOTH_PSM_HID_INTERRUPT,
|
||||
48, &hid_interrupt_cid);
|
||||
} else if (psm == BLUETOOTH_PSM_HID_INTERRUPT) {
|
||||
hid_interrupt_cid = cid;
|
||||
Serial.println("Classic HID Interrupt channel established");
|
||||
Serial.println("*** CLASSIC HID CONNECTION COMPLETE ***");
|
||||
connection_state = CLASSIC_CONNECTED;
|
||||
|
||||
celebrationBlinks(6); // 3 blinks for Classic
|
||||
|
||||
// After celebration, LED will go solid (handled in LED patterns)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case L2CAP_EVENT_CHANNEL_CLOSED:
|
||||
{
|
||||
uint16_t cid = l2cap_event_channel_closed_get_local_cid(packet);
|
||||
Serial.printf("Classic L2CAP channel closed: CID=0x%04x\n", cid);
|
||||
|
||||
if (cid == hid_control_cid) {
|
||||
hid_control_cid = 0;
|
||||
} else if (cid == hid_interrupt_cid) {
|
||||
hid_interrupt_cid = 0;
|
||||
}
|
||||
|
||||
if (hid_control_cid == 0 && hid_interrupt_cid == 0) {
|
||||
Serial.println("Classic HID connection lost.");
|
||||
connection_state = DISCONNECTED;
|
||||
target_keyboard_found = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (packet_type == L2CAP_DATA_PACKET) {
|
||||
// Classic HID input data
|
||||
if (channel == hid_interrupt_cid) {
|
||||
if (DEBUG_MODE) {
|
||||
Serial.printf("Classic HID Input Data (%d bytes): ", size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Serial.printf("%02X ", packet[i]);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
processClassicHIDReport(packet, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleClassicConnectionError(uint8_t status) {
|
||||
Serial.printf("Classic connection failed with status 0x%02x - ", status);
|
||||
switch (status) {
|
||||
case 0x04: Serial.println("Page timeout"); break;
|
||||
case 0x05: Serial.println("Authentication failure"); break;
|
||||
case 0x08: Serial.println("Connection timeout"); break;
|
||||
default: Serial.printf("Error code 0x%02x\n", status); break;
|
||||
}
|
||||
|
||||
Serial.println("Trying BLE fallback...");
|
||||
fallbackToBLE();
|
||||
}
|
||||
|
||||
void processClassicHIDReport(uint8_t *report, uint16_t length) {
|
||||
if (length < 10) {
|
||||
Serial.printf("Invalid Classic HID report length: %d\n", length);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t modifiers = report[2];
|
||||
uint8_t *keys = &report[4];
|
||||
|
||||
// Forward to USB HID
|
||||
forwardClassicToUSB(modifiers, keys);
|
||||
blinkOnActivity();
|
||||
}
|
||||
|
||||
// Shared key mapping function
|
||||
uint8_t hidToUsbKey(uint8_t hidKey) {
|
||||
switch (hidKey) {
|
||||
// Letters
|
||||
case 0x04: return 'a'; case 0x05: return 'b'; case 0x06: return 'c'; case 0x07: return 'd';
|
||||
case 0x08: return 'e'; case 0x09: return 'f'; case 0x0A: return 'g'; case 0x0B: return 'h';
|
||||
case 0x0C: return 'i'; case 0x0D: return 'j'; case 0x0E: return 'k'; case 0x0F: return 'l';
|
||||
case 0x10: return 'm'; case 0x11: return 'n'; case 0x12: return 'o'; case 0x13: return 'p';
|
||||
case 0x14: return 'q'; case 0x15: return 'r'; case 0x16: return 's'; case 0x17: return 't';
|
||||
case 0x18: return 'u'; case 0x19: return 'v'; case 0x1A: return 'w'; case 0x1B: return 'x';
|
||||
case 0x1C: return 'y'; case 0x1D: return 'z';
|
||||
|
||||
// Numbers
|
||||
case 0x1E: return '1'; case 0x1F: return '2'; case 0x20: return '3'; case 0x21: return '4';
|
||||
case 0x22: return '5'; case 0x23: return '6'; case 0x24: return '7'; case 0x25: return '8';
|
||||
case 0x26: return '9'; case 0x27: return '0';
|
||||
|
||||
// Special keys
|
||||
case 0x28: return KEY_RETURN; case 0x29: return KEY_ESC;
|
||||
case 0x2A: return KEY_BACKSPACE; case 0x2B: return KEY_TAB;
|
||||
case 0x2C: return ' '; case 0x39: return KEY_CAPS_LOCK;
|
||||
|
||||
// Symbols
|
||||
case 0x2D: return '-'; case 0x2E: return '='; case 0x2F: return '['; case 0x30: return ']';
|
||||
case 0x31: return '\\'; case 0x33: return ';'; case 0x34: return '\''; case 0x35: return '`';
|
||||
case 0x36: return ','; case 0x37: return '.'; case 0x38: return '/';
|
||||
|
||||
// Function keys
|
||||
case 0x3A: return KEY_F1; case 0x3B: return KEY_F2; case 0x3C: return KEY_F3;
|
||||
case 0x3D: return KEY_F4; case 0x3E: return KEY_F5; case 0x3F: return KEY_F6;
|
||||
case 0x40: return KEY_F7; case 0x41: return KEY_F8; case 0x42: return KEY_F9;
|
||||
case 0x43: return KEY_F10; case 0x44: return KEY_F11; case 0x45: return KEY_F12;
|
||||
|
||||
// Arrow keys
|
||||
case 0x4F: return KEY_RIGHT_ARROW; case 0x50: return KEY_LEFT_ARROW;
|
||||
case 0x51: return KEY_DOWN_ARROW; case 0x52: return KEY_UP_ARROW;
|
||||
|
||||
// Navigation
|
||||
case 0x49: return KEY_INSERT; case 0x4A: return KEY_HOME;
|
||||
case 0x4B: return KEY_PAGE_UP; case 0x4C: return KEY_DELETE;
|
||||
case 0x4D: return KEY_END; case 0x4E: return KEY_PAGE_DOWN;
|
||||
|
||||
// Modifiers
|
||||
case 0xE0: return KEY_LEFT_CTRL; case 0xE1: return KEY_LEFT_SHIFT;
|
||||
case 0xE2: return KEY_LEFT_ALT; case 0xE3: return KEY_LEFT_GUI;
|
||||
case 0xE4: return KEY_RIGHT_CTRL; case 0xE5: return KEY_RIGHT_SHIFT;
|
||||
case 0xE6: return KEY_RIGHT_ALT; case 0xE7: return KEY_RIGHT_GUI;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardClassicToUSB(uint8_t modifiers, uint8_t *keys) {
|
||||
// Handle modifier changes
|
||||
uint8_t modifier_changes = modifiers ^ last_modifiers;
|
||||
|
||||
// Process each modifier bit
|
||||
if (modifier_changes & 0x01) (modifiers & 0x01) ? Keyboard.press(KEY_LEFT_CTRL) : Keyboard.release(KEY_LEFT_CTRL);
|
||||
if (modifier_changes & 0x02) (modifiers & 0x02) ? Keyboard.press(KEY_LEFT_SHIFT) : Keyboard.release(KEY_LEFT_SHIFT);
|
||||
if (modifier_changes & 0x04) (modifiers & 0x04) ? Keyboard.press(KEY_LEFT_ALT) : Keyboard.release(KEY_LEFT_ALT);
|
||||
if (modifier_changes & 0x08) (modifiers & 0x08) ? Keyboard.press(KEY_LEFT_GUI) : Keyboard.release(KEY_LEFT_GUI);
|
||||
if (modifier_changes & 0x10) (modifiers & 0x10) ? Keyboard.press(KEY_RIGHT_CTRL) : Keyboard.release(KEY_RIGHT_CTRL);
|
||||
if (modifier_changes & 0x20) (modifiers & 0x20) ? Keyboard.press(KEY_RIGHT_SHIFT) : Keyboard.release(KEY_RIGHT_SHIFT);
|
||||
if (modifier_changes & 0x40) (modifiers & 0x40) ? Keyboard.press(KEY_RIGHT_ALT) : Keyboard.release(KEY_RIGHT_ALT);
|
||||
if (modifier_changes & 0x80) (modifiers & 0x80) ? Keyboard.press(KEY_RIGHT_GUI) : Keyboard.release(KEY_RIGHT_GUI);
|
||||
|
||||
// Handle key releases
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (last_keys[i] != 0) {
|
||||
bool still_pressed = false;
|
||||
for (int j = 0; j < 6; j++) {
|
||||
if (keys[j] == last_keys[i]) {
|
||||
still_pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!still_pressed) {
|
||||
uint8_t usb_key = hidToUsbKey(last_keys[i]);
|
||||
if (usb_key != 0) Keyboard.release(usb_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle key presses
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (keys[i] != 0) {
|
||||
bool already_pressed = false;
|
||||
for (int j = 0; j < 6; j++) {
|
||||
if (last_keys[j] == keys[i]) {
|
||||
already_pressed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!already_pressed) {
|
||||
uint8_t usb_key = hidToUsbKey(keys[i]);
|
||||
if (usb_key != 0) Keyboard.press(usb_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save current state
|
||||
last_modifiers = modifiers;
|
||||
memcpy(last_keys, keys, 6);
|
||||
}
|
||||
|
||||
void forwardBLEKeyToUSB(int key, bool state) {
|
||||
if (key >= 256) return;
|
||||
|
||||
bool isModifier = (key >= 0xE0 && key <= 0xE7);
|
||||
|
||||
if (isModifier) {
|
||||
uint8_t usbKey = hidToUsbKey(key);
|
||||
if (state) Keyboard.press(usbKey);
|
||||
else Keyboard.release(usbKey);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle regular keys
|
||||
uint8_t usbKey = hidToUsbKey(key);
|
||||
if (usbKey != 0) {
|
||||
if (state && !keyPressed[key]) {
|
||||
keyPressed[key] = true;
|
||||
Keyboard.press(usbKey);
|
||||
} else if (!state && keyPressed[key]) {
|
||||
keyPressed[key] = false;
|
||||
Keyboard.release(usbKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void celebrationBlinks(int count) {
|
||||
pairingBlinks = count;
|
||||
pairingBlinkTimer = millis();
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
|
||||
void blinkOnActivity() {
|
||||
if (BLINK_MODE && pairingBlinks == 0 && (connection_state == CLASSIC_CONNECTED || connection_state == BLE_CONNECTED)) {
|
||||
digitalWrite(LED_BUILTIN, LOW); // Turn OFF briefly to show activity
|
||||
ledBlinking = true;
|
||||
ledOffTime = millis() + 50; // Stay off for 50ms
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
// Handle state timeouts
|
||||
handleStateTimeouts(currentTime);
|
||||
|
||||
// Handle LED patterns
|
||||
handleLEDPatterns(currentTime);
|
||||
|
||||
// Handle BOOTSEL button
|
||||
handleBootselButton();
|
||||
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void handleStateTimeouts(unsigned long currentTime) {
|
||||
switch (connection_state) {
|
||||
case SCANNING_CLASSIC:
|
||||
if (currentTime - stateStartTime > CLASSIC_SCAN_TIMEOUT) {
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
Serial.println("Classic scan timeout - BT Classic only mode, retrying...");
|
||||
stateStartTime = currentTime;
|
||||
scanForClassicDevices(); // Retry Classic scan
|
||||
} else {
|
||||
Serial.println("Classic scan timeout - falling back to BLE");
|
||||
fallbackToBLE();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SCANNING_BLE:
|
||||
if (currentTime - stateStartTime > BLE_SCAN_TIMEOUT) {
|
||||
if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
Serial.println("BLE scan timeout - BLE only mode, retrying...");
|
||||
stateStartTime = currentTime;
|
||||
initAndScanBLE(); // Retry BLE scan
|
||||
} else {
|
||||
Serial.println("BLE scan timeout - restarting from Classic");
|
||||
connection_state = BOTH_FAILED;
|
||||
stateStartTime = currentTime;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BOTH_FAILED:
|
||||
if (currentTime - stateStartTime > 5000) { // Wait 5 seconds before retry
|
||||
Serial.println("Retrying scan sequence...");
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
stateStartTime = currentTime;
|
||||
initAndScanClassic();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleLEDPatterns(unsigned long currentTime) {
|
||||
// Handle pairing celebration blinks first
|
||||
if (pairingBlinks > 0) {
|
||||
if (currentTime - pairingBlinkTimer >= 150) {
|
||||
pairingBlinks--;
|
||||
bool state = (pairingBlinks % 2 == 0);
|
||||
digitalWrite(LED_BUILTIN, state);
|
||||
pairingBlinkTimer = currentTime;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle activity blinks
|
||||
if (ledBlinking && currentTime >= ledOffTime) {
|
||||
digitalWrite(LED_BUILTIN, HIGH); // Turn back ON after brief off period
|
||||
ledBlinking = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle state-based LED patterns
|
||||
switch (connection_state) {
|
||||
case SCANNING_CLASSIC:
|
||||
case SCANNING_BLE:
|
||||
// Slow blink while scanning (1 second cycle)
|
||||
if (currentTime - ledTimer >= 1000) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASSIC_CONNECTING:
|
||||
// Fast blink while connecting - tells user to press a key
|
||||
if (currentTime - ledTimer >= 250) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLASSIC_CONNECTED:
|
||||
case BLE_CONNECTED:
|
||||
// Solid ON while connected (unless doing activity blinks)
|
||||
if (!ledBlinking) {
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
break;
|
||||
|
||||
case BOTH_FAILED:
|
||||
case DISCONNECTED:
|
||||
// Very slow pulse when failed/disconnected (2 second cycle)
|
||||
if (currentTime - ledTimer >= 2000) {
|
||||
ledState = !ledState;
|
||||
digitalWrite(LED_BUILTIN, ledState);
|
||||
ledTimer = currentTime;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleBootselButton() {
|
||||
if (BOOTSEL) {
|
||||
while (BOOTSEL) delay(1);
|
||||
|
||||
Serial.println("\nBOOTSEL pressed - restarting scan sequence");
|
||||
|
||||
// Clean up current connections
|
||||
if (connection_state == CLASSIC_CONNECTED) {
|
||||
if (hid_control_cid) l2cap_disconnect(hid_control_cid);
|
||||
if (hid_interrupt_cid) l2cap_disconnect(hid_interrupt_cid);
|
||||
} else if (connection_state == BLE_CONNECTED) {
|
||||
ble_hid.disconnect();
|
||||
ble_hid.clearPairing();
|
||||
}
|
||||
|
||||
// Reset all state
|
||||
Keyboard.releaseAll();
|
||||
Mouse.release(MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE);
|
||||
|
||||
for (int i = 0; i < 256; i++) keyPressed[i] = false;
|
||||
memset(last_keys, 0, 6);
|
||||
last_modifiers = 0;
|
||||
|
||||
target_keyboard_found = false;
|
||||
hid_control_cid = 0;
|
||||
hid_interrupt_cid = 0;
|
||||
pairingBlinks = 0;
|
||||
ledBlinking = false;
|
||||
|
||||
// Restart from appropriate scan mode
|
||||
if (strcmp(SCAN_MODE, "BT_Classic") == 0) {
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
Serial.println("Restarting BT Classic scan...");
|
||||
initAndScanClassic();
|
||||
} else if (strcmp(SCAN_MODE, "BLE") == 0) {
|
||||
connection_state = SCANNING_BLE;
|
||||
Serial.println("Restarting BLE scan...");
|
||||
initAndScanBLE();
|
||||
} else {
|
||||
connection_state = SCANNING_CLASSIC;
|
||||
Serial.println("Restarting unified scan...");
|
||||
initAndScanClassic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,31 +22,17 @@ clue.pixel.fill(0) # turn off NeoPixel
|
|||
clue_display = displayio.Group()
|
||||
|
||||
# draw the dry plant
|
||||
dry_plant_file = open("dry.bmp", "rb")
|
||||
dry_plant_bmp = displayio.OnDiskBitmap(dry_plant_file)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
dry_plant_bmp = displayio.OnDiskBitmap("dry.bmp")
|
||||
dry_plant_sprite = displayio.TileGrid(
|
||||
dry_plant_bmp,
|
||||
pixel_shader=getattr(dry_plant_bmp, "pixel_shader", displayio.ColorConverter()),
|
||||
dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader
|
||||
)
|
||||
# CircuitPython 7 compatible
|
||||
# dry_plant_sprite = displayio.TileGrid(
|
||||
# dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader
|
||||
# )
|
||||
clue_display.append(dry_plant_sprite)
|
||||
|
||||
# draw the happy plant on top (so it can be moved out of the way when needed)
|
||||
happy_plant_file = open("happy.bmp", "rb")
|
||||
happy_plant_bmp = displayio.OnDiskBitmap(happy_plant_file)
|
||||
# CircuitPython 6 & 7 compatible
|
||||
happy_plant_bmp = displayio.OnDiskBitmap("happy.bmp")
|
||||
happy_plant_sprite = displayio.TileGrid(
|
||||
happy_plant_bmp,
|
||||
pixel_shader=getattr(happy_plant_bmp, "pixel_shader", displayio.ColorConverter()),
|
||||
happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader
|
||||
)
|
||||
# CircuitPython 7 compatible
|
||||
# happy_plant_sprite = displayio.TileGrid(
|
||||
# happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader
|
||||
# )
|
||||
clue_display.append(happy_plant_sprite)
|
||||
|
||||
# Create text
|
||||
|
|
|
|||
|
|
@ -22,32 +22,14 @@ splash = displayio.Group()
|
|||
# bad egg
|
||||
BAD_EGG_FILENAME = "broken_egg.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
begg_file = open(BAD_EGG_FILENAME, "rb")
|
||||
begg_bmp = displayio.OnDiskBitmap(begg_file)
|
||||
begg_sprite = displayio.TileGrid(
|
||||
begg_bmp,
|
||||
pixel_shader=getattr(begg_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME)
|
||||
# begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader)
|
||||
begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME)
|
||||
begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader)
|
||||
|
||||
# good egg
|
||||
GOOD_EGG_FILENAME = "good_egg.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
gegg_file = open(GOOD_EGG_FILENAME, "rb")
|
||||
gegg_bmp = displayio.OnDiskBitmap(gegg_file)
|
||||
gegg_sprite = displayio.TileGrid(
|
||||
gegg_bmp,
|
||||
pixel_shader=getattr(gegg_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME)
|
||||
# gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader)
|
||||
gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME)
|
||||
gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader)
|
||||
|
||||
# draw the bad egg!
|
||||
splash.append(begg_sprite)
|
||||
|
|
|
|||
|
|
@ -21,39 +21,19 @@ clue_display = displayio.Group()
|
|||
|
||||
# draw the background image
|
||||
WASH_ON_FILENAME = "wash_on.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
wash_on_file = open(WASH_ON_FILENAME, "rb")
|
||||
wash_on_bmp = displayio.OnDiskBitmap(wash_on_file)
|
||||
wash_on_sprite = displayio.TileGrid(
|
||||
wash_on_bmp,
|
||||
pixel_shader=getattr(wash_on_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME)
|
||||
# wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader)
|
||||
wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME)
|
||||
wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader)
|
||||
|
||||
clue_display.append(wash_on_sprite)
|
||||
|
||||
# draw the foreground image
|
||||
WASH_OFF_FILENAME = "wash_off.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
wash_off_file = open(WASH_OFF_FILENAME, "rb")
|
||||
wash_off_bmp = displayio.OnDiskBitmap(wash_off_file)
|
||||
wash_off_sprite = displayio.TileGrid(
|
||||
wash_off_bmp,
|
||||
pixel_shader=getattr(wash_off_bmp, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME)
|
||||
# wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader)
|
||||
wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME)
|
||||
wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader)
|
||||
|
||||
clue_display.append(wash_off_sprite)
|
||||
|
||||
|
||||
# Create text
|
||||
# first create the group
|
||||
text_group = displayio.Group()
|
||||
|
|
|
|||
|
|
@ -62,18 +62,10 @@ from rps_crypto import bytesPad, strUnpad, generateOTPadKey, \
|
|||
from rps_display import RPSDisplay, blankScreen
|
||||
|
||||
|
||||
# Look for our name in secrets.py file if present
|
||||
ble_name = None
|
||||
try:
|
||||
from secrets import secrets
|
||||
ble_name = secrets.get("rps_name")
|
||||
if ble_name is None:
|
||||
ble_name = secrets.get("ble_name")
|
||||
if ble_name is None:
|
||||
print("INFO: No rps_name or ble_name entry found in secrets dict")
|
||||
except ImportError:
|
||||
pass # File is optional, reaching here is not a program error
|
||||
|
||||
# Look for our name in settings.toml file if present
|
||||
ble_name = os.getenv("rps_name", os.getenv("ble_name"))
|
||||
if ble_name is None:
|
||||
print("INFO: No rps_name or ble_name entry found in settings.toml")
|
||||
|
||||
debug = 1
|
||||
|
||||
|
|
@ -228,7 +220,7 @@ LAST_ACK_TIME_S = 1.5
|
|||
# Intro screen with audio
|
||||
rps_display.introductionScreen()
|
||||
|
||||
# Enable the Bluetooth LE radio and set player's name (from secrets.py)
|
||||
# Enable the Bluetooth LE radio and set player's name (from settings.toml)
|
||||
ble = BLERadio()
|
||||
if ble_name is not None:
|
||||
ble.name = ble_name
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ group.append(press_data)
|
|||
|
||||
display.root_group = group
|
||||
|
||||
# function to convert celcius to fahrenheit
|
||||
# function to convert celsius to fahrenheit
|
||||
def c_to_f(temp):
|
||||
temp_f = (temp * 9/5) + 32
|
||||
return temp_f
|
||||
|
|
@ -87,12 +87,12 @@ while True:
|
|||
print(servo_value)
|
||||
# if metric units...
|
||||
if metric_units:
|
||||
# update temp & pressure text in celcius and hPa
|
||||
# update temp & pressure text in celsius and hPa
|
||||
temp_data.text = "%0.1f ºC" % bmp280.temperature
|
||||
press_data.text = "%0.1f hPa" % bmp280.pressure
|
||||
# if imperial units...
|
||||
else:
|
||||
# convert celcius to fahrenheit
|
||||
# convert celsius to fahrenheit
|
||||
temp_fahrenheit = c_to_f(bmp280.temperature)
|
||||
# convert hPa to inHg
|
||||
pressure_inHg = hpa_to_inHg(bmp280.pressure)
|
||||
|
|
|
|||
|
|
@ -65,18 +65,10 @@ clue_display.brightness = 0.5
|
|||
clueGroup = displayio.Group()
|
||||
|
||||
# loading bitmap background
|
||||
# CircuitPython 6 & 7 compatible
|
||||
clue_bg = displayio.OnDiskBitmap(open(clue_bgBMP, "rb"))
|
||||
clue_tilegrid = displayio.TileGrid(
|
||||
clue_bg, pixel_shader=getattr(clue_bg, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
clue_bg = displayio.OnDiskBitmap(clue_bgBMP)
|
||||
clue_tilegrid = displayio.TileGrid(clue_bg, pixel_shader=clue_bg.pixel_shader)
|
||||
clueGroup.append(clue_tilegrid)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# clue_bg = displayio.OnDiskBitmap(clue_bgBMP)
|
||||
# clue_tilegrid = displayio.TileGrid(clue_bg, pixel_shader=clue_bg.pixel_shader)
|
||||
# clueGroup.append(clue_tilegrid)
|
||||
|
||||
# creating the ProgressBar object
|
||||
bar_group = displayio.Group()
|
||||
prog_bar = ProgressBar(1, 1, 239, 25, bar_color=0x652f8f)
|
||||
|
|
|
|||
|
|
@ -33,15 +33,8 @@ a.solicited_services.append(AppleMediaService)
|
|||
radio.start_advertising(a)
|
||||
|
||||
def wrap_in_tilegrid(filename:str):
|
||||
# CircuitPython 6 & 7 compatible
|
||||
odb = displayio.OnDiskBitmap(open(filename, "rb"))
|
||||
return displayio.TileGrid(
|
||||
odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# odb = displayio.OnDiskBitmap(filename)
|
||||
# return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
|
||||
odb = displayio.OnDiskBitmap(filename)
|
||||
return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
|
||||
|
||||
def make_background(width, height, color):
|
||||
color_bitmap = displayio.Bitmap(width, height, 1)
|
||||
|
|
|
|||
|
|
@ -93,15 +93,8 @@ advertisement.complete_name = "CIRCUITPY"
|
|||
advertisement.solicited_services.append(AppleNotificationCenterService)
|
||||
|
||||
def wrap_in_tilegrid(filename:str):
|
||||
# CircuitPython 6 & 7 compatible
|
||||
odb = displayio.OnDiskBitmap(open(filename, "rb"))
|
||||
return displayio.TileGrid(
|
||||
odb, pixel_shader=getattr(odb, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# odb = displayio.OnDiskBitmap(filename)
|
||||
# return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
|
||||
odb = displayio.OnDiskBitmap(filename)
|
||||
return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
|
||||
|
||||
display = tft_gizmo.TFT_Gizmo()
|
||||
group = displayio.Group()
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@
|
|||
CHEEKMATE: secret message receiver using WiFi, Adafruit IO and a haptic
|
||||
buzzer. Periodically polls an Adafruit IO dashboard, converting new messages
|
||||
to Morse code.
|
||||
|
||||
secrets.py file must be present and contain WiFi & Adafruit IO credentials.
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import gc
|
||||
import time
|
||||
import ssl
|
||||
|
|
@ -23,11 +22,20 @@ import supervisor
|
|||
import wifi
|
||||
from adafruit_io.adafruit_io import IO_HTTP
|
||||
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
# CONFIGURABLE GLOBALS -----------------------------------------------------
|
||||
|
||||
|
|
@ -154,10 +162,10 @@ i2c.unlock()
|
|||
# WIFI CONNECT -------------------------------------------------------------
|
||||
|
||||
try:
|
||||
print("Connecting to {}...".format(secrets["ssid"]), end="")
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
print(f"Connecting to {ssid}...")
|
||||
wifi.radio.connect(ssid, password)
|
||||
print("OK")
|
||||
print("IP:", wifi.radio.ipv4_address)
|
||||
print(f"IP: {wifi.radio.ipv4_address}")
|
||||
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
requests = adafruit_requests.Session(pool, ssl.create_default_context())
|
||||
|
|
@ -169,8 +177,6 @@ except Exception as error: # pylint: disable=broad-except
|
|||
|
||||
# ADAFRUIT IO INITIALIZATION -----------------------------------------------
|
||||
|
||||
aio_username = secrets["aio_username"]
|
||||
aio_key = secrets["aio_key"]
|
||||
io = IO_HTTP(aio_username, aio_key, requests)
|
||||
|
||||
# SUCCESSFUL STARTUP, PROCEED INTO MAIN LOOP -------------------------------
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ import time
|
|||
|
||||
import adafruit_bitmap_font.bitmap_font
|
||||
import adafruit_display_text.label
|
||||
from adafruit_progressbar import ProgressBar
|
||||
from adafruit_progressbar.horizontalprogressbar import HorizontalProgressBar
|
||||
import sdcardio
|
||||
import analogjoy
|
||||
import audioio
|
||||
|
|
@ -75,9 +75,12 @@ class PlaybackDisplay:
|
|||
def __init__(self):
|
||||
self.group = displayio.Group()
|
||||
self.glyph_width, self.glyph_height = font.get_bounding_box()[:2]
|
||||
self.pbar = ProgressBar(0, 0, board.DISPLAY.width,
|
||||
self.glyph_height*2, bar_color=0x0000ff,
|
||||
outline_color=0x333333, stroke=1)
|
||||
self.pbar = HorizontalProgressBar((0, 0),
|
||||
(board.DISPLAY.width, self.glyph_height*2),
|
||||
min_value = 0.0, max_value = 1.0,
|
||||
bar_color=0x0000ff,
|
||||
outline_color=0x333333,
|
||||
fill_color=0x000000)
|
||||
self.iconbar = icons.IconBar()
|
||||
self.iconbar.group.y = 1000
|
||||
for i in range(5, 8):
|
||||
|
|
@ -115,11 +118,11 @@ class PlaybackDisplay:
|
|||
@property
|
||||
def progress(self):
|
||||
"""The fraction of progress through the current track"""
|
||||
return self.pbar.progress
|
||||
return self.pbar.value
|
||||
|
||||
@progress.setter
|
||||
def progress(self, frac):
|
||||
self.pbar.progress = frac
|
||||
self.pbar.value = frac
|
||||
|
||||
def set_bitmap(self, candidates):
|
||||
"""Find and use a background from among candidates, or else the fallback bitmap"""
|
||||
|
|
@ -127,32 +130,16 @@ class PlaybackDisplay:
|
|||
if i == self._bitmap_filename:
|
||||
return # Already loaded
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
try:
|
||||
bitmap_file = open(i, 'rb')
|
||||
bitmap = displayio.OnDiskBitmap(i)
|
||||
except OSError:
|
||||
continue
|
||||
bitmap = displayio.OnDiskBitmap(bitmap_file)
|
||||
self._bitmap_filename = i
|
||||
# Create a TileGrid to hold the bitmap
|
||||
self.tile_grid = displayio.TileGrid(
|
||||
bitmap,
|
||||
pixel_shader=getattr(
|
||||
bitmap, "pixel_shader", displayio.ColorConverter()
|
||||
),
|
||||
bitmap, pixel_shader=bitmap.pixel_shader
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# try:
|
||||
# bitmap = displayio.OnDiskBitmap(i)
|
||||
# except OSError:
|
||||
# continue
|
||||
# self._bitmap_filename = i
|
||||
# # Create a TileGrid to hold the bitmap
|
||||
# self.tile_grid = displayio.TileGrid(
|
||||
# bitmap, pixel_shader=bitmap.pixel_shader
|
||||
# )
|
||||
|
||||
# Add the TileGrid to the Group
|
||||
if len(self.group) == 0:
|
||||
self.group.append(self.tile_grid)
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 27 KiB |
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import time
|
||||
import board
|
||||
import adafruit_lsm6ds.lsm6ds33
|
||||
from adafruit_ht16k33 import matrix
|
||||
import matrixsand
|
||||
|
||||
|
|
@ -14,8 +13,13 @@ DELAY = 0.05 # overall update rate
|
|||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
|
||||
|
||||
# the accelo
|
||||
accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c)
|
||||
# check for LSM6DS33 or LSM6DS3TR-C (Adafruit Feather Sense)
|
||||
try:
|
||||
from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 as LSM6DS # pylint: disable=unused-import
|
||||
accelo = LSM6DS(i2c)
|
||||
except RuntimeError:
|
||||
from adafruit_lsm6ds.lsm6ds3 import LSM6DS3 as LSM6DS # pylint: disable=unused-import
|
||||
accelo = LSM6DS(i2c)
|
||||
|
||||
# the matrices
|
||||
m1 = matrix.Matrix8x8(i2c, 0x70)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
import time
|
||||
import board
|
||||
import adafruit_lsm6ds.lsm6ds33
|
||||
from adafruit_ht16k33 import matrix
|
||||
import matrixsand
|
||||
|
||||
|
|
@ -14,8 +13,13 @@ DELAY = 0.00 # add some delay if you want
|
|||
i2c = board.I2C() # uses board.SCL and board.SDA
|
||||
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
|
||||
|
||||
# the accelo
|
||||
accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c)
|
||||
# check for LSM6DS33 or LSM6DS3TR-C (Adafruit Feather Sense)
|
||||
try:
|
||||
from adafruit_lsm6ds.lsm6ds33 import LSM6DS33 as LSM6DS # pylint: disable=unused-import
|
||||
accelo = LSM6DS(i2c)
|
||||
except RuntimeError:
|
||||
from adafruit_lsm6ds.lsm6ds3 import LSM6DS3 as LSM6DS # pylint: disable=unused-import
|
||||
accelo = LSM6DS(i2c)
|
||||
|
||||
# the matrix
|
||||
matrix = matrix.Matrix8x8(i2c, 0x70)
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
CircuitPython_Logger/ble_handler.py 16: Bad option value 'missing-super-argument' (bad-option-value)
|
||||
CircuitPython_Logger/uart_handler.py 16: Bad option value 'missing-super-argument' (bad-option-value)
|
||||
CircuitPython_Logger/file_handler.py 15: Bad option value 'missing-super-argument' (bad-option-value)
|
||||
CircuitPython_Logger/aio_handler.py 15: Bad option value 'missing-super-argument' (bad-option-value)
|
||||
|
|
@ -17,30 +17,21 @@ All text above must be included in any redistribution.
|
|||
"""
|
||||
|
||||
from adafruit_portalbase import PortalBase
|
||||
from adafruit_logging import Handler, NOTSET
|
||||
|
||||
# Example:
|
||||
#
|
||||
# from aio_handler import AIOHandler
|
||||
# import adafruit_logging as logging
|
||||
# l = logging.getLogger('aio')
|
||||
# # Pass in the device object based on portal_base
|
||||
# # (Funhouse, PyPortal, MagTag, etc) as the 2nd parameter
|
||||
# l.addHandler(AIOHandler('test', portal_device))
|
||||
# l.level = logging.ERROR
|
||||
# l.error("test")
|
||||
|
||||
from adafruit_logging import Handler
|
||||
|
||||
class AIOHandler(Handler):
|
||||
|
||||
def __init__(self, name, portal_device):
|
||||
def __init__(self, name, portal_device, level: int = NOTSET):
|
||||
"""Create an instance."""
|
||||
self._log_feed_name=f"{name}-logging"
|
||||
super().__init__(level)
|
||||
self._log_feed_name = f"{name}-logging"
|
||||
if not issubclass(type(portal_device), PortalBase):
|
||||
raise TypeError("portal_device must be a PortalBase or subclass of PortalBase")
|
||||
raise TypeError(
|
||||
"portal_device must be a PortalBase or subclass of PortalBase"
|
||||
)
|
||||
self._portal_device = portal_device
|
||||
|
||||
|
||||
def emit(self, record):
|
||||
"""Generate the message and write it to the AIO Feed.
|
||||
|
||||
|
|
@ -8,27 +8,26 @@ from adafruit_pyportal import PyPortal
|
|||
from aio_handler import AIOHandler
|
||||
import adafruit_logging as logging
|
||||
|
||||
device=PyPortal()
|
||||
device = PyPortal()
|
||||
|
||||
l = logging.getLogger('aio')
|
||||
l.addHandler(AIOHandler('test', device))
|
||||
l = logging.getLogger("aio")
|
||||
l.addHandler(AIOHandler("test", device))
|
||||
|
||||
def go():
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print('debug')
|
||||
l.debug("debug message: %d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print('info')
|
||||
l.info("info message: %d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print('warning')
|
||||
l.warning("warning message: %d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print('error')
|
||||
l.error("error message: %d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print('critical')
|
||||
l.critical("critical message: %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print("debug")
|
||||
l.debug("debug message: %d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print("info")
|
||||
l.info("info message: %d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print("warning")
|
||||
l.warning("warning message: %d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print("error")
|
||||
l.error("error message: %d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print("critical")
|
||||
l.critical("critical message: %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
|
|
|
|||
|
|
@ -17,34 +17,39 @@ All text above must be included in any redistribution.
|
|||
"""
|
||||
|
||||
|
||||
from adafruit_logging import Handler
|
||||
from adafruit_ble.uart import UARTServer
|
||||
from adafruit_logging import Handler, NOTSET
|
||||
|
||||
from adafruit_ble import BLERadio
|
||||
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
|
||||
from adafruit_ble.services.nordic import UARTService
|
||||
|
||||
|
||||
class BLEHandler(Handler):
|
||||
"""Send logging output to the BLE uart port."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, level: int = NOTSET):
|
||||
"""Create an instance.
|
||||
|
||||
:param uart: the busio.UART instance to which to write messages
|
||||
"""
|
||||
super().__init__(level)
|
||||
self._advertising_now = False
|
||||
self._uart = UARTServer()
|
||||
self._uart.start_advertising()
|
||||
ble = BLERadio()
|
||||
self._uart = UARTService()
|
||||
self._advertisement = ProvideServicesAdvertisement(self._uart)
|
||||
ble.start_advertising(self._advertisement)
|
||||
|
||||
def format(self, record):
|
||||
"""Generate a string to log.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
return super().format(record) + '\r\n'
|
||||
return super().format(record) + "\r\n"
|
||||
|
||||
def emit(self, record):
|
||||
"""Generate the message and write it to the UART.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
while not self._uart.connected:
|
||||
pass
|
||||
data = bytes(self.format(record), 'utf-8')
|
||||
data = bytes(self.format(record), "utf-8")
|
||||
self._uart.write(data)
|
||||
|
|
@ -7,26 +7,25 @@ import random
|
|||
from ble_handler import BLEHandler
|
||||
import adafruit_logging as logging
|
||||
|
||||
l = logging.getLogger('ble')
|
||||
l = logging.getLogger("ble")
|
||||
|
||||
l.addHandler(BLEHandler())
|
||||
|
||||
def go():
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print('debug')
|
||||
l.debug("%d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print('info')
|
||||
l.info("%d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print('warning')
|
||||
l.warning("%d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print('error')
|
||||
l.error("%d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print('critical')
|
||||
l.critical(" %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print("debug")
|
||||
l.debug("%d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print("info")
|
||||
l.info("%d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print("warning")
|
||||
l.warning("%d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print("error")
|
||||
l.error("%d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print("critical")
|
||||
l.critical(" %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
|
|
|
|||
|
|
@ -21,25 +21,24 @@ sdcard = adafruit_sdcard.SDCard(spi, cs)
|
|||
vfs = storage.VfsFat(sdcard)
|
||||
storage.mount(vfs, "/sd")
|
||||
|
||||
l = logging.getLogger('file')
|
||||
l.addHandler(logging.FileHandler('/sd/test.txt'))
|
||||
l = logging.getLogger("file")
|
||||
l.addHandler(logging.FileHandler("/sd/test.txt"))
|
||||
|
||||
def go():
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print('debug')
|
||||
l.debug("debug message: %d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print('info')
|
||||
l.info("info message: %d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print('warning')
|
||||
l.warning("warning message: %d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print('error')
|
||||
l.error("error message: %d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print('critical')
|
||||
l.critical("critical message: %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
while True:
|
||||
t = random.randint(1, 5)
|
||||
if t == 1:
|
||||
print("debug")
|
||||
l.debug("debug message: %d", random.randint(0, 1000))
|
||||
elif t == 2:
|
||||
print("info")
|
||||
l.info("info message: %d", random.randint(0, 1000))
|
||||
elif t == 3:
|
||||
print("warning")
|
||||
l.warning("warning message: %d", random.randint(0, 1000))
|
||||
elif t == 4:
|
||||
print("error")
|
||||
l.error("error message: %d", random.randint(0, 1000))
|
||||
elif t == 5:
|
||||
print("critical")
|
||||
l.critical("critical message: %d", random.randint(0, 1000))
|
||||
time.sleep(5.0 + (random.random() * 5.0))
|
||||
|
|
|
|||
|
|
@ -1,57 +1,13 @@
|
|||
# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
import board
|
||||
import busio
|
||||
from uart_handler import UartHandler
|
||||
import adafruit_logging as logging
|
||||
|
||||
"""
|
||||
UART based message handler for CircuitPython logging.
|
||||
|
||||
Adafruit invests time and resources providing this open source code.
|
||||
Please support Adafruit and open source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Dave Astels for Adafruit Industries
|
||||
Copyright (c) 2018 Adafruit Industries
|
||||
Licensed under the MIT license.
|
||||
|
||||
All text above must be included in any redistribution.
|
||||
"""
|
||||
|
||||
|
||||
# Example:
|
||||
#
|
||||
# import board
|
||||
# import busio
|
||||
# from uart_handler import UartHandler
|
||||
# import adafruit_logging as logging
|
||||
#
|
||||
# uart = busio.UART(board.TX, board.RX, baudrate=115200)
|
||||
# logger = logging.getLogger('uart')
|
||||
# logger.addHandler(UartHandler(uart))
|
||||
# logger.level = logging.INFO
|
||||
# logger.info('testing')
|
||||
|
||||
from adafruit_logging import Handler
|
||||
|
||||
class UartHandler(Handler):
|
||||
"""Send logging output to a serial port."""
|
||||
|
||||
def __init__(self, uart):
|
||||
"""Create an instance.
|
||||
|
||||
:param uart: the busio.UART instance to which to write messages
|
||||
"""
|
||||
self._uart = uart
|
||||
|
||||
def format(self, record):
|
||||
"""Generate a string to log.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
return super().format(record) + '\r\n'
|
||||
|
||||
def emit(self, record):
|
||||
"""Generate the message and write it to the UART.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
self._uart.write(bytes(self.format(record), 'utf-8'))
|
||||
uart = busio.UART(board.TX, board.RX, baudrate=115200)
|
||||
logger = logging.getLogger("test")
|
||||
logger.addHandler(UartHandler(uart))
|
||||
logger.setLevel(logging.INFO)
|
||||
logger.info("testing")
|
||||
|
|
|
|||
46
CircuitPython_Logger/uart_handler/uart_handler.py
Normal file
46
CircuitPython_Logger/uart_handler/uart_handler.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# SPDX-FileCopyrightText: 2018 Dave Astels for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
"""
|
||||
UART based message handler for CircuitPython logging.
|
||||
|
||||
Adafruit invests time and resources providing this open source code.
|
||||
Please support Adafruit and open source hardware by purchasing
|
||||
products from Adafruit!
|
||||
|
||||
Written by Dave Astels for Adafruit Industries
|
||||
Copyright (c) 2018 Adafruit Industries
|
||||
Licensed under the MIT license.
|
||||
|
||||
All text above must be included in any redistribution.
|
||||
"""
|
||||
|
||||
|
||||
from adafruit_logging import Handler, NOTSET
|
||||
|
||||
|
||||
class UartHandler(Handler):
|
||||
"""Send logging output to a serial port."""
|
||||
|
||||
def __init__(self, uart, level: int = NOTSET):
|
||||
"""Create an instance.
|
||||
|
||||
:param uart: the busio.UART instance to which to write messages
|
||||
"""
|
||||
super().__init__(level)
|
||||
self._uart = uart
|
||||
|
||||
def format(self, record):
|
||||
"""Generate a string to log.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
return super().format(record) + "\r\n"
|
||||
|
||||
def emit(self, record):
|
||||
"""Generate the message and write it to the UART.
|
||||
|
||||
:param record: The record (message object) to be logged
|
||||
"""
|
||||
self._uart.write(bytes(self.format(record), "utf-8"))
|
||||
|
|
@ -25,14 +25,8 @@ display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)
|
|||
|
||||
filename = "emoji.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
bitmap_file = open(filename, 'rb')
|
||||
bitmap = displayio.OnDiskBitmap(bitmap_file)
|
||||
pixel_shader = getattr(bitmap, 'pixel_shader', displayio.ColorConverter())
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# bitmap = displayio.OnDiskBitmap(filename)
|
||||
# pixel_shader = bitmap.pixel_shader
|
||||
bitmap = displayio.OnDiskBitmap(filename)
|
||||
pixel_shader = bitmap.pixel_shader
|
||||
|
||||
# Each wheel can be in one of three states:
|
||||
STOPPED, RUNNING, BRAKING = range(3)
|
||||
|
|
|
|||
|
|
@ -46,24 +46,14 @@ DISPLAY = framebufferio.FramebufferDisplay(MATRIX, auto_refresh=False,
|
|||
# Load BMP image, create Group and TileGrid to hold it
|
||||
FILENAME = "wales.bmp"
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
BITMAP = displayio.OnDiskBitmap(open(FILENAME, "rb"))
|
||||
BITMAP = displayio.OnDiskBitmap(FILENAME)
|
||||
TILEGRID = displayio.TileGrid(
|
||||
BITMAP,
|
||||
pixel_shader=getattr(BITMAP, 'pixel_shader', displayio.ColorConverter()),
|
||||
pixel_shader=BITMAP.pixel_shader,
|
||||
tile_width=BITMAP.width,
|
||||
tile_height=BITMAP.height
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# BITMAP = displayio.OnDiskBitmap(FILENAME)
|
||||
# TILEGRID = displayio.TileGrid(
|
||||
# BITMAP,
|
||||
# pixel_shader=BITMAP.pixel_shader,
|
||||
# tile_width=BITMAP.width,
|
||||
# tile_height=BITMAP.height
|
||||
# )
|
||||
|
||||
GROUP = displayio.Group()
|
||||
GROUP.append(TILEGRID)
|
||||
DISPLAY.root_group = GROUP
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import random
|
||||
import audioio
|
||||
|
|
@ -24,21 +25,25 @@ wave_file = open("sound/Rain.wav", "rb")
|
|||
wave = audiocore.WaveFile(wave_file)
|
||||
audio = audioio.AudioOut(board.A0)
|
||||
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
# Use cityname, country code where countrycode is ISO3166 format.
|
||||
# E.g. "New York, US" or "London, GB"
|
||||
LOCATION = secrets['timezone']
|
||||
LOCATION = getenv('timezone')
|
||||
|
||||
# Set up where we'll be fetching data from
|
||||
DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+secrets['timezone']
|
||||
DATA_SOURCE += "&appid="+secrets['openweather_token']
|
||||
DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION
|
||||
DATA_SOURCE += "&appid="+getenv('openweather_token')
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.ESP_CS)
|
||||
|
|
@ -47,8 +52,8 @@ esp32_reset = DigitalInOut(board.ESP_RESET)
|
|||
|
||||
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
|
||||
status_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
|
||||
pixels = neopixel.NeoPixel(board.D2, 150, brightness=1.0, auto_write=False)
|
||||
pixels.fill(0x050505)
|
||||
pixels.show()
|
||||
|
|
@ -132,22 +137,17 @@ while True:
|
|||
print(weather_type) # See https://openweathermap.org/weather-conditions
|
||||
# default to no rain or thunder
|
||||
raining = snowing = thundering = has_sound = False
|
||||
wave_filename = None
|
||||
if weather_type == 'Sunny':
|
||||
palette = sunny_palette
|
||||
wave_file = open("sound/Clear.wav", "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
has_sound = True
|
||||
wave_filename = "sound/Clear.wav"
|
||||
if weather_type == 'Clouds':
|
||||
palette = cloudy_palette
|
||||
wave_file = open("sound/Clouds.wav", "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
has_sound = True
|
||||
wave_filename = "sound/Clouds.wav"
|
||||
if weather_type == 'Rain':
|
||||
palette = cloudy_palette
|
||||
wave_file = open("sound/Rain.wav", "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
wave_filename = "sound/Rain.wav"
|
||||
raining = True
|
||||
has_sound = True
|
||||
if weather_type == 'Thunderstorm':
|
||||
palette = thunder_palette
|
||||
raining = thundering = True
|
||||
|
|
@ -156,9 +156,11 @@ while True:
|
|||
next_bolt_time = time.monotonic() + random.randint(1, 5)
|
||||
if weather_type == 'Snow':
|
||||
palette = cloudy_palette
|
||||
wave_file = open("sound/Snow.wav", "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
wave_filename = "sound/Snow.wav"
|
||||
snowing = True
|
||||
if wave_filename:
|
||||
wave_file = open(wave_filename, "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
has_sound = True
|
||||
weather_refresh = time.monotonic()
|
||||
except RuntimeError as e:
|
||||
|
|
@ -204,11 +206,13 @@ while True:
|
|||
# pick next thunderbolt time now
|
||||
Thunder = random.randint(0, 2)
|
||||
if Thunder == 0:
|
||||
wave_file = open("sound/Thunderstorm0.wav", "rb")
|
||||
wave_filename = "sound/Thunderstorm0.wav"
|
||||
elif Thunder == 1:
|
||||
wave_file = open("sound/Thunderstorm1.wav", "rb")
|
||||
wave_filename = "sound/Thunderstorm1.wav"
|
||||
elif Thunder == 2:
|
||||
wave_file = open("sound/Thunderstorm2.wav", "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
audio.play(wave)
|
||||
wave_filename = "sound/Thunderstorm2.wav"
|
||||
if wave_filename:
|
||||
wave_file = open(wave_filename, "rb")
|
||||
wave = audiocore.WaveFile(wave_file)
|
||||
audio.play(wave)
|
||||
next_bolt_time = time.monotonic() + random.randint(5, 15) # between 5 and 15 s
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# This file is where you keep secret settings, passwords, and tokens!
|
||||
# If you put them in the code you risk committing that info or sharing it
|
||||
|
||||
secrets = {
|
||||
'ssid' : 'my_ssid',
|
||||
'password' : 'my_pass',
|
||||
'timezone' : "America/New_York", # http://worldtimeapi.org/timezones
|
||||
'openweather_token' : 'putYourOpenWeatherTokenHere',
|
||||
}
|
||||
12
CircuitPython_WeatherCloud/settings.toml
Normal file
12
CircuitPython_WeatherCloud/settings.toml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# This file is where you keep private settings, passwords, and tokens!
|
||||
# If you put them in the code you risk committing that info or sharing it
|
||||
|
||||
|
||||
CIRCUITPY_WIFI_SSID="your-wifi-ssid"
|
||||
CIRCUITPY_WIFI_PASSWORD="your-wifi-password"
|
||||
timezone="America/New_York" # http://worldtimeapi.org/timezones
|
||||
openweather_token="putYourOpenWeatherTokenHere"
|
||||
|
|
@ -4,12 +4,12 @@
|
|||
|
||||
"""
|
||||
This demo is designed for the Kaluga development kit version 1.3 with the
|
||||
ILI9341 display. Your secrets.py must be populated with your wifi credentials
|
||||
ILI9341 display. Your settings.toml must be populated with your wifi credentials
|
||||
and your Adafruit IO credentials.
|
||||
"""
|
||||
|
||||
from os import getenv
|
||||
import ssl
|
||||
from secrets import secrets
|
||||
from ulab import numpy as np
|
||||
from terminalio import FONT
|
||||
import board
|
||||
|
|
@ -25,6 +25,21 @@ from adafruit_ili9341 import ILI9341
|
|||
from adafruit_io.adafruit_io import IO_MQTT
|
||||
import adafruit_minimqtt.adafruit_minimqtt as MQTT
|
||||
|
||||
# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
|
||||
# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
aio_username = getenv("ADAFRUIT_AIO_USERNAME")
|
||||
aio_key = getenv("ADAFRUIT_AIO_KEY")
|
||||
|
||||
if None in [ssid, password, aio_username, aio_key]:
|
||||
raise RuntimeError(
|
||||
"WiFi and Adafruit IO settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' at a minimum."
|
||||
)
|
||||
|
||||
# To change the name of the feed on adafruit_io, just modify this string:
|
||||
feed_name = "qrstring"
|
||||
|
||||
|
|
@ -53,14 +68,14 @@ cam.flip_y = False
|
|||
cam.colorspace = adafruit_ov2640.OV2640_COLOR_YUV
|
||||
|
||||
print("Connecting to WIFI")
|
||||
wifi.radio.connect(secrets["ssid"], secrets["password"])
|
||||
wifi.radio.connect(ssid, password)
|
||||
pool = socketpool.SocketPool(wifi.radio)
|
||||
|
||||
print("Connecting to Adafruit IO")
|
||||
mqtt_client = MQTT.MQTT(
|
||||
broker="io.adafruit.com",
|
||||
username=secrets["aio_username"],
|
||||
password=secrets["aio_key"],
|
||||
username=aio_username,
|
||||
password=aio_key,
|
||||
socket_pool=pool,
|
||||
ssl_context=ssl.create_default_context(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -4,8 +4,7 @@
|
|||
|
||||
"""
|
||||
This demo is designed for the Kaluga development kit version 1.3 with the
|
||||
ILI9341 display. Your secrets.py must be populated with your wifi credentials
|
||||
and your Adafruit IO credentials.
|
||||
ILI9341 display.
|
||||
"""
|
||||
|
||||
from ulab import numpy as np
|
||||
|
|
|
|||
|
|
@ -21,17 +21,8 @@ while True:
|
|||
for filename in bmpfiles:
|
||||
print("showing", filename)
|
||||
|
||||
# CircuitPython 6 & 7 compatible
|
||||
bitmap_file = open(filename, "rb")
|
||||
bitmap = displayio.OnDiskBitmap(bitmap_file)
|
||||
tile_grid = displayio.TileGrid(
|
||||
bitmap,
|
||||
pixel_shader=getattr(bitmap, 'pixel_shader', displayio.ColorConverter())
|
||||
)
|
||||
|
||||
# # CircuitPython 7+ compatible
|
||||
# bitmap = displayio.OnDiskBitmap(filename)
|
||||
# tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
|
||||
bitmap = displayio.OnDiskBitmap(filename)
|
||||
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
|
||||
|
||||
group = displayio.Group()
|
||||
group.append(tile_grid)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
from os import getenv
|
||||
import time
|
||||
import board
|
||||
from digitalio import DigitalInOut
|
||||
|
|
@ -14,12 +15,17 @@ import displayio
|
|||
|
||||
minitft = minitft_featherwing.MiniTFTFeatherWing()
|
||||
|
||||
# Get wifi details and more from a secrets.py file
|
||||
try:
|
||||
from secrets import secrets
|
||||
except ImportError:
|
||||
print("WiFi secrets are kept in secrets.py, please add them there!")
|
||||
raise
|
||||
# Get WiFi details, ensure these are setup in settings.toml
|
||||
ssid = getenv("CIRCUITPY_WIFI_SSID")
|
||||
password = getenv("CIRCUITPY_WIFI_PASSWORD")
|
||||
|
||||
if None in [ssid, password]:
|
||||
raise RuntimeError(
|
||||
"WiFi settings are kept in settings.toml, "
|
||||
"please add them there. The settings file must contain "
|
||||
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
|
||||
"at a minimum."
|
||||
)
|
||||
|
||||
# If you are using a board with pre-defined ESP32 Pins:
|
||||
esp32_cs = DigitalInOut(board.D13)
|
||||
|
|
@ -27,11 +33,11 @@ esp32_ready = DigitalInOut(board.D11)
|
|||
esp32_reset = DigitalInOut(board.D12)
|
||||
spi = board.SPI()
|
||||
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
|
||||
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets)
|
||||
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password)
|
||||
|
||||
# Symbol "INX" for S&P500, "DJIA" for Dow
|
||||
DATA_SOURCE = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&apikey="
|
||||
DATA_SOURCE += secrets['alphavantage_key']
|
||||
DATA_SOURCE += getenv('alphavantage_key')
|
||||
symbols = ["DJIA", "INX", "AAPL", "TSLA", "MSFT"]
|
||||
|
||||
# Set text, font, and color
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
|
||||
secrets = {
|
||||
'ssid' : 'myssid',
|
||||
'password' : 'mypassword',
|
||||
'timezone' : "America/New_York", # http://worldtimeapi.org/timezones
|
||||
'alphavantage_key' : 'GRABAFREEKEYONLINE'
|
||||
}
|
||||
11
CircuitStonks/settings.toml
Normal file
11
CircuitStonks/settings.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# SPDX-FileCopyrightText: 2020 Limor Fried for Adafruit Industries
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# This file is where you keep private settings, passwords, and tokens!
|
||||
# If you put them in the code you risk committing that info or sharing it
|
||||
|
||||
CIRCUITPY_WIFI_SSID="your-wifi-ssid"
|
||||
CIRCUITPY_WIFI_PASSWORD="your-wifi-password"
|
||||
timezone="America/New_York" # http://worldtimeapi.org/timezones
|
||||
alphavantage_key="GRABAFREEKEYONLINE"
|
||||
0
Computer_Space/.feather_m4_express.test.only
Normal file
0
Computer_Space/.feather_m4_express.test.only
Normal file
1120
Computer_Space/Computer_Space.ino
Normal file
1120
Computer_Space/Computer_Space.ino
Normal file
File diff suppressed because it is too large
Load diff
1233
DMX_NeoPixels/examples/DMX_Master/Conceptinetics.cpp
Normal file
1233
DMX_NeoPixels/examples/DMX_Master/Conceptinetics.cpp
Normal file
File diff suppressed because it is too large
Load diff
383
DMX_NeoPixels/examples/DMX_Master/Conceptinetics.h
Normal file
383
DMX_NeoPixels/examples/DMX_Master/Conceptinetics.h
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Conceptinetics.h - DMX library for Arduino
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This code has been tested using the following hardware:
|
||||
|
||||
- Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD
|
||||
|
||||
- CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONCEPTINETICS_H_
|
||||
#define CONCEPTINETICS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
#include "Rdm_Defines.h"
|
||||
|
||||
#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots
|
||||
#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot
|
||||
|
||||
#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame
|
||||
|
||||
#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes
|
||||
|
||||
#define DMX_START_CODE 0x0 // Start code for a DMX frame
|
||||
#define RDM_START_CODE 0xcc // Start code for a RDM frame
|
||||
|
||||
// Uncomment to enable Inter slot delay ) (avg < 76uSec) ...
|
||||
// mimum is zero according to specification
|
||||
// #define DMX_IBG 10 // Inter slot time
|
||||
|
||||
// Speed your Arduino is running on in Hz.
|
||||
#define F_OSC 16000000UL
|
||||
|
||||
// DMX Baudrate, this should be 250000
|
||||
#define DMX_BAUD_RATE 250000
|
||||
|
||||
// The baudrate used to automaticly generate a break within
|
||||
// your ISR.. make it lower to generate longer breaks
|
||||
//#define DMX_BREAK_RATE 99900
|
||||
|
||||
// 2017, Feb 28: Set to appox 176us
|
||||
#define DMX_BREAK_RATE 49950
|
||||
|
||||
// Tabel 3-2 ANSI_E1-20-2010
|
||||
// Minimum time to allow the datalink to 'turn arround'
|
||||
#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/
|
||||
|
||||
// Define which serial port to use as DMX port, only one can be
|
||||
// selected at the time by uncommenting one of the following
|
||||
// lines
|
||||
#define USE_DMX_SERIAL_0
|
||||
//#define USE_DMX_SERIAL_1
|
||||
//#define USE_DMX_SERIAL_2
|
||||
//#define USE_DMX_SERIAL_3
|
||||
|
||||
namespace dmx
|
||||
{
|
||||
enum dmxState
|
||||
{
|
||||
dmxUnknown,
|
||||
dmxStartByte,
|
||||
dmxWaitStartAddress,
|
||||
dmxData,
|
||||
dmxFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum rdmState
|
||||
{
|
||||
rdmUnknown,
|
||||
rdmStartByte,
|
||||
rdmSubStartCode,
|
||||
rdmMessageLength,
|
||||
rdmData,
|
||||
rdmChecksumHigh,
|
||||
rdmChecksumLow,
|
||||
rdmFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
struct IFrameBuffer
|
||||
{
|
||||
virtual uint16_t getBufferSize ( void ) = 0;
|
||||
|
||||
virtual uint8_t getSlotValue ( uint16_t index ) = 0;
|
||||
virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0;
|
||||
};
|
||||
|
||||
class DMX_FrameBuffer : IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor buffersize = 1-513
|
||||
//
|
||||
DMX_FrameBuffer ( uint16_t buffer_size );
|
||||
DMX_FrameBuffer ( DMX_FrameBuffer &buffer );
|
||||
~DMX_FrameBuffer ( void );
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void setSlotRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
private:
|
||||
|
||||
uint8_t *m_refcount;
|
||||
uint16_t m_bufferSize;
|
||||
uint8_t *m_buffer;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Master controller
|
||||
//
|
||||
class DMX_Master
|
||||
{
|
||||
public:
|
||||
// Run the DMX master from a pre allocated frame buffer which
|
||||
// you have fully under your own control
|
||||
DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin );
|
||||
|
||||
// Run the DMX master by giving a predefined maximum number of
|
||||
// channels to support
|
||||
DMX_Master ( uint16_t maxChannel, int readEnablePin );
|
||||
|
||||
~DMX_Master ( void );
|
||||
|
||||
void enable ( void ); // Start transmitting
|
||||
void disable ( void ); // Stop transmitting
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
// Update channel values
|
||||
void setChannelValue ( uint16_t channel, uint8_t value );
|
||||
void setChannelRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
|
||||
public:
|
||||
//
|
||||
// Manual control over the break period
|
||||
//
|
||||
void setAutoBreakMode ( void ); // Generated from ISR
|
||||
void setManualBreakMode ( void ); // Generate manually
|
||||
|
||||
uint8_t autoBreakEnabled ( void );
|
||||
|
||||
// We are waiting for a manual break to be generated
|
||||
uint8_t waitingBreak ( void );
|
||||
|
||||
// Generate break and start transmission of frame
|
||||
void breakAndContinue ( uint8_t breakLength_us = 100 );
|
||||
|
||||
|
||||
protected:
|
||||
void setStartCode ( uint8_t value );
|
||||
|
||||
|
||||
private:
|
||||
DMX_FrameBuffer m_frameBuffer;
|
||||
uint8_t m_autoBreak;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Slave controller
|
||||
//
|
||||
class DMX_Slave : public DMX_FrameBuffer
|
||||
{
|
||||
public:
|
||||
DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 );
|
||||
|
||||
// nrChannels is the consecutive DMX512 slots required
|
||||
// to operate this slave device
|
||||
DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 );
|
||||
|
||||
~DMX_Slave ( void );
|
||||
|
||||
void enable ( void ); // Enable receiver
|
||||
void disable ( void ); // Disable receiver
|
||||
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
uint8_t getChannelValue ( uint16_t channel );
|
||||
|
||||
uint16_t getStartAddress ( void );
|
||||
void setStartAddress ( uint16_t );
|
||||
|
||||
|
||||
// Process incoming byte from USART
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Register on receive complete callback in case
|
||||
// of time critical applications
|
||||
void onReceiveComplete ( void (*func)(unsigned short) );
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
uint16_t m_startAddress; // Slave start address
|
||||
dmx::dmxState m_state;
|
||||
|
||||
static void (*event_onFrameReceived)(unsigned short channelsReceived);
|
||||
};
|
||||
|
||||
|
||||
class RDM_FrameBuffer : public IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
RDM_FrameBuffer ( void ) {};
|
||||
~RDM_FrameBuffer ( void ) {};
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
public: // functions to provide access from USART
|
||||
// Process incoming byte from USART,
|
||||
// returns false when no more data is accepted
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Process outgoing byte to USART
|
||||
// returns false when no more data is available
|
||||
bool fetchOutgoing ( volatile uint8_t *udr, bool first = false );
|
||||
|
||||
protected:
|
||||
// Process received frame
|
||||
virtual void processFrame ( void ) = 0;
|
||||
|
||||
//private:
|
||||
protected:
|
||||
rdm::rdmState m_state; // State for pushing the message in
|
||||
RDM_Message m_msg;
|
||||
RDM_Checksum m_csRecv; // Checksum received in rdm message
|
||||
};
|
||||
|
||||
//
|
||||
// RDM_Responder
|
||||
//
|
||||
class RDM_Responder : public RDM_FrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// m = manufacturer id (16bits)
|
||||
// d1-d4 = device id (32bits)
|
||||
//
|
||||
RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave);
|
||||
~RDM_Responder ( void );
|
||||
|
||||
void setDeviceInfo
|
||||
(
|
||||
uint16_t deviceModelId,
|
||||
rdm::RdmProductCategory productCategory,
|
||||
uint8_t personalities = 1,
|
||||
uint8_t personality = 1
|
||||
)
|
||||
{
|
||||
m_DeviceModelId = deviceModelId;
|
||||
m_ProductCategory = productCategory;
|
||||
m_Personalities = personalities;
|
||||
m_Personality = personality;
|
||||
};
|
||||
|
||||
//
|
||||
// Set vendor software version id
|
||||
//
|
||||
// v1 = MOST SIGNIFICANT
|
||||
// v2...
|
||||
// v3...
|
||||
// v4 = LEAST SIGNIFICANT
|
||||
//
|
||||
void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 )
|
||||
{
|
||||
m_SoftwareVersionId[0] = v1;
|
||||
m_SoftwareVersionId[1] = v2;
|
||||
m_SoftwareVersionId[2] = v3;
|
||||
m_SoftwareVersionId[3] = v4;
|
||||
}
|
||||
|
||||
// Currently no sensors and subdevices supported
|
||||
// void AddSensor ( void );
|
||||
// void AddSubDevice ( void );
|
||||
|
||||
uint8_t getPersonality ( void ) { return m_Personality; };
|
||||
void setPersonality ( uint8_t personality ) { m_Personality = personality; };
|
||||
|
||||
// Register on identify device event handler
|
||||
void onIdentifyDevice ( void (*func)(bool) );
|
||||
void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) );
|
||||
void onDMXStartAddressChanged ( void (*func) (uint16_t) );
|
||||
void onDMXPersonalityChanged ( void (*func) (uint8_t) );
|
||||
|
||||
|
||||
// Set the device label
|
||||
void setDeviceLabel ( const char *label, size_t len );
|
||||
|
||||
// Enable, Disable rdm responder
|
||||
void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; };
|
||||
void disable ( void ) { m_rdmStatus.enabled = false; };
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t raw;
|
||||
struct
|
||||
{
|
||||
uint8_t mute:1;
|
||||
uint8_t ident:1;
|
||||
uint8_t enabled:1; // Rdm responder enable/disable
|
||||
};
|
||||
} m_rdmStatus;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void processFrame ( void );
|
||||
|
||||
// Discovery to unque brach packets only requires
|
||||
// the data part of the packet to be transmitted
|
||||
// without breaks or header
|
||||
void repondDiscUniqueBranch ( void );
|
||||
|
||||
// Helpers for generating response packets which
|
||||
// have larger datafields
|
||||
void populateDeviceInfo ( void );
|
||||
|
||||
private:
|
||||
RDM_Uid m_devid; // Holds our unique device ID
|
||||
uint8_t m_Personalities; // The total number of supported personalities
|
||||
uint8_t m_Personality; // The currently active personality
|
||||
uint16_t m_DeviceModelId;
|
||||
uint8_t m_SoftwareVersionId[4]; // 32 bit Software version
|
||||
rdm::RdmProductCategory m_ProductCategory;
|
||||
|
||||
char m_deviceLabel[32]; // Device label
|
||||
|
||||
static void (*event_onIdentifyDevice)(bool);
|
||||
static void (*event_onDeviceLabelChanged)(const char*, uint8_t);
|
||||
static void (*event_onDMXStartAddressChanged)(uint16_t);
|
||||
static void (*event_onDMXPersonalityChanged)(uint8_t);
|
||||
};
|
||||
|
||||
|
||||
#endif /* CONCEPTINETICS_H_ */
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <Conceptinetics.h>
|
||||
#include "Conceptinetics.h"
|
||||
|
||||
|
||||
//
|
||||
|
|
|
|||
315
DMX_NeoPixels/examples/DMX_Master/Rdm_Defines.h
Normal file
315
DMX_NeoPixels/examples/DMX_Master/Rdm_Defines.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_DEFINES_H_
|
||||
#define RDM_DEFINES_H_
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
|
||||
#define RDM_MAX_DEVICELABEL_LENGTH 32
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum RdmCommandClass
|
||||
{
|
||||
DiscoveryCommand = 0x10,
|
||||
DiscoveryCommandResponse,
|
||||
GetCommand = 0x20,
|
||||
GetCommandResponse,
|
||||
SetCommand = 0x30,
|
||||
SetCommandResponse,
|
||||
};
|
||||
|
||||
enum RdmResponseTypes
|
||||
{
|
||||
ResponseTypeAck = 0x00,
|
||||
ResponseTypeAckTimer,
|
||||
ResponseTypeNackReason,
|
||||
ResponseTypeAckOverflow, // Additional response data available (see spec)
|
||||
};
|
||||
|
||||
enum RdmParameters
|
||||
{
|
||||
// Category - Network Management
|
||||
DiscUniqueBranch = 0x0001, // Required
|
||||
DiscMute = 0x0002, // Required
|
||||
DiscUnMute = 0x0003, // Required
|
||||
|
||||
CommsStatus = 0x0015, // Get,Set
|
||||
|
||||
// Category - Status Collection
|
||||
QueuedMessage = 0x0020, // Get [enum RdmStatusTypes]
|
||||
StatusMessages = 0x0030, // Get [enum RdmStatusTypes]
|
||||
StatusIdDescription = 0x0031, // Get
|
||||
ClearStatusId = 0x0032, // Set
|
||||
SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes]
|
||||
|
||||
// Category - RDM Information
|
||||
// ** Only required if supporting parameters
|
||||
// beyond the minimum required set
|
||||
SupportedParameters = 0x0005, // Get, **Required
|
||||
ParameterDescription = 0x0051, // Get, **Required
|
||||
|
||||
// Category = Product Information
|
||||
DeviceInfo = 0x0060, // Get, Required
|
||||
ProductDetailIdList = 0x0070, // Get
|
||||
DeviceModelDescription = 0x0080, // Get
|
||||
ManufacturerLabel = 0x0081, // Get
|
||||
DeviceLabel = 0x0082, // Get, Set
|
||||
FactoryDefaults = 0x0009, // Get, Set **
|
||||
SoftwareVersionLabel = 0x000c, // Get
|
||||
|
||||
// Category - DMX512 Setup
|
||||
DmxPersonality = 0x00e0, // Get, Set
|
||||
DmxPersonalityDescription = 0x00e1, // Get
|
||||
DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device
|
||||
SlotInfo = 0x0120, // Get
|
||||
SlotDescription = 0x0121, // Get
|
||||
DefaultSlotValue = 0x0122, // Get
|
||||
|
||||
// Category - Sensors
|
||||
// Category - Dimmer Settings
|
||||
// Category - Power/Lamp Settings
|
||||
// Category - Display Settings
|
||||
// Category - Configuration
|
||||
|
||||
// Category - Control
|
||||
IdentifyDevice = 0x1000, // Get, Set, Required
|
||||
ResetDevice = 0x1001, // Set
|
||||
PowerState = 0x1010, // Get, Set
|
||||
PerformSelftest = 0x1020, // Get, Set
|
||||
SelfTestDescription = 0x1021, // Get
|
||||
};
|
||||
|
||||
|
||||
enum RdmStatusTypes
|
||||
{
|
||||
StatusNone = 0x00,
|
||||
StatusGetLastMessage,
|
||||
StatusAdvisory,
|
||||
StatusWarning,
|
||||
StatusError,
|
||||
StatusAdvisoryCleared = 0x12,
|
||||
StatusWarningCleared,
|
||||
StatusErrorCleared,
|
||||
};
|
||||
|
||||
enum RdmProductCategory
|
||||
{
|
||||
CategoryNotDeclared = 0x0000,
|
||||
|
||||
// Fixtures - intended as source for illumination
|
||||
CategoryFixture = 0x0100,
|
||||
CategoryFixtureFixed = 0x0101,
|
||||
CategoryFixtureMovingYoke = 0x0102,
|
||||
CategoryFixtureMovingMirror = 0x0103,
|
||||
CategoryFixtureOther = 0x01ff,
|
||||
|
||||
// Fixture Accessories - add-ons to fixtures or projectors
|
||||
CategoryFixtureAccessory = 0x0200,
|
||||
CategoryFixtureAccessoryColor = 0x0201,
|
||||
CategoryFixtureAccessoryYoke = 0x0202,
|
||||
CategoryFixtureAccessoryMirror = 0x0203,
|
||||
CategoryFixtureAccessoryEffect = 0x0204,
|
||||
CategoryFixtureAccessoryBeam = 0x0205,
|
||||
CategoryFixtureAccessoryOther = 0x02ff,
|
||||
|
||||
// Projectors - Light source capable of producing
|
||||
// realistic images from another media
|
||||
CategoryProjector = 0x0300,
|
||||
CategoryProjectorFixed = 0x0301,
|
||||
CategoryProjectorMovingYoke = 0x0302,
|
||||
CategoryProjectorMovingMirror = 0x0303,
|
||||
CategoryProjectorOther = 0x03ff,
|
||||
|
||||
// Atmospheric Effect - earth/wind/fire
|
||||
CategoryAtmospheric = 0x0400,
|
||||
CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame
|
||||
CategoryAtmosphericPyro = 0x0402,
|
||||
CategoryAtmosphericOther = 0x04ff,
|
||||
|
||||
// Insensity Control (Specifically dimming equipment)
|
||||
CategoryDimmer = 0x0500,
|
||||
CategoryDimmer_AC_Incandescent = 0x0501,
|
||||
CategoryDimmer_AC_Fluorescent = 0x0502,
|
||||
CategoryDimmer_AC_Coldcathode = 0x0503,
|
||||
CategoryDimmer_AC_Nondim = 0x0504,
|
||||
CategoryDimmer_AC_Elv = 0x0505,
|
||||
CategoryDimmer_AC_Other = 0x0506,
|
||||
CategoryDimmer_DC_Level = 0x0507,
|
||||
CategoryDimmer_DC_PWM = 0x0508,
|
||||
CategoryDimmer_CS_LED = 0x0509,
|
||||
CategoryDimmer_Other = 0x05ff,
|
||||
|
||||
// Power control (Other than dimming equipment)
|
||||
CategoryPower = 0x0600,
|
||||
CategoryPowerControl = 0x0601,
|
||||
CategoryPowerSource = 0x0602,
|
||||
CategoryPowerOther = 0x06ff,
|
||||
|
||||
// Scenic Drive - Including motorized effects
|
||||
// unrelated to light source
|
||||
CategoryScenic = 0x0700,
|
||||
CategoryScenicDrive = 0x0701,
|
||||
CategoryScenicOther = 0x07ff,
|
||||
|
||||
// DMX Infrastructure, conversion and interfaces
|
||||
CategoryData = 0x0800,
|
||||
CategoryDataDistribution = 0x0801,
|
||||
CategoryDataConversion = 0x0802,
|
||||
CategoryDataOther = 0x08ff,
|
||||
|
||||
// Audio visual equipment
|
||||
Category_AV = 0x0900,
|
||||
Category_AV_Audio = 0x0901,
|
||||
Category_AV_Video = 0x0902,
|
||||
Category_AV_Other = 0x09ff,
|
||||
|
||||
// Parameter monitoring equipment
|
||||
CategoryMonitor = 0x0a00,
|
||||
CategoryMonitorACLinePower = 0x0a01,
|
||||
CategoryMonitorDCPower = 0x0a02,
|
||||
CategoryMonitorEnvironmental = 0x0a03,
|
||||
CategoryMonitorOther = 0x0aff,
|
||||
|
||||
// Controllers, backup devices
|
||||
CategoryControl = 0x7000,
|
||||
CategoryControlController = 0x7001,
|
||||
CategoryControlBackupdevice = 0x7002,
|
||||
CategoryControlOther = 0x70ff,
|
||||
|
||||
// Test equipment
|
||||
CategoryTest = 0x7100,
|
||||
CategoryTestEquipment = 0x7101,
|
||||
CategoryTestEquipmentOther = 0x71ff,
|
||||
|
||||
// Miscellaneous
|
||||
CategoryOther = 0x7fff,
|
||||
};
|
||||
|
||||
//
|
||||
// Product details not yet supported in
|
||||
// this library
|
||||
//
|
||||
enum RdmProductDetail
|
||||
{
|
||||
ProductDetailNotDeclared = 0x0000,
|
||||
};
|
||||
|
||||
// Only LSB
|
||||
enum RdmNackReasons
|
||||
{
|
||||
UnknownPid = 0x00,
|
||||
FormatError,
|
||||
HardwareFault,
|
||||
ProxyReject,
|
||||
WriteProtect,
|
||||
UnsupportedCmdClass,
|
||||
DataOutOfRange,
|
||||
BufferFull,
|
||||
PacketSizeUnsupported,
|
||||
SubDeviceOutOfRange,
|
||||
ProxyBufferFull
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define RDM_HDR_LEN 24 // RDM Message header length ** fixed
|
||||
#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231
|
||||
|
||||
|
||||
union RDM_Message
|
||||
{
|
||||
uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ];
|
||||
struct
|
||||
{
|
||||
uint8_t startCode; // 0 SC_RDM
|
||||
uint8_t subStartCode; // 1 SC_SUB_MESSAGE
|
||||
uint8_t msgLength; // 2 Range 24 - 255
|
||||
RDM_Uid dstUid; // 3-8 Destination UID
|
||||
RDM_Uid srcUid; // 9-14 Source UID (sender)
|
||||
uint8_t TN; // 15 Transaction number
|
||||
uint8_t portId; // 16 Port ID / Response type
|
||||
uint8_t msgCount; // 17
|
||||
uint16_t subDevice; // 18,19 0=root, 0xffff=all
|
||||
uint8_t CC; // 20 GET_COMMAND
|
||||
uint16_t PID; // 21,22 Parameter ID
|
||||
uint8_t PDL; // 23 Parameter Data length 1-231
|
||||
|
||||
uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length
|
||||
};
|
||||
};
|
||||
|
||||
union RDM_Checksum
|
||||
{
|
||||
uint16_t checksum;
|
||||
struct
|
||||
{
|
||||
uint8_t csl;
|
||||
uint8_t csh;
|
||||
};
|
||||
};
|
||||
|
||||
struct RDM_DiscUniqueBranchPD
|
||||
{
|
||||
RDM_Uid lbound;
|
||||
RDM_Uid hbound;
|
||||
};
|
||||
|
||||
struct RDM_DiscMuteUnMutePD
|
||||
{
|
||||
uint16_t ctrlField;
|
||||
|
||||
// Only for multiple ports
|
||||
// RDM_Uid bindingUid;
|
||||
};
|
||||
|
||||
struct RDM__DeviceInfoPD
|
||||
{
|
||||
uint8_t protocolVersionMajor;
|
||||
uint8_t protocolVersionMinor;
|
||||
uint16_t deviceModelId;
|
||||
uint16_t ProductCategory; // enum RdmProductCategory
|
||||
uint8_t SoftwareVersionId[4];
|
||||
uint16_t DMX512FootPrint;
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
uint16_t DMX512StartAddress;
|
||||
uint16_t SubDeviceCount;
|
||||
uint8_t SensorCount;
|
||||
};
|
||||
|
||||
struct RDM_DeviceGetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
};
|
||||
|
||||
struct RDM_DeviceSetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512Personality;
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_DEFINES_H_ */
|
||||
101
DMX_NeoPixels/examples/DMX_Master/Rdm_Uid.h
Normal file
101
DMX_NeoPixels/examples/DMX_Master/Rdm_Uid.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_UID_H_
|
||||
#define RDM_UID_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//
|
||||
//48 bit UID Representation to identify RDM transponders
|
||||
//
|
||||
struct RDM_Uid {
|
||||
|
||||
void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 )
|
||||
{
|
||||
m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8));
|
||||
m_id[1] = (uint8_t)m;
|
||||
m_id[2] = d1;
|
||||
m_id[3] = d2;
|
||||
m_id[4] = d3;
|
||||
m_id[5] = d4;
|
||||
}
|
||||
|
||||
void copy ( const RDM_Uid &orig )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
m_id[i] = orig.m_id[i];
|
||||
}
|
||||
|
||||
bool operator == ( const RDM_Uid & orig ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != orig.m_id[i] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != ( const RDM_Uid & orig ) const
|
||||
{
|
||||
return !(*this == orig);
|
||||
}
|
||||
|
||||
bool operator < ( const RDM_Uid & v ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] < v.m_id[i] );
|
||||
}
|
||||
|
||||
bool operator > ( const RDM_Uid & v )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] > v.m_id[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// match_mid = manufacturer id to match
|
||||
//
|
||||
bool isBroadcast ( uint8_t match_mid[2] )
|
||||
{
|
||||
// Check for genuine broadcast on device part
|
||||
for ( uint8_t i = 2; i < 6; i++ )
|
||||
if ( m_id[i] != 0xff )
|
||||
return false;
|
||||
|
||||
// Broadcast or manufacturer designated broadcast
|
||||
if ( (m_id[0] == 0xff && m_id[1] == 0xff) ||
|
||||
(m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) )
|
||||
return true;
|
||||
|
||||
// No broadcast
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_UID_H_ */
|
||||
1233
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.cpp
Normal file
1233
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.cpp
Normal file
File diff suppressed because it is too large
Load diff
383
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.h
Normal file
383
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Conceptinetics.h
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Conceptinetics.h - DMX library for Arduino
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This code has been tested using the following hardware:
|
||||
|
||||
- Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD
|
||||
|
||||
- CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONCEPTINETICS_H_
|
||||
#define CONCEPTINETICS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
#include "Rdm_Defines.h"
|
||||
|
||||
#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots
|
||||
#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot
|
||||
|
||||
#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame
|
||||
|
||||
#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes
|
||||
|
||||
#define DMX_START_CODE 0x0 // Start code for a DMX frame
|
||||
#define RDM_START_CODE 0xcc // Start code for a RDM frame
|
||||
|
||||
// Uncomment to enable Inter slot delay ) (avg < 76uSec) ...
|
||||
// mimum is zero according to specification
|
||||
// #define DMX_IBG 10 // Inter slot time
|
||||
|
||||
// Speed your Arduino is running on in Hz.
|
||||
#define F_OSC 16000000UL
|
||||
|
||||
// DMX Baudrate, this should be 250000
|
||||
#define DMX_BAUD_RATE 250000
|
||||
|
||||
// The baudrate used to automaticly generate a break within
|
||||
// your ISR.. make it lower to generate longer breaks
|
||||
//#define DMX_BREAK_RATE 99900
|
||||
|
||||
// 2017, Feb 28: Set to appox 176us
|
||||
#define DMX_BREAK_RATE 49950
|
||||
|
||||
// Tabel 3-2 ANSI_E1-20-2010
|
||||
// Minimum time to allow the datalink to 'turn arround'
|
||||
#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/
|
||||
|
||||
// Define which serial port to use as DMX port, only one can be
|
||||
// selected at the time by uncommenting one of the following
|
||||
// lines
|
||||
#define USE_DMX_SERIAL_0
|
||||
//#define USE_DMX_SERIAL_1
|
||||
//#define USE_DMX_SERIAL_2
|
||||
//#define USE_DMX_SERIAL_3
|
||||
|
||||
namespace dmx
|
||||
{
|
||||
enum dmxState
|
||||
{
|
||||
dmxUnknown,
|
||||
dmxStartByte,
|
||||
dmxWaitStartAddress,
|
||||
dmxData,
|
||||
dmxFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum rdmState
|
||||
{
|
||||
rdmUnknown,
|
||||
rdmStartByte,
|
||||
rdmSubStartCode,
|
||||
rdmMessageLength,
|
||||
rdmData,
|
||||
rdmChecksumHigh,
|
||||
rdmChecksumLow,
|
||||
rdmFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
struct IFrameBuffer
|
||||
{
|
||||
virtual uint16_t getBufferSize ( void ) = 0;
|
||||
|
||||
virtual uint8_t getSlotValue ( uint16_t index ) = 0;
|
||||
virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0;
|
||||
};
|
||||
|
||||
class DMX_FrameBuffer : IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor buffersize = 1-513
|
||||
//
|
||||
DMX_FrameBuffer ( uint16_t buffer_size );
|
||||
DMX_FrameBuffer ( DMX_FrameBuffer &buffer );
|
||||
~DMX_FrameBuffer ( void );
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void setSlotRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
private:
|
||||
|
||||
uint8_t *m_refcount;
|
||||
uint16_t m_bufferSize;
|
||||
uint8_t *m_buffer;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Master controller
|
||||
//
|
||||
class DMX_Master
|
||||
{
|
||||
public:
|
||||
// Run the DMX master from a pre allocated frame buffer which
|
||||
// you have fully under your own control
|
||||
DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin );
|
||||
|
||||
// Run the DMX master by giving a predefined maximum number of
|
||||
// channels to support
|
||||
DMX_Master ( uint16_t maxChannel, int readEnablePin );
|
||||
|
||||
~DMX_Master ( void );
|
||||
|
||||
void enable ( void ); // Start transmitting
|
||||
void disable ( void ); // Stop transmitting
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
// Update channel values
|
||||
void setChannelValue ( uint16_t channel, uint8_t value );
|
||||
void setChannelRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
|
||||
public:
|
||||
//
|
||||
// Manual control over the break period
|
||||
//
|
||||
void setAutoBreakMode ( void ); // Generated from ISR
|
||||
void setManualBreakMode ( void ); // Generate manually
|
||||
|
||||
uint8_t autoBreakEnabled ( void );
|
||||
|
||||
// We are waiting for a manual break to be generated
|
||||
uint8_t waitingBreak ( void );
|
||||
|
||||
// Generate break and start transmission of frame
|
||||
void breakAndContinue ( uint8_t breakLength_us = 100 );
|
||||
|
||||
|
||||
protected:
|
||||
void setStartCode ( uint8_t value );
|
||||
|
||||
|
||||
private:
|
||||
DMX_FrameBuffer m_frameBuffer;
|
||||
uint8_t m_autoBreak;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Slave controller
|
||||
//
|
||||
class DMX_Slave : public DMX_FrameBuffer
|
||||
{
|
||||
public:
|
||||
DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 );
|
||||
|
||||
// nrChannels is the consecutive DMX512 slots required
|
||||
// to operate this slave device
|
||||
DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 );
|
||||
|
||||
~DMX_Slave ( void );
|
||||
|
||||
void enable ( void ); // Enable receiver
|
||||
void disable ( void ); // Disable receiver
|
||||
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
uint8_t getChannelValue ( uint16_t channel );
|
||||
|
||||
uint16_t getStartAddress ( void );
|
||||
void setStartAddress ( uint16_t );
|
||||
|
||||
|
||||
// Process incoming byte from USART
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Register on receive complete callback in case
|
||||
// of time critical applications
|
||||
void onReceiveComplete ( void (*func)(unsigned short) );
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
uint16_t m_startAddress; // Slave start address
|
||||
dmx::dmxState m_state;
|
||||
|
||||
static void (*event_onFrameReceived)(unsigned short channelsReceived);
|
||||
};
|
||||
|
||||
|
||||
class RDM_FrameBuffer : public IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
RDM_FrameBuffer ( void ) {};
|
||||
~RDM_FrameBuffer ( void ) {};
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
public: // functions to provide access from USART
|
||||
// Process incoming byte from USART,
|
||||
// returns false when no more data is accepted
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Process outgoing byte to USART
|
||||
// returns false when no more data is available
|
||||
bool fetchOutgoing ( volatile uint8_t *udr, bool first = false );
|
||||
|
||||
protected:
|
||||
// Process received frame
|
||||
virtual void processFrame ( void ) = 0;
|
||||
|
||||
//private:
|
||||
protected:
|
||||
rdm::rdmState m_state; // State for pushing the message in
|
||||
RDM_Message m_msg;
|
||||
RDM_Checksum m_csRecv; // Checksum received in rdm message
|
||||
};
|
||||
|
||||
//
|
||||
// RDM_Responder
|
||||
//
|
||||
class RDM_Responder : public RDM_FrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// m = manufacturer id (16bits)
|
||||
// d1-d4 = device id (32bits)
|
||||
//
|
||||
RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave);
|
||||
~RDM_Responder ( void );
|
||||
|
||||
void setDeviceInfo
|
||||
(
|
||||
uint16_t deviceModelId,
|
||||
rdm::RdmProductCategory productCategory,
|
||||
uint8_t personalities = 1,
|
||||
uint8_t personality = 1
|
||||
)
|
||||
{
|
||||
m_DeviceModelId = deviceModelId;
|
||||
m_ProductCategory = productCategory;
|
||||
m_Personalities = personalities;
|
||||
m_Personality = personality;
|
||||
};
|
||||
|
||||
//
|
||||
// Set vendor software version id
|
||||
//
|
||||
// v1 = MOST SIGNIFICANT
|
||||
// v2...
|
||||
// v3...
|
||||
// v4 = LEAST SIGNIFICANT
|
||||
//
|
||||
void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 )
|
||||
{
|
||||
m_SoftwareVersionId[0] = v1;
|
||||
m_SoftwareVersionId[1] = v2;
|
||||
m_SoftwareVersionId[2] = v3;
|
||||
m_SoftwareVersionId[3] = v4;
|
||||
}
|
||||
|
||||
// Currently no sensors and subdevices supported
|
||||
// void AddSensor ( void );
|
||||
// void AddSubDevice ( void );
|
||||
|
||||
uint8_t getPersonality ( void ) { return m_Personality; };
|
||||
void setPersonality ( uint8_t personality ) { m_Personality = personality; };
|
||||
|
||||
// Register on identify device event handler
|
||||
void onIdentifyDevice ( void (*func)(bool) );
|
||||
void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) );
|
||||
void onDMXStartAddressChanged ( void (*func) (uint16_t) );
|
||||
void onDMXPersonalityChanged ( void (*func) (uint8_t) );
|
||||
|
||||
|
||||
// Set the device label
|
||||
void setDeviceLabel ( const char *label, size_t len );
|
||||
|
||||
// Enable, Disable rdm responder
|
||||
void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; };
|
||||
void disable ( void ) { m_rdmStatus.enabled = false; };
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t raw;
|
||||
struct
|
||||
{
|
||||
uint8_t mute:1;
|
||||
uint8_t ident:1;
|
||||
uint8_t enabled:1; // Rdm responder enable/disable
|
||||
};
|
||||
} m_rdmStatus;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void processFrame ( void );
|
||||
|
||||
// Discovery to unque brach packets only requires
|
||||
// the data part of the packet to be transmitted
|
||||
// without breaks or header
|
||||
void repondDiscUniqueBranch ( void );
|
||||
|
||||
// Helpers for generating response packets which
|
||||
// have larger datafields
|
||||
void populateDeviceInfo ( void );
|
||||
|
||||
private:
|
||||
RDM_Uid m_devid; // Holds our unique device ID
|
||||
uint8_t m_Personalities; // The total number of supported personalities
|
||||
uint8_t m_Personality; // The currently active personality
|
||||
uint16_t m_DeviceModelId;
|
||||
uint8_t m_SoftwareVersionId[4]; // 32 bit Software version
|
||||
rdm::RdmProductCategory m_ProductCategory;
|
||||
|
||||
char m_deviceLabel[32]; // Device label
|
||||
|
||||
static void (*event_onIdentifyDevice)(bool);
|
||||
static void (*event_onDeviceLabelChanged)(const char*, uint8_t);
|
||||
static void (*event_onDMXStartAddressChanged)(uint16_t);
|
||||
static void (*event_onDMXPersonalityChanged)(uint8_t);
|
||||
};
|
||||
|
||||
|
||||
#endif /* CONCEPTINETICS_H_ */
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <Conceptinetics.h>
|
||||
#include "Conceptinetics.h"
|
||||
|
||||
//
|
||||
// When configuring a DMX_Master it will normally automaticly
|
||||
|
|
|
|||
315
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Defines.h
Normal file
315
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Defines.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_DEFINES_H_
|
||||
#define RDM_DEFINES_H_
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
|
||||
#define RDM_MAX_DEVICELABEL_LENGTH 32
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum RdmCommandClass
|
||||
{
|
||||
DiscoveryCommand = 0x10,
|
||||
DiscoveryCommandResponse,
|
||||
GetCommand = 0x20,
|
||||
GetCommandResponse,
|
||||
SetCommand = 0x30,
|
||||
SetCommandResponse,
|
||||
};
|
||||
|
||||
enum RdmResponseTypes
|
||||
{
|
||||
ResponseTypeAck = 0x00,
|
||||
ResponseTypeAckTimer,
|
||||
ResponseTypeNackReason,
|
||||
ResponseTypeAckOverflow, // Additional response data available (see spec)
|
||||
};
|
||||
|
||||
enum RdmParameters
|
||||
{
|
||||
// Category - Network Management
|
||||
DiscUniqueBranch = 0x0001, // Required
|
||||
DiscMute = 0x0002, // Required
|
||||
DiscUnMute = 0x0003, // Required
|
||||
|
||||
CommsStatus = 0x0015, // Get,Set
|
||||
|
||||
// Category - Status Collection
|
||||
QueuedMessage = 0x0020, // Get [enum RdmStatusTypes]
|
||||
StatusMessages = 0x0030, // Get [enum RdmStatusTypes]
|
||||
StatusIdDescription = 0x0031, // Get
|
||||
ClearStatusId = 0x0032, // Set
|
||||
SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes]
|
||||
|
||||
// Category - RDM Information
|
||||
// ** Only required if supporting parameters
|
||||
// beyond the minimum required set
|
||||
SupportedParameters = 0x0005, // Get, **Required
|
||||
ParameterDescription = 0x0051, // Get, **Required
|
||||
|
||||
// Category = Product Information
|
||||
DeviceInfo = 0x0060, // Get, Required
|
||||
ProductDetailIdList = 0x0070, // Get
|
||||
DeviceModelDescription = 0x0080, // Get
|
||||
ManufacturerLabel = 0x0081, // Get
|
||||
DeviceLabel = 0x0082, // Get, Set
|
||||
FactoryDefaults = 0x0009, // Get, Set **
|
||||
SoftwareVersionLabel = 0x000c, // Get
|
||||
|
||||
// Category - DMX512 Setup
|
||||
DmxPersonality = 0x00e0, // Get, Set
|
||||
DmxPersonalityDescription = 0x00e1, // Get
|
||||
DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device
|
||||
SlotInfo = 0x0120, // Get
|
||||
SlotDescription = 0x0121, // Get
|
||||
DefaultSlotValue = 0x0122, // Get
|
||||
|
||||
// Category - Sensors
|
||||
// Category - Dimmer Settings
|
||||
// Category - Power/Lamp Settings
|
||||
// Category - Display Settings
|
||||
// Category - Configuration
|
||||
|
||||
// Category - Control
|
||||
IdentifyDevice = 0x1000, // Get, Set, Required
|
||||
ResetDevice = 0x1001, // Set
|
||||
PowerState = 0x1010, // Get, Set
|
||||
PerformSelftest = 0x1020, // Get, Set
|
||||
SelfTestDescription = 0x1021, // Get
|
||||
};
|
||||
|
||||
|
||||
enum RdmStatusTypes
|
||||
{
|
||||
StatusNone = 0x00,
|
||||
StatusGetLastMessage,
|
||||
StatusAdvisory,
|
||||
StatusWarning,
|
||||
StatusError,
|
||||
StatusAdvisoryCleared = 0x12,
|
||||
StatusWarningCleared,
|
||||
StatusErrorCleared,
|
||||
};
|
||||
|
||||
enum RdmProductCategory
|
||||
{
|
||||
CategoryNotDeclared = 0x0000,
|
||||
|
||||
// Fixtures - intended as source for illumination
|
||||
CategoryFixture = 0x0100,
|
||||
CategoryFixtureFixed = 0x0101,
|
||||
CategoryFixtureMovingYoke = 0x0102,
|
||||
CategoryFixtureMovingMirror = 0x0103,
|
||||
CategoryFixtureOther = 0x01ff,
|
||||
|
||||
// Fixture Accessories - add-ons to fixtures or projectors
|
||||
CategoryFixtureAccessory = 0x0200,
|
||||
CategoryFixtureAccessoryColor = 0x0201,
|
||||
CategoryFixtureAccessoryYoke = 0x0202,
|
||||
CategoryFixtureAccessoryMirror = 0x0203,
|
||||
CategoryFixtureAccessoryEffect = 0x0204,
|
||||
CategoryFixtureAccessoryBeam = 0x0205,
|
||||
CategoryFixtureAccessoryOther = 0x02ff,
|
||||
|
||||
// Projectors - Light source capable of producing
|
||||
// realistic images from another media
|
||||
CategoryProjector = 0x0300,
|
||||
CategoryProjectorFixed = 0x0301,
|
||||
CategoryProjectorMovingYoke = 0x0302,
|
||||
CategoryProjectorMovingMirror = 0x0303,
|
||||
CategoryProjectorOther = 0x03ff,
|
||||
|
||||
// Atmospheric Effect - earth/wind/fire
|
||||
CategoryAtmospheric = 0x0400,
|
||||
CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame
|
||||
CategoryAtmosphericPyro = 0x0402,
|
||||
CategoryAtmosphericOther = 0x04ff,
|
||||
|
||||
// Insensity Control (Specifically dimming equipment)
|
||||
CategoryDimmer = 0x0500,
|
||||
CategoryDimmer_AC_Incandescent = 0x0501,
|
||||
CategoryDimmer_AC_Fluorescent = 0x0502,
|
||||
CategoryDimmer_AC_Coldcathode = 0x0503,
|
||||
CategoryDimmer_AC_Nondim = 0x0504,
|
||||
CategoryDimmer_AC_Elv = 0x0505,
|
||||
CategoryDimmer_AC_Other = 0x0506,
|
||||
CategoryDimmer_DC_Level = 0x0507,
|
||||
CategoryDimmer_DC_PWM = 0x0508,
|
||||
CategoryDimmer_CS_LED = 0x0509,
|
||||
CategoryDimmer_Other = 0x05ff,
|
||||
|
||||
// Power control (Other than dimming equipment)
|
||||
CategoryPower = 0x0600,
|
||||
CategoryPowerControl = 0x0601,
|
||||
CategoryPowerSource = 0x0602,
|
||||
CategoryPowerOther = 0x06ff,
|
||||
|
||||
// Scenic Drive - Including motorized effects
|
||||
// unrelated to light source
|
||||
CategoryScenic = 0x0700,
|
||||
CategoryScenicDrive = 0x0701,
|
||||
CategoryScenicOther = 0x07ff,
|
||||
|
||||
// DMX Infrastructure, conversion and interfaces
|
||||
CategoryData = 0x0800,
|
||||
CategoryDataDistribution = 0x0801,
|
||||
CategoryDataConversion = 0x0802,
|
||||
CategoryDataOther = 0x08ff,
|
||||
|
||||
// Audio visual equipment
|
||||
Category_AV = 0x0900,
|
||||
Category_AV_Audio = 0x0901,
|
||||
Category_AV_Video = 0x0902,
|
||||
Category_AV_Other = 0x09ff,
|
||||
|
||||
// Parameter monitoring equipment
|
||||
CategoryMonitor = 0x0a00,
|
||||
CategoryMonitorACLinePower = 0x0a01,
|
||||
CategoryMonitorDCPower = 0x0a02,
|
||||
CategoryMonitorEnvironmental = 0x0a03,
|
||||
CategoryMonitorOther = 0x0aff,
|
||||
|
||||
// Controllers, backup devices
|
||||
CategoryControl = 0x7000,
|
||||
CategoryControlController = 0x7001,
|
||||
CategoryControlBackupdevice = 0x7002,
|
||||
CategoryControlOther = 0x70ff,
|
||||
|
||||
// Test equipment
|
||||
CategoryTest = 0x7100,
|
||||
CategoryTestEquipment = 0x7101,
|
||||
CategoryTestEquipmentOther = 0x71ff,
|
||||
|
||||
// Miscellaneous
|
||||
CategoryOther = 0x7fff,
|
||||
};
|
||||
|
||||
//
|
||||
// Product details not yet supported in
|
||||
// this library
|
||||
//
|
||||
enum RdmProductDetail
|
||||
{
|
||||
ProductDetailNotDeclared = 0x0000,
|
||||
};
|
||||
|
||||
// Only LSB
|
||||
enum RdmNackReasons
|
||||
{
|
||||
UnknownPid = 0x00,
|
||||
FormatError,
|
||||
HardwareFault,
|
||||
ProxyReject,
|
||||
WriteProtect,
|
||||
UnsupportedCmdClass,
|
||||
DataOutOfRange,
|
||||
BufferFull,
|
||||
PacketSizeUnsupported,
|
||||
SubDeviceOutOfRange,
|
||||
ProxyBufferFull
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define RDM_HDR_LEN 24 // RDM Message header length ** fixed
|
||||
#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231
|
||||
|
||||
|
||||
union RDM_Message
|
||||
{
|
||||
uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ];
|
||||
struct
|
||||
{
|
||||
uint8_t startCode; // 0 SC_RDM
|
||||
uint8_t subStartCode; // 1 SC_SUB_MESSAGE
|
||||
uint8_t msgLength; // 2 Range 24 - 255
|
||||
RDM_Uid dstUid; // 3-8 Destination UID
|
||||
RDM_Uid srcUid; // 9-14 Source UID (sender)
|
||||
uint8_t TN; // 15 Transaction number
|
||||
uint8_t portId; // 16 Port ID / Response type
|
||||
uint8_t msgCount; // 17
|
||||
uint16_t subDevice; // 18,19 0=root, 0xffff=all
|
||||
uint8_t CC; // 20 GET_COMMAND
|
||||
uint16_t PID; // 21,22 Parameter ID
|
||||
uint8_t PDL; // 23 Parameter Data length 1-231
|
||||
|
||||
uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length
|
||||
};
|
||||
};
|
||||
|
||||
union RDM_Checksum
|
||||
{
|
||||
uint16_t checksum;
|
||||
struct
|
||||
{
|
||||
uint8_t csl;
|
||||
uint8_t csh;
|
||||
};
|
||||
};
|
||||
|
||||
struct RDM_DiscUniqueBranchPD
|
||||
{
|
||||
RDM_Uid lbound;
|
||||
RDM_Uid hbound;
|
||||
};
|
||||
|
||||
struct RDM_DiscMuteUnMutePD
|
||||
{
|
||||
uint16_t ctrlField;
|
||||
|
||||
// Only for multiple ports
|
||||
// RDM_Uid bindingUid;
|
||||
};
|
||||
|
||||
struct RDM__DeviceInfoPD
|
||||
{
|
||||
uint8_t protocolVersionMajor;
|
||||
uint8_t protocolVersionMinor;
|
||||
uint16_t deviceModelId;
|
||||
uint16_t ProductCategory; // enum RdmProductCategory
|
||||
uint8_t SoftwareVersionId[4];
|
||||
uint16_t DMX512FootPrint;
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
uint16_t DMX512StartAddress;
|
||||
uint16_t SubDeviceCount;
|
||||
uint8_t SensorCount;
|
||||
};
|
||||
|
||||
struct RDM_DeviceGetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
};
|
||||
|
||||
struct RDM_DeviceSetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512Personality;
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_DEFINES_H_ */
|
||||
101
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Uid.h
Normal file
101
DMX_NeoPixels/examples/DMX_Master_Manual_Break/Rdm_Uid.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_UID_H_
|
||||
#define RDM_UID_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//
|
||||
//48 bit UID Representation to identify RDM transponders
|
||||
//
|
||||
struct RDM_Uid {
|
||||
|
||||
void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 )
|
||||
{
|
||||
m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8));
|
||||
m_id[1] = (uint8_t)m;
|
||||
m_id[2] = d1;
|
||||
m_id[3] = d2;
|
||||
m_id[4] = d3;
|
||||
m_id[5] = d4;
|
||||
}
|
||||
|
||||
void copy ( const RDM_Uid &orig )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
m_id[i] = orig.m_id[i];
|
||||
}
|
||||
|
||||
bool operator == ( const RDM_Uid & orig ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != orig.m_id[i] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != ( const RDM_Uid & orig ) const
|
||||
{
|
||||
return !(*this == orig);
|
||||
}
|
||||
|
||||
bool operator < ( const RDM_Uid & v ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] < v.m_id[i] );
|
||||
}
|
||||
|
||||
bool operator > ( const RDM_Uid & v )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] > v.m_id[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// match_mid = manufacturer id to match
|
||||
//
|
||||
bool isBroadcast ( uint8_t match_mid[2] )
|
||||
{
|
||||
// Check for genuine broadcast on device part
|
||||
for ( uint8_t i = 2; i < 6; i++ )
|
||||
if ( m_id[i] != 0xff )
|
||||
return false;
|
||||
|
||||
// Broadcast or manufacturer designated broadcast
|
||||
if ( (m_id[0] == 0xff && m_id[1] == 0xff) ||
|
||||
(m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) )
|
||||
return true;
|
||||
|
||||
// No broadcast
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_UID_H_ */
|
||||
1233
DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.cpp
Normal file
1233
DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.cpp
Normal file
File diff suppressed because it is too large
Load diff
383
DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.h
Normal file
383
DMX_NeoPixels/examples/DMX_Slave/Conceptinetics.h
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Conceptinetics.h - DMX library for Arduino
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This code has been tested using the following hardware:
|
||||
|
||||
- Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD
|
||||
|
||||
- CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONCEPTINETICS_H_
|
||||
#define CONCEPTINETICS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
#include "Rdm_Defines.h"
|
||||
|
||||
#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots
|
||||
#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot
|
||||
|
||||
#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame
|
||||
|
||||
#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes
|
||||
|
||||
#define DMX_START_CODE 0x0 // Start code for a DMX frame
|
||||
#define RDM_START_CODE 0xcc // Start code for a RDM frame
|
||||
|
||||
// Uncomment to enable Inter slot delay ) (avg < 76uSec) ...
|
||||
// mimum is zero according to specification
|
||||
// #define DMX_IBG 10 // Inter slot time
|
||||
|
||||
// Speed your Arduino is running on in Hz.
|
||||
#define F_OSC 16000000UL
|
||||
|
||||
// DMX Baudrate, this should be 250000
|
||||
#define DMX_BAUD_RATE 250000
|
||||
|
||||
// The baudrate used to automaticly generate a break within
|
||||
// your ISR.. make it lower to generate longer breaks
|
||||
//#define DMX_BREAK_RATE 99900
|
||||
|
||||
// 2017, Feb 28: Set to appox 176us
|
||||
#define DMX_BREAK_RATE 49950
|
||||
|
||||
// Tabel 3-2 ANSI_E1-20-2010
|
||||
// Minimum time to allow the datalink to 'turn arround'
|
||||
#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/
|
||||
|
||||
// Define which serial port to use as DMX port, only one can be
|
||||
// selected at the time by uncommenting one of the following
|
||||
// lines
|
||||
#define USE_DMX_SERIAL_0
|
||||
//#define USE_DMX_SERIAL_1
|
||||
//#define USE_DMX_SERIAL_2
|
||||
//#define USE_DMX_SERIAL_3
|
||||
|
||||
namespace dmx
|
||||
{
|
||||
enum dmxState
|
||||
{
|
||||
dmxUnknown,
|
||||
dmxStartByte,
|
||||
dmxWaitStartAddress,
|
||||
dmxData,
|
||||
dmxFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum rdmState
|
||||
{
|
||||
rdmUnknown,
|
||||
rdmStartByte,
|
||||
rdmSubStartCode,
|
||||
rdmMessageLength,
|
||||
rdmData,
|
||||
rdmChecksumHigh,
|
||||
rdmChecksumLow,
|
||||
rdmFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
struct IFrameBuffer
|
||||
{
|
||||
virtual uint16_t getBufferSize ( void ) = 0;
|
||||
|
||||
virtual uint8_t getSlotValue ( uint16_t index ) = 0;
|
||||
virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0;
|
||||
};
|
||||
|
||||
class DMX_FrameBuffer : IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor buffersize = 1-513
|
||||
//
|
||||
DMX_FrameBuffer ( uint16_t buffer_size );
|
||||
DMX_FrameBuffer ( DMX_FrameBuffer &buffer );
|
||||
~DMX_FrameBuffer ( void );
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void setSlotRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
private:
|
||||
|
||||
uint8_t *m_refcount;
|
||||
uint16_t m_bufferSize;
|
||||
uint8_t *m_buffer;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Master controller
|
||||
//
|
||||
class DMX_Master
|
||||
{
|
||||
public:
|
||||
// Run the DMX master from a pre allocated frame buffer which
|
||||
// you have fully under your own control
|
||||
DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin );
|
||||
|
||||
// Run the DMX master by giving a predefined maximum number of
|
||||
// channels to support
|
||||
DMX_Master ( uint16_t maxChannel, int readEnablePin );
|
||||
|
||||
~DMX_Master ( void );
|
||||
|
||||
void enable ( void ); // Start transmitting
|
||||
void disable ( void ); // Stop transmitting
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
// Update channel values
|
||||
void setChannelValue ( uint16_t channel, uint8_t value );
|
||||
void setChannelRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
|
||||
public:
|
||||
//
|
||||
// Manual control over the break period
|
||||
//
|
||||
void setAutoBreakMode ( void ); // Generated from ISR
|
||||
void setManualBreakMode ( void ); // Generate manually
|
||||
|
||||
uint8_t autoBreakEnabled ( void );
|
||||
|
||||
// We are waiting for a manual break to be generated
|
||||
uint8_t waitingBreak ( void );
|
||||
|
||||
// Generate break and start transmission of frame
|
||||
void breakAndContinue ( uint8_t breakLength_us = 100 );
|
||||
|
||||
|
||||
protected:
|
||||
void setStartCode ( uint8_t value );
|
||||
|
||||
|
||||
private:
|
||||
DMX_FrameBuffer m_frameBuffer;
|
||||
uint8_t m_autoBreak;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Slave controller
|
||||
//
|
||||
class DMX_Slave : public DMX_FrameBuffer
|
||||
{
|
||||
public:
|
||||
DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 );
|
||||
|
||||
// nrChannels is the consecutive DMX512 slots required
|
||||
// to operate this slave device
|
||||
DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 );
|
||||
|
||||
~DMX_Slave ( void );
|
||||
|
||||
void enable ( void ); // Enable receiver
|
||||
void disable ( void ); // Disable receiver
|
||||
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
uint8_t getChannelValue ( uint16_t channel );
|
||||
|
||||
uint16_t getStartAddress ( void );
|
||||
void setStartAddress ( uint16_t );
|
||||
|
||||
|
||||
// Process incoming byte from USART
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Register on receive complete callback in case
|
||||
// of time critical applications
|
||||
void onReceiveComplete ( void (*func)(unsigned short) );
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
uint16_t m_startAddress; // Slave start address
|
||||
dmx::dmxState m_state;
|
||||
|
||||
static void (*event_onFrameReceived)(unsigned short channelsReceived);
|
||||
};
|
||||
|
||||
|
||||
class RDM_FrameBuffer : public IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
RDM_FrameBuffer ( void ) {};
|
||||
~RDM_FrameBuffer ( void ) {};
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
public: // functions to provide access from USART
|
||||
// Process incoming byte from USART,
|
||||
// returns false when no more data is accepted
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Process outgoing byte to USART
|
||||
// returns false when no more data is available
|
||||
bool fetchOutgoing ( volatile uint8_t *udr, bool first = false );
|
||||
|
||||
protected:
|
||||
// Process received frame
|
||||
virtual void processFrame ( void ) = 0;
|
||||
|
||||
//private:
|
||||
protected:
|
||||
rdm::rdmState m_state; // State for pushing the message in
|
||||
RDM_Message m_msg;
|
||||
RDM_Checksum m_csRecv; // Checksum received in rdm message
|
||||
};
|
||||
|
||||
//
|
||||
// RDM_Responder
|
||||
//
|
||||
class RDM_Responder : public RDM_FrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// m = manufacturer id (16bits)
|
||||
// d1-d4 = device id (32bits)
|
||||
//
|
||||
RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave);
|
||||
~RDM_Responder ( void );
|
||||
|
||||
void setDeviceInfo
|
||||
(
|
||||
uint16_t deviceModelId,
|
||||
rdm::RdmProductCategory productCategory,
|
||||
uint8_t personalities = 1,
|
||||
uint8_t personality = 1
|
||||
)
|
||||
{
|
||||
m_DeviceModelId = deviceModelId;
|
||||
m_ProductCategory = productCategory;
|
||||
m_Personalities = personalities;
|
||||
m_Personality = personality;
|
||||
};
|
||||
|
||||
//
|
||||
// Set vendor software version id
|
||||
//
|
||||
// v1 = MOST SIGNIFICANT
|
||||
// v2...
|
||||
// v3...
|
||||
// v4 = LEAST SIGNIFICANT
|
||||
//
|
||||
void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 )
|
||||
{
|
||||
m_SoftwareVersionId[0] = v1;
|
||||
m_SoftwareVersionId[1] = v2;
|
||||
m_SoftwareVersionId[2] = v3;
|
||||
m_SoftwareVersionId[3] = v4;
|
||||
}
|
||||
|
||||
// Currently no sensors and subdevices supported
|
||||
// void AddSensor ( void );
|
||||
// void AddSubDevice ( void );
|
||||
|
||||
uint8_t getPersonality ( void ) { return m_Personality; };
|
||||
void setPersonality ( uint8_t personality ) { m_Personality = personality; };
|
||||
|
||||
// Register on identify device event handler
|
||||
void onIdentifyDevice ( void (*func)(bool) );
|
||||
void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) );
|
||||
void onDMXStartAddressChanged ( void (*func) (uint16_t) );
|
||||
void onDMXPersonalityChanged ( void (*func) (uint8_t) );
|
||||
|
||||
|
||||
// Set the device label
|
||||
void setDeviceLabel ( const char *label, size_t len );
|
||||
|
||||
// Enable, Disable rdm responder
|
||||
void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; };
|
||||
void disable ( void ) { m_rdmStatus.enabled = false; };
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t raw;
|
||||
struct
|
||||
{
|
||||
uint8_t mute:1;
|
||||
uint8_t ident:1;
|
||||
uint8_t enabled:1; // Rdm responder enable/disable
|
||||
};
|
||||
} m_rdmStatus;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void processFrame ( void );
|
||||
|
||||
// Discovery to unque brach packets only requires
|
||||
// the data part of the packet to be transmitted
|
||||
// without breaks or header
|
||||
void repondDiscUniqueBranch ( void );
|
||||
|
||||
// Helpers for generating response packets which
|
||||
// have larger datafields
|
||||
void populateDeviceInfo ( void );
|
||||
|
||||
private:
|
||||
RDM_Uid m_devid; // Holds our unique device ID
|
||||
uint8_t m_Personalities; // The total number of supported personalities
|
||||
uint8_t m_Personality; // The currently active personality
|
||||
uint16_t m_DeviceModelId;
|
||||
uint8_t m_SoftwareVersionId[4]; // 32 bit Software version
|
||||
rdm::RdmProductCategory m_ProductCategory;
|
||||
|
||||
char m_deviceLabel[32]; // Device label
|
||||
|
||||
static void (*event_onIdentifyDevice)(bool);
|
||||
static void (*event_onDeviceLabelChanged)(const char*, uint8_t);
|
||||
static void (*event_onDMXStartAddressChanged)(uint16_t);
|
||||
static void (*event_onDMXPersonalityChanged)(uint8_t);
|
||||
};
|
||||
|
||||
|
||||
#endif /* CONCEPTINETICS_H_ */
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <Conceptinetics.h>
|
||||
#include "Conceptinetics.h"
|
||||
|
||||
//
|
||||
// CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS
|
||||
|
|
|
|||
315
DMX_NeoPixels/examples/DMX_Slave/Rdm_Defines.h
Normal file
315
DMX_NeoPixels/examples/DMX_Slave/Rdm_Defines.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_DEFINES_H_
|
||||
#define RDM_DEFINES_H_
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
|
||||
#define RDM_MAX_DEVICELABEL_LENGTH 32
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum RdmCommandClass
|
||||
{
|
||||
DiscoveryCommand = 0x10,
|
||||
DiscoveryCommandResponse,
|
||||
GetCommand = 0x20,
|
||||
GetCommandResponse,
|
||||
SetCommand = 0x30,
|
||||
SetCommandResponse,
|
||||
};
|
||||
|
||||
enum RdmResponseTypes
|
||||
{
|
||||
ResponseTypeAck = 0x00,
|
||||
ResponseTypeAckTimer,
|
||||
ResponseTypeNackReason,
|
||||
ResponseTypeAckOverflow, // Additional response data available (see spec)
|
||||
};
|
||||
|
||||
enum RdmParameters
|
||||
{
|
||||
// Category - Network Management
|
||||
DiscUniqueBranch = 0x0001, // Required
|
||||
DiscMute = 0x0002, // Required
|
||||
DiscUnMute = 0x0003, // Required
|
||||
|
||||
CommsStatus = 0x0015, // Get,Set
|
||||
|
||||
// Category - Status Collection
|
||||
QueuedMessage = 0x0020, // Get [enum RdmStatusTypes]
|
||||
StatusMessages = 0x0030, // Get [enum RdmStatusTypes]
|
||||
StatusIdDescription = 0x0031, // Get
|
||||
ClearStatusId = 0x0032, // Set
|
||||
SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes]
|
||||
|
||||
// Category - RDM Information
|
||||
// ** Only required if supporting parameters
|
||||
// beyond the minimum required set
|
||||
SupportedParameters = 0x0005, // Get, **Required
|
||||
ParameterDescription = 0x0051, // Get, **Required
|
||||
|
||||
// Category = Product Information
|
||||
DeviceInfo = 0x0060, // Get, Required
|
||||
ProductDetailIdList = 0x0070, // Get
|
||||
DeviceModelDescription = 0x0080, // Get
|
||||
ManufacturerLabel = 0x0081, // Get
|
||||
DeviceLabel = 0x0082, // Get, Set
|
||||
FactoryDefaults = 0x0009, // Get, Set **
|
||||
SoftwareVersionLabel = 0x000c, // Get
|
||||
|
||||
// Category - DMX512 Setup
|
||||
DmxPersonality = 0x00e0, // Get, Set
|
||||
DmxPersonalityDescription = 0x00e1, // Get
|
||||
DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device
|
||||
SlotInfo = 0x0120, // Get
|
||||
SlotDescription = 0x0121, // Get
|
||||
DefaultSlotValue = 0x0122, // Get
|
||||
|
||||
// Category - Sensors
|
||||
// Category - Dimmer Settings
|
||||
// Category - Power/Lamp Settings
|
||||
// Category - Display Settings
|
||||
// Category - Configuration
|
||||
|
||||
// Category - Control
|
||||
IdentifyDevice = 0x1000, // Get, Set, Required
|
||||
ResetDevice = 0x1001, // Set
|
||||
PowerState = 0x1010, // Get, Set
|
||||
PerformSelftest = 0x1020, // Get, Set
|
||||
SelfTestDescription = 0x1021, // Get
|
||||
};
|
||||
|
||||
|
||||
enum RdmStatusTypes
|
||||
{
|
||||
StatusNone = 0x00,
|
||||
StatusGetLastMessage,
|
||||
StatusAdvisory,
|
||||
StatusWarning,
|
||||
StatusError,
|
||||
StatusAdvisoryCleared = 0x12,
|
||||
StatusWarningCleared,
|
||||
StatusErrorCleared,
|
||||
};
|
||||
|
||||
enum RdmProductCategory
|
||||
{
|
||||
CategoryNotDeclared = 0x0000,
|
||||
|
||||
// Fixtures - intended as source for illumination
|
||||
CategoryFixture = 0x0100,
|
||||
CategoryFixtureFixed = 0x0101,
|
||||
CategoryFixtureMovingYoke = 0x0102,
|
||||
CategoryFixtureMovingMirror = 0x0103,
|
||||
CategoryFixtureOther = 0x01ff,
|
||||
|
||||
// Fixture Accessories - add-ons to fixtures or projectors
|
||||
CategoryFixtureAccessory = 0x0200,
|
||||
CategoryFixtureAccessoryColor = 0x0201,
|
||||
CategoryFixtureAccessoryYoke = 0x0202,
|
||||
CategoryFixtureAccessoryMirror = 0x0203,
|
||||
CategoryFixtureAccessoryEffect = 0x0204,
|
||||
CategoryFixtureAccessoryBeam = 0x0205,
|
||||
CategoryFixtureAccessoryOther = 0x02ff,
|
||||
|
||||
// Projectors - Light source capable of producing
|
||||
// realistic images from another media
|
||||
CategoryProjector = 0x0300,
|
||||
CategoryProjectorFixed = 0x0301,
|
||||
CategoryProjectorMovingYoke = 0x0302,
|
||||
CategoryProjectorMovingMirror = 0x0303,
|
||||
CategoryProjectorOther = 0x03ff,
|
||||
|
||||
// Atmospheric Effect - earth/wind/fire
|
||||
CategoryAtmospheric = 0x0400,
|
||||
CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame
|
||||
CategoryAtmosphericPyro = 0x0402,
|
||||
CategoryAtmosphericOther = 0x04ff,
|
||||
|
||||
// Insensity Control (Specifically dimming equipment)
|
||||
CategoryDimmer = 0x0500,
|
||||
CategoryDimmer_AC_Incandescent = 0x0501,
|
||||
CategoryDimmer_AC_Fluorescent = 0x0502,
|
||||
CategoryDimmer_AC_Coldcathode = 0x0503,
|
||||
CategoryDimmer_AC_Nondim = 0x0504,
|
||||
CategoryDimmer_AC_Elv = 0x0505,
|
||||
CategoryDimmer_AC_Other = 0x0506,
|
||||
CategoryDimmer_DC_Level = 0x0507,
|
||||
CategoryDimmer_DC_PWM = 0x0508,
|
||||
CategoryDimmer_CS_LED = 0x0509,
|
||||
CategoryDimmer_Other = 0x05ff,
|
||||
|
||||
// Power control (Other than dimming equipment)
|
||||
CategoryPower = 0x0600,
|
||||
CategoryPowerControl = 0x0601,
|
||||
CategoryPowerSource = 0x0602,
|
||||
CategoryPowerOther = 0x06ff,
|
||||
|
||||
// Scenic Drive - Including motorized effects
|
||||
// unrelated to light source
|
||||
CategoryScenic = 0x0700,
|
||||
CategoryScenicDrive = 0x0701,
|
||||
CategoryScenicOther = 0x07ff,
|
||||
|
||||
// DMX Infrastructure, conversion and interfaces
|
||||
CategoryData = 0x0800,
|
||||
CategoryDataDistribution = 0x0801,
|
||||
CategoryDataConversion = 0x0802,
|
||||
CategoryDataOther = 0x08ff,
|
||||
|
||||
// Audio visual equipment
|
||||
Category_AV = 0x0900,
|
||||
Category_AV_Audio = 0x0901,
|
||||
Category_AV_Video = 0x0902,
|
||||
Category_AV_Other = 0x09ff,
|
||||
|
||||
// Parameter monitoring equipment
|
||||
CategoryMonitor = 0x0a00,
|
||||
CategoryMonitorACLinePower = 0x0a01,
|
||||
CategoryMonitorDCPower = 0x0a02,
|
||||
CategoryMonitorEnvironmental = 0x0a03,
|
||||
CategoryMonitorOther = 0x0aff,
|
||||
|
||||
// Controllers, backup devices
|
||||
CategoryControl = 0x7000,
|
||||
CategoryControlController = 0x7001,
|
||||
CategoryControlBackupdevice = 0x7002,
|
||||
CategoryControlOther = 0x70ff,
|
||||
|
||||
// Test equipment
|
||||
CategoryTest = 0x7100,
|
||||
CategoryTestEquipment = 0x7101,
|
||||
CategoryTestEquipmentOther = 0x71ff,
|
||||
|
||||
// Miscellaneous
|
||||
CategoryOther = 0x7fff,
|
||||
};
|
||||
|
||||
//
|
||||
// Product details not yet supported in
|
||||
// this library
|
||||
//
|
||||
enum RdmProductDetail
|
||||
{
|
||||
ProductDetailNotDeclared = 0x0000,
|
||||
};
|
||||
|
||||
// Only LSB
|
||||
enum RdmNackReasons
|
||||
{
|
||||
UnknownPid = 0x00,
|
||||
FormatError,
|
||||
HardwareFault,
|
||||
ProxyReject,
|
||||
WriteProtect,
|
||||
UnsupportedCmdClass,
|
||||
DataOutOfRange,
|
||||
BufferFull,
|
||||
PacketSizeUnsupported,
|
||||
SubDeviceOutOfRange,
|
||||
ProxyBufferFull
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define RDM_HDR_LEN 24 // RDM Message header length ** fixed
|
||||
#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231
|
||||
|
||||
|
||||
union RDM_Message
|
||||
{
|
||||
uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ];
|
||||
struct
|
||||
{
|
||||
uint8_t startCode; // 0 SC_RDM
|
||||
uint8_t subStartCode; // 1 SC_SUB_MESSAGE
|
||||
uint8_t msgLength; // 2 Range 24 - 255
|
||||
RDM_Uid dstUid; // 3-8 Destination UID
|
||||
RDM_Uid srcUid; // 9-14 Source UID (sender)
|
||||
uint8_t TN; // 15 Transaction number
|
||||
uint8_t portId; // 16 Port ID / Response type
|
||||
uint8_t msgCount; // 17
|
||||
uint16_t subDevice; // 18,19 0=root, 0xffff=all
|
||||
uint8_t CC; // 20 GET_COMMAND
|
||||
uint16_t PID; // 21,22 Parameter ID
|
||||
uint8_t PDL; // 23 Parameter Data length 1-231
|
||||
|
||||
uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length
|
||||
};
|
||||
};
|
||||
|
||||
union RDM_Checksum
|
||||
{
|
||||
uint16_t checksum;
|
||||
struct
|
||||
{
|
||||
uint8_t csl;
|
||||
uint8_t csh;
|
||||
};
|
||||
};
|
||||
|
||||
struct RDM_DiscUniqueBranchPD
|
||||
{
|
||||
RDM_Uid lbound;
|
||||
RDM_Uid hbound;
|
||||
};
|
||||
|
||||
struct RDM_DiscMuteUnMutePD
|
||||
{
|
||||
uint16_t ctrlField;
|
||||
|
||||
// Only for multiple ports
|
||||
// RDM_Uid bindingUid;
|
||||
};
|
||||
|
||||
struct RDM__DeviceInfoPD
|
||||
{
|
||||
uint8_t protocolVersionMajor;
|
||||
uint8_t protocolVersionMinor;
|
||||
uint16_t deviceModelId;
|
||||
uint16_t ProductCategory; // enum RdmProductCategory
|
||||
uint8_t SoftwareVersionId[4];
|
||||
uint16_t DMX512FootPrint;
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
uint16_t DMX512StartAddress;
|
||||
uint16_t SubDeviceCount;
|
||||
uint8_t SensorCount;
|
||||
};
|
||||
|
||||
struct RDM_DeviceGetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
};
|
||||
|
||||
struct RDM_DeviceSetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512Personality;
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_DEFINES_H_ */
|
||||
101
DMX_NeoPixels/examples/DMX_Slave/Rdm_Uid.h
Normal file
101
DMX_NeoPixels/examples/DMX_Slave/Rdm_Uid.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_UID_H_
|
||||
#define RDM_UID_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//
|
||||
//48 bit UID Representation to identify RDM transponders
|
||||
//
|
||||
struct RDM_Uid {
|
||||
|
||||
void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 )
|
||||
{
|
||||
m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8));
|
||||
m_id[1] = (uint8_t)m;
|
||||
m_id[2] = d1;
|
||||
m_id[3] = d2;
|
||||
m_id[4] = d3;
|
||||
m_id[5] = d4;
|
||||
}
|
||||
|
||||
void copy ( const RDM_Uid &orig )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
m_id[i] = orig.m_id[i];
|
||||
}
|
||||
|
||||
bool operator == ( const RDM_Uid & orig ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != orig.m_id[i] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != ( const RDM_Uid & orig ) const
|
||||
{
|
||||
return !(*this == orig);
|
||||
}
|
||||
|
||||
bool operator < ( const RDM_Uid & v ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] < v.m_id[i] );
|
||||
}
|
||||
|
||||
bool operator > ( const RDM_Uid & v )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] > v.m_id[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// match_mid = manufacturer id to match
|
||||
//
|
||||
bool isBroadcast ( uint8_t match_mid[2] )
|
||||
{
|
||||
// Check for genuine broadcast on device part
|
||||
for ( uint8_t i = 2; i < 6; i++ )
|
||||
if ( m_id[i] != 0xff )
|
||||
return false;
|
||||
|
||||
// Broadcast or manufacturer designated broadcast
|
||||
if ( (m_id[0] == 0xff && m_id[1] == 0xff) ||
|
||||
(m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) )
|
||||
return true;
|
||||
|
||||
// No broadcast
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_UID_H_ */
|
||||
1233
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.cpp
Normal file
1233
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.cpp
Normal file
File diff suppressed because it is too large
Load diff
383
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.h
Normal file
383
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Conceptinetics.h
Normal file
|
|
@ -0,0 +1,383 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Conceptinetics.h - DMX library for Arduino
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
This code has been tested using the following hardware:
|
||||
|
||||
- Arduino / Genuino UNO R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino MEGA2560 R3 using a CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD
|
||||
- Arduino / Genuino Leonardo using a CTC-DRA-13-R2 ISOLATED DMX-RDM SHIELD
|
||||
|
||||
- CTC-DRA-10-1 and CTC-DRA-10-R2 is the Non-isolated costs effective DMX-RDM shield
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CONCEPTINETICS_H_
|
||||
#define CONCEPTINETICS_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
#include "Rdm_Defines.h"
|
||||
|
||||
#define DMX_MAX_FRAMESIZE 513 // Startbyte + 512 Slots
|
||||
#define DMX_MIN_FRAMESIZE 2 // Startbyte + 1 Slot
|
||||
|
||||
#define DMX_MAX_FRAMECHANNELS 512 // Maxmim number of channer per frame
|
||||
|
||||
#define DMX_STARTCODE_SIZE 1 // Size of startcode in bytes
|
||||
|
||||
#define DMX_START_CODE 0x0 // Start code for a DMX frame
|
||||
#define RDM_START_CODE 0xcc // Start code for a RDM frame
|
||||
|
||||
// Uncomment to enable Inter slot delay ) (avg < 76uSec) ...
|
||||
// mimum is zero according to specification
|
||||
// #define DMX_IBG 10 // Inter slot time
|
||||
|
||||
// Speed your Arduino is running on in Hz.
|
||||
#define F_OSC 16000000UL
|
||||
|
||||
// DMX Baudrate, this should be 250000
|
||||
#define DMX_BAUD_RATE 250000
|
||||
|
||||
// The baudrate used to automaticly generate a break within
|
||||
// your ISR.. make it lower to generate longer breaks
|
||||
//#define DMX_BREAK_RATE 99900
|
||||
|
||||
// 2017, Feb 28: Set to appox 176us
|
||||
#define DMX_BREAK_RATE 49950
|
||||
|
||||
// Tabel 3-2 ANSI_E1-20-2010
|
||||
// Minimum time to allow the datalink to 'turn arround'
|
||||
#define MIN_RESPONDER_PACKET_SPACING_USEC 176 /*176*/
|
||||
|
||||
// Define which serial port to use as DMX port, only one can be
|
||||
// selected at the time by uncommenting one of the following
|
||||
// lines
|
||||
#define USE_DMX_SERIAL_0
|
||||
//#define USE_DMX_SERIAL_1
|
||||
//#define USE_DMX_SERIAL_2
|
||||
//#define USE_DMX_SERIAL_3
|
||||
|
||||
namespace dmx
|
||||
{
|
||||
enum dmxState
|
||||
{
|
||||
dmxUnknown,
|
||||
dmxStartByte,
|
||||
dmxWaitStartAddress,
|
||||
dmxData,
|
||||
dmxFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum rdmState
|
||||
{
|
||||
rdmUnknown,
|
||||
rdmStartByte,
|
||||
rdmSubStartCode,
|
||||
rdmMessageLength,
|
||||
rdmData,
|
||||
rdmChecksumHigh,
|
||||
rdmChecksumLow,
|
||||
rdmFrameReady,
|
||||
};
|
||||
};
|
||||
|
||||
struct IFrameBuffer
|
||||
{
|
||||
virtual uint16_t getBufferSize ( void ) = 0;
|
||||
|
||||
virtual uint8_t getSlotValue ( uint16_t index ) = 0;
|
||||
virtual void setSlotValue ( uint16_t index, uint8_t value ) = 0;
|
||||
};
|
||||
|
||||
class DMX_FrameBuffer : IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor buffersize = 1-513
|
||||
//
|
||||
DMX_FrameBuffer ( uint16_t buffer_size );
|
||||
DMX_FrameBuffer ( DMX_FrameBuffer &buffer );
|
||||
~DMX_FrameBuffer ( void );
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void setSlotRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
private:
|
||||
|
||||
uint8_t *m_refcount;
|
||||
uint16_t m_bufferSize;
|
||||
uint8_t *m_buffer;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Master controller
|
||||
//
|
||||
class DMX_Master
|
||||
{
|
||||
public:
|
||||
// Run the DMX master from a pre allocated frame buffer which
|
||||
// you have fully under your own control
|
||||
DMX_Master ( DMX_FrameBuffer &buffer, int readEnablePin );
|
||||
|
||||
// Run the DMX master by giving a predefined maximum number of
|
||||
// channels to support
|
||||
DMX_Master ( uint16_t maxChannel, int readEnablePin );
|
||||
|
||||
~DMX_Master ( void );
|
||||
|
||||
void enable ( void ); // Start transmitting
|
||||
void disable ( void ); // Stop transmitting
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
// Update channel values
|
||||
void setChannelValue ( uint16_t channel, uint8_t value );
|
||||
void setChannelRange ( uint16_t start, uint16_t end, uint8_t value );
|
||||
|
||||
public:
|
||||
//
|
||||
// Manual control over the break period
|
||||
//
|
||||
void setAutoBreakMode ( void ); // Generated from ISR
|
||||
void setManualBreakMode ( void ); // Generate manually
|
||||
|
||||
uint8_t autoBreakEnabled ( void );
|
||||
|
||||
// We are waiting for a manual break to be generated
|
||||
uint8_t waitingBreak ( void );
|
||||
|
||||
// Generate break and start transmission of frame
|
||||
void breakAndContinue ( uint8_t breakLength_us = 100 );
|
||||
|
||||
|
||||
protected:
|
||||
void setStartCode ( uint8_t value );
|
||||
|
||||
|
||||
private:
|
||||
DMX_FrameBuffer m_frameBuffer;
|
||||
uint8_t m_autoBreak;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// DMX Slave controller
|
||||
//
|
||||
class DMX_Slave : public DMX_FrameBuffer
|
||||
{
|
||||
public:
|
||||
DMX_Slave ( DMX_FrameBuffer &buffer, int readEnablePin = -1 );
|
||||
|
||||
// nrChannels is the consecutive DMX512 slots required
|
||||
// to operate this slave device
|
||||
DMX_Slave ( uint16_t nrChannels, int readEnablePin = -1 );
|
||||
|
||||
~DMX_Slave ( void );
|
||||
|
||||
void enable ( void ); // Enable receiver
|
||||
void disable ( void ); // Disable receiver
|
||||
|
||||
|
||||
// Get reference to the internal framebuffer
|
||||
DMX_FrameBuffer &getBuffer ( void );
|
||||
|
||||
uint8_t getChannelValue ( uint16_t channel );
|
||||
|
||||
uint16_t getStartAddress ( void );
|
||||
void setStartAddress ( uint16_t );
|
||||
|
||||
|
||||
// Process incoming byte from USART
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Register on receive complete callback in case
|
||||
// of time critical applications
|
||||
void onReceiveComplete ( void (*func)(unsigned short) );
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
private:
|
||||
uint16_t m_startAddress; // Slave start address
|
||||
dmx::dmxState m_state;
|
||||
|
||||
static void (*event_onFrameReceived)(unsigned short channelsReceived);
|
||||
};
|
||||
|
||||
|
||||
class RDM_FrameBuffer : public IFrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// Constructor
|
||||
//
|
||||
RDM_FrameBuffer ( void ) {};
|
||||
~RDM_FrameBuffer ( void ) {};
|
||||
|
||||
uint16_t getBufferSize ( void );
|
||||
|
||||
uint8_t getSlotValue ( uint16_t index );
|
||||
void setSlotValue ( uint16_t index, uint8_t value );
|
||||
void clear ( void );
|
||||
|
||||
uint8_t &operator[] ( uint16_t index );
|
||||
|
||||
public: // functions to provide access from USART
|
||||
// Process incoming byte from USART,
|
||||
// returns false when no more data is accepted
|
||||
bool processIncoming ( uint8_t val, bool first = false );
|
||||
|
||||
// Process outgoing byte to USART
|
||||
// returns false when no more data is available
|
||||
bool fetchOutgoing ( volatile uint8_t *udr, bool first = false );
|
||||
|
||||
protected:
|
||||
// Process received frame
|
||||
virtual void processFrame ( void ) = 0;
|
||||
|
||||
//private:
|
||||
protected:
|
||||
rdm::rdmState m_state; // State for pushing the message in
|
||||
RDM_Message m_msg;
|
||||
RDM_Checksum m_csRecv; // Checksum received in rdm message
|
||||
};
|
||||
|
||||
//
|
||||
// RDM_Responder
|
||||
//
|
||||
class RDM_Responder : public RDM_FrameBuffer
|
||||
{
|
||||
public:
|
||||
//
|
||||
// m = manufacturer id (16bits)
|
||||
// d1-d4 = device id (32bits)
|
||||
//
|
||||
RDM_Responder ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4, DMX_Slave &slave);
|
||||
~RDM_Responder ( void );
|
||||
|
||||
void setDeviceInfo
|
||||
(
|
||||
uint16_t deviceModelId,
|
||||
rdm::RdmProductCategory productCategory,
|
||||
uint8_t personalities = 1,
|
||||
uint8_t personality = 1
|
||||
)
|
||||
{
|
||||
m_DeviceModelId = deviceModelId;
|
||||
m_ProductCategory = productCategory;
|
||||
m_Personalities = personalities;
|
||||
m_Personality = personality;
|
||||
};
|
||||
|
||||
//
|
||||
// Set vendor software version id
|
||||
//
|
||||
// v1 = MOST SIGNIFICANT
|
||||
// v2...
|
||||
// v3...
|
||||
// v4 = LEAST SIGNIFICANT
|
||||
//
|
||||
void setSoftwareVersionId ( uint8_t v1, uint8_t v2, uint8_t v3, uint8_t v4 )
|
||||
{
|
||||
m_SoftwareVersionId[0] = v1;
|
||||
m_SoftwareVersionId[1] = v2;
|
||||
m_SoftwareVersionId[2] = v3;
|
||||
m_SoftwareVersionId[3] = v4;
|
||||
}
|
||||
|
||||
// Currently no sensors and subdevices supported
|
||||
// void AddSensor ( void );
|
||||
// void AddSubDevice ( void );
|
||||
|
||||
uint8_t getPersonality ( void ) { return m_Personality; };
|
||||
void setPersonality ( uint8_t personality ) { m_Personality = personality; };
|
||||
|
||||
// Register on identify device event handler
|
||||
void onIdentifyDevice ( void (*func)(bool) );
|
||||
void onDeviceLabelChanged ( void (*func) (const char*, uint8_t) );
|
||||
void onDMXStartAddressChanged ( void (*func) (uint16_t) );
|
||||
void onDMXPersonalityChanged ( void (*func) (uint8_t) );
|
||||
|
||||
|
||||
// Set the device label
|
||||
void setDeviceLabel ( const char *label, size_t len );
|
||||
|
||||
// Enable, Disable rdm responder
|
||||
void enable ( void ) { m_rdmStatus.enabled = true; m_rdmStatus.mute = false; };
|
||||
void disable ( void ) { m_rdmStatus.enabled = false; };
|
||||
|
||||
union
|
||||
{
|
||||
uint8_t raw;
|
||||
struct
|
||||
{
|
||||
uint8_t mute:1;
|
||||
uint8_t ident:1;
|
||||
uint8_t enabled:1; // Rdm responder enable/disable
|
||||
};
|
||||
} m_rdmStatus;
|
||||
|
||||
|
||||
protected:
|
||||
virtual void processFrame ( void );
|
||||
|
||||
// Discovery to unque brach packets only requires
|
||||
// the data part of the packet to be transmitted
|
||||
// without breaks or header
|
||||
void repondDiscUniqueBranch ( void );
|
||||
|
||||
// Helpers for generating response packets which
|
||||
// have larger datafields
|
||||
void populateDeviceInfo ( void );
|
||||
|
||||
private:
|
||||
RDM_Uid m_devid; // Holds our unique device ID
|
||||
uint8_t m_Personalities; // The total number of supported personalities
|
||||
uint8_t m_Personality; // The currently active personality
|
||||
uint16_t m_DeviceModelId;
|
||||
uint8_t m_SoftwareVersionId[4]; // 32 bit Software version
|
||||
rdm::RdmProductCategory m_ProductCategory;
|
||||
|
||||
char m_deviceLabel[32]; // Device label
|
||||
|
||||
static void (*event_onIdentifyDevice)(bool);
|
||||
static void (*event_onDeviceLabelChanged)(const char*, uint8_t);
|
||||
static void (*event_onDMXStartAddressChanged)(uint16_t);
|
||||
static void (*event_onDMXPersonalityChanged)(uint8_t);
|
||||
};
|
||||
|
||||
|
||||
#endif /* CONCEPTINETICS_H_ */
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
|
||||
|
||||
#include <Conceptinetics.h>
|
||||
#include "Conceptinetics.h"
|
||||
|
||||
//
|
||||
// CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS
|
||||
|
|
|
|||
315
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Defines.h
Normal file
315
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Defines.h
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Defines.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_DEFINES_H_
|
||||
#define RDM_DEFINES_H_
|
||||
|
||||
#include "Rdm_Uid.h"
|
||||
|
||||
#define RDM_MAX_DEVICELABEL_LENGTH 32
|
||||
|
||||
namespace rdm
|
||||
{
|
||||
enum RdmCommandClass
|
||||
{
|
||||
DiscoveryCommand = 0x10,
|
||||
DiscoveryCommandResponse,
|
||||
GetCommand = 0x20,
|
||||
GetCommandResponse,
|
||||
SetCommand = 0x30,
|
||||
SetCommandResponse,
|
||||
};
|
||||
|
||||
enum RdmResponseTypes
|
||||
{
|
||||
ResponseTypeAck = 0x00,
|
||||
ResponseTypeAckTimer,
|
||||
ResponseTypeNackReason,
|
||||
ResponseTypeAckOverflow, // Additional response data available (see spec)
|
||||
};
|
||||
|
||||
enum RdmParameters
|
||||
{
|
||||
// Category - Network Management
|
||||
DiscUniqueBranch = 0x0001, // Required
|
||||
DiscMute = 0x0002, // Required
|
||||
DiscUnMute = 0x0003, // Required
|
||||
|
||||
CommsStatus = 0x0015, // Get,Set
|
||||
|
||||
// Category - Status Collection
|
||||
QueuedMessage = 0x0020, // Get [enum RdmStatusTypes]
|
||||
StatusMessages = 0x0030, // Get [enum RdmStatusTypes]
|
||||
StatusIdDescription = 0x0031, // Get
|
||||
ClearStatusId = 0x0032, // Set
|
||||
SubDeviceStatusReportThreshold = 0x0033, // Get, Set [enum RdmStatusTypes]
|
||||
|
||||
// Category - RDM Information
|
||||
// ** Only required if supporting parameters
|
||||
// beyond the minimum required set
|
||||
SupportedParameters = 0x0005, // Get, **Required
|
||||
ParameterDescription = 0x0051, // Get, **Required
|
||||
|
||||
// Category = Product Information
|
||||
DeviceInfo = 0x0060, // Get, Required
|
||||
ProductDetailIdList = 0x0070, // Get
|
||||
DeviceModelDescription = 0x0080, // Get
|
||||
ManufacturerLabel = 0x0081, // Get
|
||||
DeviceLabel = 0x0082, // Get, Set
|
||||
FactoryDefaults = 0x0009, // Get, Set **
|
||||
SoftwareVersionLabel = 0x000c, // Get
|
||||
|
||||
// Category - DMX512 Setup
|
||||
DmxPersonality = 0x00e0, // Get, Set
|
||||
DmxPersonalityDescription = 0x00e1, // Get
|
||||
DmxStartAddress = 0x00f0, // Get, Set ** Required if DMX device
|
||||
SlotInfo = 0x0120, // Get
|
||||
SlotDescription = 0x0121, // Get
|
||||
DefaultSlotValue = 0x0122, // Get
|
||||
|
||||
// Category - Sensors
|
||||
// Category - Dimmer Settings
|
||||
// Category - Power/Lamp Settings
|
||||
// Category - Display Settings
|
||||
// Category - Configuration
|
||||
|
||||
// Category - Control
|
||||
IdentifyDevice = 0x1000, // Get, Set, Required
|
||||
ResetDevice = 0x1001, // Set
|
||||
PowerState = 0x1010, // Get, Set
|
||||
PerformSelftest = 0x1020, // Get, Set
|
||||
SelfTestDescription = 0x1021, // Get
|
||||
};
|
||||
|
||||
|
||||
enum RdmStatusTypes
|
||||
{
|
||||
StatusNone = 0x00,
|
||||
StatusGetLastMessage,
|
||||
StatusAdvisory,
|
||||
StatusWarning,
|
||||
StatusError,
|
||||
StatusAdvisoryCleared = 0x12,
|
||||
StatusWarningCleared,
|
||||
StatusErrorCleared,
|
||||
};
|
||||
|
||||
enum RdmProductCategory
|
||||
{
|
||||
CategoryNotDeclared = 0x0000,
|
||||
|
||||
// Fixtures - intended as source for illumination
|
||||
CategoryFixture = 0x0100,
|
||||
CategoryFixtureFixed = 0x0101,
|
||||
CategoryFixtureMovingYoke = 0x0102,
|
||||
CategoryFixtureMovingMirror = 0x0103,
|
||||
CategoryFixtureOther = 0x01ff,
|
||||
|
||||
// Fixture Accessories - add-ons to fixtures or projectors
|
||||
CategoryFixtureAccessory = 0x0200,
|
||||
CategoryFixtureAccessoryColor = 0x0201,
|
||||
CategoryFixtureAccessoryYoke = 0x0202,
|
||||
CategoryFixtureAccessoryMirror = 0x0203,
|
||||
CategoryFixtureAccessoryEffect = 0x0204,
|
||||
CategoryFixtureAccessoryBeam = 0x0205,
|
||||
CategoryFixtureAccessoryOther = 0x02ff,
|
||||
|
||||
// Projectors - Light source capable of producing
|
||||
// realistic images from another media
|
||||
CategoryProjector = 0x0300,
|
||||
CategoryProjectorFixed = 0x0301,
|
||||
CategoryProjectorMovingYoke = 0x0302,
|
||||
CategoryProjectorMovingMirror = 0x0303,
|
||||
CategoryProjectorOther = 0x03ff,
|
||||
|
||||
// Atmospheric Effect - earth/wind/fire
|
||||
CategoryAtmospheric = 0x0400,
|
||||
CategoryAtmosphericEffect = 0x0401, // Fogger, Hazer, Flame
|
||||
CategoryAtmosphericPyro = 0x0402,
|
||||
CategoryAtmosphericOther = 0x04ff,
|
||||
|
||||
// Insensity Control (Specifically dimming equipment)
|
||||
CategoryDimmer = 0x0500,
|
||||
CategoryDimmer_AC_Incandescent = 0x0501,
|
||||
CategoryDimmer_AC_Fluorescent = 0x0502,
|
||||
CategoryDimmer_AC_Coldcathode = 0x0503,
|
||||
CategoryDimmer_AC_Nondim = 0x0504,
|
||||
CategoryDimmer_AC_Elv = 0x0505,
|
||||
CategoryDimmer_AC_Other = 0x0506,
|
||||
CategoryDimmer_DC_Level = 0x0507,
|
||||
CategoryDimmer_DC_PWM = 0x0508,
|
||||
CategoryDimmer_CS_LED = 0x0509,
|
||||
CategoryDimmer_Other = 0x05ff,
|
||||
|
||||
// Power control (Other than dimming equipment)
|
||||
CategoryPower = 0x0600,
|
||||
CategoryPowerControl = 0x0601,
|
||||
CategoryPowerSource = 0x0602,
|
||||
CategoryPowerOther = 0x06ff,
|
||||
|
||||
// Scenic Drive - Including motorized effects
|
||||
// unrelated to light source
|
||||
CategoryScenic = 0x0700,
|
||||
CategoryScenicDrive = 0x0701,
|
||||
CategoryScenicOther = 0x07ff,
|
||||
|
||||
// DMX Infrastructure, conversion and interfaces
|
||||
CategoryData = 0x0800,
|
||||
CategoryDataDistribution = 0x0801,
|
||||
CategoryDataConversion = 0x0802,
|
||||
CategoryDataOther = 0x08ff,
|
||||
|
||||
// Audio visual equipment
|
||||
Category_AV = 0x0900,
|
||||
Category_AV_Audio = 0x0901,
|
||||
Category_AV_Video = 0x0902,
|
||||
Category_AV_Other = 0x09ff,
|
||||
|
||||
// Parameter monitoring equipment
|
||||
CategoryMonitor = 0x0a00,
|
||||
CategoryMonitorACLinePower = 0x0a01,
|
||||
CategoryMonitorDCPower = 0x0a02,
|
||||
CategoryMonitorEnvironmental = 0x0a03,
|
||||
CategoryMonitorOther = 0x0aff,
|
||||
|
||||
// Controllers, backup devices
|
||||
CategoryControl = 0x7000,
|
||||
CategoryControlController = 0x7001,
|
||||
CategoryControlBackupdevice = 0x7002,
|
||||
CategoryControlOther = 0x70ff,
|
||||
|
||||
// Test equipment
|
||||
CategoryTest = 0x7100,
|
||||
CategoryTestEquipment = 0x7101,
|
||||
CategoryTestEquipmentOther = 0x71ff,
|
||||
|
||||
// Miscellaneous
|
||||
CategoryOther = 0x7fff,
|
||||
};
|
||||
|
||||
//
|
||||
// Product details not yet supported in
|
||||
// this library
|
||||
//
|
||||
enum RdmProductDetail
|
||||
{
|
||||
ProductDetailNotDeclared = 0x0000,
|
||||
};
|
||||
|
||||
// Only LSB
|
||||
enum RdmNackReasons
|
||||
{
|
||||
UnknownPid = 0x00,
|
||||
FormatError,
|
||||
HardwareFault,
|
||||
ProxyReject,
|
||||
WriteProtect,
|
||||
UnsupportedCmdClass,
|
||||
DataOutOfRange,
|
||||
BufferFull,
|
||||
PacketSizeUnsupported,
|
||||
SubDeviceOutOfRange,
|
||||
ProxyBufferFull
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
#define RDM_HDR_LEN 24 // RDM Message header length ** fixed
|
||||
#define RDM_PD_MAXLEN 32 // RDM Maximum parameter data length 1 - 231
|
||||
|
||||
|
||||
union RDM_Message
|
||||
{
|
||||
uint8_t d[ RDM_HDR_LEN + RDM_PD_MAXLEN ];
|
||||
struct
|
||||
{
|
||||
uint8_t startCode; // 0 SC_RDM
|
||||
uint8_t subStartCode; // 1 SC_SUB_MESSAGE
|
||||
uint8_t msgLength; // 2 Range 24 - 255
|
||||
RDM_Uid dstUid; // 3-8 Destination UID
|
||||
RDM_Uid srcUid; // 9-14 Source UID (sender)
|
||||
uint8_t TN; // 15 Transaction number
|
||||
uint8_t portId; // 16 Port ID / Response type
|
||||
uint8_t msgCount; // 17
|
||||
uint16_t subDevice; // 18,19 0=root, 0xffff=all
|
||||
uint8_t CC; // 20 GET_COMMAND
|
||||
uint16_t PID; // 21,22 Parameter ID
|
||||
uint8_t PDL; // 23 Parameter Data length 1-231
|
||||
|
||||
uint8_t PD[RDM_PD_MAXLEN]; // Parameter Data ... variable length
|
||||
};
|
||||
};
|
||||
|
||||
union RDM_Checksum
|
||||
{
|
||||
uint16_t checksum;
|
||||
struct
|
||||
{
|
||||
uint8_t csl;
|
||||
uint8_t csh;
|
||||
};
|
||||
};
|
||||
|
||||
struct RDM_DiscUniqueBranchPD
|
||||
{
|
||||
RDM_Uid lbound;
|
||||
RDM_Uid hbound;
|
||||
};
|
||||
|
||||
struct RDM_DiscMuteUnMutePD
|
||||
{
|
||||
uint16_t ctrlField;
|
||||
|
||||
// Only for multiple ports
|
||||
// RDM_Uid bindingUid;
|
||||
};
|
||||
|
||||
struct RDM__DeviceInfoPD
|
||||
{
|
||||
uint8_t protocolVersionMajor;
|
||||
uint8_t protocolVersionMinor;
|
||||
uint16_t deviceModelId;
|
||||
uint16_t ProductCategory; // enum RdmProductCategory
|
||||
uint8_t SoftwareVersionId[4];
|
||||
uint16_t DMX512FootPrint;
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
uint16_t DMX512StartAddress;
|
||||
uint16_t SubDeviceCount;
|
||||
uint8_t SensorCount;
|
||||
};
|
||||
|
||||
struct RDM_DeviceGetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512CurrentPersonality;
|
||||
uint8_t DMX512NumberPersonalities;
|
||||
};
|
||||
|
||||
struct RDM_DeviceSetPersonality_PD
|
||||
{
|
||||
uint8_t DMX512Personality;
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_DEFINES_H_ */
|
||||
101
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Uid.h
Normal file
101
DMX_NeoPixels/examples/DMX_Slave_Signal_Timeout/Rdm_Uid.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// SPDX-FileCopyrightText: 2013 W.A. van der Meeren <danny@illogic.nl>
|
||||
//
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
/*
|
||||
Rdm_Uid.h - DMX library for Arduino with RDM (Remote Device Management) support
|
||||
Copyright (c) 2013 W.A. van der Meeren <danny@illogic.nl>. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RDM_UID_H_
|
||||
#define RDM_UID_H_
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
//
|
||||
//48 bit UID Representation to identify RDM transponders
|
||||
//
|
||||
struct RDM_Uid {
|
||||
|
||||
void Initialize ( uint16_t m, uint8_t d1, uint8_t d2, uint8_t d3, uint8_t d4 )
|
||||
{
|
||||
m_id[0] = ((uint8_t) (((uint16_t) (m)) >> 8));
|
||||
m_id[1] = (uint8_t)m;
|
||||
m_id[2] = d1;
|
||||
m_id[3] = d2;
|
||||
m_id[4] = d3;
|
||||
m_id[5] = d4;
|
||||
}
|
||||
|
||||
void copy ( const RDM_Uid &orig )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
m_id[i] = orig.m_id[i];
|
||||
}
|
||||
|
||||
bool operator == ( const RDM_Uid & orig ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != orig.m_id[i] )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator != ( const RDM_Uid & orig ) const
|
||||
{
|
||||
return !(*this == orig);
|
||||
}
|
||||
|
||||
bool operator < ( const RDM_Uid & v ) const
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] < v.m_id[i] );
|
||||
}
|
||||
|
||||
bool operator > ( const RDM_Uid & v )
|
||||
{
|
||||
for ( uint8_t i = 0; i < 6; i++ )
|
||||
if ( m_id[i] != v.m_id[i] )
|
||||
return ( m_id[i] > v.m_id[i] );
|
||||
}
|
||||
|
||||
//
|
||||
// match_mid = manufacturer id to match
|
||||
//
|
||||
bool isBroadcast ( uint8_t match_mid[2] )
|
||||
{
|
||||
// Check for genuine broadcast on device part
|
||||
for ( uint8_t i = 2; i < 6; i++ )
|
||||
if ( m_id[i] != 0xff )
|
||||
return false;
|
||||
|
||||
// Broadcast or manufacturer designated broadcast
|
||||
if ( (m_id[0] == 0xff && m_id[1] == 0xff) ||
|
||||
(m_id[0] == match_mid[0] && m_id[1] == match_mid[1]) )
|
||||
return true;
|
||||
|
||||
// No broadcast
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t m_id[6]; //16bit manufacturer id + 32 bits device id
|
||||
};
|
||||
|
||||
|
||||
#endif /* RDM_UID_H_ */
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue