
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, committed 2016-03-19
- Comitter:
- ptpaterson
- Date:
- Sat Mar 19 01:44:35 2016 +0000
- Parent:
- 9:8352cfe17ab1
- Commit message:
- Final Submission (probs)
Changed in this revision
diff -r 8352cfe17ab1 -r ec59d628ebdc Application/include/Node_pin0808.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Application/include/Node_pin0808.h Sat Mar 19 01:44:35 2016 +0000 @@ -0,0 +1,269 @@ +/** + ****************************************************************************** + * @file + * @author Paul Paterson + * @version + * @date 2015-12-14 + * @brief CANOpen implementation library + ****************************************************************************** + * @attention + * + * <h2><center>© 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/>. + */ + +#ifndef PPCAN_NODE_PIN0808_H +#define PPCAN_NODE_PIN0808_H + +#include "Node.h" + +namespace ppCANOpen +{ + +/** Custom Object Dictionary for pinball io_0808 device. + */ +class Node_pin0808 : public Node +{ + +public: + Node_pin0808(int id, ServiceProvider * provider, int bLoop = 0); + virtual ~Node_pin0808(void); + +private: + /* constants */ + /** milliseconds necessary to debounce all input */ + static const uint8_t DEBOUNCE_TIME = 3; + + /* IO details */ + uint8_t prevInputBuffers[1]; + uint8_t inputDebounce[8]; + + uint8_t prevOutputBuffers[1]; + int scheduleIndexTime; + + /************************************************************************** + * Implementation Overrides + ************************************************************************** + */ + + /* Application run */ + virtual void OnFixedUpdate(void); + virtual void OnUpdate(void); + + /* SYNC */ + virtual void OnSync (uint8_t counter); + + /* NMT Control */ + virtual void OnInitialize (void); + virtual void OnPreoperational (void); + virtual void OnOperational (void); + virtual void OnStopped (void); + + + /************************************************************************** + * Object Dictionary + ************************************************************************** + */ + + /* Communication --------------------------------------------------------*/ + /* index 0x1200 : SDO Server */ + ObjectData Obj1200; + SubIndexSize Obj1200_highestSubIndex; + uint32_t Obj1200_ReceiveCobId; + uint32_t Obj1200_TransmitCobId; + EntryData Obj1200_entries[3]; + + /* index 0x1400 : Receive PDO 1 Parameter (Write Digital Output) */ + ObjectData Obj1400; + SubIndexSize Obj1400_highestSubIndex; + uint32_t Obj1400_CobId; + uint8_t Obj1400_TransmissionType; + uint16_t Obj1400_InhibitTime; + uint8_t Obj1400_CompatibilityEntry; + uint16_t Obj1400_EventTimer; + EntryData Obj1400_entries[6]; + + /* index 0x1401 : Receive PDO 2 Parameter (Write Output Configuration) */ + ObjectData Obj1401; + SubIndexSize Obj1401_highestSubIndex; + uint32_t Obj1401_CobId; + uint8_t Obj1401_TransmissionType; + uint16_t Obj1401_InhibitTime; + uint8_t Obj1401_CompatibilityEntry; + uint16_t Obj1401_EventTimer; + EntryData Obj1401_entries[6]; + + /* index 0x1402 : Receive PDO 3 Parameter (Write/Clear Autotrigger Rule) */ + ObjectData Obj1402; + SubIndexSize Obj1402_highestSubIndex; + uint32_t Obj1402_CobId; + uint8_t Obj1402_TransmissionType; + uint16_t Obj1402_InhibitTime; + uint8_t Obj1402_CompatibilityEntry; + uint16_t Obj1402_EventTimer; + EntryData Obj1402_entries[6]; + + /* index 0x1403 : Receive PDO 5 Parameter (input changes) */ + ObjectData Obj1403; + SubIndexSize Obj1403_highestSubIndex; + uint32_t Obj1403_CobId; + uint8_t Obj1403_TransmissionType; + uint16_t Obj1403_InhibitTime; + uint8_t Obj1403_CompatibilityEntry; + uint16_t Obj1403_EventTimer; + EntryData Obj1403_entries[6]; + + /* index 0x1600 : Receive PDO 1 Mapping */ + ObjectData Obj1600; + SubIndexSize Obj1600_highestSubIndex; + uint32_t Obj1600_Map; + EntryData Obj1600_entries[2]; + + /* index 0x1601 : Transmit PDO 1 Mapping */ + ObjectData Obj1601; + SubIndexSize Obj1601_highestSubIndex; + uint32_t Obj1601_Map; + EntryData Obj1601_entries[2]; + + /* index 0x1602 : Transmit PDO 1 Mapping */ + ObjectData Obj1602; + SubIndexSize Obj1602_highestSubIndex; + uint32_t Obj1602_Map; + EntryData Obj1602_entries[2]; + + /* index 0x1603 : Receive PDO 2 Mapping */ + ObjectData Obj1603; + SubIndexSize Obj1603_highestSubIndex; + uint32_t Obj1603_Map; + EntryData Obj1603_entries[2]; + + + /* index 0x1800 : Transmit PDO 1 Parameter */ + ObjectData Obj1800; + SubIndexSize Obj1800_highestSubIndex; + uint32_t Obj1800_CobId; + uint8_t Obj1800_TransmissionType; + uint16_t Obj1800_InhibitTime; + uint8_t Obj1800_CompatibilityEntry; + uint16_t Obj1800_EventTimer; + EntryData Obj1800_entries[6]; + + /* index 0x1A00 : Transmit PDO 1 Mapping */ + ObjectData Obj1A00; + SubIndexSize Obj1A00_highestSubIndex; + uint32_t Obj1A00_MapInput; + uint32_t Obj1A00_MapVoid16; + uint32_t Obj1A00_MapChange; + uint32_t Obj1A00_MapSourceId; + EntryData Obj1A00_entries[6]; + + + /* Manufacturer Specific ------------------------------------------------*/ + /* index 0x2001 : Pin Output Configurations */ + struct OutputConfiguration { + static const uint8_t PULSE = 0x01; + static const uint8_t PATTER = 0x02; + static const uint8_t PULSED_PATTER = 0x04; + //static const uint8_t SCHEDULED = 0x08; + + uint8_t type; + uint8_t pulse_ms; + uint8_t pwm_on; + uint8_t pwm_off; + uint32_t writeData; + }; + + ObjectData Obj2001; + SubIndexSize Obj2001_highestSubIndex; + OutputConfiguration writeOutputConfig; + OutputConfiguration outputConfigs[8]; + OutputConfiguration outputTimers[8]; /* not actually part of dictionary */ + EntryData Obj2001_entries[10]; + + /* index 0x2002 : Output Schedule Configuration */ + ObjectData Obj2002; + SubIndexSize Obj2002_highestSubIndex; + uint32_t scheduleConfig; + uint32_t schedules[8]; + EntryData Obj2002_entries[10]; + + /* index 0x2100 : Input change data */ + ObjectData Obj2100; + SubIndexSize Obj2100_highestSubIndex; + uint8_t inputChangeMask[1]; + /* uint8_t nodeId; */ + EntryData Obj2100_entries[3]; + + /* index 0x2200 : Autotrigger Rules */ + struct AutotriggerRule { + uint8_t sourceId; + uint8_t input; /* 0-4: inputNum (0-23) + 5-7: 0 on inactive + 1 on active + 2 on any change + 3 ??? + */ + uint8_t setMask[3]; + uint8_t clearMask[3]; + }; + + struct AutotriggerMessage { + uint8_t input[3]; + uint8_t change[3]; + uint8_t sourceId; + }; + + ObjectData Obj2200; + SubIndexSize Obj2200_highestSubIndex; + AutotriggerRule writeRule; + AutotriggerMessage autotriggerMessage; + AutotriggerRule rules[24]; + EntryData Obj2200_entries[27]; + + + /* Device Specific ------------------------------------------------------*/ + /* index 0x6000 : Mapped variable "inputs" */ + ObjectData Obj6000; + SubIndexSize Obj6000_highestSubIndex; + uint8_t readInputBuffers[1]; + EntryData Obj6000_entries[2]; + + /* index 0x6005 : Global Input Interrupt Enable */ + ObjectData Obj6005; + SubIndexSize Obj6005_highestSubIndex; + uint8_t bInputInterruptEnable; + EntryData Obj6005_entries[2]; + + /* index 0x6006 : Any Change Interrupt Mask */ + ObjectData Obj6006; + SubIndexSize Obj6006_highestSubIndex; + uint8_t inputInterruptMask[1]; + EntryData Obj6006_entries[2]; + + /* index 0x6200 : Mapped variable "outputs" */ + ObjectData Obj6200; + SubIndexSize Obj6200_highestSubIndex; + uint8_t writeOutputBuffers[1]; + EntryData Obj6200_entries[2]; + + /* Scan Method */ + virtual ObjectData * ScanIndex(IndexSize index); +}; + +} /* namespace ppCANOpen */ + +#endif // PPCAN_NODE_PIN0808_H
diff -r 8352cfe17ab1 -r ec59d628ebdc Application/include/SerialBuffered.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Application/include/SerialBuffered.h Sat Mar 19 01:44:35 2016 +0000 @@ -0,0 +1,61 @@ +#ifndef _SERIAL_BUFFERED_H_ +#define _SERIAL_BUFFERED_H_ + +/** + * Buffered serial class. + */ +class SerialBuffered : public Serial { +public: + /** + * Create a buffered serial class. + * + * @param tx A pin for transmit. + * @param rx A pin for receive. + */ + SerialBuffered(PinName tx, PinName rx); + + /** + * Destroy. + */ + virtual ~SerialBuffered(); + + /** + * Get a character. + * + * @return A character. (-1:timeout) + */ + int getc(); + + /** + * Returns 1 if there is a character available to read, 0 otherwise. + */ + int readable(); + + /** + * Set timeout for getc(). + * + * @param ms milliseconds. (-1:Disable timeout) + */ + void setTimeout(int ms); + + /** + * Read requested bytes. + * + * @param bytes A pointer to a buffer. + * @param requested Length. + * + * @return Readed byte length. + */ + size_t readBytes(uint8_t *bytes, size_t requested); + +private: + void handleInterrupt(); + static const int BUFFERSIZE = 2048; + uint8_t buffer[BUFFERSIZE]; // points at a circular buffer, containing data from m_contentStart, for m_contentSize bytes, wrapping when you get to the end + uint16_t indexContentStart; // index of first bytes of content + uint16_t indexContentEnd; // index of bytes after last byte of content + int timeout; + Timer timer; +}; + +#endif
diff -r 8352cfe17ab1 -r ec59d628ebdc Application/source/Node_pin0808.cpp --- /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>© 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 */
diff -r 8352cfe17ab1 -r ec59d628ebdc Application/source/SerialBuffered.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Application/source/SerialBuffered.cpp Sat Mar 19 01:44:35 2016 +0000 @@ -0,0 +1,99 @@ +#include "mbed.h" +#include "SerialBuffered.h" + +/** + * Create a buffered serial class. + * + * @param tx A pin for transmit. + * @param rx A pin for receive. + */ +SerialBuffered::SerialBuffered(PinName tx, PinName rx) : Serial(tx, rx) { + indexContentStart = 0; + indexContentEnd = 0; + timeout = 1; + attach(this, &SerialBuffered::handleInterrupt); +} + +/** + * Destroy. + */ +SerialBuffered::~SerialBuffered() { +} + +/** + * Set timeout for getc(). + * + * @param ms milliseconds. (-1:Disable timeout) + */ +void SerialBuffered::setTimeout(int ms) { + timeout = ms; +} + +/** + * Read requested bytes. + * + * @param bytes A pointer to a buffer. + * @param requested Length. + * + * @return Readed byte length. + */ +size_t SerialBuffered::readBytes(uint8_t *bytes, size_t requested) { + int i = 0; + while (i < requested) { + int c = getc(); + if (c < 0) { + break; + } + bytes[i] = c; + i++; + } + return i; +} + +/** + * Get a character. + * + * @return A character. (-1:timeout) + */ +int SerialBuffered::getc() { + timer.reset(); + timer.start(); + while (indexContentStart == indexContentEnd) { + wait_ms(1); + if ((timeout > 0) && (timer.read_ms() > timeout)) { + /* + * Timeout occured. + */ + // printf("Timeout occured.\n"); + return EOF; + } + } + timer.stop(); + + uint8_t result = buffer[indexContentStart++]; + indexContentStart = indexContentStart % BUFFERSIZE; + + return result; +} + +/** + * Returns 1 if there is a character available to read, 0 otherwise. + */ +int SerialBuffered::readable() { + return indexContentStart != indexContentEnd; +} + +void SerialBuffered::handleInterrupt() { + while (Serial::readable()) { + if (indexContentStart == ((indexContentEnd + 1) % BUFFERSIZE)) { + /* + * Buffer overrun occured. + */ + // printf("Buffer overrun occured.\n"); + Serial::getc(); + } else { + buffer[indexContentEnd++] = Serial::getc(); + indexContentEnd = indexContentEnd % BUFFERSIZE; + } + } +}
diff -r 8352cfe17ab1 -r ec59d628ebdc Application/source/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Application/source/main.cpp Sat Mar 19 01:44:35 2016 +0000 @@ -0,0 +1,71 @@ + +/** @file + * @brief main program entry + */ + +#include "mbed.h" +#include "CAN.h" + +#include "ppCANOpen.h" +#include "Node_pin0808.h" + +DigitalOut boardLed (LED1); + +void InputScan () +{ + boardLed = !boardLed; +} + + +int main() +{ + + printf ("\r\n----- MAIN -----\r\n"); + + /* blinker task*/ + boardLed = 0; + +//#define MASTER +#ifdef MASTER + + /* CanOpen start */ + ServiceProvider service; + printf ("----- READY -----\r\n"); + + Node_pin0808 node1(2, &service); + //Node_pin0808 node2(&service); + + service.PostNmtControl(1, NMT_CS_RESET_NODE); + service.Run(); + service.PostNmtControl(2, NMT_CS_START); + service.Run(); + service.PostNmtControl(3, NMT_CS_START); + service.Run(); + service.PostNmtControl(4, NMT_CS_START); + service.Run(); + service.PostNmtControl(5, NMT_CS_START); + service.Run(); + service.PostNmtControl(6, NMT_CS_START); + service.Run(); + + while (1) { + service.Run(); + } + +#else + + /* CanOpen start */ + ServiceProvider service; + printf ("----- READY -----\r\n"); + + Node_pin0808 node1(3, &service); + + while (1) { + service.Run(); + } + +#endif + + printf ("----- END -------\r\n\n"); + +}
diff -r 8352cfe17ab1 -r ec59d628ebdc CANnucleo.lib --- a/CANnucleo.lib Wed Dec 23 10:38:02 2015 +0000 +++ b/CANnucleo.lib Sat Mar 19 01:44:35 2016 +0000 @@ -1,1 +1,1 @@ -https://developer.mbed.org/users/hudakz/code/CANnucleo/#a3e2be3d49a2 +https://developer.mbed.org/users/ptpaterson/code/CANnucleo/#cdab1fd4ff26
diff -r 8352cfe17ab1 -r ec59d628ebdc main.cpp --- a/main.cpp Wed Dec 23 10:38:02 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - * An example showing how to use the CANnucleo library: - * - * Two affordable (less than $4 on ebay) STM32F103C8T6 boards (20kB SRAM, 64kB Flash), - * compatible with the NUCLEO-F103RB platform (20kB SRAM, 128kB Flash), - * are connected to the same CAN bus via transceivers (MCP2551 or TJA1040, or etc.). - * CAN transceivers are not part of NUCLEO boards, therefore must be added by you. - * Remember also that CAN bus (even a short one) must be terminated with 120 Ohm resitors at both ends. - * - * For more details see the wiki page <https://developer.mbed.org/users/hudakz/code/CAN_Nucleo_Hello/> - * - * NOTE: If you'd like to use the official NUCLEO-F103RB boards - * comment out the line #define TARGET_STM32F103C8T6 1 - * - * The same code is used for both NUCLEO boards, but: - * For board #1 compile the example without any change. - * For board #2 comment out the line #define BOARD1 1 before compiling - * - * Once the binaries have been downloaded to the boards reset board #1. - * - */ - -#include "mbed.h" -#include "CAN.h" - -#define BOARD1 1 // comment out this line when compiling for board #2 - -#if defined(BOARD1) - #define RX_ID 0x100 - #define TX_ID 0x101 -#else - #define RX_ID 0x101 - #define TX_ID 0x100 -#endif - -// See wiki page <https://developer.mbed.org/users/hudakz/code/CAN_Nucleo_Hello/> -//#define TARGET_STM32F103C8T6 1 // comment out this line if you'd like to use the official NUCLEO-F103RB boards - -#if defined(TARGET_STM32F103C8T6) - DigitalOut led(PC_13); -#else - DigitalOut led(LED1); -#endif - -int ledReceived; -Timer timer; -CAN can(PA_11, PA_12); // CAN Rx pin name, CAN Tx pin name, Automatic recovery from bus-off state enabled by default -CANMessage rxMsg; -CANMessage txMsg; -int counter = 0; -volatile bool msgAvailable = false; - -/** - * @brief 'CAN receive-complete' interrup handler. - * @note Called on arrival of new CAN message. - * Keep it as short as possible. - * @param - * @retval - */ -void onMsgReceived() { - msgAvailable = true; -} - -/** - * @brief Main - * @note - * @param - * @retval - */ -int main() { - can.frequency(1000000); // set bit rate to 1Mbps - can.attach(&onMsgReceived, CAN::RxIrq); // attach 'CAN receive-complete' interrupt handler - -#if defined(BOARD1) - #if defined(TARGET_STM32F103C8T6) - led = 0; // turn LED on - #else - led = 1; // turn LED on - #endif - timer.start(); -#else - #if defined(TARGET_STM32F103C8T6) - led = 1; // turn LED off - #else - led = 0; // turn LED off - #endif -#endif - - while(1) { - if(timer.read() >= 1.0) { // check for timeout - timer.stop(); // stop timer - timer.reset(); // reset timer (to avaoid repeated send) - counter++; // increment counter - txMsg.clear(); // clear Tx message storage - txMsg.id = TX_ID; // set ID - txMsg << counter; // append first data item (make sure that CAN message total data lenght <= 8 bytes!) - txMsg << led.read(); // append second data item (make sure that CAN message total data lenght <= 8 bytes!) - can.write(txMsg); // transmit message - printf("CAN message sent\r\n"); - - #if defined(TARGET_STM32F103C8T6) - led = 1; // turn LED off - #else - led = 0; // turn LED off - #endif - } - if(msgAvailable) { - msgAvailable = false; // reset flag for next use - can.read(rxMsg); // read message into Rx message storage - printf("CAN message received:\r\n"); - printf(" ID = %#x\r\n", rxMsg.id); - printf(" Type = %d\r\n", rxMsg.type); - printf(" Format = %d\r\n", rxMsg.format); - printf(" Length = %d\r\n", rxMsg.len); - printf(" Data ="); - for(int i = 0; i < rxMsg.len; i++) - printf(" %x", rxMsg.data[i]); - printf("\r\n"); - if(rxMsg.id == RX_ID) { // if ID matches - rxMsg >> counter; // extract first data item - rxMsg >> ledReceived; // extract second data item - led = ledReceived; // set LED - printf("counter = %d\r\n", counter); - timer.start(); - } - } - } -} -
diff -r 8352cfe17ab1 -r ec59d628ebdc ppCANOpen.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ppCANOpen.lib Sat Mar 19 01:44:35 2016 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/ptpaterson/code/ppCANOpen/#22a337cdc0e3