STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
sense_p.cpp
Go to the documentation of this file.
1// #include <ADS126X.h>
2// #include <SPI.h>
3// #include <Arduino.h>
4// #include "board_pins.h"
5// #include "adcs.h"
6
7// #include "freertos/FreeRTOS.h"
8// #include "freertos/stream_buffer.h"
9
10// // 1 = ASCII voltages for the Python calibration script
11// // 0 = binary sweep packets
12// #define TEXT_OUTPUT 0
13// #define PT_NUM_START 0
14// #define NUM_PTS 10
15
16// static inline void flushPacketIfNeeded(bool force);
17// static void sendSweepIfNeeded(const adcs::AllResults& sweep);
18
19// // Sentinals
20
21// static constexpr uint8_t PAD_CH = 0xFF; // "no channel"
22// static constexpr int32_t SENT_I32 = INT32_MIN; // "missing" for signed 32
23// static constexpr uint32_t SENT_U32 = 0xFFFFFFFFu; // "missing" for unsigned
24// 32
25
26// // --- Buffer settings ---
27// static const size_t PKT_MAX = 1024; // packet size in bytes
28
29// static uint8_t pktA[PKT_MAX];
30// static uint8_t pktB[PKT_MAX];
31// static uint8_t* active = pktA;
32// static uint8_t* standby = pktB;
33
34// static const uint32_t FLUSH_MS = 10; // flush every ~10 ms
35// static size_t used = 0;
36// static uint32_t lastFlushMs = 0;
37
38// // ===== Sweep packet format =====
39// // Little endian
40
41// #pragma pack(push,1)
42// struct PacketHeader {
43// char magic[4]; // "AD26"
44// uint8_t version; // 2 (new format)
45// uint8_t flags; // bit0 = per-record t_us present
46// uint16_t count; // number of records in this sweep
47// uint16_t failures; // from readAll
48// uint32_t total_time_us; // total sweep time
49// uint32_t packet_time_us; // FULL micros() when this packet is sent
50// };
51
52// struct Rec18 {
53// uint8_t ch; // channel id
54// uint8_t ok; // 0 or 1
55// int32_t raw;
56// int32_t sample_time; // ADC code
57// uint32_t read_time_dur; // per read()
58// uint32_t conv_time_dur; // wait for DRDY
59// };
60// #pragma pack(pop)
61
62// // ===== CRC32 (poly 0xEDB88320, init 0xFFFFFFFF, final XOR 0xFFFFFFFF) =====
63// static uint32_t crc32_le(const uint8_t* data, size_t len) {
64// uint32_t crc = 0xFFFFFFFFu;
65// for (size_t i = 0; i < len; ++i) {
66// crc ^= data[i];
67// for (int k = 0; k < 8; ++k) {
68// uint32_t mask = -(crc & 1u);
69// crc = (crc >> 1) ^ (0xEDB88320u & mask);
70
71// }
72// }
73
74// return crc ^ 0xFFFFFFFFu;
75// }
76
77// static void sendSweepPacket(const adcs::AllResults& sweep) {
78// uint32_t packet_time = micros();
79
80// const size_t header_sz = sizeof(PacketHeader);
81// const size_t rec_sz = sizeof(Rec18);
82// const size_t n_fixed = 10;
83// const size_t payload_no_crc = header_sz + n_fixed * rec_sz;
84// const size_t total_len = payload_no_crc + sizeof(uint32_t);
85
86// if (total_len > PKT_MAX) {
87// // With n_fixed=10 this should not happen.
88// return;
89// }
90
91// // Build packet into the small scratch buffer (reuse your existing
92// “active”) uint8_t* buf = standby; // use standby as a scratch area so we
93// don't disturb "active" size_t off = 0;
94
95// PacketHeader h;
96// memcpy(h.magic, "AD26", 4);
97// h.version = 2;
98// h.flags = 0x01;
99// h.count = n_fixed;
100// h.failures = sweep.failures + static_cast<uint16_t>((n_fixed >
101// sweep.count) ? (n_fixed - sweep.count) : 0); h.total_time_us =
102// sweep.total_time; h.packet_time_us = packet_time; memcpy(buf + off, &h,
103// sizeof(h)); off += sizeof(h);
104
105// const size_t n_real = (sweep.count <= n_fixed) ? sweep.count : n_fixed;
106// for (size_t i = 0; i < n_real; ++i) {
107// const auto& s = sweep.samples[i];
108// Rec18 r;
109// r.ch = s.channel;
110// r.ok = s.result.ok ? 1u : 0u;
111// r.raw = s.result.raw;
112// r.sample_time = s.result.sample_time;
113// r.read_time_dur = s.result.read_time_dur;
114// r.conv_time_dur = s.result.conv_time_dur;
115// memcpy(buf + off, &r, sizeof(r)); off += sizeof(r);
116// }
117
118// for (size_t i = n_real; i < n_fixed; ++i) {
119// Rec18 r;
120// r.ch = PAD_CH;
121// r.ok = 0;
122// r.raw = SENT_I32;
123// r.sample_time = SENT_I32;
124// r.read_time_dur = SENT_U32;
125// r.conv_time_dur = SENT_U32;
126// memcpy(buf + off, &r, sizeof(r)); off += sizeof(r);
127// }
128
129// const uint32_t crc = crc32_le(buf, off);
130// memcpy(buf + off, &crc, sizeof(crc)); off += sizeof(crc);
131
132// // Append the completed sweep packet into the large outgoing buffer.
133// // If it won’t fit, flush first, then append.
134// if (used + off > PKT_MAX) {
135// flushPacketIfNeeded(true);
136// }
137// memcpy(active + used, buf, off);
138// used += off;
139
140// // Do not Serial.write here. Let the timed flush handle it.
141// }
142
143// void setup() {
144// Serial.begin(230400);
145// SPI.begin(SCLK, MISOp, MOSIp, CS);
146
147// if (!adcs::init()) { while (1) { delay(1000); } }
148// if (!adcs::configure()){ while (1) { delay(1000); } }
149// }
150
151// void loop() {
152// // One sweep
153// adcs::AllResults sweep = adcs::readAll(channels, num_channels);
154
155// if (TEXT_OUTPUT) {
156// // ASCII volts for calibration scripts
157// for (size_t i = 0; i < sweep.count; ++i) {
158// const auto& s = sweep.samples[i];
159// float volts = (float)s.result.raw * vRef / adcScale;
160// Serial.print(volts, 6);
161// if (i + 1 < sweep.count) Serial.print(' ');
162// }
163// Serial.print("\r\n");
164// } else {
165// sendSweepPacket(sweep);
166// flushPacketIfNeeded(false); // flush by time
167// }
168// }
169
170// static inline void flushPacketIfNeeded(bool force = false) {
171// uint32_t now = millis();
172// if (force || (used > 0 && (now - lastFlushMs >= FLUSH_MS))) {
173// Serial.write(active, used);
174// // optional delimiter: Serial.println();
175// uint8_t* tmp = active; active = standby; standby = tmp;
176// used = 0;
177// lastFlushMs = now;
178// }
179// }