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
--- /dev/null
+../util/arraylist.cpp
\ No newline at end of file
--- /dev/null
+../util/arraylist.hpp
\ No newline at end of file
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.
*
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.
*
} else {
TraceInputTimer* timer = new TraceInputTimer(pin, delay,
count,outputBuffer, this, m_logger, &m_pool);
- timer->start();
+ replaceTimer(pin, timer);
buffer.set("OK #").append(name);
}
}
#define GPIOPROCESSOR_H
#define MAX_PINS 64
+class GPIOTimer;
class GPIOProcessor : public Bcm2835, public TcpProcessor
{
public:
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];
#include "cpidjinn.hpp"
+#include "math.h"
/**
* Constructor.
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.
*
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.
*/
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;
bool m_nextHigh;
};
+
/**
* A timer watching states in a given interval.
*/
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;
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;
}
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)
--- /dev/null
+/*
+ * (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);
+}
--- /dev/null
+/*
+ * (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
--- /dev/null
+#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();
+}
}
public:
+ DynBuffer& name(DynBuffer& buffer){
+ buffer.set("PwmOutputTimer");
+ return buffer;
+ }
virtual void timerTask(){
trace1("Counter::timerTask %d\n", threadId());
m_pool.lock();
extern void testDynBuffer();
extern void testTimer();
extern void testTimerUtils();
-
+ extern void testArrayList();
+
+ testArrayList();
testTimer();
testTimerUtils();
testDynBuffer();
#ifndef __TEST_HPP
#define __TEST_HPP
#include "util.hpp"
+#include "arraylist.hpp"
#include "unittest.hpp"
#endif
#include "util.hpp"
-//#define TRACE_ON
+#define TRACE_ON
#include "trace.hpp"
int ThreadPool::m_currentMaxThreads = 128;
* 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;
pthread_t pthread = m_pthread;
if (m_autoDelete){
trace1("Thread::execute(%d) autodelete\n", m_threadId);
- delete this;
+ // delete this;
}
pthread_detach(pthread);
}
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;
}
timerTask();
sleep(m_delay);
}
+ DynBuffer buffer;
+ printf("timer stop ready: %s\n", name(buffer).str());
}
/**
// 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:
typedef unsigned char ubyte_t;
#include "dynbuffer.hpp"
+#include "arraylist.hpp"
#include "timeutils.hpp"
#include "logger.hpp"
#include "thread.hpp"
#include "timer.hpp"
+
#endif