mirror of https://github.com/arendst/Tasmota.git
Update to new API version of ESP-KNX-IP
This commit is contained in:
parent
2ce8faec62
commit
83d6049fe5
|
@ -41,7 +41,9 @@ void ESPKNXIP::__handle_root()
|
||||||
break;
|
break;
|
||||||
case FEEDBACK_TYPE_FLOAT:
|
case FEEDBACK_TYPE_FLOAT:
|
||||||
m += F("<span class='input-group-text'>");
|
m += F("<span class='input-group-text'>");
|
||||||
|
m += feedbacks[i].options.float_options.prefix;
|
||||||
m += String(*(float *)feedbacks[i].data, feedbacks[i].options.float_options.precision);
|
m += String(*(float *)feedbacks[i].data, feedbacks[i].options.float_options.precision);
|
||||||
|
m += feedbacks[i].options.float_options.suffix;
|
||||||
m += F("</span>");
|
m += F("</span>");
|
||||||
break;
|
break;
|
||||||
case FEEDBACK_TYPE_BOOL:
|
case FEEDBACK_TYPE_BOOL:
|
||||||
|
@ -52,7 +54,9 @@ void ESPKNXIP::__handle_root()
|
||||||
case FEEDBACK_TYPE_ACTION:
|
case FEEDBACK_TYPE_ACTION:
|
||||||
m += F("<input class='form-control' type='hidden' name='id' value='");
|
m += F("<input class='form-control' type='hidden' name='id' value='");
|
||||||
m += i;
|
m += i;
|
||||||
m += F("' /><div class='input-group-append'><button type='submit' class='btn btn-primary'>Do this</button></div>");
|
m += F("' /><div class='input-group-append'><button type='submit' class='btn btn-primary'>");
|
||||||
|
m += feedbacks[i].options.action_options.btn_text;
|
||||||
|
m += F("</button></div>");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m += F("</div></div></div>");
|
m += F("</div></div></div>");
|
||||||
|
@ -67,6 +71,12 @@ void ESPKNXIP::__handle_root()
|
||||||
{
|
{
|
||||||
for (uint8_t i = 0; i < registered_callback_assignments; ++i)
|
for (uint8_t i = 0; i < registered_callback_assignments; ++i)
|
||||||
{
|
{
|
||||||
|
// Skip empty slots
|
||||||
|
if ((callback_assignments[i].slot_flags & SLOT_FLAGS_USED) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip disabled callbacks
|
||||||
if (callbacks[callback_assignments[i].callback_id].cond && !callbacks[callback_assignments[i].callback_id].cond())
|
if (callbacks[callback_assignments[i].callback_id].cond && !callbacks[callback_assignments[i].callback_id].cond())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -105,6 +115,12 @@ void ESPKNXIP::__handle_root()
|
||||||
m += F("<select class='form-control' name='cb'>");
|
m += F("<select class='form-control' name='cb'>");
|
||||||
for (callback_id_t i = 0; i < registered_callbacks; ++i)
|
for (callback_id_t i = 0; i < registered_callbacks; ++i)
|
||||||
{
|
{
|
||||||
|
// Skip empty slots
|
||||||
|
if ((callbacks[i].slot_flags & SLOT_FLAGS_USED) == 0)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Skip disabled callbacks
|
||||||
if (callbacks[i].cond && !callbacks[i].cond())
|
if (callbacks[i].cond && !callbacks[i].cond())
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -295,7 +311,7 @@ void ESPKNXIP::__handle_register()
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cb >= registered_callbacks)
|
if (!__callback_is_id_valid(cb))
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("Invalid callback id"));
|
DEBUG_PRINTLN(F("Invalid callback id"));
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -319,7 +335,7 @@ void ESPKNXIP::__handle_delete()
|
||||||
DEBUG_PRINT(id);
|
DEBUG_PRINT(id);
|
||||||
DEBUG_PRINTLN(F(""));
|
DEBUG_PRINTLN(F(""));
|
||||||
|
|
||||||
if (id >= registered_callback_assignments)
|
if (id >= registered_callback_assignments || (callback_assignments[id].slot_flags & SLOT_FLAGS_USED) == 0)
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("ID wrong"));
|
DEBUG_PRINTLN(F("ID wrong"));
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
@ -6,7 +6,21 @@
|
||||||
|
|
||||||
#include "esp-knx-ip.h"
|
#include "esp-knx-ip.h"
|
||||||
|
|
||||||
ESPKNXIP::ESPKNXIP() : server(nullptr), registered_callback_assignments(0), registered_callbacks(0), registered_configs(0), registered_feedbacks(0)
|
char const *string_defaults[] =
|
||||||
|
{
|
||||||
|
"Do this",
|
||||||
|
"True",
|
||||||
|
"False",
|
||||||
|
""
|
||||||
|
};
|
||||||
|
|
||||||
|
ESPKNXIP::ESPKNXIP() : server(nullptr),
|
||||||
|
registered_callback_assignments(0),
|
||||||
|
free_callback_assignment_slots(0),
|
||||||
|
registered_callbacks(0),
|
||||||
|
free_callback_slots(0),
|
||||||
|
registered_configs(0),
|
||||||
|
registered_feedbacks(0)
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN();
|
DEBUG_PRINTLN();
|
||||||
DEBUG_PRINTLN("ESPKNXIP starting up");
|
DEBUG_PRINTLN("ESPKNXIP starting up");
|
||||||
|
@ -27,65 +41,65 @@ void ESPKNXIP::load()
|
||||||
restore_from_eeprom();
|
restore_from_eeprom();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::start(ESP8266WebServer *srv, bool espknxip_webpage)
|
void ESPKNXIP::start(ESP8266WebServer *srv)
|
||||||
{
|
{
|
||||||
server = srv;
|
server = srv;
|
||||||
if (espknxip_webpage) { __start_espknxip_webpage(); }
|
|
||||||
__start();
|
__start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::start()
|
void ESPKNXIP::start()
|
||||||
{
|
{
|
||||||
server = new ESP8266WebServer(80);
|
server = new ESP8266WebServer(80);
|
||||||
__start_espknxip_webpage();
|
|
||||||
__start();
|
__start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::__start_espknxip_webpage()
|
|
||||||
{
|
|
||||||
server->on(ROOT_PREFIX, [this](){
|
|
||||||
__handle_root();
|
|
||||||
});
|
|
||||||
server->on(__ROOT_PATH, [this](){
|
|
||||||
__handle_root();
|
|
||||||
});
|
|
||||||
server->on(__REGISTER_PATH, [this](){
|
|
||||||
__handle_register();
|
|
||||||
});
|
|
||||||
server->on(__DELETE_PATH, [this](){
|
|
||||||
__handle_delete();
|
|
||||||
});
|
|
||||||
server->on(__PHYS_PATH, [this](){
|
|
||||||
__handle_set();
|
|
||||||
});
|
|
||||||
#if !DISABLE_EEPROM_BUTTONS
|
|
||||||
server->on(__EEPROM_PATH, [this](){
|
|
||||||
__handle_eeprom();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
server->on(__CONFIG_PATH, [this](){
|
|
||||||
__handle_config();
|
|
||||||
});
|
|
||||||
server->on(__FEEDBACK_PATH, [this](){
|
|
||||||
__handle_feedback();
|
|
||||||
});
|
|
||||||
#if !DISABLE_RESTORE_BUTTON
|
|
||||||
server->on(__RESTORE_PATH, [this](){
|
|
||||||
__handle_restore();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
#if !DISABLE_REBOOT_BUTTON
|
|
||||||
server->on(__REBOOT_PATH, [this](){
|
|
||||||
__handle_reboot();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
server->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESPKNXIP::__start()
|
void ESPKNXIP::__start()
|
||||||
{
|
{
|
||||||
|
if (server != nullptr)
|
||||||
|
{
|
||||||
|
server->on(ROOT_PREFIX, [this](){
|
||||||
|
__handle_root();
|
||||||
|
});
|
||||||
|
server->on(__ROOT_PATH, [this](){
|
||||||
|
__handle_root();
|
||||||
|
});
|
||||||
|
server->on(__REGISTER_PATH, [this](){
|
||||||
|
__handle_register();
|
||||||
|
});
|
||||||
|
server->on(__DELETE_PATH, [this](){
|
||||||
|
__handle_delete();
|
||||||
|
});
|
||||||
|
server->on(__PHYS_PATH, [this](){
|
||||||
|
__handle_set();
|
||||||
|
});
|
||||||
|
#if !DISABLE_EEPROM_BUTTONS
|
||||||
|
server->on(__EEPROM_PATH, [this](){
|
||||||
|
__handle_eeprom();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
server->on(__CONFIG_PATH, [this](){
|
||||||
|
__handle_config();
|
||||||
|
});
|
||||||
|
server->on(__FEEDBACK_PATH, [this](){
|
||||||
|
__handle_feedback();
|
||||||
|
});
|
||||||
|
#if !DISABLE_RESTORE_BUTTON
|
||||||
|
server->on(__RESTORE_PATH, [this](){
|
||||||
|
__handle_restore();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
#if !DISABLE_REBOOT_BUTTON
|
||||||
|
server->on(__REBOOT_PATH, [this](){
|
||||||
|
__handle_reboot();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
server->begin();
|
||||||
|
}
|
||||||
|
|
||||||
udp.listenMulticast(MULTICAST_IP, MULTICAST_PORT);
|
udp.listenMulticast(MULTICAST_IP, MULTICAST_PORT);
|
||||||
udp.onPacket([this](AsyncUDPPacket &packet) { __loop_knx(packet); });
|
udp.onPacket([this](AsyncUDPPacket &packet) {
|
||||||
|
DEBUG_PRINTLN("got packet");
|
||||||
|
__loop_knx(packet); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::save_to_eeprom()
|
void ESPKNXIP::save_to_eeprom()
|
||||||
|
@ -139,6 +153,26 @@ void ESPKNXIP::restore_from_eeprom()
|
||||||
for (uint8_t i = 0; i < MAX_CALLBACK_ASSIGNMENTS; ++i)
|
for (uint8_t i = 0; i < MAX_CALLBACK_ASSIGNMENTS; ++i)
|
||||||
{
|
{
|
||||||
EEPROM.get(address, callback_assignments[i].address);
|
EEPROM.get(address, callback_assignments[i].address);
|
||||||
|
if (callback_assignments[i].address.value != 0)
|
||||||
|
{
|
||||||
|
// if address is not 0/0/0 then mark slot as used
|
||||||
|
callback_assignments[i].slot_flags |= SLOT_FLAGS_USED;
|
||||||
|
DEBUG_PRINTLN("used slot");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if address is 0/0/0, then we found a free slot, yay!
|
||||||
|
// however, only count those slots, if we have not reached registered_callback_assignments yet
|
||||||
|
if (i < registered_callback_assignments)
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN("free slot before reaching registered_callback_assignments");
|
||||||
|
free_callback_assignment_slots++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN("free slot");
|
||||||
|
}
|
||||||
|
}
|
||||||
address += sizeof(address_t);
|
address += sizeof(address_t);
|
||||||
}
|
}
|
||||||
for (uint8_t i = 0; i < MAX_CALLBACK_ASSIGNMENTS; ++i)
|
for (uint8_t i = 0; i < MAX_CALLBACK_ASSIGNMENTS; ++i)
|
||||||
|
@ -188,68 +222,106 @@ callback_assignment_id_t ESPKNXIP::__callback_register_assignment(address_t addr
|
||||||
if (registered_callback_assignments >= MAX_CALLBACK_ASSIGNMENTS)
|
if (registered_callback_assignments >= MAX_CALLBACK_ASSIGNMENTS)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
callback_assignment_id_t aid = registered_callback_assignments;
|
if (free_callback_assignment_slots == 0)
|
||||||
|
{
|
||||||
|
callback_assignment_id_t aid = registered_callback_assignments;
|
||||||
|
|
||||||
callback_assignments[aid].address = address;
|
callback_assignments[aid].slot_flags |= SLOT_FLAGS_USED;
|
||||||
callback_assignments[aid].callback_id = id;
|
callback_assignments[aid].address = address;
|
||||||
registered_callback_assignments++;
|
callback_assignments[aid].callback_id = id;
|
||||||
|
registered_callback_assignments++;
|
||||||
|
return aid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// find the free slot
|
||||||
|
for (callback_assignment_id_t aid = 0; aid < registered_callback_assignments; ++aid)
|
||||||
|
{
|
||||||
|
if (callback_assignments[aid].slot_flags & SLOT_FLAGS_USED)
|
||||||
|
{
|
||||||
|
// found a used slot
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// and now an empty one
|
||||||
|
callback_assignments[aid].slot_flags |= SLOT_FLAGS_USED;
|
||||||
|
callback_assignments[aid].address = address;
|
||||||
|
callback_assignments[aid].callback_id = id;
|
||||||
|
|
||||||
DEBUG_PRINT("Assigned callback id >");
|
free_callback_assignment_slots--;
|
||||||
DEBUG_PRINT(id);
|
return id;
|
||||||
DEBUG_PRINT("/ga[");
|
}
|
||||||
DEBUG_PRINT(address.ga.area);
|
}
|
||||||
DEBUG_PRINT("/");
|
|
||||||
DEBUG_PRINT(address.ga.line);
|
|
||||||
DEBUG_PRINT("/");
|
|
||||||
DEBUG_PRINT(address.ga.member);
|
|
||||||
DEBUG_PRINTLN("]");
|
|
||||||
|
|
||||||
return aid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESPKNXIP::callback_delete_assignment(callback_assignment_id_t id)
|
|
||||||
{
|
|
||||||
__callback_delete_assignment(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::__callback_delete_assignment(callback_assignment_id_t id)
|
void ESPKNXIP::__callback_delete_assignment(callback_assignment_id_t id)
|
||||||
{
|
{
|
||||||
if (id >= registered_callback_assignments)
|
// TODO this can be optimized if we are deleting the last element
|
||||||
return;
|
// as then we can decrement registered_callback_assignments
|
||||||
|
|
||||||
uint32_t dest_offset = 0;
|
// clear slot and mark it as empty
|
||||||
uint32_t src_offset = 0;
|
callback_assignments[id].slot_flags = SLOT_FLAGS_EMPTY;
|
||||||
uint32_t len = 0;
|
callback_assignments[id].address.value = 0;
|
||||||
if (id == 0)
|
callback_assignments[id].callback_id = 0;
|
||||||
|
|
||||||
|
if (id == registered_callback_assignments - 1)
|
||||||
{
|
{
|
||||||
// start of array, so delete first entry
|
DEBUG_PRINTLN("last cba deleted");
|
||||||
src_offset = 1;
|
// If this is the last callback, we can delete it by decrementing registered_callbacks.
|
||||||
// registered_ga_callbacks will be 1 in case of only one entry
|
registered_callback_assignments--;
|
||||||
// registered_ga_callbacks will be 2 in case of two entries, etc..
|
|
||||||
// so only copy anything, if there is it at least more then one element
|
// However, if the assignment before this slot are also empty, we can decrement even further
|
||||||
len = (registered_callback_assignments - 1);
|
// First check if this was also the first element
|
||||||
}
|
if (id == 0)
|
||||||
else if (id == registered_callback_assignments - 1)
|
{
|
||||||
{
|
DEBUG_PRINTLN("really last cba");
|
||||||
// last element, don't do anything, simply decrement counter
|
// If this was the last, then we are done.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id--;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
DEBUG_PRINT("checking ");
|
||||||
|
DEBUG_PRINTLN((int32_t)id);
|
||||||
|
if ((callback_assignments[id].slot_flags & SLOT_FLAGS_USED) == 0)
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN("merged free slot");
|
||||||
|
// Slot before is empty
|
||||||
|
free_callback_assignment_slots--;
|
||||||
|
registered_callback_assignments--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN("aborted on used slot");
|
||||||
|
// Slot is used, abort
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id--;
|
||||||
|
if (id == CALLBACK_ASSIGNMENT_ID_MAX)
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN("abort on wrap");
|
||||||
|
// Wrap around, abort
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// somewhere in the middle
|
DEBUG_PRINTLN("free slot created");
|
||||||
// need to calc offsets
|
// there is now one more free slot
|
||||||
|
free_callback_assignment_slots++;
|
||||||
// skip all prev elements
|
|
||||||
dest_offset = id; // id is equal to how many element are in front of it
|
|
||||||
src_offset = dest_offset + 1; // start after the current element
|
|
||||||
len = (registered_callback_assignments - 1 - id);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (len > 0)
|
bool ESPKNXIP::__callback_is_id_valid(callback_id_t id)
|
||||||
{
|
{
|
||||||
memmove(callback_assignments + dest_offset, callback_assignments + src_offset, len * sizeof(callback_assignment_t));
|
if (id < registered_callbacks)
|
||||||
}
|
return true;
|
||||||
|
|
||||||
registered_callback_assignments--;
|
if (callbacks[id].slot_flags & SLOT_FLAGS_USED)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
callback_id_t ESPKNXIP::callback_register(String name, callback_fptr_t cb, void *arg, enable_condition_t cond)
|
callback_id_t ESPKNXIP::callback_register(String name, callback_fptr_t cb, void *arg, enable_condition_t cond)
|
||||||
|
@ -257,68 +329,108 @@ callback_id_t ESPKNXIP::callback_register(String name, callback_fptr_t cb, void
|
||||||
if (registered_callbacks >= MAX_CALLBACKS)
|
if (registered_callbacks >= MAX_CALLBACKS)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
callback_id_t id = registered_callbacks;
|
if (free_callback_slots == 0)
|
||||||
|
|
||||||
callbacks[id].name = name;
|
|
||||||
callbacks[id].fkt = cb;
|
|
||||||
callbacks[id].cond = cond;
|
|
||||||
callbacks[id].arg = arg;
|
|
||||||
registered_callbacks++;
|
|
||||||
|
|
||||||
DEBUG_PRINT("Registered callback >");
|
|
||||||
DEBUG_PRINT(name);
|
|
||||||
DEBUG_PRINT("< @ ");
|
|
||||||
DEBUG_PRINTLN(id);
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ESPKNXIP::callback_delete_register(callback_id_t id)
|
|
||||||
{
|
|
||||||
if (id >= registered_callbacks)
|
|
||||||
return;
|
|
||||||
|
|
||||||
uint32_t dest_offset = 0;
|
|
||||||
uint32_t src_offset = 0;
|
|
||||||
uint32_t len = 0;
|
|
||||||
if (id == 0)
|
|
||||||
{
|
{
|
||||||
// start of array, so delete first entry
|
callback_id_t id = registered_callbacks;
|
||||||
src_offset = 1;
|
|
||||||
// registered_ga_callbacks will be 1 in case of only one entry
|
callbacks[id].slot_flags |= SLOT_FLAGS_USED;
|
||||||
// registered_ga_callbacks will be 2 in case of two entries, etc..
|
callbacks[id].name = name;
|
||||||
// so only copy anything, if there is it at least more then one element
|
callbacks[id].fkt = cb;
|
||||||
len = (registered_callbacks - 1);
|
callbacks[id].cond = cond;
|
||||||
}
|
callbacks[id].arg = arg;
|
||||||
else if (id == registered_callbacks - 1)
|
registered_callbacks++;
|
||||||
{
|
return id;
|
||||||
// last element, don't do anything, simply decrement counter
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// somewhere in the middle
|
// find the free slot
|
||||||
// need to calc offsets
|
for (callback_id_t id = 0; id < registered_callbacks; ++id)
|
||||||
|
{
|
||||||
|
if (callbacks[id].slot_flags & SLOT_FLAGS_USED)
|
||||||
|
{
|
||||||
|
// found a used slot
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// and now an empty one
|
||||||
|
callbacks[id].slot_flags |= SLOT_FLAGS_USED;
|
||||||
|
callbacks[id].name = name;
|
||||||
|
callbacks[id].fkt = cb;
|
||||||
|
callbacks[id].cond = cond;
|
||||||
|
callbacks[id].arg = arg;
|
||||||
|
|
||||||
// skip all prev elements
|
free_callback_slots--;
|
||||||
dest_offset = id; // id is equal to how many element are in front of it
|
return id;
|
||||||
src_offset = dest_offset + 1; // start after the current element
|
}
|
||||||
len = (registered_callbacks - 1 - id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (len > 0)
|
|
||||||
{
|
|
||||||
memmove(callbacks + dest_offset, callbacks + src_offset, len * sizeof(callback_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
registered_callbacks--;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESPKNXIP::callback_assign(callback_id_t id, address_t val)
|
void ESPKNXIP::callback_deregister(callback_id_t id)
|
||||||
{
|
{
|
||||||
if (id >= registered_callbacks)
|
if (!__callback_is_id_valid(id))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
__callback_register_assignment(val, id);
|
// clear slot and mark it as empty
|
||||||
|
callbacks[id].slot_flags = SLOT_FLAGS_EMPTY;
|
||||||
|
callbacks[id].fkt = nullptr;
|
||||||
|
callbacks[id].cond = nullptr;
|
||||||
|
callbacks[id].arg = nullptr;
|
||||||
|
|
||||||
|
if (id == registered_callbacks - 1)
|
||||||
|
{
|
||||||
|
// If this is the last callback, we can delete it by decrementing registered_callbacks.
|
||||||
|
registered_callbacks--;
|
||||||
|
|
||||||
|
// However, if the callbacks before this slot are also empty, we can decrement even further
|
||||||
|
// First check if this was also the first element
|
||||||
|
if (id == 0)
|
||||||
|
{
|
||||||
|
// If this was the last, then we are done.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
id--;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
if ((callbacks[id].slot_flags & SLOT_FLAGS_USED) == 0)
|
||||||
|
{
|
||||||
|
// Slot is empty
|
||||||
|
free_callback_slots--;
|
||||||
|
registered_callbacks--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Slot is used, abort
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
id--;
|
||||||
|
if (id == CALLBACK_ASSIGNMENT_ID_MAX)
|
||||||
|
{
|
||||||
|
// Wrap around, abort
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// there is now one more free slot
|
||||||
|
free_callback_slots++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_assignment_id_t ESPKNXIP::callback_assign(callback_id_t id, address_t val)
|
||||||
|
{
|
||||||
|
if (!__callback_is_id_valid(id))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return __callback_register_assignment(val, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ESPKNXIP::callback_unassign(callback_assignment_id_t id)
|
||||||
|
{
|
||||||
|
if (!__callback_is_id_valid(id))
|
||||||
|
return;
|
||||||
|
|
||||||
|
__callback_delete_assignment(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -342,7 +454,7 @@ feedback_id_t ESPKNXIP::feedback_register_int(String name, int32_t *value, enabl
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedback_id_t ESPKNXIP::feedback_register_float(String name, float *value, uint8_t precision, enable_condition_t cond)
|
feedback_id_t ESPKNXIP::feedback_register_float(String name, float *value, uint8_t precision, char const *prefix, char const *suffix, enable_condition_t cond)
|
||||||
{
|
{
|
||||||
if (registered_feedbacks >= MAX_FEEDBACKS)
|
if (registered_feedbacks >= MAX_FEEDBACKS)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -354,13 +466,15 @@ feedback_id_t ESPKNXIP::feedback_register_float(String name, float *value, uint8
|
||||||
feedbacks[id].cond = cond;
|
feedbacks[id].cond = cond;
|
||||||
feedbacks[id].data = (void *)value;
|
feedbacks[id].data = (void *)value;
|
||||||
feedbacks[id].options.float_options.precision = precision;
|
feedbacks[id].options.float_options.precision = precision;
|
||||||
|
feedbacks[id].options.float_options.prefix = prefix ? strdup(prefix) : STRING_DEFAULT_EMPTY;
|
||||||
|
feedbacks[id].options.float_options.suffix = suffix ? strdup(suffix) : STRING_DEFAULT_EMPTY;
|
||||||
|
|
||||||
registered_feedbacks++;
|
registered_feedbacks++;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedback_id_t ESPKNXIP::feedback_register_bool(String name, bool *value, enable_condition_t cond)
|
feedback_id_t ESPKNXIP::feedback_register_bool(String name, bool *value, char const *true_text, char const *false_text, enable_condition_t cond)
|
||||||
{
|
{
|
||||||
if (registered_feedbacks >= MAX_FEEDBACKS)
|
if (registered_feedbacks >= MAX_FEEDBACKS)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -371,13 +485,15 @@ feedback_id_t ESPKNXIP::feedback_register_bool(String name, bool *value, enable_
|
||||||
feedbacks[id].name = name;
|
feedbacks[id].name = name;
|
||||||
feedbacks[id].cond = cond;
|
feedbacks[id].cond = cond;
|
||||||
feedbacks[id].data = (void *)value;
|
feedbacks[id].data = (void *)value;
|
||||||
|
feedbacks[id].options.bool_options.true_text = true_text ? strdup(true_text) : STRING_DEFAULT_TRUE;
|
||||||
|
feedbacks[id].options.bool_options.false_text = false_text ? strdup(false_text) : STRING_DEFAULT_FALSE;
|
||||||
|
|
||||||
registered_feedbacks++;
|
registered_feedbacks++;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
feedback_id_t ESPKNXIP::feedback_register_action(String name, feedback_action_fptr_t value, void *arg, enable_condition_t cond)
|
feedback_id_t ESPKNXIP::feedback_register_action(String name, feedback_action_fptr_t value, const char *btn_text, void *arg, enable_condition_t cond)
|
||||||
{
|
{
|
||||||
if (registered_feedbacks >= MAX_FEEDBACKS)
|
if (registered_feedbacks >= MAX_FEEDBACKS)
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -389,6 +505,7 @@ feedback_id_t ESPKNXIP::feedback_register_action(String name, feedback_action_fp
|
||||||
feedbacks[id].cond = cond;
|
feedbacks[id].cond = cond;
|
||||||
feedbacks[id].data = (void *)value;
|
feedbacks[id].data = (void *)value;
|
||||||
feedbacks[id].options.action_options.arg = arg;
|
feedbacks[id].options.action_options.arg = arg;
|
||||||
|
feedbacks[id].options.action_options.btn_text = btn_text ? strdup(btn_text) : STRING_DEFAULT_DO_THIS;
|
||||||
|
|
||||||
registered_feedbacks++;
|
registered_feedbacks++;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
// Webserver related
|
// Webserver related
|
||||||
#define USE_BOOTSTRAP 1 // [Default 1] Set to 1 to enable use of bootstrap CSS for nicer webconfig. CSS is loaded from bootstrapcdn.com. Set to 0 to disable
|
#define USE_BOOTSTRAP 1 // [Default 1] Set to 1 to enable use of bootstrap CSS for nicer webconfig. CSS is loaded from bootstrapcdn.com. Set to 0 to disable
|
||||||
#define ROOT_PREFIX "/knx" // [Default ""] This gets prepended to all webserver paths, default is empty string "". Set this to "/knx" if you want the config to be available on http://<ip>/knx
|
#define ROOT_PREFIX "" // [Default ""] This gets prepended to all webserver paths, default is empty string "". Set this to "/knx" if you want the config to be available on http://<ip>/knx
|
||||||
#define DISABLE_EEPROM_BUTTONS 1 // [Default 0] Set to 1 to disable the EEPROM buttons in the web ui.
|
#define DISABLE_EEPROM_BUTTONS 1 // [Default 0] Set to 1 to disable the EEPROM buttons in the web ui.
|
||||||
#define DISABLE_REBOOT_BUTTON 1 // [Default 0] Set to 1 to disable the reboot button in the web ui.
|
#define DISABLE_REBOOT_BUTTON 1 // [Default 0] Set to 1 to disable the reboot button in the web ui.
|
||||||
#define DISABLE_RESTORE_BUTTON 1 // [Default 0] Set to 1 to disable the "restore defaults" button in the web ui.
|
#define DISABLE_RESTORE_BUTTON 1 // [Default 0] Set to 1 to disable the "restore defaults" button in the web ui.
|
||||||
|
@ -282,6 +282,12 @@ typedef enum __config_flags
|
||||||
CONFIG_FLAGS_VALUE_SET = 1,
|
CONFIG_FLAGS_VALUE_SET = 1,
|
||||||
} config_flags_t;
|
} config_flags_t;
|
||||||
|
|
||||||
|
typedef enum __slot_flags
|
||||||
|
{
|
||||||
|
SLOT_FLAGS_EMPTY = 0, // Empty slots have no flags
|
||||||
|
SLOT_FLAGS_USED = 1,
|
||||||
|
} slot_flags_t;
|
||||||
|
|
||||||
typedef struct __message
|
typedef struct __message
|
||||||
{
|
{
|
||||||
knx_command_type_t ct;
|
knx_command_type_t ct;
|
||||||
|
@ -295,13 +301,15 @@ typedef void (*callback_fptr_t)(message_t const &msg, void *arg);
|
||||||
typedef void (*feedback_action_fptr_t)(void *arg);
|
typedef void (*feedback_action_fptr_t)(void *arg);
|
||||||
|
|
||||||
typedef uint8_t callback_id_t;
|
typedef uint8_t callback_id_t;
|
||||||
|
#define CALLBACK_ID_MAX UINT8_MAX
|
||||||
typedef uint8_t callback_assignment_id_t;
|
typedef uint8_t callback_assignment_id_t;
|
||||||
|
#define CALLBACK_ASSIGNMENT_ID_MAX UINT8_MAX
|
||||||
typedef uint8_t config_id_t;
|
typedef uint8_t config_id_t;
|
||||||
typedef uint8_t feedback_id_t;
|
typedef uint8_t feedback_id_t;
|
||||||
|
|
||||||
typedef struct __option_entry
|
typedef struct __option_entry
|
||||||
{
|
{
|
||||||
char *name;
|
char const *name;
|
||||||
uint8_t value;
|
uint8_t value;
|
||||||
} option_entry_t;
|
} option_entry_t;
|
||||||
|
|
||||||
|
@ -317,14 +325,29 @@ typedef struct __config
|
||||||
} data;
|
} data;
|
||||||
} config_t;
|
} config_t;
|
||||||
|
|
||||||
|
extern char const *string_defaults[];
|
||||||
|
#define STRING_DEFAULT_DO_THIS (string_defaults[0])
|
||||||
|
#define STRING_DEFAULT_TRUE (string_defaults[1])
|
||||||
|
#define STRING_DEFAULT_FALSE (string_defaults[2])
|
||||||
|
#define STRING_DEFAULT_EMPTY (string_defaults[3])
|
||||||
|
|
||||||
typedef struct __feedback_float_options
|
typedef struct __feedback_float_options
|
||||||
{
|
{
|
||||||
uint8_t precision;
|
uint8_t precision;
|
||||||
|
char const *prefix;
|
||||||
|
char const *suffix;
|
||||||
} feedback_float_options_t;
|
} feedback_float_options_t;
|
||||||
|
|
||||||
|
typedef struct __feedback_bool_options
|
||||||
|
{
|
||||||
|
char const *true_text;
|
||||||
|
char const *false_text;
|
||||||
|
} feedback_bool_options_t;
|
||||||
|
|
||||||
typedef struct __feedback_action_options
|
typedef struct __feedback_action_options
|
||||||
{
|
{
|
||||||
void * arg;
|
void *arg;
|
||||||
|
char const *btn_text;
|
||||||
} feedback_action_options_t;
|
} feedback_action_options_t;
|
||||||
|
|
||||||
typedef struct __feedback
|
typedef struct __feedback
|
||||||
|
@ -334,6 +357,7 @@ typedef struct __feedback
|
||||||
enable_condition_t cond;
|
enable_condition_t cond;
|
||||||
void *data;
|
void *data;
|
||||||
union {
|
union {
|
||||||
|
feedback_bool_options_t bool_options;
|
||||||
feedback_float_options_t float_options;
|
feedback_float_options_t float_options;
|
||||||
feedback_action_options_t action_options;
|
feedback_action_options_t action_options;
|
||||||
} options;
|
} options;
|
||||||
|
@ -341,6 +365,7 @@ typedef struct __feedback
|
||||||
|
|
||||||
typedef struct __callback
|
typedef struct __callback
|
||||||
{
|
{
|
||||||
|
uint8_t slot_flags;
|
||||||
callback_fptr_t fkt;
|
callback_fptr_t fkt;
|
||||||
enable_condition_t cond;
|
enable_condition_t cond;
|
||||||
void *arg;
|
void *arg;
|
||||||
|
@ -349,6 +374,7 @@ typedef struct __callback
|
||||||
|
|
||||||
typedef struct __callback_assignment
|
typedef struct __callback_assignment
|
||||||
{
|
{
|
||||||
|
uint8_t slot_flags;
|
||||||
address_t address;
|
address_t address;
|
||||||
callback_id_t callback_id;
|
callback_id_t callback_id;
|
||||||
} callback_assignment_t;
|
} callback_assignment_t;
|
||||||
|
@ -358,45 +384,44 @@ class ESPKNXIP {
|
||||||
ESPKNXIP();
|
ESPKNXIP();
|
||||||
void load();
|
void load();
|
||||||
void start();
|
void start();
|
||||||
void start(ESP8266WebServer *srv, bool espknxip_webpage = true);
|
void start(ESP8266WebServer *srv);
|
||||||
void loop();
|
void loop();
|
||||||
|
|
||||||
void save_to_eeprom();
|
void save_to_eeprom();
|
||||||
void restore_from_eeprom();
|
void restore_from_eeprom();
|
||||||
|
|
||||||
callback_id_t callback_register(String name, callback_fptr_t cb, void *arg = nullptr, enable_condition_t cond = nullptr);
|
callback_id_t callback_register(String name, callback_fptr_t cb, void *arg = nullptr, enable_condition_t cond = nullptr);
|
||||||
void callback_assign(callback_id_t id, address_t val);
|
callback_assignment_id_t callback_assign(callback_id_t id, address_t val);
|
||||||
|
void callback_deregister(callback_id_t id);
|
||||||
|
void callback_unassign(callback_assignment_id_t id);
|
||||||
|
|
||||||
void callback_delete_register(callback_id_t id);
|
void physical_address_set(address_t const &addr);
|
||||||
void callback_delete_assignment(callback_assignment_id_t id);
|
address_t physical_address_get();
|
||||||
|
|
||||||
void physical_address_set(address_t const &addr);
|
|
||||||
address_t physical_address_get();
|
|
||||||
|
|
||||||
// Configuration functions
|
// Configuration functions
|
||||||
config_id_t config_register_string(String name, uint8_t len, String _default, enable_condition_t cond = nullptr);
|
config_id_t config_register_string(String name, uint8_t len, String _default, enable_condition_t cond = nullptr);
|
||||||
config_id_t config_register_int(String name, int32_t _default, enable_condition_t cond = nullptr);
|
config_id_t config_register_int(String name, int32_t _default, enable_condition_t cond = nullptr);
|
||||||
config_id_t config_register_bool(String name, bool _default, enable_condition_t cond = nullptr);
|
config_id_t config_register_bool(String name, bool _default, enable_condition_t cond = nullptr);
|
||||||
config_id_t config_register_options(String name, option_entry_t *options, uint8_t _default, enable_condition_t cond = nullptr);
|
config_id_t config_register_options(String name, option_entry_t *options, uint8_t _default, enable_condition_t cond = nullptr);
|
||||||
config_id_t config_register_ga(String name, enable_condition_t cond = nullptr);
|
config_id_t config_register_ga(String name, enable_condition_t cond = nullptr);
|
||||||
|
|
||||||
String config_get_string(config_id_t id);
|
String config_get_string(config_id_t id);
|
||||||
int32_t config_get_int(config_id_t id);
|
int32_t config_get_int(config_id_t id);
|
||||||
bool config_get_bool(config_id_t id);
|
bool config_get_bool(config_id_t id);
|
||||||
uint8_t config_get_options(config_id_t id);
|
uint8_t config_get_options(config_id_t id);
|
||||||
address_t config_get_ga(config_id_t id);
|
address_t config_get_ga(config_id_t id);
|
||||||
|
|
||||||
void config_set_string(config_id_t id, String val);
|
void config_set_string(config_id_t id, String val);
|
||||||
void config_set_int(config_id_t id, int32_t val);
|
void config_set_int(config_id_t id, int32_t val);
|
||||||
void config_set_bool(config_id_t, bool val);
|
void config_set_bool(config_id_t, bool val);
|
||||||
void config_set_options(config_id_t id, uint8_t val);
|
void config_set_options(config_id_t id, uint8_t val);
|
||||||
void config_set_ga(config_id_t id, address_t const &val);
|
void config_set_ga(config_id_t id, address_t const &val);
|
||||||
|
|
||||||
// Feedback functions
|
// Feedback functions
|
||||||
feedback_id_t feedback_register_int(String name, int32_t *value, enable_condition_t cond = nullptr);
|
feedback_id_t feedback_register_int(String name, int32_t *value, enable_condition_t cond = nullptr);
|
||||||
feedback_id_t feedback_register_float(String name, float *value, uint8_t precision = 2, enable_condition_t cond = nullptr);
|
feedback_id_t feedback_register_float(String name, float *value, uint8_t precision = 2, char const *prefix = nullptr, char const *suffix = nullptr, enable_condition_t cond = nullptr);
|
||||||
feedback_id_t feedback_register_bool(String name, bool *value, enable_condition_t cond = nullptr);
|
feedback_id_t feedback_register_bool(String name, bool *value, char const *true_text = nullptr, char const *false_text = nullptr, enable_condition_t cond = nullptr);
|
||||||
feedback_id_t feedback_register_action(String name, feedback_action_fptr_t value, void *arg = nullptr, enable_condition_t = nullptr);
|
feedback_id_t feedback_register_action(String name, feedback_action_fptr_t value, char const *btn_text = nullptr, void *arg = nullptr, enable_condition_t = nullptr);
|
||||||
|
|
||||||
// Send functions
|
// Send functions
|
||||||
void send(address_t const &receiver, knx_command_type_t ct, uint8_t data_len, uint8_t *data);
|
void send(address_t const &receiver, knx_command_type_t ct, uint8_t data_len, uint8_t *data);
|
||||||
|
@ -484,7 +509,6 @@ class ESPKNXIP {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void __start();
|
void __start();
|
||||||
void __start_espknxip_webpage();
|
|
||||||
void __loop_knx(AsyncUDPPacket &packet);
|
void __loop_knx(AsyncUDPPacket &packet);
|
||||||
|
|
||||||
// Webserver functions
|
// Webserver functions
|
||||||
|
@ -513,6 +537,8 @@ class ESPKNXIP {
|
||||||
void __config_set_options(config_id_t id, uint8_t val);
|
void __config_set_options(config_id_t id, uint8_t val);
|
||||||
void __config_set_ga(config_id_t id, address_t const &val);
|
void __config_set_ga(config_id_t id, address_t const &val);
|
||||||
|
|
||||||
|
bool __callback_is_id_valid(callback_id_t id);
|
||||||
|
|
||||||
callback_assignment_id_t __callback_register_assignment(address_t address, callback_id_t id);
|
callback_assignment_id_t __callback_register_assignment(address_t address, callback_id_t id);
|
||||||
void __callback_delete_assignment(callback_assignment_id_t id);
|
void __callback_delete_assignment(callback_assignment_id_t id);
|
||||||
|
|
||||||
|
@ -521,9 +547,11 @@ class ESPKNXIP {
|
||||||
AsyncUDP udp;
|
AsyncUDP udp;
|
||||||
|
|
||||||
callback_assignment_id_t registered_callback_assignments;
|
callback_assignment_id_t registered_callback_assignments;
|
||||||
|
callback_assignment_id_t free_callback_assignment_slots;
|
||||||
callback_assignment_t callback_assignments[MAX_CALLBACK_ASSIGNMENTS];
|
callback_assignment_t callback_assignments[MAX_CALLBACK_ASSIGNMENTS];
|
||||||
|
|
||||||
callback_id_t registered_callbacks;
|
callback_id_t registered_callbacks;
|
||||||
|
callback_id_t free_callback_slots;
|
||||||
callback_t callbacks[MAX_CALLBACKS];
|
callback_t callbacks[MAX_CALLBACKS];
|
||||||
|
|
||||||
config_id_t registered_configs;
|
config_id_t registered_configs;
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
# datatypes
|
# datatypes
|
||||||
address_t DATA_TYPE
|
address_t DATA_TYPE
|
||||||
|
message_t DATA_TYPE
|
||||||
callback_id_t DATA_TYPE
|
callback_id_t DATA_TYPE
|
||||||
callback_assignment_id_t DATA_TYPE
|
callback_assignment_id_t DATA_TYPE
|
||||||
|
option_entry_t DATA_TYPE
|
||||||
config_id_t DATA_TYPE
|
config_id_t DATA_TYPE
|
||||||
enable_condition_t DATA_TYPE
|
enable_condition_t DATA_TYPE
|
||||||
callback_fptr_t DATA_TYPE
|
callback_fptr_t DATA_TYPE
|
||||||
|
feedback_action_fptr_t DATA_TYPE
|
||||||
knx_command_type_t DATA_TYPE
|
knx_command_type_t DATA_TYPE
|
||||||
|
|
||||||
# methods
|
# methods
|
||||||
|
@ -14,18 +17,25 @@ GA_to_address KEYWORD2
|
||||||
PA_to_address KEYWORD2
|
PA_to_address KEYWORD2
|
||||||
callback_register KEYWORD2
|
callback_register KEYWORD2
|
||||||
callback_assign KEYWORD2
|
callback_assign KEYWORD2
|
||||||
|
callback_deregister KEYWORD2
|
||||||
|
callback_unassign KEYWORD2
|
||||||
|
physical_address_set KEYWORD2
|
||||||
|
physical_address_get KEYWORD2
|
||||||
config_register_string KEYWORD2
|
config_register_string KEYWORD2
|
||||||
config_register_int KEYWORD2
|
config_register_int KEYWORD2
|
||||||
config_register_ga KEYWORD2
|
|
||||||
config_register_bool KEYWORD2
|
config_register_bool KEYWORD2
|
||||||
|
config_register_options KEYWORD2
|
||||||
|
config_register_ga KEYWORD2
|
||||||
config_get_string KEYWORD2
|
config_get_string KEYWORD2
|
||||||
config_get_int KEYWORD2
|
config_get_int KEYWORD2
|
||||||
config_get_ga KEYWORD2
|
|
||||||
config_get_bool KEYWORD2
|
config_get_bool KEYWORD2
|
||||||
|
config_get_options KEYWORD2
|
||||||
|
config_get_ga KEYWORD2
|
||||||
config_set_string KEYWORD2
|
config_set_string KEYWORD2
|
||||||
config_set_int KEYWORD2
|
config_set_int KEYWORD2
|
||||||
config_set_ga KEYWORD2
|
|
||||||
config_set_bool KEYWORD2
|
config_set_bool KEYWORD2
|
||||||
|
config_set_options KEYWORD2
|
||||||
|
config_set_ga KEYWORD2
|
||||||
feedback_register_int KEYWORD2
|
feedback_register_int KEYWORD2
|
||||||
feedback_register_float KEYWORD2
|
feedback_register_float KEYWORD2
|
||||||
feedback_register_bool KEYWORD2
|
feedback_register_bool KEYWORD2
|
||||||
|
|
Loading…
Reference in New Issue