src/NW_Device.h
The NW-Device-Specification Schema 1 device protocol over I2C.
Classes
| Name | |
|---|---|
| class | NW_Device One NW Schema 1 device on the I2C bus: identity gates, the reading handshake, batches, faults. |
Defines
| Name | |
|---|---|
| NW_REG_SCHEMA 0x01 = Schema 1 |
|
| NW_REG_NAME 7-byte device name, null-padded (0x01-0x07) |
|
| NW_REG_HW_MAJOR | |
| NW_REG_HW_MINOR | |
| NW_REG_FW_PATCH written by the firmware |
|
| NW_REG_I2C_ADDR writable; takes effect at the device’s next boot |
|
| NW_REG_CAL Page 1: calibration, stored; device-specific (0x20-0x3F) |
|
| NW_REG_STATUS bit 0 ready; bits 1-6 chip faults; bit 7 pan-fault |
|
| NW_REG_CTRL writable: bit 0 trigger; bits 1-6 chip select; bit 7 sleep |
|
| NW_REG_COUNTER reading counter, uint16 little-endian (0x42-0x43) |
|
| NW_REG_REQUEST readings requested (batch size), uint16 little-endian, writable (0x44-0x45) |
|
| NW_REG_CONFIG writable, device-specific, volatile |
|
| NW_REG_REPORT report code; cleared by any Control write |
|
| NW_REG_DATA first device data byte |
|
| NW_BIT_READY | |
| NW_BIT_PANFAULT | |
| NW_CTRL_TRIGGER | |
| NW_CTRL_SLEEP | |
| NW_WIRE_CHUNK the AVR Wire buffer; longer reads are split into transactions of this size |
|
| NW_DATA_RETRIES readData() re-reads at most this many times when the counter moved during a read |
Macros Documentation
define NW_REG_SCHEMA
#define NW_REG_SCHEMA 0x00
0x01 = Schema 1
define NW_REG_NAME
#define NW_REG_NAME 0x01
7-byte device name, null-padded (0x01-0x07)
define NW_REG_HW_MAJOR
#define NW_REG_HW_MAJOR 0x08
define NW_REG_HW_MINOR
#define NW_REG_HW_MINOR 0x09
define NW_REG_FW_PATCH
#define NW_REG_FW_PATCH 0x0A
written by the firmware
define NW_REG_I2C_ADDR
#define NW_REG_I2C_ADDR 0x1F
writable; takes effect at the device’s next boot
define NW_REG_CAL
#define NW_REG_CAL 0x20
Page 1: calibration, stored; device-specific (0x20-0x3F)
define NW_REG_STATUS
#define NW_REG_STATUS 0x40
bit 0 ready; bits 1-6 chip faults; bit 7 pan-fault
define NW_REG_CTRL
#define NW_REG_CTRL 0x41
writable: bit 0 trigger; bits 1-6 chip select; bit 7 sleep
define NW_REG_COUNTER
#define NW_REG_COUNTER 0x42
reading counter, uint16 little-endian (0x42-0x43)
define NW_REG_REQUEST
#define NW_REG_REQUEST 0x44
readings requested (batch size), uint16 little-endian, writable (0x44-0x45)
define NW_REG_CONFIG
#define NW_REG_CONFIG 0x46
writable, device-specific, volatile
define NW_REG_REPORT
#define NW_REG_REPORT 0x47
report code; cleared by any Control write
define NW_REG_DATA
#define NW_REG_DATA 0x48
first device data byte
define NW_BIT_READY
#define NW_BIT_READY 0x01
define NW_BIT_PANFAULT
#define NW_BIT_PANFAULT 0x80
define NW_CTRL_TRIGGER
#define NW_CTRL_TRIGGER 0x01
define NW_CTRL_SLEEP
#define NW_CTRL_SLEEP 0x80
define NW_WIRE_CHUNK
#define NW_WIRE_CHUNK 32
the AVR Wire buffer; longer reads are split into transactions of this size
define NW_DATA_RETRIES
#define NW_DATA_RETRIES 2
readData() re-reads at most this many times when the counter moved during a read
Source code
#ifndef NW_Device_h
#define NW_Device_h
#include <Arduino.h>
#include <Wire.h>
#include "NW_Report.h"
// Page 0 (identity, served from EEPROM) and Page 2 Block 0 (status and control),
// as NW-Device-Specification defines them for every device.
#define NW_REG_SCHEMA 0x00
#define NW_REG_NAME 0x01
#define NW_REG_HW_MAJOR 0x08
#define NW_REG_HW_MINOR 0x09
#define NW_REG_FW_PATCH 0x0A
#define NW_REG_I2C_ADDR 0x1F
#define NW_REG_CAL 0x20
#define NW_REG_STATUS 0x40
#define NW_REG_CTRL 0x41
#define NW_REG_COUNTER 0x42
#define NW_REG_REQUEST 0x44
#define NW_REG_CONFIG 0x46
#define NW_REG_REPORT 0x47
#define NW_REG_DATA 0x48
#define NW_BIT_READY 0x01
#define NW_BIT_PANFAULT 0x80
#define NW_CTRL_TRIGGER 0x01
#define NW_CTRL_SLEEP 0x80
#define NW_WIRE_CHUNK 32
#define NW_DATA_RETRIES 2
class NW_Device {
public:
bool begin(uint8_t address, const char* name, uint8_t minPatch, unsigned long bootTimeoutMs = 0);
String beginFailure() const;
uint8_t address() const { return _adr; }
uint8_t hardwareMajor() const { return _hwMajor; }
uint8_t hardwareMinor() const { return _hwMinor; }
uint8_t firmwareVersion() const { return _fwPatch; }
bool setI2CAddress(uint8_t newAddress);
size_t printSnapshot(Print& out, const char* const* chipNames, uint8_t nChips, bool boot = false,
const char* lib = "", const char* libCommit = "");
void setTimeout(unsigned long ms) { _timeout = ms; }
unsigned long timeout() const { return _timeout; }
// --- Handshake ---
bool ready();
uint16_t readCounter();
bool newReading();
bool requestReading(uint8_t chips);
bool waitReading();
bool captureReading();
bool takeReading(uint8_t chips);
// --- Batches (NW-Device-Specification 0x24-0x25) ---
bool writeBatch(uint16_t n);
void resetBatch() { _absentChips = 0; }
bool beginBatch(uint16_t n) { if (n > 1) return writeBatch(n); resetBatch(); return true; }
template <typename F>
uint16_t takeReadings(uint8_t chips, uint16_t n, F readOne) {
beginBatch(n);
uint16_t taken = 0;
for (uint16_t i = 0; i < n; i++) {
if (readOne()) taken++;
else if (batchFaulted(chips)) break;
}
return taken;
}
bool batchFaulted(uint8_t chips = 0x3F) const { return (_absentChips & chips) != 0; }
// --- Reports (the Report register, latched) and faults (status bits, live) ---
const NW_Report& report() const { return _report; }
bool faulted(uint8_t chip) const { return _report.chipFaulted(chip); }
bool anyFault() const { return _report.any(); }
uint8_t reportChip() const { return _report.chip(); }
uint8_t reportKind() const { return _report.kind(); }
// --- Registers ---
bool readBytes(uint8_t reg, uint8_t* buf, uint8_t n);
bool readData(uint8_t reg, uint8_t* buf, uint8_t n);
bool dataMoved() const { return _dataMoved; }
const NW_Report& bootReport() const { return _bootReport; }
void clearBootReport() { _bootReport.code = 0; _bootReport.status = 0; }
bool writeByte(uint8_t reg, uint8_t value);
uint8_t readConfig();
bool writeConfig(uint8_t value) { return writeByte(NW_REG_CONFIG, value); }
bool sleep() { return writeByte(NW_REG_CTRL, NW_CTRL_SLEEP); }
private:
uint8_t _adr = 0;
uint8_t _hwMajor = 0, _hwMinor = 0, _fwPatch = 0;
uint8_t _beginFailure = 0; // 0 none, 1 no ACK, 2 read failed, 3 schema, 4 name, 5 firmware
unsigned long _timeout = 500;
uint16_t _lastCounter = 0xFFFF; // counter of the last captured reading
uint16_t _counterBefore = 0xFFFF; // counter seen at the last request
uint8_t _chips = 0; // chips selected at the last request
uint8_t _absentChips = 0; // chips that reported absent since the last writeBatch()/resetBatch()
bool _dataMoved = false; // readData() exhausted its retries
NW_Report _report;
NW_Report _bootReport; // what begin() captured, until the logger clears it
};
#endif
Updated on 2026-09-29 at 05:58:59 +0000