From: hama Date: Sun, 7 Aug 2016 07:20:30 +0000 (+0200) Subject: + arraylist.* X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=e3fc7ec38b037a8fc9bfad7da6f4918f6968e544;p=cpidjinn + arraylist.* --- diff --git a/Server/Makefile b/Server/Makefile index 872c979..9e480f0 100644 --- a/Server/Makefile +++ b/Server/Makefile @@ -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 index 0000000..1357045 --- /dev/null +++ b/Server/arraylist.cpp @@ -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 index 0000000..8981849 --- /dev/null +++ b/Server/arraylist.hpp @@ -0,0 +1 @@ +../util/arraylist.hpp \ No newline at end of file diff --git a/Server/gpioprocessor.cpp b/Server/gpioprocessor.cpp index 4340148..8555d78 100644 --- a/Server/gpioprocessor.cpp +++ b/Server/gpioprocessor.cpp @@ -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]
+ * [pin]: 1 byte. Numbering like PinNumber.
+ * [period]: 4 byte little endian. duration of a time slice in micro seconds.
+ * [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
+ * 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); } } diff --git a/Server/gpioprocessor.hpp b/Server/gpioprocessor.hpp index ac7b3ce..9cc82d0 100644 --- a/Server/gpioprocessor.hpp +++ b/Server/gpioprocessor.hpp @@ -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]; diff --git a/Server/gpiotimer.cpp b/Server/gpiotimer.cpp index ba8a160..676b11b 100644 --- a/Server/gpiotimer.cpp +++ b/Server/gpiotimer.cpp @@ -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.
+ * s(in), f(alling slope) r(ising slope) d(ual slope) + * @param functionSteps number PWM periods defining a "function period".
+ * 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. * diff --git a/Server/gpiotimer.hpp b/Server/gpiotimer.hpp index 79199f9..86f7bbe 100644 --- a/Server/gpiotimer.hpp +++ b/Server/gpiotimer.hpp @@ -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] + * + *
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]
+ * 
+ */ +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; diff --git a/Server/tcpserver.cpp b/Server/tcpserver.cpp index be8e3a6..657f687 100644 --- a/Server/tcpserver.cpp +++ b/Server/tcpserver.cpp @@ -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; } diff --git a/util/Makefile b/util/Makefile index a385304..32ef2c9 100644 --- a/util/Makefile +++ b/util/Makefile @@ -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 index 0000000..7f11c81 --- /dev/null +++ b/util/arraylist.cpp @@ -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 true: 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(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
+ * <0: item1 < item2
+ * >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
+ * 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 buffer: 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 ? "" : ptr); +} diff --git a/util/arraylist.hpp b/util/arraylist.hpp new file mode 100644 index 0000000..b531db0 --- /dev/null +++ b/util/arraylist.hpp @@ -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 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(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(cloneItem(reinterpret_cast(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 (item1), + reinterpret_cast (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(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(m_buffer[index]); + } + inline int indexOf(const T* item) const{ + int rc = BaseArrayList::indexOf(reinterpret_cast(item)); + return rc; + } + ArrayList& remove(const T* item){ + BaseArrayList::remove(reinterpret_cast(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 { +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 index 0000000..02184bc --- /dev/null +++ b/util/cuarraylist.cpp @@ -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(); +} diff --git a/util/cutimer.cpp b/util/cutimer.cpp index 47d86a6..e2096bd 100644 --- a/util/cutimer.cpp +++ b/util/cutimer.cpp @@ -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(); diff --git a/util/test.cpp b/util/test.cpp index 96f6b5a..3855d68 100644 --- a/util/test.cpp +++ b/util/test.cpp @@ -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(); diff --git a/util/test.hpp b/util/test.hpp index 49095a0..700680c 100644 --- a/util/test.hpp +++ b/util/test.hpp @@ -1,6 +1,7 @@ #ifndef __TEST_HPP #define __TEST_HPP #include "util.hpp" +#include "arraylist.hpp" #include "unittest.hpp" #endif diff --git a/util/thread.cpp b/util/thread.cpp index dc0beb9..7950698 100644 --- a/util/thread.cpp +++ b/util/thread.cpp @@ -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(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; } diff --git a/util/timer.cpp b/util/timer.cpp index 4ff3faf..2bd3142 100644 --- a/util/timer.cpp +++ b/util/timer.cpp @@ -41,6 +41,8 @@ void Timer::run(){ timerTask(); sleep(m_delay); } + DynBuffer buffer; + printf("timer stop ready: %s\n", name(buffer).str()); } /** diff --git a/util/timer.hpp b/util/timer.hpp index 3d34d41..9c4ec41 100644 --- a/util/timer.hpp +++ b/util/timer.hpp @@ -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 buffer (for chaining) + */ + virtual DynBuffer& name(DynBuffer& buffer) = 0; public: virtual void timerTask() = 0; private: diff --git a/util/util.hpp b/util/util.hpp index 3ed542d..428393a 100644 --- a/util/util.hpp +++ b/util/util.hpp @@ -12,8 +12,10 @@ typedef unsigned char ubyte_t; #include "dynbuffer.hpp" +#include "arraylist.hpp" #include "timeutils.hpp" #include "logger.hpp" #include "thread.hpp" #include "timer.hpp" + #endif