]> gitweb.hamatoma.de Git - cpidjinn/commitdiff
+ arraylist.*
authorhama <hama@siduction.net>
Sun, 7 Aug 2016 07:20:30 +0000 (09:20 +0200)
committerhama <hama@siduction.net>
Sun, 7 Aug 2016 07:20:30 +0000 (09:20 +0200)
19 files changed:
Server/Makefile
Server/arraylist.cpp [new symlink]
Server/arraylist.hpp [new symlink]
Server/gpioprocessor.cpp
Server/gpioprocessor.hpp
Server/gpiotimer.cpp
Server/gpiotimer.hpp
Server/tcpserver.cpp
util/Makefile
util/arraylist.cpp [new file with mode: 0644]
util/arraylist.hpp [new file with mode: 0644]
util/cuarraylist.cpp [new file with mode: 0644]
util/cutimer.cpp
util/test.cpp
util/test.hpp
util/thread.cpp
util/timer.cpp
util/timer.hpp
util/util.hpp

index 872c979fc66cc5dd76dd26a9b49cf5dbc0591a35..9e480f05fe9eb9a2b2ccbaa251b7ce2e5b77766b 100644 (file)
@@ -4,7 +4,7 @@ CFLAGS = -Wall
 LDFLAGS = -lbcm2835 -lpthread
 
 OBJ_UTIL_MINIMAL = dynbuffer.o logger.o
-OBJ_UTIL = timer.o thread.o $(OBJ_UTIL_MINIMAL)
+OBJ_UTIL = arraylist.o timer.o thread.o $(OBJ_UTIL_MINIMAL)
 OBJ = bcm2835def.o bcm2835.o gpiotimer.o cpidjinn.o $(OBJ_UTIL) tcpserver.o gpioprocessor.o
 PROG = cpidjinn
 
diff --git a/Server/arraylist.cpp b/Server/arraylist.cpp
new file mode 120000 (symlink)
index 0000000..1357045
--- /dev/null
@@ -0,0 +1 @@
+../util/arraylist.cpp
\ No newline at end of file
diff --git a/Server/arraylist.hpp b/Server/arraylist.hpp
new file mode 120000 (symlink)
index 0000000..8981849
--- /dev/null
@@ -0,0 +1 @@
+../util/arraylist.hpp
\ No newline at end of file
index 43401487e9d3ae5c99c72d6c4484304469bfab9d..8555d782abf4c2f212b8398dfe6f71c82e173e09 100644 (file)
@@ -42,12 +42,11 @@ void GPIOProcessor::blink(DynBuffer& buffer){
                int periodLow = buffer.valueOfLE(4, 5 + 2*4);
                SquareWaveTimer* timer = new SquareWaveTimer(pin, 0, count, periodHigh, periodLow,
                                                                                                         this, m_logger, &m_pool);
-               timer->start();
+               replaceTimer(pin, timer);
                printf("Pin: %d count: %d high: %d low: %d\n", (int) pin, count, periodHigh, periodLow);
                buffer.set("OK  ");
        }
 }
