Compare commits

..

No commits in common. "main" and "dmx_cleanup" have entirely different histories.

735 changed files with 2281 additions and 237487 deletions

View file

@ -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", "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"]
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"]
runs-on: ubuntu-latest
if: needs.check-if-needed.outputs.answer == 'true'
needs: check-if-needed
@ -97,8 +97,6 @@ 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 }}

View file

@ -1,47 +0,0 @@
// 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);
}

View file

@ -1,38 +0,0 @@
# 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)

View file

@ -1,43 +0,0 @@
# 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

View file

@ -1,40 +0,0 @@
// 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);
}

View file

@ -1,60 +0,0 @@
// 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);
}
}

View file

@ -1,30 +0,0 @@
// 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);
}

View file

@ -1,37 +0,0 @@
# 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)

View file

@ -1,48 +0,0 @@
# 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)

View file

@ -109,32 +109,16 @@ 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());
}
}

View file

@ -1,105 +0,0 @@
// 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();
}

View file

@ -1,10 +0,0 @@
// 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);

View file

@ -3,8 +3,6 @@
"""
CircuitPython Adafruit IO Example for BME280 and LC709203 Sensors
"""
from os import getenv
import time
import ssl
import alarm
@ -16,21 +14,11 @@ 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
# 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."
)
try:
from secrets import secrets
except ImportError:
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
raise
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
@ -90,9 +78,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(ssid, password)
print(f"Connected to {ssid}!")
print(f"IP: {wifi.radio.ipv4_address}")
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to {}!".format(secrets["ssid"]))
print("IP:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
@ -102,6 +90,12 @@ 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)

View file

