blk_box_tc/main/drivers/star_code.cpp

188 lines
5.2 KiB
C++

#include "star_code.h"
#include <vector>
#include <algorithm>
#include <string.h>
#include <stdint.h>
#include <esp_log.h>
#include "drivers/bottom_half.h"
static const char* TAG = "star_code";
volatile bool handling_new_starcodes = false;
static volatile bool system_initialized = false;
static volatile SemaphoreHandle_t star_codes_sem;
static std::vector<StarCodeEntry> star_codes;
static volatile bool doing_starcode = false;
static uint16_t starcode_waiting_on_release;
static char current[STARCODE_MAX_LEN + 1];
static size_t current_idx;
void star_code_handle_keypad(uint16_t* just_pressed, uint16_t* just_released) {
if (handling_new_starcodes && (*just_pressed | (1 << KeypadKey::star))) {
current_idx = 0;
current[current_idx] = '\0';
doing_starcode = true;
}
if (doing_starcode) {
// If we get a press while handling a starcode, we also want to capture the release of that key.
starcode_waiting_on_release |= *just_pressed;
KeypadKey key;
while (take_key(&key, just_pressed)) {
if (key == KeypadKey::star) {
current_idx = 0;
current[current_idx] = '\0';
} else if (key == KeypadKey::pound) {
doing_starcode = false;
if (current_idx != 0) {
trigger_star_code(current);
}
} else {
// shift the digits left if neccesary
if (current_idx >= STARCODE_MAX_LEN) {
for (int i = 1; i < current_idx; i++) {
current[i-1] = current[i];
}
current_idx--;
}
// append the character
current[current_idx++] = char_of_keypad_key(key);
current[current_idx] = '\0';
}
}
}
// capture any releases from starcodes
uint16_t new_just_released = (*just_released) & (~starcode_waiting_on_release);
starcode_waiting_on_release = starcode_waiting_on_release & (~*just_released);
*just_released = new_just_released;
}
void init_star_code_system() {
star_codes_sem = xSemaphoreCreateBinary();
xSemaphoreGive(star_codes_sem);
handling_new_starcodes = true;
system_initialized = true;
}
/// Checks if a triggered code matches an expected code.
/// @return true iff the codes match, where '*'s in the expected code can match any character in the triggered code
static bool check_code_match(const char* triggered, const char* expected) {
size_t triggered_len = strlen(triggered);
size_t match_len = strlen(triggered);
if (triggered_len != match_len)
return false;
for (int i = 0; i < triggered_len; i++) {
if (!(expected[i] == '*' || expected[i] == triggered[i])) {
return false;
}
}
return true;
}
bool add_star_code(StarCodeEntry code) {
if (code.code == nullptr || strlen(code.code) > STARCODE_MAX_LEN) {
return false;
}
if (code.display_text != nullptr && strlen(code.display_text) > STARCODE_MAX_LEN + 1) {
return false;
}
// check for a existing entry
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& other) {
return check_code_match(code.code, other.code);
});
if (it != star_codes.end()) {
// existing star code found!
ESP_LOGW(TAG, "Failed to add star code %s", code.code);
return false;
}
star_codes.push_back(code);
return true;
}
bool add_star_codes(const StarCodeEntry* codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!add_star_code(codes[i])) {
success = false;
}
}
return success;
}
bool rm_star_code(const char* code){
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& star_code) {
return strcmp(code, star_code.code) == 0;
});
if (it == star_codes.end()) {
ESP_LOGW(TAG, "Failed to remove star code %s", code);
return false;
}
star_codes.erase(it);
return true;
}
bool rm_star_codes(const StarCodeEntry* codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!rm_star_code(codes[i].code)) {
success = false;
}
}
return success;
}
bool rm_star_codes_str(const char** codes, size_t len) {
bool success = true;
for (int i = 0; i < len; i++) {
if (!rm_star_code(codes[i])) {
success = false;
}
}
return success;
}
void clear_star_codes() {
star_codes.clear();
}
bool trigger_star_code(const char* code) {
auto it = std::find_if(star_codes.begin(), star_codes.end(), [&](const StarCodeEntry& other) {
return check_code_match(code, other.code);
});
if (it == star_codes.end()) {
return false;
}
// TODO: do display text
// TODO: do delay ticks
if (it->triggered_sem != nullptr)
xSemaphoreGive(it->triggered_sem);
if (it->callback != nullptr)
(it->callback)();
return true;
}
void pause_star_code_system() {
doing_starcode = false;
handling_new_starcodes = false;
}
void resume_star_code_system() {
handling_new_starcodes = system_initialized;
}