STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
fake_air.h
Go to the documentation of this file.
1#ifndef STAR_FAKE_AIR_H
2#define STAR_FAKE_AIR_H
3
4// A pretend SX1262 on a virtual clock, for the Idle end-to-end checks.
5// It answers the commands Sx1262Setup (start-up, send) and Ryan's Sx1262
6// (receive) use, the way DS_SX1261-2 Rev 1.2 describes: TxDone after the
7// packet's time on air (6.1.4 p.41), Timeout when the SetTx timer runs out
8// (p.69), RxDone + DIO1 when the ground's packet lands while it listens in
9// continuous RX (SetRx 0xFFFFFF, p.70). Every sent packet is captured with
10// the virtual time it left the antenna.
11
12#include <string.h>
13
14#include "sx1262.h"
15#include "sx1262_setup.h"
16
17namespace radio_link {
18
19class FakeAir : public SpiBus {
20public:
21 struct Sent {
22 uint32_t t_ms;
23 uint8_t len;
24 uint8_t data[255];
25 };
26 static constexpr unsigned kMaxSent = 64;
27
28 explicit FakeAir(uint32_t* now_ms) : now_(now_ms) {
29 memset(buffer_, 0, sizeof buffer_);
30 }
31
32 // Test knobs.
33 bool tx_never_done = false; // TxDone never comes (bad PA, no antenna)
34
35 // What happened.
36 bool listening = false; // in RX: continuous, or a sniff duty cycle
37 bool sniffing = false; // SetRxDutyCycle (0x94) is the RX mode
38 uint16_t irq = 0;
39 unsigned n_sent = 0;
41 unsigned tx_attempts = 0;
42
43 // The ground's packet arrives now. Heard only while listening.
44 bool packet_arrives(const uint8_t* bytes, uint8_t n) {
45 if (!listening)
46 return false;
47 memcpy(buffer_ + kRxBase, bytes, n);
48 rx_len_ = n;
49 irq |= kIrqRxDone;
50 // In sniff mode a packet ends the duty cycle: the chip drops to
51 // STDBY_RC (DS 13.1.7, p.71) and is deaf until SetRxDutyCycle again.
52 // The ground's Arm preamble is assumed long enough to span the sleep
53 // (>= 260 symbols); tests/radio/test_sniff models the windows.
54 if (sniffing)
55 listening = false;
56 return true;
57 }
58 bool dio1() const {
59 return (irq & kDio1Mask) != 0;
60 }
61
62 bool wait_busy() override {
63 return true;
64 }
65
66 void transfer(const uint8_t* tx, uint8_t* rx, uint16_t len) override {
67 memset(rx, 0, len);
68 rx[1] = listening ? 0x54 : 0x24; // RX / STBY_RC, no error (p.95)
69 const uint16_t addr =
70 len >= 3 ? static_cast<uint16_t>(tx[1] << 8 | tx[2]) : 0;
71 switch (tx[0]) {
72 case 0x80: // SetStandby
73 listening = false;
74 break;
75 case 0x82: // SetRx: 0xFFFFFF = continuous
76 listening = tx[1] == 0xFF && tx[2] == 0xFF && tx[3] == 0xFF;
77 sniffing = false;
78 break;
79 case 0x94: // SetRxDutyCycle: listen / sleep on its own (p.71)
80 listening = true;
81 sniffing = true;
82 break;
83 case 0x8C: // SetPacketParams: byte 4 = payload length
84 payload_len_ = tx[4];
85 break;
86 case 0x1D: // ReadRegister
87 rx[4] = addr == 0x08D8 ? 0xC8 : addr == 0x0889 ? 0x01 : 0;
88 break;
89 case 0x0E: // WriteBuffer
90 memcpy(buffer_ + tx[1], tx + 2, len - 2u);
91 break;
92 case 0x83: { // SetTx with timeout steps of 15.625 us
94 const uint32_t steps = static_cast<uint32_t>(tx[1]) << 16 |
95 static_cast<uint32_t>(tx[2]) << 8 |
96 tx[3];
97 tx_start_ = *now_;
98 tx_timeout_ms_ = steps * 15625u / 1000000u;
101 (lora_time_on_air_us(cfg, payload_len_) + 999u) / 1000u;
102 transmitting_ = true;
103 listening = false;
104 break;
105 }
106 case 0x12: // GetIrqStatus
107 if (transmitting_) {
108 const uint32_t dt = *now_ - tx_start_;
109 if (!tx_never_done && dt >= tx_done_ms_) {
110 transmitting_ = false;
111 irq |= 1u << 0; // TxDone
112 if (n_sent < kMaxSent) {
113 Sent& s = sent[n_sent++];
114 s.t_ms = tx_start_;
115 s.len = payload_len_;
116 memcpy(s.data, buffer_, payload_len_);
117 }
118 } else if (dt >= tx_timeout_ms_) {
119 transmitting_ = false;
120 irq |= 1u << 9; // Timeout
121 }
122 }
123 rx[2] = static_cast<uint8_t>(irq >> 8);
124 rx[3] = static_cast<uint8_t>(irq);
125 break;
126 case 0x02: // ClearIrqStatus
127 irq = static_cast<uint16_t>(irq & ~(tx[1] << 8 | tx[2]));
128 break;
129 case 0x13: // GetRxBufferStatus
130 rx[2] = rx_len_;
131 rx[3] = kRxBase;
132 break;
133 case 0x1E: // ReadBuffer: RFU, status, status, data
134 for (unsigned i = 3; i < len; ++i)
135 rx[i] = buffer_[(tx[1] + i - 3) & 0xFF];
136 break;
137 default:
138 break;
139 }
140 }
141
142private:
143 static constexpr uint8_t kRxBase = 0x80; // anywhere but the TX bytes
144 static constexpr uint16_t kDio1Mask = 0x0263;
145 uint32_t* now_;
146 uint8_t buffer_[256];
147 uint8_t payload_len_ = 0, rx_len_ = 0;
148 bool transmitting_ = false;
149 uint32_t tx_start_ = 0, tx_done_ms_ = 0, tx_timeout_ms_ = 0;
150};
151
152} // namespace radio_link
153
154#endif // STAR_FAKE_AIR_H
*brief user defined string literal for JSON values *sa std::size_t n
Definition json.hpp:24474