@ -5,8 +5,8 @@ CircuitPython Simple Example for BME280 and LC709203 Sensors
"""
import time
import board
from adafruit_lc709203f import LC709203F, PackSize
from adafruit_bme280 import basic as adafruit_bme280
from adafruit_lc709203f import LC709203F, PackSize
# Create sensor objects, using the board's default I2C bus.
i2c = board.I2C() # uses board.SCL and board.SDA

View file

@ -1,110 +0,0 @@
# 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.

View file

@ -3,8 +3,6 @@
"""
CircuitPython Adafruit IO Example for LC709203 Sensor
"""
from os import getenv
import time
import ssl
import alarm
@ -15,21 +13,11 @@ import socketpool
import adafruit_requests
from adafruit_io.adafruit_io import IO_HTTP
from adafruit_lc709203f import LC709203F, PackSize
# 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."
)
try:
from secrets import secrets
except ImportError:
print("WiFi and Adafruit IO credentials are kept in secrets.py, please add them there!")
raise
# Duration of sleep in seconds. Default is 600 seconds (10 minutes).
# Feather will sleep for this duration between sensor readings / sending data to AdafruitIO
@ -70,9 +58,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(ssid, password)
print(f"Connected to {ssid}!")
print(f"IP: {wifi.radio.ipv4_address}")
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to {}!".format(secrets["ssid"]))
print("IP:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
@ -82,6 +70,12 @@ 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)

View file

@ -3,8 +3,6 @@
"""
CircuitPython GitHub Stars viewer
"""
from os import getenv
import time
import ssl
import wifi
@ -15,17 +13,12 @@ from adafruit_display_text import bitmap_label
from adafruit_bitmap_font import bitmap_font
import adafruit_requests
# 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."
)
# 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
display = board.DISPLAY
@ -45,10 +38,10 @@ group.append(text_area)
display.root_group = group
# Connect to WiFi
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}")
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)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())

View file

@ -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("booploop.wav", "rb") as wave_file:
with open("chikken.wav", "rb") as wave_file:
wav = audiocore.WaveFile(wave_file)
print("Playing wav file!")

View file

@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MIT
from os import getenv
import time
import board
import busio
@ -23,23 +22,15 @@ USE_CELSIUS = False
# Interval the sensor publishes to Adafruit IO, in minutes
PUBLISH_INTERVAL = 10
# 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."
)
### 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
# AirLift FeatherWing
esp32_cs = DigitalInOut(board.D13)
esp32_reset = DigitalInOut(board.D12)
@ -47,8 +38,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_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
# Connect to a PM2.5 sensor over UART
reset_pin = None
@ -151,7 +142,7 @@ def read_bme(is_celsius=False):
# Create an instance of the Adafruit IO HTTP client
io = IO_HTTP(aio_username, aio_key, wifi)
io = IO_HTTP(secrets["aio_user"], secrets["aio_key"], wifi)
# Describes feeds used to hold Adafruit IO data
feed_aqi = io.get_feed("air-quality-sensor.aqi")
@ -159,11 +150,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 settings.toml file
# Set up location metadata from secrets.py file
location_metadata = {
"lat": getenv("latitude"),
"lon": getenv("longitude"),
"ele": getenv("elevation"),
"lat": secrets["latitude"],
"lon": secrets["longitude"],
"ele": secrets["elevation"],
}
elapsed_minutes = 0

View file

@ -14,20 +14,13 @@ from adafruit_esp32spi import adafruit_esp32spi_wifimanager
import adafruit_minimqtt.adafruit_minimqtt as MQTT
# Get WiFi details, ensure these are setup in settings.toml
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 ###
secrets = {
"ssid" : os.getenv("CIRCUITPY_WIFI_SSID"),
"password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"),
}
# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
@ -41,19 +34,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_pixel = neopixel.NeoPixel(
status_light = neopixel.NeoPixel(
board.NEOPIXEL, 1, brightness=0.2
) # Uncomment for Most Boards
"""Uncomment below for ItsyBitsy M4"""
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
# status_light = 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_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
# Set up a pin for controlling the relay
power_pin = DigitalInOut(board.D3)

View file

@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MIT
from os import getenv
import time
import board
import busio
@ -15,21 +14,6 @@ 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
@ -38,6 +22,13 @@ 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)
@ -51,19 +42,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_pixel = neopixel.NeoPixel(
status_light = neopixel.NeoPixel(
board.NEOPIXEL, 1, brightness=0.2
) # Uncomment for Most Boards
"""Uncomment below for ItsyBitsy M4"""
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
# status_light = 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_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
# Set up a pin for controlling the relay
power_pin = DigitalInOut(board.D3)
@ -76,10 +67,10 @@ sensor = adafruit_bh1750.BH1750(i2c)
### Feeds ###
# Set up a feed named Relay for subscribing to the relay feed on Adafruit IO
feed_relay = f"{aio_username}/feeds/relay"
feed_relay = secrets["aio_username"] + "/feeds/relay"
# Set up a feed named status for subscribing to the status feed on Adafruit IO
feed_status = f"{aio_username}/feeds/status"
feed_status = secrets["aio_username"] + "/feeds/status"
### Code ###
@ -131,8 +122,8 @@ ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
# Set up a MiniMQTT Client
client = MQTT.MQTT(
broker="io.adafruit.com",
username=aio_username,
password=aio_key,
username=secrets["aio_username"],
password=secrets["aio_key"],
socket_pool=pool,
ssl_context=ssl_context,
)

View file

@ -1,27 +0,0 @@
{
"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"
}
}
]
}

View file

@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MIT
from os import getenv
import time
import board
import busio
@ -14,23 +13,15 @@ import neopixel
import adafruit_minimqtt.adafruit_minimqtt as MQTT
from adafruit_io.adafruit_io import IO_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."
)
### 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)
@ -44,19 +35,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_pixel = neopixel.NeoPixel(
status_light = neopixel.NeoPixel(
board.NEOPIXEL, 1, brightness=0.2
) # Uncomment for Most Boards
"""Uncomment below for ItsyBitsy M4"""
# status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
# status_light = 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_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
# Set up a pin for controlling the relay
power_pin = DigitalInOut(board.D3)
@ -98,11 +89,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 == "1":
print("Received 1 - turning outlet ON")
if message == "morning":
print("Morning - turning outlet ON")
power_pin.value = True
elif message == "0":
print("Received 0 - turning outlet OFF")
elif message == "night":
print("Night - turning outlet OFF")
power_pin.value = False
else:
print("Unexpected value received on relay feed.")
@ -119,8 +110,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=aio_username,
password=aio_key,
username=secrets["aio_username"],
password=secrets["aio_key"],
socket_pool=pool,
ssl_context=ssl_context,
)

View file

@ -99,7 +99,7 @@ while True:
time.sleep(30)
# Stepper 1
if not st1.is_alive() and int(stepper_start.value):
if not st1.isAlive() 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.is_alive() and int(stepper_start.value):
if not st2.isAlive() 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

View file

@ -1,83 +0,0 @@
{
"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
}
]
}

View file

@ -1,72 +0,0 @@
<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 %}

View file

@ -1,71 +0,0 @@
// 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();
}

View file

@ -1,36 +0,0 @@
# 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)
)

View file

@ -7,7 +7,6 @@ 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
@ -15,17 +14,12 @@ import adafruit_connection_manager
import adafruit_requests
from adafruit_esp32spi import adafruit_esp32spi
# 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."
)
# 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
print("Arduino Nano RP2040 Connect webclient test")
@ -57,7 +51,7 @@ for ap in esp.scan_networks():
print("Connecting to AP...")
while not esp.is_connected:
try:
esp.connect_AP(ssid, password)
esp.connect_AP(secrets["ssid"], secrets["password"])
except RuntimeError as e:
print("could not connect to AP, retrying: ", e)
continue

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

View file

@ -1,161 +0,0 @@
# 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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

View file

@ -1,109 +0,0 @@
-----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-----

View file

@ -1,7 +1,6 @@
# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
from os import getenv
import time
import json
import board
@ -39,20 +38,15 @@ nau7802 = NAU7802(board.STEMMA_I2C(), address=0x2A, active_channels=2)
nau7802.gain = 128
enabled = nau7802.enable(True)
# 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."
)
# 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
print("Connecting to WiFi...")
wifi.radio.connect(ssid, password)
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("Connected to WiFi!")
# check system time
@ -71,7 +65,7 @@ else:
esp = None
pool = socketpool.SocketPool(wifi.radio)
device = IoTCentralDevice(
pool, esp, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key")
pool, esp, secrets['id_scope'], secrets['device_id'], secrets['device_primary_key']
)
display.fill(0)
display.print("DIALING*")
@ -197,8 +191,6 @@ avg_oz = []
values = []
val_offset = 0
avg_values = []
the_ounces = 0
the_grams = 0
# initial reading from the scale
for w in range(5):

View file

@ -1,44 +0,0 @@
// 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() {
}

View file

@ -1,730 +0,0 @@
// 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();
}
}
}

View file

@ -22,17 +22,31 @@ clue.pixel.fill(0) # turn off NeoPixel
clue_display = displayio.Group()
# draw the dry plant
dry_plant_bmp = displayio.OnDiskBitmap("dry.bmp")
dry_plant_file = open("dry.bmp", "rb")
dry_plant_bmp = displayio.OnDiskBitmap(dry_plant_file)
# CircuitPython 6 & 7 compatible
dry_plant_sprite = displayio.TileGrid(
dry_plant_bmp, pixel_shader=dry_plant_bmp.pixel_shader
dry_plant_bmp,
pixel_shader=getattr(dry_plant_bmp, "pixel_shader", displayio.ColorConverter()),
)
# 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_bmp = displayio.OnDiskBitmap("happy.bmp")
happy_plant_file = open("happy.bmp", "rb")
happy_plant_bmp = displayio.OnDiskBitmap(happy_plant_file)
# CircuitPython 6 & 7 compatible
happy_plant_sprite = displayio.TileGrid(
happy_plant_bmp, pixel_shader=happy_plant_bmp.pixel_shader
happy_plant_bmp,
pixel_shader=getattr(happy_plant_bmp, "pixel_shader", displayio.ColorConverter()),
)
# 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

View file

@ -22,14 +22,32 @@ splash = displayio.Group()
# bad egg
BAD_EGG_FILENAME = "broken_egg.bmp"
begg_bmp = displayio.OnDiskBitmap(BAD_EGG_FILENAME)
begg_sprite = displayio.TileGrid(begg_bmp, pixel_shader=begg_bmp.pixel_shader)
# 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)
# good egg
GOOD_EGG_FILENAME = "good_egg.bmp"
gegg_bmp = displayio.OnDiskBitmap(GOOD_EGG_FILENAME)
gegg_sprite = displayio.TileGrid(gegg_bmp, pixel_shader=gegg_bmp.pixel_shader)
# 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)
# draw the bad egg!
splash.append(begg_sprite)

View file

@ -21,19 +21,39 @@ clue_display = displayio.Group()
# draw the background image
WASH_ON_FILENAME = "wash_on.bmp"
wash_on_bmp = displayio.OnDiskBitmap(WASH_ON_FILENAME)
wash_on_sprite = displayio.TileGrid(wash_on_bmp, pixel_shader=wash_on_bmp.pixel_shader)
# 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)
clue_display.append(wash_on_sprite)
# draw the foreground image
WASH_OFF_FILENAME = "wash_off.bmp"
wash_off_bmp = displayio.OnDiskBitmap(WASH_OFF_FILENAME)
wash_off_sprite = displayio.TileGrid(wash_off_bmp, pixel_shader=wash_off_bmp.pixel_shader)
# 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)
clue_display.append(wash_off_sprite)
# Create text
# first create the group
text_group = displayio.Group()

View file

@ -62,10 +62,18 @@ from rps_crypto import bytesPad, strUnpad, generateOTPadKey, \
from rps_display import RPSDisplay, blankScreen
# 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")
# 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
debug = 1
@ -220,7 +228,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 settings.toml)
# Enable the Bluetooth LE radio and set player's name (from secrets.py)
ble = BLERadio()
if ble_name is not None:
ble.name = ble_name

View file

@ -58,7 +58,7 @@ group.append(press_data)
display.root_group = group
# function to convert celsius to fahrenheit
# function to convert celcius 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 celsius and hPa
# update temp & pressure text in celcius and hPa
temp_data.text = "%0.1f ºC" % bmp280.temperature
press_data.text = "%0.1f hPa" % bmp280.pressure
# if imperial units...
else:
# convert celsius to fahrenheit
# convert celcius to fahrenheit
temp_fahrenheit = c_to_f(bmp280.temperature)
# convert hPa to inHg
pressure_inHg = hpa_to_inHg(bmp280.pressure)

View file

@ -65,10 +65,18 @@ clue_display.brightness = 0.5
clueGroup = displayio.Group()
# loading bitmap background
clue_bg = displayio.OnDiskBitmap(clue_bgBMP)
clue_tilegrid = displayio.TileGrid(clue_bg, pixel_shader=clue_bg.pixel_shader)
# 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())
)
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)

View file

@ -33,8 +33,15 @@ a.solicited_services.append(AppleMediaService)
radio.start_advertising(a)
def wrap_in_tilegrid(filename:str):
odb = displayio.OnDiskBitmap(filename)
return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
# 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)
def make_background(width, height, color):
color_bitmap = displayio.Bitmap(width, height, 1)

View file

@ -93,8 +93,15 @@ advertisement.complete_name = "CIRCUITPY"
advertisement.solicited_services.append(AppleNotificationCenterService)
def wrap_in_tilegrid(filename:str):
odb = displayio.OnDiskBitmap(filename)
return displayio.TileGrid(odb, pixel_shader=odb.pixel_shader)
# 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)
display = tft_gizmo.TFT_Gizmo()
group = displayio.Group()

View file

@ -6,9 +6,10 @@
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
@ -22,20 +23,11 @@ import supervisor
import wifi
from adafruit_io.adafruit_io import IO_HTTP
# 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."
)
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
# CONFIGURABLE GLOBALS -----------------------------------------------------
@ -162,10 +154,10 @@ i2c.unlock()
# WIFI CONNECT -------------------------------------------------------------
try:
print(f"Connecting to {ssid}...")
wifi.radio.connect(ssid, password)
print("Connecting to {}...".format(secrets["ssid"]), end="")
wifi.radio.connect(secrets["ssid"], secrets["password"])
print("OK")
print(f"IP: {wifi.radio.ipv4_address}")
print("IP:", wifi.radio.ipv4_address)
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
@ -177,6 +169,8 @@ 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 -------------------------------

View file

@ -38,7 +38,7 @@ import time
import adafruit_bitmap_font.bitmap_font
import adafruit_display_text.label
from adafruit_progressbar.horizontalprogressbar import HorizontalProgressBar
from adafruit_progressbar import ProgressBar
import sdcardio
import analogjoy
import audioio
@ -75,12 +75,9 @@ class PlaybackDisplay:
def __init__(self):
self.group = displayio.Group()
self.glyph_width, self.glyph_height = font.get_bounding_box()[:2]
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.pbar = ProgressBar(0, 0, board.DISPLAY.width,
self.glyph_height*2, bar_color=0x0000ff,
outline_color=0x333333, stroke=1)
self.iconbar = icons.IconBar()
self.iconbar.group.y = 1000
for i in range(5, 8):
@ -118,11 +115,11 @@ class PlaybackDisplay:
@property
def progress(self):
"""The fraction of progress through the current track"""
return self.pbar.value
return self.pbar.progress
@progress.setter
def progress(self, frac):
self.pbar.value = frac
self.pbar.progress = frac
def set_bitmap(self, candidates):
"""Find and use a background from among candidates, or else the fallback bitmap"""
@ -130,16 +127,32 @@ class PlaybackDisplay:
if i == self._bitmap_filename:
return # Already loaded
# CircuitPython 6 & 7 compatible
try:
bitmap = displayio.OnDiskBitmap(i)
bitmap_file = open(i, 'rb')
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=bitmap.pixel_shader
bitmap,
pixel_shader=getattr(
bitmap, "pixel_shader", displayio.ColorConverter()
),
)
# # 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: 27 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -4,6 +4,7 @@
import time
import board
import adafruit_lsm6ds.lsm6ds33
from adafruit_ht16k33 import matrix
import matrixsand
@ -13,13 +14,8 @@ 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
# 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 accelo
accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c)
# the matrices
m1 = matrix.Matrix8x8(i2c, 0x70)

View file

@ -4,6 +4,7 @@
import time
import board
import adafruit_lsm6ds.lsm6ds33
from adafruit_ht16k33 import matrix
import matrixsand
@ -13,13 +14,8 @@ 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
# 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 accelo
accelo = adafruit_lsm6ds.lsm6ds33.LSM6DS33(i2c)
# the matrix
matrix = matrix.Matrix8x8(i2c, 0x70)

View file

@ -0,0 +1,4 @@
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)

View file

@ -17,21 +17,30 @@ 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, level: int = NOTSET):
def __init__(self, name, portal_device):
"""Create an instance."""
super().__init__(level)
self._log_feed_name = f"{name}-logging"
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.

View file

@ -8,26 +8,27 @@ 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))
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))
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))

View file

@ -17,39 +17,34 @@ All text above must be included in any redistribution.
"""
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
from adafruit_logging import Handler
from adafruit_ble.uart import UARTServer
class BLEHandler(Handler):
"""Send logging output to the BLE uart port."""
def __init__(self, level: int = NOTSET):
def __init__(self):
"""Create an instance.
:param uart: the busio.UART instance to which to write messages
"""
super().__init__(level)
self._advertising_now = False
ble = BLERadio()
self._uart = UARTService()
self._advertisement = ProvideServicesAdvertisement(self._uart)
ble.start_advertising(self._advertisement)
self._uart = UARTServer()
self._uart.start_advertising()
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
"""
data = bytes(self.format(record), "utf-8")
while not self._uart.connected:
pass
data = bytes(self.format(record), 'utf-8')
self._uart.write(data)

View file

@ -7,25 +7,26 @@ import random
from ble_handler import BLEHandler
import adafruit_logging as logging
l = logging.getLogger("ble")
l = logging.getLogger('ble')
l.addHandler(BLEHandler())
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))
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))

View file

@ -21,24 +21,25 @@ 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'))
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))
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))

View file

@ -1,13 +1,57 @@
# 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 = busio.UART(board.TX, board.RX, baudrate=115200)
logger = logging.getLogger("test")
logger.addHandler(UartHandler(uart))
logger.setLevel(logging.INFO)
logger.info("testing")
"""
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'))

