SatNOGS-COMMS  4.1.0
A COMMS subsystem for CubeSats
Loading...
Searching...
No Matches
memory_monitor.cpp
Go to the documentation of this file.
1/*
2 * SatNOGS-COMMS MCU software
3 *
4 * Copyright (C) 2025, Libre Space Foundation <http://libre.space>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: GNU General Public License v3.0 or later
20 */
21
22#include "memory_monitor.hpp"
23#include "callbacks.hpp"
24#include "error_handler.hpp"
25#include <zephyr/dfu/mcuboot.h>
26#include <zephyr/drivers/flash.h>
27#include <zephyr/sys/printk.h>
28
29namespace satnogs::comms
30{
31
32static K_WORK_DELAYABLE_DEFINE(scan_work, memory_monitor::flash_monitor_hdlr);
33
34/* ─────────────────── Flash device & constants ───────────────────────── */
35static const struct device *const flash = DEVICE_DT_GET(DT_NODELABEL(flash));
36
37static constexpr size_t chunk_bytes = 32; /* one flash_read() */
38static constexpr size_t burst_bytes = 1024; /* pause every 1 KB */
39uint8_t buf[chunk_bytes];
40
52void
54{
55 /* if already running -> do nothing */
56 if (atomic_cas(&m_running, settings::FALSE_MAGIC, settings::TRUE_MAGIC)) {
57 m_burst_delay_ms = delay * 1000; /* convert to milliseconds */
58 m_scan_off = 0;
59 k_work_schedule(&scan_work, K_NO_WAIT); /* first sweep now */
60 }
61}
62
72void
74{
75 /* if already stopped -> do nothing */
76 if (atomic_cas(&m_running, settings::TRUE_MAGIC, settings::FALSE_MAGIC)) {
77 k_work_cancel_delayable(&scan_work);
78 }
79}
80
82 : m_running(settings::FALSE_MAGIC),
83 m_burst_delay_ms(CONFIG_FLASH_MONITOR_BURST_DELAY_SECS * 1000),
84 m_scan_off(0)
85{
86#ifdef CONFIG_BOOTLOADER_MCUBOOT
87 const struct flash_area *fa;
88 if (flash_area_open(boot_fetch_active_slot(), &fa) != 0) {
89 throw flash_init_exception(__FILE__, __LINE__);
90 }
91 m_flash_size = fa->fa_size;
92 m_flash_offset = fa->fa_off;
93#else
94 m_flash_size = DT_REG_SIZE(DT_NODELABEL(slot0_partition));
95 m_flash_offset = DT_REG_ADDR(DT_NODELABEL(slot0_partition));
96#endif
97}
98
116void
118{
119 try {
120 auto &mem_mon = memory_monitor::get_instance();
121 if (atomic_get(&mem_mon.m_running) ==
122 static_cast<atomic_val_t>(settings::TRUE_MAGIC)) {
123
124 /* ---- scan at most one 1 KiB burst per invocation ---- */
125 const off_t off_start = mem_mon.m_scan_off;
126 const off_t off_end = MIN(off_start + static_cast<off_t>(burst_bytes),
127 static_cast<off_t>(mem_mon.m_flash_size));
128
129 for (off_t off = off_start; off < off_end; off += chunk_bytes) {
130 const size_t len = MIN(chunk_bytes, mem_mon.m_flash_size - off);
131 const off_t addr = mem_mon.m_flash_offset + off;
132
133 int err = flash_read(flash, addr, buf, len);
134 if (err == -EIO) {
135 throw flash_read_exception(__FILE__, __LINE__);
136 }
137 }
138 mem_mon.m_scan_off = off_end;
139 if (mem_mon.m_scan_off >= static_cast<off_t>(mem_mon.m_flash_size)) {
140 mem_mon.m_scan_off = 0;
141 }
142 k_work_reschedule(&scan_work, K_MSEC(mem_mon.m_burst_delay_ms));
143 }
144 } catch (const lib::exception &e) {
145 auto &err = error_handler::get_instance();
146 err.handle(e);
147 } catch (const std::exception &e) {
148 auto &err = error_handler::get_instance();
149 err.handle(e);
150 }
151}
152
153} // namespace satnogs::comms
static error_handler & get_instance()
Singleton access to the error_handler subsystem.
Exception base class.
Definition exception.hpp:63
void start(int32_t delay=CONFIG_FLASH_MONITOR_BURST_DELAY_SECS)
Start the flash-monitor task.
static memory_monitor & get_instance()
static void flash_monitor_hdlr(struct k_work *work)
Work-queue handler that scans the active firmware image for unrecoverable flash ECC errors.
memory_monitor(memory_monitor const &)=delete
void stop()
Stop the flash-monitor task.
Store and retrieve reliably persistent settings.
Definition settings.hpp:60
static constexpr uint32_t FALSE_MAGIC
Definition settings.hpp:63
static constexpr uint32_t TRUE_MAGIC
Definition settings.hpp:62
uint8_t buf[chunk_bytes]