summaryrefslogtreecommitdiff
path: root/trunk/users/lamadio
diff options
context:
space:
mode:
authorlamadio <lamadio>2009-02-28 01:37:19 +0000
committerlamadio <lamadio@cb376a5e-1013-0410-a455-b6b1f9ac8223>2009-02-28 01:37:19 +0000
commit4e9447d867358b43c71b59cf2b24a3326dc360a1 (patch)
tree5fdf6a4c83e51e7fb75b1cbb06c31b89e6ec0dd6 /trunk/users/lamadio
parent6e4598df6c4a4bf83293ae23ab420f5b7b8a65a7 (diff)
downloadreprap-4e9447d867358b43c71b59cf2b24a3326dc360a1.tar.gz
reprap-4e9447d867358b43c71b59cf2b24a3326dc360a1.zip
Arduino port of the firmware refactor proposal.
This particular change introduces several concepts: 1) Dynamic arrays are used internally for tracking various interesting bits of data, such as timers, periodic calls, and observations. In addition, this array can be used as a queue or a stack. While constructing this, I discovered a bug in realloc which corrupts the freelist, however, the fix is understood, but can take quite a while to make it into a mainline build. 2) Introduces the following classes: Observable - An object that has events which can be subscribed to Observer - An object which consumes manually generated events PeriodicCallback - An object which is called every event loop cycle. EventLoopTimer - An object which is called at a specified period. This code also handles period wrapping. EventLoop - An object which manages all top level interactions on the Arduino. It services the PeriodicCallback and EventLoopTimer objects when they request servicing (they can be added dynamically as needed). Device - A generic abstraction dealing with generic devices (although may go away) OptialInterrupter - An object which services an input (although not completely implemented in this checkin) StepperDevice - An object which represents a stepper motor. It is a timed serviced object. It assumes a step pin and dir pin, as well as a step rate, and steps per rotation. Not married to the interface. StepperLinearActuator - An object which represents a collection of components which, current is implemented with optical end switches and a stepper motor. Although other types of linear actuators can be implemented as long as they adhere to the LinearActuator interface (again, not married to it). 3) This lays the groundwork for a Cartesian device, itself made of 3 linear actuators, and an extruder device - which can be implemented locally or the local object can be a conduit to an external board via a serial line. git-svn-id: https://reprap.svn.sourceforge.net/svnroot/reprap@2613 cb376a5e-1013-0410-a455-b6b1f9ac8223
Diffstat (limited to 'trunk/users/lamadio')
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/Collections.cpp176
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/EventLoop.cpp40
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.cpp201
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.h62
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Device.cpp24
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Device.h18
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.cpp209
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.h88
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.cpp73
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.h27
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.cpp111
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.h52
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.cpp28
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.h21
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.cpp90
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.h32
-rw-r--r--trunk/users/lamadio/FirmwareRefactorPrep/main/main.pde70
17 files changed, 1239 insertions, 83 deletions
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/Collections.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/Collections.cpp
index 22a83a36..06583ea3 100644
--- a/trunk/users/lamadio/FirmwareRefactorPrep/Collections.cpp
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/Collections.cpp
@@ -5,29 +5,26 @@
* Copyright 2008 OoeyGUI. All rights reserved.
*
*/
-#include <stdlib.h>
-#include <strings.h>
+#include <WProgram.h>
#include "Collections.h"
-#define ARRAY_GROWTH_COUNT 3
-
DArray::DArray()
: _array(NULL)
, _count(0)
-, _allocated(0)
{
}
DArray::~DArray()
{
- free(_array);
+ if (_array)
+ free(_array);
}
-void* DArray::item(int i)
+void* DArray::item(size_t i)
{
- if (i >= 0 && i < _count)
+ if (i < _count)
{
return _array[i];
}
@@ -65,42 +62,31 @@ void* DArray::pop()
return item;
}
-void DArray::set(int i, void* item)
+void DArray::set(size_t i, void* item)
{
- if (i < 0)
- i = 0;
if (i < _count)
{
_array[i] = item;
}
}
-bool DArray::insert(int i, void* item)
+bool DArray::insert(size_t i, void* item)
{
- if (i < 0)
- i = 0;
- int needed = max(i, _count + 1);
- if (needed > _allocated)
+ size_t needed = max(i, _count + 1);
+
+ if (_array)
{
- _allocated += ARRAY_GROWTH_COUNT;
-
- void** newArray = (void**)malloc(_allocated * sizeof(void*));
- if (newArray)
- {
- memmove(newArray, _array, _count * sizeof(void*));
- free(_array);
- _array = newArray;
- }
- else
- return false;
- /*
-
- void** newArray = (void**)realloc(_array, _allocated * sizeof(void*));
+ void** newArray = (void**)realloc(_array, needed * sizeof(void*));
if (newArray)
_array = newArray;
else
return false;
- */
+ }
+ else
+ {
+ _array = (void**)malloc(needed * sizeof(void*));
+ if (!_array)
+ return false;
}
@@ -116,35 +102,28 @@ bool DArray::insert(int i, void* item)
return true;
}
-void DArray::remove(int i)
+void DArray::remove(size_t i)
{
- if (i < 0)
- return;
-
- if (i < _count - 1)
+ if (i < _count)
{
- memmove(&_array[i], &_array[i + 1], (_count - i - 1) * sizeof(void*));
+ memmove(&_array[i], &_array[i + 1], (_count - i) * sizeof(void*));
+
+ // We don't need to reallocate this, because realloc will handle this correctly.
+ _count--;
}
-
- _count--;
-
- if (_count == 0)
- {
- _allocated = 0;
- free(_array);
- _array = NULL;
- }
}
-bool DArray::find(void* item, size_t* at)
+bool DArray::find(void* itemToFind, size_t* at)
{
for (size_t index = 0; index < count(); index++)
{
void* i = this->item(index);
- if (i == item)
+ if (i == itemToFind)
{
if (at)
+ {
*at = index;
+ }
return true;
}
}
@@ -152,7 +131,6 @@ bool DArray::find(void* item, size_t* at)
return false;
}
-
void DArray::foreach(DArrayForEach cb, void* context)
{
for (size_t index = 0; index < count(); index++)
@@ -161,8 +139,6 @@ void DArray::foreach(DArrayForEach cb, void* context)
}
}
-
-
void DArray::sort(DArraySortCallback cb)
{
qsort(_array, _count, sizeof(void*), cb);
@@ -185,34 +161,82 @@ DArray* DArray::shallowClone()
}
bool testCollections()
-{
- int i = 0x12121212;
- DArray a;
- a.pushValue(i++);
- a.pushValue(i++);
- a.pushValue(i++);
- a.pushValue(i++);
- a.pushValue(i++);
-
- while (a.count())
- {
- if (a.popValue() != --i)
- return false;
- }
+{
+// {
+ int i = 0;
+ DArray a;
+ a.pushValue(i++);
+ a.pushValue(i++);
+ a.pushValue(i++);
+ a.pushValue(i++);
+ a.pushValue(i++);
+
+ Serial.print("DArray: Count:");
+ Serial.println(a.count());
+
+ Serial.println("DArray: poping values");
+ while (a.count())
+ {
+ if (a.popValue() != --i)
+ {
+ Serial.println("DArray: poping not in order");
+ return false;
+ }
+ }
+
+ a.insertValue(0, 3);
+ a.insertValue(0, 3);
+ a.insertValue(0, 1);
+ a.insertValue(0, 1);
+ a.insertValue(0, 4);
+ a.insertValue(0, 4);
+
+ Serial.print("Inserted 6 items, got Count:");
+ Serial.println(a.count());
+ int tests[] = { 4, 4, 1, 1, 3, 3};
+ for (int index = 0; index < a.count(); index++)
+ {
+ if (tests[index] != a.value(index))
+ {
+ Serial.println("DArray: inserted values not in order");
+ for (index = 0; index < a.count(); index++)
+ {
+ Serial.print((long)a[index]);
+ Serial.print(", ");
+ }
+
+ return false;
+ }
+ }
- a.insertValue(0, 0xaaaaaab0);
- a.insertValue(0, 0xaaaaaab1);
- a.insertValue(0, 0xaaaaaab2);
- a.insertValue(0, 0xaaaaaab3);
- a.insertValue(0, 0xaaaaaab4);
- a.insertValue(0, 0xaaaaaab5);
+ DArray b;
+ b.pushValue(0);
+ b.pushValue(1);
+ b.pushValue(2);
+ b.pushValue(3);
+ b.pushValue(4);
- int tests[] = { 0xaaaaaab5, 0xaaaaaab4, 0xaaaaaab3, 0xaaaaaab2, 0xaaaaaab1, 0xaaaaaab0};
- for (int index = 0; index < a.count(); index++)
- {
- if (tests[index] != a.value(index))
+ Serial.print("pushed 5 values got Count:");
+ Serial.println(a.count());
+ size_t index;
+
+ Serial.println("Finding value 1");
+ bool found = b.findValue(1, &index);
+ if (found)
+ {
+ Serial.println("Found value 1");
+ }
+ else
+ {
+ Serial.println("Did not find value 1");
+ }
+ if (!found || index != 1)
+ {
+ Serial.println("DArray: values not found correctly");
return false;
- }
+ }
+// }
+ Serial.println("DArray: test succeeded");
return true;
}
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/EventLoop.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/EventLoop.cpp
index 0019d1c9..22de585c 100644
--- a/trunk/users/lamadio/FirmwareRefactorPrep/EventLoop.cpp
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/EventLoop.cpp
@@ -179,6 +179,8 @@ DArray* EventLoop::findFiringTimers()
EventLoop* EventLoop::current()
{
+ if (!g_eventLoop)
+ g_eventLoop = new EventLoop();
return g_eventLoop;
}
@@ -197,7 +199,6 @@ public:
{
printf("Serviced\n");
EventLoop::current()->removePeriodicCallback(this);
-
delete this;
}
}
@@ -212,6 +213,8 @@ public:
}
void fire()
{
+ Serial.println("Timer Fired");
+
milliclock_t delta = 0;
if (lastTimeout() > millis())
{
@@ -224,7 +227,8 @@ public:
}
if (delta != period())
{
- printf("Epic Failure");
+ Serial.println("Frak - Timer period calculation failed");
+ s_success = false;
}
printf("Timer %u - Delta %u\n", millis(), delta);
@@ -235,12 +239,34 @@ public:
bool eventLoopTest()
{
EventLoop loop;
-// loop.addPeriodicCallback(new EventCallbackTest(5000));
-// loop.addPeriodicCallback(new EventCallbackTest(2000));
-// loop.addPeriodicCallback(new EventCallbackTest(4000));
-// loop.addPeriodicCallback(new EventCallbackTest(8000));
- loop.addTimer(new EventTimerTest(3));
+ Serial.println("Event Loop - adding a periodic timer to be called 5000 times");
+ loop.addPeriodicCallback(new EventCallbackTest(5000));
+ Serial.println("Event Loop - adding a timer to be called 5000 times");
+ loop.addTimer(new EventTimerTest(300));
loop.run();
return true;
}
+
+
+
+void* operator new(size_t size)
+{
+ return malloc(size);
+}
+
+void operator delete(void* p)
+{
+ free(p);
+}
+
+extern "C" void __cxa_pure_virtual()
+{
+ Serial.println("Pure virtual function called.");
+ while (1)
+ {
+ // Hard lock?
+ }
+}
+=======
+>>>>>>> .r2612
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.cpp
new file mode 100644
index 00000000..5ceaa7fb
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.cpp
@@ -0,0 +1,201 @@
+/*
+ * Collections.cpp
+ *
+ * Created by Lou Amadio on 9/17/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+#include <stdlib.h>
+#include <string.h>
+#include "WProgram.h"
+#include "Collections.h"
+
+#define ARRAY_GROWTH_COUNT 3
+
+
+DArray::DArray()
+: _array(NULL)
+, _count(0)
+, _allocated(0)
+{
+
+}
+
+DArray::~DArray()
+{
+ free(_array);
+}
+
+void* DArray::item(int i)
+{
+ if (i >= 0 && i < _count)
+ {
+ return _array[i];
+ }
+
+ return NULL;
+}
+
+void DArray::push(void* item)
+{
+ insert(_count, item);
+}
+
+void* DArray::dequeue()
+{
+ void* item = NULL;
+ if (_count)
+ {
+ item = _array[0];
+ }
+
+ remove(0);
+
+ return item;
+}
+
+void* DArray::pop()
+{
+ void* item = NULL;
+ if (_count)
+ {
+ item = _array[_count - 1];
+ remove(_count - 1);
+ }
+
+ return item;
+}
+
+void DArray::set(int i, void* item)
+{
+ if (i < 0)
+ i = 0;
+ if (i < _count)
+ {
+ _array[i] = item;
+ }
+}
+
+bool DArray::insert(int i, void* item)
+{
+ if (i < 0)
+ i = 0;
+ int needed = max(i, _count + 1);
+ if (needed > _allocated)
+ {
+ _allocated += ARRAY_GROWTH_COUNT;
+
+ /*
+ NOTE: Ideally this codepath would use realloc in order to expand an
+ existing array, however, the current libc implementation of realloc
+ has a subtle bug which causes freelist corruption.
+ Editorial of this bug is:
+ http://www.ooeygui.com/?p=216
+ With annotated fix here:
+ http://www.ooeygui.com/?p=221
+
+ The patch will be submitted to the AVR working group, however,
+ the workaround posted will function, albeit more slowly as it requires
+ a memmove on each allocation. This codepath attempts to workaround it
+ with by keeping track of a separate count and allocated.
+ void** newArray = (void**)realloc(_array, _allocated * sizeof(void*));
+ if (newArray)
+ _array = newArray;
+ else
+ return false;
+ */
+ void** newArray = (void**)malloc(_allocated * sizeof(void*));
+ if (newArray)
+ {
+ if (_array)
+ {
+ memmove(newArray, _array, _count * sizeof(void*));
+ free(_array);
+ }
+
+ _array = newArray;
+ }
+ else
+ return false;
+ }
+
+
+ if (i < _count)
+ {
+ memmove(&_array[i + 1], &_array[i], (_count - i) * sizeof(void*));
+ }
+
+ _array[i] = item;
+
+ _count = needed;
+
+ return true;
+}
+
+void DArray::remove(int i)
+{
+ if (i < 0)
+ return;
+
+ if (i < _count - 1)
+ {
+ memmove(&_array[i], &_array[i + 1], (_count - i - 1) * sizeof(void*));
+ }
+
+ _count--;
+
+ if (_count == 0)
+ {
+ _allocated = 0;
+ free(_array);
+ _array = NULL;
+ }
+}
+
+bool DArray::find(void* item, size_t* at)
+{
+ for (size_t index = 0; index < count(); index++)
+ {
+ void* i = this->item(index);
+ if (i == item)
+ {
+ if (at)
+ *at = index;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+void DArray::foreach(DArrayForEach cb, void* context)
+{
+ for (size_t index = 0; index < count(); index++)
+ {
+ cb(_array[index], context);
+ }
+}
+
+
+
+void DArray::sort(DArraySortCallback cb)
+{
+ qsort(_array, _count, sizeof(void*), cb);
+}
+
+DArray* DArray::shallowClone()
+{
+ DArray* newArray = new DArray();
+ if (newArray)
+ {
+ newArray->_count = _count;
+ newArray->_array = (void**)malloc(_count * sizeof(void**));
+ if (newArray->_array)
+ {
+ memmove(newArray->_array, _array, _count * sizeof(void*));
+ }
+ }
+
+ return newArray;
+}
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.h
new file mode 100644
index 00000000..62faf1b0
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Collections.h
@@ -0,0 +1,62 @@
+/*
+ * Collections.h
+ *
+ * Created by Lou Amadio on 9/17/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+
+#ifndef Collections_h
+#define Collections_h
+
+#ifndef max
+inline int max(int x, int y)
+{
+ return (x > y)?x:y;
+}
+#endif
+
+typedef void (*DArrayForEach)(void* item, void* context);
+typedef int (*DArraySortCallback)(const void* item1, const void* item2);
+
+
+//
+// Dynamic Array
+// Dynamic array implementation for Arduino which is memory efficient.
+// Implements several simple datastructures - Queue, Stack, and List
+//
+class DArray
+{
+ void** _array;
+ size_t _count;
+ size_t _allocated;
+public:
+ DArray();
+ ~DArray();
+
+ inline int count() { return _count; }
+ void* item(int i);
+ void push(void* item);
+ void* pop();
+ void* dequeue();
+ void set(int i, void* item);
+ bool insert(int i, void* item);
+ void remove(int i);
+ bool find(void* item, size_t* index = NULL);
+ void* operator[](size_t index) { return item(index); }
+
+ DArray* shallowClone();
+
+ void sort(DArraySortCallback cb);
+ // Do not modify the array during handling
+ void foreach(DArrayForEach cb, void* context);
+
+ int value(int i) { return (int)item(i); }
+ void pushValue(int i) { push((void*)i); }
+ int popValue() { return (int)pop(); }
+ int dequeueValue() { return (int)dequeue(); }
+ bool insertValue(int i, int value) { return insert(i, (void*)value); }
+};
+
+#endif
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.cpp
new file mode 100644
index 00000000..b657e368
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.cpp
@@ -0,0 +1,24 @@
+/*
+ * Device.cpp
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+#include "WProgram.h"
+#include "Collections.h"
+#include "Device.h"
+
+static DArray s_deviceMap;
+
+void Device::map(size_t pin, Device* toDevice)
+{
+ s_deviceMap.set(pin, toDevice);
+}
+
+Device* Device::get(size_t pin)
+{
+ return (Device*)s_deviceMap[pin];
+}
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.h
new file mode 100644
index 00000000..783207c9
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Device.h
@@ -0,0 +1,18 @@
+/*
+ * Device.h
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+
+class Device
+{
+public:
+ Device() {}
+ virtual ~Device() {}
+
+ static void map(size_t pin, Device* toDevice);
+ static Device* get(size_t pin);
+};
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.cpp
new file mode 100644
index 00000000..f00b61bd
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.cpp
@@ -0,0 +1,209 @@
+/*
+ * EventLoop.cpp
+ *
+ * Created by Lou Amadio on 9/17/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+#include "WProgram.h"
+#include "Collections.h"
+#include "EventLoop.h"
+
+const unsigned long MILLICLOCK_MAX = UINT32_MAX;
+
+PeriodicCallback::PeriodicCallback()
+{
+
+}
+
+PeriodicCallback::~PeriodicCallback()
+{
+
+}
+
+
+EventLoopTimer::EventLoopTimer(unsigned long period)
+: _lastTimeout(0)
+, _period(period)
+{
+
+}
+
+EventLoopTimer::~EventLoopTimer()
+{
+
+}
+
+milliclock_t EventLoopTimer::nextTimeout() const
+{
+ milliclock_t nextTimeout = 0;
+ if (_lastTimeout > millis())
+ {
+ nextTimeout = millis() + period() - (MILLICLOCK_MAX - _lastTimeout);
+ }
+ else
+ {
+ nextTimeout = millis() + period();
+ }
+
+ return nextTimeout;
+}
+
+
+
+static EventLoop* g_eventLoop = NULL;
+
+EventLoop::EventLoop()
+: _lastTimeout(0)
+, _running(false)
+{
+ g_eventLoop = this;
+}
+
+EventLoop::~EventLoop()
+{
+
+}
+
+void EventLoop::addPeriodicCallback(PeriodicCallback* callback)
+{
+ // No checking done for duplicates. Don't do it.
+ _periodicEvents.push(callback);
+}
+
+void EventLoop::removePeriodicCallback(PeriodicCallback* callback)
+{
+ _periodicEvents.remove(_periodicEvents.find(callback));
+}
+
+void EventLoop::addTimer(EventLoopTimer* timer)
+{
+ // No checking done for duplicates. Don't do it.
+ _timers.push(timer);
+ sortTimers();
+}
+
+void EventLoop::removeTimer(EventLoopTimer* timer)
+{
+ _timers.remove(_timers.find(timer));
+}
+
+void EventLoop::run()
+{
+ _running = true;
+ while (_running)
+ {
+ // This clone prevents changes to the event loop during a pass from interrupting the run.
+ if (_periodicEvents.count())
+ {
+ DArray* clone = _periodicEvents.shallowClone();
+ if (clone)
+ {
+ for (int i = 0; i < clone->count(); i++)
+ {
+ PeriodicCallback* cb = (PeriodicCallback*)clone->item(i);
+ cb->service();
+ }
+
+ delete clone;
+ }
+ }
+
+ if (_timers.count())
+ {
+ milliclock_t currentTimeout = millis();
+ DArray* firingTimers = findFiringTimers();
+ if (firingTimers)
+ {
+ for (int i = 0; i < firingTimers->count(); i++)
+ {
+ EventLoopTimer* cb = (EventLoopTimer*)firingTimers->item(i);
+ cb->fire();
+ cb->setLastTimeout(currentTimeout);
+ }
+
+ delete firingTimers;
+
+ sortTimers();
+ }
+
+ _lastTimeout = currentTimeout;
+ }
+ }
+}
+
+int timerSort(const void* item1, const void* item2)
+{
+ const EventLoopTimer* one = (const EventLoopTimer*)item1;
+ const EventLoopTimer* two = (const EventLoopTimer*)item2;
+ if (one->nextTimeout() == two->nextTimeout())
+ return 0;
+ else if (one->nextTimeout() < two->nextTimeout())
+ return -1;
+ else
+ return 1;
+}
+
+
+void EventLoop::sortTimers()
+{
+ _timers.sort(timerSort);
+}
+
+DArray* EventLoop::findFiringTimers()
+{
+ DArray* firingTimers = NULL;
+ for (int i = 0; i < _timers.count(); i++)
+ {
+ EventLoopTimer* cb = (EventLoopTimer*)_timers.item(i);
+ milliclock_t delta = 0;
+ if (cb->lastTimeout() > millis())
+ {
+ delta += MILLICLOCK_MAX - cb->lastTimeout();
+ delta += millis();
+ }
+ else
+ {
+ delta += millis() - cb->lastTimeout();
+ }
+
+ if (delta >= cb->period())
+ {
+ if (firingTimers == NULL)
+ firingTimers = new DArray();
+ if (firingTimers)
+ firingTimers->push(cb);
+ }
+ }
+
+ return firingTimers;
+}
+
+EventLoop* EventLoop::current()
+{
+ if (!g_eventLoop)
+ g_eventLoop = new EventLoop();
+ return g_eventLoop;
+}
+
+void* operator new(size_t size)
+{
+ return malloc(size);
+}
+
+void operator delete(void* p)
+{
+ free(p);
+}
+
+extern "C" void __cxa_pure_virtual()
+{
+ Serial.println("Pure virtual function called.");
+ while (1)
+ {
+ // Hard lock?
+ }
+}
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.h
new file mode 100644
index 00000000..9e847931
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/EventLoop.h
@@ -0,0 +1,88 @@
+/*
+ * EventLoop.h
+ *
+ * Created by Lou Amadio on 9/17/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+#ifndef EventLoop_h
+#define EventLoop_h
+
+typedef unsigned long milliclock_t;
+extern const unsigned long MILLICLOCK_MAX;
+
+//
+// Periodic Event Callback
+// Derive from this class to implement a periodic servicing
+//
+class PeriodicCallback
+{
+public:
+ // NOTE: This is a harmless warning:
+ // alignment of 'PeriodicCallback::_ZTV16PeriodicCallback' is greater than maximum object file alignment.
+ // Bug in avr-g++. See http://www.mail-archive.com/avr-chat@nongnu.org/msg00982.html
+ PeriodicCallback();
+ virtual ~PeriodicCallback();
+
+ virtual void service() = 0;
+};
+
+//
+// Timer
+// Derive from this class to implement a periodic timer.
+// This class also contains information needed for maintianing a timer, designed to be memory efficient.
+//
+class EventLoopTimer
+{
+ milliclock_t _lastTimeout;
+ milliclock_t _period;
+public:
+ EventLoopTimer(unsigned long period);
+ virtual ~EventLoopTimer();
+
+ virtual void fire() = 0;
+
+ inline milliclock_t period() const { return _period; }
+ inline milliclock_t lastTimeout() const { return _lastTimeout; }
+ milliclock_t nextTimeout() const;
+
+ inline void setLastTimeout(milliclock_t nextTimeout) { _lastTimeout = nextTimeout; }
+};
+
+//
+// Event Loop
+// This class implements the main loop.
+// It allows clients to register for periodic servicing, or timed servicing.
+//
+class EventLoop
+{
+private:
+ DArray _periodicEvents;
+ DArray _timers;
+ milliclock_t _lastTimeout;
+ bool _running;
+
+ void sortTimers();
+ DArray* findFiringTimers();
+public:
+ EventLoop();
+ ~EventLoop();
+
+ void addPeriodicCallback(PeriodicCallback* callback);
+ void removePeriodicCallback(PeriodicCallback* callback);
+
+ int periodicCallbacks() { return _periodicEvents.count(); }
+
+ void addTimer(EventLoopTimer* timer);
+ void removeTimer(EventLoopTimer* timer);
+ int timers() { return _timers.count(); }
+
+ bool running() { return _running; }
+ void exit() { _running = false; }
+
+ void run();
+
+ static EventLoop* current();
+};
+
+#endif
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.cpp
new file mode 100644
index 00000000..f8aed8b7
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.cpp
@@ -0,0 +1,73 @@
+/*
+ * LinearActuator.cpp
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+#include "WProgram.h"
+#include "Collections.h"
+#include "EventLoop.h"
+#include "Observable.h"
+#include "Device.h"
+#include "OpticalInterrupt.h"
+#include "StepperDevice.h"
+#include "LinearActuator.h"
+
+StepperLinearActuator::StepperLinearActuator(float revPerMM, StepperDevice& stepper,
+ OpticalInterrupt& far, OpticalInterrupt& near)
+: _currentPos(0.0f)
+, _revPerMM(revPerMM)
+, _stepper(stepper)
+, _nearInterrupter(near)
+, _farInterrupter(far)
+{
+}
+
+void StepperLinearActuator::moveTo(float newPosMM)
+{
+ float revs;
+ if (newPosMM == 0)
+ {
+ _stepper.goBackward();
+ _stepper.start();
+ }
+ else
+ {
+ if (newPosMM < _currentPos)
+ {
+ revs = (_currentPos - newPosMM) / _revPerMM;
+ _stepper.goBackward();
+ }
+ else
+ {
+ revs = (newPosMM - _currentPos) / _revPerMM;
+ _stepper.goForward();
+ }
+
+ _stepper.turn(revs);
+ }
+}
+
+void StepperLinearActuator::notify(uint32_t eventId, void* context)
+{
+ switch (eventId)
+ {
+ case StepperEvent_Complete:
+ notify(StepperLinearActuator_CompletedMove, this);
+ break;
+ case OpticalInterrupt_Interrupted:
+ _stepper.stop();
+ if (context == &_nearInterrupter)
+ {
+ notify(StepperLinearActuator_Homed, this);
+ }
+ else if (context == &_farInterrupter)
+ {
+ notify(StepperLinearActuator_Extent, this);
+ }
+ break;
+ }
+}
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.h
new file mode 100644
index 00000000..918ddb64
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/LinearActuator.h
@@ -0,0 +1,27 @@
+/*
+ * LinearActuator.h
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+
+const uint32_t StepperLinearActuator_CompletedMove = 'SLAC';
+const uint32_t StepperLinearActuator_Extent = 'SLAF';
+const uint32_t StepperLinearActuator_Homed = 'SLAH';
+
+class StepperLinearActuator : public Device, Observer, Observable
+{
+ float _currentPos;
+ float _revPerMM;
+ StepperDevice& _stepper;
+ OpticalInterrupt& _nearInterrupter;
+ OpticalInterrupt& _farInterrupter;
+
+public:
+ StepperLinearActuator(float _revPerMM, StepperDevice& stepper, OpticalInterrupt& far, OpticalInterrupt& near);
+
+ void moveTo(float newPosMM);
+ virtual void notify(uint32_t eventId, void* context);
+}; \ No newline at end of file
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.cpp
new file mode 100644
index 00000000..d2f79ffe
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.cpp
@@ -0,0 +1,111 @@
+/*
+ * Observable.cpp
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 10/18/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+#include "WProgram.h"
+#include "Collections.h"
+#include "Observable.h"
+
+struct forEachNotifyContext
+{
+ void* observerContext;
+ uint32_t event;
+ forEachNotifyContext(uint32_t evt, void* oc = NULL)
+ : observerContext(oc)
+ , event(evt)
+ {
+
+ }
+};
+
+void forEachFireEvent(void* item, void* context)
+{
+ forEachNotifyContext* ctx = (forEachNotifyContext*)context;
+ ((Observer*)item)->notify(ctx->event, ctx->observerContext);
+}
+
+
+Observable::Observable()
+{
+
+}
+
+
+Observable::~Observable()
+{
+ notifyObservers(ObservedEvent_Destroyed, this);
+}
+
+void Observable::notifyObservers(uint32_t eventId, void* context)
+{
+ forEachNotifyContext ctx(eventId, context);
+ _observers.foreach(forEachFireEvent, &ctx);
+}
+
+bool Observable::hasObservers()
+{
+ return _observers.count() > 0;
+
+}
+
+void Observable::addObserver(Observer* o)
+{
+ if (!_observers.find(o))
+ {
+ _observers.push(o);
+ o->notify(ObservedEvent_Attached, this);
+ }
+
+}
+
+void Observable::removeObserver(Observer* o)
+{
+ size_t index;
+ if (_observers.find(o, &index))
+ {
+ ((Observer*)_observers[index])->notify(ObservedEvent_Detached, this);
+ _observers.remove(index);
+ }
+}
+
+
+Observer::Observer()
+{
+
+}
+
+void removeObserver(void* item, void* context)
+{
+ ((Observable*)item)->removeObserver((Observer*)context);
+}
+
+Observer::~Observer()
+{
+ _observing.foreach(removeObserver, this);
+}
+
+void Observer::notify(uint32_t eventId, void* context)
+{
+ switch (eventId)
+ {
+ case ObservedEvent_Attached:
+ if (!_observing.find(context))
+ _observing.push(context);
+ break;
+
+ case ObservedEvent_Destroyed:
+ case ObservedEvent_Detached:
+ {
+ size_t index;
+ if (_observing.find(context, &index))
+ _observing.remove(index);
+ }
+ break;
+ }
+}
+
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.h
new file mode 100644
index 00000000..0b61c878
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/Observable.h
@@ -0,0 +1,52 @@
+/*
+ * Observable.h
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 10/18/08.
+ * Copyright 2008 OoeyGUI. All rights reserved.
+ *
+ */
+#ifndef Observable_h
+#define Observable_h
+
+class DArray;
+class Observer;
+
+const uint32_t ObservedEvent_None = 0;
+const uint32_t ObservedEvent_Attached = 1;
+const uint32_t ObservedEvent_Detached = 2;
+const uint32_t ObservedEvent_Destroyed = 3;
+
+const uint32_t ObservedEvent_ComponentFirst = 10;
+
+
+class Observable
+{
+ DArray _observers;
+
+public:
+ Observable();
+ virtual ~Observable();
+
+ bool hasObservers();
+ void notifyObservers(uint32_t eventId, void* context = NULL);
+
+ void addObserver(Observer* o);
+ void removeObserver(Observer* o);
+};
+
+
+class Observer
+{
+ // Used to remove this class from observables when this is destroyed
+ DArray _observing;
+public:
+ Observer();
+ virtual ~Observer();
+
+ virtual void notify(uint32_t eventId, void* context);
+};
+
+
+#endif
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.cpp
new file mode 100644
index 00000000..a6f8c390
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.cpp
@@ -0,0 +1,28 @@
+/*
+ * OpticalInterrupt.cpp
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+#include "WProgram.h"
+#include "Collections.h"
+#include "EventLoop.h"
+#include "Device.h"
+#include "Observable.h"
+#include "OpticalInterrupt.h"
+
+OpticalInterrupt::OpticalInterrupt(int pin)
+: _inputPin(pin)
+{
+ EventLoop::current()->addPeriodicCallback(this);
+}
+
+void OpticalInterrupt::service()
+{
+ if (digitalRead(_inputPin) == HIGH)
+ {
+ notifyObservers(OpticalInterrupt_Interrupted, this);
+ }
+}
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.h
new file mode 100644
index 00000000..c8d999a2
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/OpticalInterrupt.h
@@ -0,0 +1,21 @@
+/*
+ * OpticalInterrupt.h
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+
+const uint32_t OpticalInterrupt_Interrupted = 'OPTI';
+
+
+
+class OpticalInterrupt : public Device, Observable, PeriodicCallback
+{
+ int _inputPin;
+public:
+ OpticalInterrupt(int pin);
+ virtual void service();
+};
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.cpp b/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.cpp
new file mode 100644
index 00000000..efc9e3cc
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.cpp
@@ -0,0 +1,90 @@
+/*
+ * StepperDevice.cpp
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+#include "WProgram.h"
+#include "Collections.h"
+#include "Device.h"
+#include "Observable.h"
+#include "EventLoop.h"
+#include "StepperDevice.h"
+
+#define FORWARD HIGH
+#define BACKWARD LOW
+
+StepperDevice::StepperDevice(int8_t stepPin, int8_t dirPin, int ticksPerRev, milliclock_t rate)
+: EventLoopTimer(rate)
+, _stepPin(stepPin)
+, _dirPin(dirPin)
+, _ticksPerRev(ticksPerRev)
+, _currentTick(0)
+, _targetTick(0)
+{
+ pinMode(stepPin, OUTPUT);
+ pinMode(dirPin, OUTPUT);
+
+}
+
+void StepperDevice::start()
+{
+ if (_currentTick)
+ {
+ _currentTick = _targetTick = 0;
+ notifyObservers(StepperEvent_Start, this);
+ EventLoop::current()->addTimer(this);
+ }
+}
+
+void StepperDevice::stop()
+{
+ if (_currentTick)
+ {
+ _currentTick = 0;
+ notifyObservers(StepperEvent_Stop, this);
+ EventLoop::current()->removeTimer(this);
+ }
+}
+
+void StepperDevice::goForward()
+{
+ stop();
+ digitalWrite(_dirPin, FORWARD);
+}
+
+void StepperDevice::goBackward()
+{
+ stop();
+ digitalWrite(_dirPin, BACKWARD);
+}
+
+void StepperDevice::turn(float numberOfRevolutions)
+{
+ if (_currentTick)
+ {
+ stop();
+ }
+
+ _targetTick = (int)(numberOfRevolutions / _ticksPerRev);
+
+ notifyObservers(StepperEvent_Start, this);
+ EventLoop::current()->addTimer(this);
+}
+
+void StepperDevice::fire()
+{
+ digitalWrite(_stepPin, HIGH);
+ delay(1);
+ digitalWrite(_stepPin, LOW);
+ ++_currentTick;
+
+ if (_targetTick && (_currentTick == _targetTick))
+ {
+ notifyObservers(StepperEvent_Complete, this);
+ stop();
+ }
+}
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.h b/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.h
new file mode 100644
index 00000000..185669e7
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/StepperDevice.h
@@ -0,0 +1,32 @@
+/*
+ * StepperDevice.h
+ * FirmwareRefactorPrep
+ *
+ * Created by Lou Amadio on 2/24/09.
+ * Copyright 2009 OoeyGUI. All rights reserved.
+ *
+ */
+
+const uint32_t StepperEvent_Start = 'STPS';
+const uint32_t StepperEvent_Stop = 'STPE';
+const uint32_t StepperEvent_Complete = 'STPC';
+
+class StepperDevice : public EventLoopTimer, Device, Observable
+{
+ int8_t _stepPin;
+ int8_t _dirPin;
+ bool _forward;
+ int _currentTick;
+ int _targetTick;
+ int _ticksPerRev;
+public:
+ StepperDevice(int8_t stepPin, int8_t dirPin, int ticksPerRev, milliclock_t rate);
+
+ void goForward();
+ void goBackward();
+ void turn(float numberOfRevolutions = 0.0f);
+ void start();
+ void stop();
+ virtual void fire();
+};
+
diff --git a/trunk/users/lamadio/FirmwareRefactorPrep/main/main.pde b/trunk/users/lamadio/FirmwareRefactorPrep/main/main.pde
new file mode 100644
index 00000000..edf75290
--- /dev/null
+++ b/trunk/users/lamadio/FirmwareRefactorPrep/main/main.pde
@@ -0,0 +1,70 @@
+#include "WProgram.h"
+#include "Collections.h"
+#include "EventLoop.h"
+#include "EventLoop.h"
+#include "Collections.h"
+#include "Observable.h"
+#include "Device.h"
+#include "OpticalInterrupt.h"
+#include "StepperDevice.h"
+#include "LinearActuator.h"
+
+extern char* __data_start;
+extern char* __data_end;
+extern char* __bss_end;
+
+void setup()
+{
+ Serial.begin(115200);
+ /*
+ Interesting heap data when working with dynamic memory
+ Serial.print("Heap Start:");
+ Serial.println((long)__malloc_heap_start);
+ Serial.print("Heap End:");
+ Serial.println((long)__malloc_heap_end);
+ Serial.print("data start:");
+ Serial.println((long)__data_start);
+ Serial.print("data end:");
+ Serial.println((long)__data_end);
+ Serial.print("bss end:");
+ Serial.println((long)__bss_end);
+ Serial.print("Size of size_t:");
+ Serial.println((long)sizeof(size_t));
+ Serial.print("Size of void*:");
+ Serial.println((long)sizeof(void*));
+ */
+}
+
+class HeartbeatTimer : public EventLoopTimer
+{
+public:
+ HeartbeatTimer(unsigned long period) : EventLoopTimer(period)
+ {
+ Serial.println("Created heartbeat");
+ }
+
+ virtual void fire()
+ {
+ Serial.println("*");
+ Serial.flush();
+
+ }
+};
+
+
+void loop()
+{
+ Serial.println("Starting");
+ HeartbeatTimer heartbeat(1000);
+ StepperDevice xAxisStepper(2, 3, 300, 1000);
+// OpticalInterrupt xAxisFar(10);
+// OpticalInterrupt xAxisNear(11);
+// StepperLinearActuator linearActuator(4.5f, xAxisStepper, xAxisFar, xAxisNear);
+
+ xAxisStepper.goForward();
+ xAxisStepper.turn();
+ EventLoop::current()->addTimer(&heartbeat);
+ EventLoop::current()->run();
+}
+
+