View file

@ -1,46 +0,0 @@
# 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"))

View file

@ -25,8 +25,14 @@ display = framebufferio.FramebufferDisplay(matrix, auto_refresh=False)
filename = "emoji.bmp"
bitmap = displayio.OnDiskBitmap(filename)
pixel_shader = bitmap.pixel_shader
# 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
# Each wheel can be in one of three states:
STOPPED, RUNNING, BRAKING = range(3)

View file

@ -46,14 +46,24 @@ DISPLAY = framebufferio.FramebufferDisplay(MATRIX, auto_refresh=False,
# Load BMP image, create Group and TileGrid to hold it
FILENAME = "wales.bmp"
BITMAP = displayio.OnDiskBitmap(FILENAME)
# CircuitPython 6 & 7 compatible
BITMAP = displayio.OnDiskBitmap(open(FILENAME, "rb"))
TILEGRID = displayio.TileGrid(
BITMAP,
pixel_shader=BITMAP.pixel_shader,
pixel_shader=getattr(BITMAP, 'pixel_shader', displayio.ColorConverter()),
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

View file

@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MIT
from os import getenv
import time
import random
import audioio
@ -25,25 +24,21 @@ 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")
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."
)
# 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
# Use cityname, country code where countrycode is ISO3166 format.
# E.g. "New York, US" or "London, GB"
LOCATION = getenv('timezone')
LOCATION = secrets['timezone']
# Set up where we'll be fetching data from
DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+LOCATION
DATA_SOURCE += "&appid="+getenv('openweather_token')
DATA_SOURCE = "http://api.openweathermap.org/data/2.5/weather?q="+secrets['timezone']
DATA_SOURCE += "&appid="+secrets['openweather_token']
# If you are using a board with pre-defined ESP32 Pins:
esp32_cs = DigitalInOut(board.ESP_CS)
@ -52,8 +47,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_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)
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
pixels = neopixel.NeoPixel(board.D2, 150, brightness=1.0, auto_write=False)
pixels.fill(0x050505)
pixels.show()
@ -137,17 +132,22 @@ 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_filename = "sound/Clear.wav"
wave_file = open("sound/Clear.wav", "rb")
wave = audiocore.WaveFile(wave_file)
has_sound = True
if weather_type == 'Clouds':
palette = cloudy_palette
wave_filename = "sound/Clouds.wav"
wave_file = open("sound/Clouds.wav", "rb")
wave = audiocore.WaveFile(wave_file)
has_sound = True
if weather_type == 'Rain':
palette = cloudy_palette
wave_filename = "sound/Rain.wav"
wave_file = open("sound/Rain.wav", "rb")
wave = audiocore.WaveFile(wave_file)
raining = True
has_sound = True
if weather_type == 'Thunderstorm':
palette = thunder_palette
raining = thundering = True
@ -156,11 +156,9 @@ while True:
next_bolt_time = time.monotonic() + random.randint(1, 5)
if weather_type == 'Snow':
palette = cloudy_palette
wave_filename = "sound/Snow.wav"
snowing = True
if wave_filename:
wave_file = open(wave_filename, "rb")
wave_file = open("sound/Snow.wav", "rb")
wave = audiocore.WaveFile(wave_file)
snowing = True
has_sound = True
weather_refresh = time.monotonic()
except RuntimeError as e:
@ -206,13 +204,11 @@ while True:
# pick next thunderbolt time now
Thunder = random.randint(0, 2)
if Thunder == 0:
wave_filename = "sound/Thunderstorm0.wav"
wave_file = open("sound/Thunderstorm0.wav", "rb")
elif Thunder == 1:
wave_filename = "sound/Thunderstorm1.wav"
wave_file = open("sound/Thunderstorm1.wav", "rb")
elif Thunder == 2:
wave_filename = "sound/Thunderstorm2.wav"
if wave_filename:
wave_file = open(wave_filename, "rb")
wave = audiocore.WaveFile(wave_file)
audio.play(wave)
wave_file = open("sound/Thunderstorm2.wav", "rb")
wave = audiocore.WaveFile(wave_file)
audio.play(wave)
next_bolt_time = time.monotonic() + random.randint(5, 15) # between 5 and 15 s

View file

@ -0,0 +1,13 @@
# 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',
}

View file

@ -1,12 +0,0 @@
# 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"

View file

@ -4,12 +4,12 @@
"""
This demo is designed for the Kaluga development kit version 1.3 with the
ILI9341 display. Your settings.toml must be populated with your wifi credentials
ILI9341 display. Your secrets.py 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,21 +25,6 @@ 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"
@ -68,14 +53,14 @@ cam.flip_y = False
cam.colorspace = adafruit_ov2640.OV2640_COLOR_YUV
print("Connecting to WIFI")
wifi.radio.connect(ssid, password)
wifi.radio.connect(secrets["ssid"], secrets["password"])
pool = socketpool.SocketPool(wifi.radio)
print("Connecting to Adafruit IO")
mqtt_client = MQTT.MQTT(
broker="io.adafruit.com",
username=aio_username,
password=aio_key,
username=secrets["aio_username"],
password=secrets["aio_key"],
socket_pool=pool,
ssl_context=ssl.create_default_context(),
)

View file

@ -4,7 +4,8 @@
"""
This demo is designed for the Kaluga development kit version 1.3 with the
ILI9341 display.
ILI9341 display. Your secrets.py must be populated with your wifi credentials
and your Adafruit IO credentials.
"""
from ulab import numpy as np

View file

@ -21,8 +21,17 @@ while True:
for filename in bmpfiles:
print("showing", filename)
bitmap = displayio.OnDiskBitmap(filename)
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
# 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)
group = displayio.Group()
group.append(tile_grid)

View file

@ -2,7 +2,6 @@
#
# SPDX-License-Identifier: MIT
from os import getenv
import time
import board
from digitalio import DigitalInOut
@ -15,17 +14,12 @@ import displayio
minitft = minitft_featherwing.MiniTFTFeatherWing()
# 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."
)
# 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.D13)
@ -33,11 +27,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.WiFiManager(esp, ssid, password)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets)
# Symbol "INX" for S&P500, "DJIA" for Dow
DATA_SOURCE = "https://www.alphavantage.co/query?function=GLOBAL_QUOTE&apikey="
DATA_SOURCE += getenv('alphavantage_key')
DATA_SOURCE += secrets['alphavantage_key']
symbols = ["DJIA", "INX", "AAPL", "TSLA", "MSFT"]
# Set text, font, and color

11
CircuitStonks/secrets.py Normal file
View file

@ -0,0 +1,11 @@
# 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'
}

View file

@ -1,11 +0,0 @@
# 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"

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,383 +0,0 @@
// 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_ */

View file

@ -21,7 +21,7 @@
*/
#include "Conceptinetics.h"
#include <Conceptinetics.h>
//

View file

@ -1,315 +0,0 @@
// 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_ */

View file

@ -1,101 +0,0 @@
// 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_ */

View file

@ -1,383 +0,0 @@
// 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_ */

View file

@ -21,7 +21,7 @@
*/
#include "Conceptinetics.h"
#include <Conceptinetics.h>
//
// When configuring a DMX_Master it will normally automaticly

View file

@ -1,315 +0,0 @@
// 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_ */

View file

@ -1,101 +0,0 @@
// 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_ */

File diff suppressed because it is too large Load diff

View file

@ -1,383 +0,0 @@
// 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_ */

View file

@ -21,7 +21,7 @@
*/
#include "Conceptinetics.h"
#include <Conceptinetics.h>
//
// CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS

View file

@ -1,315 +0,0 @@
// 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_ */

View file

@ -1,101 +0,0 @@
// 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_ */

View file

@ -1,383 +0,0 @@
// 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_ */

View file

@ -21,7 +21,7 @@
*/
#include "Conceptinetics.h"
#include <Conceptinetics.h>
//
// CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS

View file

@ -1,315 +0,0 @@
// 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_ */

View file

@ -1,101 +0,0 @@
// 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_ */

File diff suppressed because it is too large Load diff

View file

@ -1,383 +0,0 @@
// 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_ */

View file

@ -21,7 +21,7 @@
*/
#include "Conceptinetics.h"
#include <Conceptinetics.h>
//
// CTC-DRA-13-1 ISOLATED DMX-RDM SHIELD JUMPER INSTRUCTIONS

Some files were not shown because too many files have changed in this diff Show more