Skip to content

Commit f06e358

Browse files
committed
Initial definition of memory layout.
0 parents  commit f06e358

11 files changed

Lines changed: 748 additions & 0 deletions

File tree

.github/workflows/generate.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Generate device headers
2+
3+
on:
4+
push:
5+
branches: ["main", "master"]
6+
paths:
7+
- "eeprom_layout.yaml"
8+
- "xDOS_devices.yaml"
9+
- "scripts/generate.py"
10+
workflow_dispatch:
11+
12+
jobs:
13+
generate:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: write
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
with:
21+
# Fetch the full branch so we can push back
22+
ref: ${{ github.head_ref || github.ref_name }}
23+
24+
- uses: actions/setup-python@v5
25+
with:
26+
python-version: "3.11"
27+
28+
- name: Install dependencies
29+
run: pip install -r scripts/requirements.txt
30+
31+
- name: Generate C/C++ and Python sources
32+
run: python scripts/generate.py
33+
34+
- name: Commit generated files
35+
run: |
36+
git config user.name "github-actions[bot]"
37+
git config user.email "github-actions[bot]@users.noreply.github.com"
38+
git add generated/
39+
if git diff --cached --quiet; then
40+
echo "No changes to generated files."
41+
else
42+
git commit -m "chore: regenerate device headers from YAML [skip ci]"
43+
git push
44+
fi

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__/
2+
*.pyc
3+
*.pyo

eeprom_layout.yaml

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
eeprom_layout:
2+
name: dosimeter_eeprom
3+
language: en
4+
endianness: little
5+
checksum:
6+
algorithm: crc32
7+
coverage: full_structure
8+
checksum_field_behavior: replace_checksum_bytes_with_zero_before_crc
9+
10+
notes:
11+
- "The EEPROM layout should be represented by a fixed C/C++ struct with explicit field sizes."
12+
- "The same binary layout should be readable and writable from both Arduino/C++ and Python."
13+
- "RTC validity should be determined from RTC chip status flags."
14+
- "The last RTC reset/init time should be stored so the log header can contain an approximate device power-on estimate."
15+
- "Device variants are intentionally ignored here; this is a single unified structure."
16+
- "RTC history should be stored as an array of triplets, not as three separate arrays."
17+
18+
fields:
19+
format_version:
20+
type: uint16
21+
description: EEPROM format version for backward compatibility
22+
23+
device_type:
24+
type: uint16
25+
description: Device type identifier
26+
encoding: enum
27+
28+
crc32:
29+
type: uint32
30+
description: Structure checksum
31+
crc_zero_fill: true
32+
33+
hardware_version:
34+
type: struct
35+
description: Device version and hardware revision
36+
fields:
37+
device_version:
38+
type: uint8
39+
range: "1-99"
40+
hardware_revision:
41+
type: uint8
42+
range: "A-Z"
43+
44+
device_identifier:
45+
type: char[24]
46+
description: Human-readable device identifier
47+
example: "animal name printed on enclosure"
48+
49+
operating_modes:
50+
type: uint16
51+
description: Operating modes and configuration flags
52+
53+
rtc_flags:
54+
type: uint8
55+
description: RTC capability and status flags
56+
bit_mapping:
57+
bit_0: has_rtc
58+
bit_1: has_rtc_backup_battery
59+
bit_2: rtc_initialized
60+
bit_3: rtc_power_loss_detected
61+
bit_4: geiger_mode_enabled
62+
bit_5: led_enabled
63+
bit_6: reserved
64+
bit_7: reserved
65+
66+
rtc_history:
67+
type: array
68+
length: 5
69+
description: History table of RTC-related reference points
70+
item_type: struct
71+
item_fields:
72+
rtc_initialization_timestamp:
73+
type: uint32
74+
description: Time when RTC was reset or initialized
75+
reference_timestamp:
76+
type: uint32
77+
description: Periodically updated reference time
78+
rtc_value_at_reference_timestamp:
79+
type: uint32
80+
description: RTC counter/state captured when the reference timestamp was written
81+
82+
calibration_constants:
83+
type: float[3]
84+
description: Calibration parameters
85+
86+
calibration_version:
87+
type: uint32
88+
description: Calibration timestamp or calibration version

