document everything except InternalDisplay and IoT
This commit is contained in:
parent
4031b7555a
commit
789afc04dc
|
@ -1,5 +1,12 @@
|
|||
#include <DigitalOutputCard.hpp>
|
||||
|
||||
/**
|
||||
* @brief Create a new Digital Output Card object with the specified address
|
||||
*
|
||||
* @note If you are using the ESPMegaI/O board, you should use the dip switch constructor
|
||||
*
|
||||
* @param address The ESPMegaI/O address of the card
|
||||
*/
|
||||
DigitalOutputCard::DigitalOutputCard(uint8_t address) : change_callbacks(){
|
||||
this->address = address;
|
||||
// load default pin map
|
||||
|
@ -10,14 +17,34 @@ DigitalOutputCard::DigitalOutputCard(uint8_t address) : change_callbacks(){
|
|||
this->framBinded = false;
|
||||
this->callbacks_handler_index = 0;
|
||||
}
|
||||
// Instantiate the card with the specified position on the dip switch
|
||||
|
||||
/**
|
||||
* @brief Create a new Digital Output Card object with the specified position on the dip switch
|
||||
*
|
||||
* @note The bit 0 are at the left of the dip switch
|
||||
*
|
||||
* @warning There are 5 switches on the dip switch, they should be unique accross all the cards
|
||||
*
|
||||
* @param bit0 The position of the first switch on the dip switch
|
||||
* @param bit1 The position of the second switch on the dip switch
|
||||
* @param bit2 The position of the third switch on the dip switch
|
||||
* @param bit3 The position of the fourth switch on the dip switch
|
||||
* @param bit4 The position of the fifth switch on the dip switch
|
||||
*/
|
||||
DigitalOutputCard::DigitalOutputCard(bool bit0, bool bit1, bool bit2, bool bit3, bool bit4) :
|
||||
DigitalOutputCard(0x20+bit0+bit1*2+bit2*4+bit3*8+bit4*16)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
// Initialize the card
|
||||
|
||||
/**
|
||||
* @brief Initialize the Digital Output Card
|
||||
*
|
||||
* @note Although this function can be called inside the main program, it is recommended to use ESPMegaPRO::installCard() instead
|
||||
*
|
||||
* @return True if the initialization is successful, false otherwise
|
||||
*/
|
||||
bool DigitalOutputCard::begin() {
|
||||
this->pwm = Adafruit_PWMServoDriver(this->address);
|
||||
this->pwm.begin();
|
||||
|
@ -26,7 +53,15 @@ bool DigitalOutputCard::begin() {
|
|||
// so we just return true
|
||||
return true;
|
||||
}
|
||||
// Set the output to the specified state
|
||||
|
||||
/**
|
||||
* @brief Write a digtal LOW or HIGH to the specified pin
|
||||
*
|
||||
* @note This function set both the state and the pwm value of the pin
|
||||
*
|
||||
* @param pin The pin to set the state
|
||||
* @param state The logic level to set the pin to
|
||||
*/
|
||||
void DigitalOutputCard::digitalWrite(uint8_t pin, bool state) {
|
||||
this->pwm.setPin(virtualPinMap[pin], state ? 4095 : 0);
|
||||
this->state_buffer[pin] = state;
|
||||
|
@ -40,7 +75,15 @@ void DigitalOutputCard::digitalWrite(uint8_t pin, bool state) {
|
|||
callback.second(pin, state, state ? 4095 : 0);
|
||||
}
|
||||
}
|
||||
// Set the output to the specified pwm value
|
||||
|
||||
/**
|
||||
* @brief Write a pwm value to the specified pin
|
||||
*
|
||||
* @note This function set both the state and the pwm value of the pin
|
||||
*
|
||||
* @param pin The pin to set the pwm value
|
||||
* @param value The pwm value to set
|
||||
*/
|
||||
void DigitalOutputCard::analogWrite(uint8_t pin, uint16_t value) {
|
||||
// If value is greater than 4095, set it to 4095
|
||||
if (value > 4095) value = 4095;
|
||||
|
@ -58,25 +101,49 @@ void DigitalOutputCard::analogWrite(uint8_t pin, uint16_t value) {
|
|||
}
|
||||
}
|
||||
|
||||
// Dummy loop function
|
||||
/**
|
||||
* @brief The main loop for the Digital Output Card object.
|
||||
*
|
||||
* @note This function is not used, it is only here to implement the ExpansionCard interface
|
||||
*/
|
||||
void DigitalOutputCard::loop() {
|
||||
}
|
||||
|
||||
// Get the state of the specified pin
|
||||
/**
|
||||
* @brief Get the state of the specified pin
|
||||
*
|
||||
* @param pin The pin to get the state
|
||||
* @return The state of the pin
|
||||
*/
|
||||
bool DigitalOutputCard::getState(uint8_t pin) {
|
||||
return this->state_buffer[pin];
|
||||
}
|
||||
|
||||
// Get the pwm value of the specified pin
|
||||
/**
|
||||
* @brief Get the pwm value of the specified pin
|
||||
*
|
||||
* @param pin The pin to get the pwm value
|
||||
* @return The pwm value of the pin
|
||||
*/
|
||||
uint16_t DigitalOutputCard::getValue(uint8_t pin) {
|
||||
return this->value_buffer[pin];
|
||||
}
|
||||
|
||||
// Get type of card
|
||||
/**
|
||||
* @brief Get the type of the card
|
||||
*
|
||||
* @return The type of the card
|
||||
*/
|
||||
uint8_t DigitalOutputCard::getType() {
|
||||
return CARD_TYPE_DIGITAL_OUTPUT;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the state of the specified pin
|
||||
*
|
||||
* @param pin The pin to set the state
|
||||
* @param state The state of the pin
|
||||
*/
|
||||
void DigitalOutputCard::setState(uint8_t pin, bool state) {
|
||||
this-> state_buffer[pin] = state;
|
||||
this->pwm.setPin(pin, state*value_buffer[pin]);
|
||||
|
@ -88,6 +155,12 @@ void DigitalOutputCard::setState(uint8_t pin, bool state) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the pwm value of the specified pin
|
||||
*
|
||||
* @param pin The pin to set the pwm value
|
||||
* @param value The pwm value to set
|
||||
*/
|
||||
void DigitalOutputCard::setValue(uint8_t pin, uint16_t value) {
|
||||
// If value is greater than 4095, set it to 4095
|
||||
if (value > 4095) value = 4095;
|
||||
|
@ -102,15 +175,36 @@ void DigitalOutputCard::setValue(uint8_t pin, uint16_t value) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register a callback function for the specified pin
|
||||
*
|
||||
* @param callback The callback function to be called, the first parameter is the pin, the second parameter is the state, the third parameter is the pwm value
|
||||
* @return The handler of the callback function
|
||||
*/
|
||||
uint8_t DigitalOutputCard::registerChangeCallback(std::function<void(uint8_t, bool, uint16_t)> callback) {
|
||||
this->change_callbacks[this->callbacks_handler_index] = callback;
|
||||
return this->callbacks_handler_index++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unregister a callback function
|
||||
*
|
||||
* @param handler The handler of the callback function to be unregistered
|
||||
*/
|
||||
void DigitalOutputCard::unregisterChangeCallback(uint8_t handler) {
|
||||
this->change_callbacks.erase(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load a pin map
|
||||
*
|
||||
* A pin map is an array of 16 elements that maps the physical pins to virtual pins
|
||||
* The virtual pins are the pins that are used in the callback functions and are used for all the functions in this class
|
||||
* The physical pins are the pins on the Output IC, This can be found on the schematic of the ESPMegaI/O board
|
||||
* This function is useful if you want to change the number identification of the pins to match your project needs
|
||||
*
|
||||
* @param pinMap The pin map to load
|
||||
*/
|
||||
void DigitalOutputCard::loadPinMap(uint8_t pinMap[16]) {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
this->pinMap[i] = pinMap[i];
|
||||
|
@ -118,12 +212,27 @@ void DigitalOutputCard::loadPinMap(uint8_t pinMap[16]) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Bind a FRAM to the card
|
||||
*
|
||||
* @note The Output Card use 34 bytes of FRAM
|
||||
*
|
||||
* @warning If the fram range overlap with another card, undefined behavior will occur
|
||||
*
|
||||
* @param fram The FRAM to bind
|
||||
* @param address The address of the card in the FRAM
|
||||
*/
|
||||
void DigitalOutputCard::bindFRAM(FRAM *fram, uint16_t address) {
|
||||
this->fram = fram;
|
||||
this->framBinded = true;
|
||||
this->framAddress = address;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pack the states of all the pins into a 16 bit integer
|
||||
*
|
||||
* @return The packed states
|
||||
*/
|
||||
uint16_t DigitalOutputCard::packStates() {
|
||||
uint16_t packed = 0;
|
||||
for(int i = 0; i < 16; i++) {
|
||||
|
@ -132,12 +241,20 @@ uint16_t DigitalOutputCard::packStates() {
|
|||
return packed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unpack the states of all the pins from a 16 bit integer
|
||||
*
|
||||
* @param states The packed states
|
||||
*/
|
||||
void DigitalOutputCard::unpackStates(uint16_t states) {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
this->setState(i, (states >> i) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save the states and values of all the pins to the FRAM
|
||||
*/
|
||||
void DigitalOutputCard::saveToFRAM() {
|
||||
if(!framBinded) return;
|
||||
// Save the state
|
||||
|
@ -147,6 +264,9 @@ void DigitalOutputCard::saveToFRAM() {
|
|||
this->fram->write(framAddress+2, (uint8_t*)value_buffer, 32);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Load the states and values of all the pins from the FRAM
|
||||
*/
|
||||
void DigitalOutputCard::loadFromFRAM() {
|
||||
if(!framBinded) return;
|
||||
// Load the state
|
||||
|
@ -160,15 +280,28 @@ void DigitalOutputCard::loadFromFRAM() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the auto save to FRAM
|
||||
*
|
||||
* @param autoSave True to enable auto save, false to disable auto save
|
||||
*/
|
||||
void DigitalOutputCard::setAutoSaveToFRAM(bool autoSave) {
|
||||
this->framAutoSave = autoSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save a single pin value to FRAM
|
||||
*
|
||||
* @param pin The pin to save
|
||||
*/
|
||||
void DigitalOutputCard::savePinValueToFRAM(uint8_t pin) {
|
||||
if(!framBinded) return;
|
||||
this->fram->write(framAddress+2+pin*2, (uint8_t*)&value_buffer[pin], 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Save the states of all the pins to FRAM
|
||||
*/
|
||||
void DigitalOutputCard::saveStateToFRAM() {
|
||||
if(!framBinded) return;
|
||||
uint16_t packed = packStates();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// Publish all topic: requeststate payload: N/A
|
||||
// Enable/disable publish topic: publish_enable payload: 0/1
|
||||
|
||||
// MQTT Topics
|
||||
#define SET_STATE_TOPIC "/set/state"
|
||||
#define SET_VALUE_TOPIC "/set/value"
|
||||
#define STATE_TOPIC "/state"
|
||||
|
@ -20,8 +21,20 @@
|
|||
#define REQUEST_STATE_TOPIC "requeststate"
|
||||
#define PUBLISH_ENABLE_TOPIC "publish_enable"
|
||||
|
||||
// Card type
|
||||
#define CARD_TYPE_DIGITAL_OUTPUT 0x00
|
||||
|
||||
/**
|
||||
* @brief The DigitalOutputCard class is a class for controlling the Digital Output Card.
|
||||
*
|
||||
* This Digital Output Card has 16 digital outputs.
|
||||
* All outputs are PWM capable.
|
||||
* ALl outputs are 12V Push-Pull outputs.
|
||||
* Outputs is grouped in 4 groups of 4 outputs.(0-3, 4-7, 8-11, 12-15)
|
||||
* Each pin is capable of 0.6A, however each group's total current is limited to 1.2A.
|
||||
*
|
||||
* @warning You should not instantiate this class directly, instead use ESPMegaIO's registerCard function.
|
||||
*/
|
||||
class DigitalOutputCard : public ExpansionCard
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,22 +1,42 @@
|
|||
#include <DigitalOutputIoT.hpp>
|
||||
|
||||
DigitalOutputIoT::DigitalOutputIoT() {
|
||||
/**
|
||||
* @brief Create a new DigitalOutputIoT object
|
||||
*/
|
||||
DigitalOutputIoT::DigitalOutputIoT()
|
||||
{
|
||||
this->state_report_topic = new char[10];
|
||||
this->value_report_topic = new char[10];
|
||||
this->digital_outputs_publish_enabled = true;
|
||||
}
|
||||
|
||||
DigitalOutputIoT::~DigitalOutputIoT() {
|
||||
/**
|
||||
* @brief Destroy the DigitalOutputIoT object
|
||||
*/
|
||||
DigitalOutputIoT::~DigitalOutputIoT()
|
||||
{
|
||||
delete[] this->state_report_topic;
|
||||
delete[] this->value_report_topic;
|
||||
}
|
||||
|
||||
bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic) {
|
||||
/**
|
||||
* @brief Initialize the DigitalOutputIoT object
|
||||
*
|
||||
* @note ALthough this function can be called inside the main program, it is recommended to use ESPMegaPRO::installCard() instead
|
||||
*
|
||||
* @param card_id The id of the card
|
||||
* @param card The card object
|
||||
* @param mqtt The PubSubClient object
|
||||
* @param base_topic The base topic of the card
|
||||
* @return True if the initialization is successful, false otherwise
|
||||
*/
|
||||
bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic)
|
||||
{
|
||||
ESP_LOGD("DigitalOutputIoT", "Beginning DigitalOutputIoT");
|
||||
this->mqtt = mqtt;
|
||||
this->base_topic = base_topic;
|
||||
this->card = (DigitalOutputCard *) card;
|
||||
this-> card_id = card_id;
|
||||
this->card = (DigitalOutputCard *)card;
|
||||
this->card_id = card_id;
|
||||
this->set_state_length = strlen(SET_STATE_TOPIC);
|
||||
this->set_value_length = strlen(SET_VALUE_TOPIC);
|
||||
this->state_length = strlen(STATE_TOPIC);
|
||||
|
@ -27,51 +47,78 @@ bool DigitalOutputIoT::begin(uint8_t card_id, ExpansionCard *card, PubSubClient
|
|||
strcpy(this->value_report_topic, "00/value");
|
||||
ESP_LOGV("DigitalOutputIoT", "Registering callbacks inside DigitalOutputIoT::begin");
|
||||
// Register callbacks
|
||||
auto bindedCallback = std::bind(&DigitalOutputIoT::handleValueChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
auto bindedCallback = std::bind(&DigitalOutputIoT::handleValueChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
this->card->registerChangeCallback(bindedCallback);
|
||||
ESP_LOGV("DigitalOutputIoT", "DigitalOutputIoT::begin complete");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Protocol for digital output card
|
||||
// Note that pin is always 2 characters long and padded with 0 if necessary
|
||||
// Set pin state topic: <pin>/set/state payload: 0/1
|
||||
// Set pin pwm topic: <pin>/set/value payload: 0-4095
|
||||
// Publish pin state topic: <pin>/state payload: 0/1
|
||||
// Publish pin pwm topic: <pin>/value payload: 0-4095
|
||||
// Publish all topic: requeststate payload: N/A
|
||||
// Enable/disable publish topic: publish_enable payload: 0/1
|
||||
void DigitalOutputIoT::handleMqttMessage(char *topic, char *payload) {
|
||||
/**
|
||||
* @brief Handle the MQTT messages for the DigitalOutputIoT card
|
||||
*
|
||||
* @param topic The topic of the message
|
||||
* @param payload The payload of the message
|
||||
*/
|
||||
void DigitalOutputIoT::handleMqttMessage(char *topic, char *payload)
|
||||
{
|
||||
// Protocol for digital output card
|
||||
// Note that pin is always 2 characters long and padded with 0 if necessary
|
||||
// Set pin state topic: <pin>/set/state payload: 0/1
|
||||
// Set pin pwm topic: <pin>/set/value payload: 0-4095
|
||||
// Publish pin state topic: <pin>/state payload: 0/1
|
||||
// Publish pin pwm topic: <pin>/value payload: 0-4095
|
||||
// Publish all topic: requeststate payload: N/A
|
||||
// Enable/disable publish topic: publish_enable payload: 0/1
|
||||
uint8_t topic_length = strlen(topic);
|
||||
if(this-> processSetStateMessage(topic, payload, topic_length)) return;
|
||||
if(this-> processSetValueMessage(topic, payload, topic_length)) return;
|
||||
if(this-> processRequestStateMessage(topic, payload, topic_length)) return;
|
||||
if (this->processSetStateMessage(topic, payload, topic_length))
|
||||
return;
|
||||
if (this->processSetValueMessage(topic, payload, topic_length))
|
||||
return;
|
||||
if (this->processRequestStateMessage(topic, payload, topic_length))
|
||||
return;
|
||||
}
|
||||
|
||||
bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_t topic_length) {
|
||||
/**
|
||||
* @brief Process a set state message
|
||||
*
|
||||
* @param topic The null terminated topic
|
||||
* @param payload The null terminated payload
|
||||
* @param topic_length The length of the topic
|
||||
* @return True if the message is a set state message, false otherwise
|
||||
*/
|
||||
bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_t topic_length)
|
||||
{
|
||||
// Check if the topic is a set state topic
|
||||
// The correct format is <pin>/set/state
|
||||
// This mean that the topic must end with /set/state
|
||||
// Check if the 3rd character is /
|
||||
if(topic[2] != '/') {
|
||||
if (topic[2] != '/')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// The topic must be set_state_length + 2 characters long
|
||||
if(topic_length != set_state_length + 2) {
|
||||
if (topic_length != set_state_length + 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check if the topic ends with /set/state
|
||||
if (!strncmp(topic+2, SET_STATE_TOPIC, set_state_length)) {
|
||||
if (!strncmp(topic + 2, SET_STATE_TOPIC, set_state_length))
|
||||
{
|
||||
// Get the pin number
|
||||
uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0');
|
||||
uint8_t pin = (topic[0] - '0') * 10 + (topic[1] - '0');
|
||||
// Get the state
|
||||
bool state = false;
|
||||
char state_char = payload[0];
|
||||
if (state_char == '0') {
|
||||
if (state_char == '0')
|
||||
{
|
||||
state = false;
|
||||
} else if (state_char == '1') {
|
||||
}
|
||||
else if (state_char == '1')
|
||||
{
|
||||
state = true;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Set the state
|
||||
|
@ -81,22 +128,34 @@ bool DigitalOutputIoT::processSetStateMessage(char *topic, char *payload, uint8_
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DigitalOutputIoT::processSetValueMessage(char *topic, char *payload, uint8_t topic_length) {
|
||||
/**
|
||||
* @brief Process a set value message
|
||||
*
|
||||
* @param topic The null terminated topic
|
||||
* @param payload The null terminated payload
|
||||
* @param topic_length The length of the topic
|
||||
* @return True if the message is a set value message, false otherwise
|
||||
*/
|
||||
bool DigitalOutputIoT::processSetValueMessage(char *topic, char *payload, uint8_t topic_length)
|
||||
{
|
||||
// Check if the topic is a set value topic
|
||||
// The correct format is <pin>/set/value
|
||||
// This mean that the topic must end with /set/value
|
||||
// Check if the 3rd character is /
|
||||
if(topic[2] != '/') {
|
||||
if (topic[2] != '/')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// The topic must be set_value_length + 2 characters long
|
||||
if(topic_length != set_value_length + 2) {
|
||||
if (topic_length != set_value_length + 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check if the topic ends with /set/value
|
||||
if (!strncmp(topic+2, SET_VALUE_TOPIC, set_value_length)) {
|
||||
if (!strncmp(topic + 2, SET_VALUE_TOPIC, set_value_length))
|
||||
{
|
||||
// Get the pin number
|
||||
uint8_t pin = (topic[0] - '0')*10 + (topic[1] - '0');
|
||||
uint8_t pin = (topic[0] - '0') * 10 + (topic[1] - '0');
|
||||
// Get the value
|
||||
uint16_t value = atoi(payload);
|
||||
// Set the value
|
||||
|
@ -106,16 +165,27 @@ bool DigitalOutputIoT::processSetValueMessage(char *topic, char *payload, uint8_
|
|||
return false;
|
||||
}
|
||||
|
||||
bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, uint8_t topic_length) {
|
||||
/**
|
||||
* @brief Process a request state message
|
||||
*
|
||||
* @param topic The null terminated topic
|
||||
* @param payload The null terminated payload
|
||||
* @param topic_length The length of the topic
|
||||
* @return True if the message is a request state message, false otherwise
|
||||
*/
|
||||
bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, uint8_t topic_length)
|
||||
{
|
||||
// Check if the topic is a request state topic
|
||||
// The correct format is requeststate
|
||||
// This mean that the topic must be request_state_length characters long
|
||||
// The topic must be request_state_length characters long
|
||||
if(topic_length != request_state_length) {
|
||||
if (topic_length != request_state_length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Check if the topic is requeststate
|
||||
if (!strncmp(topic, REQUEST_STATE_TOPIC, request_state_length)) {
|
||||
if (!strncmp(topic, REQUEST_STATE_TOPIC, request_state_length))
|
||||
{
|
||||
// Publish the state of all pins
|
||||
publishDigitalOutputs();
|
||||
return true;
|
||||
|
@ -123,27 +193,53 @@ bool DigitalOutputIoT::processRequestStateMessage(char *topic, char *payload, ui
|
|||
return false;
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::publishDigitalOutputs() {
|
||||
if(!digital_outputs_publish_enabled) return;
|
||||
for(int i = 0; i < 16; i++) {
|
||||
/**
|
||||
* @brief Publish the state of all digital outputs
|
||||
*/
|
||||
void DigitalOutputIoT::publishDigitalOutputs()
|
||||
{
|
||||
if (!digital_outputs_publish_enabled)
|
||||
return;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
publishDigitalOutput(i);
|
||||
}
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::publishDigitalOutput(uint8_t pin) {
|
||||
/**
|
||||
* @brief Publish the state and value of the specified digital output
|
||||
*
|
||||
* @param pin The pin to publish
|
||||
*/
|
||||
void DigitalOutputIoT::publishDigitalOutput(uint8_t pin)
|
||||
{
|
||||
publishDigitalOutputState(pin);
|
||||
publishDigitalOutputValue(pin);
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::publishDigitalOutputState(uint8_t pin) {
|
||||
if(!digital_outputs_publish_enabled) return;
|
||||
/**
|
||||
* @brief Publish the state of the specified digital output
|
||||
*
|
||||
* @param pin The pin to publish
|
||||
*/
|
||||
void DigitalOutputIoT::publishDigitalOutputState(uint8_t pin)
|
||||
{
|
||||
if (!digital_outputs_publish_enabled)
|
||||
return;
|
||||
state_report_topic[0] = pin / 10 + '0';
|
||||
state_report_topic[1] = pin % 10 + '0';
|
||||
publishRelative(state_report_topic, card->getState(pin) ? "1" : "0");
|
||||
}
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::publishDigitalOutputValue(uint8_t pin) {
|
||||
if(!digital_outputs_publish_enabled) return;
|
||||
/**
|
||||
* @brief Publish the value of the specified digital output
|
||||
*
|
||||
* @param pin The pin to publish
|
||||
*/
|
||||
void DigitalOutputIoT::publishDigitalOutputValue(uint8_t pin)
|
||||
{
|
||||
if (!digital_outputs_publish_enabled)
|
||||
return;
|
||||
value_report_topic[0] = pin / 10 + '0';
|
||||
value_report_topic[1] = pin % 10 + '0';
|
||||
char payload[5];
|
||||
|
@ -151,42 +247,65 @@ void DigitalOutputIoT::publishDigitalOutputValue(uint8_t pin) {
|
|||
publishRelative(value_report_topic, payload);
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::setDigitalOutputsPublishEnabled(bool enabled) {
|
||||
/**
|
||||
* @brief Enable/disable publishing of digital outputs
|
||||
*
|
||||
* @param enabled True to enable publishing, false to disable publishing
|
||||
*/
|
||||
void DigitalOutputIoT::setDigitalOutputsPublishEnabled(bool enabled)
|
||||
{
|
||||
digital_outputs_publish_enabled = enabled;
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::handleValueChange(uint8_t pin, bool state, uint16_t value) {
|
||||
/**
|
||||
* @brief Handle the value change of a pin
|
||||
*
|
||||
* @note This function is registered as a callback function with the DigitalOutputCard object
|
||||
*
|
||||
* @param pin The pin that changed
|
||||
* @param state The new state of the pin
|
||||
* @param value The new value of the pin
|
||||
*/
|
||||
void DigitalOutputIoT::handleValueChange(uint8_t pin, bool state, uint16_t value)
|
||||
{
|
||||
publishDigitalOutput(pin);
|
||||
if(value_change_callback != NULL) {
|
||||
value_change_callback(pin, state, value);
|
||||
}
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::registerChangeCallback(std::function<void(uint8_t, bool, uint16_t)> callback) {
|
||||
value_change_callback = callback;
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::unregisterChangeCallback() {
|
||||
value_change_callback = NULL;
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::publishReport() {
|
||||
/**
|
||||
* @brief Publish all digital outputs
|
||||
*
|
||||
* @note This function is called by the ESPMegaIoT object
|
||||
*/
|
||||
void DigitalOutputIoT::publishReport()
|
||||
{
|
||||
publishDigitalOutputs();
|
||||
}
|
||||
|
||||
uint8_t DigitalOutputIoT::getType() {
|
||||
/**
|
||||
* @brief Get the type of the IoT component
|
||||
*
|
||||
* @return The type of the IoT component
|
||||
*/
|
||||
uint8_t DigitalOutputIoT::getType()
|
||||
{
|
||||
return CARD_TYPE_DIGITAL_OUTPUT;
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::subscribe() {
|
||||
/**
|
||||
* @brief Subscribe to the MQTT topics used by the DigitalOutputIoT object
|
||||
*/
|
||||
void DigitalOutputIoT::subscribe()
|
||||
{
|
||||
char topic[20];
|
||||
// Subscribe to all set state topics
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
sprintf(topic, "%02d/set/state", i);
|
||||
subscribeRelative(topic);
|
||||
}
|
||||
// Subscribe to all set value topics
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
sprintf(topic, "%02d/set/value", i);
|
||||
subscribeRelative(topic);
|
||||
}
|
||||
|
@ -196,5 +315,11 @@ void DigitalOutputIoT::subscribe() {
|
|||
subscribeRelative(PUBLISH_ENABLE_TOPIC);
|
||||
}
|
||||
|
||||
void DigitalOutputIoT::loop() {
|
||||
/**
|
||||
* @brief The main loop for the DigitalOutputIoT object
|
||||
*
|
||||
* @note This function is not used, it is only here to implement the IoTComponent interface
|
||||
*/
|
||||
void DigitalOutputIoT::loop()
|
||||
{
|
||||
}
|
|
@ -3,6 +3,11 @@
|
|||
#include <ExpansionCard.hpp>
|
||||
#include <DigitalOutputCard.hpp>
|
||||
|
||||
/**
|
||||
* @brief The DigitalOutputIoT class is a class interfacing with the Digital Output Card through MQTT.
|
||||
*
|
||||
* @warning You should not instantiate this class directly, instead use ESPMegaIO's registerCard function.
|
||||
*/
|
||||
class DigitalOutputIoT : public IoTComponent {
|
||||
public:
|
||||
DigitalOutputIoT();
|
||||
|
@ -15,8 +20,6 @@ class DigitalOutputIoT : public IoTComponent {
|
|||
void publishDigitalOutputValue(uint8_t pin);
|
||||
void setDigitalOutputsPublishEnabled(bool enabled);
|
||||
void handleValueChange(uint8_t pin, bool state, uint16_t value);
|
||||
void registerChangeCallback(std::function<void(uint8_t, bool, uint16_t)> callback);
|
||||
void unregisterChangeCallback();
|
||||
void publishReport();
|
||||
void subscribe();
|
||||
void loop();
|
||||
|
@ -26,7 +29,6 @@ class DigitalOutputIoT : public IoTComponent {
|
|||
bool processSetStateMessage(char *topic, char *payload, uint8_t topic_length);
|
||||
bool processSetValueMessage(char *topic, char *payload, uint8_t topic_length);
|
||||
bool processRequestStateMessage(char *topic, char *payload, uint8_t topic_length);
|
||||
std::function<void(uint8_t, bool, uint16_t)> value_change_callback;
|
||||
DigitalOutputCard *card;
|
||||
char *state_report_topic;
|
||||
char *value_report_topic;
|
||||
|
|
|
@ -36,6 +36,7 @@ bool ESPMegaDisplay::recieveSerialCommand()
|
|||
|
||||
/**
|
||||
* @brief Processes the received serial command.
|
||||
* @note This function interacts directly with the rx_buffer.
|
||||
*/
|
||||
void ESPMegaDisplay::processSerialCommand()
|
||||
{
|
||||
|
@ -62,6 +63,7 @@ void ESPMegaDisplay::processSerialCommand()
|
|||
|
||||
/**
|
||||
* @brief Processes the touch event payload.
|
||||
* @note This function interacts directly with the rx_buffer.
|
||||
*/
|
||||
void ESPMegaDisplay::processTouchPayload()
|
||||
{
|
||||
|
@ -83,6 +85,7 @@ void ESPMegaDisplay::processTouchPayload()
|
|||
|
||||
/**
|
||||
* @brief Processes the page report event payload.
|
||||
* @note This function interacts directly with the rx_buffer.
|
||||
*/
|
||||
void ESPMegaDisplay::processPageReportPayload()
|
||||
{
|
||||
|
@ -161,6 +164,8 @@ void ESPMegaDisplay::setString(const char *component, const char *value)
|
|||
|
||||
/**
|
||||
* @brief Gets the value of a number component from the display.
|
||||
* @warning This function is blocking.
|
||||
* @warning If the display does not respond or is not connected, this function will block for up to DISPLAY_FETCH_RETRY_COUNT * DISPLAY_FETCH_TIMEOUT milliseconds.
|
||||
* @param component The component name.
|
||||
* @return The value of the number component.
|
||||
*/
|
||||
|
@ -219,6 +224,8 @@ uint32_t ESPMegaDisplay::getNumber(const char *component)
|
|||
|
||||
/**
|
||||
* @brief Gets the value of a string component from the display.
|
||||
* @warning This function is blocking.
|
||||
* @warning If the display does not respond or is not connected, this function will block for up to DISPLAY_FETCH_RETRY_COUNT * DISPLAY_FETCH_TIMEOUT milliseconds.
|
||||
* @param component The component name.
|
||||
* @return The value of the string component.
|
||||
* @note The returned char array must be freed after use.
|
||||
|
@ -275,6 +282,15 @@ const char *ESPMegaDisplay::getString(const char *component)
|
|||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the value of a number component from the display and stores it in a buffer.
|
||||
* @warning This function is blocking.
|
||||
* @warning If the display does not respond or is not connected, this function will block for up to DISPLAY_FETCH_RETRY_COUNT * DISPLAY_FETCH_TIMEOUT milliseconds.
|
||||
* @param component The component name.
|
||||
* @param buffer The buffer to store the value.
|
||||
* @param buffer_size The size of the buffer.
|
||||
* @return True if the value is successfully stored in the buffer, false otherwise.
|
||||
*/
|
||||
bool ESPMegaDisplay::getStringToBuffer(const char *component, char *buffer, uint8_t buffer_size)
|
||||
{
|
||||
// We might be in the middle of a serial command
|
||||
|
|
|
@ -5,6 +5,12 @@
|
|||
#define DISPLAY_FETCH_TIMEOUT 100 // ms
|
||||
#define DISPLAY_FETCH_RETRY_COUNT 5
|
||||
|
||||
/**
|
||||
* @brief The ESPMegaDisplay class is a class for controlling the ESPMegaDisplay.
|
||||
*
|
||||
* @note The ESPMegaDisplay is a UART controlled display.
|
||||
* @note Connect the Display's TX pin to the ESPMega's RX pin and the Display's RX pin to the ESPMega's TX pin.
|
||||
*/
|
||||
class ESPMegaDisplay
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -1,6 +1,17 @@
|
|||
#pragma once
|
||||
#include <Arduino.h>
|
||||
|
||||
/**
|
||||
* @brief The base class for all expansion cards
|
||||
*
|
||||
* In order to create a new expansion card, you should create a new class that inherits from this class.
|
||||
* Your class should implement the following functions:
|
||||
* - begin() : Initialize the card
|
||||
* - loop() : A function that is called in the main loop
|
||||
* - getType() : Get the type of the card, The type should be a unique number between 0 and 255
|
||||
*
|
||||
* @warning This class is abstract and should not be instantiated directly.
|
||||
*/
|
||||
class ExpansionCard {
|
||||
public:
|
||||
// Instantiate the card with the specified address
|
||||
|
|
|
@ -2,6 +2,25 @@
|
|||
#include <ExpansionCard.hpp>
|
||||
#include <PubSubClient.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
/**
|
||||
* @brief The IoTComponent class is a base class that is used to interface with an expansion card through MQTT.
|
||||
*
|
||||
* In order to create a new IoTComponent, you should create a new class that inherits from this class.
|
||||
* Your class should implement the following functions:
|
||||
* - begin() : Initialize the component, record the card id, ExpansionCard object, the PubSubClient object and the base topic
|
||||
* - handleMqttMessage() : Handle the MQTT messages for the component
|
||||
* - publishReport() : Publish all the reports for the component
|
||||
* - getType() : Get the type of the component, This should return the underlying ExpansionCard type
|
||||
* - subscribe() : Subscribe to the MQTT topics used by the component
|
||||
* - loop() : A function that is called in the main loop
|
||||
*
|
||||
* Additionally, the inherited class will have access to these helper functions:
|
||||
* - publishRelative() : Publish a message to a topic relative to the base topic and the card id
|
||||
* - subscribeRelative() : Subscribe to a topic relative to the base topic and the card id
|
||||
*
|
||||
* @warning This class is abstract and should not be instantiated directly.
|
||||
*/
|
||||
class IoTComponent {
|
||||
public:
|
||||
virtual bool begin(uint8_t card_id, ExpansionCard *card, PubSubClient *mqtt, char *base_topic);
|
||||
|
@ -10,7 +29,6 @@ class IoTComponent {
|
|||
virtual void publishReport();
|
||||
virtual uint8_t getType();
|
||||
virtual void subscribe();
|
||||
|
||||
void loop();
|
||||
protected:
|
||||
char *base_topic;
|
||||
|
|
Loading…
Reference in New Issue