diff --git a/src/hal/adc.cpp b/src/hal/adc.cpp index c97b9c3..5089d7d 100644 --- a/src/hal/adc.cpp +++ b/src/hal/adc.cpp @@ -3,7 +3,7 @@ namespace hal { namespace adc { - uint16_t ReadADC(uint8_t adc) { return 0; } +uint16_t ReadADC(uint8_t adc) { return 0; } } // namespace adc } // namespace hal diff --git a/src/hal/adc.h b/src/hal/adc.h index cd9cef6..9116dff 100644 --- a/src/hal/adc.h +++ b/src/hal/adc.h @@ -6,8 +6,8 @@ namespace hal { namespace adc { - /// ADC access routines - uint16_t ReadADC(uint8_t adc); +/// ADC access routines +uint16_t ReadADC(uint8_t adc); } // namespace adc } // namespace hal diff --git a/src/hal/avr/cpu.cpp b/src/hal/avr/cpu.cpp index 991342c..96d539d 100644 --- a/src/hal/avr/cpu.cpp +++ b/src/hal/avr/cpu.cpp @@ -3,8 +3,8 @@ namespace hal { namespace cpu { - void Init() { - } +void Init() { +} } // namespace CPU } // namespace hal diff --git a/src/hal/avr/usart.cpp b/src/hal/avr/usart.cpp index 1dac360..436bbe7 100644 --- a/src/hal/avr/usart.cpp +++ b/src/hal/avr/usart.cpp @@ -4,72 +4,72 @@ namespace hal { namespace usart { - USART usart1; +USART usart1; - uint8_t USART::Read() { - uint8_t c = 0; - rx_buf.ConsumeFirst(c); - return c; +uint8_t USART::Read() { + uint8_t c = 0; + rx_buf.ConsumeFirst(c); + return c; +} + +void USART::Write(uint8_t c) { + _written = true; + // If the buffer and the data register is empty, just write the byte + // to the data register and be done. This shortcut helps + // significantly improve the effective datarate at high (> + // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. + if (tx_buf.IsEmpty() && (husart->UCSRxA & (1 << 5))) { + husart->UDRx = c; + husart->UCSRxA |= (1 << 6); + return; } - void USART::Write(uint8_t c) { - _written = true; - // If the buffer and the data register is empty, just write the byte - // to the data register and be done. This shortcut helps - // significantly improve the effective datarate at high (> - // 500kbit/s) bitrates, where interrupt overhead becomes a slowdown. - if (tx_buf.IsEmpty() && (husart->UCSRxA & (1 << 5))) { - husart->UDRx = c; - husart->UCSRxA |= (1 << 6); - return; - } - - // If the output buffer is full, there's nothing for it other than to - // wait for the interrupt handler to empty it a bit - while (!tx_buf.push_back_DontRewrite(c)) { - if (bit_is_clear(SREG, SREG_I)) { - // Interrupts are disabled, so we'll have to poll the data - // register empty flag ourselves. If it is set, pretend an - // interrupt has happened and call the handler to free up - // space for us. - if (husart->UCSRxA & (1 << 5)) { - ISR_UDRE(); - } - } else { - // nop, the interrupt handler will free up space for us + // If the output buffer is full, there's nothing for it other than to + // wait for the interrupt handler to empty it a bit + while (!tx_buf.push_back_DontRewrite(c)) { + if (bit_is_clear(SREG, SREG_I)) { + // Interrupts are disabled, so we'll have to poll the data + // register empty flag ourselves. If it is set, pretend an + // interrupt has happened and call the handler to free up + // space for us. + if (husart->UCSRxA & (1 << 5)) { + ISR_UDRE(); } - } - - husart->UCSRxB |= (1 << 5); //enable UDRE interrupt - } - - void USART::Flush() { - // If we have never written a byte, no need to flush. This special - // case is needed since there is no way to force the TXC (transmit - // complete) bit to 1 during initialization - if (!_written) { - return; - } - - while ((husart->UCSRxB & (1 << 5)) || ~(husart->UCSRxA & (1 << 6))) { - if (bit_is_clear(SREG, SREG_I) && (husart->UCSRxB & (1 << 5))) - // Interrupts are globally disabled, but the DR empty - // interrupt should be enabled, so poll the DR empty flag to - // prevent deadlock - if (husart->UCSRxA & (1 << 5)) { - ISR_UDRE(); - } - } - // If we get here, nothing is queued anymore (DRIE is disabled) and - // the hardware finished tranmission (TXC is set). - } - - void USART::puts(const char *str) { - while (*str) { - Write(*str++); + } else { + // nop, the interrupt handler will free up space for us } } + husart->UCSRxB |= (1 << 5); //enable UDRE interrupt +} + +void USART::Flush() { + // If we have never written a byte, no need to flush. This special + // case is needed since there is no way to force the TXC (transmit + // complete) bit to 1 during initialization + if (!_written) { + return; + } + + while ((husart->UCSRxB & (1 << 5)) || ~(husart->UCSRxA & (1 << 6))) { + if (bit_is_clear(SREG, SREG_I) && (husart->UCSRxB & (1 << 5))) + // Interrupts are globally disabled, but the DR empty + // interrupt should be enabled, so poll the DR empty flag to + // prevent deadlock + if (husart->UCSRxA & (1 << 5)) { + ISR_UDRE(); + } + } + // If we get here, nothing is queued anymore (DRIE is disabled) and + // the hardware finished tranmission (TXC is set). +} + +void USART::puts(const char *str) { + while (*str) { + Write(*str++); + } +} + } // namespace usart } // namespace hal diff --git a/src/hal/cpu.h b/src/hal/cpu.h index 880cc79..9775408 100644 --- a/src/hal/cpu.h +++ b/src/hal/cpu.h @@ -5,8 +5,8 @@ namespace hal { namespace cpu { - /// CPU init routines (not really necessary for the AVR) - void Init(); +/// CPU init routines (not really necessary for the AVR) +void Init(); } // namespace cpu } // namespace hal diff --git a/src/hal/eeprom.h b/src/hal/eeprom.h index 094cd37..231eeff 100644 --- a/src/hal/eeprom.h +++ b/src/hal/eeprom.h @@ -3,10 +3,10 @@ namespace hal { namespace EEPROM { - /// EEPROM interface - void WriteByte(uint16_t addr, uint8_t value); - void UpdateByte(uint16_t addr, uint8_t value); - uint8_t ReadByte(uint16_t addr); +/// EEPROM interface +void WriteByte(uint16_t addr, uint8_t value); +void UpdateByte(uint16_t addr, uint8_t value); +uint8_t ReadByte(uint16_t addr); } // namespace EEPROM } // namespace hal diff --git a/src/hal/gpio.h b/src/hal/gpio.h index 4d473bf..aceaa17 100644 --- a/src/hal/gpio.h +++ b/src/hal/gpio.h @@ -5,72 +5,72 @@ namespace hal { namespace gpio { - struct GPIO_TypeDef { - volatile uint8_t PINx; - volatile uint8_t DDRx; - volatile uint8_t PORTx; - }; +struct GPIO_TypeDef { + volatile uint8_t PINx; + volatile uint8_t DDRx; + volatile uint8_t PORTx; +}; - enum class Mode : uint8_t { - input = 0, - output, - }; +enum class Mode : uint8_t { + input = 0, + output, +}; - enum class Pull : uint8_t { - none = 0, - up, - down, //not available on the AVR - }; +enum class Pull : uint8_t { + none = 0, + up, + down, //not available on the AVR +}; - enum class Level : uint8_t { - low = 0, - high, - }; +enum class Level : uint8_t { + low = 0, + high, +}; - struct GPIO_InitTypeDef { - Mode mode; - Pull pull; - Level level; - inline GPIO_InitTypeDef(Mode mode, Pull pull) - : mode(mode) - , pull(pull) {}; - inline GPIO_InitTypeDef(Mode mode, Level level) - : mode(mode) - , level(level) {}; - }; +struct GPIO_InitTypeDef { + Mode mode; + Pull pull; + Level level; + inline GPIO_InitTypeDef(Mode mode, Pull pull) + : mode(mode) + , pull(pull) {}; + inline GPIO_InitTypeDef(Mode mode, Level level) + : mode(mode) + , level(level) {}; +}; - struct GPIO_pin { - GPIO_TypeDef *const port; - const uint8_t pin; - inline GPIO_pin(GPIO_TypeDef *const port, const uint8_t pin) - : port(port) - , pin(pin) {}; - }; +struct GPIO_pin { + GPIO_TypeDef *const port; + const uint8_t pin; + inline GPIO_pin(GPIO_TypeDef *const port, const uint8_t pin) + : port(port) + , pin(pin) {}; +}; - __attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) { - if (level == Level::high) - portPin.port->PORTx |= (1 << portPin.pin); - else - portPin.port->PORTx &= ~(1 << portPin.pin); - } - - __attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) { - return (Level)(portPin.port->PINx & (1 << portPin.pin)); - } - - __attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) { - portPin.port->PINx |= (1 << portPin.pin); - } - - __attribute__((always_inline)) inline void Init(const GPIO_pin portPin, GPIO_InitTypeDef GPIO_Init) { - if (GPIO_Init.mode == Mode::output) { - WritePin(portPin, GPIO_Init.level); - portPin.port->DDRx |= (1 << portPin.pin); - } else { - portPin.port->DDRx &= ~(1 << portPin.pin); - WritePin(portPin, (Level)GPIO_Init.pull); - } +__attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) { + if (level == Level::high) + portPin.port->PORTx |= (1 << portPin.pin); + else + portPin.port->PORTx &= ~(1 << portPin.pin); +} + +__attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) { + return (Level)(portPin.port->PINx & (1 << portPin.pin)); +} + +__attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) { + portPin.port->PINx |= (1 << portPin.pin); +} + +__attribute__((always_inline)) inline void Init(const GPIO_pin portPin, GPIO_InitTypeDef GPIO_Init) { + if (GPIO_Init.mode == Mode::output) { + WritePin(portPin, GPIO_Init.level); + portPin.port->DDRx |= (1 << portPin.pin); + } else { + portPin.port->DDRx &= ~(1 << portPin.pin); + WritePin(portPin, (Level)GPIO_Init.pull); } +} } } diff --git a/src/hal/spi.h b/src/hal/spi.h index 5e067d3..8b9546e 100644 --- a/src/hal/spi.h +++ b/src/hal/spi.h @@ -6,42 +6,42 @@ namespace hal { namespace spi { - struct SPI_TypeDef { - volatile uint8_t SPCRx; - volatile uint8_t SPSRx; - volatile uint8_t SPDRx; - }; +struct SPI_TypeDef { + volatile uint8_t SPCRx; + volatile uint8_t SPSRx; + volatile uint8_t SPDRx; +}; - struct SPI_InitTypeDef { - hal::gpio::GPIO_pin miso_pin; - hal::gpio::GPIO_pin mosi_pin; - hal::gpio::GPIO_pin sck_pin; - hal::gpio::GPIO_pin ss_pin; - uint8_t prescaler; - uint8_t cpha; - uint8_t cpol; - }; +struct SPI_InitTypeDef { + hal::gpio::GPIO_pin miso_pin; + hal::gpio::GPIO_pin mosi_pin; + hal::gpio::GPIO_pin sck_pin; + hal::gpio::GPIO_pin ss_pin; + uint8_t prescaler; + uint8_t cpha; + uint8_t cpol; +}; - __attribute__((always_inline)) inline void Init(SPI_TypeDef *const hspi, SPI_InitTypeDef *const conf) { - using namespace hal; - gpio::Init(conf->miso_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Pull::none)); - gpio::Init(conf->mosi_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); - gpio::Init(conf->sck_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); - gpio::Init(conf->ss_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::high)); //the AVR requires this pin to be an output for SPI master mode to work properly. +__attribute__((always_inline)) inline void Init(SPI_TypeDef *const hspi, SPI_InitTypeDef *const conf) { + using namespace hal; + gpio::Init(conf->miso_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Pull::none)); + gpio::Init(conf->mosi_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); + gpio::Init(conf->sck_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); + gpio::Init(conf->ss_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::high)); //the AVR requires this pin to be an output for SPI master mode to work properly. - const uint8_t spi2x = (conf->prescaler == 7) ? 0 : (conf->prescaler & 0x01); - const uint8_t spr = ((conf->prescaler - 1) >> 1) & 0x03; + const uint8_t spi2x = (conf->prescaler == 7) ? 0 : (conf->prescaler & 0x01); + const uint8_t spr = ((conf->prescaler - 1) >> 1) & 0x03; - hspi->SPCRx = (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | ((conf->cpol & 0x01) << CPOL) | ((conf->cpha & 0x01) << CPHA) | (spr << SPR0); - hspi->SPSRx = (spi2x << SPI2X); - } + hspi->SPCRx = (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | ((conf->cpol & 0x01) << CPOL) | ((conf->cpha & 0x01) << CPHA) | (spr << SPR0); + hspi->SPSRx = (spi2x << SPI2X); +} - __attribute__((always_inline)) inline uint8_t TxRx(SPI_TypeDef *const hspi, uint8_t val) { - hspi->SPDRx = val; - while (!(hspi->SPSRx & (1 << SPIF))) - ; - return hspi->SPDRx; - } +__attribute__((always_inline)) inline uint8_t TxRx(SPI_TypeDef *const hspi, uint8_t val) { + hspi->SPDRx = val; + while (!(hspi->SPSRx & (1 << SPIF))) + ; + return hspi->SPDRx; +} } } diff --git a/src/hal/timers.h b/src/hal/timers.h index f233616..8eba17b 100644 --- a/src/hal/timers.h +++ b/src/hal/timers.h @@ -5,10 +5,10 @@ namespace hal { namespace timers { - /// timers - void ConfigureTimer(uint8_t timer /* some config struct */); - void StartTimer(uint8_t timer); - void StopTimer(uint8_t timer); +/// timers +void ConfigureTimer(uint8_t timer /* some config struct */); +void StartTimer(uint8_t timer); +void StopTimer(uint8_t timer); } // namespace cpu } // namespace hal diff --git a/src/hal/usart.h b/src/hal/usart.h index 080e5cc..c6f8612 100644 --- a/src/hal/usart.h +++ b/src/hal/usart.h @@ -10,95 +10,95 @@ namespace hal { namespace usart { - class USART { - public: - struct USART_TypeDef { - volatile uint8_t UCSRxA; - volatile uint8_t UCSRxB; - volatile uint8_t UCSRxC; - volatile uint8_t UCSRxD; - volatile uint16_t UBRRx; - volatile uint8_t UDRx; - }; - - struct USART_InitTypeDef { - hal::gpio::GPIO_pin rx_pin; - hal::gpio::GPIO_pin tx_pin; - uint32_t baudrate; - }; - - /// @returns current character from the UART without extracting it from the read buffer - uint8_t Peek() const { - return rx_buf.GetFirstIfAble(); - } - /// @returns true if there are no bytes to be read - bool ReadEmpty() const { - return rx_buf.IsEmpty(); - } - /// @returns current character from the UART and extracts it from the read buffer - uint8_t Read(); - - /// @param c character to be pushed into the TX buffer (to be sent) - void Write(uint8_t c); - /// @param str c string to be sent. NL is appended - void puts(const char *str); - /// @returns true if there is at least one byte free in the TX buffer (i.e. some space to add a character to be sent) - bool CanWrite() const { - return tx_buf.CanPush(); - } - /// blocks until the TX buffer was successfully transmitted - void Flush(); - - /// Initializes USART interface - __attribute__((always_inline)) inline void Init(USART_InitTypeDef *const conf) { - gpio::Init(conf->rx_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Level::low)); - gpio::Init(conf->tx_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); - husart->UBRRx = (((double)(F_CPU)) / (((double)(conf->baudrate)) * 8.0) - 1.0 + 0.5); - husart->UCSRxA = (1 << 1); // Set double baudrate setting. Clear all other status bits/flags - // husart->UCSRxC |= (1 << 3); // 2 stop bits. Preserve data size setting - husart->UCSRxD = 0; //disable hardware flow control. This register is reserved on all AVR devides with USART. - husart->UCSRxB = (1 << 3) | (1 << 4) | (1 << 7); // Turn on the transmission and reception circuitry and enable the RX interrupt - } - - /// implementation of the receive ISR's body - __attribute__((always_inline)) inline void ISR_RX() { - if (husart->UCSRxA & (1 << 4)) { - (void)husart->UDRx; - } else { - rx_buf.push_back_DontRewrite(husart->UDRx); - } - } - /// implementation of the transmit ISR's body - __attribute__((always_inline)) inline void ISR_UDRE() { - uint8_t c = 0; - tx_buf.ConsumeFirst(c); - husart->UDRx = c; - - // clear the TXC bit -- "can be cleared by writing a one to its bit - // location". This makes sure flush() won't return until the bytes - // actually got written - husart->UCSRxA |= (1 << 6); - - if (tx_buf.IsEmpty()) - husart->UCSRxB &= ~(1 << 5); // disable UDRE interrupt - } - - USART() = default; - void Init(USART_TypeDef *conf) { - husart = conf; - } - - private: - // IO base address - USART_TypeDef *husart; - bool _written; - - CircleBuffer tx_buf; - CircleBuffer rx_buf; +class USART { +public: + struct USART_TypeDef { + volatile uint8_t UCSRxA; + volatile uint8_t UCSRxB; + volatile uint8_t UCSRxC; + volatile uint8_t UCSRxD; + volatile uint16_t UBRRx; + volatile uint8_t UDRx; }; - /// beware - normally we'd make a singleton, but avr-gcc generates suboptimal code for them, therefore we only keep this extern variable - extern USART usart1; + struct USART_InitTypeDef { + hal::gpio::GPIO_pin rx_pin; + hal::gpio::GPIO_pin tx_pin; + uint32_t baudrate; + }; + + /// @returns current character from the UART without extracting it from the read buffer + uint8_t Peek() const { + return rx_buf.GetFirstIfAble(); + } + /// @returns true if there are no bytes to be read + bool ReadEmpty() const { + return rx_buf.IsEmpty(); + } + /// @returns current character from the UART and extracts it from the read buffer + uint8_t Read(); + + /// @param c character to be pushed into the TX buffer (to be sent) + void Write(uint8_t c); + /// @param str c string to be sent. NL is appended + void puts(const char *str); + /// @returns true if there is at least one byte free in the TX buffer (i.e. some space to add a character to be sent) + bool CanWrite() const { + return tx_buf.CanPush(); + } + /// blocks until the TX buffer was successfully transmitted + void Flush(); + + /// Initializes USART interface + __attribute__((always_inline)) inline void Init(USART_InitTypeDef *const conf) { + gpio::Init(conf->rx_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Level::low)); + gpio::Init(conf->tx_pin, gpio::GPIO_InitTypeDef(gpio::Mode::output, gpio::Level::low)); + husart->UBRRx = (((double)(F_CPU)) / (((double)(conf->baudrate)) * 8.0) - 1.0 + 0.5); + husart->UCSRxA = (1 << 1); // Set double baudrate setting. Clear all other status bits/flags + // husart->UCSRxC |= (1 << 3); // 2 stop bits. Preserve data size setting + husart->UCSRxD = 0; //disable hardware flow control. This register is reserved on all AVR devides with USART. + husart->UCSRxB = (1 << 3) | (1 << 4) | (1 << 7); // Turn on the transmission and reception circuitry and enable the RX interrupt + } + + /// implementation of the receive ISR's body + __attribute__((always_inline)) inline void ISR_RX() { + if (husart->UCSRxA & (1 << 4)) { + (void)husart->UDRx; + } else { + rx_buf.push_back_DontRewrite(husart->UDRx); + } + } + /// implementation of the transmit ISR's body + __attribute__((always_inline)) inline void ISR_UDRE() { + uint8_t c = 0; + tx_buf.ConsumeFirst(c); + husart->UDRx = c; + + // clear the TXC bit -- "can be cleared by writing a one to its bit + // location". This makes sure flush() won't return until the bytes + // actually got written + husart->UCSRxA |= (1 << 6); + + if (tx_buf.IsEmpty()) + husart->UCSRxB &= ~(1 << 5); // disable UDRE interrupt + } + + USART() = default; + void Init(USART_TypeDef *conf) { + husart = conf; + } + +private: + // IO base address + USART_TypeDef *husart; + bool _written; + + CircleBuffer tx_buf; + CircleBuffer rx_buf; +}; + +/// beware - normally we'd make a singleton, but avr-gcc generates suboptimal code for them, therefore we only keep this extern variable +extern USART usart1; } // namespace usart } // namespace hal diff --git a/src/hal/watchdog.h b/src/hal/watchdog.h index de264a2..850589d 100644 --- a/src/hal/watchdog.h +++ b/src/hal/watchdog.h @@ -5,9 +5,9 @@ namespace hal { namespace watchdog { - /// watchdog interface - void ConfigureWatchDog(uint16_t period); - void ResetWatchDog(); +/// watchdog interface +void ConfigureWatchDog(uint16_t period); +void ResetWatchDog(); } // namespace watchdog } // namespace hal diff --git a/src/modules/buttons.cpp b/src/modules/buttons.cpp index 7ce76e1..94a0b6f 100644 --- a/src/modules/buttons.cpp +++ b/src/modules/buttons.cpp @@ -3,69 +3,69 @@ namespace modules { namespace buttons { - uint16_t Buttons::tmpTiming = 0; +uint16_t Buttons::tmpTiming = 0; - // original idea from: https://www.eeweb.com/debouncing-push-buttons-using-a-state-machine-approach - void Button::Step(uint16_t time, bool press) { - switch (f.state) { - case State::Waiting: - if (press) { - f.state = State::Detected; - timeLastChange = time; - f.tmp = press; - } - break; - case State::Detected: - if (f.tmp == press) { - if (time - timeLastChange > debounce) { - f.state = State::WaitForRelease; - } - } else { - f.state = State::Waiting; - } - break; - case State::WaitForRelease: - if (!press) { - f.state = State::Update; - } - break; - case State::Update: - f.state = State::Waiting; +// original idea from: https://www.eeweb.com/debouncing-push-buttons-using-a-state-machine-approach +void Button::Step(uint16_t time, bool press) { + switch (f.state) { + case State::Waiting: + if (press) { + f.state = State::Detected; timeLastChange = time; - f.tmp = false; - break; - default: + f.tmp = press; + } + break; + case State::Detected: + if (f.tmp == press) { + if (time - timeLastChange > debounce) { + f.state = State::WaitForRelease; + } + } else { f.state = State::Waiting; - timeLastChange = time; - f.tmp = false; } - } - - int8_t Buttons::Sample(uint16_t rawADC) { - // decode 3 buttons' levels from one ADC - // Button 1 - 0 - // Button 2 - 344 - // Button 3 - 516 - // Doesn't handle multiple pressed buttons at once - - if (rawADC < 10) - return 0; - else if (rawADC > 320 && rawADC < 360) - return 1; - else if (rawADC > 500 && rawADC < 530) - return 2; - return -1; - } - - void Buttons::Step(uint16_t rawADC) { - // @@TODO temporary timing - ++tmpTiming; - int8_t currentState = Sample(rawADC); - for (uint_fast8_t b = 0; b < N; ++b) { - // this button was pressed if b == currentState, released otherwise - buttons[b].Step(tmpTiming, b == currentState); + break; + case State::WaitForRelease: + if (!press) { + f.state = State::Update; } + break; + case State::Update: + f.state = State::Waiting; + timeLastChange = time; + f.tmp = false; + break; + default: + f.state = State::Waiting; + timeLastChange = time; + f.tmp = false; } +} + +int8_t Buttons::Sample(uint16_t rawADC) { + // decode 3 buttons' levels from one ADC + // Button 1 - 0 + // Button 2 - 344 + // Button 3 - 516 + // Doesn't handle multiple pressed buttons at once + + if (rawADC < 10) + return 0; + else if (rawADC > 320 && rawADC < 360) + return 1; + else if (rawADC > 500 && rawADC < 530) + return 2; + return -1; +} + +void Buttons::Step(uint16_t rawADC) { + // @@TODO temporary timing + ++tmpTiming; + int8_t currentState = Sample(rawADC); + for (uint_fast8_t b = 0; b < N; ++b) { + // this button was pressed if b == currentState, released otherwise + buttons[b].Step(tmpTiming, b == currentState); + } +} } // namespace buttons } // namespace modules diff --git a/src/modules/buttons.h b/src/modules/buttons.h index d20260e..6f9fc53 100644 --- a/src/modules/buttons.h +++ b/src/modules/buttons.h @@ -9,67 +9,67 @@ namespace modules { namespace buttons { - struct Button { - inline constexpr Button() - : timeLastChange(0) {} +struct Button { + inline constexpr Button() + : timeLastChange(0) {} - /// @returns true if button is currently considered as pressed - inline bool Pressed() const { return f.state == State::WaitForRelease; } + /// @returns true if button is currently considered as pressed + inline bool Pressed() const { return f.state == State::WaitForRelease; } - /// State machine stepping routine - void Step(uint16_t time, bool press); + /// State machine stepping routine + void Step(uint16_t time, bool press); - private: - /// time interval for debouncing @@TODO specify units - constexpr static const uint16_t debounce = 100; +private: + /// time interval for debouncing @@TODO specify units + constexpr static const uint16_t debounce = 100; - /// States of the debouncing automaton - /// Intentionally not modeled as an enum class - /// as it would impose additional casts which do not play well with the struct Flags - /// and would make the code less readable - enum State { Waiting = 0, - Detected, - WaitForRelease, - Update }; + /// States of the debouncing automaton + /// Intentionally not modeled as an enum class + /// as it would impose additional casts which do not play well with the struct Flags + /// and would make the code less readable + enum State { Waiting = 0, + Detected, + WaitForRelease, + Update }; - /// The sole purpose of this data struct is to save RAM by compressing several flags into one byte on the AVR - struct Flags { - uint8_t state : 2; ///< state of the button - uint8_t tmp : 1; ///< temporary state of button before the debouncing state machine finishes - inline constexpr Flags() - : state(State::Waiting) - , tmp(false) {} - }; - - /// Flags and state of the debouncing automaton - Flags f; - - /// Timestamp of the last change of ADC state for this button - uint16_t timeLastChange; + /// The sole purpose of this data struct is to save RAM by compressing several flags into one byte on the AVR + struct Flags { + uint8_t state : 2; ///< state of the button + uint8_t tmp : 1; ///< temporary state of button before the debouncing state machine finishes + inline constexpr Flags() + : state(State::Waiting) + , tmp(false) {} }; - class Buttons { - constexpr static const uint8_t N = 3; ///< number of buttons currently supported - constexpr static const uint8_t adc = 1; ///< ADC index - will be some define or other constant later on - static uint16_t tmpTiming; ///< subject to removal when we have timers implemented - now used for the unit tests + /// Flags and state of the debouncing automaton + Flags f; - public: - inline constexpr Buttons() = default; + /// Timestamp of the last change of ADC state for this button + uint16_t timeLastChange; +}; - /// State machine step - reads the ADC, processes debouncing, updates states of individual buttons - void Step(uint16_t rawADC); +class Buttons { + constexpr static const uint8_t N = 3; ///< number of buttons currently supported + constexpr static const uint8_t adc = 1; ///< ADC index - will be some define or other constant later on + static uint16_t tmpTiming; ///< subject to removal when we have timers implemented - now used for the unit tests - /// @return true if button at index is pressed - /// @@TODO add range checking if necessary - inline bool ButtonPressed(uint8_t index) const { return buttons[index].Pressed(); } +public: + inline constexpr Buttons() = default; - private: - Button buttons[N]; + /// State machine step - reads the ADC, processes debouncing, updates states of individual buttons + void Step(uint16_t rawADC); - /// Call to the ADC and decode its output into a button index - /// @returns index of the button pressed or -1 in case no button is pressed - static int8_t Sample(uint16_t rawADC); - }; + /// @return true if button at index is pressed + /// @@TODO add range checking if necessary + inline bool ButtonPressed(uint8_t index) const { return buttons[index].Pressed(); } + +private: + Button buttons[N]; + + /// Call to the ADC and decode its output into a button index + /// @returns index of the button pressed or -1 in case no button is pressed + static int8_t Sample(uint16_t rawADC); +}; } // namespace buttons } // namespace modules diff --git a/src/modules/leds.cpp b/src/modules/leds.cpp index c994d42..4787e92 100644 --- a/src/modules/leds.cpp +++ b/src/modules/leds.cpp @@ -3,48 +3,48 @@ namespace modules { namespace leds { - void LED::SetMode(Mode mode) { - state.mode = mode; - // set initial state of LEDs correctly - transition from one mode to another - switch (state.mode) { - case Mode::blink1: - case Mode::off: - state.on = 0; - break; +void LED::SetMode(Mode mode) { + state.mode = mode; + // set initial state of LEDs correctly - transition from one mode to another + switch (state.mode) { + case Mode::blink1: + case Mode::off: + state.on = 0; + break; - case Mode::blink0: - case Mode::on: - state.on = 1; - break; - default: - break; - } + case Mode::blink0: + case Mode::on: + state.on = 1; + break; + default: + break; } +} - bool LED::Step(bool oddPeriod) { - switch (state.mode) { - // on and off don't change while stepping - case Mode::blink0: - state.on = oddPeriod; - break; - case Mode::blink1: - state.on = !oddPeriod; - break; - default: // do nothing - break; - } +bool LED::Step(bool oddPeriod) { + switch (state.mode) { + // on and off don't change while stepping + case Mode::blink0: + state.on = oddPeriod; + break; + case Mode::blink1: + state.on = !oddPeriod; + break; + default: // do nothing + break; } +} - uint16_t LEDs::Step(uint8_t delta_ms) { - ms += delta_ms; - bool oddPeriod = ((ms / 1000U) & 0x01U) != 0; - uint16_t result = 0; - for (uint8_t i = 0; i < ledPairs * 2; ++i) { - result <<= 1; - result |= leds[i].Step(oddPeriod); - } - return result; +uint16_t LEDs::Step(uint8_t delta_ms) { + ms += delta_ms; + bool oddPeriod = ((ms / 1000U) & 0x01U) != 0; + uint16_t result = 0; + for (uint8_t i = 0; i < ledPairs * 2; ++i) { + result <<= 1; + result |= leds[i].Step(oddPeriod); } + return result; +} } // namespace leds } // namespace modules diff --git a/src/modules/protocol.cpp b/src/modules/protocol.cpp index 356a30e..a230fd3 100644 --- a/src/modules/protocol.cpp +++ b/src/modules/protocol.cpp @@ -13,176 +13,197 @@ namespace modules { namespace protocol { - // decoding automaton - // states: input -> transition into state - // Code QTLMUXPSBEWK -> msgcode - // \n ->start - // * ->error - // error \n ->start - // * ->error - // msgcode 0-9 ->msgvalue - // * ->error - // msgvalue 0-9 ->msgvalue - // \n ->start successfully accepted command +// decoding automaton +// states: input -> transition into state +// Code QTLMUXPSBEWK -> msgcode +// \n ->start +// * ->error +// error \n ->start +// * ->error +// msgcode 0-9 ->msgvalue +// * ->error +// msgvalue 0-9 ->msgvalue +// \n ->start successfully accepted command - DecodeStatus Protocol::DecodeRequest(uint8_t c) { - switch (rqState) { - case RequestStates::Code: - switch (c) { - case 'Q': - case 'T': - case 'L': - case 'M': - case 'U': - case 'X': - case 'P': - case 'S': - case 'B': - case 'E': - case 'W': - case 'K': - requestMsg.code = (RequestMsgCodes)c; - requestMsg.value = 0; - rqState = RequestStates::Value; - return DecodeStatus::NeedMoreData; - default: - requestMsg.code = RequestMsgCodes::unknown; - rqState = RequestStates::Error; - return DecodeStatus::Error; - } - case RequestStates::Value: - if (c >= '0' && c <= '9') { - requestMsg.value *= 10; - requestMsg.value += c - '0'; - return DecodeStatus::NeedMoreData; - } else if (c == '\n') { - rqState = RequestStates::Code; - return DecodeStatus::MessageCompleted; - } else { - requestMsg.code = RequestMsgCodes::unknown; - rqState = RequestStates::Error; - return DecodeStatus::Error; - } - default: //case error: - if (c == '\n') { - rqState = RequestStates::Code; - return DecodeStatus::MessageCompleted; - } else { - requestMsg.code = RequestMsgCodes::unknown; - rqState = RequestStates::Error; - return DecodeStatus::Error; - } +DecodeStatus Protocol::DecodeRequest(uint8_t c) { + switch (rqState) { + case RequestStates::Code: + switch (c) { + case 'Q': + case 'T': + case 'L': + case 'M': + case 'U': + case 'X': + case 'P': + case 'S': + case 'B': + case 'E': + case 'W': + case 'K': + requestMsg.code = (RequestMsgCodes)c; + requestMsg.value = 0; + rqState = RequestStates::Value; + return DecodeStatus::NeedMoreData; + default: + requestMsg.code = RequestMsgCodes::unknown; + rqState = RequestStates::Error; + return DecodeStatus::Error; + } + case RequestStates::Value: + if (c >= '0' && c <= '9') { + requestMsg.value *= 10; + requestMsg.value += c - '0'; + return DecodeStatus::NeedMoreData; + } else if (c == '\n') { + rqState = RequestStates::Code; + return DecodeStatus::MessageCompleted; + } else { + requestMsg.code = RequestMsgCodes::unknown; + rqState = RequestStates::Error; + return DecodeStatus::Error; + } + default: //case error: + if (c == '\n') { + rqState = RequestStates::Code; + return DecodeStatus::MessageCompleted; + } else { + requestMsg.code = RequestMsgCodes::unknown; + rqState = RequestStates::Error; + return DecodeStatus::Error; } } +} - uint8_t Protocol::EncodeRequest(const RequestMsg &msg, uint8_t *txbuff) { - txbuff[0] = (uint8_t)msg.code; - txbuff[1] = msg.value + '0'; - txbuff[2] = '\n'; - return 3; - } +uint8_t Protocol::EncodeRequest(const RequestMsg &msg, uint8_t *txbuff) { + txbuff[0] = (uint8_t)msg.code; + txbuff[1] = msg.value + '0'; + txbuff[2] = '\n'; + return 3; +} - DecodeStatus Protocol::DecodeResponse(uint8_t c) { - switch (rspState) { - case ResponseStates::RequestCode: - switch (c) { - case 'Q': - case 'T': - case 'L': - case 'M': - case 'U': - case 'X': - case 'P': - case 'S': - case 'B': - case 'E': - case 'W': - case 'K': - responseMsg.request.code = (RequestMsgCodes)c; - responseMsg.request.value = 0; - rspState = ResponseStates::RequestValue; - return DecodeStatus::NeedMoreData; - default: - rspState = ResponseStates::Error; - return DecodeStatus::Error; - } - case ResponseStates::RequestValue: - if (c >= '0' && c <= '9') { - responseMsg.request.value *= 10; - responseMsg.request.value += c - '0'; - return DecodeStatus::NeedMoreData; - } else if (c == ' ') { - rspState = ResponseStates::ParamCode; - return DecodeStatus::NeedMoreData; - } else { - rspState = ResponseStates::Error; - return DecodeStatus::Error; - } - case ResponseStates::ParamCode: - switch (c) { - case 'P': - case 'E': - case 'F': - case 'A': - case 'R': - rspState = ResponseStates::ParamValue; - responseMsg.paramCode = (ResponseMsgParamCodes)c; - responseMsg.paramValue = 0; - return DecodeStatus::NeedMoreData; - default: - responseMsg.paramCode = ResponseMsgParamCodes::unknown; - rspState = ResponseStates::Error; - return DecodeStatus::Error; - } - case ResponseStates::ParamValue: - if (c >= '0' && c <= '9') { - responseMsg.paramValue *= 10; - responseMsg.paramValue += c - '0'; - return DecodeStatus::NeedMoreData; - } else if (c == '\n') { - rspState = ResponseStates::RequestCode; - return DecodeStatus::MessageCompleted; - } else { - responseMsg.paramCode = ResponseMsgParamCodes::unknown; - rspState = ResponseStates::Error; - return DecodeStatus::Error; - } - default: //case error: - if (c == '\n') { - rspState = ResponseStates::RequestCode; - return DecodeStatus::MessageCompleted; - } else { - responseMsg.paramCode = ResponseMsgParamCodes::unknown; - return DecodeStatus::Error; - } +DecodeStatus Protocol::DecodeResponse(uint8_t c) { + switch (rspState) { + case ResponseStates::RequestCode: + switch (c) { + case 'Q': + case 'T': + case 'L': + case 'M': + case 'U': + case 'X': + case 'P': + case 'S': + case 'B': + case 'E': + case 'W': + case 'K': + responseMsg.request.code = (RequestMsgCodes)c; + responseMsg.request.value = 0; + rspState = ResponseStates::RequestValue; + return DecodeStatus::NeedMoreData; + default: + rspState = ResponseStates::Error; + return DecodeStatus::Error; + } + case ResponseStates::RequestValue: + if (c >= '0' && c <= '9') { + responseMsg.request.value *= 10; + responseMsg.request.value += c - '0'; + return DecodeStatus::NeedMoreData; + } else if (c == ' ') { + rspState = ResponseStates::ParamCode; + return DecodeStatus::NeedMoreData; + } else { + rspState = ResponseStates::Error; + return DecodeStatus::Error; + } + case ResponseStates::ParamCode: + switch (c) { + case 'P': + case 'E': + case 'F': + case 'A': + case 'R': + rspState = ResponseStates::ParamValue; + responseMsg.paramCode = (ResponseMsgParamCodes)c; + responseMsg.paramValue = 0; + return DecodeStatus::NeedMoreData; + default: + responseMsg.paramCode = ResponseMsgParamCodes::unknown; + rspState = ResponseStates::Error; + return DecodeStatus::Error; + } + case ResponseStates::ParamValue: + if (c >= '0' && c <= '9') { + responseMsg.paramValue *= 10; + responseMsg.paramValue += c - '0'; + return DecodeStatus::NeedMoreData; + } else if (c == '\n') { + rspState = ResponseStates::RequestCode; + return DecodeStatus::MessageCompleted; + } else { + responseMsg.paramCode = ResponseMsgParamCodes::unknown; + rspState = ResponseStates::Error; + return DecodeStatus::Error; + } + default: //case error: + if (c == '\n') { + rspState = ResponseStates::RequestCode; + return DecodeStatus::MessageCompleted; + } else { + responseMsg.paramCode = ResponseMsgParamCodes::unknown; + return DecodeStatus::Error; } } +} - uint8_t Protocol::EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff) { - txbuff[0] = (uint8_t)msg.code; - txbuff[1] = msg.value + '0'; - txbuff[2] = ' '; - txbuff[3] = (uint8_t)ar; - txbuff[4] = '\n'; - return 5; +uint8_t Protocol::EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff) { + txbuff[0] = (uint8_t)msg.code; + txbuff[1] = msg.value + '0'; + txbuff[2] = ' '; + txbuff[3] = (uint8_t)ar; + txbuff[4] = '\n'; + return 5; +} + +uint8_t Protocol::EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff) { + txbuff[0] = (uint8_t)msg.code; + txbuff[1] = msg.value + '0'; + txbuff[2] = ' '; + txbuff[3] = (uint8_t)ResponseMsgParamCodes::Accepted; + txbuff[4] = findaValue + '0'; + txbuff[5] = '\n'; + return 6; +} + +uint8_t Protocol::EncodeResponseVersion(const RequestMsg &msg, uint8_t value, uint8_t *txbuff) { + txbuff[0] = (uint8_t)msg.code; + txbuff[1] = msg.value + '0'; + txbuff[2] = ' '; + txbuff[3] = (uint8_t)ResponseMsgParamCodes::Accepted; + uint8_t *dst = txbuff + 4; + if (value < 10) { + *dst++ = value + '0'; + } else if (value < 100) { + *dst++ = value / 10 + '0'; + *dst++ = value % 10 + '0'; + } else { + *dst++ = value / 100 + '0'; + *dst++ = (value / 10) % 10 + '0'; + *dst++ = value % 10 + '0'; } + *dst = '\n'; + return dst - txbuff + 1; +} - uint8_t Protocol::EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff) { - txbuff[0] = (uint8_t)msg.code; - txbuff[1] = msg.value + '0'; - txbuff[2] = ' '; - txbuff[3] = (uint8_t)ResponseMsgParamCodes::Accepted; - txbuff[4] = findaValue + '0'; - txbuff[5] = '\n'; - return 6; - } - - uint8_t Protocol::EncodeResponseVersion(const RequestMsg &msg, uint8_t value, uint8_t *txbuff) { - txbuff[0] = (uint8_t)msg.code; - txbuff[1] = msg.value + '0'; - txbuff[2] = ' '; - txbuff[3] = (uint8_t)ResponseMsgParamCodes::Accepted; - uint8_t *dst = txbuff + 4; +uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff) { + txbuff[0] = (uint8_t)msg.code; + txbuff[1] = msg.value + '0'; + txbuff[2] = ' '; + txbuff[3] = (uint8_t)code; + uint8_t *dst = txbuff + 4; + if (code != ResponseMsgParamCodes::Finished) { if (value < 10) { *dst++ = value + '0'; } else if (value < 100) { @@ -193,31 +214,10 @@ namespace protocol { *dst++ = (value / 10) % 10 + '0'; *dst++ = value % 10 + '0'; } - *dst = '\n'; - return dst - txbuff + 1; - } - - uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff) { - txbuff[0] = (uint8_t)msg.code; - txbuff[1] = msg.value + '0'; - txbuff[2] = ' '; - txbuff[3] = (uint8_t)code; - uint8_t *dst = txbuff + 4; - if (code != ResponseMsgParamCodes::Finished) { - if (value < 10) { - *dst++ = value + '0'; - } else if (value < 100) { - *dst++ = value / 10 + '0'; - *dst++ = value % 10 + '0'; - } else { - *dst++ = value / 100 + '0'; - *dst++ = (value / 10) % 10 + '0'; - *dst++ = value % 10 + '0'; - } - } - *dst = '\n'; - return dst - txbuff + 1; } + *dst = '\n'; + return dst - txbuff + 1; +} } // namespace protocol } // namespace modules diff --git a/src/modules/protocol.h b/src/modules/protocol.h index 98a8d61..a9ee3c2 100644 --- a/src/modules/protocol.h +++ b/src/modules/protocol.h @@ -9,137 +9,137 @@ namespace modules { namespace protocol { - enum class RequestMsgCodes : uint8_t { - unknown = 0, - Query = 'Q', - Tool = 'T', - Load = 'L', - Mode = 'M', - Unload = 'U', - Reset = 'X', - Finda = 'P', - Version = 'S', - Button = 'B', - Eject = 'E', - Wait = 'W', - Cut = 'K' +enum class RequestMsgCodes : uint8_t { + unknown = 0, + Query = 'Q', + Tool = 'T', + Load = 'L', + Mode = 'M', + Unload = 'U', + Reset = 'X', + Finda = 'P', + Version = 'S', + Button = 'B', + Eject = 'E', + Wait = 'W', + Cut = 'K' +}; + +enum class ResponseMsgParamCodes : uint8_t { + unknown = 0, + Processing = 'P', + Error = 'E', + Finished = 'F', + Accepted = 'A', + Rejected = 'R' +}; + +/// A request message +/// Requests are being sent by the printer into the MMU +/// It is the same structure as the generic Msg +struct RequestMsg { + RequestMsgCodes code; + uint8_t value; + inline RequestMsg(RequestMsgCodes code, uint8_t value) + : code(code) + , value(value) {} +}; + +/// A response message +/// Responses are being sent from the MMU into the printer as a response to a request message +struct ResponseMsg { + RequestMsg request; ///< response is always preceeded by the request message + ResponseMsgParamCodes paramCode; ///< parameters of reply + uint8_t paramValue; ///< parameters of reply + inline ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint8_t paramValue) + : request(request) + , paramCode(paramCode) + , paramValue(paramValue) {} +}; + +/// Message decoding return value +enum class DecodeStatus : uint_fast8_t { + MessageCompleted, ///< message completed and successfully lexed + NeedMoreData, ///< message incomplete yet, waiting for another byte to come + Error, ///< input character broke message decoding +}; + +/// Protocol class is responsible for creating/decoding messages in Rx/Tx buffer +/// Beware - in the decoding more, it is meant to be a statefull instance which works through public methods +/// processing one input byte per call +class Protocol { +public: + inline Protocol() + : rqState(RequestStates::Code) + , requestMsg(RequestMsgCodes::unknown, 0) + , rspState(ResponseStates::RequestCode) + , responseMsg(RequestMsg(RequestMsgCodes::unknown, 0), ResponseMsgParamCodes::unknown, 0) { + } + + /// Takes the input byte c and steps one step through the state machine + /// @returns state of the message being decoded + DecodeStatus DecodeRequest(uint8_t c); + + /// Decodes response message in rxbuff + /// @returns decoded response message structure + DecodeStatus DecodeResponse(uint8_t c); + + /// Encodes request message msg into txbuff memory + /// It is expected the txbuff is large enough to fit the message + /// @returns number of bytes written into txbuff + static uint8_t EncodeRequest(const RequestMsg &msg, uint8_t *txbuff); + + /// Encode generic response Command Accepted or Rejected + /// @param msg source request message for this response + /// @returns number of bytes written into txbuff + static uint8_t EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff); + + /// Encode response to Read FINDA query + /// @param msg source request message for this response + /// @param findaValue 1/0 (on/off) status of FINDA + /// @returns number of bytes written into txbuff + static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff); + + /// Encode response to Version query + /// @param msg source request message for this response + /// @param value version number (0-255) + /// @returns number of bytes written into txbuff + static uint8_t EncodeResponseVersion(const RequestMsg &msg, uint8_t value, uint8_t *txbuff); + + /// Encode response to Query operation status + /// @param msg source request message for this response + /// @param code status of operation (Processing, Error, Finished) + /// @param value related to status of operation(e.g. error code or progress) + /// @returns number of bytes written into txbuff + static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff); + + /// @returns the most recently lexed request message + inline const RequestMsg GetRequestMsg() const { return requestMsg; } + + /// @returns the most recently lexed response message + inline const ResponseMsg GetResponseMsg() const { return responseMsg; } + +private: + enum class RequestStates : uint8_t { + Code, ///< starting state - expects message code + Value, ///< expecting code value + Error ///< automaton in error state }; - enum class ResponseMsgParamCodes : uint8_t { - unknown = 0, - Processing = 'P', - Error = 'E', - Finished = 'F', - Accepted = 'A', - Rejected = 'R' + RequestStates rqState; + RequestMsg requestMsg; + + enum class ResponseStates : uint8_t { + RequestCode, ///< starting state - expects message code + RequestValue, ///< expecting code value + ParamCode, ///< expecting param code + ParamValue, ///< expecting param value + Error ///< automaton in error state }; - /// A request message - /// Requests are being sent by the printer into the MMU - /// It is the same structure as the generic Msg - struct RequestMsg { - RequestMsgCodes code; - uint8_t value; - inline RequestMsg(RequestMsgCodes code, uint8_t value) - : code(code) - , value(value) {} - }; - - /// A response message - /// Responses are being sent from the MMU into the printer as a response to a request message - struct ResponseMsg { - RequestMsg request; ///< response is always preceeded by the request message - ResponseMsgParamCodes paramCode; ///< parameters of reply - uint8_t paramValue; ///< parameters of reply - inline ResponseMsg(RequestMsg request, ResponseMsgParamCodes paramCode, uint8_t paramValue) - : request(request) - , paramCode(paramCode) - , paramValue(paramValue) {} - }; - - /// Message decoding return value - enum class DecodeStatus : uint_fast8_t { - MessageCompleted, ///< message completed and successfully lexed - NeedMoreData, ///< message incomplete yet, waiting for another byte to come - Error, ///< input character broke message decoding - }; - - /// Protocol class is responsible for creating/decoding messages in Rx/Tx buffer - /// Beware - in the decoding more, it is meant to be a statefull instance which works through public methods - /// processing one input byte per call - class Protocol { - public: - inline Protocol() - : rqState(RequestStates::Code) - , requestMsg(RequestMsgCodes::unknown, 0) - , rspState(ResponseStates::RequestCode) - , responseMsg(RequestMsg(RequestMsgCodes::unknown, 0), ResponseMsgParamCodes::unknown, 0) { - } - - /// Takes the input byte c and steps one step through the state machine - /// @returns state of the message being decoded - DecodeStatus DecodeRequest(uint8_t c); - - /// Decodes response message in rxbuff - /// @returns decoded response message structure - DecodeStatus DecodeResponse(uint8_t c); - - /// Encodes request message msg into txbuff memory - /// It is expected the txbuff is large enough to fit the message - /// @returns number of bytes written into txbuff - static uint8_t EncodeRequest(const RequestMsg &msg, uint8_t *txbuff); - - /// Encode generic response Command Accepted or Rejected - /// @param msg source request message for this response - /// @returns number of bytes written into txbuff - static uint8_t EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff); - - /// Encode response to Read FINDA query - /// @param msg source request message for this response - /// @param findaValue 1/0 (on/off) status of FINDA - /// @returns number of bytes written into txbuff - static uint8_t EncodeResponseReadFINDA(const RequestMsg &msg, uint8_t findaValue, uint8_t *txbuff); - - /// Encode response to Version query - /// @param msg source request message for this response - /// @param value version number (0-255) - /// @returns number of bytes written into txbuff - static uint8_t EncodeResponseVersion(const RequestMsg &msg, uint8_t value, uint8_t *txbuff); - - /// Encode response to Query operation status - /// @param msg source request message for this response - /// @param code status of operation (Processing, Error, Finished) - /// @param value related to status of operation(e.g. error code or progress) - /// @returns number of bytes written into txbuff - static uint8_t EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff); - - /// @returns the most recently lexed request message - inline const RequestMsg GetRequestMsg() const { return requestMsg; } - - /// @returns the most recently lexed response message - inline const ResponseMsg GetResponseMsg() const { return responseMsg; } - - private: - enum class RequestStates : uint8_t { - Code, ///< starting state - expects message code - Value, ///< expecting code value - Error ///< automaton in error state - }; - - RequestStates rqState; - RequestMsg requestMsg; - - enum class ResponseStates : uint8_t { - RequestCode, ///< starting state - expects message code - RequestValue, ///< expecting code value - ParamCode, ///< expecting param code - ParamValue, ///< expecting param value - Error ///< automaton in error state - }; - - ResponseStates rspState; - ResponseMsg responseMsg; - }; + ResponseStates rspState; + ResponseMsg responseMsg; +}; } // namespace protocol } // namespace modules diff --git a/tests/unit/modules/buttons/stub_adc.cpp b/tests/unit/modules/buttons/stub_adc.cpp index 5006f68..5cf7593 100644 --- a/tests/unit/modules/buttons/stub_adc.cpp +++ b/tests/unit/modules/buttons/stub_adc.cpp @@ -5,28 +5,28 @@ namespace hal { namespace adc { - static TADCData values2Return; - static TADCData::const_iterator rdptr = values2Return.cbegin(); - static uint8_t oversampleFactor = 1; - static uint8_t oversample = 1; ///< current count of oversampled values returned from the ADC - will get filled with oversampleFactor once it reaches zero +static TADCData values2Return; +static TADCData::const_iterator rdptr = values2Return.cbegin(); +static uint8_t oversampleFactor = 1; +static uint8_t oversample = 1; ///< current count of oversampled values returned from the ADC - will get filled with oversampleFactor once it reaches zero - void ReinitADC(TADCData &&d, uint8_t ovsmpl) { - values2Return = std::move(d); - oversampleFactor = ovsmpl; - oversample = ovsmpl; - rdptr = values2Return.cbegin(); - } +void ReinitADC(TADCData &&d, uint8_t ovsmpl) { + values2Return = std::move(d); + oversampleFactor = ovsmpl; + oversample = ovsmpl; + rdptr = values2Return.cbegin(); +} - /// ADC access routines - uint16_t ReadADC(uint8_t /*adc*/) { - if (!oversample) { - ++rdptr; - oversample = oversampleFactor; - } else { - --oversample; - } - return rdptr != values2Return.end() ? *rdptr : 1023; +/// ADC access routines +uint16_t ReadADC(uint8_t /*adc*/) { + if (!oversample) { + ++rdptr; + oversample = oversampleFactor; + } else { + --oversample; } + return rdptr != values2Return.end() ? *rdptr : 1023; +} } // namespace adc } // namespace hal diff --git a/tests/unit/modules/buttons/stub_adc.h b/tests/unit/modules/buttons/stub_adc.h index ae3b658..4f76f70 100644 --- a/tests/unit/modules/buttons/stub_adc.h +++ b/tests/unit/modules/buttons/stub_adc.h @@ -6,9 +6,9 @@ namespace hal { namespace adc { - using TADCData = std::vector; +using TADCData = std::vector; - void ReinitADC(TADCData &&d, uint8_t ovsmpl); +void ReinitADC(TADCData &&d, uint8_t ovsmpl); } // namespace adc } // namespace hal