Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add support for UART devices #493

Merged
merged 58 commits into from
Oct 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
850ca1e
signals match f2f6ff8
brentru Jul 25, 2023
2f7d2d5
hooks for topics
brentru Jul 25, 2023
3a11dd9
decoder and match commit
brentru Jul 25, 2023
8890f19
match latest uart PR with refactored init sequence
brentru Jul 25, 2023
74d3c33
add uart skel.
brentru Jul 26, 2023
615615a
sync ws proto commit 2e9136f
brentru Jul 26, 2023
f61bc02
include ws_uart, hw serial init
brentru Jul 26, 2023
4b45546
compile
brentru Jul 26, 2023
0af7867
add uart driver base:
brentru Jul 26, 2023
69614d1
add pm25aqi class mock using base
brentru Jul 26, 2023
ae3f258
rename
brentru Jul 26, 2023
daea7dd
inclusion of hwserial and swserial in driver, notes for Friday
brentru Jul 26, 2023
28462e2
driver begin()
brentru Aug 8, 2023
1a9975a
working on begin() for drivers
brentru Aug 8, 2023
eb9fab9
properly attach uart device and publish response back via hook
brentru Aug 8, 2023
44781c0
add begin, switch around logging msgs
brentru Aug 9, 2023
7d243ce
passing mqtt client in, read uart sensor
brentru Aug 9, 2023
f1ca518
match 0b49845c972f37c5e26e15b0713266d750864e82
brentru Aug 10, 2023
1cdfaef
match a7b14abeacee98c2b0f2750468c27853f55d56bc
brentru Aug 11, 2023
45dc6f8
change payload name for new proto
brentru Aug 11, 2023
2e54ee8
add message encoding, publishing, new data_available getter
brentru Aug 11, 2023
ce20afd
write update()
brentru Aug 11, 2023
2892455
doxygen cleanup
brentru Aug 11, 2023
31ca579
init. uart class in ws.cpp, split uart bus init into two functions
brentru Aug 11, 2023
2b4317f
Merge branch 'main' of github.com:adafruit/Adafruit_Wippersnapper_Ard…
brentru Sep 6, 2023
f7318b2
complete merge, annotate a breaking change with the new protobufs
brentru Sep 6, 2023
805e43c
refactor update even more
brentru Sep 7, 2023
11bec50
add uart detach
brentru Sep 7, 2023
a666bd7
safely iterate through the vector of drivers and deallocate memory
brentru Sep 7, 2023
6f855cf
working on staging
brentru Sep 11, 2023
7e30c82
put back network interface switch between prod. and staging URLS and …
brentru Sep 11, 2023
12c073d
rename some methods, add packUart response method
brentru Sep 11, 2023
f61d832
add doxy
brentru Sep 11, 2023
a25be51
route for sw uart too
brentru Sep 12, 2023
b1c5e71
update routine for Loren
brentru Sep 12, 2023
01d9af2
add getter for is uart bus init
brentru Sep 12, 2023
8364859
fix interface esp32 prod/staging switch
brentru Sep 19, 2023
c4836b0
reduce printout for uart pm25
brentru Sep 19, 2023
1e2828b
refactor dynamic topic allocation
brentru Sep 20, 2023
0b69623
refactor topic allocation 2
brentru Sep 20, 2023
c44b1d1
update .h
brentru Sep 20, 2023
b3d14a2
Update src/components/uart/drivers/ws_uart_drv_pm25aqi.h
brentru Sep 21, 2023
bc1b05a
refactor for deinitializing uart device, dangling ptr bug
brentru Sep 21, 2023
228a564
was allocating 1 extra byte where we didnt need to
brentru Sep 22, 2023
7d3cd56
put swserial and hwserial initializers behind guard condition, correc…
brentru Sep 22, 2023
c3dc36d
use littlefs for esp8266 piod ef
brentru Sep 25, 2023
86cdcba
Fixes for SWSerial and complete Tyeth review
brentru Sep 25, 2023
adfc0dd
use standard rx/tx for swuart
brentru Sep 25, 2023
a3e96e6
Merge branch 'main' into add-uart-feature
brentru Sep 25, 2023
d27fc52
fix interval Warning/Error
brentru Sep 25, 2023
e1f5c3f
preproc for src/components/uart/ws_uart.cpp
brentru Sep 26, 2023
cbb6bea
try this!
brentru Sep 26, 2023
4ac969f
update to our samd board tests
brentru Sep 26, 2023
1ce5ca8
try fix for samd's HardwareSerial class
brentru Sep 26, 2023
a026823
clang-format
brentru Sep 26, 2023
c623294
add board_build.filesystem for littlefs on esp8266
brentru Sep 27, 2023
6536cff
remove printfs and todos
brentru Sep 27, 2023
cab36d9
remove debugging comment
brentru Oct 2, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"files.associations": {
"limits": "c",
"type_traits": "c"
}
},
"C_Cpp.dimInactiveRegions": false
}
26 changes: 19 additions & 7 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ framework = arduino
monitor_speed = 115200
lib_compat_mode = strict
lib_deps =
adafruit/Adafruit Zero DMA Library
adafruit/Adafruit TinyUSB Library
adafruit/Adafruit NeoPixel
adafruit/Adafruit Zero DMA Library
adafruit/Adafruit SPIFlash
adafruit/Adafruit DotStar
adafruit/ENS160 - Adafruit Fork
Expand Down Expand Up @@ -71,10 +71,16 @@ platform = espressif32 @ ^6.3.2
lib_ignore = WiFiNINA
monitor_filters = esp32_exception_decoder, time

