Files
libretiny/examples/PinScan/src/digital.cpp
2022-08-03 12:48:50 +02:00

211 lines
4.3 KiB
C++

/* Copyright (c) Kuba Szczodrzyński 2022-07-31. */
#include "pinscan.h"
#define PULL 0
#define WRITE 1
static bool pins[NUM_DIGITAL_PINS] = {};
static bool used[NUM_DIGITAL_PINS] = {};
static bool active = false;
static int pin = -1;
static unsigned long last = 0;
static bool outputMode = PULL;
static void printPin(bool state) {
if (ansi) {
stream->print(state ? (ANSI_RED "HI" ANSI_RESET) : (ANSI_BLUE "LO" ANSI_RESET));
} else {
stream->print(state ? "HI" : "LO");
}
}
static void printState() {
printAnsi(ANSI_TWO_LINES);
printAnsi(ANSI_ERASE_LINE);
for (pin_size_t i = 0; i < NUM_DIGITAL_PINS; i++) {
if (i < 10)
stream->write(' ');
stream->write('D');
stream->print(i);
stream->write(' ');
}
stream->println();
printAnsi(ANSI_ERASE_LINE);
for (pin_size_t i = 0; i < NUM_DIGITAL_PINS; i++) {
stream->write(' ');
if (used[i]) {
printPin(pins[i]);
} else {
stream->print("--");
}
stream->write(' ');
}
stream->println();
}
static void irqHandler(void *ptr) {
bool *pin = (bool *)ptr;
pin_size_t i = pin - pins;
pins[i] = digitalRead(i);
// change interrupt level according to current state
PinStatus status = pins[i] ? FALLING : RISING;
attachInterruptParam(i, irqHandler, status, ptr);
printState();
}
static void digitalAllIrq() {
#if USE_WIFI
LT_I("Disabling logger");
lt_log_disable();
Serial.end();
#endif
for (pin_size_t i = 0; i < NUM_DIGITAL_PINS; i++) {
if (pinSkip[0] == i || pinSkip[1] == i) {
used[i] = false;
continue;
}
pinMode(i, INPUT);
pins[i] = digitalRead(i);
used[i] = true;
// choose interrupt level according to current state
PinStatus status = pins[i] ? FALLING : RISING;
attachInterruptParam(i, irqHandler, status, pins + i);
}
active = true;
}
static void digitalOut(pin_size_t pin, PinStatus state) {
if (outputMode == PULL) {
pinMode(pin, state ? INPUT_PULLUP : INPUT_PULLDOWN);
} else {
pinMode(pin, OUTPUT);
digitalWrite(pin, state);
}
pins[pin] = state;
}
static int digitalAllLow() {
int first = -1;
for (pin_size_t i = 0; i < NUM_DIGITAL_PINS; i++) {
if (pinSkip[0] == i || pinSkip[1] == i) {
used[i] = false;
continue;
}
if (first == -1)
first = i;
digitalOut(i, LOW);
used[i] = true;
}
active = true;
return first;
}
void digitalDetach() {
outputMode = PULL;
if (!active)
return;
for (pin_size_t i = 0; i < NUM_DIGITAL_PINS; i++) {
if (pinSkip[0] == i || pinSkip[1] == i) {
continue;
}
if (used[i])
detachInterrupt(i);
used[i] = false;
pinMode(i, INPUT_PULLDOWN);
}
active = false;
pin = -1;
#if USE_WIFI
lt_log_set_port(LT_UART_DEFAULT_LOGGER);
Serial.begin(115200);
LT_I("Logger enabled");
#endif
}
void runDigital() {
if (mode[1] == '\0')
return;
switch (mode[1]) {
case '?':
printHelp('d');
pin = -1;
break;
case 'p':
outputMode = PULL;
stream->println("Will pull outputs UP/DOWN");
mode[1] = '?';
ansiSkipErase = true;
return;
case 'w':
outputMode = WRITE;
stream->println("Will write LOW/HIGH to outputs");
mode[1] = '?';
ansiSkipErase = true;
return;
case 'r':
if (!active) {
digitalAllIrq();
if (ansi)
printHelp('d');
printAnsi("\n\n"); // reserve two lines for readouts
printState();
}
return;
case 'o':
if (pin == -1) {
pin = inputPin();
pinMode(pin, INPUT);
}
printAnsi(ANSI_LINE_START);
stream->print("Pin D");
stream->print(pin);
stream->print(" state: ");
printPin(digitalRead(pin));
if (!ansi)
stream->println();
return;
case 's':
if (pin == -1) {
// choose the first pin
pin = digitalAllLow();
if (ansi)
printHelp('d');
printAnsi("\n\n"); // reserve two lines for readouts
printState();
}
if (mode[2] == 'n') {
// go to next pin; leave the current as LOW
digitalOut(pin, LOW);
do {
if (++pin >= NUM_DIGITAL_PINS)
pin = 0;
} while (used[pin] == false);
printState();
}
mode[2] = '\0';
// toggle the pin every 500ms
if (millis() - last < 500)
return;
last = millis();
digitalOut(pin, (PinStatus)!pins[pin]);
printState();
return;
case 'h':
case 'l':
pin = inputPin();
digitalOut(pin, mode[1] == 'h' ? HIGH : LOW);
stream->println("OK");
mode[1] = '?';
ansiSkipErase = true;
return;
}
mode[1] = '\0';
}