Skip to content

Commit 96e8bb8

Browse files
Implement EEPROM position storage for focuser state persistence
1 parent e61d266 commit 96e8bb8

File tree

13 files changed

+391
-22
lines changed

13 files changed

+391
-22
lines changed

app/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ project(app LANGUAGES C CXX)
1212
target_sources(app PRIVATE
1313
src/main.cpp
1414
src/Focuser.cpp
15+
src/EepromPositionStore.cpp
1516
src/FocuserThread.cpp
1617
src/UartHandler.cpp
1718
src/UartThread.cpp

app/boards/esp32s3_devkitc_procpu.overlay

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
*/
1313

1414
/ {
15+
aliases {
16+
eeprom-0 = &eeprom0;
17+
};
18+
1519
chosen {
1620
zephyr,console = &uart1;
1721
zephyr,log-uart = &focuser_log_uarts;
@@ -20,6 +24,17 @@
2024
focuser,stepper-drv = &focuser_stepper_drv;
2125
};
2226

27+
eeprom0: eeprom@0 {
28+
compatible = "zephyr,emu-eeprom";
29+
label = "focuser-eeprom";
30+
reg = <0x0 0x20>;
31+
size = <32>;
32+
pagesize = <0x1000>;
33+
partition = <&storage_partition>;
34+
rambuf;
35+
status = "okay";
36+
};
37+
2338
focuser_log_uarts: focuser_log_uarts {
2439
compatible = "zephyr,log-uart";
2540
uarts = <&uart1>;

app/prj.conf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ CONFIG_UART_CONSOLE=y
2121
# Enable Logging (LOG_INF, LOG_ERR)
2222
CONFIG_LOG=y
2323

24+
# Persist focuser state in flash-backed EEPROM.
25+
CONFIG_EEPROM=y
26+
2427
# Set the application log level.
2528
CONFIG_APP_LOG_LEVEL_INF=y
2629

@@ -32,3 +35,6 @@ CONFIG_STEPPER_ADI_TMC2209=y
3235

3336
# Grow the main thread stack to accommodate the C++ runtime initialisation.
3437
CONFIG_MAIN_STACK_SIZE=3072
38+
39+
# Enable MCUBoot bootloader support.
40+
CONFIG_BOOTLOADER_MCUBOOT=y

app/src/EepromPositionStore.cpp

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
#include "EepromPositionStore.hpp"
2+
3+
#include <zephyr/device.h>
4+
#include <zephyr/devicetree.h>
5+
#include <zephyr/drivers/eeprom.h>
6+
#include <zephyr/logging/log.h>
7+
#include <zephyr/sys/util.h>
8+
9+
LOG_MODULE_REGISTER(position_store, CONFIG_APP_LOG_LEVEL);
10+
11+
namespace
12+
{
13+
#if DT_HAS_ALIAS(eeprom_0)
14+
#define FOCUSER_EEPROM_NODE DT_ALIAS(eeprom_0)
15+
#endif
16+
17+
#ifdef FOCUSER_EEPROM_NODE
18+
const struct device *const k_eeprom = DEVICE_DT_GET(FOCUSER_EEPROM_NODE);
19+
#endif
20+
21+
constexpr uint32_t kPositionMagic = 0x464F4350U; // "FOCP"
22+
constexpr off_t kPositionOffset = 0;
23+
24+
} // namespace
25+
26+
EepromPositionStore::EepromPositionStore()
27+
{
28+
}
29+
30+
bool EepromPositionStore::load(uint16_t &position_out)
31+
{
32+
#ifndef FOCUSER_EEPROM_NODE
33+
ARG_UNUSED(position_out);
34+
return false;
35+
#else
36+
if (!ensure_ready())
37+
{
38+
return false;
39+
}
40+
41+
PositionRecord record{};
42+
const int ret = eeprom_read(k_eeprom, kPositionOffset, &record, sizeof(record));
43+
if (ret != 0)
44+
{
45+
LOG_WRN("Failed to read position from EEPROM (%d)", ret);
46+
return false;
47+
}
48+
49+
if ((record.magic != kPositionMagic) || (record.checksum != checksum(record.position)))
50+
{
51+
return false;
52+
}
53+
54+
position_out = record.position;
55+
m_last_value = record.position;
56+
m_has_value = true;
57+
return true;
58+
#endif
59+
}
60+
61+
void EepromPositionStore::save(uint16_t position)
62+
{
63+
#ifndef FOCUSER_EEPROM_NODE
64+
ARG_UNUSED(position);
65+
return;
66+
#else
67+
if (m_has_value && (position == m_last_value))
68+
{
69+
return;
70+
}
71+
72+
if (!ensure_ready())
73+
{
74+
return;
75+
}
76+
77+
PositionRecord record{
78+
.magic = kPositionMagic,
79+
.position = position,
80+
.checksum = checksum(position),
81+
};
82+
83+
const int ret = eeprom_write(k_eeprom, kPositionOffset, &record, sizeof(record));
84+
if (ret != 0)
85+
{
86+
LOG_ERR("Failed to save position to EEPROM (%d)", ret);
87+
return;
88+
}
89+
90+
m_last_value = position;
91+
m_has_value = true;
92+
LOG_DBG("Saved focuser position 0x%04x (%u) to EEPROM", position, position);
93+
#endif
94+
}
95+
96+
bool EepromPositionStore::ensure_ready()
97+
{
98+
#ifndef FOCUSER_EEPROM_NODE
99+
return false;
100+
#else
101+
if (!m_ready)
102+
{
103+
if (!device_is_ready(k_eeprom))
104+
{
105+
LOG_WRN("EEPROM device not ready");
106+
return false;
107+
}
108+
109+
m_eeprom_size = eeprom_get_size(k_eeprom);
110+
if (m_eeprom_size < sizeof(PositionRecord))
111+
{
112+
LOG_ERR("EEPROM too small (%zu < %zu)", m_eeprom_size, sizeof(PositionRecord));
113+
return false;
114+
}
115+
116+
m_ready = true;
117+
}
118+
119+
return true;
120+
#endif
121+
}
122+
123+
uint16_t EepromPositionStore::checksum(uint16_t position) const
124+
{
125+
return static_cast<uint16_t>(((kPositionMagic >> 16) ^ (kPositionMagic & 0xFFFFU) ^ position) & 0xFFFFU);
126+
}

app/src/EepromPositionStore.hpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#include <cstddef>
4+
#include <cstdint>
5+
6+
#include "PositionStore.hpp"
7+
8+
class EepromPositionStore final : public PositionStore
9+
{
10+
public:
11+
EepromPositionStore();
12+
13+
bool load(uint16_t &position_out) override;
14+
void save(uint16_t position) override;
15+
16+
private:
17+
struct PositionRecord
18+
{
19+
uint32_t magic;
20+
uint16_t position;
21+
uint16_t checksum;
22+
};
23+
24+
bool ensure_ready();
25+
uint16_t checksum(uint16_t position) const;
26+
27+
bool m_ready{false};
28+
bool m_has_value{false};
29+
uint16_t m_last_value{0U};
30+
size_t m_eeprom_size{0U};
31+
};

app/src/Focuser.cpp

Lines changed: 66 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ namespace
2222

2323
} // namespace
2424

25-
Focuser::Focuser(FocuserStepper &stepper, const char *firmware_version)
26-
: m_firmware_version(firmware_version), m_stepper(stepper)
25+
Focuser::Focuser(FocuserStepper &stepper, PositionStore *store, const char *firmware_version)
26+
: m_firmware_version(firmware_version), m_stepper(stepper), m_store(store)
2727
{
2828
(void)set_stepper_driver_enabled(true);
2929
}
@@ -50,6 +50,8 @@ int Focuser::initialise()
5050
return ret;
5151
}
5252

53+
restore_position();
54+
5355
uint64_t interval_ns = 0;
5456
{
5557
MutexLock lock(m_state.lock);
@@ -139,6 +141,7 @@ void Focuser::stop()
139141
(void)m_stepper.stop();
140142
(void)set_stepper_driver_enabled(false);
141143
k_sem_give(&m_state.move_sem);
144+
save_position(actual16);
142145
LOG_INF("stop()");
143146
}
144147

@@ -157,19 +160,7 @@ uint16_t Focuser::getCurrentPosition()
157160

158161
void Focuser::setCurrentPosition(uint16_t position)
159162
{
160-
LOG_DBG("setCurrentPosition()");
161-
int ret = m_stepper.set_reference_position(static_cast<int32_t>(position));
162-
if (ret != 0)
163-
{
164-
LOG_ERR("Failed to set reference position (%d)", ret);
165-
}
166-
167-
MutexLock lock(m_state.lock);
168-
m_state.staged_position = position;
169-
m_state.desired_position = position;
170-
m_state.move_request = false;
171-
m_state.cancel_move = false;
172-
LOG_INF("setCurrentPosition 0x%04x (%u)", position, position);
163+
applyCurrentPosition(position, true);
173164
}
174165

175166
uint16_t Focuser::getNewPosition()
@@ -356,6 +347,8 @@ void Focuser::move_to(uint16_t target)
356347
{
357348
(void)set_stepper_driver_enabled(false);
358349
}
350+
351+
save_position(actual16);
359352
LOG_DBG("Motion complete -> 0x%04x (%d)", static_cast<uint16_t>(actual & 0xFFFF), actual);
360353
}
361354

@@ -391,6 +384,64 @@ int32_t Focuser::read_actual_position()
391384
return actual;
392385
}
393386

387+
void Focuser::restore_position()
388+
{
389+
if (m_store == nullptr)
390+
{
391+
LOG_INF("No position store configured; using default position 0");
392+
return;
393+
}
394+
395+
uint16_t persisted = 0U;
396+
if (m_store->load(persisted))
397+
{
398+
LOG_INF("Restoring focuser position 0x%04x (%u) from store", persisted, persisted);
399+
applyCurrentPosition(persisted, false);
400+
}
401+
else
402+
{
403+
LOG_INF("No persisted focuser position found, defaulting to 0");
404+
}
405+
}
406+
407+
void Focuser::applyCurrentPosition(uint16_t position, bool persist)
408+
{
409+
LOG_DBG("setCurrentPosition()");
410+
int ret = m_stepper.set_reference_position(static_cast<int32_t>(position));
411+
if (ret != 0)
412+
{
413+
LOG_ERR("Failed to set reference position (%d)", ret);
414+
}
415+
416+
{
417+
MutexLock lock(m_state.lock);
418+
m_state.staged_position = position;
419+
m_state.desired_position = position;
420+
m_state.move_request = false;
421+
m_state.cancel_move = false;
422+
}
423+
424+
if (persist)
425+
{
426+
save_position(position);
427+
LOG_INF("setCurrentPosition 0x%04x (%u)", position, position);
428+
}
429+
else
430+
{
431+
LOG_INF("setCurrentPosition 0x%04x (%u) (no persist)", position, position);
432+
}
433+
}
434+
435+
void Focuser::save_position(uint16_t position)
436+
{
437+
if (m_store == nullptr)
438+
{
439+
return;
440+
}
441+
442+
m_store->save(position);
443+
}
444+
394445
int Focuser::set_stepper_driver_enabled(bool enable)
395446
{
396447
const int ret = m_stepper.enable_driver(enable);

app/src/Focuser.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
#include <string>
99

1010
#include "FocuserStepper.hpp"
11+
#include "PositionStore.hpp"
1112

1213
class Focuser final : public moonlite::Handler
1314
{
1415
public:
15-
explicit Focuser(FocuserStepper &stepper, const char *firmware_version);
16+
explicit Focuser(FocuserStepper &stepper, PositionStore *store, const char *firmware_version);
1617

1718
int initialise();
1819
void loop();
@@ -70,9 +71,13 @@ class Focuser final : public moonlite::Handler
7071
int apply_step_interval(uint64_t interval_ns);
7172
int32_t read_actual_position();
7273
int set_stepper_driver_enabled(bool enable);
74+
void restore_position();
75+
void applyCurrentPosition(uint16_t position, bool persist);
76+
void save_position(uint16_t position);
7377

7478
const char *m_firmware_version;
7579

7680
FocuserState m_state{};
7781
FocuserStepper &m_stepper;
82+
PositionStore *m_store;
7883
};

app/src/PositionStore.hpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#pragma once
2+
3+
#include <cstdint>
4+
5+
class PositionStore
6+
{
7+
public:
8+
virtual ~PositionStore() = default;
9+
10+
virtual bool load(uint16_t &position_out) = 0;
11+
virtual void save(uint16_t position) = 0;
12+
};

app/src/main.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include <errno.h>
1313

1414
#include "Configuration.hpp"
15+
#include "EepromPositionStore.hpp"
1516
#include "Focuser.hpp"
1617
#include "FocuserThread.hpp"
1718
#include "UartHandler.hpp"
@@ -23,8 +24,9 @@ LOG_MODULE_REGISTER(focuser, CONFIG_APP_LOG_LEVEL);
2324
namespace
2425
{
2526

27+
EepromPositionStore g_position_store;
2628
ZephyrFocuserStepper g_stepper_adapter(config::devices::stepper, config::devices::stepper_drv);
27-
Focuser g_focuser(g_stepper_adapter, config::version);
29+
Focuser g_focuser(g_stepper_adapter, &g_position_store, config::version);
2830
FocuserThread g_focuser_thread(g_focuser);
2931
UartHandler g_uart_handler(config::devices::uart);
3032
UartThread g_uart_thread(g_focuser, g_uart_handler);

0 commit comments

Comments
 (0)