generated/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Auto-generated — do not edit manually.
2+
from .xdos_devices import DeviceType, KnownDevice, KNOWN_DEVICES, KNOWN_DEVICES_BY_NAME
3+
from .eeprom_layout import DosimeterEeprom, RtcFlagsFlags

generated/eeprom_layout.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/* Auto-generated from eeprom_layout.yaml — do not edit manually. */
2+
#pragma once
3+
#include "xdos_devices.h"
4+
5+
typedef struct __attribute__((packed)) {
6+
uint16_t format_version;
7+
uint16_t device_type;
8+
uint32_t crc32;
9+
struct __attribute__((packed)) {
10+
uint8_t device_version;
11+
uint8_t hardware_revision;
12+
} hardware_version;
13+
char device_identifier[24];
14+
uint16_t operating_modes;
15+
uint8_t rtc_flags;
16+
struct __attribute__((packed)) {
17+
uint32_t rtc_initialization_timestamp;
18+
uint32_t reference_timestamp;
19+
uint32_t rtc_value_at_reference_timestamp;
20+
} rtc_history[5];
21+
float calibration_constants[3];
22+
uint32_t calibration_version;
23+
} DosimeterEeprom;
24+
25+
/* Bit flags for field 'rtc_flags' */
26+
#define EEPROM_HAS_RTC (1u << 0)
27+
#define EEPROM_HAS_RTC_BACKUP_BATTERY (1u << 1)
28+
#define EEPROM_RTC_INITIALIZED (1u << 2)
29+
#define EEPROM_RTC_POWER_LOSS_DETECTED (1u << 3)
30+
#define EEPROM_GEIGER_MODE_ENABLED (1u << 4)
31+
#define EEPROM_LED_ENABLED (1u << 5)

generated/eeprom_layout.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Auto-generated from eeprom_layout.yaml — do not edit manually.
2+
import ctypes
3+
import enum
4+
from .xdos_devices import DeviceType # noqa: F401
5+
6+
class RtcFlagsFlags(enum.IntFlag):
7+
HAS_RTC = 1 << 0
8+
HAS_RTC_BACKUP_BATTERY = 1 << 1
9+
RTC_INITIALIZED = 1 << 2
10+
RTC_POWER_LOSS_DETECTED = 1 << 3
11+
GEIGER_MODE_ENABLED = 1 << 4
12+
LED_ENABLED = 1 << 5
13+
14+
class HardwareVersion(ctypes.LittleEndianStructure):
15+
_pack_ = 1
16+
_fields_ = [
17+
("device_version", ctypes.c_uint8),
18+
("hardware_revision", ctypes.c_uint8),
19+
]
20+
21+
class RtcHistoryEntry(ctypes.LittleEndianStructure):
22+
_pack_ = 1
23+
_fields_ = [
24+
("rtc_initialization_timestamp", ctypes.c_uint32),
25+
("reference_timestamp", ctypes.c_uint32),
26+
("rtc_value_at_reference_timestamp", ctypes.c_uint32),
27+
]
28+
29+
class DosimeterEeprom(ctypes.LittleEndianStructure):
30+
_pack_ = 1
31+
_fields_ = [
32+
("format_version", ctypes.c_uint16),
33+
("device_type", ctypes.c_uint16),
34+
("crc32", ctypes.c_uint32),
35+
("hardware_version", HardwareVersion),
36+
("device_identifier", ctypes.c_char * 24),
37+
("operating_modes", ctypes.c_uint16),
38+
("rtc_flags", ctypes.c_uint8),
39+
("rtc_history", RtcHistoryEntry * 5),
40+
("calibration_constants", ctypes.c_float * 3),
41+
("calibration_version", ctypes.c_uint32),
42+
]

