Skip to content

Commit f837f41

Browse files
Overhaul the pin handling (not backwards compatible)
This makes a number of changes: - Split INPUT mode into INPUT_DIGITAL and INPUT_ANALOG. This allows using analog pins as digital pins as well. It requires explicitely choosing either of these modes, except when using pin.makeinput, which autoselects based on the pin type. - Rename and renumber the pin mode constants. This makes things a bit more consistent and by removing the negative values we allow using the upper bits of the mode as flags or other values. - Generalize the "pin mode" value into a "pin config" value, which contains the pin mode, combined with other values. Right now, this is only a flag for wether the pullup is enabled (which was previously part of the mode), but in the future flags like "reports enabled" or values like the analog reference to use can be included. This removes the pin.setmode command and replaces it with pin.config, which works similar. It accepts the following modes: disabled, disconnected, input_digital, input_analog, output_digital, output_pwm. Additionally, the value flag_pullup can be added to the input modes to enable pullups (defaulting to disabled). e.g.: pin.config("d8", output_digital) pin.config("a0", input_digital + flag_pullup) - When setting a pin to output_digital, it now gets written to LOW by default. Previously, the value would be unchanged, which meant that if the pullup was previously enabled, it would be HIGH, otherwise it would be LOW. When using pin.config, the value can be overridden (which is useful if you must go from input-with-pullup to output-high without going through output-low for some reason). - pin.makeinput no longer takes input or input_pullup as the second argument, but instead expects a 0 or 1 value to disable/enable pullups. Leaving it out makes the default depend on the pin type (see next item). - When setting an analog pin to input using pin.makeinput, it no longer defaults to having the pullup enabled. Since the pullup is connected to 3.3V, that's too high for the ADC, and if the voltage sensed comes from a voltage divider, having the pullup enabled will even influence the values read. - PinConfig and Mode values are now wrapped in structs, so you can do things like config.mode().input() to see if an input mode was selected. The constants for them are no also in their own scope, so you write things like PinConfig::Mode::DISCONNECTED, which is more clear than before. It seems like this would be a good usecase to use C++11 enum classes to add scoping and type safety, but you cannot add methods to enum classes. So this uses a struct with methods and an old-style enum, which fixes the scoping but is a bit less typesafe. This struct-wrapping does not add any storage overhead and minimal to no code size overhead. This does not properly update the reports yet. They are somewhat updated, but analog pins still only generate analog reports now and the pin modes are replaced by the new pin configs directly, which have different values. There should probably be a single mode report and a single value report, instead of splitting through analog and digital, but that's for a later commit.
1 parent 760c94f commit f837f41

File tree

3 files changed

+247
-172
lines changed

3 files changed

+247
-172
lines changed

src/Scout.cpp

Lines changed: 101 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -320,9 +320,9 @@ void PinoccioScout::saveState() {
320320
for (int i=0; i<NUM_DIGITAL_PINS; i++) {
321321
PinState *state = &pinStates[i];
322322
if (isPinReserved(i)) {
323-
state->mode = PINMODE_RESERVED;
323+
state->config = PinConfig::Mode::RESERVED;
324324
} else {
325-
state->mode = PINMODE_UNSET;
325+
state->config = PinConfig::Mode::UNSET;
326326
}
327327
}
328328

@@ -347,61 +347,77 @@ int8_t PinoccioScout::getRegisterPinMode(uint8_t pin) {
347347
}
348348
}
349349

