From 70e3d52dea90ac4e9b5d2722c9705a5206c6fa3b Mon Sep 17 00:00:00 2001 From: BlackMark Date: Mon, 29 Jun 2020 00:33:14 +0200 Subject: [PATCH] Implemented templated vcp wrapper --- AdaptiveBrightnessFirmware/Inc/terminal.hpp | 158 +++++++++ AdaptiveBrightnessFirmware/Inc/uart.hpp | 329 ++++++++++++++++++ .../Inc/uart_config.hpp | 32 ++ AdaptiveBrightnessFirmware/Inc/uart_vcp.hpp | 209 +++++++++++ AdaptiveBrightnessFirmware/Inc/usbd_cdc_if.h | 19 +- AdaptiveBrightnessFirmware/Makefile | 2 +- AdaptiveBrightnessFirmware/Src/main.cpp | 22 +- AdaptiveBrightnessFirmware/Src/uart_vcp.cpp | 10 + AdaptiveBrightnessFirmware/Src/usbd_cdc_if.c | 312 ----------------- 9 files changed, 752 insertions(+), 341 deletions(-) create mode 100644 AdaptiveBrightnessFirmware/Inc/terminal.hpp create mode 100644 AdaptiveBrightnessFirmware/Inc/uart.hpp create mode 100644 AdaptiveBrightnessFirmware/Inc/uart_config.hpp create mode 100644 AdaptiveBrightnessFirmware/Inc/uart_vcp.hpp create mode 100644 AdaptiveBrightnessFirmware/Src/uart_vcp.cpp delete mode 100644 AdaptiveBrightnessFirmware/Src/usbd_cdc_if.c diff --git a/AdaptiveBrightnessFirmware/Inc/terminal.hpp b/AdaptiveBrightnessFirmware/Inc/terminal.hpp new file mode 100644 index 0000000..a191273 --- /dev/null +++ b/AdaptiveBrightnessFirmware/Inc/terminal.hpp @@ -0,0 +1,158 @@ +#pragma once + +#include +#include +#include +#include + +namespace detail { + +constexpr auto ENDL = "\r\n"; +constexpr auto HELP_CMD = "help"; +constexpr auto READ_CMD = "read"; + +constexpr auto VERSION_CMD = "version"; +constexpr auto VERSION = "1.0"; + +static inline bool substringEquals(const char* str1, const char* str2, const size_t& size) +{ + return (std::strncmp(str1, str2, size) == 0); +} + +static inline bool stringEquals(const char* str1, const char* str2, const size_t& size) +{ + if(size == std::strlen(str2)) { + return substringEquals(str1, str2, size); + } + + return false; +} + +} // namespace detail + +template +class Terminal { + public: + static void init() + { + m_serial.init(); + + m_serial << detail::ENDL; + printVersion(); + m_serial << detail::ENDL << "$ "; + } + + static void callback() + { + if(receiveInput()) { + parseInput(); + } + } + + private: + static constexpr auto INPUT_BUFFER_SIZE = 128; + static constexpr auto BACKSPACE = uint8_t{0x7f}; + static constexpr auto CTRL_C = uint8_t{0x03}; + + static Uart m_serial; + static char m_inputBuffer[INPUT_BUFFER_SIZE]; + static uint16_t m_inputSize; + + static bool receiveInput() + { + uint8_t inputByte; + + while(m_serial.rxByte(inputByte)) { + if(std::isprint(inputByte) || inputByte == CTRL_C) { + m_inputBuffer[m_inputSize++] = inputByte; + + // Handle Ctrl + C + if(inputByte == CTRL_C) { + m_serial << "^C" << detail::ENDL; + return true; + } + // Echo + else { + m_serial << static_cast(inputByte); + } + } + + // Handle backspace + if(inputByte == BACKSPACE && m_inputSize > 0) { + m_serial << "\b \b"; + --m_inputSize; + } + // Handle line terminator + else if(inputByte == '\r' || inputByte == '\n') { + // Consume possible second line terminator + if(m_serial.peek(inputByte) && (inputByte == '\r' || inputByte == '\n')) { + m_serial.rxByte(inputByte); + } + m_serial << detail::ENDL; + return true; + } + + if(m_inputSize >= INPUT_BUFFER_SIZE) { + m_serial << detail::ENDL << "WARNING: Terminal input buffer overflow!" << detail::ENDL; + return true; + } + } + + return false; + } + + static void parseInput() + { + if(m_inputSize) { + if(m_inputBuffer[m_inputSize - 1] == CTRL_C) { + handleCtrlC(); + } + else { + if(detail::substringEquals(m_inputBuffer, detail::HELP_CMD, m_inputSize)) { + printHelp(); + } + else if(detail::substringEquals(m_inputBuffer, detail::READ_CMD, m_inputSize)) { + readSensor(); + } + else if(detail::substringEquals(m_inputBuffer, detail::VERSION_CMD, m_inputSize)) { + printVersion(); + } + else { + printUnknown(); + } + } + } + + m_inputSize = 0; + m_serial << "$ "; + } + + static void handleCtrlC() { m_serial << "Abort!" << detail::ENDL; } + + static void printHelp() + { + m_serial << "AdaptiveBrightness command overview: " << detail::ENDL; + m_serial << detail::HELP_CMD << " .......: prints this help message" << detail::ENDL; + m_serial << detail::READ_CMD << " .......: reads and displays all LDR values" << detail::ENDL; + m_serial << detail::VERSION_CMD << " ....: displays firmware version" << detail::ENDL; + } + + static void readSensor() { m_serial << "Sensor values: 1 2 3" << detail::ENDL; } + + static void printVersion() { m_serial << "AdaptiveBrightness v" << detail::VERSION << detail::ENDL; } + + static void printUnknown() + { + m_serial << "Unknown command \""; + for(uint16_t i = 0; i < m_inputSize; ++i) { + m_serial << static_cast(m_inputBuffer[i]); + } + m_serial << "\"" << detail::ENDL; + } +}; + +template +char Terminal::m_inputBuffer[INPUT_BUFFER_SIZE]; + +template +uint16_t Terminal::m_inputSize = 0; diff --git a/AdaptiveBrightnessFirmware/Inc/uart.hpp b/AdaptiveBrightnessFirmware/Inc/uart.hpp new file mode 100644 index 0000000..d5cdc79 --- /dev/null +++ b/AdaptiveBrightnessFirmware/Inc/uart.hpp @@ -0,0 +1,329 @@ +#pragma once + +#include +#include + +#include + +#include "uart_config.hpp" +#include "uart_vcp.hpp" + +namespace uart { + +namespace detail { + + template + struct always_false : std::false_type { + }; + template + inline constexpr auto always_false_v = always_false::value; + + template + static constexpr size_t cntDigits() + { + T num = Limit; + size_t cnt = 0; + + do { + num /= Base; + ++cnt; + } while(num > 0); + + return cnt; + } + + template + static constexpr size_t maxNumDigits() + { + constexpr T MinVal = std::numeric_limits::min(); + constexpr T MaxVal = std::numeric_limits::max(); + + constexpr T MinDigits = cntDigits(); + constexpr T MaxDigits = cntDigits(); + + return (MinDigits < MaxDigits) ? MaxDigits : MinDigits; + } + +} // namespace detail + +template +class Uart { + public: + // Constructing a uart object does not initialize the driver to allow different specializations with the same + // back-end to exists at the same time + // Note that init must be called every time when switching specializations with the same back-end + Uart() = default; + + // Moving and copying uart objects is not supported + Uart(const Uart&) = delete; + Uart(Uart&&) = delete; + Uart& operator=(const Uart&) = delete; + Uart& operator=(Uart&&) = delete; + + // Before using the uart init must be called + static void init() { Driver::init(); } + + static void txByte(const uint8_t& byte) { Driver::txByte(byte); } + + static bool rxByte(uint8_t& byte) { return Driver::rxByte(byte); } + + static bool peek(uint8_t& byte) { return Driver::peek(byte); } + + static bool peek() { return Driver::peek(); } + + static void flushTx() { Driver::flushTx(); } + + static void txString(const char* str) + { + static_assert(Driver::DATA_BITS == DataBits::EIGHT, "Strings are only supported with 8 data bits"); + + while(char ch = *str++) + txByte(ch); + } + + template + static void txNumber(const T& val) + { + static_assert(std::is_integral_v, "Only supported on integral types"); + static_assert(Base >= 2, "Numbers with base less than 2 make no sense"); + static_assert(Base <= 16, "Numbers with base higher than 16 are not supported"); + static_assert(Padding <= detail::maxNumDigits(), "Cannot pad more than maximum length of number"); + + constexpr char AlphaChar = (LowerCase) ? 'a' : 'A'; + constexpr size_t NumDigits = detail::maxNumDigits(); + + T digits = val; + + if(digits < 0) { + digits = -digits; + txByte('-'); + } + + uint8_t buffer[NumDigits]; + uint8_t* bufEnd = buffer + NumDigits - 1; + + do { + const uint8_t lastDigit = digits % Base; + *bufEnd-- = (lastDigit < 10) ? ('0' + lastDigit) : (AlphaChar + lastDigit - 10); + digits /= Base; + } while(digits > 0); + + if(Padding > 0) { + size_t strLen = buffer + NumDigits - (bufEnd + 1); + + if(Padding > strLen) { + for(size_t i = Padding; i > strLen && bufEnd >= buffer; --i) { + *bufEnd-- = PadChar; + } + } + } + + for(uint8_t* buf = bufEnd + 1; buf < buffer + NumDigits; ++buf) { + txByte(*buf); + } + } + + ////////////////////////////////////////////////////////////////////////// + // Output stream overloads + + Uart& operator<<(const char* str) + { + txString(str); + return *this; + } + + Uart& operator<<(const char& val) + { + txByte(val); + return *this; + } + + Uart& operator<<(const signed char& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const unsigned char& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const short& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const unsigned short& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const int& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const unsigned int& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const long& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const unsigned long& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const long long& val) + { + txNumber(val); + return *this; + } + + Uart& operator<<(const unsigned long long& val) + { + txNumber(val); + return *this; + } + + template + Uart& operator<<(float) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + template + Uart& operator<<(double) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + template + Uart& operator<<(long double) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + Uart& operator<<(const bool& val) + { + txString(val ? "true" : "false"); + return *this; + } + + Uart& operator<<(const void* val) + { + txString("0x"); + txNumber(reinterpret_cast(val)); + return *this; + } + + ////////////////////////////////////////////////////////////////////////// + // Input stream overloads + + template + Uart& operator>>(char&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(unsigned char&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(short&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(unsigned short&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(int&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(unsigned int&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(long&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(unsigned long&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(long long&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(unsigned long long&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(float&) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + template + Uart& operator>>(double&) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + template + Uart& operator>>(long double&) const + { + static_assert(detail::always_false_v, "Not supported by hardware"); + } + + template + Uart& operator>>(bool&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } + + template + Uart& operator>>(const void*&) const + { + static_assert(detail::always_false_v, "Not implemented"); + } +}; + +template> +using Vcp = Uart>; + +} // namespace uart diff --git a/AdaptiveBrightnessFirmware/Inc/uart_config.hpp b/AdaptiveBrightnessFirmware/Inc/uart_config.hpp new file mode 100644 index 0000000..3d648d0 --- /dev/null +++ b/AdaptiveBrightnessFirmware/Inc/uart_config.hpp @@ -0,0 +1,32 @@ +#pragma once + +namespace uart { + +enum class DataBits { + FIVE, + SIX, + SEVEN, + EIGHT, + NINE, +}; + +enum class StopBits { + ONE, + TWO, +}; + +enum class Parity { + NONE, + ODD, + EVEN, +}; + +template +struct Config { + static constexpr auto BAUD_RATE = baudRate; + static constexpr auto DATA_BITS = dataBits; + static constexpr auto PARITY = parity; + static constexpr auto STOP_BITS = stopBits; +}; + +} // namespace uart diff --git a/AdaptiveBrightnessFirmware/Inc/uart_vcp.hpp b/AdaptiveBrightnessFirmware/Inc/uart_vcp.hpp new file mode 100644 index 0000000..c781ec4 --- /dev/null +++ b/AdaptiveBrightnessFirmware/Inc/uart_vcp.hpp @@ -0,0 +1,209 @@ +#pragma once + +#include + +#include + +#include "usbd_cdc.h" +#include "usbd_def.h" + +extern "C" { +extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; +extern USBD_HandleTypeDef hUsbDeviceFS; +} + +namespace uart::detail { + +template +struct RingBuffer { + size_t head; + size_t tail; + uint8_t data[Size]; +}; + +template +class VirtualComPort { + public: + static constexpr auto DATA_BITS = cfg::DATA_BITS; + + [[gnu::always_inline]] static void init() + { + USBD_Interface_fops_FS.Init = CdcInit; + USBD_Interface_fops_FS.DeInit = CdcDeInit; + USBD_Interface_fops_FS.Control = CdcControl; + USBD_Interface_fops_FS.Receive = CdcReceive; + } + + [[gnu::always_inline]] static bool rxByte(uint8_t& byte) + { + if(m_rxBuffer.head == m_rxBuffer.tail) + return false; + + const size_t newTail = (m_rxBuffer.tail + 1) % RX_BUFFER_SIZE; + byte = m_rxBuffer.data[newTail]; + m_rxBuffer.tail = newTail; + return true; + } + + [[gnu::always_inline]] static void txByte(const uint8_t& byte) + { + const size_t newHead = (m_txBuffer.head + 1) % TX_BUFFER_SIZE; + + if(m_txBuffer.tail == newHead) { + flushTx(); + } + + m_txBuffer.data[newHead] = byte; + m_txBuffer.head = newHead; + } + + [[gnu::always_inline]] static bool peek(uint8_t& byte) + { + if(m_rxBuffer.head == m_rxBuffer.tail) + return false; + + const size_t newTail = (m_rxBuffer.tail + 1) % RX_BUFFER_SIZE; + byte = m_rxBuffer.data[newTail]; + + return true; + } + + [[gnu::always_inline]] static void flushTx() + { + if(m_txBuffer.head == m_txBuffer.tail) { + return; + } + + constexpr auto usbReady = []() { + USBD_CDC_HandleTypeDef* hcdc = static_cast(hUsbDeviceFS.pClassData); + return hcdc->TxState != 0; + }; + + constexpr auto txPacket = [usbReady](volatile uint8_t* buffer, size_t length) { + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, const_cast(buffer), length); + USBD_CDC_TransmitPacket(&hUsbDeviceFS); + while(!usbReady()) + ; + }; + + if(m_txBuffer.head > m_txBuffer.tail) { + txPacket(&m_txBuffer.data[m_txBuffer.tail], m_txBuffer.head - m_txBuffer.tail); + } + else { + txPacket(&m_txBuffer.data[m_txBuffer.tail], TX_BUFFER_SIZE - 1 - m_txBuffer.tail); + txPacket(m_txBuffer.data, m_txBuffer.head + 1); + } + + m_txBuffer.tail = m_txBuffer.head; + } + + private: + static constexpr auto TX_BUFFER_SIZE = 512; + static constexpr auto RX_BUFFER_SIZE = 512; + + static volatile RingBuffer m_txBuffer; + static volatile RingBuffer m_rxBuffer; + + static std::array m_usbAsyncRxBuffer; + + static int8_t CdcInit() + { + USBD_CDC_SetTxBuffer(&hUsbDeviceFS, const_cast(m_txBuffer.data), 0); + USBD_CDC_SetRxBuffer(&hUsbDeviceFS, const_cast(m_usbAsyncRxBuffer.data())); + return USBD_OK; + } + + static int8_t CdcDeInit() + { + USBD_Interface_fops_FS.Init = nullptr; + USBD_Interface_fops_FS.DeInit = nullptr; + USBD_Interface_fops_FS.Control = nullptr; + USBD_Interface_fops_FS.Receive = nullptr; + return USBD_OK; + } + + static int8_t CdcControl(uint8_t cmd, [[maybe_unused]] uint8_t* buf, [[maybe_unused]] uint16_t length) + { + switch(cmd) { + case CDC_SEND_ENCAPSULATED_COMMAND: + break; + case CDC_GET_ENCAPSULATED_RESPONSE: + break; + case CDC_SET_COMM_FEATURE: + break; + case CDC_GET_COMM_FEATURE: + break; + case CDC_CLEAR_COMM_FEATURE: + break; + + case CDC_SET_LINE_CODING: + /*******************************************************************************/ + /* Line Coding Structure */ + /*-----------------------------------------------------------------------------*/ + /* Offset | Field | Size | Value | Description */ + /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ + /* 4 | bCharFormat | 1 | Number | Stop bits */ + /* 0 - 1 Stop bit */ + /* 1 - 1.5 Stop bits */ + /* 2 - 2 Stop bits */ + /* 5 | bParityType | 1 | Number | Parity */ + /* 0 - None */ + /* 1 - Odd */ + /* 2 - Even */ + /* 3 - Mark */ + /* 4 - Space */ + /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ + /*******************************************************************************/ + break; + + case CDC_GET_LINE_CODING: + break; + + case CDC_SET_CONTROL_LINE_STATE: + break; + + case CDC_SEND_BREAK: + break; + + default: + break; + } + + return USBD_OK; + } + + static int8_t CdcReceive([[maybe_unused]] uint8_t* buf, uint32_t* length) + { + USBD_CDC_ReceivePacket(&hUsbDeviceFS); + + for(uint32_t i = 0; i < *length; ++i) { + const auto byte = m_usbAsyncRxBuffer[i]; + rxHandler(byte); + } + return USBD_OK; + } + + [[gnu::always_inline]] static inline void rxHandler(const uint8_t& data) + { + const size_t newHead = (m_rxBuffer.head + 1) % RX_BUFFER_SIZE; + + if(newHead != m_rxBuffer.tail) { + m_rxBuffer.data[newHead] = data; + m_rxBuffer.head = newHead; + } + else { + // TODO: Handle overflow + } + } +}; + +template +volatile RingBuffer::TX_BUFFER_SIZE> VirtualComPort::m_txBuffer = {0, 0, {0}}; + +template +volatile RingBuffer::RX_BUFFER_SIZE> VirtualComPort::m_rxBuffer = {0, 0, {0}}; + +template +std::array VirtualComPort::m_usbAsyncRxBuffer = {0}; + +} // namespace uart::detail diff --git a/AdaptiveBrightnessFirmware/Inc/usbd_cdc_if.h b/AdaptiveBrightnessFirmware/Inc/usbd_cdc_if.h index 4c90faa..7dcf22d 100644 --- a/AdaptiveBrightnessFirmware/Inc/usbd_cdc_if.h +++ b/AdaptiveBrightnessFirmware/Inc/usbd_cdc_if.h @@ -38,11 +38,11 @@ * @brief For Usb device. * @{ */ - + /** @defgroup USBD_CDC_IF USBD_CDC_IF * @brief Usb VCP device module * @{ - */ + */ /** @defgroup USBD_CDC_IF_Exported_Defines USBD_CDC_IF_Exported_Defines * @brief Defines. @@ -92,21 +92,6 @@ extern USBD_CDC_ItfTypeDef USBD_Interface_fops_FS; /* USER CODE BEGIN EXPORTED_VARIABLES */ -/* USER CODE END EXPORTED_VARIABLES */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Exported_FunctionsPrototype USBD_CDC_IF_Exported_FunctionsPrototype - * @brief Public functions declaration. - * @{ - */ - -uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len); - -/* USER CODE BEGIN EXPORTED_FUNCTIONS */ - /* USER CODE END EXPORTED_FUNCTIONS */ /** diff --git a/AdaptiveBrightnessFirmware/Makefile b/AdaptiveBrightnessFirmware/Makefile index c08a4e4..b0a53db 100644 --- a/AdaptiveBrightnessFirmware/Makefile +++ b/AdaptiveBrightnessFirmware/Makefile @@ -43,7 +43,6 @@ Src/adc.c \ Src/usb_device.c \ Src/usbd_conf.c \ Src/usbd_desc.c \ -Src/usbd_cdc_if.c \ Src/stm32f0xx_it.c \ Src/stm32f0xx_hal_msp.c \ Drivers/STM32F0xx_HAL_Driver/Src/stm32f0xx_ll_usb.c \ @@ -75,6 +74,7 @@ Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c # C++ sources CXX_SOURCES = \ Src/main.cpp \ +Src/uart_vcp.cpp \ Src/vcp_receiver.cpp # ASM sources diff --git a/AdaptiveBrightnessFirmware/Src/main.cpp b/AdaptiveBrightnessFirmware/Src/main.cpp index c42d4f7..aacd104 100644 --- a/AdaptiveBrightnessFirmware/Src/main.cpp +++ b/AdaptiveBrightnessFirmware/Src/main.cpp @@ -5,9 +5,9 @@ #include "adc.h" #include "init.h" -#include "usbd_cdc_if.h" +#include "terminal.hpp" +#include "uart.hpp" #include "utils.hpp" -#include "vcp_receiver.hpp" std::array sampleLightSensors() { @@ -30,9 +30,10 @@ std::array sampleLightSensors() int main() { - init(); + uart::Vcp<> serial; - VcpReceiver vcpReceiver; + init(); + serial.init(); HAL_GPIO_WritePin(RED_LED_GPIO_Port, RED_LED_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(GREEN_LED_GPIO_Port, GREEN_LED_Pin, GPIO_PIN_RESET); @@ -47,24 +48,23 @@ int main() uint8_t data = 0; while(true) { - if(vcpReceiver.rxByte(data)) { - CDC_Transmit_FS(&data, 1); + if(serial.rxByte(data)) { + serial.txByte(data); } const auto ldrValues = sampleLightSensors(); HAL_GPIO_WritePin(BLUE_LED_GPIO_Port, BLUE_LED_Pin, GPIO_PIN_RESET); - std::array printBuffer; + std::array printBuffer; for(uint8_t i = 0; i < ldrValues.size(); ++i) { const auto ldrID = i + 1; const auto percentage = ldrValues[i] * 100 / 0xFFF; - const auto bufLen = std::sprintf(reinterpret_cast(printBuffer.data()), "LDR%d: %04hu - %03d%%\r\n%s", ldrID, ldrValues[i], percentage, - (i == 2) ? "\r\n" : ""); + const auto bufLen = std::sprintf(printBuffer.data(), "LDR%d: %04hu - %03d%%\r\n%s", ldrID, ldrValues[i], percentage, (i == 2) ? "\r\n" : ""); if(bufLen > 0) { - while(CDC_Transmit_FS(printBuffer.data(), bufLen) == USBD_BUSY) - ; + serial.txString(printBuffer.data()); + serial.flushTx(); } } diff --git a/AdaptiveBrightnessFirmware/Src/uart_vcp.cpp b/AdaptiveBrightnessFirmware/Src/uart_vcp.cpp new file mode 100644 index 0000000..3b63415 --- /dev/null +++ b/AdaptiveBrightnessFirmware/Src/uart_vcp.cpp @@ -0,0 +1,10 @@ +#include "uart_vcp.hpp" + +extern "C" { +USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = { + nullptr, + nullptr, + nullptr, + nullptr, +}; +} diff --git a/AdaptiveBrightnessFirmware/Src/usbd_cdc_if.c b/AdaptiveBrightnessFirmware/Src/usbd_cdc_if.c deleted file mode 100644 index 17a6221..0000000 --- a/AdaptiveBrightnessFirmware/Src/usbd_cdc_if.c +++ /dev/null @@ -1,312 +0,0 @@ -/* USER CODE BEGIN Header */ -/** - ****************************************************************************** - * @file : usbd_cdc_if.c - * @version : v2.0_Cube - * @brief : Usb device for Virtual Com Port. - ****************************************************************************** - * @attention - * - *

