Appendix

IO Module ISR

Skip to chapter navigation
namespace ISR {
  void panic(Error::ErrorType err) {
    Timer1::stop();
    detachInterrupt(digitalPinToInterrupt(K_IN_PIN));
    Error::errno = err;
  }

  static volatile enum : uint8_t {
    IDLE,
    WAIT_FOR_KEYBOARD,
    WAIT_AFTER_WRITE,
    WAIT_AFTER_READ
  } state = IDLE;

  void onKCleared() {
    switch (state) {
      case IDLE: return;
      case WAIT_AFTER_WRITE: setIOPinsToInput(); break;
      case WAIT_AFTER_READ:  break;
      default: return panic(Error::REACHED_DEFAULT_1);
    }
    state = IDLE;
    Timer1::restart();
  }

  void writeByteToBusAndWait(uint8_t const value) {
    Timer1::stop();
    setIOPinsToOutput();
    writeByteToBus(value);
    setK();
    state = WAIT_AFTER_WRITE;
  };

  void enqueueByteFromBusAndWait() {
    Timer1::stop();
    lcdBuffer.enqueue(readByteFromBus());
    setK();
    state = WAIT_AFTER_READ;
  };

  void onTimer() {
    switch (state) {
      case IDLE: break;
      case WAIT_FOR_KEYBOARD: {
        if (kbBuffer.available()) {
          writeByteToBusAndWait(kbBuffer.get());
        }
        return;     
      }
      default: return panic(Error::REACHED_DEFAULT_2);
    }

    bool const EN_OUT = digitalRead<DISPLAY_ENABLE_PIN>();
    bool const EN_IN = digitalRead<KEYBOARD_ENABLE_PIN>();

    switch (EN_IN << 1 | EN_OUT) {
      case 0b00: return;
      case 0b01: return enqueueByteFromBusAndWait();
      case 0b10: {
        if (settings.inputMode == IMMEDIATE || kbBuffer.available()) {
          return writeByteToBusAndWait(kbBuffer.get());  
        } else {
          state = WAIT_FOR_KEYBOARD;
          return;
        }
      }
      case 0b11: return writeByteToBusAndWait(rng.get());
      default:   return panic(Error::REACHED_DEFAULT_3);
    }
  }
} // namespace ISR
Listing 16. ISRs that implement the state machine of the IO module.