Skip to content

Instantly share code, notes, and snippets.

@RickKimball
Last active July 14, 2016 22:06
Show Gist options
  • Save RickKimball/ebfb741a17870355236d04b9db479254 to your computer and use it in GitHub Desktop.
Save RickKimball/ebfb741a17870355236d04b9db479254 to your computer and use it in GitHub Desktop.
#include "ringbuffer_e.h"
#include "streaming.h"
uint8_t buffer[32];
ring_buffer message_buffer = { buffer, 0, 0, sizeof(buffer) };
void queue_message(const char *str) {
while (*str) {
GPIOC_BASE->BRR = (1 << 13); // time function using gpio toggle
rb_safe_insert(&message_buffer, *str++);
GPIOC_BASE->BSRR = (1 << 13);
// put a scope on PC13 to see how much time rb_safe_insert() actually takes
// I measured ~500 nano seconds
}
}
void setup() {
Serial.begin(115200);
pinMode(PC13, OUTPUT);
queue_message("Hello World\r\n");
}
void loop() {
if ( !rb_is_empty(&message_buffer)) {
Serial << "message size=" << rb_full_count(&message_buffer)
<< " head=" << message_buffer.head
<< " used=" << message_buffer.used
<< "\r\n";
Serial << "[";
do {
int c = rb_remove(&message_buffer);
Serial.write(c);
} while (!rb_is_empty(&message_buffer));
Serial << "]\r\n";
}
delay(1000);
queue_message("Hello Again\r\n");
}
/******************************************************************************
* The MIT License
*
* Copyright (c) 2011 LeafLabs, LLC.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*****************************************************************************/
/**
* @file libmaple/include/libmaple/ring_buffer.h
* @brief Simple circular buffer
*
* This implementation is not thread-safe. In particular, none of
* these functions is guaranteed re-entrant.
*/
#ifndef _LIBMAPLE_RING_BUFFER_H_
#define _LIBMAPLE_RING_BUFFER_H_
#ifdef __cplusplus
extern "C"{
#endif
#include <libmaple/libmaple_types.h>
/**
* Ring buffer type.
*
* The buffer is empty when used == 0.
*
* The buffer is full when used == size.
*
* This implementation allows using the full buffer size instead of the buffer size - 1. */
typedef struct ring_buffer {
volatile uint8 *buf; /**< Buffer items are stored into */
uint16 head; /**< Index of the next item to remove */
uint16 used; /**< Amount of used buffer */
uint16 size; /**< Buffer size */
} ring_buffer;
/**
* Initialise a ring buffer.
*
* @param rb Instance to initialise
*
* @param size Number of items in buf
*
* @param buf Buffer to store items into
*/
static inline void rb_init(ring_buffer *rb, uint16 size, uint8 *buf) {
rb->head = 0;
rb->used = 0;
rb->size = size;
rb->buf = buf;
}
/**
* Initialise a ring buffer. The buffer is dynamically allocated with malloc()
*
* @param rb Instance to initialise
*
* @param size Number of items in buf
*/
inline void rb_init_new(ring_buffer *rb, uint16 size);
/**
* @brief Return the number of elements stored in the ring buffer.
* @param rb Buffer whose elements to count.
*/
static inline uint16 rb_full_count(ring_buffer *rb) {
return rb->used;
}
/**
* @brief Returns true if and only if the ring buffer is full.
* @param rb Buffer to test.
*/
static inline int rb_is_full(ring_buffer *rb) {
return rb->used == rb->size;
}
/**
* @brief Returns true if and only if the ring buffer is empty.
* @param rb Buffer to test.
*/
static inline int rb_is_empty(ring_buffer *rb) {
return rb->used == 0;
}
/**
* Append element onto the end of a ring buffer.
* @param rb Buffer to append onto.
* @param element Value to append.
*/
static inline void rb_insert(ring_buffer *rb, uint8 element) {
if(rb->used < rb->size)
{
rb->buf[(rb->head + rb->used) % rb->size] = element;
rb->used += 1;
}
}
/**
* @brief Remove and return the first item from a ring buffer.
* @param rb Buffer to remove from, must contain at least one element.
*/
static inline int16 rb_remove(ring_buffer *rb) {
int16 ch = -1;
if(rb->used > 0)
{
ch = rb->buf[rb->head];
rb->head = (rb->head + 1) % rb->size;
rb->used -= 1;
}
return ch;
}
/*
* Roger Clark. 20141125,
* added peek function.
* @brief Return the first item from a ring buffer, without removing it
* @param rb Buffer to remove from, must contain at least one element.
*/
static inline int16 rb_peek(ring_buffer *rb)
{
return rb->used == 0 ? -1 : rb->buf[rb->head];
}
/**
* @brief Attempt to remove the first item from a ring buffer.
*
* If the ring buffer is nonempty, removes and returns its first item.
* If it is empty, does nothing and returns a negative value.
*
* @param rb Buffer to attempt to remove from.
*/
static inline int16 rb_safe_remove(ring_buffer *rb) {
return rb_remove(rb);
}
/**
* @brief Attempt to insert an element into a ring buffer.
*
* @param rb Buffer to insert into.
* @param element Value to insert into rb.
* @sideeffect If rb is not full, appends element onto buffer.
* @return If element was appended, then true; otherwise, false. */
static inline int rb_safe_insert(ring_buffer *rb, uint8 element) {
if (rb_is_full(rb)) {
return 0;
}
rb_insert(rb, element);
return 1;
}
/**
* @brief Append an item onto the end of a non-full ring buffer.
*
* If the buffer is full, removes its first item, then inserts the new
* element at the end.
*
* @param rb Ring buffer to insert into.
* @param element Value to insert into ring buffer.
* @return On success, returns -1. If an element was popped, returns
* the popped value.
*/
static inline int16 rb_push_insert(ring_buffer *rb, uint8 element) {
int ret = -1;
if (rb_is_full(rb)) {
ret = rb_remove(rb);
}
rb_insert(rb, element);
return ret;
}
/**
* @brief Discard all items from a ring buffer.
* @param rb Ring buffer to discard all items from.
*/
static inline void rb_reset(ring_buffer *rb) {
rb->used=0;
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif
/*
Streaming.h - Arduino library for supporting the << streaming operator
Copyright (c) 2010-2012 Mikal Hart. All rights reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ARDUINO_STREAMING
#define ARDUINO_STREAMING
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#define STREAMING_LIBRARY_VERSION 5
// Generic template
template<class T>
inline Print &operator <<(Print &stream, T arg)
{ stream.print(arg); return stream; }
struct _BASED
{
long val;
int base;
_BASED(long v, int b): val(v), base(b)
{}
};
#if ARDUINO >= 100
struct _BYTE_CODE
{
byte val;
_BYTE_CODE(byte v) : val(v)
{}
};
#define _BYTE(a) _BYTE_CODE(a)
inline Print &operator <<(Print &obj, const _BYTE_CODE &arg)
{ obj.write(arg.val); return obj; }
#else
#define _BYTE(a) _BASED(a, BYTE)
#endif
#define _HEX(a) _BASED(a, HEX)
#define _DEC(a) _BASED(a, DEC)
#define _OCT(a) _BASED(a, OCT)
#define _BIN(a) _BASED(a, BIN)
// Specialization for class _BASED
// Thanks to Arduino forum user Ben Combee who suggested this
// clever technique to allow for expressions like
// Serial << _HEX(a);
inline Print &operator <<(Print &obj, const _BASED &arg)
{ obj.print(arg.val, arg.base); return obj; }
#if ARDUINO >= 18
// Specialization for class _FLOAT
// Thanks to Michael Margolis for suggesting a way
// to accommodate Arduino 0018's floating point precision
// feature like this:
// Serial << _FLOAT(gps_latitude, 6); // 6 digits of precision
struct _FLOAT
{
float val;
int digits;
_FLOAT(double v, int d): val(v), digits(d)
{}
};
inline Print &operator <<(Print &obj, const _FLOAT &arg)
{ obj.print(arg.val, arg.digits); return obj; }
#endif
// Specialization for enum _EndLineCode
// Thanks to Arduino forum user Paul V. who suggested this
// clever technique to allow for expressions like
// Serial << "Hello!" << endl;
enum _EndLineCode { endl };
inline Print &operator <<(Print &obj, _EndLineCode arg)
{ obj.println(); return obj; }
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment