Reformat sources to fit the new namespace formatting rules
parent
acc33bfacb
commit
9226230fd5
|
|
@ -3,7 +3,7 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
uint16_t ReadADC(uint8_t adc) { return 0; }
|
uint16_t ReadADC(uint8_t adc) { return 0; }
|
||||||
|
|
||||||
} // namespace adc
|
} // namespace adc
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
/// ADC access routines
|
/// ADC access routines
|
||||||
uint16_t ReadADC(uint8_t adc);
|
uint16_t ReadADC(uint8_t adc);
|
||||||
|
|
||||||
} // namespace adc
|
} // namespace adc
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace CPU
|
} // namespace CPU
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -4,72 +4,72 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace usart {
|
namespace usart {
|
||||||
|
|
||||||
USART usart1;
|
USART usart1;
|
||||||
|
|
||||||
uint8_t USART::Read() {
|
uint8_t USART::Read() {
|
||||||
uint8_t c = 0;
|
uint8_t c = 0;
|
||||||
rx_buf.ConsumeFirst(c);
|
rx_buf.ConsumeFirst(c);
|
||||||
return 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) {
|
// If the output buffer is full, there's nothing for it other than to
|
||||||
_written = true;
|
// wait for the interrupt handler to empty it a bit
|
||||||
// If the buffer and the data register is empty, just write the byte
|
while (!tx_buf.push_back_DontRewrite(c)) {
|
||||||
// to the data register and be done. This shortcut helps
|
if (bit_is_clear(SREG, SREG_I)) {
|
||||||
// significantly improve the effective datarate at high (>
|
// Interrupts are disabled, so we'll have to poll the data
|
||||||
// 500kbit/s) bitrates, where interrupt overhead becomes a slowdown.
|
// register empty flag ourselves. If it is set, pretend an
|
||||||
if (tx_buf.IsEmpty() && (husart->UCSRxA & (1 << 5))) {
|
// interrupt has happened and call the handler to free up
|
||||||
husart->UDRx = c;
|
// space for us.
|
||||||
husart->UCSRxA |= (1 << 6);
|
if (husart->UCSRxA & (1 << 5)) {
|
||||||
return;
|
ISR_UDRE();
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
}
|
} 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++);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 usart
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace cpu {
|
namespace cpu {
|
||||||
|
|
||||||
/// CPU init routines (not really necessary for the AVR)
|
/// CPU init routines (not really necessary for the AVR)
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,10 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace EEPROM {
|
namespace EEPROM {
|
||||||
|
|
||||||
/// EEPROM interface
|
/// EEPROM interface
|
||||||
void WriteByte(uint16_t addr, uint8_t value);
|
void WriteByte(uint16_t addr, uint8_t value);
|
||||||
void UpdateByte(uint16_t addr, uint8_t value);
|
void UpdateByte(uint16_t addr, uint8_t value);
|
||||||
uint8_t ReadByte(uint16_t addr);
|
uint8_t ReadByte(uint16_t addr);
|
||||||
|
|
||||||
} // namespace EEPROM
|
} // namespace EEPROM
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
118
src/hal/gpio.h
118
src/hal/gpio.h
|
|
@ -5,72 +5,72 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace gpio {
|
namespace gpio {
|
||||||
|
|
||||||
struct GPIO_TypeDef {
|
struct GPIO_TypeDef {
|
||||||
volatile uint8_t PINx;
|
volatile uint8_t PINx;
|
||||||
volatile uint8_t DDRx;
|
volatile uint8_t DDRx;
|
||||||
volatile uint8_t PORTx;
|
volatile uint8_t PORTx;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Mode : uint8_t {
|
enum class Mode : uint8_t {
|
||||||
input = 0,
|
input = 0,
|
||||||
output,
|
output,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Pull : uint8_t {
|
enum class Pull : uint8_t {
|
||||||
none = 0,
|
none = 0,
|
||||||
up,
|
up,
|
||||||
down, //not available on the AVR
|
down, //not available on the AVR
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Level : uint8_t {
|
enum class Level : uint8_t {
|
||||||
low = 0,
|
low = 0,
|
||||||
high,
|
high,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GPIO_InitTypeDef {
|
struct GPIO_InitTypeDef {
|
||||||
Mode mode;
|
Mode mode;
|
||||||
Pull pull;
|
Pull pull;
|
||||||
Level level;
|
Level level;
|
||||||
inline GPIO_InitTypeDef(Mode mode, Pull pull)
|
inline GPIO_InitTypeDef(Mode mode, Pull pull)
|
||||||
: mode(mode)
|
: mode(mode)
|
||||||
, pull(pull) {};
|
, pull(pull) {};
|
||||||
inline GPIO_InitTypeDef(Mode mode, Level level)
|
inline GPIO_InitTypeDef(Mode mode, Level level)
|
||||||
: mode(mode)
|
: mode(mode)
|
||||||
, level(level) {};
|
, level(level) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GPIO_pin {
|
struct GPIO_pin {
|
||||||
GPIO_TypeDef *const port;
|
GPIO_TypeDef *const port;
|
||||||
const uint8_t pin;
|
const uint8_t pin;
|
||||||
inline GPIO_pin(GPIO_TypeDef *const port, const uint8_t pin)
|
inline GPIO_pin(GPIO_TypeDef *const port, const uint8_t pin)
|
||||||
: port(port)
|
: port(port)
|
||||||
, pin(pin) {};
|
, pin(pin) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) {
|
__attribute__((always_inline)) inline void WritePin(const GPIO_pin portPin, Level level) {
|
||||||
if (level == Level::high)
|
if (level == Level::high)
|
||||||
portPin.port->PORTx |= (1 << portPin.pin);
|
portPin.port->PORTx |= (1 << portPin.pin);
|
||||||
else
|
else
|
||||||
portPin.port->PORTx &= ~(1 << portPin.pin);
|
portPin.port->PORTx &= ~(1 << portPin.pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) {
|
__attribute__((always_inline)) inline Level ReadPin(const GPIO_pin portPin) {
|
||||||
return (Level)(portPin.port->PINx & (1 << portPin.pin));
|
return (Level)(portPin.port->PINx & (1 << portPin.pin));
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) {
|
__attribute__((always_inline)) inline void TogglePin(const GPIO_pin portPin) {
|
||||||
portPin.port->PINx |= (1 << portPin.pin);
|
portPin.port->PINx |= (1 << portPin.pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline)) inline void Init(const GPIO_pin portPin, GPIO_InitTypeDef GPIO_Init) {
|
__attribute__((always_inline)) inline void Init(const GPIO_pin portPin, GPIO_InitTypeDef GPIO_Init) {
|
||||||
if (GPIO_Init.mode == Mode::output) {
|
if (GPIO_Init.mode == Mode::output) {
|
||||||
WritePin(portPin, GPIO_Init.level);
|
WritePin(portPin, GPIO_Init.level);
|
||||||
portPin.port->DDRx |= (1 << portPin.pin);
|
portPin.port->DDRx |= (1 << portPin.pin);
|
||||||
} else {
|
} else {
|
||||||
portPin.port->DDRx &= ~(1 << portPin.pin);
|
portPin.port->DDRx &= ~(1 << portPin.pin);
|
||||||
WritePin(portPin, (Level)GPIO_Init.pull);
|
WritePin(portPin, (Level)GPIO_Init.pull);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,42 +6,42 @@
|
||||||
|
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace spi {
|
namespace spi {
|
||||||
struct SPI_TypeDef {
|
struct SPI_TypeDef {
|
||||||
volatile uint8_t SPCRx;
|
volatile uint8_t SPCRx;
|
||||||
volatile uint8_t SPSRx;
|
volatile uint8_t SPSRx;
|
||||||
volatile uint8_t SPDRx;
|
volatile uint8_t SPDRx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SPI_InitTypeDef {
|
struct SPI_InitTypeDef {
|
||||||
hal::gpio::GPIO_pin miso_pin;
|
hal::gpio::GPIO_pin miso_pin;
|
||||||
hal::gpio::GPIO_pin mosi_pin;
|
hal::gpio::GPIO_pin mosi_pin;
|
||||||
hal::gpio::GPIO_pin sck_pin;
|
hal::gpio::GPIO_pin sck_pin;
|
||||||
hal::gpio::GPIO_pin ss_pin;
|
hal::gpio::GPIO_pin ss_pin;
|
||||||
uint8_t prescaler;
|
uint8_t prescaler;
|
||||||
uint8_t cpha;
|
uint8_t cpha;
|
||||||
uint8_t cpol;
|
uint8_t cpol;
|
||||||
};
|
};
|
||||||
|
|
||||||
__attribute__((always_inline)) inline void Init(SPI_TypeDef *const hspi, SPI_InitTypeDef *const conf) {
|
__attribute__((always_inline)) inline void Init(SPI_TypeDef *const hspi, SPI_InitTypeDef *const conf) {
|
||||||
using namespace hal;
|
using namespace hal;
|
||||||
gpio::Init(conf->miso_pin, gpio::GPIO_InitTypeDef(gpio::Mode::input, gpio::Pull::none));
|
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->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->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.
|
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 spi2x = (conf->prescaler == 7) ? 0 : (conf->prescaler & 0x01);
|
||||||
const uint8_t spr = ((conf->prescaler - 1) >> 1) & 0x03;
|
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->SPCRx = (0 << SPIE) | (1 << SPE) | (0 << DORD) | (1 << MSTR) | ((conf->cpol & 0x01) << CPOL) | ((conf->cpha & 0x01) << CPHA) | (spr << SPR0);
|
||||||
hspi->SPSRx = (spi2x << SPI2X);
|
hspi->SPSRx = (spi2x << SPI2X);
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((always_inline)) inline uint8_t TxRx(SPI_TypeDef *const hspi, uint8_t val) {
|
__attribute__((always_inline)) inline uint8_t TxRx(SPI_TypeDef *const hspi, uint8_t val) {
|
||||||
hspi->SPDRx = val;
|
hspi->SPDRx = val;
|
||||||
while (!(hspi->SPSRx & (1 << SPIF)))
|
while (!(hspi->SPSRx & (1 << SPIF)))
|
||||||
;
|
;
|
||||||
return hspi->SPDRx;
|
return hspi->SPDRx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,10 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace timers {
|
namespace timers {
|
||||||
|
|
||||||
/// timers
|
/// timers
|
||||||
void ConfigureTimer(uint8_t timer /* some config struct */);
|
void ConfigureTimer(uint8_t timer /* some config struct */);
|
||||||
void StartTimer(uint8_t timer);
|
void StartTimer(uint8_t timer);
|
||||||
void StopTimer(uint8_t timer);
|
void StopTimer(uint8_t timer);
|
||||||
|
|
||||||
} // namespace cpu
|
} // namespace cpu
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
174
src/hal/usart.h
174
src/hal/usart.h
|
|
@ -10,95 +10,95 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace usart {
|
namespace usart {
|
||||||
|
|
||||||
class USART {
|
class USART {
|
||||||
public:
|
public:
|
||||||
struct USART_TypeDef {
|
struct USART_TypeDef {
|
||||||
volatile uint8_t UCSRxA;
|
volatile uint8_t UCSRxA;
|
||||||
volatile uint8_t UCSRxB;
|
volatile uint8_t UCSRxB;
|
||||||
volatile uint8_t UCSRxC;
|
volatile uint8_t UCSRxC;
|
||||||
volatile uint8_t UCSRxD;
|
volatile uint8_t UCSRxD;
|
||||||
volatile uint16_t UBRRx;
|
volatile uint16_t UBRRx;
|
||||||
volatile uint8_t UDRx;
|
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<uint8_t, 32> tx_buf;
|
|
||||||
CircleBuffer<uint8_t, 32> rx_buf;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// beware - normally we'd make a singleton, but avr-gcc generates suboptimal code for them, therefore we only keep this extern variable
|
struct USART_InitTypeDef {
|
||||||
extern USART usart1;
|
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<uint8_t, 32> tx_buf;
|
||||||
|
CircleBuffer<uint8_t, 32> 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 usart
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace watchdog {
|
namespace watchdog {
|
||||||
|
|
||||||
/// watchdog interface
|
/// watchdog interface
|
||||||
void ConfigureWatchDog(uint16_t period);
|
void ConfigureWatchDog(uint16_t period);
|
||||||
void ResetWatchDog();
|
void ResetWatchDog();
|
||||||
|
|
||||||
} // namespace watchdog
|
} // namespace watchdog
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -3,69 +3,69 @@
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace buttons {
|
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
|
// original idea from: https://www.eeweb.com/debouncing-push-buttons-using-a-state-machine-approach
|
||||||
void Button::Step(uint16_t time, bool press) {
|
void Button::Step(uint16_t time, bool press) {
|
||||||
switch (f.state) {
|
switch (f.state) {
|
||||||
case State::Waiting:
|
case State::Waiting:
|
||||||
if (press) {
|
if (press) {
|
||||||
f.state = State::Detected;
|
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;
|
|
||||||
timeLastChange = time;
|
timeLastChange = time;
|
||||||
f.tmp = false;
|
f.tmp = press;
|
||||||
break;
|
}
|
||||||
default:
|
break;
|
||||||
|
case State::Detected:
|
||||||
|
if (f.tmp == press) {
|
||||||
|
if (time - timeLastChange > debounce) {
|
||||||
|
f.state = State::WaitForRelease;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
f.state = State::Waiting;
|
f.state = State::Waiting;
|
||||||
timeLastChange = time;
|
|
||||||
f.tmp = false;
|
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
|
case State::WaitForRelease:
|
||||||
int8_t Buttons::Sample(uint16_t rawADC) {
|
if (!press) {
|
||||||
// decode 3 buttons' levels from one ADC
|
f.state = State::Update;
|
||||||
// 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::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 buttons
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
|
|
||||||
|
|
@ -9,67 +9,67 @@
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace buttons {
|
namespace buttons {
|
||||||
|
|
||||||
struct Button {
|
struct Button {
|
||||||
inline constexpr Button()
|
inline constexpr Button()
|
||||||
: timeLastChange(0) {}
|
: timeLastChange(0) {}
|
||||||
|
|
||||||
/// @returns true if button is currently considered as pressed
|
/// @returns true if button is currently considered as pressed
|
||||||
inline bool Pressed() const { return f.state == State::WaitForRelease; }
|
inline bool Pressed() const { return f.state == State::WaitForRelease; }
|
||||||
|
|
||||||
/// State machine stepping routine
|
/// State machine stepping routine
|
||||||
void Step(uint16_t time, bool press);
|
void Step(uint16_t time, bool press);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// time interval for debouncing @@TODO specify units
|
/// time interval for debouncing @@TODO specify units
|
||||||
constexpr static const uint16_t debounce = 100;
|
constexpr static const uint16_t debounce = 100;
|
||||||
|
|
||||||
/// States of the debouncing automaton
|
/// States of the debouncing automaton
|
||||||
/// Intentionally not modeled as an enum class
|
/// Intentionally not modeled as an enum class
|
||||||
/// as it would impose additional casts which do not play well with the struct Flags
|
/// as it would impose additional casts which do not play well with the struct Flags
|
||||||
/// and would make the code less readable
|
/// and would make the code less readable
|
||||||
enum State { Waiting = 0,
|
enum State { Waiting = 0,
|
||||||
Detected,
|
Detected,
|
||||||
WaitForRelease,
|
WaitForRelease,
|
||||||
Update };
|
Update };
|
||||||
|
|
||||||
/// The sole purpose of this data struct is to save RAM by compressing several flags into one byte on the AVR
|
/// The sole purpose of this data struct is to save RAM by compressing several flags into one byte on the AVR
|
||||||
struct Flags {
|
struct Flags {
|
||||||
uint8_t state : 2; ///< state of the button
|
uint8_t state : 2; ///< state of the button
|
||||||
uint8_t tmp : 1; ///< temporary state of button before the debouncing state machine finishes
|
uint8_t tmp : 1; ///< temporary state of button before the debouncing state machine finishes
|
||||||
inline constexpr Flags()
|
inline constexpr Flags()
|
||||||
: state(State::Waiting)
|
: state(State::Waiting)
|
||||||
, tmp(false) {}
|
, 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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Buttons {
|
/// Flags and state of the debouncing automaton
|
||||||
constexpr static const uint8_t N = 3; ///< number of buttons currently supported
|
Flags f;
|
||||||
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
|
|
||||||
|
|
||||||
public:
|
/// Timestamp of the last change of ADC state for this button
|
||||||
inline constexpr Buttons() = default;
|
uint16_t timeLastChange;
|
||||||
|
};
|
||||||
|
|
||||||
/// State machine step - reads the ADC, processes debouncing, updates states of individual buttons
|
class Buttons {
|
||||||
void Step(uint16_t rawADC);
|
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
|
public:
|
||||||
/// @@TODO add range checking if necessary
|
inline constexpr Buttons() = default;
|
||||||
inline bool ButtonPressed(uint8_t index) const { return buttons[index].Pressed(); }
|
|
||||||
|
|
||||||
private:
|
/// State machine step - reads the ADC, processes debouncing, updates states of individual buttons
|
||||||
Button buttons[N];
|
void Step(uint16_t rawADC);
|
||||||
|
|
||||||
/// Call to the ADC and decode its output into a button index
|
/// @return true if button at index is pressed
|
||||||
/// @returns index of the button pressed or -1 in case no button is pressed
|
/// @@TODO add range checking if necessary
|
||||||
static int8_t Sample(uint16_t rawADC);
|
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 buttons
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,48 @@
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace leds {
|
namespace leds {
|
||||||
|
|
||||||
void LED::SetMode(Mode mode) {
|
void LED::SetMode(Mode mode) {
|
||||||
state.mode = mode;
|
state.mode = mode;
|
||||||
// set initial state of LEDs correctly - transition from one mode to another
|
// set initial state of LEDs correctly - transition from one mode to another
|
||||||
switch (state.mode) {
|
switch (state.mode) {
|
||||||
case Mode::blink1:
|
case Mode::blink1:
|
||||||
case Mode::off:
|
case Mode::off:
|
||||||
state.on = 0;
|
state.on = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Mode::blink0:
|
case Mode::blink0:
|
||||||
case Mode::on:
|
case Mode::on:
|
||||||
state.on = 1;
|
state.on = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool LED::Step(bool oddPeriod) {
|
bool LED::Step(bool oddPeriod) {
|
||||||
switch (state.mode) {
|
switch (state.mode) {
|
||||||
// on and off don't change while stepping
|
// on and off don't change while stepping
|
||||||
case Mode::blink0:
|
case Mode::blink0:
|
||||||
state.on = oddPeriod;
|
state.on = oddPeriod;
|
||||||
break;
|
break;
|
||||||
case Mode::blink1:
|
case Mode::blink1:
|
||||||
state.on = !oddPeriod;
|
state.on = !oddPeriod;
|
||||||
break;
|
break;
|
||||||
default: // do nothing
|
default: // do nothing
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t LEDs::Step(uint8_t delta_ms) {
|
uint16_t LEDs::Step(uint8_t delta_ms) {
|
||||||
ms += delta_ms;
|
ms += delta_ms;
|
||||||
bool oddPeriod = ((ms / 1000U) & 0x01U) != 0;
|
bool oddPeriod = ((ms / 1000U) & 0x01U) != 0;
|
||||||
uint16_t result = 0;
|
uint16_t result = 0;
|
||||||
for (uint8_t i = 0; i < ledPairs * 2; ++i) {
|
for (uint8_t i = 0; i < ledPairs * 2; ++i) {
|
||||||
result <<= 1;
|
result <<= 1;
|
||||||
result |= leds[i].Step(oddPeriod);
|
result |= leds[i].Step(oddPeriod);
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace leds
|
} // namespace leds
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
|
|
||||||
|
|
@ -13,176 +13,197 @@
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace protocol {
|
namespace protocol {
|
||||||
|
|
||||||
// decoding automaton
|
// decoding automaton
|
||||||
// states: input -> transition into state
|
// states: input -> transition into state
|
||||||
// Code QTLMUXPSBEWK -> msgcode
|
// Code QTLMUXPSBEWK -> msgcode
|
||||||
// \n ->start
|
// \n ->start
|
||||||
// * ->error
|
// * ->error
|
||||||
// error \n ->start
|
// error \n ->start
|
||||||
// * ->error
|
// * ->error
|
||||||
// msgcode 0-9 ->msgvalue
|
// msgcode 0-9 ->msgvalue
|
||||||
// * ->error
|
// * ->error
|
||||||
// msgvalue 0-9 ->msgvalue
|
// msgvalue 0-9 ->msgvalue
|
||||||
// \n ->start successfully accepted command
|
// \n ->start successfully accepted command
|
||||||
|
|
||||||
DecodeStatus Protocol::DecodeRequest(uint8_t c) {
|
DecodeStatus Protocol::DecodeRequest(uint8_t c) {
|
||||||
switch (rqState) {
|
switch (rqState) {
|
||||||
case RequestStates::Code:
|
case RequestStates::Code:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'Q':
|
case 'Q':
|
||||||
case 'T':
|
case 'T':
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'M':
|
case 'M':
|
||||||
case 'U':
|
case 'U':
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'S':
|
case 'S':
|
||||||
case 'B':
|
case 'B':
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'W':
|
case 'W':
|
||||||
case 'K':
|
case 'K':
|
||||||
requestMsg.code = (RequestMsgCodes)c;
|
requestMsg.code = (RequestMsgCodes)c;
|
||||||
requestMsg.value = 0;
|
requestMsg.value = 0;
|
||||||
rqState = RequestStates::Value;
|
rqState = RequestStates::Value;
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
default:
|
default:
|
||||||
requestMsg.code = RequestMsgCodes::unknown;
|
requestMsg.code = RequestMsgCodes::unknown;
|
||||||
rqState = RequestStates::Error;
|
rqState = RequestStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
case RequestStates::Value:
|
case RequestStates::Value:
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
requestMsg.value *= 10;
|
requestMsg.value *= 10;
|
||||||
requestMsg.value += c - '0';
|
requestMsg.value += c - '0';
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
rqState = RequestStates::Code;
|
rqState = RequestStates::Code;
|
||||||
return DecodeStatus::MessageCompleted;
|
return DecodeStatus::MessageCompleted;
|
||||||
} else {
|
} else {
|
||||||
requestMsg.code = RequestMsgCodes::unknown;
|
requestMsg.code = RequestMsgCodes::unknown;
|
||||||
rqState = RequestStates::Error;
|
rqState = RequestStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
default: //case error:
|
default: //case error:
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
rqState = RequestStates::Code;
|
rqState = RequestStates::Code;
|
||||||
return DecodeStatus::MessageCompleted;
|
return DecodeStatus::MessageCompleted;
|
||||||
} else {
|
} else {
|
||||||
requestMsg.code = RequestMsgCodes::unknown;
|
requestMsg.code = RequestMsgCodes::unknown;
|
||||||
rqState = RequestStates::Error;
|
rqState = RequestStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Protocol::EncodeRequest(const RequestMsg &msg, uint8_t *txbuff) {
|
uint8_t Protocol::EncodeRequest(const RequestMsg &msg, uint8_t *txbuff) {
|
||||||
txbuff[0] = (uint8_t)msg.code;
|
txbuff[0] = (uint8_t)msg.code;
|
||||||
txbuff[1] = msg.value + '0';
|
txbuff[1] = msg.value + '0';
|
||||||
txbuff[2] = '\n';
|
txbuff[2] = '\n';
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
DecodeStatus Protocol::DecodeResponse(uint8_t c) {
|
DecodeStatus Protocol::DecodeResponse(uint8_t c) {
|
||||||
switch (rspState) {
|
switch (rspState) {
|
||||||
case ResponseStates::RequestCode:
|
case ResponseStates::RequestCode:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'Q':
|
case 'Q':
|
||||||
case 'T':
|
case 'T':
|
||||||
case 'L':
|
case 'L':
|
||||||
case 'M':
|
case 'M':
|
||||||
case 'U':
|
case 'U':
|
||||||
case 'X':
|
case 'X':
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'S':
|
case 'S':
|
||||||
case 'B':
|
case 'B':
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'W':
|
case 'W':
|
||||||
case 'K':
|
case 'K':
|
||||||
responseMsg.request.code = (RequestMsgCodes)c;
|
responseMsg.request.code = (RequestMsgCodes)c;
|
||||||
responseMsg.request.value = 0;
|
responseMsg.request.value = 0;
|
||||||
rspState = ResponseStates::RequestValue;
|
rspState = ResponseStates::RequestValue;
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
default:
|
default:
|
||||||
rspState = ResponseStates::Error;
|
rspState = ResponseStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
case ResponseStates::RequestValue:
|
case ResponseStates::RequestValue:
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
responseMsg.request.value *= 10;
|
responseMsg.request.value *= 10;
|
||||||
responseMsg.request.value += c - '0';
|
responseMsg.request.value += c - '0';
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
} else if (c == ' ') {
|
} else if (c == ' ') {
|
||||||
rspState = ResponseStates::ParamCode;
|
rspState = ResponseStates::ParamCode;
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
} else {
|
} else {
|
||||||
rspState = ResponseStates::Error;
|
rspState = ResponseStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
case ResponseStates::ParamCode:
|
case ResponseStates::ParamCode:
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'P':
|
case 'P':
|
||||||
case 'E':
|
case 'E':
|
||||||
case 'F':
|
case 'F':
|
||||||
case 'A':
|
case 'A':
|
||||||
case 'R':
|
case 'R':
|
||||||
rspState = ResponseStates::ParamValue;
|
rspState = ResponseStates::ParamValue;
|
||||||
responseMsg.paramCode = (ResponseMsgParamCodes)c;
|
responseMsg.paramCode = (ResponseMsgParamCodes)c;
|
||||||
responseMsg.paramValue = 0;
|
responseMsg.paramValue = 0;
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
default:
|
default:
|
||||||
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
||||||
rspState = ResponseStates::Error;
|
rspState = ResponseStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
case ResponseStates::ParamValue:
|
case ResponseStates::ParamValue:
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
responseMsg.paramValue *= 10;
|
responseMsg.paramValue *= 10;
|
||||||
responseMsg.paramValue += c - '0';
|
responseMsg.paramValue += c - '0';
|
||||||
return DecodeStatus::NeedMoreData;
|
return DecodeStatus::NeedMoreData;
|
||||||
} else if (c == '\n') {
|
} else if (c == '\n') {
|
||||||
rspState = ResponseStates::RequestCode;
|
rspState = ResponseStates::RequestCode;
|
||||||
return DecodeStatus::MessageCompleted;
|
return DecodeStatus::MessageCompleted;
|
||||||
} else {
|
} else {
|
||||||
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
||||||
rspState = ResponseStates::Error;
|
rspState = ResponseStates::Error;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
}
|
||||||
default: //case error:
|
default: //case error:
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
rspState = ResponseStates::RequestCode;
|
rspState = ResponseStates::RequestCode;
|
||||||
return DecodeStatus::MessageCompleted;
|
return DecodeStatus::MessageCompleted;
|
||||||
} else {
|
} else {
|
||||||
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
responseMsg.paramCode = ResponseMsgParamCodes::unknown;
|
||||||
return DecodeStatus::Error;
|
return DecodeStatus::Error;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t Protocol::EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff) {
|
uint8_t Protocol::EncodeResponseCmdAR(const RequestMsg &msg, ResponseMsgParamCodes ar, uint8_t *txbuff) {
|
||||||
txbuff[0] = (uint8_t)msg.code;
|
txbuff[0] = (uint8_t)msg.code;
|
||||||
txbuff[1] = msg.value + '0';
|
txbuff[1] = msg.value + '0';
|
||||||
txbuff[2] = ' ';
|
txbuff[2] = ' ';
|
||||||
txbuff[3] = (uint8_t)ar;
|
txbuff[3] = (uint8_t)ar;
|
||||||
txbuff[4] = '\n';
|
txbuff[4] = '\n';
|
||||||
return 5;
|
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) {
|
uint8_t Protocol::EncodeResponseQueryOperation(const RequestMsg &msg, ResponseMsgParamCodes code, uint8_t value, uint8_t *txbuff) {
|
||||||
txbuff[0] = (uint8_t)msg.code;
|
txbuff[0] = (uint8_t)msg.code;
|
||||||
txbuff[1] = msg.value + '0';
|
txbuff[1] = msg.value + '0';
|
||||||
txbuff[2] = ' ';
|
txbuff[2] = ' ';
|
||||||
txbuff[3] = (uint8_t)ResponseMsgParamCodes::Accepted;
|
txbuff[3] = (uint8_t)code;
|
||||||
txbuff[4] = findaValue + '0';
|
uint8_t *dst = txbuff + 4;
|
||||||
txbuff[5] = '\n';
|
if (code != ResponseMsgParamCodes::Finished) {
|
||||||
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) {
|
if (value < 10) {
|
||||||
*dst++ = value + '0';
|
*dst++ = value + '0';
|
||||||
} else if (value < 100) {
|
} else if (value < 100) {
|
||||||
|
|
@ -193,31 +214,10 @@ namespace protocol {
|
||||||
*dst++ = (value / 10) % 10 + '0';
|
*dst++ = (value / 10) % 10 + '0';
|
||||||
*dst++ = value % 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 protocol
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
|
|
||||||
|
|
@ -9,137 +9,137 @@
|
||||||
namespace modules {
|
namespace modules {
|
||||||
namespace protocol {
|
namespace protocol {
|
||||||
|
|
||||||
enum class RequestMsgCodes : uint8_t {
|
enum class RequestMsgCodes : uint8_t {
|
||||||
unknown = 0,
|
unknown = 0,
|
||||||
Query = 'Q',
|
Query = 'Q',
|
||||||
Tool = 'T',
|
Tool = 'T',
|
||||||
Load = 'L',
|
Load = 'L',
|
||||||
Mode = 'M',
|
Mode = 'M',
|
||||||
Unload = 'U',
|
Unload = 'U',
|
||||||
Reset = 'X',
|
Reset = 'X',
|
||||||
Finda = 'P',
|
Finda = 'P',
|
||||||
Version = 'S',
|
Version = 'S',
|
||||||
Button = 'B',
|
Button = 'B',
|
||||||
Eject = 'E',
|
Eject = 'E',
|
||||||
Wait = 'W',
|
Wait = 'W',
|
||||||
Cut = 'K'
|
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 {
|
RequestStates rqState;
|
||||||
unknown = 0,
|
RequestMsg requestMsg;
|
||||||
Processing = 'P',
|
|
||||||
Error = 'E',
|
enum class ResponseStates : uint8_t {
|
||||||
Finished = 'F',
|
RequestCode, ///< starting state - expects message code
|
||||||
Accepted = 'A',
|
RequestValue, ///< expecting code value
|
||||||
Rejected = 'R'
|
ParamCode, ///< expecting param code
|
||||||
|
ParamValue, ///< expecting param value
|
||||||
|
Error ///< automaton in error state
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A request message
|
ResponseStates rspState;
|
||||||
/// Requests are being sent by the printer into the MMU
|
ResponseMsg responseMsg;
|
||||||
/// 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;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace protocol
|
} // namespace protocol
|
||||||
} // namespace modules
|
} // namespace modules
|
||||||
|
|
|
||||||
|
|
@ -5,28 +5,28 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
static TADCData values2Return;
|
static TADCData values2Return;
|
||||||
static TADCData::const_iterator rdptr = values2Return.cbegin();
|
static TADCData::const_iterator rdptr = values2Return.cbegin();
|
||||||
static uint8_t oversampleFactor = 1;
|
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 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) {
|
void ReinitADC(TADCData &&d, uint8_t ovsmpl) {
|
||||||
values2Return = std::move(d);
|
values2Return = std::move(d);
|
||||||
oversampleFactor = ovsmpl;
|
oversampleFactor = ovsmpl;
|
||||||
oversample = ovsmpl;
|
oversample = ovsmpl;
|
||||||
rdptr = values2Return.cbegin();
|
rdptr = values2Return.cbegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ADC access routines
|
/// ADC access routines
|
||||||
uint16_t ReadADC(uint8_t /*adc*/) {
|
uint16_t ReadADC(uint8_t /*adc*/) {
|
||||||
if (!oversample) {
|
if (!oversample) {
|
||||||
++rdptr;
|
++rdptr;
|
||||||
oversample = oversampleFactor;
|
oversample = oversampleFactor;
|
||||||
} else {
|
} else {
|
||||||
--oversample;
|
--oversample;
|
||||||
}
|
|
||||||
return rdptr != values2Return.end() ? *rdptr : 1023;
|
|
||||||
}
|
}
|
||||||
|
return rdptr != values2Return.end() ? *rdptr : 1023;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace adc
|
} // namespace adc
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,9 @@
|
||||||
namespace hal {
|
namespace hal {
|
||||||
namespace adc {
|
namespace adc {
|
||||||
|
|
||||||
using TADCData = std::vector<uint16_t>;
|
using TADCData = std::vector<uint16_t>;
|
||||||
|
|
||||||
void ReinitADC(TADCData &&d, uint8_t ovsmpl);
|
void ReinitADC(TADCData &&d, uint8_t ovsmpl);
|
||||||
|
|
||||||
} // namespace adc
|
} // namespace adc
|
||||||
} // namespace hal
|
} // namespace hal
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue