-
-
Save pan-/9c836b51116aa8e9c3c262dca60c17b5 to your computer and use it in GitHub Desktop.
NRF52 SDK15 update serial issue reproducer.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* mbed Microcontroller Library | |
* Copyright (c) 2015 ARM Limited | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#ifndef BLE_CLIAPP_UTIL_CIRCULARBUFFER_H | |
#define BLE_CLIAPP_UTIL_CIRCULARBUFFER_H | |
#include <algorithm> | |
#include <stdint.h> | |
namespace util { | |
/** Templated Circular buffer class | |
*/ | |
template<typename T, size_t BufferSize, typename CounterType = uint32_t> | |
class CircularBuffer { | |
public: | |
CircularBuffer() : _head(0), _tail(0), _full(false) { | |
} | |
/** | |
* Push the transaction to the buffer. This operation will fail if there is | |
* no room left in the buffer. | |
* | |
* @param data Data to be pushed to the buffer | |
* @return true if the operation succeed and false otherwise | |
*/ | |
bool push(const T& data) { | |
if (full()) { | |
return false; | |
} | |
_buffer[_head] = data; | |
_head = incrementCounter(_head); | |
if (_head == _tail) { | |
_full = true; | |
} | |
return true; | |
} | |
/** Pop the transaction from the buffer | |
* | |
* @param data Data to be pushed to the buffer | |
* @return True if the buffer is not empty and data contains a transaction, false otherwise | |
*/ | |
bool pop(T& data) { | |
if(empty()) { | |
return false; | |
} | |
data = _buffer[_tail]; | |
_tail = incrementCounter(_tail); | |
_full = false; | |
return true; | |
} | |
/** | |
* @brief pop multiples elements from the buffer | |
* | |
* @param dest The array which will received the elements | |
* @param len The number of elements to pop | |
* | |
* @return The number of elements pop | |
*/ | |
CounterType pop(T* dest, CounterType len) { | |
if(empty()) { | |
return 0; | |
} | |
if(_tail < _head) { | |
// truncation if the count if there is not enough elements available | |
if((_tail + len) > _head) { | |
len = _head - _tail; | |
} | |
std::copy(_buffer + _tail, _buffer + _tail + len, dest); | |
_tail += len; | |
return len; | |
} else { | |
if((_tail + len ) <= BufferSize) { | |
std::copy(_buffer + _tail, _buffer + _tail + len, dest); | |
_tail += len; | |
_tail = _tail % BufferSize; | |
_full = false; | |
return len; | |
} else { | |
// composition of previous operations | |
CounterType firstChunk = pop(dest, BufferSize - _tail); | |
return firstChunk + pop(dest + firstChunk, len - firstChunk); | |
} | |
} | |
} | |
/** | |
* @brief pop multiples elements from the buffer | |
* | |
* @param dest The array which will received the elements | |
* | |
* @return The number of elements pop | |
*/ | |
template<CounterType N> | |
CounterType pop(T (&dest)[N]) { | |
return pop(dest, N); | |
} | |
/** Check if the buffer is empty | |
* | |
* @return True if the buffer is empty, false if not | |
*/ | |
bool empty() const { | |
return (_head == _tail) && !_full; | |
} | |
/** Check if the buffer is full | |
* | |
* @return True if the buffer is full, false if not | |
*/ | |
bool full() const { | |
return _full; | |
} | |
/** | |
* Reset the buffer | |
*/ | |
void reset() { | |
_head = 0; | |
_tail = 0; | |
_full = false; | |
} | |
private: | |
CounterType incrementCounter(CounterType val) { | |
return (++val) % BufferSize; | |
} | |
T _buffer[BufferSize]; | |
CounterType _head; | |
CounterType _tail; | |
bool _full; | |
}; | |
} // namespace util | |
#endif /* BLE_CLIAPP_UTIL_CIRCULARBUFFER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "events/EventQueue.h" | |
#include "drivers/RawSerial.h" | |
#include "CB.h" | |
#include "platform/mbed_error.h" | |
#include "platform/CriticalSectionLock.h" | |
/** | |
* Macros for setting console flow control. | |
*/ | |
#define CONSOLE_FLOWCONTROL_RTS 1 | |
#define CONSOLE_FLOWCONTROL_CTS 2 | |
#define CONSOLE_FLOWCONTROL_RTSCTS 3 | |
#define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x | |
#define mbed_console_concat(x) mbed_console_concat_(x) | |
#define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL) | |
events::EventQueue event_queue; | |
// Prototypes | |
static void whenRxInterrupt(void); | |
static void consumeSerialBytes(void); | |
mbed::RawSerial& get_serial() { | |
static mbed::RawSerial serial(USBTX, USBRX); | |
static bool initialized = false; | |
if (!initialized) { | |
#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS | |
serial.set_flow_control(SerialBase::RTS, STDIO_UART_RTS, NC); | |
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS | |
serial.set_flow_control(SerialBase::CTS, NC, STDIO_UART_CTS); | |
#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS | |
serial.set_flow_control(SerialBase::RTSCTS, STDIO_UART_RTS, STDIO_UART_CTS); | |
#endif | |
initialized = true; | |
} | |
return serial; | |
} | |
// constants | |
static const size_t CIRCULAR_BUFFER_LENGTH = 768; | |
static const size_t CONSUMER_BUFFER_LENGTH = 32; | |
// circular buffer used by serial port interrupt to store characters | |
// It will be use in a single producer, single consumer setup: | |
// producer => RX interrupt | |
// consumer => a callback run by minar | |
static util::CircularBuffer<uint8_t, CIRCULAR_BUFFER_LENGTH> rxBuffer; | |
// callback called when a character arrive on the serial port | |
// this function will run in handler mode | |
static void whenRxInterrupt(void) | |
{ | |
static mbed::RawSerial& serial = get_serial(); | |
if (serial.readable()) { | |
bool startConsumer = rxBuffer.empty(); | |
while (serial.readable()) { | |
if(rxBuffer.push((uint8_t) serial.getc()) == false) { | |
error("Not enough space in the circular buffer\r\n"); | |
}; | |
} | |
if(startConsumer) { | |
event_queue.call(consumeSerialBytes); | |
} | |
} | |
} | |
// consumptions of bytes from the serial port. | |
// this function should run in thread mode | |
static void consumeSerialBytes(void) { | |
// buffer of data | |
uint8_t data[CONSUMER_BUFFER_LENGTH]; | |
uint32_t dataAvailable = 0; | |
bool shouldExit = false; | |
do { | |
{ | |
mbed::CriticalSectionLock lock; | |
dataAvailable = rxBuffer.pop(data); | |
if(!dataAvailable) { | |
// sanity check, this should never happen | |
error("error, serial buffer is empty\r\n"); | |
} | |
shouldExit = rxBuffer.empty(); | |
} | |
mbed::RawSerial& serial = get_serial(); | |
for (const uint8_t* c = data, *end = data + dataAvailable; c < end; ++c) { | |
serial.putc(*c); | |
} | |
} while(shouldExit == false); | |
} | |
int main(void) | |
{ | |
//configure serial port | |
get_serial().baud(115200); // This is default baudrate for our test applications. 230400 is also working, but not 460800. At least with k64f. | |
get_serial().attach(whenRxInterrupt); | |
event_queue.dispatch_forever(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment