Files
wadamesh/variants/wio_tracker_l2/WioTrackerL2Io.cpp
T
2026-09-03 12:52:03 -04:00

170 lines
5.0 KiB
C++

// SPDX-License-Identifier: GPL-3.0-or-later
#include "WioTrackerL2Io.h"
#include <Arduino.h>
#include <Wire.h>
namespace {
constexpr uint8_t kAddress = 0x21;
constexpr uint8_t kRegInput0 = 0x00;
constexpr uint8_t kRegOutput0 = 0x02;
constexpr uint8_t kRegConfig0 = 0x06;
constexpr uint8_t kWakeButton = 0;
constexpr uint8_t kI2cInterrupt = 1;
constexpr uint8_t kSdDetect = 2;
constexpr uint8_t kTouchInterrupt = 3;
constexpr uint8_t kLcdControl = 4;
constexpr uint8_t kLcdPower = 5;
constexpr uint8_t kLcdReset = 6;
constexpr uint8_t kGrovePower = 7;
constexpr uint8_t kTouchReset = 8;
constexpr uint8_t kGnssReset = 9;
constexpr uint8_t kUserLed = 10;
constexpr uint8_t kUsbOtg = 11;
constexpr uint8_t kAudioPa = 12;
constexpr uint8_t kGnssPower = 13;
constexpr uint8_t kSdPower = 14;
constexpr uint8_t kBatterySense = 15;
uint8_t s_output[2] = {0xFF, 0xFF};
uint8_t s_config[2] = {0xFF, 0xFF};
bool s_ready = false;
bool readRegisters(uint8_t reg, uint8_t* data, size_t length) {
Wire.beginTransmission(kAddress);
Wire.write(reg);
if (Wire.endTransmission(false) != 0) return false;
if (Wire.requestFrom((int)kAddress, (int)length) != length) return false;
for (size_t i = 0; i < length; ++i) data[i] = (uint8_t)Wire.read();
return true;
}
bool writeRegisters(uint8_t reg, const uint8_t* data, size_t length) {
Wire.beginTransmission(kAddress);
Wire.write(reg);
for (size_t i = 0; i < length; ++i) Wire.write(data[i]);
return Wire.endTransmission() == 0;
}
void stageInput(uint8_t bit) {
s_config[bit >> 3] |= (uint8_t)(1U << (bit & 7));
}
void stageOutput(uint8_t bit, bool high) {
const uint8_t mask = (uint8_t)(1U << (bit & 7));
uint8_t& output = s_output[bit >> 3];
uint8_t& config = s_config[bit >> 3];
if (high) output |= mask;
else output &= (uint8_t)~mask;
config &= (uint8_t)~mask;
}
bool writeState() {
// Latch output levels before exposing pins as outputs.
return writeRegisters(kRegOutput0, s_output, sizeof(s_output)) &&
writeRegisters(kRegConfig0, s_config, sizeof(s_config));
}
bool setOutput(uint8_t bit, bool high) {
if (!s_ready) return false;
const uint8_t output0 = s_output[0], output1 = s_output[1];
const uint8_t config0 = s_config[0], config1 = s_config[1];
stageOutput(bit, high);
if (writeState()) return true;
s_output[0] = output0; s_output[1] = output1;
s_config[0] = config0; s_config[1] = config1;
return false;
}
bool readInputBit(uint8_t bit, bool& high) {
uint8_t inputs[2] = {0xFF, 0xFF};
if (!s_ready || !readRegisters(kRegInput0, inputs, sizeof(inputs))) return false;
high = (inputs[bit >> 3] & (uint8_t)(1U << (bit & 7))) != 0;
return true;
}
} // namespace
namespace WioTrackerL2Io {
bool begin() {
s_ready = false;
Wire.setClock(100000);
Wire.setTimeOut(30);
pinMode(45, INPUT_PULLUP);
if (!readRegisters(kRegOutput0, s_output, sizeof(s_output)) ||
!readRegisters(kRegConfig0, s_config, sizeof(s_config))) {
Serial.println("[wio-l2] expander probe failed");
return false;
}
stageInput(kWakeButton);
stageInput(kI2cInterrupt);
stageInput(kSdDetect);
stageInput(kLcdControl);
stageOutput(kTouchInterrupt, false);
stageOutput(kLcdPower, true);
stageOutput(kLcdReset, true);
stageOutput(kGrovePower, false);
stageOutput(kTouchReset, false);
stageOutput(kGnssReset, true);
stageOutput(kUserLed, false);
stageOutput(kUsbOtg, false);
stageOutput(kAudioPa, false);
stageOutput(kGnssPower, true);
stageOutput(kSdPower, false);
stageOutput(kBatterySense, false);
if (!writeState()) return false;
delay(10);
stageOutput(kGnssReset, false);
if (!writeState()) return false;
delay(40);
stageOutput(kLcdReset, false);
if (!writeState()) return false;
delay(10);
stageOutput(kLcdReset, true);
if (!writeState()) return false;
delay(500);
stageOutput(kLcdControl, true);
if (!writeState()) return false;
delay(10);
stageOutput(kTouchReset, true);
if (!writeState()) return false;
delay(60);
s_ready = true;
Serial.printf("[wio-l2] expander ready out=%02X/%02X cfg=%02X/%02X\n",
s_output[0], s_output[1], s_config[0], s_config[1]);
return true;
}
bool ready() { return s_ready; }
bool readWakeButton(bool& pressed) {
bool high = true;
if (!readInputBit(kWakeButton, high)) return false;
pressed = !high;
return true;
}
bool readSdPresent(bool& present) {
bool high = true;
if (!readInputBit(kSdDetect, high)) return false;
present = !high;
return true;
}
bool setLcdPower(bool enabled) { return setOutput(kLcdPower, enabled); }
bool setLcdResetReleased(bool released) { return setOutput(kLcdReset, released); }
bool setTouchResetReleased(bool released) { return setOutput(kTouchReset, released); }
bool setGnssPower(bool enabled) { return setOutput(kGnssPower, enabled); }
bool setGnssResetReleased(bool released) { return setOutput(kGnssReset, !released); }
bool setSdPower(bool enabled) { return setOutput(kSdPower, enabled); }
bool setBatterySense(bool enabled) { return setOutput(kBatterySense, enabled); }
bool setAudioPaPower(bool enabled) { return setOutput(kAudioPa, enabled); }
} // namespace WioTrackerL2Io