refactoring

This commit is contained in:
Svante Kaiser 2023-11-02 16:04:15 +03:00
parent d46849736f
commit 4bdc98bd7b
10 changed files with 302 additions and 270 deletions

View File

@ -0,0 +1,22 @@
#pragma once
#define MQTT_HOST IPAddress(192, 168, 1, 173)
#define MQTT_PORT 1883
#define SERIAL_NUMBER "4823"
#define MAC_ADDRESS_MQTT_TOPIC "/digitum/intercom_bridge4823/out/mac"
#define IP_ADDRESS_MQTT_TOPIC "/digitum/intercom_bridge4823/out/ip"
#define SERIAL_NUMBER_MQTT_TOPIC "/digitum/intercom_bridge4823/out/sn"
#define FLAT_NUMBER_MQTT_TOPIC "/digitum/intercom_bridge4823/out/flat_number"
#define STATE_MQTT_TOPIC "/digitum/intercom_bridge4823/out/state"
#define LEDS_PIN 32
#define DRY_CONT_PIN 15
#define DOOR_SENS_PIN 114
#define DATA_PIN 12
#define DATA_PERIOD 240 // microseconds
#define PRINT_RAW_SIGNAL_FLAG 0

View File

@ -1,4 +1,29 @@
#include "stateMachine.h" #include "utils/print.h"
#include "config/config.h"
#include "infra/mqtt.h"
#include "domain/stateMachine.h"
State currentState = NOT_CONNECTED;
int countZeros = 0;
int countOnes = 0;
int previousData = 0;
int dataLength = 0;
int signalDuration = 0;
void resetCounters() {
countZeros = 0;
countOnes = 0;
previousData = 0;
dataLength = 0;
signalDuration = 0;
}
void writeState(char* message) {
println(message);
publishToMQTT(STATE_MQTT_TOPIC, message);
}
void updateStateMachine(int data) { void updateStateMachine(int data) {
switch (currentState) { switch (currentState) {
@ -7,7 +32,7 @@ void updateStateMachine(int data) {
// Stay in the NOT_CONNECTED state // Stay in the NOT_CONNECTED state
} else if (data == 1) { } else if (data == 1) {
currentState = CONNECTED; currentState = CONNECTED;
println("connected"); writeState("connected");
} }
break; break;
@ -16,13 +41,13 @@ void updateStateMachine(int data) {
countZeros++; countZeros++;
if (countZeros >= NOT_CONNECTED_THRESHOLD) { if (countZeros >= NOT_CONNECTED_THRESHOLD) {
currentState = NOT_CONNECTED; currentState = NOT_CONNECTED;
println("not connected"); writeState("not connected");
resetCounters(); resetCounters();
} }
} else if (data == 1) { } else if (data == 1) {
if (countZeros >= INITIALIZING_CALL_THRESHOLD) { if (countZeros >= INITIALIZING_CALL_THRESHOLD) {
currentState = RECEIVING_DATA; currentState = RECEIVING_DATA;
println("receiving data"); writeState("receiving data");
resetCounters(); resetCounters();
} }
} }
@ -44,10 +69,9 @@ void updateStateMachine(int data) {
if (countZeros >= DATA_RECEIVED_THESHOLD) { if (countZeros >= DATA_RECEIVED_THESHOLD) {
println("| data length: ", dataLength); println("| data length: ", dataLength);
println("| flat: ", dataLength/2); println("| flat: ", dataLength/2);
//sendDataToMQTT(dataLength/2); publishToMQTT(FLAT_NUMBER_MQTT_TOPIC, dataLength/2);
currentState = DATA_RECEIVED; currentState = DATA_RECEIVED;
println("data received");
resetCounters(); resetCounters();
} }
} else if (data == 1) { } else if (data == 1) {
@ -55,7 +79,7 @@ void updateStateMachine(int data) {
countOnes++; countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) { if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED; currentState = CONNECTED;
println("connected"); writeState("connected");
resetCounters(); resetCounters();
} }
} }
@ -66,14 +90,14 @@ void updateStateMachine(int data) {
countZeros++; countZeros++;
if (countZeros >= CALL_ENDED_THRESHOLD) { if (countZeros >= CALL_ENDED_THRESHOLD) {
currentState = CALL_ENDED; currentState = CALL_ENDED;
println("call ended"); writeState("call ended");
resetCounters(); resetCounters();
} }
} else if (data == 1) { } else if (data == 1) {
countOnes++; countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) { if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED; currentState = CONNECTED;
println("connected"); writeState("connected");
resetCounters(); resetCounters();
} }
break; break;
@ -84,14 +108,14 @@ void updateStateMachine(int data) {
countZeros++; countZeros++;
if (countZeros >= NOT_CONNECTED_THRESHOLD) { if (countZeros >= NOT_CONNECTED_THRESHOLD) {
currentState = NOT_CONNECTED; currentState = NOT_CONNECTED;
println("not connected"); writeState("not connected");
resetCounters(); resetCounters();
} }
} else if (data == 1) { } else if (data == 1) {
countOnes++; countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) { if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED; currentState = CONNECTED;
println("connected"); writeState("connected");
resetCounters(); resetCounters();
} }
break; break;