-
 /**
  * Returns the next "free" buffer.
  *
@@ -171,12 +170,60 @@ TcpProcessor::State GPIOProcessor::process(DynBuffer& buffer){
                trace(buffer);
        } else if (buffer.startsWith("GETB", 4)){
                getBuffer(buffer);
+       } else if (buffer.startsWith("OPWM", 4)){
+               pwmOutput(buffer);
        } else {
                rc = stIgnored;
        }
        return rc;
 }
 
+/**
+ * Initializes a Pulse Width Modulation output sequence.
+ *
+ * Syntax: OPWM[pin][clock][steps][startvalue][function][functionSteps]<br>
+ * [pin]: 1 byte. Numbering like <i>PinNumber</i>.<br>
+ * [period]: 4 byte little endian. duration of a time slice in micro seconds.<br>
+ * [startvalue]: 2 byte little endian, first value when starting the sequence multiplied by 1E4.
+ * [function]: 's': sin, 'r': rising slope, 'f': falling slope, 'd': dual slope
+ * [functionSteps]: 2 byte little endian, number of PWM periods defining one function period
+ * [count]: 4 byte little endian.number of function periods
+ *
+ * @param buffer               IN: contains the blink command<br>
+ *                                             OUT: answer for the client
+ */
+void GPIOProcessor::pwmOutput(DynBuffer& buffer){
+       if (buffer.length() != 18){
+               buffer.clear().appendFormatted("ERR wrong packet length %d instead of 18",
+                                                                       buffer.length());
+       } else {
+               PinNumber pin = (PinNumber) buffer.str()[4];
+               int period = buffer.valueOfLE(4, 5);
+               double startValue = buffer.valueOfLE(4, 5 + 4) / 1E4;
+               char function = buffer.at(5 + 4 + 4);
+               int functionSteps = buffer.valueOfLE(2, 5 + 4 + 2 + 1);
+               int count = buffer.valueOfLE(4, 5 + 4 + 2 + 1 + 2);
+               PwmOutputTimer* timer = new PwmOutputTimer(pin, period, startValue, function, functionSteps, count,
+                                                                                                        this, m_logger, &m_pool);
+               replaceTimer(pin, timer);
+               printf("Pin: %d period: %d start: %f function: %c functionSteps: %d count: %d\n",
+                          (int) pin, period, startValue, function, functionSteps, count);
+               buffer.set("OK  ");
+       }
+}
+/**
+ * Replaces the current timer task with a new one.
+ *
+ * @param timer        the new timer task
+ */
+void GPIOProcessor::replaceTimer(PinNumber pin, GPIOTimer* timer){
+       GPIOTimer* oldTimer = m_timers[pin];
+       if (oldTimer != NULL)
+               oldTimer->terminate();
+       m_timers[pin] = timer;
+       timer->start();
+}
+
 /**
  * Inspects the input state of a GPIO pin in a timer loop.
  *
@@ -204,7 +251,7 @@ void GPIOProcessor::trace(DynBuffer& buffer){
                } else {
                        TraceInputTimer* timer = new TraceInputTimer(pin, delay,
                                                count,outputBuffer, this, m_logger, &m_pool);
-                       timer->start();
+                       replaceTimer(pin, timer);
                        buffer.set("OK  #").append(name);
                }
        }
index ac7b3ce6a70ca0f8108908d3f447b130748b98da..9cc82d0a1e750bad4d9f3c0562df92a6353a9789 100644 (file)
@@ -2,6 +2,7 @@
 #define GPIOPROCESSOR_H
 
 #define MAX_PINS 64
+class GPIOTimer;
 class GPIOProcessor : public Bcm2835, public TcpProcessor
 {
 public:
@@ -19,11 +20,14 @@ private:
        void getBuffer(DynBuffer& buffer);
        void melody(DynBuffer& buffer);
        void pulseWidthModulation(DynBuffer& buffer);
+       void pwmOutput(DynBuffer& buffer);
+       void replaceTimer(PinNumber pin, GPIOTimer* timer);
        void trace(DynBuffer& buffer);
 public:
        virtual State process(DynBuffer& buffer);
 private:
        PinInfo m_pins[MAX_PINS];
+       GPIOTimer* m_timers[MAX_PINS];
        Announcer* m_logger;
        ThreadPool m_pool;
        DynBuffer* m_buffers[26];
index ba8a160a3fce6c4d8dde1256688e00b1938b1a53..676b11b8acddf4e94c6b6fe1f212c16fd8c06210 100644 (file)
@@ -1,4 +1,5 @@
 #include "cpidjinn.hpp"
+#include "math.h"
 
 /**
  * Constructor.
@@ -32,6 +33,71 @@ void GPIOTimer::switchState(PinState state){
        m_logger->sayf(LOG_DEBUG, "pin %d: %c", m_pin, state ? 'H' : 'L');
        m_processor->writeToGPIO(m_pin, state);
 }
+
+/**
+ * Constructor.
+ *
+ * @param pin                  the pin for output
+ * @param period               duration of a single pwm signal in microseconds
+ * @param startValue   the first PWM value: 0.0..1.0
+ * @param function             function defining the PWM values.<br>
+ *                                             s(in), f(alling slope) r(ising slope) d(ual slope)
+ * @param functionSteps        number PWM periods defining a "function period".<br>
+ *                                             After this number of PWM periods the values are repeated
+ * @param count                        number of function periods
+ */
+PwmOutputTimer::PwmOutputTimer(PinNumber pin, int period,
+                               double startValue, char function, int functionSteps, int count,
+                               GPIOProcessor* gpioProcessor, Announcer* logger, ThreadPool* pool) :
+       GPIOTimer(pin, 0, gpioProcessor, logger, pool),
+       m_period(period),
+       m_value(startValue),
+       m_function(function),
+       m_functionSteps(functionSteps),
+       m_functionStep(0),
+       m_high(true)
+{
+       m_taskCount = 2 * count;
+}
+
+/**
+ * The action done from the timer.
+ */
+void PwmOutputTimer::timerTask(){
+       m_high = ! m_high;
+       if (! m_high){
+               m_delay = m_period - (int) (m_period / m_value);
+       } else {
+               if (++m_functionStep == m_functionSteps)
+                       m_functionStep = 0;
+               double x = m_functionStep / (double) m_functionSteps;
+               switch(m_function){
+               case 'c':
+                       // no change!
+                       break;
+               case 's':
+                       m_value = sin(M_PI * x);
+                       break;
+               case 'f':
+                       m_value = 1.0 - x;
+                       break;
+               case 'r':
+                       m_value = x;
+                       break;
+               case 'd':
+                       if (x < 0.5)
+                               m_value = x / 2.0;
+                       else
+                               m_value = 1.0 - x / 2.0;
+                       break;
+               default:
+                       break;
+               }
+               m_delay = (int) (m_period / m_value);
+       }
+       switchState(m_high ? psHigh : psLow);
+}
+
 /**
  * Constructor.
  *
index 79199f914110d2741ceee38df3615a186a6bbc8c..86f7bbe8ecde32c0eb588ed67b63923a182570f2 100644 (file)
@@ -19,6 +19,39 @@ protected:
        GPIOProcessor* m_processor;
 };
 
+/**
+ * A timer producing a sequence of PWM pulses with values following a given function.
+ *
+ * The PWM value is the ratio duration_high / period: [0.0, 1.0]
+ *
+ * <pre>Example for the function "rising slope" period=4 functionSteps=5 startValue=0.25
+ *  ___     ____    ______   _______        ___
+ *  | |_____|  |____|    |__|       |_______| |
+ *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0
+ * 5 values: [0.25, 0.5, 0.75. 1, 0]
+ * </pre>
+ */
+class PwmOutputTimer : public GPIOTimer{
+public:
+       PwmOutputTimer(PinNumber pin, int period,
+                               double startValue, char function, int functionSteps, int count,
+                               GPIOProcessor* gpioProcessor, Announcer* logger, ThreadPool* pool);
+public:
+       DynBuffer& name(DynBuffer& buffer){
+               buffer.set("PwmOutputTimer");
+               return buffer;
+       }
+       virtual void timerTask();
+private:
+        int m_period;
+        double m_value;
+        char m_function;
+        int m_functionSteps;
+        int m_functionStep;
+        bool m_high;
+};
+
+
 /**
  * A timer producing a square wave with constant frequency.
  */
