diff --git a/dependencies.lock b/dependencies.lock
index 6666658..fdedac0 100644
--- a/dependencies.lock
+++ b/dependencies.lock
@@ -1,6 +1,6 @@
dependencies:
esp-idf-lib/esp_idf_lib_helpers:
- component_hash: a8049b1e609679fb54b2d57b0399dd29c4d1fda09a797edac9926f7810aa5703
+ component_hash: 689853bb8993434f9556af0f2816e808bf77b5d22100144b21f3519993daf237
dependencies: []
source:
registry_url: https://components.espressif.com
@@ -16,9 +16,9 @@ dependencies:
- esp32p4
- esp32s2
- esp32s3
- version: 1.3.10
+ version: 1.4.0
esp-idf-lib/i2cdev:
- component_hash: 11c08f9e1a7d346b5dd763196dc2567cf2209ae49042402c2c2d296624601c14
+ component_hash: 4f3838b2e68ab2b77fd43737139fa97dd0243b46af7b4a04588c67ff6b275ba1
dependencies:
- name: esp-idf-lib/esp_idf_lib_helpers
registry_url: https://components.espressif.com
@@ -38,7 +38,7 @@ dependencies:
- esp32p4
- esp32s2
- esp32s3
- version: 2.0.8
+ version: 2.1.0
esp-idf-lib/tca95x5:
component_hash: 4bbdbd82828cf1fd5c03fd07e3ea2cb0f36daf16cb3ac7219d1e5decb9ec04ee
dependencies:
@@ -65,6 +65,16 @@ dependencies:
- esp32s2
- esp32s3
version: 1.0.7
+ espressif/mdns:
+ component_hash: 29e47564b1a7ee778135e17fbbf2a2773f71c97ebabfe626c8eda7c958a7ad16
+ dependencies:
+ - name: idf
+ require: private
+ version: '>=5.0'
+ source:
+ registry_url: https://components.espressif.com/
+ type: service
+ version: 1.9.1
idf:
source:
type: idf
@@ -81,8 +91,9 @@ dependencies:
version: 1.20.3
direct_dependencies:
- esp-idf-lib/tca95x5
+- espressif/mdns
- idf
- joltwallet/littlefs
-manifest_hash: b32a1e2b2eb19ff5cd4984c921bf3a1bcd9c1546566ee977021d2d4bf4b3de31
+manifest_hash: c3a20310a8ecc5e8e0221a7589abf8d2e372eb48f06d6b6fbb3fbf5f48a61aaf
target: esp32
version: 2.0.0
diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt
index 2e96531..b82a9cf 100644
--- a/main/CMakeLists.txt
+++ b/main/CMakeLists.txt
@@ -2,11 +2,14 @@
# for more information about component CMakeLists.txt files.
idf_component_register(
- SRCS main.c i2c.c rtc.c storage.c uart_comms.c control_fsm.c power_mgmt.c rf_433.c rtc.c sensors.c solar.c webserver.c # list the source files of this component
+ SRCS main.c i2c.c rtc.c storage.c uart_comms.c control_fsm.c power_mgmt.c rf_433.c rtc.c sensors.c solar.c webserver.c simple_dns_server.c # list the source files of this component
INCLUDE_DIRS # optional, add here public include directories
PRIV_INCLUDE_DIRS # optional, add here private include directories
- REQUIRES # optional, list the public requirements (component names)
- PRIV_REQUIRES # optional, list the private requirements
+
+ REQUIRES driver esp_http_server esp_netif lwip json esp_timer esp_adc app_update esp_wifi nvs_flash mdns # optional, list the public requirements (component names)
+ # esp_https_server
+ PRIV_REQUIRES # optional, list the private requirements
+ #EMBED_TXTFILES servercert.pem prvtkey.pem
)
diff --git a/main/control_fsm.c b/main/control_fsm.c
index e77b2b8..1aec2f8 100644
--- a/main/control_fsm.c
+++ b/main/control_fsm.c
@@ -8,6 +8,7 @@
#include "control_fsm.h"
#include "esp_task_wdt.h"
#include "esp_timer.h"
+#include "i2c.h"
#include "power_mgmt.h"
#include "rtc_wdt.h"
#include "driver/gpio.h"
@@ -18,6 +19,9 @@
#define TRANSITION_DELAY_US 1000000
+#define CALIBRATE_JACK_MAX_TIME 3000000
+#define CALIBRATE_DRIVE_MAX_TIME 6000000
+
#define TAG "FSM"
static QueueHandle_t fsm_cmd_queue = NULL;
@@ -37,8 +41,12 @@ bool relay_states[8] = {false};
int64_t override_times[8] = {-1};
bool enabled = false;
+RTC_DATA_ATTR float remaining_distance = 0.0f;
+float fsm_get_remaining_distance(void) { return remaining_distance; }
+void fsm_set_remaining_distance(float x) { remaining_distance = x;}
-
+// Track the starting encoder count for the current move
+static int32_t move_start_encoder = 0;
volatile fsm_state_t current_state = STATE_IDLE;
volatile int64_t current_time = 0;
@@ -89,6 +97,12 @@ void pulseOverride(relay_t relay) {
set_timer(TRANSITION_DELAY_US);
}*/
+int64_t fsm_cal_t, fsm_cal_e;
+float fsm_cal_val;
+void fsm_set_cal_val(float v) {fsm_cal_val = v;}
+int64_t fsm_get_cal_t(){return fsm_cal_t;}
+int64_t fsm_get_cal_e(){return fsm_cal_e;}
+
void fsm_request(fsm_cmd_t cmd)
{
if (fsm_cmd_queue != NULL)
@@ -120,7 +134,7 @@ int8_t fsm_get_current_progress(int8_t denominator) {
}
-#define JACK_TIME get_param_value_t(PARAM_JACK_KT).f32 * get_param_value_t(PARAM_JACK_DIST ).f32
+#define JACK_TIME get_param_value_t(PARAM_JACK_KT).f32 * get_param_value_t(PARAM_JACK_DIST ).f32
#define DRIVE_TIME get_param_value_t(PARAM_DRIVE_KT).f32 * get_param_value_t(PARAM_DRIVE_DIST).f32
#define DRIVE_DIST get_param_value_t(PARAM_DRIVE_KE).f32 * get_param_value_t(PARAM_DRIVE_DIST).f32
@@ -141,8 +155,13 @@ void control_task(void *param) {
switch (cmd) {
case FSM_CMD_START:
if (current_state == STATE_IDLE) {
- current_state = STATE_MOVE_START_DELAY;
- set_timer(TRANSITION_DELAY_US);
+ // Check if we have remaining distance before starting
+ if (remaining_distance > 0.0f) {
+ current_state = STATE_MOVE_START_DELAY;
+ set_timer(TRANSITION_DELAY_US);
+ } else {
+ ESP_LOGW(TAG, "Cannot start move: no remaining distance (%.2f)", remaining_distance);
+ }
}
break;
case FSM_CMD_STOP:
@@ -158,6 +177,68 @@ void control_task(void *param) {
case FSM_CMD_SHUTDOWN:
enabled = false;
break;
+
+ case FSM_CMD_CALIBRATE_JACK_PREP:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_PREP");
+ if (current_state == STATE_IDLE) {
+ current_state = STATE_CALIBRATE_JACK_DELAY;
+ }
+ break;
+
+ case FSM_CMD_CALIBRATE_JACK_START:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_START");
+ if (current_state == STATE_CALIBRATE_JACK_DELAY) {
+ current_state = STATE_CALIBRATE_JACK_MOVE;
+ set_timer(CALIBRATE_JACK_MAX_TIME);
+ }
+ break;
+ case FSM_CMD_CALIBRATE_JACK_END:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_END");
+ if (current_state == STATE_CALIBRATE_JACK_MOVE) {
+ fsm_cal_t = current_time - timer_start;
+ current_state = STATE_IDLE;
+ }
+ break;
+ case FSM_CMD_CALIBRATE_JACK_FINISH:
+ set_param_value_t(PARAM_JACK_KT,
+ (param_value_t){.f32 = fsm_cal_t / fsm_cal_val});
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_JACK_FINISH -> %f", get_param_value_t(PARAM_JACK_KT).f32);
+ break;
+
+
+
+ case FSM_CMD_CALIBRATE_DRIVE_PREP:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_PREP");
+ if (current_state == STATE_IDLE) {
+ current_state = STATE_CALIBRATE_DRIVE_DELAY;
+ }
+ break;
+
+ case FSM_CMD_CALIBRATE_DRIVE_START:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_START");
+ if (current_state == STATE_CALIBRATE_DRIVE_DELAY) {
+ current_state = STATE_CALIBRATE_DRIVE_MOVE;
+ set_timer(CALIBRATE_DRIVE_MAX_TIME);
+ set_sensor_counter(SENSOR_DRIVE, 0);
+ }
+ break;
+ case FSM_CMD_CALIBRATE_DRIVE_END:
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_END");
+ if (current_state == STATE_CALIBRATE_DRIVE_MOVE) {
+ fsm_cal_t = current_time - timer_start;
+ fsm_cal_e = get_sensor_counter(SENSOR_DRIVE);
+ current_state = STATE_IDLE;
+ }
+ break;
+ case FSM_CMD_CALIBRATE_DRIVE_FINISH:
+ set_param_value_t(PARAM_DRIVE_KT,
+ (param_value_t){.f32 = fsm_cal_t / fsm_cal_val});
+ set_param_value_t(PARAM_DRIVE_KE,
+ (param_value_t){.f32 = fsm_cal_e / fsm_cal_val});
+ ESP_LOGI(TAG, "FSM_CMD_CALIBRATE_DRIVE_FINISH -> %f / %f",
+ get_param_value_t(PARAM_DRIVE_KT).f32,
+ get_param_value_t(PARAM_DRIVE_KE).f32);
+ break;
}
}
@@ -188,16 +269,58 @@ void control_task(void *param) {
if (timer_done()) {
current_state = STATE_DRIVE;
set_timer(DRIVE_TIME);
+ // Set the encoder counter to track remaining distance in this move
set_sensor_counter(SENSOR_DRIVE, -DRIVE_DIST);
+ // Record starting encoder position AFTER setting it
+ move_start_encoder = get_sensor_counter(SENSOR_DRIVE);
+ ESP_LOGI(TAG, "STATE_DRIVE starting: encoder=%ld, remaining_distance=%.2f, DRIVE_DIST=%.2f",
+ (long)move_start_encoder, remaining_distance, DRIVE_DIST);
}
break;
case STATE_DRIVE:
- if (timer_done() || get_sensor_counter(SENSOR_DRIVE) > 0) {
- current_state = STATE_DRIVE_END_DELAY;
- set_timer(TRANSITION_DELAY_US);
- }
- if (efuse_is_tripped(BRIDGE_DRIVE)) {
- current_state = STATE_UNDO_JACK_START;
+ {
+ int32_t current_encoder = get_sensor_counter(SENSOR_DRIVE);
+ int32_t ticks_traveled = current_encoder - move_start_encoder;
+ float ke = get_param_value_t(PARAM_DRIVE_KE).f32;
+ float distance_traveled = ticks_traveled / ke;
+
+ ESP_LOGI(TAG, "STATE_DRIVE: current_encoder=%ld, move_start=%ld, ticks=%ld, ke=%.2f, dist_traveled=%.2f, remaining=%.2f",
+ (long)current_encoder, (long)move_start_encoder, (long)ticks_traveled,
+ ke, distance_traveled, remaining_distance);
+
+ // Check if we'll exceed remaining distance with a full move
+ bool will_exceed = distance_traveled >= remaining_distance;
+
+ // Stop if timer expires OR encoder target reached OR we've used up remaining distance
+ if (timer_done() || current_encoder > 0 || will_exceed) {
+ ESP_LOGI(TAG, "Drive stopping: timer_done=%d, encoder>0=%d, will_exceed=%d",
+ timer_done(), current_encoder > 0, will_exceed);
+
+ // Update remaining distance based on actual travel
+ float old_remaining = remaining_distance;
+ if (will_exceed) {
+ ESP_LOGI(TAG, "Move stopped early - reached remaining distance limit (%.2f)", remaining_distance);
+ remaining_distance = 0.0f;
+ } else {
+ remaining_distance -= distance_traveled;
+ if (remaining_distance < 0.0f) remaining_distance = 0.0f;
+ }
+ ESP_LOGI(TAG, "Drive complete: traveled %.2f, old_remaining %.2f, new_remaining %.2f",
+ distance_traveled, old_remaining, remaining_distance);
+
+ current_state = STATE_DRIVE_END_DELAY;
+ set_timer(TRANSITION_DELAY_US);
+ }
+
+ if (efuse_is_tripped(BRIDGE_DRIVE)) {
+ float old_remaining = remaining_distance;
+ // Update remaining distance even on fault
+ remaining_distance -= distance_traveled;
+ if (remaining_distance < 0.0f) remaining_distance = 0.0f;
+ ESP_LOGW(TAG, "Drive fault: traveled %.2f, old_remaining %.2f, new_remaining %.2f",
+ distance_traveled, old_remaining, remaining_distance);
+ current_state = STATE_UNDO_JACK_START;
+ }
}
break;
case STATE_DRIVE_END_DELAY:
@@ -205,8 +328,9 @@ void control_task(void *param) {
current_state = STATE_JACK_DOWN;
set_timer(JACK_TIME);
}
+ break;
case STATE_JACK_DOWN:
- if (timer_done() || get_sensor(SENSOR_JACK)) {
+ if (timer_done()) { // || get_sensor(SENSOR_JACK)) {
current_state = STATE_IDLE;
}
@@ -225,7 +349,7 @@ void control_task(void *param) {
}
break;
case STATE_UNDO_JACK:
- if (timer_done() || get_sensor(SENSOR_JACK)) {
+ if (timer_done()){ // || get_sensor(SENSOR_JACK)) {
current_state = STATE_IDLE;
}
@@ -234,6 +358,32 @@ void control_task(void *param) {
current_state = STATE_IDLE;
}
break;
+
+
+ case STATE_CALIBRATE_JACK_DELAY:
+ // no way out of this except a command
+ break;
+ case STATE_CALIBRATE_JACK_MOVE:
+ if (timer_done()) {
+ ESP_LOGI(TAG, "STATE_CALIBRATE_JACK_END");
+ current_state = STATE_IDLE;
+ fsm_cal_t = current_time - timer_start;
+ }
+ break;
+
+
+ case STATE_CALIBRATE_DRIVE_DELAY:
+ // no way out of this except a command
+ break;
+ case STATE_CALIBRATE_DRIVE_MOVE:
+ if (timer_done()) {
+ ESP_LOGI(TAG, "STATE_CALIBRATE_DRIVE_END");
+ current_state = STATE_IDLE;
+ fsm_cal_t = current_time - timer_start;
+ fsm_cal_e = get_sensor_counter(SENSOR_DRIVE);
+ }
+ break;
+
default: break;
}
@@ -261,6 +411,7 @@ void control_task(void *param) {
}
break;
+ case STATE_CALIBRATE_JACK_MOVE:
case STATE_JACK_UP:
// jack up and fluff
setRelay(RELAY_A1, false);
@@ -272,6 +423,7 @@ void control_task(void *param) {
setRelay(RELAY_A3, true);
reset_shutdown_timer();
break;
+ case STATE_CALIBRATE_DRIVE_MOVE:
case STATE_DRIVE:
// drive and fluff
setRelay(RELAY_A1, true);
@@ -308,6 +460,7 @@ void control_task(void *param) {
setRelay(RELAY_A3, true);
reset_shutdown_timer();
break;
+ case STATE_CALIBRATE_JACK_DELAY:
default:
// invalid state; turn all relays off
setRelay(RELAY_A1, false);
diff --git a/main/control_fsm.h b/main/control_fsm.h
index 20823e9..93e1507 100644
--- a/main/control_fsm.h
+++ b/main/control_fsm.h
@@ -7,7 +7,22 @@
#include "freertos/queue.h"
-typedef enum { FSM_CMD_START, FSM_CMD_STOP, FSM_CMD_UNDO, FSM_CMD_SHUTDOWN} fsm_cmd_t;
+typedef enum {
+ FSM_CMD_START,
+ FSM_CMD_STOP,
+ FSM_CMD_UNDO,
+ FSM_CMD_SHUTDOWN,
+
+ FSM_CMD_CALIBRATE_JACK_PREP,
+ FSM_CMD_CALIBRATE_JACK_START,
+ FSM_CMD_CALIBRATE_JACK_END,
+ FSM_CMD_CALIBRATE_JACK_FINISH,
+
+ FSM_CMD_CALIBRATE_DRIVE_PREP,
+ FSM_CMD_CALIBRATE_DRIVE_START,
+ FSM_CMD_CALIBRATE_DRIVE_END,
+ FSM_CMD_CALIBRATE_DRIVE_FINISH
+} fsm_cmd_t;
typedef enum {
STATE_IDLE = 0,
@@ -19,6 +34,12 @@ typedef enum {
STATE_JACK_DOWN = 6,
STATE_UNDO_JACK = 7,
STATE_UNDO_JACK_START = 8,
+
+ STATE_CALIBRATE_JACK_DELAY,
+ STATE_CALIBRATE_JACK_MOVE,
+
+ STATE_CALIBRATE_DRIVE_DELAY,
+ STATE_CALIBRATE_DRIVE_MOVE
} fsm_state_t;
typedef enum {
@@ -46,8 +67,15 @@ void pulseOverride(relay_t relay/*, int64_t pulse*/);
esp_err_t fsm_init();
esp_err_t fsm_stop();
+void fsm_set_cal_val(float v);
+int64_t fsm_get_cal_t();
+int64_t fsm_get_cal_e();
void fsm_request(fsm_cmd_t cmd);
+
+float fsm_get_remaining_distance(void);
+void fsm_set_remaining_distance(float x);
+
//void fsm_begin_auto_move();
int8_t fsm_get_current_progress(int8_t remainder);
diff --git a/main/i2c.c b/main/i2c.c
index e8ea6d1..e4337a0 100644
--- a/main/i2c.c
+++ b/main/i2c.c
@@ -24,9 +24,11 @@
#define TCA_REG_CONFIG1 0x07
// Debounce & Repeat Settings
-#define DEBOUNCE_MS 50
-#define REPEAT_MS 200
-#define REPEAT_START_MS 700
+#define DEBOUNCE_US 50000
+#define REPEAT_US 200000
+#define REPEAT_START_US 700000
+
+#define MAX_REPEATS 100
// Static Variables
static bool i2c_initted = false;
@@ -85,8 +87,8 @@ esp_err_t i2c_stop() {
#define N_BTNS 2
static bool debounced_state[N_BTNS] = {false};
static bool last_known_state[N_BTNS] = {false};
-static uint64_t last_stable_time[N_BTNS] = {0};
-static uint64_t last_change_time[N_BTNS] = {0};
+static int64_t last_stable_time[N_BTNS] = {0};
+static int64_t last_change_time[N_BTNS] = {0};
static uint8_t claimed_repeats[N_BTNS] = {0};
esp_err_t i2c_poll_buttons() {
for (uint8_t btn = 0; btn < N_BTNS; ++btn) {
@@ -98,13 +100,13 @@ esp_err_t i2c_poll_buttons() {
uint8_t raw_buttons = (uint8_t)(port_val & 0x0F);
uint8_t raw_states = ~raw_buttons & 0x0F;
- uint64_t now = esp_timer_get_time() / 1000;
+ int64_t now = esp_timer_get_time() / 1000;
for (uint8_t btn = 0; btn < N_BTNS; ++btn) {
bool raw_pressed = (raw_states & (1 << btn)) != 0;
if (raw_pressed != debounced_state[btn]) {
- if (now - last_stable_time[btn] >= DEBOUNCE_MS) {
+ if (now - last_stable_time[btn] >= DEBOUNCE_US) {
debounced_state[btn] = raw_pressed;
last_stable_time[btn] = now;
last_change_time[btn] = now;
@@ -131,9 +133,9 @@ bool i2c_get_button_state(uint8_t button) {
bool i2c_get_button_repeat(uint8_t btn) {
if (btn >= N_BTNS || !debounced_state[btn]) return false;
- uint64_t now = esp_timer_get_time() / 1000;
- if (now + DEBOUNCE_MS < last_change_time[btn]) return false;
- if ((now - last_change_time[btn]) > (REPEAT_START_MS + REPEAT_MS * claimed_repeats[btn])) {
+ int64_t now = esp_timer_get_time();
+ if (now + DEBOUNCE_US < last_change_time[btn]) return false;
+ if ((now - last_change_time[btn]) > (REPEAT_START_US + REPEAT_US * claimed_repeats[btn])) {
claimed_repeats[btn]++;
return true;
}
@@ -145,18 +147,15 @@ int8_t i2c_get_button_repeats(uint8_t btn) {
return 0;
if (btn >= N_BTNS || !debounced_state[btn]) return false;
- uint64_t now = esp_timer_get_time() / 1000;
- if (now + DEBOUNCE_MS < last_change_time[btn]) return false;
- if ((now - last_change_time[btn]) > (REPEAT_START_MS + REPEAT_MS * claimed_repeats[btn])) {
+ int64_t now = esp_timer_get_time();
+ if (now + DEBOUNCE_US < last_change_time[btn]) return false;
+ if ((now - last_change_time[btn]) > (REPEAT_START_US + REPEAT_US * claimed_repeats[btn])) {
claimed_repeats[btn]++;
- if (claimed_repeats[btn] > 100)
- claimed_repeats[btn] = 100;
- ESP_LOGI("BTN", "RPT %d", (uint8_t)claimed_repeats[btn]+2);
+ if (claimed_repeats[btn] > MAX_REPEATS)
+ claimed_repeats[btn] = MAX_REPEATS;
return claimed_repeats[btn]+1;
}
if (debounced_state[btn] && !last_known_state[btn]) {
-
- ESP_LOGI("BTN", "FST %d", 1);
return 1;
}
@@ -167,6 +166,6 @@ int64_t i2c_get_button_ms(uint8_t btn) {
if (!i2c_get_button_state(btn))
return 0;
- uint64_t now = esp_timer_get_time() / 1000;
+ int64_t now = esp_timer_get_time();
return now - last_change_time[btn];
}
\ No newline at end of file
diff --git a/main/idf_component.yml b/main/idf_component.yml
index 8ee682a..cc3338f 100644
--- a/main/idf_component.yml
+++ b/main/idf_component.yml
@@ -1,5 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
+ espressif/mdns: "*"
joltwallet/littlefs: "==1.20.3"
esp-idf-lib/tca95x5: "*"
## Required IDF version
diff --git a/main/landingpage.html b/main/landingpage.html
index ca9e812..6fdab2d 100644
--- a/main/landingpage.html
+++ b/main/landingpage.html
@@ -1,27 +1,81 @@
+
Control Panel
+
-
+
+
+
+
ClusterCommand
+
+ |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
@@ -77,17 +118,13 @@
| Program RF Remote |
-
-
-
-
-
+
|
| Calibration |
-
- |
+
+ |
| Firmware |
@@ -101,304 +138,485 @@
+
+
+ |
+
+
+
+
-
-
+