350-
int8_t PinoccioScout::getPinMode(uint8_t pin) {
350+
PinConfig PinoccioScout::getPinConfig(uint8_t pin) {
351351
if (pin < NUM_DIGITAL_PINS)
352-
return pinStates[pin].mode;
353-
return PINMODE_UNSET;
352+
return pinStates[pin].config;
353+
return PinConfig::Mode::UNSET;
354354
}
355355

356356
void PinoccioScout::makeUnsetDisconnected() {
357357
for (int i=0; i<NUM_DIGITAL_PINS; i++) {
358-
if (getPinMode(i) == PINMODE_UNSET)
359-
setMode(i, PINMODE_DISCONNECTED);
358+
if (getPinConfig(i).mode() == PinConfig::Mode::UNSET)
359+
setPinConfig(i, PinConfig::Mode::DISCONNECTED);
360360
}
361361
}
362362

363-
bool PinoccioScout::setMode(uint8_t pin, int8_t mode) {
364-
if (isPinReserved(pin)) {
363+
bool PinoccioScout::setPinConfig(uint8_t pin, PinConfig config, uint8_t outvalue) {
364+
// Cannot change pins marked as reserved
365+
if (getPinConfig(pin).mode() == PinConfig::Mode::RESERVED)
366+
return false;
367+
368+
// Pullup flag is only valid for input modes
369+
if ((config & PinConfig::Flag::PULLUP)
370+
&& config.mode() != PinConfig::Mode::INPUT_DIGITAL
371+
&& config.mode() != PinConfig::Mode::INPUT_ANALOG)
372+
return false;
373+
374+
if (config.mode() == PinConfig::Mode::OUTPUT_PWM && !digitalPinHasPWM(pin))
365375
return false;
366-
}
367376

368-
// pre-set initial values for mode change
369-
int value;
370-
switch (mode) {
371-
case PINMODE_DISABLED:
372-
case PINMODE_INPUT:
377+
if (config.mode() == PinConfig::Mode::INPUT_ANALOG && !isAnalogPin(pin))
378+
return false;
379+
380+
uint16_t value;
381+
switch(config.mode()) {
382+
case PinConfig::Mode::INPUT_DIGITAL:
373383
pinMode(pin, INPUT);
384+
// Writing non-zero to an input pin enables the pullup
385+
digitalWrite(pin, config & PinConfig::Flag::PULLUP);
386+
value = digitalRead(pin);
374387
break;
375-
// On disconnected (floating) pins, enable a pullup. Without the
376-
// pullup, the input logic might switch between high and low all the
377-
// time, causing excessive power usage.
378-
case PINMODE_DISCONNECTED:
379-
case PINMODE_INPUT_PULLUP:
380-
pinMode(pin, INPUT_PULLUP);
388+
case PinConfig::Mode::INPUT_ANALOG:
389+
pinMode(pin, INPUT);
390+
// Writing non-zero to an input pin enables the pullup
391+
digitalWrite(pin, config & PinConfig::Flag::PULLUP);
392+
value = analogRead(pin);
381393
break;
382-
case PINMODE_OUTPUT:
383-
case PINMODE_PWM:
394+
case PinConfig::Mode::OUTPUT_DIGITAL:
395+
value = outvalue;
384396
pinMode(pin, OUTPUT);
397+
digitalWrite(pin, outvalue);
385398
break;
386-
default:
387-
return false;
388-
}
389-
390-
switch(mode) {
391-
case PINMODE_DISABLED:
399+
case PinConfig::Mode::OUTPUT_PWM:
400+
value = outvalue;
401+
pinMode(pin, OUTPUT);
402+
analogWrite(pin, value);
403+
case PinConfig::Mode::DISABLED:
404+
// INPUT is effectively high-impedance
392405
value = 0;
406+
pinMode(pin, INPUT);
393407
break;
394-
case PINMODE_PWM:
408+
case PinConfig::Mode::DISCONNECTED:
409+
// On disconnected (floating) pins, enable a pullup. Without the
410+
// pullup, the input logic might switch between high and low all
411+
// the time, causing excessive power usage.
395412
value = 0;
413+
pinMode(pin, INPUT_PULLUP);
396414
break;
397-
case PINMODE_INPUT:
398-
case PINMODE_OUTPUT:
399-
case PINMODE_INPUT_PULLUP:
400-
value = pinRead(pin);
401-
break;
415+
case PinConfig::Mode::UNSET:
416+
default:
417+
return false;
402418
}
403419

404-
updatePinState(pin, value, mode);
420+
updatePinState(pin, value, config);
405421

406422
return true;
407423
}
@@ -418,44 +434,41 @@ bool PinoccioScout::isPWMPin(uint8_t pin) {
418434
return digitalPinHasPWM(pin);
419435
}
420436

421-
bool PinoccioScout::isInputPin(uint8_t pin) {
422-
return (getPinMode(pin) == PINMODE_INPUT || getPinMode(pin) == PINMODE_INPUT_PULLUP) ? true : false;
423-
}
437+
bool PinoccioScout::pinWrite(uint8_t pin, uint8_t value) {
438+
PinConfig config = getPinConfig(pin);
439+
switch(config.mode()) {
440+
case PinConfig::Mode::OUTPUT_DIGITAL:
441+
digitalWrite(pin, value);
442+
break;
424443

425-
bool PinoccioScout::isOutputPin(uint8_t pin) {
426-
return (getPinMode(pin) == PINMODE_OUTPUT || getPinMode(pin) == PINMODE_PWM) ? true : false;
427-
}
444+
case PinConfig::Mode::OUTPUT_PWM:
445+
analogWrite(pin, value);
446+
break;
428447

429-
bool PinoccioScout::pinWrite(uint8_t pin, uint8_t value) {
430-
if (isPinReserved(pin) || !isOutputPin(pin)) {
431-
return false;
448+
default:
449+
return false;
432450
}
433451

434-
if (getPinMode(pin) == PINMODE_PWM)
435-
analogWrite(pin, value);
436-
else
437-
digitalWrite(pin, value);
438-
439-
updatePinState(pin, value, getPinMode(pin));
452+
updatePinState(pin, value, config);
440453

441454
return true;
442455
}
443456

444457
uint16_t PinoccioScout::pinRead(uint8_t pin) {
445-
switch(getPinMode(pin)) {
446-
case PINMODE_PWM:
447-
return pinStates[pin].value;
458+
PinConfig config = getPinConfig(pin);
459+
switch(config.mode()) {
460+
case PinConfig::Mode::INPUT_ANALOG:
461+
return analogRead(pin - A0);
448462

449-
case PINMODE_INPUT:
450-
case PINMODE_INPUT_PULLUP:
451-
if (isAnalogPin(pin))
452-
return analogRead(pin - A0);
453-
else
454-
return digitalRead(pin);
463+
case PinConfig::Mode::INPUT_DIGITAL:
464+
return digitalRead(pin);
455465

456-
case PINMODE_OUTPUT:
466+
case PinConfig::Mode::OUTPUT_DIGITAL:
457467
return digitalRead(pin);
458468

469+
case PinConfig::Mode::OUTPUT_PWM:
470+
return pinStates[pin].value;
471+
459472
default:
460473
return 0;
461474
}
@@ -477,24 +490,24 @@ const __FlashStringHelper* PinoccioScout::getNameForPin(uint8_t pin) {
477490
return NULL;
478491
}
479492

480-
const __FlashStringHelper* PinoccioScout::getNameForPinMode(int8_t mode) {
493+
const __FlashStringHelper* PinoccioScout::getNameForPinMode(PinConfig::Mode mode) {
481494
switch(mode) {
482-
case (PINMODE_DISCONNECTED):
495+
case (PinConfig::Mode::DISCONNECTED):
483496
return F("disconnected");
484-
case (PINMODE_UNSET):
497+
case (PinConfig::Mode::UNSET):
485498
return F("unset");
486-
case (PINMODE_RESERVED):
487-
return F("reserved");
488-
case (PINMODE_DISABLED):
499+
case (PinConfig::Mode::DISABLED):
489500
return F("disabled");
490-
case (PINMODE_INPUT):
491-
return F("input");
492-
case (PINMODE_OUTPUT):
493-
return F("output");
494-
case (PINMODE_INPUT_PULLUP):
495-
return F("input_pullup");
496-
case (PINMODE_PWM):
497-
return F("pwm");
501+
case (PinConfig::Mode::RESERVED):
502+
return F("reserved");
503+
case (PinConfig::Mode::INPUT_DIGITAL):
504+
return F("input_digital");
505+
case (PinConfig::Mode::INPUT_ANALOG):
506+
return F("input_analog");
507+
case (PinConfig::Mode::OUTPUT_DIGITAL):
508+
return F("output_digital");
509+
case (PinConfig::Mode::OUTPUT_PWM):
510+
return F("output_pwm");
498511
default:
499512
return NULL;
500513
}
@@ -523,11 +536,11 @@ bool PinoccioScout::isPinReserved(uint8_t pin) {
523536
}
524537
}
525538

526-
bool PinoccioScout::updatePinState(uint8_t pin, int16_t val, int8_t mode) {
539+
bool PinoccioScout::updatePinState(uint8_t pin, int16_t val, PinConfig config) {
527540
PinState *state = &pinStates[pin];
528-
if (state->value != val || state->mode != mode) {
541+
if (state->value != val || state->config != config) {
529542
state->value = val;
530-
state->mode = mode;
543+
state->config = config;
531544

532545
if (isDigitalPin(pin) && digitalPinEventHandler != 0) {
533546
if (eventVerboseOutput) {
@@ -536,10 +549,10 @@ bool PinoccioScout::updatePinState(uint8_t pin, int16_t val, int8_t mode) {
536549
Serial.print(F(","));
537550
Serial.print(val);
538551
Serial.print(F(","));
539-
Serial.print(mode);
552+
Serial.print(config);
540553
Serial.println(F(")"));
541554
}
542-
digitalPinEventHandler(pin, val, mode);
555+
digitalPinEventHandler(pin, val, config);
543556
}
544557

545558
if (isAnalogPin(pin) && analogPinEventHandler != 0) {
@@ -549,10 +562,10 @@ bool PinoccioScout::updatePinState(uint8_t pin, int16_t val, int8_t mode) {
549562
Serial.print(F(","));
550563
Serial.print(val);
551564
Serial.print(F(","));
552-
Serial.print(mode);
565+
Serial.print(config);
553566
Serial.println(F(")"));
554567
}
555-
analogPinEventHandler(pin - A0, val, mode);
568+
analogPinEventHandler(pin - A0, val, config);
556569
}
557570

558571
return true;
@@ -563,10 +576,10 @@ bool PinoccioScout::updatePinState(uint8_t pin, int16_t val, int8_t mode) {
563576
static void scoutDigitalStateChangeTimerHandler(SYS_Timer_t *timer) {
564577
if (Scout.digitalPinEventHandler != 0) {
565578
for (int i=2; i<9; i++) {
566-
int mode = Scout.getPinMode(i);
567-
if (mode >= 0) {
579+
PinConfig config = Scout.getPinConfig(i);
580+
if (config.mode().active()) {
568581
int value = Scout.pinRead(i);
569-
Scout.updatePinState(i, value, mode);
582+
Scout.updatePinState(i, value, config);
570583
}
571584
}
572585
}
@@ -575,10 +588,10 @@ static void scoutDigitalStateChangeTimerHandler(SYS_Timer_t *timer) {
575588
static void scoutAnalogStateChangeTimerHandler(SYS_Timer_t *timer) {
576589
if (Scout.analogPinEventHandler != 0) {
577590
for (int i=0; i<NUM_ANALOG_INPUTS; i++) {
578-
int mode = Scout.getPinMode(i+A0);
579-
if (mode >= 0) {
591+
PinConfig config = Scout.getPinConfig(i+A0);
592+
if (config.mode().active()) {
580593
int value = Scout.pinRead(i+A0);
581-
Scout.updatePinState(i+A0, value, mode);
594+
Scout.updatePinState(i+A0, value, config);
582595
}
583596
}
584597
}

0 commit comments

Comments
 (0)