@@ -28,6 +61,10 @@ public:
                                uint64_t high, uint64_t low,
                                GPIOProcessor* gpioProcessor, Announcer* logger, ThreadPool* pool);
 public:
+       DynBuffer& name(DynBuffer& buffer){
+               buffer.set("SquareWaveTimer");
+               return buffer;
+       }
        virtual void timerTask();
 private:
        uint64_t m_pause;
@@ -36,6 +73,7 @@ private:
        bool m_nextHigh;
 };
 
+
 /**
  * A timer watching states in a given interval.
  */
@@ -44,6 +82,10 @@ public:
        TraceInputTimer(PinNumber pin, uint64_t pause, int count, DynBuffer* buffer,
                                GPIOProcessor* gpioProcessor, Announcer* logger, ThreadPool* pool);
 public:
+       DynBuffer& name(DynBuffer& buffer){
+               buffer.set("TraceInputTimer");
+               return buffer;
+       }
        virtual void timerTask();
 private:
        DynBuffer* m_buffer;
index be8e3a6fa55c95a666959355ba5c72dd12943fed..657f68732ccfdf227d44712a1e2eace140bfc865 100644 (file)
@@ -178,9 +178,12 @@ void TcpServer::listen(){
                                                int sent;
                                                while ( (sent = ::send (connectionSocket, m_buffer.str() + offset,
                                                                                   m_buffer.length() - offset, 0)) > 0){
-                                                       m_logger->sayf(LOG_DEBUG, "sent: %.4s[%d/%d]",
-                                                               m_buffer.str(), sent, m_buffer.length() - offset);
-                                                       if (offset + sent >= m_buffer.length())
+                                                       if (m_buffer.startsWith("ERR"))
+                                                               m_logger->sayf(LOG_DEBUG, "sent: %s", m_buffer.str());
+                                                       else
+                                                               m_logger->sayf(LOG_DEBUG, "sent: %.4s[%d/%d]",
+                                                                       m_buffer.str(), sent, m_buffer.length() - offset);
+                                                       if (offset + sent >= (int) m_buffer.length())
                                                                break;
                                                        offset += sent;
                                                }
index a385304aa901fab0f00783282ccc3f741ee6e86f..32ef2c96cd0329b21160039a21b50188a21fc4e7 100644 (file)
@@ -3,8 +3,9 @@ CFLAGS = "-Wall"
 LDFLAGS = -lm -lpthread
 CL = g++
 
-OBJ = cutimeutils.o timeutils.o cutimer.o cudynbuffer.o thread.o timer.o dynbuffer.o \
-       logger.o unittest.o test.o
+OBJ = cuarraylist.o cutimeutils.o cutimer.o cudynbuffer.o \
+       arraylist.o dynbuffer.o logger.o timeutils.o unittest.o test.o thread.o \
+       timer.o
 PROG = test
 
 all : $(PROG)
diff --git a/util/arraylist.cpp b/util/arraylist.cpp
new file mode 100644 (file)
index 0000000..7f11c81
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+ * (Un)License: Public Domain
+ * You can use and modify this file without any restriction.
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * More info: http://unlicense.org
+ * The latest sources: https://github.com/republib
+ *
+ */
+#include "stdlib.h"
+#include "assert.h"
+#include "memory.h"
+#include "util.hpp"
+
+/**
+ * Constructor.
+ *
+ * @param capacity                     the size of the list m_buffer
+ * @param blocksize                    the minimum count of entries to reserve
+ * @param maxBlocksize         the blocksize is doubled during enlarging the buffer
+ *                                                     while blocksize is smaller than this maximum
+ * @param sorted                       <i>true</i>: the buffer is sorted
+ */
+BaseArrayList::BaseArrayList(int capacity, int blocksize, int maxBlocksize,
+               bool sorted) :
+       m_capacity(capacity),
+       m_blocksize(blocksize),
+       m_maxBlocksize(maxBlocksize),
+       m_count(0),
+       m_buffer(new void*[capacity]),
+       m_sorted(sorted)
+{
+       memset(m_buffer, 0, capacity * sizeof m_buffer[0] );
+}
+
+/**
+ * Copy constructor.
+ *
+ * @param source       the source to copy
+ */
+BaseArrayList::BaseArrayList ( const BaseArrayList& source ) :
+       m_capacity(source.m_capacity),
+       m_blocksize(source.m_blocksize),
+       m_maxBlocksize(source.m_maxBlocksize),
+       m_count(source.m_count),
+       m_buffer(new void*[source.m_capacity]),
+       m_sorted(source.m_sorted)
+{
+       // the derived class must call cloneBuffer().
+       // not allowed here: virtual method cloneItem() is not initialized here
+}
+
+
+/**
+ * Destructor.
+ */
+BaseArrayList::~BaseArrayList() {
+       for (int ix = 0; ix < m_capacity; ix++){
+               if (m_buffer[ix] != NULL){
+                       destroyItem(m_buffer[ix]);
+               }
+       }
+       memset(m_buffer, 0, sizeof m_buffer[0] * m_capacity);
+       delete[] m_buffer;
+       m_buffer = NULL;
+}
+
+/**
+ * Assign operator.
+ *
+ * @param source       source to copy
+ * @return                     the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::operator= ( const BaseArrayList& source ) {
+       clear();
+       m_sorted = source.m_sorted;
+       cloneBuffer(source);
+       return *this;
+}
+
+/**
+ * Adds an item to the list.
+ *
+ * @return                     the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::add(const void* item, int index){
+       if (m_count + 1 > m_capacity)
+               ensuresSize(m_count+1);
+       if (m_sorted){
+               // ignore index!
+               int index;
+               binarySearch(item, index);
+               if (index >= m_count){
+                       m_buffer[m_count++] = cloneItem(item);
+               } else {
+                       // build a gap:
+                       // [?, ?, ix, ?]: items to copy: 4 - 2 = count - ix
+                       memmove(m_buffer + index + 1, m_buffer + index,
+                                       sizeof m_buffer[0] * (m_count++ - index));
+                       m_buffer[index] = cloneItem(item);
+               }
+       } else {
+               if (index >= m_count)
+                       m_buffer[m_count++] = cloneItem(item);
+               else {
+                       if (index < 0)
+                               index = 0;
+                       memcpy(m_buffer + index, m_buffer + index + 1, sizeof m_buffer[0] * (++m_count - index));
+                       m_buffer[index] = cloneItem(item);
+               }
+
+       }
+       return *this;
+}
+
+/**
+ * @brief Searches the an element with binary search.
+ *
+ * @param toFind       the value which should be found
+ * @param index     OUT: the index usable for insert:
+ *                                     index is the smallest value with content[index] >= toFind
+ * @return                     true: the key has been found.
+ */
+bool BaseArrayList::binarySearch(const void* item, int& index) const {
+       assert(m_sorted);
+       bool rc = false;
+       int lbound = 0;
+       int theCount = m_count;
+       int ubound = theCount - 1;
+       int compareRc = 0;
+       // binary search over the sorted vector:
+       while (lbound <= ubound) {
+               int half = (ubound + lbound) / 2;
+               compareRc = compareItems(item, (const void*) m_buffer[half]);
+               if (compareRc < 0)
+                       ubound = half - 1;
+               else if (compareRc > 0)
+                       lbound = half + 1;
+               else {
+                       rc = true;
+                       index = half;
+                       break;
+               }
+       }
+       if (!rc)
+               index = ubound > lbound ? ubound :
+                       lbound > theCount ? theCount : lbound;
+       return rc;
+}
+
+/**
+ * Removes all items.
+ *
+ * @return                     the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::clear(){
+       for (int ix = m_count - 1; ix >= 0; ix--)
+               removeAt(ix);
+       m_count = 0;
+       return *this;
+}
+
+/**
+ * Clones the buffer.
+ *
+ * This method must not be called from a copy constructor of BaseArrayList:
+ * It uses the abstract methed cloneItem(), which is not initialized
+ * in the base class.
+ *
+ * Call it in the copy constructor of the derived class.
+ *
+ * @param source       the source
+ */
+void BaseArrayList::cloneBuffer(const BaseArrayList& source){
+       ensuresSize(m_count = source.m_count);
+       for (int ix = 0; ix < m_count; ix++){
+               m_buffer[ix] = cloneItem(reinterpret_cast<void*>(source.m_buffer[ix]));
+       }
+}
+
+/**
+ * Compares two items.
+ *
+ * @param item1        the first item to compare
+ * @param item2        the 2nd item to compare
+ * @return             0: the items are equal<br>
+ *                             <0: item1 < item2<br>
+ *                             >0: item2 > item2
+ */
+int BaseArrayList::compareItems(const void* item1, const void* item2) const{
+       int rc = item1 == item2 ? 0 : (int) ((char*) item1 - (char*) item2);
+       return rc;
+}
+
+/**
+ * Ensures that the list have at least the given size.
+ *
+ * @param capacity     the size to inspect
+ * @return                     the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::ensuresSize(int capacity){
+       if (capacity > m_capacity){
+               if ((m_blocksize *= 2) > m_maxBlocksize)
+                       m_blocksize = m_maxBlocksize;
+               if (capacity - m_capacity < m_blocksize)
+                       capacity = m_capacity + m_blocksize;
+               void** buffer = new void*[m_capacity = capacity];
+               memcpy(buffer, m_buffer, sizeof m_buffer[0] * m_count);
+               delete[] m_buffer;
+               m_buffer = buffer;
+       }
+       return *this;
+}
+/**
+ * Search the item in the list.
+ *
+ * @param item item to search
+ * @return             -1: not found<br>
+ *                             otherwise: the index of the item in the list
+ */
+int BaseArrayList::indexOf(const void* item) const{
+       int rc;
+       if (m_sorted){
+               if (! binarySearch(item, rc))
+                       rc = -1;
+       } else {
+               rc = -1;
+               for (int ix = 0; rc != 0 && ix < m_count; ix++){
+                       if (compareItems(item, (const void*) m_buffer[ix]) == 0)
+                               rc = 0;
+               }
+       }
+       return rc;
+}
+
+/**
+ * Removes a given item from the list.
+ *
+ * @param item item to delete
+ * @return             the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::remove(const void* item){
+       int index = indexOf(item);
+       if (index >= 0)
+               removeAt(index);
+       return *this;
+}
+
+/**
+ * Removes a the item with a given index from the list.
+ *
+ * @param index        item to delete
+ * @return             the instance (for chaining)
+ */
+BaseArrayList& BaseArrayList::removeAt(int index){
+       if (index >= 0 && index < m_count){
+               destroyItem(m_buffer[index]);
+               m_buffer[index] = NULL;
+               if (index < --m_count)
+                       // [?, ?, item, ?]: items to copy: 4 - 2 - 1 = count - ix - 1
+                       memcpy(m_buffer + index, m_buffer + index + 1, --m_count - index);
+       }
+       return *this;
+}
+
+/**
+ * Joins the list members to a concatenated string.
+ *
+ * @param buffer       the buffer for the result
+ * @return                     <i>buffer</i>: for chaining
+ */
+DynBuffer& CStringList::join(DynBuffer& buffer, const char* separator){
+       for (int ix = 0; ix < m_count; ix++){
+               if (ix > 0 && separator != NULL)
+                       buffer.append(separator);
+               buffer.append(get(ix));
+       }
+       return buffer;
+}
+
+void CStringList::dump(const char* title) const{
+       printf("=== %s: count: %d capacity: %d\n", title == NULL ? "" : title, count(), capacity());
+       const char* ptr;
+       for (int ii = 0; ii < m_count; ii++)
+               printf("%2d: %s\n", ii, (ptr = get(ii)) == NULL ? "<null>" : ptr);
+}
diff --git a/util/arraylist.hpp b/util/arraylist.hpp
new file mode 100644 (file)
index 0000000..b531db0
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * (Un)License: Public Domain
+ * You can use and modify this file without any restriction.
+ * Do what you want.
+ * No warranties and disclaimer of any damages.
+ * More info: http://unlicense.org
+ * The latest sources: https://github.com/republib
+ *
+ */
+
+#ifndef ARRAYLIST_H
+#define ARRAYLIST_H
+
+class BaseArrayList
+{
+public:
+    BaseArrayList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
+                         bool sorted = false);
+    BaseArrayList ( const BaseArrayList& other );
+    virtual ~BaseArrayList();
+    BaseArrayList& operator= ( const BaseArrayList& other );
+public:
+       virtual void* cloneItem(const void* source) = 0;
+public:
+       BaseArrayList& add(const void* item, int index = 0x7ffffff);
+       bool binarySearch(const void* item, int& index) const;
+       BaseArrayList& clear();
+       virtual int compareItems(const void* item1, const void* item2) const;
+       virtual void destroyItem(const void* item){
+       }
+       BaseArrayList& ensuresSize(int capacity);
+       int indexOf(const void* item) const;
+       BaseArrayList& remove(const void* item);
+       BaseArrayList& removeAt(int index);
+protected:
+       void cloneBuffer(const BaseArrayList& source);
+public:
+       inline void** getBuffer() const{
+               return m_buffer;
+       }
+protected:
+    int m_capacity;
+    int m_blocksize;
+       int m_maxBlocksize;
+    int m_count;
+    void** m_buffer;
+       bool m_sorted;
+};
+
+template<class T> class ArrayList : protected BaseArrayList {
+public:
+    ArrayList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
+                         bool sorted = false):
+                       BaseArrayList(capacity, blocksize, maxBlocksize, sorted) {
+       }
+    ArrayList ( const BaseArrayList& source ):
+               BaseArrayList(source){
+       }
+    virtual ~ArrayList(){
+    }
+    ArrayList& operator= ( const ArrayList& source ){
+               m_sorted = source.m_sorted;
+               cloneBuffer(source);
+               return *this;
+       }
+public:
+       inline ArrayList& add(const T* item, int index = 0x7ffffff){
+               BaseArrayList::add(reinterpret_cast<const void*>(item), index);
+               return *this;
+       }
+       inline int blocksize() const{
+               return m_blocksize;
+       }
+       inline int capacity() const{
+               return m_capacity;
+       }
+       inline ArrayList& clear(){
+               BaseArrayList::clear();
+               return *this;
+       }
+private:
+       virtual void* cloneItem(const void* source){
+               void* rc = reinterpret_cast<void*>(cloneItem(reinterpret_cast<const T*>(source)));
+               return rc;
+       }
+public:
+       virtual T* cloneItem(const T* source) = 0;
+
+private:
+       virtual int compareItems(const void* item1, const void* item2) const{
+               int rc = compareItems(reinterpret_cast<const T*> (item1),
+                       reinterpret_cast<const T *> (item2));
+                       return rc;
+               return rc;
+       }
+public:
+       virtual int compareItems(const T* item1, const T* item2) const = 0;
+       inline int count() const {
+               return m_count;
+       }
+private:
+       virtual void destroyItem(const void* item){
+               destroyItem(reinterpret_cast<const T*>(item));
+       }
+public:
+       virtual void destroyItem(const T* item){
+               delete (T*) item;
+       }
+       inline ArrayList& ensuresSize(int capacity){
+               BaseArrayList::ensuresSize(capacity);
+               return *this;
+       }
+       inline T* get(int index) const{
+               return index < 0 || index >= m_count ? NULL : reinterpret_cast<T*>(m_buffer[index]);
+       }
+       inline int indexOf(const T* item) const{
+               int rc = BaseArrayList::indexOf(reinterpret_cast<const void*>(item));
+               return rc;
+       }
+       ArrayList& remove(const T* item){
+               BaseArrayList::remove(reinterpret_cast<const void*>(item));
+               return *this;
+       }
+       inline ArrayList& removeAt(int index){
+               BaseArrayList::removeAt(index);
+               return *this;
+       }
+       inline int sorted() const{
+               return m_sorted;
+       }
+       inline void setSorted(bool sorted){
+               m_sorted = sorted;
+       }
+};
+
+/**
+ * List of strings delimited by '\0' (C string).
+ */
+class CStringList : public ArrayList<char> {
+public:
+       CStringList(int capacity = 16, int blocksize = 16, int maxBlocksize = 1024*1024,
+                         bool sorted = false):
+                       ArrayList(capacity, blocksize, maxBlocksize, sorted) {
+       }
+    CStringList ( const CStringList& source ) :
+               ArrayList(source){
+               cloneBuffer(source);
+       }
+public:
+       virtual char* cloneItem(const char* source){
+               char* rc = strdup(source);
+               return rc;
+       }
+       virtual int compareItems(const char* item1, const char* item2) const{
+               int rc = strcmp(item1, item2);
+               return rc;
+       }
+       virtual void destroyItem(const char* item){
+               // reserved with strdup()
+               free((void*) item);
+       }
+public:
+       DynBuffer& join(DynBuffer& buffer, const char* separator = NULL);
+       void dump(const char* title) const;
+};
+#endif // ARRAYLIST_H
diff --git a/util/cuarraylist.cpp b/util/cuarraylist.cpp
new file mode 100644 (file)
index 0000000..02184bc
--- /dev/null
@@ -0,0 +1,347 @@
+#include "test.hpp"
+#include "math.h"
+
+static Logger s_logger;
+static ThreadPool s_timerPool ( 2, &s_logger );
+
+class TestArrayList : public UnitTest {
+    private:
+    static int m_permutation[];
+    static int m_permutationSize;
+
+    public:
+    TestArrayList() :
+    UnitTest ( "cuarraylist" ) {
+
+    }
+    public:
+    virtual void run() {
+        testCopyUnsorted();
+               testCopySorted();
+        testDestroy();
+        testBasic();
+        testAddSorted();
+        testAddUnsorted();
+        testBlocksize();
+        testCapacity();
+        testClear();
+        testCount();
+        testCompareItems();
+        testDestroyItem();
+        testEnsuresSize();
+        testGet();
+        testIndexOf();
+        testRemove();
+        testRemoveAt();
+        testSorted();
+        testSetSorted();
+    }
+    void testCopyUnsorted() {
+        CStringList list1;
+        list1.add ( "Hi" );
+
+        CStringList list2 ( list1 );
+        checkE ( 1, list2.count() );
+        checkE ( "Hi", list2.get ( 0 ) );
+        checkF ( list2.sorted() );
+
+        list1.add ( " world" );
+        list2 = list1;
+        checkE ( 2, list2.count() );
+        checkE ( "Hi", list2.get ( 0 ) );
+        checkE ( " world", list2.get ( 1 ) );
+
+    }
+    void testCopySorted() {
+        CStringList list1 ( 16, 16, 256, true );
+        DynBuffer buffer;
+        for ( int ii = 0; ii < m_permutationSize * 2; ii++ ) {
+            buffer.clear().appendInt ( m_permutation[ii % m_permutationSize] );
+            list1.add ( buffer.str() );
+        }
+        CStringList list2 ( list1 );
+        checkT ( list2.sorted() );
+        checkE ( list1.count(), list2.count() );
+        for ( int ii = 0; ii < m_permutationSize; ii++ ) {
+            buffer.clear().appendInt ( ii );
+            checkE ( buffer.str(), list2.get ( 2*ii ) );
+            checkE ( buffer.str(), list2.get ( 2*ii + 1 ) );
+        }
+        CStringList list3;
+        list3 = list2;
+        checkT ( list3.sorted() );
+        checkE ( list1.count(), list3.count() );
+        for ( int ii = 0; ii < m_permutationSize; ii++ ) {
+            buffer.clear().appendInt ( ii );
+            checkE ( buffer.str(), list3.get ( 2*ii ) );
+            checkE ( buffer.str(), list3.get ( 2*ii + 1 ) );
+        }
+    }
+    void testDestroy() {
+        {
+            CStringList list;
+            list.add ( "Hi" );
+            list.clear();
+            list.add ( "Buh" );
+        }
+        m_logger.say ( LOG_DEBUG, "destroy successful" );
+    }
+    void testBasic() {
+        int capacity = 2;
+        int blocksize = 4;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        list.add ( "hi" );
+        list.add ( " " );
+        list.add ( "world" );
+        DynBuffer buffer;
+        checkE ( "hi world", list.join ( buffer ) );
+        list.clear();
+        buffer.clear();
+        checkE ( "", list.join ( buffer ) );
+    }
+    void testAddUnsorted() {
+        int capacity = 2;
+        int blocksize = 4;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+        }
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            checkE ( buffer.str(), list.get ( ix ) );
+        }
+    }
+    void testAddSorted() {
+        int capacity = 2;
+        int blocksize = 4;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, sorted );
+        DynBuffer buffer;
+        for ( int ix = 0; ix < m_permutationSize; ix++ ) {
+            buffer.clear().appendInt ( m_permutation[ix] );
+            list.add ( buffer.str() );
+        }
+        //list.dump(NULL);
+        for ( int ix = 0; ix < m_permutationSize; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            checkE ( buffer.str(), list.get ( ix ) );
+        }
+    }
+    void testBlocksize() {
+        int capacity = 1;
+        int blocksize = 1;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 1; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+        }
+        checkE ( 512, list.blocksize() );
+    }
+    void testCapacity() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 1; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+        }
+        checkE ( 2032, list.capacity() );
+    }
+    void testClear() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 1; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+        }
+        checkE ( 1023, list.count() );
+        checkE ( 0, list.clear().count() );
+
+    }
+    void testCompareItems() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        // same length:
+        checkT ( list.compareItems ( "abc", "abd" ) < 0 );
+        checkT ( list.compareItems ( "abc", "abc" ) == 0 );
+        checkT ( list.compareItems ( "abc", "abb" ) > 0 );
+        // different length:
+        checkT ( list.compareItems ( "abc", "abc " ) < 0 );
+        checkT ( list.compareItems ( "abc ", "abc" ) > 0 );
+
+    }
+    void testCount() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 1; ix <= 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+            checkE ( ix, list.count() );
+        }
+    }
+    void testDestroyItem() {
+        DynBuffer big;
+        int size = 10*1024*1024;
+        big.ensureSize ( size );
+        memset ( big.buffer(), 'x', size -1 );
+        big.setLength ( size - 1 );
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            CStringList list1;
+            list1.add ( big.str() );
+            list1.add ( big.str() );
+            checkE ( size - 1, strlen ( list1.get ( 0 ) ) );
+            checkE ( size - 1, strlen ( list1.get ( 1 ) ) );
+
+            CStringList list2 ( list1 );
+            checkE ( 2, list2.count() );
+            checkE ( size - 1, strlen ( list2.get ( 0 ) ) );
+            checkE ( size - 1, strlen ( list2.get ( 1 ) ) );
+        }
+        m_logger.say ( LOG_INFO, "end of testDestroyItem()" );
+    }
+    void testEnsuresSize() {
+        int capacity = 1;
+        int blocksize = 1;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 1; ix < 1024; ix++ ) {
+            list.ensuresSize ( 7*ix );
+            checkT ( list.capacity() >= 7*ix );
+        }
+    }
+    void testGet() {
+        int capacity = 2;
+        int blocksize = 4;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        list.add ( "joe" );
+        list.add ( "adam" );
+        list.add ( "charly" );
+        DynBuffer buffer;
+        checkE ( 3, list.count() );
+        checkE ( "joe", list.get ( 0 ) );
+        checkE ( "adam", list.get ( 1 ) );
+        checkE ( "charly", list.get ( 2 ) );
+        list.clear();
+
+        list.setSorted ( true );
+        list.add ( "joe" );
+        list.add ( "adam" );
+        list.add ( "charly" );
+        checkE ( 3, list.count() );
+        checkE ( "joe", list.get ( 0 ) );
+        checkE ( "adam", list.get ( 1 ) );
+        checkE ( "charly", list.get ( 2 ) );
+    }
+    void testIndexOf() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( 0x42ab7*ix );
+            list.add ( buffer.str() );
+        }
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( 0x42ab7*ix );
+            checkE ( ix, list.indexOf ( buffer.str() ) );
+        }
+    }
+    void testRemove() {
+        int capacity = 2;
+        int blocksize = 4;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 0; ix < m_permutationSize; ix++ ) {
+            buffer.clear().appendInt ( m_permutation[ix] );
+            list.add ( buffer.str() );
+        }
+        for ( int ix = 0; ix < m_permutationSize; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.remove ( buffer.str() );
+        }
+        checkE ( 0, list.count() );
+    }
+    void testRemoveAt() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        DynBuffer buffer;
+        for ( int ix = 0; ix < 1024; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            list.add ( buffer.str() );
+        }
+        for ( int ix = 1020; ix >= 3; ix-- ) {
+            list.removeAt ( ix );
+        }
+        checkE ( 8, list.count() );
+        for ( int ix = 0; ix < 4; ix++ ) {
+            buffer.clear().appendInt ( ix );
+            checkE ( buffer.str(), list.get ( ix ) );
+        }
+        for ( int ix = 4; ix < list.count(); ix++ ) {
+            buffer.clear().appendInt ( ix + 1020 );
+            checkE ( buffer.str(), list.get ( ix ) );
+        }
+    }
+    void testSorted() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, ! sorted );
+        checkF ( list.sorted() );
+        list.setSorted ( sorted );
+        checkT ( list.sorted() );
+    }
+    void testSetSorted() {
+        int capacity = 16;
+        int blocksize = 16;
+        int maxBlocksize = 1024*1024;
+        bool sorted = true;
+        CStringList list ( capacity, blocksize, maxBlocksize, sorted );
+        checkT ( list.sorted() );
+        list.setSorted ( !sorted );
+        checkF ( list.sorted() );
+    }
+};
+int TestArrayList::m_permutation[] = { 2, 7, 3, 1, 0, 9, 6, 8, 4, 5 };
+int TestArrayList::m_permutationSize = 10;
+
+void testArrayList() {
+    TestArrayList test;
+    test.run();
+}
index 47d86a6d158f2c7621af0298053b8fe988ef8640..e2096bd4712bab5851a411eb387150b5b694f299 100644 (file)
@@ -14,6 +14,10 @@ public:
 
        }
 public:
+       DynBuffer& name(DynBuffer& buffer){
+               buffer.set("PwmOutputTimer");
+               return buffer;
+       }
        virtual void timerTask(){
                trace1("Counter::timerTask %d\n", threadId());
                m_pool.lock();
index 96f6b5a982836f75acc8ec1d4abfa0c043d9c418..3855d68b5637677f0a05b920a4ccb0b1fd135621 100644 (file)
@@ -6,7 +6,9 @@ int main(int argc, char **argv) {
        extern void testDynBuffer();
        extern void testTimer();
        extern void testTimerUtils();
-       
+       extern void testArrayList();
+
+       testArrayList();
        testTimer();
        testTimerUtils();
        testDynBuffer();
index 49095a09719698bc9cdebcd673dfc031a2331b6e..700680c6108b55a87062bd0bd6be06357bc344ca 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __TEST_HPP
 #define __TEST_HPP
 #include "util.hpp"
+#include "arraylist.hpp"
 #include "unittest.hpp"
 
 #endif
index dc0beb9a1d135e2dc547fad27afc971c77ecdd6a..7950698b3f56c4b441a9937fce5ef50c3cff171f 100644 (file)
@@ -1,5 +1,5 @@
 #include "util.hpp"
-//#define TRACE_ON
+#define TRACE_ON
 #include "trace.hpp"
 
 int ThreadPool::m_currentMaxThreads = 128;
@@ -11,7 +11,7 @@ pthread_mutex_t Thread::m_mutexStarter = PTHREAD_MUTEX_INITIALIZER;
  * Connects the posix thread to the class instance.
  */
 void* threadStarter(void *param){
-       trace1("threadstarter(%llx)", (uint64_t) param);
+       trace1("threadstarter(%llx)", (long long unsigned int) param);
        Thread* thread = reinterpret_cast<Thread*>(param);
        thread->execute();
        return param;
@@ -54,7 +54,7 @@ void Thread::execute(){
        pthread_t pthread = m_pthread;
        if (m_autoDelete){
                trace1("Thread::execute(%d) autodelete\n", m_threadId);
-               delete this;
+               // delete this;
        }
        pthread_detach(pthread);
 }
@@ -175,7 +175,7 @@ void* ThreadPool::join(int threadId){
                if (thread != NULL)
                        Thread::microSleep(10*1000);
        } while(thread != NULL);
-       trace2("join: thread: %c %llx\n", thread != NULL ? 't' : 'f', (uint64_t) thread);
+       trace2("join: thread: %c %llx\n", thread != NULL ? 't' : 'f', (long long unsigned int) thread);
        return rc;
 }
 
index 4ff3fafa3bfe02e17e9f2784fb1d4a5094c3a142..2bd31429267f658a1f68f1c8a9d138b836c2157c 100644 (file)
@@ -41,6 +41,8 @@ void Timer::run(){
                timerTask();
                sleep(m_delay);
        }
+       DynBuffer buffer;
+       printf("timer stop ready: %s\n", name(buffer).str());
 }
 
 /**
index 3d34d41e91708494d95263f687f46aff6552165e..9c4ec412622de41d5e62d41653caec69a0379aab 100644 (file)
@@ -21,6 +21,13 @@ private:
        // not implemented, private to avoid usage:
     Timer ( const Timer& other );
     Timer& operator= ( const Timer& other );
+public:
+       /**
+        * Returns the name of the timer.
+        * @param buffer        OUT: the buffer for the name
+        * @return                      <i>buffer</i> (for chaining)
+        */
+       virtual DynBuffer& name(DynBuffer& buffer) = 0;
 public:
        virtual void timerTask() = 0;
 private:
index 3ed542d7870423c9d14ca940ee68babbcb69824f..428393a9643ca754fefb12a3481bcdaf3889cd2a 100644 (file)
 
 typedef unsigned char ubyte_t;
 #include "dynbuffer.hpp"
+#include "arraylist.hpp"
 #include "timeutils.hpp"
 #include "logger.hpp"
 #include "thread.hpp"
 #include "timer.hpp"
+
 #endif