From 5bfc0cb902cc17586c4e957a1a984b022671d8f8 Mon Sep 17 00:00:00 2001
From: Martino Facchin <m.facchin@arduino.cc>
Date: Fri, 1 Jul 2016 11:44:47 +0200
Subject: [PATCH] Add generic uint8_t RingBuffer class

* cloned from samd core
* implement addStorage() API to allow static/dynamic size increase
---
 api/RingBuffer.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 api/RingBuffer.h   | 57 +++++++++++++++++++++++++++++++
 2 files changed, 156 insertions(+)
 create mode 100644 api/RingBuffer.cpp
 create mode 100644 api/RingBuffer.h

diff --git a/api/RingBuffer.cpp b/api/RingBuffer.cpp
new file mode 100644
index 0000000..be29afe
--- /dev/null
+++ b/api/RingBuffer.cpp
@@ -0,0 +1,99 @@
+/*
+  Copyright (c) 2014 Arduino.  All right 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
+*/
+
+#include "RingBuffer.h"
+#include <string.h>
+
+RingBuffer::RingBuffer( void )
+{
+    memset( _aucBuffer, 0, RINGBUFFER_SIZE ) ;
+    clear();
+}
+
+void RingBuffer::store_char( uint8_t c )
+{
+    int i = nextIndex(_iHead);
+
+    // if we should be storing the received character into the location
+    // just before the tail (meaning that the head would advance to the
+    // current location of the tail), we're about to overflow the buffer
+    // and so we don't write the character or advance the head.
+    if ( i != _iTail )
+    {
+        if (_iHead < RINGBUFFER_SIZE) {
+            _aucBuffer[_iHead] = c ;
+        } else {
+            additionalBuffer[_iHead - RINGBUFFER_SIZE] = c;
+        }
+    _iHead = i ;
+    }
+}
+
+void RingBuffer::clear()
+{
+    _iHead = 0;
+    _iTail = 0;
+}
+
+int RingBuffer::read_char()
+{
+    if(_iTail == _iHead)
+        return -1;
+
+    uint8_t value;
+    if (_iTail < RINGBUFFER_SIZE) {
+        value  = _aucBuffer[_iTail];
+    } else {
+        value = additionalBuffer[_iTail - RINGBUFFER_SIZE];
+    }
+    _iTail = nextIndex(_iTail);
+
+    return value;
+}
+
+int RingBuffer::available()
+{
+    int delta = _iHead - _iTail;
+
+    if(delta < 0)
+        return RINGBUFFER_SIZE + additionalSize + delta;
+    else
+        return delta;
+}
+
+int RingBuffer::peek()
+{
+    if(_iTail == _iHead)
+        return -1;
+
+    if (_iTail < RINGBUFFER_SIZE) {
+        return _aucBuffer[_iTail];
+    } else {
+        return additionalBuffer[_iTail - RINGBUFFER_SIZE];
+    }
+}
+
+int RingBuffer::nextIndex(int index)
+{
+    return (uint32_t)(index + 1) % (RINGBUFFER_SIZE + additionalSize);
+}
+
+bool RingBuffer::isFull()
+{
+    return (nextIndex(_iHead) == _iTail);
+}
diff --git a/api/RingBuffer.h b/api/RingBuffer.h
new file mode 100644
index 0000000..99dd674
--- /dev/null
+++ b/api/RingBuffer.h
@@ -0,0 +1,57 @@
+/*
+  Copyright (c) 2014 Arduino.  All right 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 _RING_BUFFER_
+#define _RING_BUFFER_
+
+#include <stdint.h>
+
+// Define constants and variables for buffering incoming serial data.  We're
+// using a ring buffer (I think), in which head is the index of the location
+// to which to write the next incoming character and tail is the index of the
+// location from which to read.
+
+#define RINGBUFFER_SIZE 64
+
+class RingBuffer
+{
+    public:
+    uint8_t _aucBuffer[RINGBUFFER_SIZE] ;
+    int _iHead ;
+    int _iTail ;
+
+    public:
+    RingBuffer( void ) ;
+    void store_char( uint8_t c ) ;
+    void clear();
+    int read_char();
+    int available();
+    int peek();
+    bool isFull();
+    void addStorage(uint8_t* _buffer, int _size) {
+        additionalSize = _size;
+        additionalBuffer = _buffer;
+    };
+
+    private:
+    int nextIndex(int index);
+    uint8_t* additionalBuffer;
+    int additionalSize = 0;
+};
+
+#endif /* _RING_BUFFER_ */