View File

@ -2,7 +2,6 @@
#define STATE_MACHINE_H #define STATE_MACHINE_H
#include <Arduino.h> #include <Arduino.h>
#include "utils/print.cpp"
#define CONNECTED_THRESHOLD 50000 #define CONNECTED_THRESHOLD 50000
#define NOT_CONNECTED_THRESHOLD 50000 #define NOT_CONNECTED_THRESHOLD 50000
@ -18,15 +17,6 @@ enum State {
CALL_ENDED CALL_ENDED
}; };
int data = 0;
State currentState = NOT_CONNECTED;
int countZeros = 0;
int countOnes = 0;
int previousData = 0;
int dataLength = 0;
int signalDuration = 0;
void resetCounters(); void resetCounters();
void updateStateMachine(int data); void updateStateMachine(int data);

118
src/infra/eth.cpp Normal file
View File

@ -0,0 +1,118 @@
#include "infra/eth.h"
#include "infra/mqtt.h"
extern bool eth_connected;
TimerHandle_t ethReconnectTimer;
void WiFiEvent(WiFiEvent_t event)
{
#if ESP_IDF_VERSION_MAJOR > 3
switch (event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
connectToMqtt();
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#elif
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#endif
}
void connectEth() {
pinMode(NRST, OUTPUT);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
ETH.begin(ETH_ADDR,
ETH_POWER_PIN,
ETH_MDC_PIN,
ETH_MDIO_PIN,
ETH_TYPE,
ETH_CLK_MODE);
}
void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}
Serial.println("closing connection\n");
client.stop();
}

32
src/infra/eth.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#include <ETH.h>
/*
* ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator
* ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN 16
// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE ETH_PHY_LAN8720
// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR 1
// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN 23
// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN 18
#define NRST 5
void WiFiEvent(WiFiEvent_t event);
void connectEth();
void testClient(const char * host, uint16_t port);

View File

@ -1,19 +1,50 @@
#include <Arduino.h> #include <Arduino.h>
#include <ETH.h>
#include "config/config.h"
#include "infra/mqtt.h" #include "infra/mqtt.h"
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
void connectToMqtt() { void connectToMqtt() {
Serial.println("Connecting to MQTT..."); Serial.println("Connecting to MQTT...");
mqttClient.connect(); mqttClient.connect();
} }
void publishToMQTT(const char* topic, const char* message) {
mqttClient.publish(topic, 2, true, message);
}
void publishToMQTT(const char* topic, int message) {
char num_char[10];
sprintf(num_char, "%d", message);
mqttClient.publish(topic, 2, true, num_char);
}
void publishToMQTT(const char* topic, float message) {
char num_char[10];
dtostrf(message, 1, 2, num_char); // Convert float to string
mqttClient.publish(topic, 2, true, num_char);
}
void publishToMQTT(const char* topic, bool message) {
const char* bool_str = message ? "true" : "false";
mqttClient.publish(topic, 2, true, bool_str);
}
void onMqttConnect(bool sessionPresent) { void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT."); Serial.println("Connected to MQTT.");
Serial.print("Session present: "); Serial.print("Session present: ");
Serial.println(sessionPresent); Serial.println(sessionPresent);
uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0); publishToMQTT(MAC_ADDRESS_MQTT_TOPIC, ETH.macAddress().c_str());
Serial.print("Subscribing at QoS 0, packetId: "); publishToMQTT(IP_ADDRESS_MQTT_TOPIC, ETH.localIP().toString().c_str());
Serial.println(packetIdSub); publishToMQTT(SERIAL_NUMBER_MQTT_TOPIC, SERIAL_NUMBER);
//uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0);
//Serial.print("Subscribing at QoS 0, packetId: ");
//Serial.println(packetIdSub);
} }
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
@ -43,8 +74,14 @@ void onMqttPublish(uint16_t packetId) {
Serial.println(packetId); Serial.println(packetId);
} }
void sendDataToMQTT(int flatNumber) { void initMQTT() {
char num_char[3]; mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
sprintf(num_char, "%d", flatNumber);
mqttClient.publish("/digitum/out/flat_number", 2, true, num_char); mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onSubscribe(onMqttSubscribe);
mqttClient.onUnsubscribe(onMqttUnsubscribe);
//mqttClient.onMessage(onMqttMessage);
//mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
} }

View File

@ -1,12 +1,8 @@
#ifndef INFRA_MQTT_H #pragma once
#define INFRA_MQTT_H
#include <HTTPClient.h> #include <HTTPClient.h>
#include <AsyncMqttClient.h> #include <AsyncMqttClient.h>
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
void connectToMqtt(); void connectToMqtt();
void onMqttConnect(bool sessionPresent); void onMqttConnect(bool sessionPresent);
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason); void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
@ -14,5 +10,8 @@ void onMqttSubscribe(uint16_t packetId, uint8_t qos);
void onMqttUnsubscribe(uint16_t packetId); void onMqttUnsubscribe(uint16_t packetId);
void onMqttPublish(uint16_t packetId); void onMqttPublish(uint16_t packetId);
void sendDataToMQTT(int flatNumber); void sendDataToMQTT(int flatNumber);
void publishToMQTT(const char* topic, const char* message);
#endif // INFRA_MQTT_H void publishToMQTT(const char* topic, int message);
void publishToMQTT(const char* topic, float message);
void publishToMQTT(const char* topic, bool message);
void initMQTT();

View File

@ -6,166 +6,18 @@
#include <IPAddress.h> #include <IPAddress.h>
#include <AsyncMqttClient.h> #include <AsyncMqttClient.h>
#include "infra/mqtt.h"
#include "utils/print.h" #include "utils/print.h"
#include "stateMachine.h" #include "config/config.h"
#include "infra/eth.h"
#define LEDS_PIN 32 #include "infra/mqtt.h"
#define DRY_CONT_PIN 15 #include "domain/stateMachine.h"
#define DOOR_SENS_PIN 114
#define DATA_PIN 12
#define DATA_PERIOD 240 // microseconds
#define PRINT_RAW_SIGNAL_FLAG 0
/*
* ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator
* ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN 16
// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE ETH_PHY_LAN8720
// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR 1
// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN 23
// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN 18
#define NRST 5
#define MQTT_HOST IPAddress(192, 168, 1, 173)
#define MQTT_PORT 1883
uint32_t lastMillis; uint32_t lastMillis;
uint64_t lastMicros; uint64_t lastMicros;
static bool eth_connected = false; bool eth_connected = false;
TimerHandle_t ethReconnectTimer; int data = 0;
void WiFiEvent(WiFiEvent_t event)
{
#if ESP_IDF_VERSION_MAJOR > 3
switch (event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
connectToMqtt();
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#elif
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#endif
}
void connectEth() {
pinMode(NRST, OUTPUT);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
ETH.begin(ETH_ADDR,
ETH_POWER_PIN,
ETH_MDC_PIN,
ETH_MDIO_PIN,
ETH_TYPE,
ETH_CLK_MODE);
}
void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}
Serial.println("closing connection\n");
client.stop();
}
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
@ -173,16 +25,7 @@ void setup() {
WiFi.onEvent(WiFiEvent); WiFi.onEvent(WiFiEvent);
connectEth(); connectEth();
initMQTT();
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onSubscribe(onMqttSubscribe);
mqttClient.onUnsubscribe(onMqttUnsubscribe);
//mqttClient.onMessage(onMqttMessage);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
pinMode(DATA_PIN, INPUT); pinMode(DATA_PIN, INPUT);

View File

@ -1,77 +1,19 @@
#include <Arduino.h> #include <Arduino.h>
#include "utils/print.h"
void print() { void print() {
// Empty function to terminate recursion // Empty function to terminate recursion
} }
// Overloaded function to print a single value
template <typename T>
void print(T value) {
Serial.print(value);
}
// Recursive function to print multiple values
template <typename T, typename... Args>
void print(T value, Args... args) {
Serial.print(value);
print(args...); // Recursively call print for the remaining arguments
}
// Function to print a newline // Function to print a newline
void println() { void println() {
Serial.println(); Serial.println();
} }
// Overloaded function to print a single value and a newline
template <typename T>
void println(T value) {
Serial.println(value);
}
// Recursive function to print multiple values and a newline
template <typename T, typename... Args>
void println(T value, Args... args) {
Serial.print(value);
println(args...); // Recursively call println for the remaining arguments
}
// Convenience functions for easy usage
template <typename... Args>
void print(Args... args) {
print(args...);
}
template <typename... Args>
void println(Args... args) {
println(args...);
}
String fstring(const char* format) { String fstring(const char* format) {
String result = format; String result = format;
return result; return result;
} }
template <typename... Args>
String fstring(const char* format, Args... args) {
String result = "";
while (*format) {
if (*format == '{' && *(format + 1) == '}' && sizeof...(args) > 0) {
result += String(args...);
format += 2; // Skip the "{}" in the format string
} else {
result += *format;
format++;
}
}
return result;
}
void printf(const char* format) { void printf(const char* format) {
Serial.print(fstring(format)); Serial.print(fstring(format));
} }
template <typename... Args>
void printf(const char* format, Args... args) {
Serial.print(fstring(format, args...));
}

View File

@ -1,5 +1,4 @@
#ifndef UTILS_PRINT_H #pragma once
#define UTILS_PRINT_H
#include <Arduino.h> #include <Arduino.h>
@ -7,38 +6,64 @@ void print();
// Overloaded function to print a single value // Overloaded function to print a single value
template <typename T> template <typename T>
void print(T value); void print(T value) {
Serial.print(value);
}
// Recursive function to print multiple values // Recursive function to print multiple values
template <typename T, typename... Args> template <typename T, typename... Args>
void print(T value, Args... args); void print(T value, Args... args) {
Serial.print(value);
print(args...); // Recursively call print for the remaining arguments
}
// Function to print a newline // Function to print a newline
void println(); void println();
// Overloaded function to print a single value and a newline // Overloaded function to print a single value and a newline
template <typename T> template <typename T>
void println(T value); void println(T value) {
Serial.println(value);
}
// Recursive function to print multiple values and a newline // Recursive function to print multiple values and a newline
template <typename T, typename... Args> template <typename T, typename... Args>
void println(T value, Args... args); void println(T value, Args... args) {
Serial.print(value);
println(args...); // Recursively call println for the remaining arguments
}
// Convenience functions for easy usage // Convenience functions for easy usage
template <typename... Args> template <typename... Args>
void print(Args... args); void print(Args... args) {
print(args...);
}
template <typename... Args> template <typename... Args>
void println(Args... args); void println(Args... args) {
println(args...);
}
String fstring(const char* format); String fstring(const char* format);
template <typename... Args> template <typename... Args>
String fstring(const char* format, Args... args); String fstring(const char* format, Args... args) {
String result = "";
while (*format) {
if (*format == '{' && *(format + 1) == '}' && sizeof...(args) > 0) {
result += String(args...);
format += 2; // Skip the "{}" in the format string
} else {
result += *format;
format++;
}
}
return result;
}
void printf(const char* format); void printf(const char* format);
template <typename... Args> template <typename... Args>
void printf(const char* format, Args... args); void printf(const char* format, Args... args) {
Serial.print(fstring(format, args...));
#endif // UTILS_PRINT_H }