; Common build environment for ESP8266 platform
[common:esp8266]
platform = espressif8266
lib_ignore = WiFiNINA, Adafruit TinyUSB Library

; Common build environment for Atmel/Microchip SAMDx platform
[common:atsamd]
platform = atmelsam
lib_ldf_mode = deep

; ESP32-x Boards ;

; Adafruit ESP32 Feather
Expand Down Expand Up @@ -186,23 +192,29 @@ extra_scripts = pre:rename_usb_config.py
extends=common:esp8266
board = huzzah
build_flags = -DARDUINO_ESP8266_ADAFRUIT_HUZZAH
board_build.filesystem = littlefs
upload_port = /dev/cu.SLAB_USBtoUART

; SAMD51 Boards ;

; Adafruit PyPortal M4
[env:adafruit_pyportal_m4]
platform = atmelsam
extends = common:atsamd
board = adafruit_pyportal_m4
lib_ldf_mode = deep+ ; Required for the inclusion of ZeroDMA for some reason
build_flags = -DUSE_TINYUSB=1
-DADAFRUIT_PYPORTAL
;upload_port=/dev/cu./dev/cu.usbmodem13301

; Adafruit PyPortal M4 Titano
[env:adafruit_pyportal_m4_titano]
platform = atmelsam
extends = common:atsamd
board = adafruit_pyportal_m4_titano
lib_ldf_mode = deep+ ; Required for the inclusion of ZeroDMA for some reason
build_flags = -DUSE_TINYUSB=1
-DADAFRUIT_PYPORTAL_M4_TITANO
;upload_port=/dev/cu./dev/cu.usbmodem13301

; Adafruit Metro M4 Airlift Lite
[env:adafruit_metro_m4_airliftlite]
extends = common:atsamd
board = adafruit_metro_m4_airliftlite
build_flags = -DUSE_TINYUSB=1
-DADAFRUIT_METRO_M4_AIRLIFT_LITE
upload_port = /dev/cu.usbmodem1201
192 changes: 186 additions & 6 deletions src/Wippersnapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,26 @@ Wippersnapper::Wippersnapper() {
_throttle_sub = 0;

// Init. component classes

// DallasSemi (OneWire)
WS._ds18x20Component = new ws_ds18x20();
// LEDC (ESP32-ONLY)
#ifdef ARDUINO_ARCH_ESP32
WS._ledc = new ws_ledc();
#endif
// Servo
WS._servoComponent = new ws_servo();
// PWM

// PWM (Arch-specific implementations)
#ifdef ARDUINO_ARCH_ESP32
WS._pwmComponent = new ws_pwm(WS._ledc);
#else
WS._pwmComponent = new ws_pwm();
#endif

// Servo
WS._servoComponent = new ws_servo();

// UART
WS._uartComponent = new ws_uart();

// DallasSemi (OneWire)
WS._ds18x20Component = new ws_ds18x20();
};

/**************************************************************************/
Expand Down Expand Up @@ -1476,6 +1481,126 @@ void cbPixelsMsg(char *data, uint16_t len) {
WS_DEBUG_PRINTLN("ERROR: Unable to decode pixel topic message");
}

/******************************************************************************************/
/*!
@brief Decodes a UART message and executes the callback based on the
message's tag.
@param stream
Incoming data stream from buffer.
@param field
Protobuf message's tag type.
@param arg
Optional arguments from decoder calling function.
@returns True if decoded successfully, False otherwise.
*/
/******************************************************************************************/
bool cbDecodeUARTMessage(pb_istream_t *stream, const pb_field_t *field,
void **arg) {
if (field->tag ==
wippersnapper_signal_v1_UARTRequest_req_uart_device_attach_tag) {
WS_DEBUG_PRINTLN(
"[Message Type]: "
"wippersnapper_signal_v1_UARTRequest_req_uart_device_attach_tag");

// attempt to decode create message
wippersnapper_uart_v1_UARTDeviceAttachRequest msgUARTInitReq =
wippersnapper_uart_v1_UARTDeviceAttachRequest_init_zero;
if (!pb_decode(stream, wippersnapper_uart_v1_UARTDeviceAttachRequest_fields,
&msgUARTInitReq)) {
WS_DEBUG_PRINTLN(
"ERROR: Could not decode message of type: UARTDeviceAttachRequest!");
return false;
}

// Check if bus_info is within the message
if (!msgUARTInitReq.has_bus_info) {
WS_DEBUG_PRINTLN("ERROR: UART bus info not found within message!");
return false;
}

// Have we previously initialized the UART bus?
if (!WS._uartComponent->isUARTBusInitialized())
WS._uartComponent->initUARTBus(&msgUARTInitReq); // Init. UART bus

// Attach UART device to the bus specified in the message
bool did_begin = WS._uartComponent->initUARTDevice(&msgUARTInitReq);

// Create a UARTResponse message
wippersnapper_signal_v1_UARTResponse msgUARTResponse =
wippersnapper_signal_v1_UARTResponse_init_zero;
msgUARTResponse.which_payload =
wippersnapper_signal_v1_UARTResponse_resp_uart_device_attach_tag;
msgUARTResponse.payload.resp_uart_device_attach.is_success = did_begin;
strcpy(msgUARTResponse.payload.resp_uart_device_attach.device_id,
msgUARTInitReq.device_id);
memset(WS._buffer_outgoing, 0, sizeof(WS._buffer_outgoing));
pb_ostream_t ostream = pb_ostream_from_buffer(WS._buffer_outgoing,
sizeof(WS._buffer_outgoing));
if (!pb_encode(&ostream, wippersnapper_signal_v1_UARTResponse_fields,
&msgUARTResponse)) {
WS_DEBUG_PRINTLN("ERROR: Unable to encode UART response message!");
return false;
}
size_t msgSz; // message's encoded size
pb_get_encoded_size(&msgSz, wippersnapper_signal_v1_UARTResponse_fields,
&msgUARTResponse);
WS_DEBUG_PRINT("PUBLISHING: UART Attach Response...");
WS._mqtt->publish(WS._topic_signal_uart_device, WS._buffer_outgoing, msgSz,
1);
WS_DEBUG_PRINTLN("Published!");

} else if (field->tag ==
wippersnapper_signal_v1_UARTRequest_req_uart_device_detach_tag) {
WS_DEBUG_PRINTLN("[New Message] UART Detach");
// attempt to decode uart detach request message
wippersnapper_uart_v1_UARTDeviceDetachRequest msgUARTDetachReq =
wippersnapper_uart_v1_UARTDeviceDetachRequest_init_zero;
if (!pb_decode(stream, wippersnapper_uart_v1_UARTDeviceDetachRequest_fields,
&msgUARTDetachReq)) {
WS_DEBUG_PRINTLN("ERROR: Could not decode message!");
return false;
}
// detach UART device
WS._uartComponent->detachUARTDevice(&msgUARTDetachReq);
WS_DEBUG_PRINTLN("Detached uart device from bus");
} else {
WS_DEBUG_PRINTLN("ERROR: UART message type not found!");
return false;
}
return true;
}

