Axeda Corp
/
AxedaGo-ubloxC027
Axeda demo software for u-blox C027 (GSM)
Diff: C027_Support/Pipe.h
- Revision:
- 0:a725e8eab383
diff -r 000000000000 -r a725e8eab383 C027_Support/Pipe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C027_Support/Pipe.h Mon Aug 11 19:02:42 2014 +0000 @@ -0,0 +1,242 @@ +#pragma once + +/** pipe, this class implements a buffered pipe that can be savely + written and read between two context. E.g. Written from a task + and read from a interrupt. +*/ +template <class T> +class Pipe +{ +public: + /* Constructor + \param n size of the pipe/buffer + \param b optional buffer that should be used. + if NULL the constructor will allocate a buffer of size n. + */ + Pipe(int n, T* b = NULL) + { + _a = b ? NULL : n ? new T[n] : NULL; + _r = 0; + _w = 0; + _b = b ? b : _a; + _s = n; + } + /** Destructor + frees a allocated buffer. + */ + ~Pipe(void) + { + if (_a) + delete [] _a; + } + + /* This function can be used during debugging to hexdump the + content of a buffer to the stdout. + */ + void dump(void) + { + int o = _r; + printf("pipe: %d/%d ", size(), _s); + while (o != _w) { + T t = _b[o]; + printf("%0*X", sizeof(T)*2, t); + o = _inc(o); + } + printf("\n"); + } + + // writing thread/context API + //------------------------------------------------------------- + + /** Check if buffer is writeable (=not full) + \return true if writeable + */ + bool writeable(void) + { + return free() > 0; + } + + /** Return the number of free elements in the buffer + \return the number of free elements + */ + int free(void) + { + int s = _r - _w; + if (s <= 0) + s += _s; + return s - 1; + } + + /* Add a single element to the buffer. (blocking) + \param c the element to add. + \return c + */ + T putc(T c) + { + int i = _w; + int j = i; + i = _inc(i); + while (i == _r) // = !writeable() + /* nothing / just wait */; + _b[j] = c; + _w = i; + return c; + } + + /* Add a buffer of elements to the buffer. + \param p the elements to add + \param n the number elements to add from p + \param t set to true if blocking, false otherwise + \return number elements added + */ + int put(const T* p, int n, bool t = false) + { + int c = n; + while (c) + { + int f; + for (;;) // wait for space + { + f = free(); + if (f > 0) break; // data avail + if (!t) return n - c; // no more space and not blocking + /* nothing / just wait */; + } + // check free space + if (c < f) f = c; + int w = _w; + int m = _s - w; + // check wrap + if (f > m) f = m; + memcpy(&_b[w], p, f); + _w = _inc(w, f); + c -= f; + p += f; + } + return n - c; + } + + // reading thread/context API + // -------------------------------------------------------- + + /** Check if there are any emelemnt available (readble / not empty) + \return true if readable/not empty + */ + bool readable(void) + { + return (_r != _w); + } + + /** Get the number of values available in the buffer + return the number of element available + */ + int size(void) + { + int s = _w - _r; + if (s < 0) + s += _s; + return s; + } + + /** get a single value from buffered pipe (this function will block if no values available) + \return the element extracted + */ + T getc(void) + { + int r = _r; + while (r == _w) // = !readable() + /* nothing / just wait */; + T t = _b[r]; + _r = _inc(r); + return t; + } + + /*! get elements from the buffered pipe + \param p the elements extracted + \param n the maximum number elements to extract + \param t set to true if blocking, false otherwise + \return number elements extracted + */ + int get(T* p, int n, bool t = false) + { + int c = n; + while (c) + { + int f; + for (;;) // wait for data + { + f = size(); + if (f) break; // free space + if (!t) return n - c; // no space and not blocking + /* nothing / just wait */; + } + // check available data + if (c < f) f = c; + int r = _r; + int m = _s - r; + // check wrap + if (f > m) f = m; + memcpy(p, &_b[r], f); + _r = _inc(r, f); + c -= f; + p += f; + } + return n - c; + } + + // the following functions are useful if you like to inspect + // or parse the buffer in the reading thread/context + // -------------------------------------------------------- + + /** set the parsing index and return the number of available + elments starting this position. + \param ix the index to set. + \return the number of elements starting at this position + */ + int set(int ix) + { + int sz = size(); + ix = (ix > sz) ? sz : ix; + _o = _inc(_r, ix); + return sz - ix; + } + + /** get the next element from parsing position and increment parsing index + \return the extracted element. + */ + T next(void) + { + int o = _o; + T t = _b[o]; + _o = _inc(o); + return t; + } + + /** commit the index, mark the current parsing index as consumed data. + */ + void done(void) + { + _r = _o; + } + +private: + /** increment the index + \param i index to increment + \param n the step to increment + \return the incremented index. + */ + inline int _inc(int i, int n = 1) + { + i += n; + if (i >= _s) + i -= _s; + return i; + } + + T* _b; //!< buffer + T* _a; //!< allocated buffer + int _s; //!< size of buffer (s - 1) elements can be stored + volatile int _w; //!< write index + volatile int _r; //!< read index + int _o; //!< offest index used by parsing functions +};