© Copyright (c) 2020 STMicroelectronics. - * All rights reserved.

- * - * This software component is licensed by ST under Ultimate Liberty license - * SLA0044, the "License"; You may not use this file except in compliance with - * the License. You may obtain a copy of the License at: - * www.st.com/SLA0044 - * - ****************************************************************************** - */ -/* USER CODE END Header */ - -/* Includes ------------------------------------------------------------------*/ -#include "usbd_cdc_if.h" - -/* USER CODE BEGIN INCLUDE */ - -/* USER CODE END INCLUDE */ - -/* Private typedef -----------------------------------------------------------*/ -/* Private define ------------------------------------------------------------*/ -/* Private macro -------------------------------------------------------------*/ - -/* USER CODE BEGIN PV */ -/* Private variables ---------------------------------------------------------*/ - -/* USER CODE END PV */ - -/** @addtogroup STM32_USB_OTG_DEVICE_LIBRARY - * @brief Usb device library. - * @{ - */ - -/** @addtogroup USBD_CDC_IF - * @{ - */ - -/** @defgroup USBD_CDC_IF_Private_TypesDefinitions USBD_CDC_IF_Private_TypesDefinitions - * @brief Private types. - * @{ - */ - -/* USER CODE BEGIN PRIVATE_TYPES */ - -/* USER CODE END PRIVATE_TYPES */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Private_Defines USBD_CDC_IF_Private_Defines - * @brief Private defines. - * @{ - */ - -/* USER CODE BEGIN PRIVATE_DEFINES */ -/* Define size for the receive and transmit buffer over CDC */ -/* It's up to user to redefine and/or remove those define */ -#define APP_RX_DATA_SIZE 512 -#define APP_TX_DATA_SIZE 512 -/* USER CODE END PRIVATE_DEFINES */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Private_Macros USBD_CDC_IF_Private_Macros - * @brief Private macros. - * @{ - */ - -/* USER CODE BEGIN PRIVATE_MACRO */ - -/* USER CODE END PRIVATE_MACRO */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Private_Variables USBD_CDC_IF_Private_Variables - * @brief Private variables. - * @{ - */ -/* Create buffer for reception and transmission */ -/* It's up to user to redefine and/or remove those define */ -/** Received data over USB are stored in this buffer */ -uint8_t UserRxBufferFS[APP_RX_DATA_SIZE]; - -/** Data to send over USB CDC are stored in this buffer */ -uint8_t UserTxBufferFS[APP_TX_DATA_SIZE]; - -/* USER CODE BEGIN PRIVATE_VARIABLES */ - -/* USER CODE END PRIVATE_VARIABLES */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Exported_Variables USBD_CDC_IF_Exported_Variables - * @brief Public variables. - * @{ - */ - -extern USBD_HandleTypeDef hUsbDeviceFS; - -/* USER CODE BEGIN EXPORTED_VARIABLES */ - -/* USER CODE END EXPORTED_VARIABLES */ - -/** - * @} - */ - -/** @defgroup USBD_CDC_IF_Private_FunctionPrototypes USBD_CDC_IF_Private_FunctionPrototypes - * @brief Private functions declaration. - * @{ - */ - -static int8_t CDC_Init_FS(void); -static int8_t CDC_DeInit_FS(void); -static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length); -static int8_t CDC_Receive_FS(uint8_t* pbuf, uint32_t *Len); - -/* USER CODE BEGIN PRIVATE_FUNCTIONS_DECLARATION */ - -/* USER CODE END PRIVATE_FUNCTIONS_DECLARATION */ - -/** - * @} - */ - -USBD_CDC_ItfTypeDef USBD_Interface_fops_FS = -{ - CDC_Init_FS, - CDC_DeInit_FS, - CDC_Control_FS, - CDC_Receive_FS -}; - -/* Private functions ---------------------------------------------------------*/ -/** - * @brief Initializes the CDC media low layer over the FS USB IP - * @retval USBD_OK if all operations are OK else USBD_FAIL - */ -static int8_t CDC_Init_FS(void) -{ - /* USER CODE BEGIN 3 */ - /* Set Application Buffers */ - USBD_CDC_SetTxBuffer(&hUsbDeviceFS, UserTxBufferFS, 0); - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, UserRxBufferFS); - return (USBD_OK); - /* USER CODE END 3 */ -} - -/** - * @brief DeInitializes the CDC media low layer - * @retval USBD_OK if all operations are OK else USBD_FAIL - */ -static int8_t CDC_DeInit_FS(void) -{ - /* USER CODE BEGIN 4 */ - return (USBD_OK); - /* USER CODE END 4 */ -} - -/** - * @brief Manage the CDC class requests - * @param cmd: Command code - * @param pbuf: Buffer containing command data (request parameters) - * @param length: Number of data to be sent (in bytes) - * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL - */ -static int8_t CDC_Control_FS(uint8_t cmd, uint8_t* pbuf, uint16_t length) -{ - /* USER CODE BEGIN 5 */ - switch(cmd) - { - case CDC_SEND_ENCAPSULATED_COMMAND: - - break; - - case CDC_GET_ENCAPSULATED_RESPONSE: - - break; - - case CDC_SET_COMM_FEATURE: - - break; - - case CDC_GET_COMM_FEATURE: - - break; - - case CDC_CLEAR_COMM_FEATURE: - - break; - - /*******************************************************************************/ - /* Line Coding Structure */ - /*-----------------------------------------------------------------------------*/ - /* Offset | Field | Size | Value | Description */ - /* 0 | dwDTERate | 4 | Number |Data terminal rate, in bits per second*/ - /* 4 | bCharFormat | 1 | Number | Stop bits */ - /* 0 - 1 Stop bit */ - /* 1 - 1.5 Stop bits */ - /* 2 - 2 Stop bits */ - /* 5 | bParityType | 1 | Number | Parity */ - /* 0 - None */ - /* 1 - Odd */ - /* 2 - Even */ - /* 3 - Mark */ - /* 4 - Space */ - /* 6 | bDataBits | 1 | Number Data bits (5, 6, 7, 8 or 16). */ - /*******************************************************************************/ - case CDC_SET_LINE_CODING: - - break; - - case CDC_GET_LINE_CODING: - - break; - - case CDC_SET_CONTROL_LINE_STATE: - - break; - - case CDC_SEND_BREAK: - - break; - - default: - break; - } - - return (USBD_OK); - /* USER CODE END 5 */ -} - -extern void vcpReceiveCallback(uint8_t* buf, uint32_t len); - -/** - * @brief Data received over USB OUT endpoint are sent over CDC interface - * through this function. - * - * @note - * This function will block any OUT packet reception on USB endpoint - * untill exiting this function. If you exit this function before transfer - * is complete on CDC interface (ie. using DMA controller) it will result - * in receiving more data while previous ones are still not sent. - * - * @param Buf: Buffer of data to be received - * @param Len: Number of data received (in bytes) - * @retval Result of the operation: USBD_OK if all operations are OK else USBD_FAIL - */ -static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) -{ - /* USER CODE BEGIN 6 */ - USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); - USBD_CDC_ReceivePacket(&hUsbDeviceFS); - vcpReceiveCallback(Buf, *Len); - return (USBD_OK); - /* USER CODE END 6 */ -} - -/** - * @brief CDC_Transmit_FS - * Data to send over USB IN endpoint are sent over CDC interface - * through this function. - * @note - * - * - * @param Buf: Buffer of data to be sent - * @param Len: Number of data to be sent (in bytes) - * @retval USBD_OK if all operations are OK else USBD_FAIL or USBD_BUSY - */ -uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) -{ - uint8_t result = USBD_OK; - /* USER CODE BEGIN 7 */ - USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData; - if (hcdc->TxState != 0){ - return USBD_BUSY; - } - USBD_CDC_SetTxBuffer(&hUsbDeviceFS, Buf, Len); - result = USBD_CDC_TransmitPacket(&hUsbDeviceFS); - /* USER CODE END 7 */ - return result; -} - -/* USER CODE BEGIN PRIVATE_FUNCTIONS_IMPLEMENTATION */ - -/* USER CODE END PRIVATE_FUNCTIONS_IMPLEMENTATION */ - -/** - * @} - */ - -/** - * @} - */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/