I am no longer actively working on the ppCANOpen library, however, I want to publish this project so that anyone who wants to pick up any of the pieces can have a good example. This is a a project I was working on using the ppCANOpen library. It has a pretty in deep use of the object dictionary structure. And a number of functions to control high voltage pinball drivers, if you're into that sort of thing.

Dependencies:   CANnucleo mbed ppCANOpen

Revision:
10:ec59d628ebdc
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Application/source/Node_pin0808.cpp	Sat Mar 19 01:44:35 2016 +0000
@@ -0,0 +1,700 @@
+/**
+ ******************************************************************************
+ * @file
+ * @author  Paul Paterson
+ * @version
+ * @date    2015-12-14
+ * @brief   CANOpen implementation library
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>&copy; COPYRIGHT(c) 2015 Paul Paterson
+ *
+ * All rights reserved.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Node_pin0808.h"
+#include "ServiceProvider.h"
+
+#include "stdio.h"
+#include "mbed.h"
+
+PortIn mbedInputs(PortB, 0x00FF);
+PortOut mbedOutputs(PortB, 0xFF00);
+
+namespace ppCANOpen
+{
+
+/******************************************************************************
+ * Constructor/Destructor
+ ******************************************************************************
+ */
+
+Node_pin0808::Node_pin0808 (int id, ServiceProvider * provider, int bLoop)
+    : Node(id, provider, bLoop)
+{
+    dictionary = new ObjectData[22];
+
+
+    /* Init values ***********************************************************/
+    memset(prevInputBuffers, 0, sizeof(prevInputBuffers));
+    memset(inputDebounce,    0, sizeof(inputDebounce));
+    
+    memset(prevOutputBuffers,0, sizeof(prevOutputBuffers));
+
+    /* Init Object Dictionary ************************************************/
+
+    /* Communication Objects ================================================*/
+    
+    /* SDO ------------------------------------------------------------------*/
+    /* index 0x1200  */
+    Obj1200_highestSubIndex = 2;
+    Obj1200_ReceiveCobId    = 0x600 + nodeId;
+    Obj1200_TransmitCobId   = 0x580 + nodeId;
+    Obj1200_entries[0] = EntryData((void*)&Obj1200_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1200_entries[1] = EntryData((void*)&Obj1200_ReceiveCobId,    sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1200_entries[2] = EntryData((void*)&Obj1200_TransmitCobId,   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1200 = ObjectData(Obj1200_entries, 0x1200, sizeof(Obj1200_entries) / sizeof(Obj1200_entries[0]));
+    
+    /* RPDO -----------------------------------------------------------------*/
+    /* index 0x1400  */
+    Obj1400_highestSubIndex     = 5;
+    Obj1400_CobId               = 0x200 + nodeId;
+    Obj1400_TransmissionType    = 1;
+    Obj1400_InhibitTime         = 0;
+    Obj1400_CompatibilityEntry  = 0;
+    Obj1400_EventTimer          = 0;
+    Obj1400_entries[0] = EntryData((void*)&Obj1400_highestSubIndex,    sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1400_entries[1] = EntryData((void*)&Obj1400_CobId,              sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1400_entries[2] = EntryData((void*)&Obj1400_TransmissionType,   sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1400_entries[3] = EntryData((void*)&Obj1400_InhibitTime,        sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1400_entries[4] = EntryData((void*)&Obj1400_CompatibilityEntry, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1400_entries[5] = EntryData((void*)&Obj1400_EventTimer,         sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1400 = ObjectData(Obj1400_entries, 0x1400, sizeof(Obj1400_entries) / sizeof(Obj1400_entries[0]));
+
+    /* index 0x1401  */
+    Obj1401_highestSubIndex     = 5;
+    Obj1401_CobId               = 0x300 + nodeId;
+    Obj1401_TransmissionType    = 1;
+    Obj1401_InhibitTime         = 0;
+    Obj1401_CompatibilityEntry  = 0;
+    Obj1401_EventTimer          = 0;
+    Obj1401_entries[0] = EntryData((void*)&Obj1401_highestSubIndex,    sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1401_entries[1] = EntryData((void*)&Obj1401_CobId,              sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1401_entries[2] = EntryData((void*)&Obj1401_TransmissionType,   sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1401_entries[3] = EntryData((void*)&Obj1401_InhibitTime,        sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1401_entries[4] = EntryData((void*)&Obj1401_CompatibilityEntry, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1401_entries[5] = EntryData((void*)&Obj1401_EventTimer,         sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1401 = ObjectData(Obj1401_entries, 0x1401, sizeof(Obj1401_entries) / sizeof(Obj1401_entries[0]));
+
+    /* index 0x1402  */
+    Obj1402_highestSubIndex     = 5;
+    Obj1402_CobId               = 0x400 + nodeId;
+    Obj1402_TransmissionType    = 1;
+    Obj1402_InhibitTime         = 0;
+    Obj1402_CompatibilityEntry  = 0;
+    Obj1402_EventTimer          = 0;
+    Obj1402_entries[0] = EntryData((void*)&Obj1402_highestSubIndex,    sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1402_entries[1] = EntryData((void*)&Obj1402_CobId,              sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1402_entries[2] = EntryData((void*)&Obj1402_TransmissionType,   sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1402_entries[3] = EntryData((void*)&Obj1402_InhibitTime,        sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1402_entries[4] = EntryData((void*)&Obj1402_CompatibilityEntry, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1402_entries[5] = EntryData((void*)&Obj1402_EventTimer,         sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1402 = ObjectData(Obj1402_entries, 0x1402, sizeof(Obj1402_entries) / sizeof(Obj1402_entries[0]));
+
+    /* index 0x1403  */
+    Obj1403_highestSubIndex     = 5;
+    Obj1403_CobId               = 0x181;
+    Obj1403_TransmissionType    = 1;
+    Obj1403_InhibitTime         = 0;
+    Obj1403_CompatibilityEntry  = 0;
+    Obj1403_EventTimer          = 0;
+    Obj1403_entries[0] = EntryData((void*)&Obj1403_highestSubIndex,    sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1403_entries[1] = EntryData((void*)&Obj1403_CobId,              sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1403_entries[2] = EntryData((void*)&Obj1403_TransmissionType,   sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1403_entries[3] = EntryData((void*)&Obj1403_InhibitTime,        sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1403_entries[4] = EntryData((void*)&Obj1403_CompatibilityEntry, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1403_entries[5] = EntryData((void*)&Obj1403_EventTimer,         sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1403 = ObjectData(Obj1403_entries, 0x1403, sizeof(Obj1403_entries) / sizeof(Obj1403_entries[0]));
+
+    /* index 0x1600  */
+    Obj1600_highestSubIndex = 1;
+    Obj1600_Map             = 0x62000108;
+    Obj1600_entries[0] = EntryData((void*)&Obj1600_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1600_entries[1] = EntryData((void*)&Obj1600_Map,             sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1600 = ObjectData(Obj1600_entries, 0x1600, sizeof(Obj1600_entries) / sizeof(Obj1600_entries[0]));
+    
+    /* index 0x1601  */
+    Obj1601_highestSubIndex = 1;
+    Obj1601_Map             = 0x20010140;
+    Obj1601_entries[0] = EntryData((void*)&Obj1601_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1601_entries[1] = EntryData((void*)&Obj1601_Map,             sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1601 = ObjectData(Obj1601_entries, 0x1601, sizeof(Obj1601_entries) / sizeof(Obj1601_entries[0]));
+
+    /* index 0x1602  */
+    Obj1602_highestSubIndex = 1;
+    Obj1602_Map             = 0x22000140;
+    Obj1602_entries[0] = EntryData((void*)&Obj1602_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1602_entries[1] = EntryData((void*)&Obj1602_Map,             sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1602 = ObjectData(Obj1602_entries, 0x1602, sizeof(Obj1602_entries) / sizeof(Obj1602_entries[0]));
+
+    /* index 0x1603  */
+    Obj1603_highestSubIndex = 1;
+    Obj1603_Map             = 0x22000238;
+    Obj1603_entries[0] = EntryData((void*)&Obj1603_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1603_entries[1] = EntryData((void*)&Obj1603_Map,             sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1603 = ObjectData(Obj1603_entries, 0x1603, sizeof(Obj1603_entries) / sizeof(Obj1603_entries[0]));
+
+    /* TPDO -----------------------------------------------------------------*/
+    /* index 0x1800  */
+    Obj1800_highestSubIndex     = 5;
+    Obj1800_CobId               = 0x181;
+    Obj1800_TransmissionType    = 0xFE;  /* event driven Manuf specific */
+    Obj1800_InhibitTime         = 0;     // TODO review if this is needed
+    Obj1800_CompatibilityEntry  = 0;
+    Obj1800_EventTimer          = 0;
+    Obj1800_entries[0] = EntryData((void*)&Obj1800_highestSubIndex,    sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1800_entries[1] = EntryData((void*)&Obj1800_CobId,              sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1800_entries[2] = EntryData((void*)&Obj1800_TransmissionType,   sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1800_entries[3] = EntryData((void*)&Obj1800_InhibitTime,        sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1800_entries[4] = EntryData((void*)&Obj1800_CompatibilityEntry, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1800_entries[5] = EntryData((void*)&Obj1800_EventTimer,         sizeof(uint16_t), EntryData::TYPE_UINT16, EntryData::PROPERTY_READABLE);
+    Obj1800 = ObjectData(Obj1800_entries, 0x1800, sizeof(Obj1800_entries) / sizeof(Obj1800_entries[0]));
+
+    /* index 0x1A00  */
+    Obj1A00_highestSubIndex = 5;
+    Obj1A00_MapInput        = 0x60000108;
+    Obj1A00_MapVoid16       = 0x00000010;
+    Obj1A00_MapChange       = 0x21000108;
+    Obj1A00_MapSourceId     = 0x21000208;
+    Obj1A00_entries[0] = EntryData((void*)&Obj1A00_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj1A00_entries[1] = EntryData((void*)&Obj1A00_MapInput,        sizeof(uint8_t),  EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1A00_entries[2] = EntryData((void*)&Obj1A00_MapVoid16,       sizeof(uint16_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1A00_entries[3] = EntryData((void*)&Obj1A00_MapChange,       sizeof(uint8_t),  EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1A00_entries[4] = EntryData((void*)&Obj1A00_MapVoid16,       sizeof(uint16_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1A00_entries[5] = EntryData((void*)&Obj1A00_MapSourceId,     sizeof(uint8_t),  EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj1A00 = ObjectData(Obj1A00_entries, 0x1A00, sizeof(Obj1A00_entries) / sizeof(Obj1A00_entries[0]));
+
+
+    /* Manufacturer Specific Objects ========================================*/
+
+    /* index 0x2001 : Pin Output Configurations */
+    Obj2001_highestSubIndex = 8;
+    memset(&writeOutputConfig, 0, sizeof(writeOutputConfig));
+    memset(outputConfigs, 0, sizeof(outputConfigs));
+    outputConfigs[0].type       = 0x08;
+    memset(outputTimers, 0, sizeof(outputTimers));
+    Obj2001_entries[0] = EntryData((void*)&Obj2001_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj2001_entries[1] = EntryData((void*)&writeOutputConfig, sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[2] = EntryData((void*)&outputConfigs[0],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[3] = EntryData((void*)&outputConfigs[1],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[4] = EntryData((void*)&outputConfigs[2],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[5] = EntryData((void*)&outputConfigs[3],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[6] = EntryData((void*)&outputConfigs[4],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[7] = EntryData((void*)&outputConfigs[5],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[8] = EntryData((void*)&outputConfigs[6],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001_entries[9] = EntryData((void*)&outputConfigs[7],  sizeof(OutputConfiguration), EntryData::TYPE_UINT64, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2001 = ObjectData(Obj2001_entries, 0x2001, sizeof(Obj2001_entries) / sizeof(Obj2001_entries[0]));
+
+    /* index 0x2002 : Output Schedule Configuration */
+    Obj2002_highestSubIndex = 1;
+    scheduleConfig  = 0x01;
+    schedules[0] = 0xFF00F0F0;
+    Obj2002_entries[0] = EntryData((void*)&Obj2002_highestSubIndex, sizeof(uint8_t),  EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj2002_entries[1] = EntryData((void*)&scheduleConfig, sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[2] = EntryData((void*)&schedules[0],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[3] = EntryData((void*)&schedules[1],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[4] = EntryData((void*)&schedules[2],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[5] = EntryData((void*)&schedules[3],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[6] = EntryData((void*)&schedules[4],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[7] = EntryData((void*)&schedules[5],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[8] = EntryData((void*)&schedules[6],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002_entries[9] = EntryData((void*)&schedules[7],   sizeof(uint32_t), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2002 = ObjectData(Obj2002_entries, 0x2002, sizeof(Obj2002_entries) / sizeof(Obj2002_entries[0]));
+
+    /* Index 2100 */
+    Obj2100_highestSubIndex = 2;
+    inputChangeMask[0] = 0;
+    /* nodeId; */
+    Obj2100_entries[0] = EntryData((void*)&Obj2100_highestSubIndex, sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj2100_entries[1] = EntryData((void*)&inputChangeMask[0],      sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj2100_entries[2] = EntryData((void*)&nodeId,                  sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj2100 = ObjectData(Obj2100_entries, 0x2100, sizeof(Obj2100_entries) / sizeof(Obj2100_entries[0]));
+    
+    /* Index 2200 */
+    Obj2200_highestSubIndex = 2;
+    memset(&writeRule,          0, sizeof(AutotriggerRule));
+    memset(&autotriggerMessage, 0, sizeof(AutotriggerMessage));
+    memset(rules, 0, sizeof(rules));
+    Obj2200_entries[0]  = EntryData((void*)&Obj2200_highestSubIndex, sizeof(uint8_t),            EntryData::TYPE_UINT8,  EntryData::PROPERTY_READABLE);
+    Obj2200_entries[1]  = EntryData((void*)&writeRule,               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2200_entries[2]  = EntryData((void*)&autotriggerMessage,      sizeof(AutotriggerMessage), EntryData::TYPE_UINT32, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj2200_entries[3]  = EntryData((void*)&rules[0],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[4]  = EntryData((void*)&rules[1],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[5]  = EntryData((void*)&rules[2],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[6]  = EntryData((void*)&rules[3],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[7]  = EntryData((void*)&rules[4],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[8]  = EntryData((void*)&rules[5],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[9]  = EntryData((void*)&rules[6],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[10] = EntryData((void*)&rules[7],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[11] = EntryData((void*)&rules[8],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[12] = EntryData((void*)&rules[9],                sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[13] = EntryData((void*)&rules[10],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[14] = EntryData((void*)&rules[11],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[15] = EntryData((void*)&rules[12],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[16] = EntryData((void*)&rules[13],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[17] = EntryData((void*)&rules[14],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[18] = EntryData((void*)&rules[15],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[19] = EntryData((void*)&rules[16],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[20] = EntryData((void*)&rules[17],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[21] = EntryData((void*)&rules[18],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[22] = EntryData((void*)&rules[19],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[23] = EntryData((void*)&rules[20],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[24] = EntryData((void*)&rules[21],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[25] = EntryData((void*)&rules[22],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200_entries[26] = EntryData((void*)&rules[23],               sizeof(AutotriggerRule),    EntryData::TYPE_UINT32, EntryData::PROPERTY_READABLE);
+    Obj2200 = ObjectData(Obj2200_entries, 0x2200, sizeof(Obj2200_entries) / sizeof(Obj2200_entries[0]));
+
+    /* Device Profile Specific Objects ======================================*/
+
+    /* Index 6000 */
+    Obj6000_highestSubIndex = 1;
+    readInputBuffers[0]  = 0;
+    Obj6000_entries[0] = EntryData((void*)&Obj6000_highestSubIndex, sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj6000_entries[1] = EntryData((void*)&readInputBuffers,        sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj6000 = ObjectData(Obj6000_entries, 0x6000, sizeof(Obj6000_entries) / sizeof(Obj6000_entries[0]));
+    
+    /* Index 6005 */
+    Obj6005_highestSubIndex = 1;
+    bInputInterruptEnable   = 0x01;
+    Obj6005_entries[0] = EntryData((void*)&Obj6005_highestSubIndex, sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj6005_entries[1] = EntryData((void*)&bInputInterruptEnable,   sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj6005 = ObjectData(Obj6005_entries, 0x6005, sizeof(Obj6005_entries) / sizeof(Obj6005_entries[0]));
+    
+    /* Index 6006 */
+    Obj6006_highestSubIndex = 1;
+    inputInterruptMask[0]      = 0xFF;
+    Obj6006_entries[0] = EntryData((void*)&Obj6006_highestSubIndex, sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj6006_entries[1] = EntryData((void*)&inputInterruptMask,      sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj6006 = ObjectData(Obj6006_entries, 0x6006, sizeof(Obj6006_entries) / sizeof(Obj6006_entries[0]));
+
+    /* Index 6200 */
+    Obj6200_highestSubIndex = 1;
+    writeOutputBuffers[0] = 0;
+    Obj6200_entries[0] = EntryData((void*)&Obj6200_highestSubIndex, sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READABLE);
+    Obj6200_entries[1] = EntryData((void*)&writeOutputBuffers,      sizeof(uint8_t), EntryData::TYPE_UINT8, EntryData::PROPERTY_READ_WRITEABLE);
+    Obj6200 = ObjectData(Obj6200_entries, 0x6200, sizeof(Obj6200_entries) / sizeof(Obj6200_entries[0]));
+
+    /* Set up the whole dictionary */
+    dictionary[0]  = Obj1200;
+    dictionary[1]  = Obj1400;
+    dictionary[2]  = Obj1401;
+    dictionary[3]  = Obj1402;
+    dictionary[4]  = Obj1403;
+    dictionary[5]  = Obj1600;
+    dictionary[6]  = Obj1601;
+    dictionary[7]  = Obj1602;
+    dictionary[8]  = Obj1603;
+    dictionary[10] = Obj1800;
+    dictionary[11] = Obj1A00;
+    dictionary[12] = Obj2001;
+    dictionary[13] = Obj2002;
+    dictionary[14] = Obj2100;
+    dictionary[15] = Obj2200;
+    dictionary[16] = Obj6000;
+    dictionary[17] = Obj6005;
+    dictionary[18] = Obj6006;
+    dictionary[19] = Obj6200;
+
+}
+
+Node_pin0808::~Node_pin0808(void)
+{
+    delete dictionary;
+}
+
+/******************************************************************************
+ * Application Run Implementation
+ ******************************************************************************
+ */
+
+void Node_pin0808::OnFixedUpdate (void)
+{
+    /**************************************************************************
+     * INPUTS
+     **************************************************************************
+     */
+
+    uint8_t inputSample = ~(uint8_t)(mbedInputs.read());
+    
+    uint8_t inputChange = readInputBuffers[0] ^ inputSample; 
+    
+    /* Loop through all of the inputs */
+    for (int in = 0; in < 8; in++) {
+        if (inputChange & (1 << in)) {
+            
+            inputDebounce[in] += (uint8_t)(timeSinceLastTick);
+            if (inputDebounce[in] > DEBOUNCE_TIME) {
+                readInputBuffers[0] &= ~(1 << in);
+                readInputBuffers[0] |=  (inputSample & (1 << in));
+                
+                inputDebounce[in] = 0; 
+            }
+            
+        } else {
+            inputDebounce[in] = 0;   
+        }
+    }
+    
+
+    /**************************************************************************
+     * OUTPUTS
+     **************************************************************************
+     */
+
+    /* create a copy of the current outputs and edit as we go */
+    uint8_t newOutput = (uint8_t)(mbedOutputs >> 8);
+
+    /* big operation, so let's only do it once! */
+    int scheduleIndexer = 1 << ((timeCurrentTick * 100) / 3125) % 32;    
+
+    /* Loop through all of the outputs */
+    for (int out = 0; out < 8; out++) {
+
+        if (scheduleConfig & (1 << out)) {
+            
+            if (schedules[out] & scheduleIndexer) {
+                writeOutputBuffers[0] |= (1 << out);
+            } else {
+                writeOutputBuffers[0] &= ~(1 << out);
+            }
+        }
+        
+        /* update GPIO's immediately only if new signal was given */
+        int outputBufferChanges = writeOutputBuffers[0] ^ prevOutputBuffers[0];
+        
+        if (outputBufferChanges & (1 << out)) {
+            if ((1 << out) & writeOutputBuffers[0]) {
+                /* switched on */
+                newOutput |= (1 << out);
+
+                /* reset timers */
+                if (outputConfigs[out].type) {
+                    outputTimers[out] = OutputConfiguration(outputConfigs[out]);
+                }
+            } else {
+                /* switched off */
+                newOutput &= ~(1 << out);
+                memset(&outputTimers[out], 0, sizeof(outputTimers[out]));
+            }
+        }
+
+        /* if there is a pulse run down the timer */
+        if (outputTimers[out].type & 0x01) {
+
+            if (outputTimers[out].pulse_ms >= timeSinceLastTick) {
+                outputTimers[out].pulse_ms -= timeSinceLastTick;
+            } else {
+                /* time past would put timer below 0 */
+                outputTimers[out].pulse_ms = 0;
+            }
+
+            /* if time has run out */
+            if (0 == outputTimers[out].pulse_ms) {
+
+                /* just turn off pulse */
+                outputTimers[out].type &= 0xFE;
+                newOutput &= ~(1 << out);
+
+                /* if there is a patter, then output buffer will stay on */
+                /* but if there is a pulsed-patter, then it should still turn off */
+                if (!(outputTimers[out].type & 0x02) ||
+                        (outputTimers[out].type & (0x02 | 0x04))) {
+                    /* turn buffer off */
+                    outputTimers[out].type = 0;
+                    writeOutputBuffers[0] &= ~(1 << out);
+                }
+            }
+        }
+
+        /* two ways to patter:
+         * wait until after pulse (pulse-then-patter),
+         * or config so pulse happens at same time (pulsed-patter)
+         */
+        if (((outputTimers[out].type & 0x02)          && !(outputTimers[out].type & 0x01)) ||
+                ((outputTimers[out].type & (0x02 | 0x04)) &&  (outputTimers[out].type & 0x01))) {
+
+            /* if output is on, run down pwm_on, else tun down pwm_off */
+            uint8_t *pw_timer;
+            if (newOutput & (1 << out)) {
+                pw_timer = &outputTimers[out].pwm_on;
+            } else {
+                pw_timer = &outputTimers[out].pwm_off;
+            }
+
+            if (*pw_timer >= timeSinceLastTick) {
+                *pw_timer -= timeSinceLastTick;
+            } else {
+                *pw_timer = 0;
+            }
+
+            if (*pw_timer == 0) {
+                newOutput ^= (1 << out);
+
+                outputTimers[out].pwm_on  = outputConfigs[out].pwm_on;
+                outputTimers[out].pwm_off = outputConfigs[out].pwm_off;
+            }
+        }
+
+
+    }
+
+    mbedOutputs = ((uint16_t)newOutput) << 8;
+
+    prevOutputBuffers[0] = writeOutputBuffers[0];
+}
+
+void Node_pin0808::OnUpdate (void)
+{    
+    /* Check for output configurations --------------------------------------*/
+    if (writeOutputConfig.writeData) {
+        uint8_t out = (uint8_t)(writeOutputConfig.writeData);
+        
+        writeOutputConfig.writeData = 0;
+        outputConfigs[out] = writeOutputConfig;
+        
+        memset(&writeOutputConfig, 0, sizeof(writeOutputConfig));
+    }
+
+
+    /* Check for rule configurations ----------------------------------------*/
+    if (writeRule.sourceId) {
+        printf("      Configuring Rules...\r\n");
+        if (writeRule.sourceId & 0x80) {
+            /* write new rule*/
+            
+            /* scan through array of rules for available (8th bit cleared) */
+            int ruleNum = 0;
+            while (ruleNum < 24) {
+                if (!(rules[ruleNum].sourceId & 0x80)) {
+                                        
+                    rules[ruleNum] = writeRule;
+                    printf("      Rule added: #%d\r\n", ruleNum);
+                    ruleNum = 24;
+                } else {
+                    ruleNum++;
+                    if (ruleNum == 24) {
+                        printf("      ERROR: Not enough rules available");
+                    }
+                }
+            }
+            
+        } else {
+            /* clear rules */
+            
+            /* scan through array of rules matching input and disable */
+            for (int ruleNum = 0; ruleNum < 24; ruleNum++) {
+                
+                /* check if rule enabled and input num matches */
+                if ((rules[ruleNum].sourceId & 0x80) &&
+                   ((rules[ruleNum].sourceId & 0x7F) == writeRule.sourceId) &&
+                   ((rules[ruleNum].input    & 0x1F) == (writeRule.input & 0x1F))) 
+                {
+                    memset(&rules[ruleNum], 0, sizeof(AutotriggerRule));
+                    printf("      Rule removed: #%d\r\n", ruleNum);
+                }
+                
+            }
+        }
+    
+        memset(&writeRule, 0, sizeof(AutotriggerRule));   
+    }
+
+    /* check for input changes  from other devices---------------------------*/
+    if (autotriggerMessage.sourceId) {
+        
+        printf("      detected change from node: %#04x\r\n", (autotriggerMessage.sourceId & 0x7F));
+        /* scan through array of rules matching inputs and direction */
+        for (int ruleNum = 0; ruleNum < 24; ruleNum++) {
+            
+            /* check if rule enabled and input num matches */
+            if ((rules[ruleNum].sourceId & 0x80) &&                                     /* rule is active AND */                  
+                (rules[ruleNum].sourceId == autotriggerMessage.sourceId) &&             /* rule source matches message source AND */ 
+                (autotriggerMessage.change[0] & (1 << (rules[ruleNum].input & 0x1F))))  /* change exists at input num */
+            {
+                
+                int ruleActivity = rules[ruleNum].input >> 5;
+                int inputActivity = (autotriggerMessage.input[0] >> (rules[ruleNum].input & 0x1F)) & 1;
+                
+                printf("         id match:      %#04x\r\n", ruleNum);
+                printf("         ruleActivity:  %#04x\r\n", ruleActivity);
+                printf("         inputActivity: %#04x\r\n", inputActivity);
+                
+                if ((2 == ruleActivity) || (inputActivity == ruleActivity)) {
+                    
+                    printf("            activating Rule...\r\n");
+                    printf("            setMask:   %#10x\r\n", rules[ruleNum].setMask[0]);
+                    printf("            clearMask: %#10x\r\n", ~rules[ruleNum].clearMask[0]);
+                    
+                    writeOutputBuffers[0] |= rules[ruleNum].setMask[0];
+                    //writeOutputBuffers[1] |= rules[ruleNum].setMask[1];
+                    //writeOutputBuffers[2] |= rules[ruleNum].setMask[2];
+                    
+                    writeOutputBuffers[0] &= ~rules[ruleNum].clearMask[0];
+                    //writeOutputBuffers[1] &= ~rules[ruleNum].clearMask[1];
+                    //writeOutputBuffers[2] &= ~rules[ruleNum].clearMask[2];
+                }
+            }
+            
+        }
+        
+        memset(&autotriggerMessage, 0, sizeof(AutotriggerMessage)); 
+    }
+
+    /* check for input changes from this device -----------------------------*/
+    /* update Index 2101-01 */
+    inputChangeMask[0] = readInputBuffers[0] ^ prevInputBuffers[0];
+
+    /* check for rules against this devices inputs */
+    if (inputChangeMask[0]) {
+        /* scan through array of rules matching inputs and direction */
+        for (int ruleNum = 0; ruleNum < 24; ruleNum++) {
+            
+            /* check if rule enabled and input num matches */
+            if ((rules[ruleNum].sourceId & 0x80) &&                             /* rule is active AND */                  
+                ((rules[ruleNum].sourceId & 0x7F) == nodeId) &&                 /* rule source is this nodeId AND */ 
+                (inputChangeMask[0] & (1 << (rules[ruleNum].input & 0x1F))))    /* change exists at input num */
+            {
+                
+                int ruleActivity = rules[ruleNum].input >> 5;
+                int inputActivity = (readInputBuffers[0] >> (rules[ruleNum].input & 0x1F)) & 1;
+                
+                if ((2 == ruleActivity) || (inputActivity == ruleActivity)) {
+                    writeOutputBuffers[0] |= rules[ruleNum].setMask[0];
+                    //writeOutputBuffers[1] |= rules[ruleNum].setMask[1];
+                    //writeOutputBuffers[2] |= rules[ruleNum].setMask[2];
+                    
+                    writeOutputBuffers[0] &= ~rules[ruleNum].clearMask[0];
+                    //writeOutputBuffers[1] &= ~rules[ruleNum].clearMask[1];
+                    //writeOutputBuffers[2] &= ~rules[ruleNum].clearMask[2];
+                }
+            }
+            
+        }
+    }
+
+    /* index 6005-01 configured to enable interrupt messages */
+    if (bInputInterruptEnable) {
+        
+        /* if change is within index 6006-01, interrupt mask */
+        if (inputChangeMask[0] & inputInterruptMask[0]) {
+            
+            /* send a message immediately */
+            PostTPDO(0x181);
+        }
+        
+    }
+    
+    prevInputBuffers[0] = readInputBuffers[0];
+}
+
+/******************************************************************************
+ * SYNC Implementation
+ ******************************************************************************
+ */
+
+void Node_pin0808::OnSync (uint8_t counter)
+{
+
+}
+
+/******************************************************************************
+ * NMT Control Implementation
+ ******************************************************************************
+ */
+
+void Node_pin0808::OnInitialize (void)
+{
+    printf("      Node_pin0808::INITIALIZE!\r\n");
+
+    mbedOutputs = 0xFFFF;
+    wait(1.0);
+    mbedOutputs = 0;
+
+    prevOutputBuffers[0] = 0;
+    writeOutputBuffers[0] = 0;
+    
+    prevInputBuffers[0] = 0;
+    readInputBuffers[0] = 0;
+}
+
+void Node_pin0808::OnPreoperational (void)
+{
+    printf("      Node_pin0808::PRE-OPERATIONAL!\r\n");
+}
+
+void Node_pin0808::OnOperational (void)
+{
+    printf("      Node_pin0808::OPERATIONAL!\r\n");
+
+    mbedOutputs = (writeOutputBuffers[0] << 16);
+}
+
+void Node_pin0808::OnStopped (void)
+{
+    printf("      Node_pin0808::STOPPED!\r\n");
+
+    mbedOutputs = 0;
+}
+
+/******************************************************************************
+ * Object Dictionary Handling
+ ******************************************************************************
+ */
+
+ObjectData * Node_pin0808::ScanIndex(IndexSize index)
+{
+    ObjectData * result = 0;
+
+    switch(index) {
+        case 0x1200: result = &dictionary[0]; break;
+        case 0x1400: result = &dictionary[1]; break;
+        case 0x1401: result = &dictionary[2]; break;
+        case 0x1402: result = &dictionary[3]; break;
+        case 0x1403: result = &dictionary[4]; break;
+        case 0x1600: result = &dictionary[5]; break;
+        case 0x1601: result = &dictionary[6]; break;
+        case 0x1602: result = &dictionary[7]; break;
+        case 0x1603: result = &dictionary[8]; break;
+        case 0x1800: result = &dictionary[10]; break;
+        case 0x1A00: result = &dictionary[11]; break;
+        case 0x2001: result = &dictionary[12]; break;
+        case 0x2002: result = &dictionary[13]; break;
+        case 0x2100: result = &dictionary[14]; break;
+        case 0x2200: result = &dictionary[15]; break;
+        case 0x6000: result = &dictionary[16]; break;
+        case 0x6005: result = &dictionary[17]; break;
+        case 0x6006: result = &dictionary[18]; break;
+        case 0x6200: result = &dictionary[19]; break;
+        default:
+            // TODO add error handling
+            break;
+    }
+
+    return result;
+}
+
+} /* namespace ppCANOpen */