205 lines
5.5 KiB
C++
205 lines
5.5 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 bool system_initialized = false;
|
|
|
|
static volatile SemaphoreHandle_t star_codes_sem;
|
|
static std::vector<StarCodeEntry> star_codes;
|
|
|
|
static TaskHandle_t task_handle;
|
|
|
|
static void star_code_task(void* param) {
|
|
KeypadKey key;
|
|
|
|
int current_idx = 0;
|
|
char current[STRING_MAX_LEN+1] = {0};
|
|
|
|
while (1) {
|
|
while (get_keypad_pressed(&key)) {
|
|
if (key == KeypadKey::star) {
|
|
current[0] = '*';
|
|
for (int i = 1; i < STRING_MAX_LEN; i++) {
|
|
current[i] = 0;
|
|
}
|
|
current_idx = 1;
|
|
} else if (key == KeypadKey::pound) {
|
|
// submit
|
|
if (current[0] == '\0') {
|
|
continue;
|
|
}
|
|
|
|
bool hit = false;
|
|
for (int i = 0; i < star_codes_len; i++) {
|
|
StarCodeHandler sch = star_codes[i];
|
|
if (strcmp(current, sch.code) == 0) {
|
|
hit = true;
|
|
lcd_print(1, 2, sch.display_text);
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
if (sch.callback != nullptr) {
|
|
(sch.callback)();
|
|
}
|
|
if (sch.should_exit) {
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hit) {
|
|
lcd_print(1, 2, "Invalid Star Code");
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
}
|
|
|
|
// clear
|
|
for (int i = 0; i < STRING_MAX_LEN; i++) {
|
|
current[i] = 0;
|
|
}
|
|
current_idx = 0;
|
|
} else {
|
|
// out of room. skip
|
|
if (current_idx >= STRING_MAX_LEN) break;
|
|
// no code started.
|
|
if (current[0] != '*') continue;
|
|
|
|
char c = char_of_keypad_key(key);
|
|
current[current_idx++] = c;
|
|
}
|
|
// ESP_LOGI(STEP0_TAG, "Pressed: %c", c);
|
|
|
|
lcd_clear();
|
|
lcd_print(1, 1, current);
|
|
}
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(10));
|
|
}
|
|
}
|
|
|
|
void init_star_code_system() {
|
|
star_codes_sem = xSemaphoreCreateBinary();
|
|
xSemaphoreGive(star_codes_sem);
|
|
|
|
xTaskCreate(star_code_task, "star_code", 2048, nullptr, 1, &task_handle);
|
|
|
|
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;
|
|
}
|
|
|
|
if (it->callback != nullptr)
|
|
(it->callback)();
|
|
return true;
|
|
}
|
|
|
|
void pause_star_code_system() {
|
|
handling_new_starcodes = false;
|
|
}
|
|
|
|
void resume_star_code_system() {
|
|
handling_new_starcodes = system_initialized;
|
|
} |