-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcommon.h
More file actions
215 lines (196 loc) · 12.7 KB
/
Copy pathcommon.h
File metadata and controls
215 lines (196 loc) · 12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
/**
* common.h — 5G NR-Aligned MAC Layer Definitions
* TDMA WSN over ESP32 / ESP-NOW
*
* ┌─────────────────────────────────────────────────────────────────────────┐
* │ 5G NR Concept → Simulation Mapping │
* ├──────────────────────────┬──────────────────────────────────────────────┤
* │ NR (TS 38.321 / 38.214) │ This implementation │
* ├──────────────────────────┼──────────────────────────────────────────────┤
* │ gNB │ Coordinator ESP32 │
* │ UE │ Sensor node ESP32 │
* │ Radio Frame (10ms) │ Hyper-frame (100ms, 10× scale) │
* │ Slot (μ=0, 1ms, 14 sym) │ Sim-slot (10ms, 10× scale) │
* │ PDCCH (UL DCI format 0_1)│ DciGrant[] array inside beacon frame │
* │ PUSCH │ DataFrame (uplink data PDU) │
* │ HARQ 8 processes │ HarqPid 0..7, NDI, RV ∈ {0,1,2,3} │
* │ BSR (MAC CE short BSR) │ 4-bit lcg_bsr field in DataFrame │
* │ CQI (UCI on PUSCH) │ 4-bit cqi field piggybacked on data frame │
* │ MCS Table 1 (64QAM) │ 8-level simplified TBS table │
* │ BLER │ Block Error Rate logged per HARQ process │
* │ SR (Scheduling Request) │ SR frame type (PUCCH analogue) │
* │ Logical Channel (LCID) │ 4-bit lcid: CCCH=0, DTCH=1, BSR_CE=2 │
* │ RRC Connected │ STATE_SYNCED (post JOIN_ACK) │
* └──────────────────────────┴──────────────────────────────────────────────┘
*
* Timing scale note:
* 5G NR μ=0 slot = 1ms. ESP-NOW+FreeRTOS jitter ≈ 200–800µs → need
* ≥5ms practical slot. We scale 10× so 1 NR slot = 10ms sim-slot.
* All timing analysis is still valid — just multiply by 1/10 for NR
* equivalents when writing the report.
*
* References:
* 3GPP TS 38.321 — NR MAC specification
* 3GPP TS 38.214 — NR Physical layer procedures (MCS/CQI tables)
* 3GPP TS 38.211 — NR Physical channels (frame structure)
*/
#pragma once
#include <stdint.h>
// ── 5G NR Numerology (μ = 0, SCS = 15 kHz, FR1 sub-6GHz) ────────────────────
#define NR_NUMEROLOGY_MU 0 // Subcarrier Spacing index
#define NR_SCS_KHZ 15 // Subcarrier spacing (kHz)
#define NR_SLOTS_PER_FRAME 10 // μ=0: 10 slots per 10ms radio frame
#define NR_SYMBOLS_PER_SLOT 14 // Normal cyclic prefix
#define SIM_SCALE 10 // Simulation scale factor vs real NR
// ── Simulation Timing (10× scaled NR μ=0) ───────────────────────────────────
#define SIM_SLOT_MS 10 // 10× NR slot (real NR = 1ms)
#define SIM_GUARD_MS 3 // Guard interval between slots (CP analogue)
#define SIM_BEACON_MS 10 // PDCCH window (DCI broadcast)
#define MAX_NODES 4 // Max UEs in network
// Hyper-frame = beacon + N×(slot + guard) ≈ 10 + 4×13 = 62ms
// → ~16 hyper-frames/sec when 4 nodes active
#define HYPERFRAME_MS (SIM_BEACON_MS + MAX_NODES * (SIM_SLOT_MS + SIM_GUARD_MS))
// ── Network Config ────────────────────────────────────────────────────────────
#define WIFI_CHANNEL 6
#define MAX_RETRIES 3 // Max HARQ retransmissions (RV sequence)
#define ACK_TIMEOUT_MS 7 // HARQ feedback window
// ── HARQ Parameters (TS 38.321 §5.4) ─────────────────────────────────────────
#define HARQ_PROCESSES 8 // 3GPP max UL HARQ processes per UE
#define HARQ_RV_SEQUENCE_LEN 4 // RV rotation: 0 → 2 → 3 → 1 → 0 ...
// Redundancy version rotation (Chase combining simplified: all RV=0)
// Full IR-HARQ would use {0, 2, 3, 1}
static const uint8_t HARQ_RV_SEQ[HARQ_RV_SEQUENCE_LEN] = {0, 2, 3, 1};
// ── MCS Table (Simplified TS 38.214 Table 5.1.3.1-1, 64QAM max) ─────────────
// 8 MCS levels → Transport Block Size (TBS) in bytes
// Real NR TBS calculation uses resource blocks + code rate;
// here TBS = payload bytes per uplink slot grant
#define NR_MCS_LEVELS 8
static const uint8_t MCS_TBS_BYTES[NR_MCS_LEVELS] = {
/* MCS0 MCS1 MCS2 MCS3 MCS4 MCS5 MCS6 MCS7 */
10, 20, 35, 50, 70, 90, 110, 125
// QPSK 16QAM 64QAM
};
// Approximate modulation order per MCS (for logging only)
static const uint8_t MCS_MOD_ORDER[NR_MCS_LEVELS] = {
2, 2, 2, 4, 4, 4, 6, 6 // 2=QPSK, 4=16QAM, 6=64QAM
};
// ── CQI Table (TS 38.214 Table 5.2.2.1-3, 4-bit CQI) ────────────────────────
// CQI 0 = out of range, CQI 15 = 64QAM, code rate ~948/1024
// CQI → MCS index (simplified linear mapping)
static const uint8_t CQI_TO_MCS[16] = {
/* CQI: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7
};
// RSSI (dBm) → CQI (0–15) — empirical for ESP32/ESP-NOW at 2.4 GHz
static inline uint8_t rssiToCqi(int8_t rssi) {
if (rssi >= -45) return 15;
if (rssi >= -50) return 13;
if (rssi >= -55) return 11;
if (rssi >= -60) return 9;
if (rssi >= -65) return 8;
if (rssi >= -70) return 6;
if (rssi >= -75) return 4;
if (rssi >= -80) return 2;
if (rssi >= -85) return 1;
return 0; // Out of range — UE should not be scheduled
}
// ── BSR Table (TS 38.321 Table 6.1.3.1-1, Short BSR, 4-bit LCG BSR) ─────────
// BSR index → buffer size upper bound (bytes)
// Coordinator uses this to decide grant size
#define BSR_LEVELS 16
static const uint16_t BSR_TABLE[BSR_LEVELS] = {
0, 10, 20, 36, 60, 80, 150, 300, 500, 1000,
2000, 3000, 4000, 5000, 6000, 7000
};
// Local buffer size → BSR index (inverse lookup)
static inline uint8_t bufferToBsr(uint16_t buf_bytes) {
for (int i = BSR_LEVELS - 1; i >= 0; i--)
if (buf_bytes >= BSR_TABLE[i]) return (uint8_t)i;
return 0;
}
// ── Logical Channel IDs (LCID, TS 38.321 Table 6.2.1-1) ─────────────────────
#define LCID_CCCH 0 // Common Control Channel — JOIN_REQ / SR
#define LCID_DTCH 1 // Dedicated Traffic Channel — sensor data
#define LCID_BSR_CE 2 // Short BSR MAC Control Element (piggybacked)
#define LCID_PAD 63 // Padding
// ── Frame Type Constants ──────────────────────────────────────────────────────
// (NR analogue in comments)
#define FRAME_BEACON 0x01 // SSB + PDCCH (DCI UL grant broadcast)
#define FRAME_DATA 0x02 // PUSCH (uplink data + UCI)
#define FRAME_HARQ_FB 0x03 // PDCCH with HARQ-ACK (replaces simple ACK)
#define FRAME_JOIN_REQ 0x04 // RRC Setup Request (CCCH / RACH analogue)
#define FRAME_JOIN_ACK 0x05 // RRC Setup (slot + HARQ config assignment)
#define FRAME_SR 0x06 // Scheduling Request (PUCCH format 0 analogue)
// ── DCI Uplink Grant (TS 38.212 DCI format 0_1, simplified) ──────────────────
// One entry per scheduled UE; carried in beacon payload (PDCCH analogue)
typedef struct __attribute__((packed)) {
uint8_t ue_node_id; // UE this grant targets (0 = not scheduled)
uint8_t slot_index; // Which sim-slot this UE should transmit in
uint8_t mcs_index; // MCS to use (0..NR_MCS_LEVELS-1) → TBS
uint8_t harq_pid : 4; // HARQ process ID (0..7)
uint8_t ndi : 1; // New Data Indicator (toggle = new TB, same = retx)
uint8_t rv : 2; // Redundancy Version (0,1,2,3)
uint8_t _pad : 1;
} DciGrant; // 4 bytes per UE
// ── MAC Header (TS 38.321 MAC subheader, extended) ────────────────────────────
typedef struct __attribute__((packed)) {
uint8_t frame_type; // FRAME_* constant
uint8_t src_id; // Sender ID (0 = gNB/coordinator)
uint8_t dst_id; // Receiver ID (0xFF = broadcast)
uint16_t seq_num; // TB sequence number
uint32_t tx_timestamp_us; // Sender µs clock (esp_timer_get_time)
uint8_t harq_pid : 4; // HARQ process ID [0..7]
uint8_t ndi : 1; // New Data Indicator
uint8_t rv : 2; // Redundancy Version
uint8_t lcid : 5; // Logical Channel ID
uint8_t slot_id : 3; // TDMA slot index
} MACHeader; // 12 bytes
// ── Beacon Frame (SSB + PDCCH payload) ───────────────────────────────────────
typedef struct __attribute__((packed)) {
MACHeader hdr;
uint32_t hyper_frame_num; // Monotonic hyper-frame counter
uint64_t gnb_clock_us; // gNB reference clock (for sync)
uint8_t num_scheduled; // Number of UEs granted this frame
uint8_t active_mask; // Bitmask: bit i = UE (i+1) connected
DciGrant grants[MAX_NODES]; // UL DCI grants (PDCCH)
} BeaconFrame; // 12 + 4 + 8 + 1 + 1 + 4×4 = 42 bytes
// ── Data Frame (PUSCH — MAC PDU with UCI piggybacked) ────────────────────────
typedef struct __attribute__((packed)) {
MACHeader hdr;
// ── MAC Control Elements (CEs) ─────────────────────────────────────
uint8_t lcg_bsr : 4; // Short BSR: LCG buffer status index
uint8_t cqi : 4; // CQI report (UCI piggybacked on PUSCH)
// ── Application SDU ────────────────────────────────────────────────
float temperature; // DTCH payload: sensor readings
float humidity;
uint16_t battery_mv;
// ── Variable-length payload (TBS - header size) ────────────────────
uint8_t sdu[125]; // Max TBS=125 at MCS7; actual used = mcs_tbs_bytes[mcs]
uint8_t sdu_len; // Actual SDU bytes (= MCS_TBS_BYTES[grant.mcs])
uint8_t retry_count; // Retransmission number (0 = first attempt)
} DataFrame;
// ── HARQ Feedback Frame (PDCCH with HARQ-ACK, TS 38.213 §9) ─────────────────
typedef struct __attribute__((packed)) {
MACHeader hdr;
uint8_t harq_pid : 4; // Which HARQ process this feedback is for
uint8_t ack : 1; // 1 = ACK (PUSCH decoded OK), 0 = NACK
uint8_t rv_next : 2; // Suggested RV for next retransmission
uint8_t _pad : 1;
int8_t rx_rssi; // gNB-measured RSSI (for CQI calibration)
uint8_t new_mcs; // Updated MCS grant for next transmission
uint8_t assigned_slot; // For JOIN_ACK: slot assignment
uint8_t assigned_id; // For JOIN_ACK: node ID
} HarqFeedback; // 12 + 5 = 17 bytes
// ── Scheduling Request Frame (PUCCH format 0 analogue) ───────────────────────
typedef struct __attribute__((packed)) {
MACHeader hdr;
uint8_t lcg_bsr : 4; // Buffer status that triggered SR
uint8_t cqi : 4; // Current CQI measurement
} SRFrame;
// ── Slot Timing Helpers ───────────────────────────────────────────────────────
static inline int64_t slotStartUs(int s) {
return ((int64_t)SIM_BEACON_MS + s * (SIM_SLOT_MS + SIM_GUARD_MS)) * 1000LL;
}
static inline int64_t slotEndUs(int s) {
return slotStartUs(s) + (int64_t)(SIM_SLOT_MS - SIM_GUARD_MS) * 1000LL;
}