generated/xdos_devices.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/* Auto-generated from xDOS_devices.yaml — do not edit manually. */
2+
#pragma once
3+
#include <stdint.h>
4+
5+
typedef enum {
6+
DEVICE_TYPE_UNKNOWN = 0,
7+
DEVICE_TYPE_AIRDOS = 1,
8+
DEVICE_TYPE_GEODOS = 2,
9+
DEVICE_TYPE_LABDOS = 3,
10+
DEVICE_TYPE_SPACEDOS = 4,
11+
} DeviceType;
12+
13+
typedef struct {
14+
const char *full_name;
15+
DeviceType device_type;
16+
uint8_t device_version;
17+
char hardware_revision; /* '\0' = no revision letter */
18+
} KnownDevice;
19+
20+
static const KnownDevice KNOWN_DEVICES[] = {
21+
{"AIRDOS01", DEVICE_TYPE_AIRDOS, 1, '\0'},
22+
{"AIRDOS02", DEVICE_TYPE_AIRDOS, 2, '\0'},
23+
{"AIRDOS03A", DEVICE_TYPE_AIRDOS, 3, 'A'},
24+
{"AIRDOS03B", DEVICE_TYPE_AIRDOS, 3, 'B'},
25+
{"AIRDOS04A", DEVICE_TYPE_AIRDOS, 4, 'A'},
26+
{"AIRDOS04B", DEVICE_TYPE_AIRDOS, 4, 'B'},
27+
{"AIRDOS04C", DEVICE_TYPE_AIRDOS, 4, 'C'},
28+
{"GEODOS01", DEVICE_TYPE_GEODOS, 1, '\0'},
29+
{"GEODOS02", DEVICE_TYPE_GEODOS, 2, '\0'},
30+
{"LABDOS01", DEVICE_TYPE_LABDOS, 1, '\0'},
31+
{"SPACEDOS01B", DEVICE_TYPE_SPACEDOS, 1, 'B'},
32+
{"SPACEDOS02", DEVICE_TYPE_SPACEDOS, 2, '\0'},
33+
{"SPACEDOS04", DEVICE_TYPE_SPACEDOS, 4, '\0'},
34+
};
35+
36+
static const int KNOWN_DEVICE_COUNT =
37+
(int)(sizeof(KNOWN_DEVICES) / sizeof(KNOWN_DEVICES[0]));

generated/xdos_devices.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Auto-generated from xDOS_devices.yaml — do not edit manually.
2+
from __future__ import annotations
3+
import enum
4+
from dataclasses import dataclass
5+
from typing import Optional
6+
7+
class DeviceType(enum.IntEnum):
8+
UNKNOWN = 0
9+
AIRDOS = 1
10+
GEODOS = 2
11+
LABDOS = 3
12+
SPACEDOS = 4
13+
14+
@dataclass(frozen=True)
15+
class KnownDevice:
16+
full_name: str
17+
device_type: DeviceType
18+
device_version: int
19+
hardware_revision: Optional[str]
20+
21+
KNOWN_DEVICES: list[KnownDevice] = [
22+
KnownDevice("AIRDOS01", DeviceType.AIRDOS, 1, None),
23+
KnownDevice("AIRDOS02", DeviceType.AIRDOS, 2, None),
24+
KnownDevice("AIRDOS03A", DeviceType.AIRDOS, 3, "A"),
25+
KnownDevice("AIRDOS03B", DeviceType.AIRDOS, 3, "B"),
26+
KnownDevice("AIRDOS04A", DeviceType.AIRDOS, 4, "A"),
27+
KnownDevice("AIRDOS04B", DeviceType.AIRDOS, 4, "B"),
28+
KnownDevice("AIRDOS04C", DeviceType.AIRDOS, 4, "C"),
29+
KnownDevice("GEODOS01", DeviceType.GEODOS, 1, None),
30+
KnownDevice("GEODOS02", DeviceType.GEODOS, 2, None),
31+
KnownDevice("LABDOS01", DeviceType.LABDOS, 1, None),
32+
KnownDevice("SPACEDOS01B", DeviceType.SPACEDOS, 1, "B"),
33+
KnownDevice("SPACEDOS02", DeviceType.SPACEDOS, 2, None),
34+
KnownDevice("SPACEDOS04", DeviceType.SPACEDOS, 4, None),
35+
]
36+
37+
KNOWN_DEVICES_BY_NAME: dict[str, KnownDevice] = {
38+
d.full_name: d for d in KNOWN_DEVICES
39+
}

0 commit comments

Comments
 (0)