/**************************************************************************/
/*!
@brief Called when the signal UART sub-topic receives a
new message. Performs decoding.
@param data
Incoming data from MQTT broker.
@param len
Length of incoming data.
*/
/**************************************************************************/
void cbSignalUARTReq(char *data, uint16_t len) {
WS_DEBUG_PRINTLN("* NEW MESSAGE on Signal of type UART: ");
WS_DEBUG_PRINT(len);
WS_DEBUG_PRINTLN(" bytes.");
// zero-out current buffer
memset(WS._buffer, 0, sizeof(WS._buffer));
// copy mqtt data into buffer
memcpy(WS._buffer, data, len);
WS.bufSize = len;

// Set up the payload callback, which will set up the callbacks for
// each oneof payload field once the field tag is known
WS.msgSignalUART.cb_payload.funcs.decode = cbDecodeUARTMessage;

// Decode DS signal request
pb_istream_t istream = pb_istream_from_buffer(WS._buffer, WS.bufSize);
if (!pb_decode(&istream, wippersnapper_signal_v1_UARTRequest_fields,
&WS.msgSignalUART))
WS_DEBUG_PRINTLN("ERROR: Unable to decode UART Signal message");
}

/****************************************************************************/
/*!
@brief Handles MQTT messages on signal topic until timeout.
Expand Down Expand Up @@ -2125,6 +2250,58 @@ bool Wippersnapper::generateWSTopics() {
return false;
}

// Create device-to-broker UART topic

// Calculate size for dynamic MQTT topic
size_t topicLen = strlen(WS._username) + strlen("/") + strlen(_device_uid) +
strlen("/wprsnpr/") + strlen(TOPIC_SIGNALS) +
strlen("broker/uart") + 1;

// Allocate memory for dynamic MQTT topic
#ifdef USE_PSRAM
WS._topic_signal_uart_brkr = (char *)ps_malloc(topicLen);
#else
WS._topic_signal_uart_brkr = (char *)malloc(topicLen);
#endif

// Generate the topic if memory was allocated successfully
if (WS._topic_signal_uart_brkr != NULL) {
snprintf(WS._topic_signal_uart_brkr, topicLen, "%s/wprsnpr/%s%sbroker/uart",
WS._username, _device_uid, TOPIC_SIGNALS);
} else {
WS_DEBUG_PRINTLN("FATAL ERROR: Failed to allocate memory for UART topic!");
return false;
}

// Subscribe to signal's UART sub-topic
_topic_signal_uart_sub =
new Adafruit_MQTT_Subscribe(WS._mqtt, WS._topic_signal_uart_brkr, 1);
WS._mqtt->subscribe(_topic_signal_uart_sub);
// Set MQTT callback function
_topic_signal_uart_sub->setCallback(cbSignalUARTReq);

// Create broker-to-device UART topic
// Calculate size for dynamic MQTT topic
topicLen = strlen(WS._username) + strlen("/") + strlen(_device_uid) +
strlen("/wprsnpr/") + strlen(TOPIC_SIGNALS) +
strlen("device/uart") + 1;

// Allocate memory for dynamic MQTT topic
#ifdef USE_PSRAM
WS._topic_signal_uart_device = (char *)ps_malloc(topicLen);
#else
WS._topic_signal_uart_device = (char *)malloc(topicLen);
#endif

// Generate the topic if memory was allocated successfully
if (WS._topic_signal_uart_device != NULL) {
snprintf(WS._topic_signal_uart_device, topicLen,
"%s/wprsnpr/%s%sdevice/uart", WS._username, _device_uid,
TOPIC_SIGNALS);
} else {
WS_DEBUG_PRINTLN("FATAL ERROR: Failed to allocate memory for UART topic!");
return false;
}
return true;
}

Expand Down Expand Up @@ -2661,5 +2838,8 @@ ws_status_t Wippersnapper::run() {
// Process DS18x20 sensor events
WS._ds18x20Component->update();

// Process UART sensor events
WS._uartComponent->update();

return WS_NET_CONNECTED; // TODO: Make this funcn void!
}
Loading
Loading