Skip to content

Add support to read/write a single block in the RTC Memory #7725

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions docs/library/machine.RTC.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,42 @@ Methods
- ``handler`` is the function to be called when the callback is triggered.
- ``wake`` specifies the sleep mode from where this interrupt can wake
up the system.

.. method:: RTC.memory([data])

Stores ``data`` (byte literal) into RTC memory, which is kept stored in deep sleep mode of the ESP8266 or ESP32.
The data is stored together with a magic word to detect that the RTC memory is valid.
An uninitialized or cleared RTC memory has no magic word and will deliver ``b''``.
Without ``data`` the method delivers the RTC memory content.
In the ESP8266 are max. 492 bytes and in the ESP32 are max. 2048 Bytes storeable by this method.

Example::

import machine
rtc = machine.RTC()
writedata = b'test'
rtc.memory(writedata) # this command writes writedata into the RTC memory
readdata = rtc.memory() # this command puts the RTC memory into readdata
print(readdata)

Availability: ESP8266, ESP32

.. method:: RTC.memory(idx, len, [data])

Same as `RTC.memory([data])` but allows slot wise access to the memory.
On the ESP8266, 122 slots with 4bytes each are available.
The memory stays compatible with the block read/write functionality.

Example::

import machine
rtc = machine.RTC()
writedata = b'\x20\x30\x40\x50'
rtc.memory(0, 1, writedata) # this command writes writedata into the first slot of the RTC memory
readdata = rtc.memory(0, 1) # this command puts the content of SLot 0 of the RTC memory into readdata
print(readdata)

Availability: ESP8266

Constants
---------
Expand Down
82 changes: 78 additions & 4 deletions ports/esp8266/machine_rtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "py/runtime.h"
Expand All @@ -42,7 +43,9 @@ typedef struct _pyb_rtc_obj_t {
#define MEM_USER_MAGIC_ADDR (MEM_CAL_ADDR + 1)
#define MEM_USER_LEN_ADDR (MEM_USER_MAGIC_ADDR + 1)
#define MEM_USER_DATA_ADDR (MEM_USER_LEN_ADDR + 1)
#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4)
#define MEM_USER_MAXLEN (512 - (MEM_USER_DATA_ADDR - MEM_DELTA_ADDR) * 4) // 492
#define MEM_USER_SLOTS_SIZE 4 /* Slots have 4 bytes, see https://nodemcu.readthedocs.io/en/release/modules/rtcmem/ */
#define MEM_USER_SLOTS (MEM_USER_MAXLEN/MEM_USER_SLOTS_SIZE)

// singleton RTC object
STATIC const pyb_rtc_obj_t pyb_rtc_obj = {{&pyb_rtc_type}};
Expand Down Expand Up @@ -166,6 +169,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_datetime_obj, 1, 2, pyb_rtc_d
STATIC mp_obj_t pyb_rtc_memory(size_t n_args, const mp_obj_t *args) {
uint8_t rtcram[MEM_USER_MAXLEN];
uint32_t len;
uint32_t idx;

if (n_args == 1) {
// read RTC memory
Expand All @@ -174,8 +178,9 @@ STATIC mp_obj_t pyb_rtc_memory(size_t n_args, const mp_obj_t *args) {
system_rtc_mem_read(MEM_USER_DATA_ADDR, rtcram, (len + 3) & ~3);

return mp_obj_new_bytes(rtcram, len);
} else {
// write RTC memory
}
else if (n_args == 2) {
// write RTC memory: [data]

mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
Expand All @@ -196,9 +201,78 @@ STATIC mp_obj_t pyb_rtc_memory(size_t n_args, const mp_obj_t *args) {

return mp_const_none;
}
else if (n_args == 3) {
// read addressed memory slot: [32bit slot ID, number of slots]

// idx = atoi(args[1]); // Linker error: undefined reference to 'atoi'
idx = (uint32_t)(args[1]);

// len = atoi(args[2]); // Linker error: undefined reference to 'atoi'
len = (uint32_t)(args[2]);

/* For some reason idx and len somehow get multiplied by 2 and +1!
We need to revert this. Since indx is always a multiple of 2, we savely can divide it again by 2 */
idx = (idx - 1) / 2; // Slot ID, 0..122
len = (len - 1) / 2; // Number of 4-byte slots, 0..123

if (idx > MEM_USER_SLOTS) { // idx must be 0..122
mp_raise_ValueError(MP_ERROR_TEXT("index out of range"));
}

if ((idx + len) > MEM_USER_SLOTS) {
mp_raise_ValueError(MP_ERROR_TEXT("read beyond valid range"));
}

if (len == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("must read at least 1 slot"));
}

system_rtc_mem_read(MEM_USER_DATA_ADDR + idx, rtcram, len * 4);
return mp_obj_new_bytes(rtcram, len * 4);
}
else if (n_args == 4) {
// write addressed memory slot: [32bit slot ID, number of slots, data]

// idx = atoi(args[1]); // Linker error: undefined reference to 'atoi'
idx = (uint32_t)(args[1]);

// len = atoi(args[2]); // Linker error: undefined reference to 'atoi'
len = (uint32_t)(args[2]);

/* For some reason idx and len somehow get multiplied by 2 and +1!
We need to revert this. Since indx is always a multiple of 2, we savely can divide it again by 2 */
idx = (idx - 1) / 2; // Slot ID, 0..122
len = (len - 1) / 2; // Number of 4-byte slots, 0..123

if (idx > MEM_USER_SLOTS) { // idx must be 0..122
mp_raise_ValueError(MP_ERROR_TEXT("index out of range"));
}

if ((idx + len) > MEM_USER_SLOTS) {
mp_raise_ValueError(MP_ERROR_TEXT("write beyond valid range"));
}

if (len == 0) {
mp_raise_ValueError(MP_ERROR_TEXT("must write at least 1 slot"));
}

mp_buffer_info_t bufinfo;
mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);

int i = 0;
for (; i < bufinfo.len; i++) {
rtcram[i] = ((uint8_t *)bufinfo.buf)[i];
}

system_rtc_mem_write(MEM_USER_DATA_ADDR + idx, rtcram, len * 4);

return mp_const_none;
}
else {
return mp_const_none;
}
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 2, pyb_rtc_memory);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_rtc_memory_obj, 1, 4, pyb_rtc_memory);

STATIC mp_obj_t pyb_rtc_alarm(mp_obj_t self_in, mp_obj_t alarm_id, mp_obj_t time_in) {
(void)self_in; // unused
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy