diff --git a/.cproject b/.cproject
new file mode 100644
index 0000000..6cc94b6
--- /dev/null
+++ b/.cproject
@@ -0,0 +1,278 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/.gitignore
diff --git a/.project b/.project
new file mode 100644
index 0000000..36ba0c5
--- /dev/null
+++ b/.project
@@ -0,0 +1,29 @@
+
+
+ DALI
+
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.genmakebuilder
+ clean,full,incremental,
+
+
+
+
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
+ full,incremental,
+
+
+
+
+
+ org.eclipse.cdt.core.cnature
+ com.ifx.xmc4000.xmc4000Nature
+ com.dave.common.daveBenchNature
+ org.eclipse.cdt.managedbuilder.core.managedBuildNature
+ org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
+ org.eclipse.cdt.core.ccnature
+
+
diff --git a/.settings/com.dave.mbs.xc800.prefs b/.settings/com.dave.mbs.xc800.prefs
new file mode 100644
index 0000000..b0d2b88
--- /dev/null
+++ b/.settings/com.dave.mbs.xc800.prefs
@@ -0,0 +1,13 @@
+ACTIVE_CONFIG_NAME=Debug
+AppCompatibilitySet=1
+DEVICE_DESC=Package\= TSSOP38 \nROM\= 200 KB Flash \nRAM\= 16 KB RAM \nInOut\= 34 digital I/O \nADC\= 12 ADC Channels, 12-bit, Analog-to-Digital Converter \nTimed_InOut\= 6 Timer, 4 CAPCOM channels \nSerial\= 2 USIC channels \nSHS\= 2 Sample and Hold Sequencer \nCOMP\= Comparator Control Unit \nTouch\= Touch and LED matrix control \nBCCU\= Brightness and Color Control Unit \n
+DEVICE_NAME=XMC1200-T038x0200
+DEVICE_PACKAGE=TSSOP38
+DEVICE_PACK_VERSION=2.0.0
+DEVICE_PATH=/DeviceRoot/Microcontrollers/XMC1000/XMC1200 Series/XMC1200-T038x0200
+FLASH_SIZE=200
+MBS_PROVIDER_ID_KEY=com.dave.mbs.xmc4000.xmc4000MbsFactory
+SOFTWARE_ID=XMC1.2.00.T038.ALL
+TEMPLATE_KEY=com.ifx.xmc4000.appEmptyMainTemplate
+eclipse.preferences.version=1
+minDaveVersion=4.1.2
diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml
new file mode 100644
index 0000000..5bc6ec3
--- /dev/null
+++ b/.settings/language.settings.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/properties.index b/.settings/properties.index
new file mode 100644
index 0000000..1f7acaf
--- /dev/null
+++ b/.settings/properties.index
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 224f14c..8593882 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,7 @@
# dali_slave
-Implementation of DALI slave.
+Implementation of DALI slave using C++ 11.
+
+Requirements:
+* DAVE4
+* Infineon libraries "Infineon/Libraries"
+* LED Lighting Application Kit
\ No newline at end of file
diff --git a/linker_script.ld b/linker_script.ld
new file mode 100644
index 0000000..92c412c
--- /dev/null
+++ b/linker_script.ld
@@ -0,0 +1,241 @@
+/**
+ * @file XMC1200x0200.ld
+ * @date 2015-07-07
+ *
+ * @cond
+ *********************************************************************************************************************
+ * Linker file for the GNU C Compiler v1.7
+ * Supported devices: XMC1200-T038F0200
+ * XMC1201-T038F0200
+ * XMC1201-Q040F0200
+ *
+ * Copyright (c) 2015, Infineon Technologies AG
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the
+ * following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with
+ * Infineon Technologies AG dave@infineon.com).
+ *********************************************************************************************************************
+ *
+ * Change History
+ * --------------
+ *
+ * 2015-07-07:
+ * - Product splitting
+ * - Copyright notice update
+ *
+ * @endcond
+ *
+ */
+
+OUTPUT_FORMAT("elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(Reset_Handler)
+
+MEMORY
+{
+ FLASH(RX) : ORIGIN = 0x10001000, LENGTH = 0x31a00
+ SRAM(!RX) : ORIGIN = 0x20000000, LENGTH = 0x4000
+}
+
+stack_size = 1536;
+
+SECTIONS
+{
+ /* TEXT section */
+
+ .text :
+ {
+ sText = .;
+ KEEP(*(.reset));
+ *(.text .text.* .gnu.linkonce.t.*);
+
+ /* ARM <->THUMB interworking */
+ *(.glue*)
+ *(.v4*)
+ *(.vfp11_veneer)
+
+ /* C++ Support */
+ KEEP(*(.init))
+ __preinit_array_start = .;
+ KEEP (*(.preinit_array))
+ __preinit_array_end = .;
+ __init_array_start = .;
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ __init_array_end = .;
+ KEEP (*crtbegin.o(.ctors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*crtend.o(.ctors))
+ KEEP(*(.fini))
+ __fini_array_start = .;
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ __fini_array_end = .;
+
+ KEEP (*crtbegin.o(.dtors))
+ KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*crtend.o(.dtors))
+
+ /* Exception handling support */
+ __extab_start = .;
+ *(.ARM.extab* .gnu.linkonce.armextab.*)
+ . = ALIGN(4);
+ __extab_end = ABSOLUTE(.);
+ } > FLASH
+
+ /* Exception handling, exidx needs a dedicated section */
+ .ARM.exidx :
+ {
+ __exidx_start = .;
+ *(.ARM.exidx* .gnu.linkonce.armexidx.*)
+ . = ALIGN(4);
+ __exidx_end = ABSOLUTE(.);
+ } > FLASH
+
+ /* CONST data section */
+ .rodata :
+ {
+ *(.rodata .rodata.*)
+ *(.gnu.linkonce.r*)
+ } > FLASH
+
+ . = ALIGN(16);
+
+ /* End of RO-DATA and start of LOAD region for the veneers */
+ eROData = . ;
+
+ /* DSRAM layout (Lowest to highest)*/
+ /* Veneer <-> Stack <-> DATA <-> BSS <-> HEAP */
+
+ .VENEER_Code ABSOLUTE(0x2000000C): AT(eROData)
+ {
+ VeneerStart = .;
+ KEEP(*(.XmcVeneerCode));
+ . = ALIGN(4);
+ VeneerEnd = .;
+ } > SRAM
+
+ VeneerSize = ABSOLUTE(VeneerEnd) - ABSOLUTE(VeneerStart);
+
+ /* Dummy section for stack */
+ Stack (NOLOAD) : AT(0)
+ {
+ . = ALIGN(8);
+ . = . + stack_size;
+ __initial_sp = .;
+ } > SRAM
+
+ /* Standard DATA and user defined DATA/BSS/CONST sections */
+ DataLoadAddr = eROData + VeneerSize;
+ .data : AT(DataLoadAddr)
+ {
+ __data_start = .;
+ * (.data);
+ * (.data*);
+ *(*.data);
+ *(.gnu.linkonce.d*)
+ . = ALIGN(4);
+ __data_end = .;
+ } > SRAM
+ __data_size = __data_end - __data_start;
+
+ .ram_code : AT(DataLoadAddr + __data_size)
+ {
+ __ram_code_start = .;
+ /* functions with __attribute__ ((section (".ram_code")))*/
+ *(.ram_code)
+ . = ALIGN(4);
+ __ram_code_end = .;
+ } > SRAM
+ __ram_code_load = LOADADDR (.ram_code);
+ __ram_code_size = __ram_code_end - __ram_code_start;
+
+ /* BSS section */
+ .bss (NOLOAD) :
+ {
+ __bss_start = .;
+ * (.bss);
+ * (.bss*);
+ * (COMMON);
+ *(.gnu.linkonce.b*)
+ . = ALIGN(4);
+ __bss_end = .;
+ . = ALIGN(8);
+ Heap_Bank1_Start = .;
+ } > SRAM
+ __bss_size = __bss_end - __bss_start;
+
+ /* .no_init section */
+ .no_init 0x20003FFC (NOLOAD) :
+ {
+ Heap_Bank1_End = .;
+ * (.no_init);
+ } > SRAM
+
+ /* Heap - Bank1*/
+ Heap_Bank1_Size = Heap_Bank1_End - Heap_Bank1_Start;
+
+ /DISCARD/ :
+ {
+ *(.comment)
+ }
+
+ .stab 0 (NOLOAD) : { *(.stab) }
+ .stabstr 0 (NOLOAD) : { *(.stabstr) }
+
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+
+ /* DWARF 2.1 */
+ .debug_ranges 0 : { *(.debug_ranges) }
+
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ /* Build attributes */
+ .build_attributes 0 : { *(.ARM.attributes) }
+}
diff --git a/src/dali/commands.hpp b/src/dali/commands.hpp
new file mode 100644
index 0000000..583214d
--- /dev/null
+++ b/src/dali/commands.hpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_COMMANDS_HPP_
+#define DALI_COMMANDS_HPP_
+
+#include
+
+namespace dali {
+
+enum class Command {
+ // Power control commands
+ OFF = 0,
+ UP = 1,
+ DOWN = 2,
+ STEP_UP = 3,
+ STEP_DOWN = 4,
+ RECALL_MAX_LEVEL = 5,
+ RECALL_MIN_LEVEL = 6,
+ STEP_DOWN_AND_OFF = 7,
+ ON_AND_STEP_UP = 8,
+
+ ENABLE_DAPC_SEQUENCE = 9,
+
+ GO_TO_SCENE_0 = 16,
+ GO_TO_SCENE_1 = 17,
+ GO_TO_SCENE_2 = 18,
+ GO_TO_SCENE_3 = 19,
+ GO_TO_SCENE_4 = 20,
+ GO_TO_SCENE_5 = 21,
+ GO_TO_SCENE_6 = 22,
+ GO_TO_SCENE_7 = 23,
+ GO_TO_SCENE_8 = 24,
+ GO_TO_SCENE_9 = 25,
+ GO_TO_SCENE_A = 26,
+ GO_TO_SCENE_B = 27,
+ GO_TO_SCENE_C = 28,
+ GO_TO_SCENE_D = 29,
+ GO_TO_SCENE_E = 30,
+ GO_TO_SCENE_F = 31,
+ RESET = 32,
+ STORE_ACTUAL_LEVEL_IN_DTR = 33,
+ STORE_DTR_AS_MAX_LEVEL = 42,
+ STORE_DTR_AS_MIN_LEVEL = 43,
+ STORE_DTR_AS_SYS_FAIL_LEVEL = 44,
+ STORE_DTR_AS_POWER_ON_LEVEL = 45,
+ STORE_DTR_AS_FADE_TIME = 46,
+ STORE_DTR_AS_FADE_RATE = 47,
+ STORE_DTR_AS_SCENE_0 = 64,
+ STORE_DTR_AS_SCENE_1 = 65,
+ STORE_DTR_AS_SCENE_2 = 66,
+ STORE_DTR_AS_SCENE_3 = 67,
+ STORE_DTR_AS_SCENE_4 = 68,
+ STORE_DTR_AS_SCENE_5 = 69,
+ STORE_DTR_AS_SCENE_6 = 70,
+ STORE_DTR_AS_SCENE_7 = 71,
+ STORE_DTR_AS_SCENE_8 = 72,
+ STORE_DTR_AS_SCENE_9 = 73,
+ STORE_DTR_AS_SCENE_A = 74,
+ STORE_DTR_AS_SCENE_B = 75,
+ STORE_DTR_AS_SCENE_C = 76,
+ STORE_DTR_AS_SCENE_D = 77,
+ STORE_DTR_AS_SCENE_E = 78,
+ STORE_DTR_AS_SCENE_F = 79,
+ REMOVE_FROM_SCENE_0 = 80, // to 95
+ REMOVE_FROM_SCENE_1 = 81,
+ REMOVE_FROM_SCENE_2 = 82,
+ REMOVE_FROM_SCENE_3 = 83,
+ REMOVE_FROM_SCENE_4 = 84,
+ REMOVE_FROM_SCENE_5 = 85,
+ REMOVE_FROM_SCENE_6 = 86,
+ REMOVE_FROM_SCENE_7 = 87,
+ REMOVE_FROM_SCENE_8 = 88,
+ REMOVE_FROM_SCENE_9 = 89,
+ REMOVE_FROM_SCENE_A = 90,
+ REMOVE_FROM_SCENE_B = 91,
+ REMOVE_FROM_SCENE_C = 92,
+ REMOVE_FROM_SCENE_D = 93,
+ REMOVE_FROM_SCENE_E = 94,
+ REMOVE_FROM_SCENE_F = 95,
+ ADD_TO_GROUP_0 = 96,
+ ADD_TO_GROUP_1 = 97,
+ ADD_TO_GROUP_2 = 98,
+ ADD_TO_GROUP_3 = 99,
+ ADD_TO_GROUP_4 = 100,
+ ADD_TO_GROUP_5 = 101,
+ ADD_TO_GROUP_6 = 102,
+ ADD_TO_GROUP_7 = 103,
+ ADD_TO_GROUP_8 = 104,
+ ADD_TO_GROUP_9 = 105,
+ ADD_TO_GROUP_A = 106,
+ ADD_TO_GROUP_B = 107,
+ ADD_TO_GROUP_C = 108,
+ ADD_TO_GROUP_D = 109,
+ ADD_TO_GROUP_E = 110,
+ ADD_TO_GROUP_F = 111,
+ REMOVE_FROM_GROUP_0 = 112,
+ REMOVE_FROM_GROUP_1 = 113,
+ REMOVE_FROM_GROUP_2 = 114,
+ REMOVE_FROM_GROUP_3 = 115,
+ REMOVE_FROM_GROUP_4 = 116,
+ REMOVE_FROM_GROUP_5 = 117,
+ REMOVE_FROM_GROUP_6 = 118,
+ REMOVE_FROM_GROUP_7 = 119,
+ REMOVE_FROM_GROUP_8 = 120,
+ REMOVE_FROM_GROUP_9 = 121,
+ REMOVE_FROM_GROUP_A = 122,
+ REMOVE_FROM_GROUP_B = 123,
+ REMOVE_FROM_GROUP_C = 124,
+ REMOVE_FROM_GROUP_D = 125,
+ REMOVE_FROM_GROUP_E = 126,
+ REMOVE_FROM_GROUP_F = 127,
+ STORE_DTR_AS_SHORT_ADDR = 128,
+ ENABLE_WRITE_MEMORY = 129,
+
+ // Query commands
+ QUERY_STATUS = 144,
+ QUERY_CONTROL_GEAR = 145,
+ QUERY_LAMP_FAILURE = 146,
+ QUERY_LAMP_POWER_ON = 147,
+ QUERY_LIMIT_ERROR = 148,
+ QUERY_RESET_STATE = 149,
+ QUERY_MISSING_SHORT_ADDR = 150,
+ QUERY_VERSION_NUMBER = 151,
+ QUERY_CONTENT_DTR = 152,
+ QUERY_DEVICE_TYPE = 153,
+ QUERY_PHISICAL_MIN_LEVEL = 154,
+ QUERY_POWER_FAILURE = 155,
+ QUERY_CONTENT_DTR1 = 156,
+ QUERY_CONTENT_DTR2 = 157,
+
+ QUERY_ACTUAL_LEVEL = 160,
+ QUERY_MAX_LEVEL = 161,
+ QUERY_MIN_LEVEL = 162,
+ QUERY_POWER_ON_LEVEL = 163,
+ QUERY_SYS_FAILURE_LEVEL = 164,
+ QUERY_FADE_TIME_OR_RATE = 165,
+ QUERY_SCENE_0_LEVEL = 176, // to 191
+ QUERY_SCENE_1_LEVEL = 177,
+ QUERY_SCENE_2_LEVEL = 178,
+ QUERY_SCENE_3_LEVEL = 179,
+ QUERY_SCENE_4_LEVEL = 180,
+ QUERY_SCENE_5_LEVEL = 181,
+ QUERY_SCENE_6_LEVEL = 182,
+ QUERY_SCENE_7_LEVEL = 183,
+ QUERY_SCENE_8_LEVEL = 184,
+ QUERY_SCENE_9_LEVEL = 185,
+ QUERY_SCENE_A_LEVEL = 186,
+ QUERY_SCENE_B_LEVEL = 187,
+ QUERY_SCENE_C_LEVEL = 188,
+ QUERY_SCENE_D_LEVEL = 189,
+ QUERY_SCENE_E_LEVEL = 190,
+ QUERY_SCENE_F_LEVEL = 191,
+ QUERY_GROUPS_L = 192,
+ QUERY_GROUPS_H = 193,
+ QUERY_RANDOM_ADDR_H = 194,
+ QUERY_RANDOM_ADDR_M = 195,
+ QUERY_RANDOM_ADDR_L = 196,
+ READ_MEMORY_LOCATION = 197,
+
+ QUERY_EXTENDED_VERSION_NUMBER = 255,
+
+ // Special commands
+ _SPECIAL_COMMAND = 1024, // not for use
+
+ DIRECT_POWER_CONTROL = _SPECIAL_COMMAND,
+ TERMINATE = _SPECIAL_COMMAND + 161, // 256
+ DATA_TRANSFER_REGISTER = _SPECIAL_COMMAND + 163, // 257
+ INITIALISE = _SPECIAL_COMMAND + 165, // 258
+ RANDOMISE = _SPECIAL_COMMAND + 167, // 259
+ COMPARE = _SPECIAL_COMMAND + 169, // 260
+ WITHDRAW = _SPECIAL_COMMAND + 171, // 261
+ SEARCHADDRH = _SPECIAL_COMMAND + 177, // 264
+ SEARCHADDRM = _SPECIAL_COMMAND + 179, // 265
+ SEARCHADDRL = _SPECIAL_COMMAND + 181, // 266,
+ PROGRAM_SHORT_ADDRESS = _SPECIAL_COMMAND + 183, // 267
+ VERIFY_SHORT_ADDRESS = _SPECIAL_COMMAND + 185, // 268
+ QUERY_SHORT_ADDRESS = _SPECIAL_COMMAND + 187, // 269
+ PHYSICAL_SELECTION = _SPECIAL_COMMAND + 189, // 270
+ ENABLE_DEVICE_TYPE_X = _SPECIAL_COMMAND + 193, // 272
+ DATA_TRANSFER_REGISTER_1 = _SPECIAL_COMMAND + 195, // 273
+ DATA_TRANSFER_REGISTER_2 = _SPECIAL_COMMAND + 197, // 274
+ WRITE_MEMORY_LOCATION = _SPECIAL_COMMAND + 199, // 275
+
+ INVALID = 0xffff,
+};
+
+}
+// namespace dali
+
+#endif // DALI_COMMANDS_HPP_
diff --git a/src/dali/config.hpp b/src/dali/config.hpp
new file mode 100644
index 0000000..d84351e
--- /dev/null
+++ b/src/dali/config.hpp
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_CONFIG_H_
+#define DALI_CONFIG_H_
+
+#define DALI_VERSION 1
+#define DALI_DEVICE_TYPE 8
+
+#define DALI_BANKS 3
+#define DALI_BANK0_ADDR 0 // Bank 0 (16 bytes) according to 62386-102
+#define DALI_BANK1_ADDR 16 // Bank 1 (16 bytes) according to 62386-102
+#define DALI_BANK2_ADDR 32 // Bank 2 (28 bytes) data 62386-102 (26 bytes)
+#define DALI_BANK3_ADDR 60
+
+#define DALI_PHISICAL_MIN_LEVEL 1
+
+#endif // DALI_CONFIG_H_
diff --git a/src/dali/controller/bus.cpp b/src/dali/controller/bus.cpp
new file mode 100644
index 0000000..b2a00c1
--- /dev/null
+++ b/src/dali/controller/bus.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "bus.hpp"
+
+#include
+
+namespace dali {
+namespace controller {
+namespace {
+
+const uint64_t kCommandRepeatTimeout = 100;
+
+}
+
+Bus::Bus(IBus* bus) :
+ mBus(bus),
+ mState(IBus::IBusState::UNKNOWN),
+ mListener(nullptr),
+ mLastCommand(Command::INVALID),
+ mCommandRepeatCount(0),
+ mLastCommandTimeMs(0) {
+ mBus->registerClient(this);
+}
+
+Bus::~Bus() {
+ mBus->unregisterClient(this);
+}
+
+void Bus::setListener(Listener* listener) {
+ mListener = listener;
+}
+
+void Bus::onDataReceived(uint64_t timeMs, uint16_t data) {
+ Command command;
+ uint8_t param;
+ if (filterAddress(data, &command, ¶m) != Status::OK) {
+ return; // Status::INVALID;
+ }
+ if (command != Command::INVALID) { // should be always true
+ if (mLastCommand == Command::INVALID) {
+ mCommandRepeatCount = 0;
+ mLastCommandTimeMs = timeMs;
+ Status status = mListener->handleCommand(mCommandRepeatCount, command, param);
+ if (status == Status::REPEAT_REQUIRED) {
+ mLastCommand = command;
+ return; // Status::OK;
+ } else {
+ mLastCommand = Command::INVALID;
+ return; // status;
+ }
+ } else if (mLastCommand == command) {
+ if (timeMs - mLastCommandTimeMs < kCommandRepeatTimeout) {
+ mCommandRepeatCount++;
+ } else {
+ mLastCommand = Command::INVALID;
+ mCommandRepeatCount = 0;
+ }
+ mLastCommandTimeMs = timeMs;
+ Status status = mListener->handleCommand(mCommandRepeatCount, command, param);
+ if (status == Status::REPEAT_REQUIRED) {
+ mLastCommand = command;
+ return; // Status::OK;
+ } else {
+ mLastCommand = Command::INVALID;
+ return; // status;
+ }
+ } else { // (mLastCommand != Command::INVALID) || (mLastCommand != cmd)
+ mLastCommand = Command::INVALID;
+ mCommandRepeatCount = 0;
+ if (timeMs - mLastCommandTimeMs < kCommandRepeatTimeout) {
+ mLastCommandTimeMs = timeMs;
+ mListener->handleIgnoredCommand(command, param);
+ } else {
+ mLastCommandTimeMs = timeMs;
+ Status status = mListener->handleCommand(mCommandRepeatCount, command, param);
+ if (status == Status::REPEAT_REQUIRED) {
+ mLastCommand = command;
+ return; // Status::OK;
+ } else {
+ return; // status;
+ }
+ }
+ }
+ }
+ return; // Status::INVALID;
+}
+
+void Bus::onBusStateChanged(IBus::IBusState state) {
+ if (mState != state) {
+ mState = state;
+ if (state == IBus::IBusState::DISCONNECTED) {
+ mListener->onBusDisconnected();
+ }
+ }
+}
+
+Status Bus::sendAck(uint8_t ack) {
+ return mBus->sendAck(ack);
+}
+
+Status Bus::filterAddress(uint16_t data, Command* command, uint8_t* param) {
+ *param = (uint8_t) (data & 0xff);
+ *command = Command::INVALID;
+ uint8_t addr = (uint8_t) (data >> 8);
+ bool cmdBitSet = ((addr & 0x01) != 0);
+ if ((addr & 0xfe) == 0xfe) {
+ // Broadcast
+ if (cmdBitSet) {
+ *command = (Command) *param;
+ *param = 0xff;
+ } else {
+ *command = Command::DIRECT_POWER_CONTROL;
+ }
+ } else if ((addr & 0x80) == 0) {
+ // Short address
+ addr >>= 1;
+ uint8_t myAddr = mListener->getShortAddr() >> 1;
+ if (cmdBitSet) {
+ *command = (Command) *param;
+ *param = 0xff;
+ } else {
+ *command = Command::DIRECT_POWER_CONTROL;
+ }
+ if (addr != myAddr) {
+ return Status::INVALID;
+ }
+ } else if ((addr & 0x60) == 0) {
+ // Group address
+ uint8_t group = (addr >> 1) & 0x0f;
+ uint16_t groups = mListener->getGroups();
+ if (cmdBitSet) {
+ *command = (Command) *param;
+ *param = 0xff;
+ } else {
+ *command = Command::DIRECT_POWER_CONTROL;
+ }
+ if ((groups & (1 << group)) == 0) {
+ return Status::INVALID;
+ }
+ } else {
+ *command = (Command) ((uint16_t) Command::_SPECIAL_COMMAND + addr);
+ if (*command == Command::INITIALISE) {
+ uint8_t myAddr = mListener->getShortAddr() >> 1;
+ switch (*param) {
+ case 0x00: // All control gear shall react
+ break;
+ case 0xff: // Control gear without short address shall react
+ if (myAddr <= DALI_ADDR_MAX) {
+ return Status::INVALID;
+ }
+ break;
+ default: // Control gear with the address AAAAAAb shall react
+ if (myAddr != (*param >> 1)) {
+ return Status::INVALID;
+ }
+ break;
+ }
+ }
+ }
+ return Status::OK;
+}
+
+} // namespace controller
+}// namespace dali
diff --git a/src/dali/controller/bus.hpp b/src/dali/controller/bus.hpp
new file mode 100644
index 0000000..0827cf6
--- /dev/null
+++ b/src/dali/controller/bus.hpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_BUS_CONTROLLER_H_
+#define DALI_BUS_CONTROLLER_H_
+
+#include
+
+namespace dali {
+namespace controller {
+
+class Bus: public IBus::IBusClient {
+public:
+
+ class Listener {
+ public:
+ virtual uint8_t getShortAddr() = 0;
+ virtual uint16_t getGroups() = 0;
+ virtual Status handleCommand(uint16_t repeat, Command cmd, uint8_t param) = 0;
+ virtual Status handleIgnoredCommand(Command cmd, uint8_t param) = 0;
+ virtual void onBusDisconnected() = 0;
+ };
+
+ explicit Bus(IBus* bus);
+ virtual ~Bus();
+
+ void setListener(Listener* listener);
+
+ void onDataReceived(uint64_t timeMs, uint16_t data) override;
+ void onBusStateChanged(IBus::IBusState state) override;
+
+ Status sendAck(uint8_t ack);
+ uint64_t getLastCommandTimeMs() {
+ return mLastCommandTimeMs;
+ }
+
+private:
+ Bus(const Bus& other) = delete;
+ Bus& operator=(const Bus&) = delete;
+
+ Status filterAddress(uint16_t data, Command* command, uint8_t* param);
+
+ IBus* const mBus;
+ IBus::IBusState mState;
+ Listener* mListener;
+ Command mLastCommand;
+ uint16_t mCommandRepeatCount;
+ uint64_t mLastCommandTimeMs;
+};
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_BUS_CONTROLLER_H_
diff --git a/src/dali/controller/initialization.cpp b/src/dali/controller/initialization.cpp
new file mode 100644
index 0000000..b721ca6
--- /dev/null
+++ b/src/dali/controller/initialization.cpp
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "initialization.hpp"
+
+#include "bus.hpp"
+#include "memory.hpp"
+
+namespace dali {
+namespace controller {
+
+Initialization::Initialization(ITimer* timer, Memory* memoryController) :
+ mTimer(timer),
+ mMemoryController(memoryController),
+ mInitializeTime(0),
+ mInitialized(false),
+ mWithdraw(false),
+ mSelected(Selection::NONE) {
+}
+
+Status Initialization::initialize(uint8_t param) {
+ checkOperatingTimeout();
+
+ if (!mInitialized) {
+ mInitialized = true;
+ operatingTimeStart();
+ return Status::OK;
+ } else {
+ return Status::INVALID_STATE;
+ }
+}
+
+Status Initialization::randomize() {
+ checkOperatingTimeout();
+
+ uint32_t randomAddr = mTimer->randomize();
+ randomAddr &= 0x00ffffff;
+ mMemoryController->setRandomAddr(randomAddr);
+ return Status::OK;
+}
+
+Status Initialization::compare() {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ switch (mSelected) {
+ case Selection::NONE:
+ case Selection::SELECTED: {
+ if (mWithdraw) {
+ return Status::INVALID;
+ }
+ uint32_t searchAddr = mMemoryController->getSearchAddr();
+ uint32_t randomAddr = mMemoryController->getRandomAddr();
+ if (randomAddr <= searchAddr) {
+ return Status::OK;
+ }
+ return Status::INVALID;
+ }
+
+ default:
+ return Status::INVALID_STATE;
+ }
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::withdraw() {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ switch (mSelected) {
+ case Selection::NONE:
+ case Selection::SELECTED: {
+ uint32_t searchAddr = mMemoryController->getSearchAddr();
+ uint32_t randomAddr = mMemoryController->getRandomAddr();
+ if (searchAddr == randomAddr) {
+ mWithdraw = true;
+ }
+ return Status::OK;
+ }
+
+ default:
+ return Status::INVALID_STATE;
+ }
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::searchAddrH(uint8_t addr) {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ return setSearchAddr(addr, 16);
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::searchAddrM(uint8_t addr) {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ return setSearchAddr(addr, 8);
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::searchAddrL(uint8_t addr) {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ return setSearchAddr(addr, 0);
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::programShortAddr(uint8_t addr) {
+ checkOperatingTimeout();
+
+ if ((addr != DALI_MASK) && ((addr >> 1) > DALI_ADDR_MAX)) {
+ return Status::ERROR;
+ }
+
+ if (mInitialized) {
+ switch (mSelected) {
+ case Selection::NONE:
+ case Selection::SELECTED: {
+ uint32_t searchAddr = mMemoryController->getSearchAddr();
+ uint32_t randomAddr = mMemoryController->getRandomAddr();
+ if (searchAddr == randomAddr) {
+ return mMemoryController->setShortAddr(addr);
+ }
+ return Status::OK;
+ }
+
+ case Selection::PHYSICAL_SELECTED:
+ return mMemoryController->setShortAddr(addr);
+
+ default:
+ return Status::INVALID_STATE;
+ }
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::verifySortAddr(uint8_t addr) {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ uint8_t myAddr = mMemoryController->getShortAddr();
+ if (myAddr == addr) {
+ return Status::OK;
+ }
+ return Status::INVALID;
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::queryShortAddr(uint8_t* addr) {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ switch (mSelected) {
+ case Selection::NONE:
+ case Selection::SELECTED: {
+ uint32_t searchAddr = mMemoryController->getSearchAddr();
+ uint32_t randomAddr = mMemoryController->getRandomAddr();
+ if (searchAddr == randomAddr) {
+ *addr = mMemoryController->getShortAddr();
+ return Status::OK;
+ }
+ return Status::INVALID;
+ }
+
+ case Selection::PHYSICAL_SELECTED: {
+ *addr = mMemoryController->getShortAddr();
+ return Status::OK;
+ }
+
+ default:
+ return Status::INVALID_STATE;
+ }
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::physicalSelection() {
+ checkOperatingTimeout();
+
+ if (mInitialized) {
+ switch (mSelected) {
+ case Selection::NONE:
+ mSelected = Selection::SELECTED;
+ break;
+
+ case Selection::PHYSICAL_SELECTED:
+ mSelected = Selection::SELECTED;
+ break;
+
+ default:
+ mSelected = Selection::NONE;
+ break;
+ }
+ return Status::OK;
+ }
+ return Status::INVALID_STATE;
+}
+
+Status Initialization::terminate() {
+ if (mInitialized) {
+ operatingTimeStop();
+ mInitialized = false;
+ mWithdraw = false;
+ mSelected = Selection::NONE;
+ return Status::OK;
+ }
+ return Status::INVALID_STATE;
+}
+
+void Initialization::reset() {
+ checkOperatingTimeout();
+ // TODO check what should be reset
+ mSelected = Selection::NONE;
+ mWithdraw = false;
+}
+
+void Initialization::onLampStateChnaged(ILamp::ILampState state) {
+ switch (state) {
+ case ILamp::ILampState::DISCONNECTED:
+ if (mSelected == Selection::SELECTED) {
+ mSelected = Selection::PHYSICAL_SELECTED;
+ }
+ break;
+
+ case ILamp::ILampState::OK:
+ if (mSelected == Selection::PHYSICAL_SELECTED) {
+ mSelected = Selection::SELECTED;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+Status Initialization::setSearchAddr(uint8_t addr, uint8_t offset) {
+ uint32_t searchAddr = mMemoryController->getSearchAddr();
+ searchAddr &= ~((uint32_t) 0xff << offset);
+ searchAddr |= (uint32_t) addr << offset;
+ mMemoryController->setSearchAddr(searchAddr);
+ return Status::OK;
+}
+
+void Initialization::operatingTimeStart() {
+ mInitializeTime = mTimer->getTime();
+ mInitializeTime += 1000 * 60 * 60 * 15; // 15min
+}
+
+void Initialization::operatingTimeStop() {
+ mInitializeTime = 0;
+}
+
+void Initialization::checkOperatingTimeout() {
+ if ((mInitializeTime != 0) && (mTimer->getTime() > mInitializeTime)) {
+ terminate();
+ }
+}
+
+} // namespace controller
+} // namespace dali
diff --git a/src/dali/controller/initialization.hpp b/src/dali/controller/initialization.hpp
new file mode 100644
index 0000000..747fa6c
--- /dev/null
+++ b/src/dali/controller/initialization.hpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_CONFIGURATION_CONTROLER_H_
+#define DALI_CONFIGURATION_CONTROLER_H_
+
+#include
+
+namespace dali {
+namespace controller {
+
+class Memory;
+class Bus;
+
+class Initialization {
+public:
+ explicit Initialization(ITimer* timer, Memory* memoryController);
+ virtual ~Initialization() {}
+
+ Status initialize(uint8_t param);
+ Status randomize();
+ Status compare();
+ Status withdraw();
+ Status searchAddrH(uint8_t addr);
+ Status searchAddrM(uint8_t addr);
+ Status searchAddrL(uint8_t addr);
+ Status programShortAddr(uint8_t addr);
+ Status verifySortAddr(uint8_t addr);
+ Status queryShortAddr(uint8_t* addr);
+ Status physicalSelection();
+ Status terminate();
+ void reset();
+
+ void onLampStateChnaged(ILamp::ILampState state);
+
+private:
+ Initialization(const Initialization& other) = delete;
+ Initialization& operator=(const Initialization&) = delete;
+
+ enum class Selection {
+ NONE, SELECTED, PHYSICAL_SELECTED
+ };
+
+ Status setSearchAddr(uint8_t addr, uint8_t offset);
+
+ void operatingTimeStart();
+ void operatingTimeStop();
+ void checkOperatingTimeout();
+
+ ITimer* const mTimer;
+ Memory* const mMemoryController;
+ uint64_t mInitializeTime;
+ bool mInitialized;
+ bool mWithdraw;
+ Selection mSelected;
+};
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_CONFIGURATION_CONTROLER_H_
diff --git a/src/dali/controller/lamp.cpp b/src/dali/controller/lamp.cpp
new file mode 100644
index 0000000..4b5bd3f
--- /dev/null
+++ b/src/dali/controller/lamp.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "lamp.hpp"
+
+#include "lamp_helper.hpp"
+
+#define DAPC_TIME_MS 200
+
+namespace dali {
+namespace controller {
+
+Lamp::Lamp(ILamp* lamp, Memory* memoryController)
+ : mLamp(lamp)
+ , mMemoryController(memoryController)
+ , mLampState(ILamp::ILampState::OK)
+ , mListener(nullptr)
+ , mIsPowerSet(false)
+ , mLimitError(false)
+ , mDapcTime(0)
+ , mConstPower(DALI_MASK) {
+ mLamp->registerClient(this);
+ setLevel(mMemoryController->getPhisicalMinLevel(), 0);
+}
+
+Lamp::~Lamp() {
+ mLamp->unregisterClient(this);
+}
+
+void Lamp::onReset() {
+ setLevel(mMemoryController->getMaxLevel(), 0);
+ mIsPowerSet = true;
+}
+
+bool Lamp::isPowerOn() {
+ return (mLamp->getLevel() > 0);
+}
+
+bool Lamp::isFailure() {
+ switch (mLampState) {
+ case ILamp::ILampState::DISCONNECTED:
+ case ILamp::ILampState::OVERHEAT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool Lamp::isFading() {
+ return mLamp->isFading();
+}
+
+bool Lamp::isLimitError() {
+ return mLimitError;
+}
+
+bool Lamp::isPowerSet() {
+ return mIsPowerSet;
+}
+
+uint8_t Lamp::getLevel() {
+ if (mLampState == ILamp::ILampState::OK) {
+ return driver2level(mLamp->getLevel(), mMemoryController->getMinLevel());
+ }
+ return mMemoryController->getActualLevel();
+}
+
+Status Lamp::setLevel(uint8_t level, uint32_t fadeTime) {
+ mLimitError = false;
+
+ Status status = Status::OK;
+ if (level != DALI_MASK) {
+ uint8_t minLevel = mMemoryController->getMinLevel();
+ uint8_t maxLevel = mMemoryController->getMaxLevel();
+
+ if ((level != 0) && (level < minLevel)) {
+ mLimitError = true;
+ level = minLevel;
+ }
+ if (level > maxLevel) {
+ mLimitError = true;
+ level = maxLevel;
+ }
+
+ mLamp->setLevel(level2driver(level), fadeTime);
+ status = mMemoryController->setActualLevel(level);
+ }
+ return status;
+}
+
+uint32_t Lamp::getFadeTime() {
+ return kFadeTime[mMemoryController->getFadeTime()];
+}
+
+uint32_t Lamp::getFadeRate() {
+ return kFadeTime[mMemoryController->getFadeRate()];
+}
+
+Status Lamp::abortFading() {
+ if (mLamp->isFading()) {
+ mLamp->abortFading();
+ uint8_t level = driver2level(mLamp->getLevel(), mMemoryController->getMinLevel());
+ return mMemoryController->setActualLevel(level);
+ }
+ return Status::OK;
+}
+
+void Lamp::setListener(Listener* listener) {
+ mListener = listener;
+}
+
+void Lamp::notifyPowerDown() {
+ mLamp->setLevel(0, 0);
+}
+
+Status Lamp::powerDirect(uint8_t level, uint64_t time) {
+ if (level == DALI_MASK) {
+ mLamp->abortFading();
+ return Status::OK;
+ }
+ if (time - mDapcTime <= DAPC_TIME_MS) {
+ return dapcSequence(level, time);
+ }
+ onPowerCommand();
+ return setLevel(level, getFadeTime());
+}
+
+Status Lamp::powerOff() {
+ onPowerCommand();
+ return setLevel(0, 0);
+}
+
+Status Lamp::powerScene(uint8_t scene) {
+ uint8_t level = mMemoryController->getLevelForScene(scene);
+ if (level == DALI_MASK) {
+ level = mMemoryController->getActualLevel();
+ }
+ onPowerCommand();
+ return setLevel(level, getFadeTime());
+}
+
+Status Lamp::powerUp() {
+ onPowerCommand();
+ uint8_t fade = mMemoryController->getFadeRate();
+ uint8_t steps = kStepsFor200FadeRate[fade];
+ uint8_t level = getLevel();
+ uint8_t maxLevel = mMemoryController->getMaxLevel();
+ if ((int16_t) level + steps > (int16_t) maxLevel) {
+ level = maxLevel;
+ } else {
+ level += steps;
+ }
+ return setLevel(level, kFadeTime[fade]);
+}
+
+Status Lamp::powerDown() {
+ onPowerCommand();
+ uint8_t fade = mMemoryController->getFadeRate();
+ uint8_t steps = kStepsFor200FadeRate[fade];
+ uint8_t level = getLevel();
+ uint8_t minLevel = mMemoryController->getMinLevel();
+ if ((int16_t) level - steps < (int16_t) minLevel) {
+ level = minLevel;
+ } else {
+ level -= steps;
+ }
+ return setLevel(level, kFadeTime[fade]);
+}
+
+Status Lamp::powerStepUp() {
+ onPowerCommand();
+ uint8_t level = getLevel();
+ uint8_t maxLevel = mMemoryController->getMaxLevel();
+ if (level >= maxLevel) {
+ level = maxLevel;
+ } else {
+ level++;
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::powerStepDown() {
+ onPowerCommand();
+ uint8_t level = getLevel();
+ uint8_t minLevel = mMemoryController->getMinLevel();
+ if (level <= minLevel) {
+ level = minLevel;
+ } else {
+ level--;
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::powerOnAndStepUp() {
+ onPowerCommand();
+ uint8_t level = getLevel();
+ if (level == 0) {
+ level = mMemoryController->getMinLevel();
+ } else {
+ uint8_t maxLevel = mMemoryController->getMaxLevel();
+ if (level >= maxLevel) {
+ level = maxLevel;
+ } else {
+ level++;
+ }
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::powerStepDownAndOff() {
+ onPowerCommand();
+ uint8_t level = getLevel();
+ uint8_t minLevel = mMemoryController->getMinLevel();
+ if (level <= minLevel) {
+ level = 0;
+ } else {
+ level--;
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::powerRecallMinLevel() {
+ onPowerCommand();
+ return setLevel(mMemoryController->getMinLevel(), 0);
+}
+
+Status Lamp::powerRecallMaxLevel() {
+ onPowerCommand();
+ return setLevel(mMemoryController->getMaxLevel(), 0);
+}
+
+Status Lamp::powerRecallOnLevel() {
+ if (mIsPowerSet) {
+ return Status::INVALID;
+ }
+ uint8_t level = mMemoryController->getPowerOnLevel();
+ if (level == DALI_MASK) {
+ level = mMemoryController->getActualLevel();
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::powerRecallFaliureLevel() {
+ // TODO change mIsPowerSet if called before power on?
+ uint8_t level = mMemoryController->getFaliureLevel();
+ if (level == DALI_MASK) {
+ level = mMemoryController->getActualLevel();
+ }
+ return setLevel(level, 0);
+}
+
+Status Lamp::enableDapcSequence(uint64_t time) {
+ mDapcTime = time;
+ return Status::OK;
+}
+
+Status Lamp::dapcSequence(uint8_t level, uint64_t time) {
+ onPowerCommand();
+ mDapcTime = time;
+ uint8_t actualLevel = getLevel();
+ if (actualLevel == 0) {
+ // If the actual arc power level is zero, the new level shall be adopted without fading.
+ return setLevel(level, 0);
+ }
+ int16_t deltaLevel = (int32_t) level - actualLevel;
+ if (deltaLevel < 0)
+ deltaLevel = -deltaLevel;
+ if (deltaLevel == 0)
+ return Status::OK;
+ // deltaLevel should change in 200ms
+ int32_t fadeTime = (uint32_t) DALI_LEVEL_MAX * DAPC_TIME_MS / deltaLevel;
+ return setLevel(level, (uint32_t) fadeTime);
+}
+
+void Lamp::onPowerCommand() {
+ mDapcTime = 0;
+ mIsPowerSet = true;
+}
+
+void Lamp::onLampStateChnaged(ILamp::ILampState state) {
+ mLampState = state;
+ mListener->onLampStateChnaged(state);
+}
+
+} // namespace controller
+} // namespace dali
diff --git a/src/dali/controller/lamp.hpp b/src/dali/controller/lamp.hpp
new file mode 100644
index 0000000..acb8986
--- /dev/null
+++ b/src/dali/controller/lamp.hpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_LAMP_CONTROLLER_HPP_
+#define DALI_LAMP_CONTROLLER_HPP_
+
+#include
+
+#include "memory.hpp"
+
+namespace dali {
+namespace controller {
+
+class Lamp: public ILamp::ILampClient {
+public:
+
+ class Listener {
+ public:
+ virtual void onLampStateChnaged(ILamp::ILampState state) = 0;
+ };
+
+ explicit Lamp(ILamp* lamp, Memory* memoryController);
+ virtual ~Lamp();
+
+// >>> used only in controller namespace
+ void onReset();
+ bool isPowerOn();
+ bool isFailure();
+ bool isFading();
+ bool isLimitError();
+ bool isPowerSet();
+
+ uint8_t getLevel();
+ Status setLevel(uint8_t level, uint32_t fadeTime);
+ uint32_t getFadeTime();
+ uint32_t getFadeRate();
+
+ Status abortFading();
+// <<< used only in controller namespace
+
+ void setListener(Listener* listener);
+ void notifyPowerDown();
+
+ Status powerDirect(uint8_t level, uint64_t time);
+ Status powerOff();
+ Status powerScene(uint8_t scene);
+ Status powerUp();
+ Status powerDown();
+ Status powerStepUp();
+ Status powerStepDown();
+ Status powerOnAndStepUp();
+ Status powerStepDownAndOff();
+ Status powerRecallMinLevel();
+ Status powerRecallMaxLevel();
+ Status powerRecallOnLevel();
+ Status powerRecallFaliureLevel();
+ Status enableDapcSequence(uint64_t time);
+
+private:
+ Lamp(const Lamp& other) = delete;
+ Lamp& operator=(const Lamp&) = delete;
+
+ Status dapcSequence(uint8_t level, uint64_t time);
+
+ void onPowerCommand();
+
+ // ILamp::ILampClient
+ void onLampStateChnaged(ILamp::ILampState state) override;
+
+ ILamp* const mLamp;
+ Memory* const mMemoryController;
+ ILamp::ILampState mLampState;
+ Listener* mListener;
+ bool mIsPowerSet;
+ bool mLimitError;
+ uint64_t mDapcTime;
+ uint8_t mConstPower;
+};
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_LAMP_CONTROLLER_HPP_
diff --git a/src/dali/controller/lamp_helper.cpp b/src/dali/controller/lamp_helper.cpp
new file mode 100644
index 0000000..c7e5e3b
--- /dev/null
+++ b/src/dali/controller/lamp_helper.cpp
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "lamp_helper.hpp"
+
+#define DAPC_TIME_MS 200
+
+namespace dali {
+namespace controller {
+namespace {
+
+const uint16_t kLevel2driver[256] = {
+ 0,
+ 66,
+ 67,
+ 69,
+ 71,
+ 73,
+ 75,
+ 77,
+ 79,
+ 82,
+ 84,
+ 86,
+ 88,
+ 91,
+ 93,
+ 96,
+ 99,
+ 101,
+ 104,
+ 107,
+ 110,
+ 113,
+ 116,
+ 119,
+ 123,
+ 126,
+ 130,
+ 133,
+ 137,
+ 141,
+ 145,
+ 149,
+ 153,
+ 157,
+ 161,
+ 166,
+ 170,
+ 175,
+ 180,
+ 185,
+ 190,
+ 195,
+ 201,
+ 206,
+ 212,
+ 218,
+ 224,
+ 230,
+ 236,
+ 243,
+ 250,
+ 257,
+ 264,
+ 271,
+ 279,
+ 286,
+ 294,
+ 302,
+ 311,
+ 319,
+ 328,
+ 337,
+ 347,
+ 356,
+ 366,
+ 376,
+ 387,
+ 397,
+ 408,
+ 420,
+ 431,
+ 443,
+ 455,
+ 468,
+ 481,
+ 494,
+ 508,
+ 522,
+ 536,
+ 551,
+ 567,
+ 582,
+ 598,
+ 615,
+ 632,
+ 649,
+ 667,
+ 686,
+ 705,
+ 724,
+ 744,
+ 765,
+ 786,
+ 808,
+ 830,
+ 853,
+ 877,
+ 901,
+ 926,
+ 952,
+ 978,
+ 1005,
+ 1033,
+ 1062,
+ 1091,
+ 1121,
+ 1152,
+ 1184,
+ 1217,
+ 1251,
+ 1285,
+ 1321,
+ 1357,
+ 1395,
+ 1434,
+ 1473,
+ 1514,
+ 1556,
+ 1599,
+ 1643,
+ 1689,
+ 1735,
+ 1783,
+ 1833,
+ 1884,
+ 1936,
+ 1989,
+ 2044,
+ 2101,
+ 2159,
+ 2219,
+ 2280,
+ 2343,
+ 2408,
+ 2475,
+ 2543,
+ 2614,
+ 2686,
+ 2760,
+ 2837,
+ 2915,
+ 2996,
+ 3079,
+ 3164,
+ 3252,
+ 3342,
+ 3434,
+ 3529,
+ 3627,
+ 3728,
+ 3831,
+ 3937,
+ 4046,
+ 4158,
+ 4273,
+ 4391,
+ 4513,
+ 4637,
+ 4766,
+ 4898,
+ 5033,
+ 5173,
+ 5316,
+ 5463,
+ 5614,
+ 5770,
+ 5929,
+ 6093,
+ 6262,
+ 6435,
+ 6614,
+ 6797,
+ 6985,
+ 7178,
+ 7377,
+ 7581,
+ 7791,
+ 8006,
+ 8228,
+ 8456,
+ 8690,
+ 8930,
+ 9178,
+ 9432,
+ 9693,
+ 9961,
+ 10237,
+ 10520,
+ 10811,
+ 11110,
+ 11418,
+ 11734,
+ 12059,
+ 12393,
+ 12736,
+ 13088,
+ 13450,
+ 13823,
+ 14205,
+ 14598,
+ 15003,
+ 15418,
+ 15845,
+ 16283,
+ 16734,
+ 17197,
+ 17673,
+ 18162,
+ 18665,
+ 19182,
+ 19712,
+ 20258,
+ 20819,
+ 21395,
+ 21987,
+ 22596,
+ 23221,
+ 23864,
+ 24525,
+ 25203,
+ 25901,
+ 26618,
+ 27355,
+ 28112,
+ 28890,
+ 29690,
+ 30512,
+ 31356,
+ 32224,
+ 33116,
+ 34033,
+ 34975,
+ 35943,
+ 36938,
+ 37960,
+ 39011,
+ 40090,
+ 41200,
+ 42341,
+ 43513,
+ 44717,
+ 45955,
+ 47227,
+ 48534,
+ 49877,
+ 51258,
+ 52677,
+ 54135,
+ 55633,
+ 57173,
+ 58756,
+ 60382,
+ 62053,
+ 63771,
+ 65535,
+ 0,
+};
+} // namespace
+
+const uint32_t kFadeTime[16] = { // fade times from 0 to 254 in milliseconds
+ 0, // 0
+ 707, // 1
+ 1000, // 2
+ 1414, // 3
+ 2000, // 4
+ 2828, // 5
+ 4000, // 6
+ 5657, // 7
+ 8000, // 8
+ 11314, // 9
+ 16000, // 10
+ 22627, // 11
+ 32000, // 12
+ 45255, // 13
+ 64000, // 14
+ 90510, // 15
+};
+
+const uint8_t kStepsFor200FadeRate[16] = { 1, 72, 51, 36, 25, 18, 13, 9, 6, 4, 3, 2, 2, 1, 1, 1 };
+
+uint16_t level2driver(uint8_t level) {
+ return kLevel2driver[level];
+}
+
+uint8_t driver2level(uint16_t driverLevel, uint8_t minLevel) {
+ if (driverLevel < kLevel2driver[minLevel]) {
+ return 0;
+ }
+ uint16_t a = minLevel;
+ uint16_t b = DALI_LEVEL_MAX;
+ while (true) {
+ uint16_t m = (a + b) / 2;
+ uint16_t v = kLevel2driver[m];
+ if (driverLevel == v) {
+ return m;
+ } else if (driverLevel < v) {
+ b = m;
+ if (b - a <= 1) {
+ uint16_t av = driverLevel - kLevel2driver[a];
+ uint16_t bv = v - driverLevel;
+ if (av < bv) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+ } else {
+ a = m;
+ if (b - a <= 1) {
+ uint16_t av = driverLevel - v;
+ uint16_t bv = kLevel2driver[b] - driverLevel;
+ if (av < bv) {
+ return a;
+ } else {
+ return b;
+ }
+ }
+ }
+ }
+}
+} // namespace controller
+} // namespace dali
diff --git a/src/dali/controller/lamp_helper.hpp b/src/dali/controller/lamp_helper.hpp
new file mode 100644
index 0000000..2bbbe68
--- /dev/null
+++ b/src/dali/controller/lamp_helper.hpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_LAMP_CONTROLLER_CONSTS_HPP_
+#define DALI_LAMP_CONTROLLER_CONSTS_HPP_
+
+#include
+
+namespace dali {
+namespace controller {
+
+uint16_t level2driver(uint8_t level);
+uint8_t driver2level(uint16_t driverLevel, uint8_t minLevel);
+
+extern const uint32_t kFadeTime[16];
+extern const uint8_t kStepsFor200FadeRate[16];
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_LAMP_CONTROLLER_CONSTS_HPP_
diff --git a/src/dali/controller/memory.cpp b/src/dali/controller/memory.cpp
new file mode 100644
index 0000000..e5e1cba
--- /dev/null
+++ b/src/dali/controller/memory.cpp
@@ -0,0 +1,429 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "memory.hpp"
+
+#include
+
+#define DATA_FIELD_OFFSET(type, field) ((uintptr_t) &(((type *) 0)->field))
+#define TEMP_FIELD_OFFSET(type, field) ((uintptr_t) &(((type *) 0)->field))
+
+#define LONG_ADDR_MASK 0x00ffffff
+
+#define INVALID_BANK_ADDR 0xffffffff
+
+namespace dali {
+namespace controller {
+
+Memory::Memory(IMemory* memory) :
+ mMemory(memory),
+ mData((Data*) memory->data(DALI_BANK2_ADDR, sizeof(Data))),
+ mTemp((Temp*) memory->tempData(0, sizeof(Temp)))
+{
+ resetRam(true);
+
+ for (uint8_t i = 0; i < DALI_BANKS; ++i) {
+ mBankData[i] = mMemory->data(getBankAddr(i), getBankSize(i));
+ if ((uintptr_t) mBankData[i] == INVALID_BANK_ADDR) {
+ mBankData[i] = nullptr;
+ }
+ resetBankIfNeeded(i);
+ }
+
+ if (mData != nullptr) {
+ if (!isDataValid()) {
+ resetData(true);
+ }
+ }
+ if (mTemp != nullptr) {
+ if (!isTempValid()) {
+ resetTemp();
+ }
+ }
+ setSearchAddr(LONG_ADDR_MASK);
+}
+
+Status Memory::readMemory(uint8_t* data) {
+ uint8_t bank = mRam.dtr1;
+ uint8_t addr = mRam.dtr;
+
+ Status status = Status::OK;
+ if (bankRead(bank, addr++, data) != Status::OK) {
+ status = Status::ERROR;
+ }
+ if (bankRead(bank, addr, &mRam.dtr2) != Status::OK) {
+ // ignore status
+ }
+ if (status == Status::OK) {
+ mRam.dtr++;
+ }
+ return status;
+}
+
+Status Memory::writeMemory(uint8_t data) {
+ uint8_t bank = mRam.dtr1;
+ uint8_t addr = mRam.dtr;
+
+ Status status = bankWrite(bank, addr, data, false);
+ if (status == Status::OK) {
+ mRam.dtr++;
+ }
+ return status;
+}
+
+uint8_t Memory::getPhisicalMinLevel() {
+ return mData->phisicalMinLevel;
+}
+
+Status Memory::setPhisicalMinLevel(uint8_t level) {
+ return writeData8(DATA_FIELD_OFFSET(Data, phisicalMinLevel), level);
+}
+
+uint8_t Memory::getShortAddr() {
+ return mData->shortAddr;
+}
+
+Status Memory::setShortAddr(uint8_t addr) {
+ addr |= 0x01; // normalize address
+ return writeData8(DATA_FIELD_OFFSET(Data, shortAddr), addr);
+}
+
+uint8_t Memory::getMinLevel() {
+ return mData->minLevel;
+}
+
+Status Memory::setMinLevel(uint8_t level) {
+ return writeData8(DATA_FIELD_OFFSET(Data, minLevel), level);
+}
+
+uint8_t Memory::getMaxLevel() {
+ return mData->maxLevel;
+}
+
+Status Memory::setMaxLevel(uint8_t level) {
+ return writeData8(DATA_FIELD_OFFSET(Data, maxLevel), level);
+}
+
+uint8_t Memory::getPowerOnLevel() {
+ return mData->powerOnLevel;
+}
+
+Status Memory::setPowerOnLevel(uint8_t level) {
+ return writeData8(DATA_FIELD_OFFSET(Data, powerOnLevel), level);
+}
+
+uint8_t Memory::getFaliureLevel() {
+ return mData->failureLevel;
+}
+
+Status Memory::setFaliureLevel(uint8_t level) {
+ return writeData8(DATA_FIELD_OFFSET(Data, failureLevel), level);
+}
+
+uint8_t Memory::getFadeTime() {
+ return mData->fadeTime;
+}
+
+Status Memory::setFadeTime(uint8_t fadeTime) {
+ return writeData8(DATA_FIELD_OFFSET(Data, fadeTime), fadeTime);
+}
+
+uint8_t Memory::getFadeRate() {
+ return mData->fadeRate;
+}
+
+Status Memory::setFadeRate(uint8_t fadeRate) {
+ return writeData8(DATA_FIELD_OFFSET(Data, fadeRate), fadeRate);
+}
+
+uint8_t Memory::getLevelForScene(uint8_t scene) {
+ if (scene > DALI_SCENE_MAX) {
+ return DALI_MASK;
+ }
+ return mData->scene[scene];
+}
+
+Status Memory::setLevelForScene(uint8_t scene, uint8_t level) {
+ if (scene > DALI_SCENE_MAX) {
+ return Status::ERROR;
+ }
+ return writeData8(DATA_FIELD_OFFSET(Data, scene[scene]), level);
+}
+
+uint16_t Memory::getGroups() {
+ return mData->groups;
+}
+
+uint8_t Memory::getGroupsL() {
+ return mData->groups;
+}
+
+uint8_t Memory::getGroupsH() {
+ return mData->groups >> 8;
+}
+
+Status Memory::setGroups(uint16_t groups) {
+ return writeData16(DATA_FIELD_OFFSET(Data, groups), groups);
+}
+
+
+uint32_t Memory::getSearchAddr() {
+ return mRam.searchAddr;
+}
+
+Status Memory::setSearchAddr(uint32_t searchAddr) {
+ mRam.searchAddr = searchAddr & LONG_ADDR_MASK;
+ return Status::OK;
+}
+
+uint32_t Memory::getRandomAddr() {
+ return mTemp->randomAddr;
+}
+
+Status Memory::setRandomAddr(uint32_t randomAddr) {
+ randomAddr &= LONG_ADDR_MASK;
+ return writeTemp32(TEMP_FIELD_OFFSET(Temp, randomAddr), randomAddr);
+}
+
+uint8_t Memory::getActualLevel() {
+ return mTemp->actualLevel;
+}
+
+Status Memory::setActualLevel(uint8_t level) {
+ return writeTemp8(TEMP_FIELD_OFFSET(Temp, actualLevel), level);
+}
+
+bool Memory::isDataValid() {
+ // check ranges of values
+ if ((mData->phisicalMinLevel == 0) || (mData->phisicalMinLevel == DALI_MASK))
+ return false;
+ if (mData->fadeRate < DALI_FADE_RATE_MIN || mData->fadeRate > DALI_FADE_RATE_MAX)
+ return false;
+ if (mData->fadeTime < DALI_FADE_TIME_MIN || mData->fadeTime > DALI_FADE_TIME_MAX)
+ return false;
+ if (mData->shortAddr != DALI_MASK && (mData->shortAddr >> 1) > DALI_ADDR_MAX)
+ return false;
+ if (mData->minLevel > mData->maxLevel)
+ return false;
+ return true;
+}
+
+bool Memory::isTempValid() {
+ if (mTemp->randomAddr > LONG_ADDR_MASK)
+ return false;
+ return true;
+}
+
+bool Memory::isReset() {
+ if (mData->powerOnLevel != DALI_LEVEL_MAX)
+ return false;
+ if (mData->failureLevel != DALI_LEVEL_MAX)
+ return false;
+ if (mData->minLevel != getPhisicalMinLevel())
+ return false;
+ if (mData->maxLevel != DALI_LEVEL_MAX)
+ return false;
+ if (mData->fadeRate != DALI_FADE_RATE_DEFAULT)
+ return false;
+
+ if (mData->fadeTime != DALI_FADE_TIME_DEFAULT)
+ return false;
+ // skip checking mData->shortAddr
+ if (mData->groups != 0)
+ return false;
+ for (uint16_t i = 0; i <= DALI_SCENE_MAX; i++) {
+ if (mData->scene[i] != DALI_MASK)
+ return false;
+ }
+ if (mTemp->randomAddr != LONG_ADDR_MASK)
+ return false;
+ return true;
+}
+
+Status Memory::reset() {
+ resetRam(false);
+ resetData(false);
+ resetTemp();
+ return Status::OK;
+}
+
+void Memory::resetRam(bool initialize) {
+ if (initialize) {
+ mRam.dtr = DALI_MASK;
+ mRam.dtr1 = DALI_MASK;
+ mRam.dtr2 = DALI_MASK;
+ }
+ mRam.searchAddr = LONG_ADDR_MASK;
+}
+
+void Memory::resetData(bool initialize) {
+ if (initialize) {
+ setPhisicalMinLevel(DALI_PHISICAL_MIN_LEVEL);
+ }
+ setPowerOnLevel(DALI_LEVEL_MAX);
+ setFaliureLevel(DALI_LEVEL_MAX);
+ setMinLevel(getPhisicalMinLevel());
+ setMaxLevel(DALI_LEVEL_MAX);
+ setFadeRate(DALI_FADE_RATE_DEFAULT);
+ setFadeTime(DALI_FADE_TIME_DEFAULT);
+ if (initialize) {
+ setShortAddr(DALI_MASK);
+ }
+ setGroups(0);
+ for (size_t i = 0; i < 16; i++) {
+ setLevelForScene(i, DALI_MASK);
+ }
+}
+
+void Memory::resetTemp() {
+ setRandomAddr(LONG_ADDR_MASK);
+ setActualLevel(DALI_MASK);
+}
+
+Status Memory::internalBankWrite(uint8_t bank, uint8_t addr, uint8_t* data, uint8_t size) {
+ Status status = Status::OK;
+ const uint8_t* bankData = mBankData[bank];
+ uint8_t crc = bankData[1];
+
+ const uintptr_t bankAddr = getBankAddr(bank);
+ const uint16_t endAddr = (uint16_t)addr + size;
+ for (; addr < endAddr; ++addr, ++data) {
+ crc += bankData[addr];
+ crc -= *data;
+
+ if (mMemory->dataWrite(bankAddr + addr, data, 1) != 1) {
+ status = Status::ERROR;
+ }
+ }
+
+ if (mMemory->dataWrite(bankAddr + 1, &crc, 1) != 1) {
+ status = Status::ERROR;
+ }
+
+ return status;
+}
+
+size_t Memory::getBankSize(uint8_t bank) {
+ switch (bank) {
+ case 0:
+ return DALI_BANK1_ADDR - DALI_BANK0_ADDR;
+ case 1:
+ return DALI_BANK2_ADDR - DALI_BANK1_ADDR;
+ case 2:
+ return DALI_BANK3_ADDR - DALI_BANK2_ADDR;
+ default:
+ return 0;
+ }
+}
+
+uintptr_t Memory::getBankAddr(uint8_t bank) {
+ switch (bank) {
+ case 0: // read only
+ return DALI_BANK0_ADDR;
+ case 1:
+ return DALI_BANK1_ADDR;
+ case 2:
+ return DALI_BANK2_ADDR;
+ default:
+ return INVALID_BANK_ADDR;
+ }
+}
+
+Status Memory::bankWrite(uint8_t bank, uint8_t addr, uint8_t data, bool force) {
+ uint8_t size = getBankSize(bank);
+ if (size < 3 && addr > size) {
+ return Status::ERROR;
+ }
+ if (!force && !isBankAddrWritable(bank, addr)) {
+ return Status::INVALID;
+ }
+ return internalBankWrite(bank, addr, &data, sizeof(uint8_t));
+}
+
+Status Memory::bankRead(uint8_t bank, uint8_t addr, uint8_t* data) {
+ uint8_t size = getBankSize(bank);
+ if (addr + 1 > size) {
+ return Status::ERROR;
+ }
+ uintptr_t bankAddr = getBankAddr(bank);
+ if (bankAddr == INVALID_BANK_ADDR) {
+ return Status::ERROR;
+ }
+ const uint8_t* bankData = mMemory->data(bankAddr + addr, 1);
+ if (bankData == nullptr) {
+ return dali::Status::ERROR;
+ }
+ *data = *bankData;
+ return Status::OK;
+}
+
+bool Memory::isBankAddrWritable(uint8_t bank, uint8_t addr) {
+ if (bank == 0) {
+ // read only
+ return false;
+ }
+
+ uintptr_t bankAddr = getBankAddr(bank);
+ if (bankAddr != INVALID_BANK_ADDR) {
+ if (addr < 2) {
+ return false;
+ }
+ if (addr == 2) {
+ return true;
+ }
+ const uint8_t* bankData = mMemory->data(bankAddr + 2, 1);
+ if ((bankData == nullptr) || (*bankData != 0x55)) {
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+void Memory::resetBankIfNeeded(uint8_t bank) {
+ if ((bank >= DALI_BANKS) || (mBankData[bank] == nullptr)) {
+ return;
+ }
+ const size_t bankSize = getBankSize(bank);
+
+ bool reset = false;
+ const uint8_t* bankData = mBankData[bank];
+ if (bankData[0] != (uint8_t) (bankSize - 1)) {
+ reset = true;
+ }
+ if (!reset) {
+ uint8_t checksum = 0;
+ ++bankData;
+ for (uint8_t i = 1; i < bankSize; ++i, ++bankData) {
+ checksum += *bankData;
+ }
+ reset = (checksum != 0);
+ }
+
+ if (reset) {
+ uintptr_t bankAddr = getBankAddr(bank);
+ uint8_t temp = bankSize - 1; // size
+ mMemory->dataWrite(bankAddr, &temp, 1);
+ temp = 0 - (0xff * (bankSize - 2)); // crc
+ mMemory->dataWrite(bankAddr + 1, &temp, 1);
+ temp = 0xff; // reset data
+ for (uint8_t i = 2; i < bankSize; ++i) {
+ mMemory->dataWrite(bankAddr + i, &temp, 1);
+ }
+
+ if (bank == 0) {
+ uint8_t banks = DALI_BANKS - 1;
+ internalBankWrite(0, 0x02, &banks, 1);
+ }
+ }
+}
+
+} // namespace controller
+} // namespace dali
diff --git a/src/dali/controller/memory.hpp b/src/dali/controller/memory.hpp
new file mode 100644
index 0000000..80db93f
--- /dev/null
+++ b/src/dali/controller/memory.hpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_MEMORY_CONTROLLER_HPP_
+#define DALI_MEMORY_CONTROLLER_HPP_
+
+#include
+
+namespace dali {
+namespace controller {
+
+class Memory {
+public:
+ explicit Memory(IMemory* memory);
+ virtual ~Memory() {};
+
+ uint8_t getDTR() {
+ return mRam.dtr;
+ }
+
+ void setDTR(uint8_t value) {
+ mRam.dtr = value;
+ }
+
+ uint8_t getDTR1() {
+ return mRam.dtr1;
+ }
+
+ void setDTR1(uint8_t value) {
+ mRam.dtr1 = value;
+ }
+
+ uint8_t getDTR2() {
+ return mRam.dtr2;
+ }
+
+ void setDTR2(uint8_t value) {
+ mRam.dtr2 = value;
+ }
+
+ Status readMemory(uint8_t* data);
+ Status writeMemory(uint8_t data);
+
+ uint8_t getPhisicalMinLevel();
+ Status setPhisicalMinLevel(uint8_t level);
+
+ uint8_t getShortAddr();
+ Status setShortAddr(uint8_t addr);
+
+ uint8_t getMinLevel();
+ Status setMinLevel(uint8_t level);
+
+ uint8_t getMaxLevel();
+ Status setMaxLevel(uint8_t level);
+
+ uint8_t getPowerOnLevel();
+ Status setPowerOnLevel(uint8_t level);
+
+ uint8_t getFaliureLevel();
+ Status setFaliureLevel(uint8_t level);
+
+ uint8_t getFadeTime();
+ Status setFadeTime(uint8_t fadeTime);
+
+ uint8_t getFadeRate();
+ Status setFadeRate(uint8_t fadeRate);
+
+ uint8_t getLevelForScene(uint8_t scene);
+ Status setLevelForScene(uint8_t scene, uint8_t level);
+
+ uint16_t getGroups();
+ uint8_t getGroupsL();
+ uint8_t getGroupsH();
+ Status setGroups(uint16_t groups);
+
+ uint32_t getSearchAddr();
+ Status setSearchAddr(uint32_t searchAddr);
+
+ uint32_t getRandomAddr();
+ Status setRandomAddr(uint32_t randomAddr);
+
+ uint8_t getActualLevel();
+ Status setActualLevel(uint8_t level);
+
+ bool isValid() {
+ return isDataValid() && isTempValid();
+ }
+
+ bool isReset();
+ Status reset();
+
+ uint16_t uint16FromDtrAndDtr1() {
+ return ((uint16_t) mRam.dtr1 << 8) | mRam.dtr;
+ }
+
+private:
+ Memory(const Memory& other) = delete;
+ Memory& operator=(const Memory&) = delete;
+
+ typedef struct __attribute__((__packed__)) {
+ uint32_t randomAddr;
+ uint8_t actualLevel;
+ uint8_t reversed1;
+ uint8_t reversed2;
+ uint8_t reversed3;
+ } Temp;
+
+ typedef struct __attribute__((__packed__)) {
+ uint8_t size; // BANK mandatory field
+ uint8_t crc; // BANK mandatory field
+ uint8_t phisicalMinLevel;
+ uint8_t powerOnLevel;
+ uint8_t failureLevel;
+ uint8_t minLevel;
+ uint8_t maxLevel;
+ uint8_t fadeRate;
+ uint8_t fadeTime;
+ uint8_t shortAddr;
+ uint16_t groups;
+ uint8_t scene[16];
+ } Data;
+
+ typedef struct {
+ uint8_t dtr;
+ uint8_t dtr1;
+ uint8_t dtr2;
+ uint32_t searchAddr;
+ } Ram;
+
+ Status internalBankWrite(uint8_t bank, uint8_t addr, uint8_t* data, uint8_t size);
+
+ Status writeTemp(uintptr_t addr, uint8_t* data, size_t size) {
+ return mMemory->tempWrite(addr, data, size) == size ? Status::OK : Status::ERROR;
+ }
+
+ Status writeTemp8(uintptr_t addr, uint8_t data) {
+ return mMemory->tempWrite(addr, &data, sizeof(uint8_t)) == sizeof(uint8_t) ? Status::OK : Status::ERROR;
+ }
+
+ Status writeTemp16(uintptr_t addr, uint16_t data) {
+ return mMemory->tempWrite(addr, (uint8_t*) &data, sizeof(uint16_t)) == sizeof(uint16_t) ? Status::OK : Status::ERROR;
+ }
+
+ Status writeTemp32(uintptr_t addr, uint32_t data) {
+ return mMemory->tempWrite(addr, (uint8_t*) &data, sizeof(uint32_t)) == sizeof(uint32_t) ? Status::OK : Status::ERROR;
+ }
+
+ Status writeData8(uintptr_t addr, uint8_t data) {
+ return internalBankWrite(2, addr, &data, sizeof(uint8_t));
+ }
+
+ Status writeData16(uintptr_t addr, uint16_t data) {
+ return internalBankWrite(2, addr, (uint8_t*)&data, sizeof(uint16_t));
+ }
+
+ Status writeData32(uintptr_t addr, uint32_t data) {
+ return internalBankWrite(2, addr, (uint8_t*)&data, sizeof(uint16_t));
+ }
+
+ Status writeData(uintptr_t addr, uint8_t* data, size_t size) {
+ return internalBankWrite(2, addr, data, size);
+ }
+
+ Status bankWrite(uint8_t bank, uint8_t addr, uint8_t data, bool force);
+ Status bankRead(uint8_t bank, uint8_t addr, uint8_t* data);
+
+
+ bool isDataValid();
+ bool isTempValid();
+ void resetRam(bool initialize);
+ void resetData(bool initialize);
+ void resetTemp();
+
+ size_t getBankSize(uint8_t bank);
+ uintptr_t getBankAddr(uint8_t bank);
+ bool isBankAddrWritable(uint8_t bank, uint8_t addr);
+ void resetBankIfNeeded(uint8_t bank);
+
+ IMemory* const mMemory;
+ Ram mRam;
+ const uint8_t* mBankData[DALI_BANKS];
+ const Data* mData;
+ const Temp* mTemp;
+};
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_MEMORY_CONTROLLER_HPP_
diff --git a/src/dali/controller/query_store.cpp b/src/dali/controller/query_store.cpp
new file mode 100644
index 0000000..f5c1552
--- /dev/null
+++ b/src/dali/controller/query_store.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "query_store.hpp"
+
+namespace dali {
+namespace controller {
+
+QueryStore::QueryStore(Memory* memory, Lamp* lamp) :
+ mMemoryController(memory), mLampController(lamp) {
+}
+
+Status QueryStore::reset() {
+ Status status = mMemoryController->reset();
+ mLampController->onReset();
+ return status;
+}
+
+Status QueryStore::storeActualLevelInDtr() {
+ mMemoryController->setDTR(mLampController->getLevel());
+ return Status::OK;
+}
+
+Status QueryStore::storeDtrAsMaxLevel() {
+ uint8_t minLevel = mMemoryController->getMinLevel();
+ uint8_t maxLevel = mMemoryController->getDTR();
+ if (maxLevel < minLevel) {
+ maxLevel = minLevel;
+ }
+ if (maxLevel > DALI_LEVEL_MAX) {
+ maxLevel = DALI_LEVEL_MAX;
+ }
+ Status status = mMemoryController->setMaxLevel(maxLevel);
+
+ uint8_t level = mMemoryController->getActualLevel();
+ if ((level != 0) && (level > maxLevel)) {
+ mLampController->setLevel(maxLevel, 0);
+ }
+ return status;
+}
+
+Status QueryStore::storeDtrAsMinLevel() {
+ uint8_t minLevel = mMemoryController->getDTR();
+ uint8_t maxLevel = mMemoryController->getMaxLevel();
+ if (minLevel > maxLevel) {
+ minLevel = maxLevel;
+ }
+ uint8_t phiscalMinLevel = mMemoryController->getPhisicalMinLevel();
+ if (minLevel < phiscalMinLevel) {
+ minLevel = phiscalMinLevel;
+ }
+ Status status = mMemoryController->setMinLevel(minLevel);
+
+ uint8_t level = mMemoryController->getActualLevel();
+ if ((level != 0) && (level < minLevel)) {
+ mLampController->setLevel(minLevel, 0);
+ }
+ return status;
+}
+
+Status QueryStore::storeDtrAsFailureLevel() {
+ return mMemoryController->setFaliureLevel(mMemoryController->getDTR());
+}
+
+Status QueryStore::storePowerOnLevel() {
+ return mMemoryController->setPowerOnLevel(mMemoryController->getDTR());
+}
+
+Status QueryStore::storeDtrAsFadeTime() {
+ uint8_t fadeTime = mMemoryController->getDTR();
+ if (fadeTime < DALI_FADE_TIME_MIN) {
+ fadeTime = DALI_FADE_TIME_MIN;
+ }
+ if (fadeTime > DALI_FADE_TIME_MAX) {
+ fadeTime = DALI_FADE_TIME_MAX;
+ }
+ return mMemoryController->setFadeTime(fadeTime);
+}
+
+Status QueryStore::storeDtrAsFadeRate() {
+ uint8_t fadeRate = mMemoryController->getDTR();
+ if (fadeRate < DALI_FADE_RATE_MIN) {
+ fadeRate = DALI_FADE_RATE_MIN;
+ }
+ if (fadeRate > DALI_FADE_RATE_MAX) {
+ fadeRate = DALI_FADE_RATE_MAX;
+ }
+ return mMemoryController->setFadeRate(fadeRate);
+}
+
+Status QueryStore::storeDtrAsScene(uint8_t scene) {
+ return mMemoryController->setLevelForScene(scene, mMemoryController->getDTR());
+}
+
+Status QueryStore::removeFromScene(uint8_t scene) {
+ return mMemoryController->setLevelForScene(scene, DALI_MASK);
+}
+
+Status QueryStore::addToGroup(uint8_t group) {
+ if (group > DALI_GROUP_MAX) {
+ return Status::ERROR;
+ }
+ uint16_t groups = mMemoryController->getGroups();
+ groups |= 1 << group;
+ return mMemoryController->setGroups(groups);
+}
+
+Status QueryStore::removeFromGroup(uint8_t group) {
+ if (group > DALI_GROUP_MAX) {
+ return Status::ERROR;
+ }
+ uint16_t groups = mMemoryController->getGroups();
+ groups &= ~(1 << group);
+ return mMemoryController->setGroups(groups);
+}
+
+Status QueryStore::storeDtrAsShortAddr() {
+ uint8_t addr = mMemoryController->getDTR();
+ if ((addr != DALI_MASK) && ((addr >> 1) > DALI_ADDR_MAX)) {
+ return Status::ERROR;
+ }
+ return mMemoryController->setShortAddr(addr);
+}
+
+uint8_t QueryStore::queryStatus() {
+ uint8_t status = 0;
+
+ if (!isMemoryValid()) { // FIXME this should be false but for debug purpose is checked
+ status |= (1 << 0);
+ }
+ if (queryLampFailure()) {
+ status |= (1 << 1);
+ }
+ if (queryLampPowerOn()) {
+ status |= (1 << 2);
+ }
+ if (queryLampLimitError()) {
+ status |= (1 << 3);
+ }
+ if (queryIsFading()) {
+ status |= (1 << 4);
+ }
+ if (queryResetState()) {
+ status |= (1 << 5);
+ }
+ if (queryMissingShortAddr()) {
+ status |= (1 << 6);
+ }
+ if (!queryLampPowerSet()) {
+ status |= (1 << 7);
+ }
+ return status;
+}
+
+bool QueryStore::queryLampFailure() {
+ return mLampController->isFailure();
+}
+
+bool QueryStore::queryLampPowerOn() {
+ return mLampController->isPowerOn();
+}
+
+bool QueryStore::queryLampLimitError() {
+ return mLampController->isLimitError();
+}
+
+bool QueryStore::queryIsFading() {
+ return mLampController->isFading();
+}
+
+bool QueryStore::queryResetState() {
+ return mMemoryController->isReset();
+}
+
+bool QueryStore::queryMissingShortAddr() {
+ return mMemoryController->getShortAddr() == DALI_MASK;
+}
+
+bool QueryStore::queryLampPowerSet() {
+ return mLampController->isPowerSet();
+}
+
+uint8_t QueryStore::queryActualLevel() {
+ return mLampController->getLevel();
+}
+
+uint8_t QueryStore::queryMaxLevel() {
+ return mMemoryController->getMaxLevel();
+}
+
+uint8_t QueryStore::queryMinLevel() {
+ return mMemoryController->getMinLevel();
+}
+
+uint8_t QueryStore::queryPowerOnLevel() {
+ return mMemoryController->getPowerOnLevel();
+}
+
+uint8_t QueryStore::queryFaliureLevel() {
+ return mMemoryController->getFaliureLevel();
+}
+
+uint8_t QueryStore::queryFadeRateOrTime() {
+ uint8_t fadeRate = mMemoryController->getFadeRate();
+ uint8_t fadeTime = mMemoryController->getFadeTime();
+ return (fadeTime << 4) | fadeRate;
+}
+
+uint8_t QueryStore::queryLevelForScene(uint8_t scene) {
+ return mMemoryController->getLevelForScene(scene);
+}
+
+uint8_t QueryStore::queryGroupsL() {
+ return mMemoryController->getGroupsL();
+}
+
+uint8_t QueryStore::queryGroupsH() {
+ return mMemoryController->getGroupsH();
+}
+
+uint8_t QueryStore::queryRandomAddrH() {
+ return (uint8_t) ((mMemoryController->getRandomAddr() >> 16) & 0xff);
+}
+
+uint8_t QueryStore::queryRandomAddrM() {
+ return (uint8_t) ((mMemoryController->getRandomAddr() >> 8) & 0xff);
+}
+
+uint8_t QueryStore::queryRandomAddrL() {
+ return (uint8_t) ((mMemoryController->getRandomAddr() >> 0) & 0xff);
+}
+
+bool QueryStore::isMemoryValid() {
+ return mMemoryController->isValid();
+}
+
+} // namespace controller
+} // namespace dali
diff --git a/src/dali/controller/query_store.hpp b/src/dali/controller/query_store.hpp
new file mode 100644
index 0000000..4c9d680
--- /dev/null
+++ b/src/dali/controller/query_store.hpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_CONTROLLER_QUERY_HPP_
+#define DALI_CONTROLLER_QUERY_HPP_
+
+#include "lamp.hpp"
+#include "memory.hpp"
+
+namespace dali {
+namespace controller {
+
+class QueryStore {
+
+public:
+ explicit QueryStore(Memory* memory, Lamp* lamp);
+ virtual ~QueryStore() {};
+
+ Status reset();
+ Status storeActualLevelInDtr();
+ Status storeDtrAsMaxLevel();
+ Status storeDtrAsMinLevel();
+ Status storeDtrAsFailureLevel();
+ Status storePowerOnLevel();
+ Status storeDtrAsFadeTime();
+ Status storeDtrAsFadeRate();
+ Status storeDtrAsScene(uint8_t scene);
+ Status removeFromScene(uint8_t scene);
+ Status addToGroup(uint8_t group);
+ Status removeFromGroup(uint8_t group);
+ Status storeDtrAsShortAddr();
+ uint8_t queryStatus();
+ bool queryLampFailure();
+ bool queryLampPowerOn();
+ bool queryLampLimitError();
+ bool queryIsFading();
+ bool queryResetState();
+ bool queryMissingShortAddr();
+ bool queryLampPowerSet();
+ uint8_t queryActualLevel();
+ uint8_t queryMaxLevel();
+ uint8_t queryMinLevel();
+ uint8_t queryPowerOnLevel();
+ uint8_t queryFaliureLevel();
+ uint8_t queryFadeRateOrTime();
+ uint8_t queryLevelForScene(uint8_t scene);
+ uint8_t queryGroupsL();
+ uint8_t queryGroupsH();
+ uint8_t queryRandomAddrH();
+ uint8_t queryRandomAddrM();
+ uint8_t queryRandomAddrL();
+
+private:
+ bool isMemoryValid();
+
+ QueryStore(const QueryStore& other) = delete;
+ QueryStore& operator=(const QueryStore&) = delete;
+
+ Memory* const mMemoryController;
+ Lamp* const mLampController;
+};
+
+} // namespace controller
+} // namespace dali
+
+#endif // DALI_CONTROLLER_QUERY_HPP_
diff --git a/src/dali/dali.hpp b/src/dali/dali.hpp
new file mode 100644
index 0000000..240d023
--- /dev/null
+++ b/src/dali/dali.hpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_DALI_HPP_
+#define DALI_DALI_HPP_
+
+#include "config.hpp"
+#include "commands.hpp"
+
+#include
+#include
+#include
+#include
+
+#define DALI_MASK 255
+
+#define DALI_LEVEL_MAX 254
+#define DALI_LEVEL_DEFAULT 254
+
+#define DALI_FADE_TIME_MIN 0
+#define DALI_FADE_TIME_MAX 15
+#define DALI_FADE_TIME_DEFAULT 0
+
+#define DALI_FADE_RATE_MIN 1
+#define DALI_FADE_RATE_MAX 15
+#define DALI_FADE_RATE_DEFAULT 7
+
+#define DALI_SCENE_MAX 15
+#define DALI_GROUP_MAX 15
+#define DALI_ADDR_MAX 63
+#define DALI_ACK_YES DALI_MASK
+
+namespace dali {
+
+enum class Status {
+ OK, ERROR, INVALID, INVALID_STATE, REPEAT_REQUIRED
+};
+
+class IMemory {
+public:
+ class IMemoryClient {
+ public:
+ virtual void onBankReset(uint8_t bank) = 0;
+ };
+
+ virtual size_t dataSize() = 0;
+ virtual size_t dataWrite(uintptr_t addr, const uint8_t* data, size_t size) = 0;
+ virtual const uint8_t* data(uintptr_t addr, size_t size) = 0;
+
+ virtual size_t tempSize() = 0;
+ virtual size_t tempWrite(uintptr_t addr, const uint8_t* data, size_t size) = 0;
+ virtual const uint8_t* tempData(uintptr_t addr, size_t size) = 0;
+};
+
+class ILamp {
+public:
+ enum class ILampState {
+ OK, DISCONNECTED, OVERHEAT
+ };
+
+ class ILampClient {
+ public:
+ virtual void onLampStateChnaged(ILampState state) = 0;
+ };
+
+ virtual Status registerClient(ILampClient* c) = 0;
+ virtual Status unregisterClient(ILampClient* c) = 0;
+ virtual void setLevel(uint16_t level, uint32_t fadeTime) = 0;
+ virtual uint16_t getLevel() = 0;
+ virtual bool isFading() = 0;
+ virtual void abortFading() = 0;
+};
+
+class IBus {
+public:
+ enum class IBusState {
+ UNKNOWN, DISCONNECTED, CONNECTED
+ };
+
+ class IBusClient {
+ public:
+ virtual void onDataReceived(uint64_t timeMs, uint16_t data) = 0;
+ virtual void onBusStateChanged(IBusState state);
+ };
+
+ virtual Status registerClient(IBusClient* c) = 0;
+ virtual Status unregisterClient(IBusClient* c) = 0;
+ virtual Status sendAck(uint8_t ack) = 0;
+};
+
+class ITimer {
+public:
+ class ITimerTask {
+ public:
+ virtual void timerTaskRun() = 0;
+ };
+
+ virtual uint64_t getTime() = 0;
+ virtual Status schedule(ITimerTask* task, uint32_t delay, uint32_t period) = 0;
+ virtual void cancel(ITimerTask* task) = 0;
+ virtual uint32_t randomize() = 0;
+};
+
+} // namespace dali
+
+#endif // DALI_DALI_HPP_
+
diff --git a/src/dali/slave.cpp b/src/dali/slave.cpp
new file mode 100644
index 0000000..655d9ed
--- /dev/null
+++ b/src/dali/slave.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "slave.hpp"
+
+namespace dali {
+
+// static
+Slave* Slave::create(IMemory* memoryDriver, ILamp* lampDriver, IBus* busDriver, ITimer* timer) {
+ controller::Memory* memory = new controller::Memory(memoryDriver);
+ controller::Lamp* lamp = new controller::Lamp(lampDriver, memory);
+ controller::QueryStore* queryStore = new controller::QueryStore(memory, lamp);
+ controller::Bus* bus = new controller::Bus(busDriver);
+ controller::Initialization* initialization = new controller::Initialization(timer, memory);
+
+ return new Slave(memory, lamp, queryStore, bus, initialization);
+}
+
+Slave::Slave(controller::Memory* memory, controller::Lamp* lamp, controller::QueryStore* queryStore,
+ controller::Bus* bus, controller::Initialization* initialization) :
+ mMemoryController(memory), mLampController(lamp), mQueryStoreController(queryStore),
+ mBusController(bus), mInitializationController(initialization),
+ mMemoryWriteEnabled(false), mDeviceType(0xff) {
+ mLampController->setListener(this);
+ mBusController->setListener(this);
+}
+
+Slave::~Slave() {
+ mBusController->setListener(nullptr);
+ mLampController->setListener(nullptr);
+ delete mInitializationController;
+ delete mBusController;
+ delete mQueryStoreController;
+ delete mLampController;
+ delete mMemoryController;
+}
+
+void Slave::notifyPowerUp() {
+ mLampController->powerRecallOnLevel();
+}
+
+void Slave::notifyPowerDown() {
+ mLampController->notifyPowerDown();
+}
+
+void Slave::onLampStateChnaged(ILamp::ILampState state) {
+ mInitializationController->onLampStateChnaged(state);
+}
+
+uint8_t Slave::getShortAddr() {
+ return mMemoryController->getShortAddr();
+}
+
+uint16_t Slave::getGroups() {
+ return mMemoryController->getGroups();
+}
+
+void Slave::onBusDisconnected() {
+ mLampController->powerRecallFaliureLevel();
+}
+
+Status Slave::handleHandleDaliDeviceTypeCommand(uint16_t repeat, Command cmd, uint8_t param, uint8_t device_type) {
+ return Status::INVALID;
+}
+
+Status Slave::handleCommand(uint16_t repeatCount, Command cmd, uint8_t param) {
+ // check memory write
+ switch (cmd) {
+ case Command::ENABLE_WRITE_MEMORY:
+ case Command::WRITE_MEMORY_LOCATION:
+ break;
+
+ case Command::ENABLE_DEVICE_TYPE_X:
+ mDeviceType = param;
+ return Status::OK;
+
+ default:
+ mMemoryWriteEnabled = false;
+ }
+
+ Status status = internalHandleDaliDT8Command(repeatCount, cmd, param);
+ if (status != Status::REPEAT_REQUIRED) {
+ mDeviceType = 0xff;
+ }
+ return status;
+}
+
+Status Slave::handleIgnoredCommand(Command cmd, uint8_t param) {
+ mDeviceType = 0xff;
+ return Status::INVALID;
+}
+
+Status Slave::internalHandleDaliDT8Command(uint16_t repeatCount, Command cmd, uint8_t param) {
+
+ // handle commands
+ switch (cmd) {
+
+ case Command::OFF:
+ return mLampController->powerOff();
+
+ case Command::UP:
+ return mLampController->powerUp();
+
+ case Command::DOWN:
+ return mLampController->powerDown();
+
+ case Command::STEP_UP:
+ return mLampController->powerStepUp();
+
+ case Command::STEP_DOWN:
+ return mLampController->powerStepDown();
+
+ case Command::RECALL_MAX_LEVEL:
+ return mLampController->powerRecallMaxLevel();
+
+ case Command::RECALL_MIN_LEVEL:
+ return mLampController->powerRecallMinLevel();
+
+ case Command::STEP_DOWN_AND_OFF:
+ return mLampController->powerStepDownAndOff();
+
+ case Command::ON_AND_STEP_UP:
+ return mLampController->powerOnAndStepUp();
+
+ case Command::ENABLE_DAPC_SEQUENCE:
+ return mLampController->enableDapcSequence(mBusController->getLastCommandTimeMs());
+
+ case Command::GO_TO_SCENE_0:
+ case Command::GO_TO_SCENE_1:
+ case Command::GO_TO_SCENE_2:
+ case Command::GO_TO_SCENE_3:
+ case Command::GO_TO_SCENE_4:
+ case Command::GO_TO_SCENE_5:
+ case Command::GO_TO_SCENE_6:
+ case Command::GO_TO_SCENE_7:
+ case Command::GO_TO_SCENE_8:
+ case Command::GO_TO_SCENE_9:
+ case Command::GO_TO_SCENE_A:
+ case Command::GO_TO_SCENE_B:
+ case Command::GO_TO_SCENE_C:
+ case Command::GO_TO_SCENE_D:
+ case Command::GO_TO_SCENE_E:
+ case Command::GO_TO_SCENE_F:
+ return mLampController->powerScene(((uint8_t) cmd) & 0x0f);
+
+ case Command::RESET:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ mInitializationController->reset();
+ mQueryStoreController->reset();
+ return Status::OK;
+
+ case Command::STORE_ACTUAL_LEVEL_IN_DTR:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeActualLevelInDtr();
+
+ case Command::STORE_DTR_AS_MAX_LEVEL:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsMaxLevel();
+
+ case Command::STORE_DTR_AS_MIN_LEVEL:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsMinLevel();
+
+ case Command::STORE_DTR_AS_SYS_FAIL_LEVEL:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsFailureLevel();
+
+ case Command::STORE_DTR_AS_POWER_ON_LEVEL:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storePowerOnLevel();
+
+ case Command::STORE_DTR_AS_FADE_TIME:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsFadeTime();
+
+ case Command::STORE_DTR_AS_FADE_RATE:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsFadeRate();
+
+ case Command::STORE_DTR_AS_SCENE_0:
+ case Command::STORE_DTR_AS_SCENE_1:
+ case Command::STORE_DTR_AS_SCENE_2:
+ case Command::STORE_DTR_AS_SCENE_3:
+ case Command::STORE_DTR_AS_SCENE_4:
+ case Command::STORE_DTR_AS_SCENE_5:
+ case Command::STORE_DTR_AS_SCENE_6:
+ case Command::STORE_DTR_AS_SCENE_7:
+ case Command::STORE_DTR_AS_SCENE_8:
+ case Command::STORE_DTR_AS_SCENE_9:
+ case Command::STORE_DTR_AS_SCENE_A:
+ case Command::STORE_DTR_AS_SCENE_B:
+ case Command::STORE_DTR_AS_SCENE_C:
+ case Command::STORE_DTR_AS_SCENE_D:
+ case Command::STORE_DTR_AS_SCENE_E:
+ case Command::STORE_DTR_AS_SCENE_F:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsScene(((uint8_t) cmd) & 0x0f);
+
+ case Command::REMOVE_FROM_SCENE_0:
+ case Command::REMOVE_FROM_SCENE_1:
+ case Command::REMOVE_FROM_SCENE_2:
+ case Command::REMOVE_FROM_SCENE_3:
+ case Command::REMOVE_FROM_SCENE_4:
+ case Command::REMOVE_FROM_SCENE_5:
+ case Command::REMOVE_FROM_SCENE_6:
+ case Command::REMOVE_FROM_SCENE_7:
+ case Command::REMOVE_FROM_SCENE_8:
+ case Command::REMOVE_FROM_SCENE_9:
+ case Command::REMOVE_FROM_SCENE_A:
+ case Command::REMOVE_FROM_SCENE_B:
+ case Command::REMOVE_FROM_SCENE_C:
+ case Command::REMOVE_FROM_SCENE_D:
+ case Command::REMOVE_FROM_SCENE_E:
+ case Command::REMOVE_FROM_SCENE_F:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->removeFromScene(((uint8_t) cmd) & 0x0f);
+
+ case Command::ADD_TO_GROUP_0:
+ case Command::ADD_TO_GROUP_1:
+ case Command::ADD_TO_GROUP_2:
+ case Command::ADD_TO_GROUP_3:
+ case Command::ADD_TO_GROUP_4:
+ case Command::ADD_TO_GROUP_5:
+ case Command::ADD_TO_GROUP_6:
+ case Command::ADD_TO_GROUP_7:
+ case Command::ADD_TO_GROUP_8:
+ case Command::ADD_TO_GROUP_9:
+ case Command::ADD_TO_GROUP_A:
+ case Command::ADD_TO_GROUP_B:
+ case Command::ADD_TO_GROUP_C:
+ case Command::ADD_TO_GROUP_D:
+ case Command::ADD_TO_GROUP_E:
+ case Command::ADD_TO_GROUP_F:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->addToGroup(((uint8_t) cmd) & 0x0f);
+
+ case Command::REMOVE_FROM_GROUP_0:
+ case Command::REMOVE_FROM_GROUP_1:
+ case Command::REMOVE_FROM_GROUP_2:
+ case Command::REMOVE_FROM_GROUP_3:
+ case Command::REMOVE_FROM_GROUP_4:
+ case Command::REMOVE_FROM_GROUP_5:
+ case Command::REMOVE_FROM_GROUP_6:
+ case Command::REMOVE_FROM_GROUP_7:
+ case Command::REMOVE_FROM_GROUP_8:
+ case Command::REMOVE_FROM_GROUP_9:
+ case Command::REMOVE_FROM_GROUP_A:
+ case Command::REMOVE_FROM_GROUP_B:
+ case Command::REMOVE_FROM_GROUP_C:
+ case Command::REMOVE_FROM_GROUP_D:
+ case Command::REMOVE_FROM_GROUP_E:
+ case Command::REMOVE_FROM_GROUP_F:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->removeFromGroup(((uint8_t) cmd) & 0x0f);
+
+ case Command::STORE_DTR_AS_SHORT_ADDR:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mQueryStoreController->storeDtrAsShortAddr();
+
+ case Command::ENABLE_WRITE_MEMORY:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ mMemoryWriteEnabled = true;
+ return Status::OK;
+
+ case Command::QUERY_STATUS:
+ return sendAck(mQueryStoreController->queryStatus());
+
+ case Command::QUERY_CONTROL_GEAR:
+ return sendAck(DALI_ACK_YES);
+
+ case Command::QUERY_LAMP_FAILURE:
+ if (mQueryStoreController->queryLampFailure()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+
+ case Command::QUERY_LAMP_POWER_ON:
+ if (mQueryStoreController->queryLampPowerOn()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+
+ case Command::QUERY_LIMIT_ERROR:
+ if (mQueryStoreController->queryLampLimitError()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+
+ case Command::QUERY_RESET_STATE:
+ if (mQueryStoreController->queryResetState()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+
+ case Command::QUERY_MISSING_SHORT_ADDR: {
+ if (mQueryStoreController->queryMissingShortAddr()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+ }
+
+ case Command::QUERY_VERSION_NUMBER:
+ return sendAck(DALI_VERSION);
+
+ case Command::QUERY_CONTENT_DTR:
+ return sendAck(mMemoryController->getDTR());
+
+ case Command::QUERY_DEVICE_TYPE:
+ return sendAck(DALI_DEVICE_TYPE);
+
+ case Command::QUERY_PHISICAL_MIN_LEVEL:
+ return sendAck(mMemoryController->getPhisicalMinLevel());
+
+ case Command::QUERY_POWER_FAILURE:
+ if (!mQueryStoreController->queryLampPowerSet()) {
+ return sendAck(DALI_ACK_YES);
+ }
+ return Status::OK;
+
+ case Command::QUERY_CONTENT_DTR1:
+ return sendAck(mMemoryController->getDTR1());
+
+ case Command::QUERY_CONTENT_DTR2:
+ return sendAck(mMemoryController->getDTR2());
+
+ case Command::QUERY_ACTUAL_LEVEL:
+ return sendAck(mQueryStoreController->queryActualLevel());
+
+ case Command::QUERY_MAX_LEVEL:
+ return sendAck(mQueryStoreController->queryMaxLevel());
+
+ case Command::QUERY_MIN_LEVEL:
+ return sendAck(mQueryStoreController->queryMinLevel());
+
+ case Command::QUERY_POWER_ON_LEVEL:
+ return sendAck(mQueryStoreController->queryPowerOnLevel());
+
+ case Command::QUERY_SYS_FAILURE_LEVEL:
+ return sendAck(mQueryStoreController->queryFaliureLevel());
+
+ case Command::QUERY_FADE_TIME_OR_RATE:
+ return sendAck(mQueryStoreController->queryFadeRateOrTime());
+
+ case Command::QUERY_SCENE_0_LEVEL:
+ case Command::QUERY_SCENE_1_LEVEL:
+ case Command::QUERY_SCENE_2_LEVEL:
+ case Command::QUERY_SCENE_3_LEVEL:
+ case Command::QUERY_SCENE_4_LEVEL:
+ case Command::QUERY_SCENE_5_LEVEL:
+ case Command::QUERY_SCENE_6_LEVEL:
+ case Command::QUERY_SCENE_7_LEVEL:
+ case Command::QUERY_SCENE_8_LEVEL:
+ case Command::QUERY_SCENE_9_LEVEL:
+ case Command::QUERY_SCENE_A_LEVEL:
+ case Command::QUERY_SCENE_B_LEVEL:
+ case Command::QUERY_SCENE_C_LEVEL:
+ case Command::QUERY_SCENE_D_LEVEL:
+ case Command::QUERY_SCENE_E_LEVEL:
+ case Command::QUERY_SCENE_F_LEVEL:
+ return sendAck(mQueryStoreController->queryLevelForScene(((uint8_t) cmd) & 0xf));
+
+ case Command::QUERY_GROUPS_L:
+ return sendAck(mQueryStoreController->queryGroupsL());
+
+ case Command::QUERY_GROUPS_H:
+ return sendAck(mQueryStoreController->queryGroupsH());
+
+ case Command::QUERY_RANDOM_ADDR_H:
+ return sendAck(mQueryStoreController->queryRandomAddrH());
+
+ case Command::QUERY_RANDOM_ADDR_M:
+ return sendAck(mQueryStoreController->queryRandomAddrM());
+
+ case Command::QUERY_RANDOM_ADDR_L:
+ return sendAck(mQueryStoreController->queryRandomAddrL());
+
+ case Command::READ_MEMORY_LOCATION: {
+ uint8_t data = 0;
+ if (mMemoryController->readMemory(&data) != Status::OK) {
+ return Status::ERROR;
+ }
+ return sendAck(data);
+ }
+
+ // extended commands
+
+ case Command::DIRECT_POWER_CONTROL:
+ return mLampController->powerDirect(param, mBusController->getLastCommandTimeMs());
+
+ case Command::TERMINATE:
+ return mInitializationController->terminate();
+
+ case Command::DATA_TRANSFER_REGISTER:
+ mMemoryController->setDTR(param);
+ return Status::OK;
+
+ case Command::INITIALISE:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mInitializationController->initialize(param);
+
+ case Command::RANDOMISE:
+ if (repeatCount == 0) {
+ return Status::REPEAT_REQUIRED;
+ }
+ return mInitializationController->randomize();
+
+ case Command::COMPARE: {
+ Status status = mInitializationController->compare();
+ if (status == Status::OK) {
+ return mBusController->sendAck(DALI_ACK_YES);
+ }
+ return status;
+ }
+ case Command::WITHDRAW:
+ return mInitializationController->withdraw();
+
+ case Command::SEARCHADDRH:
+ return mInitializationController->searchAddrH(param);
+
+ case Command::SEARCHADDRM:
+ return mInitializationController->searchAddrM(param);
+
+ case Command::SEARCHADDRL:
+ return mInitializationController->searchAddrL(param);
+
+ case Command::PROGRAM_SHORT_ADDRESS:
+ return mInitializationController->programShortAddr(param);
+
+ case Command::VERIFY_SHORT_ADDRESS: {
+ Status status = mInitializationController->verifySortAddr(param);
+ if (status == Status::OK) {
+ return mBusController->sendAck(DALI_ACK_YES);
+ }
+ return status;
+ }
+ case Command::QUERY_SHORT_ADDRESS: {
+ uint8_t shortAddr;
+ Status status = mInitializationController->queryShortAddr(&shortAddr);
+ if (status == Status::OK) {
+ return mBusController->sendAck(shortAddr);
+ }
+ return status;
+ }
+ case Command::PHYSICAL_SELECTION:
+ return mInitializationController->physicalSelection();
+
+ case Command::DATA_TRANSFER_REGISTER_1:
+ mMemoryController->setDTR1(param);
+ return Status::OK;
+
+ case Command::DATA_TRANSFER_REGISTER_2:
+ mMemoryController->setDTR2(param);
+ return Status::OK;
+
+ case Command::WRITE_MEMORY_LOCATION:
+ if (!mMemoryWriteEnabled) {
+ return Status::ERROR;
+ }
+ switch (mMemoryController->writeMemory(param)) {
+ case Status::OK:
+ return sendAck(param);
+ default:
+ return Status::ERROR;
+ }
+
+ default:
+ return handleHandleDaliDeviceTypeCommand(repeatCount, cmd, param, mDeviceType);
+ }
+}
+
+}
+// namespace dali
diff --git a/src/dali/slave.hpp b/src/dali/slave.hpp
new file mode 100644
index 0000000..398049b
--- /dev/null
+++ b/src/dali/slave.hpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef DALI_SLAVE_H_
+#define DALI_SLAVE_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace dali {
+
+class Slave: public controller::Bus::Listener, controller::Lamp::Listener {
+public:
+ static Slave* create(IMemory* memoryDriver, ILamp* lampDriver, IBus* busDriver, ITimer* timer);
+
+ virtual ~Slave();
+
+ void notifyPowerUp();
+ void notifyPowerDown();
+
+private:
+ Slave(const Slave& other) = delete;
+ Slave& operator=(const Slave&) = delete;
+
+ // LampController::Listener
+ void onLampStateChnaged(ILamp::ILampState state) override;
+
+ // BusController::BusController
+ uint8_t getShortAddr() override;
+ uint16_t getGroups() override;
+ void onBusDisconnected() override;
+ Status handleCommand(uint16_t repeat, Command cmd, uint8_t param) override;
+ Status handleIgnoredCommand(Command cmd, uint8_t param) override;
+ Status internalHandleDaliDT8Command(uint16_t repeat, Command cmd, uint8_t param);
+
+ Status sendAck(uint8_t ack) {
+ return mBusController->sendAck(ack);
+ }
+
+ Status handleHandleDaliDeviceTypeCommand(uint16_t repeat, Command cmd, uint8_t param, uint8_t device_type);
+
+ Slave(controller::Memory* memory, controller::Lamp* lamp, controller::QueryStore* queryStore,
+ controller::Bus* busDriver, controller::Initialization* initializationController);
+
+ controller::Memory* const mMemoryController;
+ controller::Lamp* const mLampController;
+ controller::QueryStore* const mQueryStoreController;
+ controller::Bus* const mBusController;
+ controller::Initialization* const mInitializationController;
+ bool mMemoryWriteEnabled;
+ uint8_t mDeviceType;
+};
+
+} // namespace dali
+
+#endif // DALI_SLAVE_H_
diff --git a/src/util/manchester.cpp b/src/util/manchester.cpp
new file mode 100644
index 0000000..798719e
--- /dev/null
+++ b/src/util/manchester.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "manchester.hpp"
+
+uint32_t manchesterEncode16(uint16_t data) {
+ uint32_t result = 0xffffffff;
+ for (uint8_t i = 0; i < 8; ++i) {
+ result <<= 2;
+ if (data & 0x80) {
+ result |= 1;
+ } else {
+ result |= 2;
+ }
+ data <<= 1;
+ }
+ return result;
+}
+
+uint32_t manchesterEncode32(uint16_t data) {
+ uint32_t result = 0xffffffff;
+ for (uint8_t i = 0; i < 16; ++i) {
+ result <<= 2;
+ if (data & 0x8000) {
+ result |= 1;
+ } else {
+ result |= 2;
+ }
+ data <<= 1;
+ }
+ return result;
+}
+
+uint32_t manchesterEncode16Inv(uint16_t data) {
+ uint32_t result = 0xffffffff;
+ for (uint8_t i = 0; i < 8; ++i) {
+ result <<= 2;
+ if (data & 0x01) {
+ result |= 2;
+ } else {
+ result |= 1;
+ }
+ data >>= 1;
+ }
+ return result;
+}
+
+uint32_t manchesterEncode32Inv(uint16_t data) {
+ uint32_t result = 0xffffffff;
+ for (uint8_t i = 0; i < 16; ++i) {
+ result <<= 2;
+ if (data & 0x01) {
+ result |= 2;
+ } else {
+ result |= 1;
+ }
+ data >>= 1;
+ }
+ return result;
+}
+
+uint16_t manchesterDecode32(uint32_t data) {
+ uint16_t result = 0x00000000;
+ for (uint8_t i = 0; i < 16; i++) {
+ uint16_t x = data >> 30;
+ switch (x) {
+ case 1:
+ result <<= 1;
+ result |= 1;
+ data <<= 2;
+ break;
+
+ case 2:
+ result <<= 1;
+ data <<= 2;
+ break;
+
+ default:
+ return 0xffff;
+ }
+ }
+ return result;
+}
+
+uint16_t manchesterDecode16(uint32_t data) {
+ uint16_t result = 0x0000;
+ for (uint8_t i = 0; i < 8; i++) {
+ uint16_t x = (data & 0xffff) >> 14;
+ switch (x) {
+ case 1:
+ result <<= 1;
+ result |= 1;
+ data <<= 2;
+ break;
+
+ case 2:
+ result <<= 1;
+ data <<= 2;
+ break;
+
+ default:
+ return 0xffff;
+ }
+ }
+ return result;
+}
diff --git a/src/util/manchester.hpp b/src/util/manchester.hpp
new file mode 100644
index 0000000..87fb809
--- /dev/null
+++ b/src/util/manchester.hpp
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef UTIL_MANCHESTER_HPP_
+#define UTIL_MANCHESTER_HPP_
+
+#include
+
+uint32_t manchesterEncode16(uint16_t data);
+uint32_t manchesterEncode32(uint16_t data);
+uint32_t manchesterEncode16Inv(uint16_t data);
+uint32_t manchesterEncode32Inv(uint16_t data);
+uint16_t manchesterDecode32(uint32_t data);
+uint16_t manchesterDecode16(uint32_t data);
+
+#endif // UTIL_MANCHESTER_HPP_
diff --git a/src/xmc1200/bccu.cpp b/src/xmc1200/bccu.cpp
new file mode 100644
index 0000000..d4a8d0e
--- /dev/null
+++ b/src/xmc1200/bccu.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "bccu.hpp"
+
+#include "bccu_config.h"
+#include "clock.hpp"
+
+#define LINPRES_MAX 1023
+#define LINPRES_MAGIC 8192
+
+#define DIMMING_MAX 1023
+#define DIMMING_MAGIC_UP 20479
+#define DIMMING_MAGIC_DOWN 20734
+#define DIMMING_MAGIC ((DIMMING_MAGIC_UP + DIMMING_MAGIC_DOWN) / 2)
+
+#define MSEC_PER_SEC 1000
+
+namespace xmc {
+namespace {
+
+BCCU_Type* const BCCU = BCCU0;
+
+BCCU_DE_Type* const BCCU_DEs[] = { BCCU0_DE0, BCCU0_DE1, BCCU0_DE2 };
+
+BCCU_CH_Type* const BCCU_CHs[] = {
+ BCCU0_CH0,
+ BCCU0_CH1,
+ BCCU0_CH2,
+ BCCU0_CH3,
+ BCCU0_CH4,
+ BCCU0_CH5,
+ BCCU0_CH6,
+ BCCU0_CH7,
+ BCCU0_CH8, };
+
+uint16_t calculateDimmingPrescaller(uint32_t timeMs, uint32_t magic) {
+ uint32_t dclk_ps = BCCU->GLOBCLK & BCCU_GLOBCLK_DCLK_PS_Msk;
+ dclk_ps >>= BCCU_GLOBCLK_DCLK_PS_Pos;
+
+ uint32_t prescaler = ((uint32_t) (CPU_CLOCK / MSEC_PER_SEC) * timeMs / dclk_ps + magic / 2) / magic;
+ if (prescaler > DIMMING_MAX) {
+ return 0;
+ }
+ return (uint16_t) prescaler;
+}
+
+uint16_t calculateLinearPrescaller(uint32_t timeMs) {
+ uint32_t fclk_ps = BCCU->GLOBCLK & BCCU_GLOBCLK_FCLK_PS_Msk;
+ fclk_ps >>= BCCU_GLOBCLK_FCLK_PS_Pos;
+
+ uint32_t prescaler = ((uint32_t) (CPU_CLOCK / MSEC_PER_SEC) * timeMs / fclk_ps + LINPRES_MAGIC / 2) / LINPRES_MAGIC;
+ if (prescaler > LINPRES_MAX) {
+ return 0;
+ }
+ return (uint16_t) prescaler;
+}
+
+bool gBccuConfigured = false;
+
+void configureBccuGlobal() {
+ if (gBccuConfigured) {
+ return;
+ }
+
+ XMC_BCCU_GlobalInit(BCCU, &kBCCUGlobalConfig);
+ BCCU->CHTRIG = 0;
+
+#ifdef XMC_BCCU_CH0_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH0_PIN, XMC_BCCU_CH0_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH1_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH1_PIN, XMC_BCCU_CH1_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH2_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH2_PIN, XMC_BCCU_CH2_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH3_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH3_PIN, XMC_BCCU_CH3_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH4_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH4_PIN, XMC_BCCU_CH4_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH5_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH5_PIN, XMC_BCCU_CH5_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH6_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH6_PIN, XMC_BCCU_CH6_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH7_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH7_PIN, XMC_BCCU_CH7_PIN_MODE);
+#endif
+#ifdef XMC_BCCU_CH8_PIN
+ XMC_GPIO_SetMode(XMC_BCCU_CH8_PIN, XMC_BCCU_CH8_PIN_MODE);
+#endif
+
+ gBccuConfigured = true;
+}
+
+void configureBccuDimmingEngine(BCCU_DE_Type* BCCU_DE) {
+ configureBccuGlobal();
+
+ XMC_BCCU_DIM_Init(BCCU_DE, &kBCCUDimmingConfig);
+ XMC_BCCU_DIM_SetTargetDimmingLevel(BCCU_DE, 0);
+}
+
+void configureBccuChannel(BCCU_CH_Type* BCCU_CH, Bccu::DimmingEngine engine,
+ const XMC_BCCU_CH_CONFIG_t* channelConfig) {
+ XMC_BCCU_CH_Init(BCCU_CH, channelConfig);
+ XMC_BCCU_CH_SelectDimEngine(BCCU_CH, (XMC_BCCU_CH_DIMMING_SOURCE_t) engine);
+}
+
+} // namespace
+
+Bccu::Bccu(DimmingEngine de, uint32_t engineMask, uint32_t channelsMask) :
+ BCCU_DE(BCCU_DEs[de]), mEngineMask(engineMask), mChannelsMask(channelsMask), mLastFadeTime(0), mLastChangeTime(0) {
+}
+
+void Bccu::enable() {
+ XMC_BCCU_ConcurrentEnableChannels(BCCU, mChannelsMask);
+ for (uint16_t i = 0; i < 9; ++i) {
+ if (mChannelsMask & (1 << i)) {
+ BCCU_CH_Type* BCCU_CH = BCCU_CHs[i];
+ XMC_BCCU_CH_SetLinearWalkPrescaler(BCCU_CH, 0);
+ XMC_BCCU_CH_SetTargetIntensity(BCCU_CH, 0);
+ }
+ }
+ XMC_BCCU_ConcurrentStartLinearWalk(BCCU, mChannelsMask);
+ XMC_BCCU_ConcurrentEnableDimmingEngine(BCCU, mEngineMask);
+ XMC_BCCU_ConcurrentStartDimming(BCCU, mEngineMask);
+}
+
+void Bccu::disable() {
+ XMC_BCCU_ConcurrentAbortLinearWalk(BCCU, mChannelsMask);
+ XMC_BCCU_ConcurrentDisableChannels(BCCU, mChannelsMask);
+
+ XMC_BCCU_ConcurrentAbortDimming(BCCU, mEngineMask);
+ XMC_BCCU_DIM_SetTargetDimmingLevel(BCCU_DE, 0);
+ XMC_BCCU_ConcurrentStartDimming(BCCU, mEngineMask);
+ while (isFading()) {
+ }
+ XMC_BCCU_ConcurrentDisableDimmingEngine(BCCU, mEngineMask);
+}
+
+void Bccu::setLevel(uint16_t level, uint32_t fadeTime) {
+ // ASSERT(fadeTime < 2^31)
+ if (isFading()) {
+ abortFading();
+ }
+ uint32_t up = getLevel() > level ? 1 : -1;
+ int32_t _fadeTime = up * (int32_t) fadeTime;
+ if (mLastFadeTime != _fadeTime) {
+ mLastFadeTime = _fadeTime;
+ uint32_t prescaler = calculateDimmingPrescaller(fadeTime, up ? DIMMING_MAGIC_UP : DIMMING_MAGIC_DOWN);
+ XMC_BCCU_DIM_SetDimDivider(BCCU_DE, prescaler);
+ }
+ XMC_BCCU_DIM_SetTargetDimmingLevel(BCCU_DE, level);
+ XMC_BCCU_ConcurrentStartDimming(BCCU, mEngineMask);
+}
+
+uint16_t Bccu::getLevel() {
+ return XMC_BCCU_DIM_ReadDimmingLevel(BCCU_DE);
+}
+
+bool Bccu::isFading() {
+ return (BCCU->DESTRCON & mEngineMask) != 0;
+}
+
+void Bccu::abortFading() {
+ XMC_BCCU_ConcurrentAbortDimming(BCCU, mEngineMask);
+}
+
+bool Bccu::isColorChanging() {
+ return (BCCU->CHSTRCON & mChannelsMask) != 0;
+}
+
+void Bccu::abortColorChanging() {
+ XMC_BCCU_ConcurrentAbortLinearWalk(BCCU, mChannelsMask);
+}
+
+BccuLampRGB::BccuLampRGB(DimmingEngine de, Channel r, Channel g, Channel b, const XMC_BCCU_CH_CONFIG_t* channelConfigR,
+ const XMC_BCCU_CH_CONFIG_t* channelConfigG, const XMC_BCCU_CH_CONFIG_t* channelConfigB) :
+ Bccu(de, (1 << de), ((1 << r) | (1 << g) | (1 << b))), BCCU_CH_R(BCCU_CHs[r]), BCCU_CH_G(BCCU_CHs[g]),
+ BCCU_CH_B(BCCU_CHs[b]) {
+ configureBccuDimmingEngine(BCCU_DE);
+ configureBccuChannel(BCCU_CH_R, de, channelConfigR);
+ configureBccuChannel(BCCU_CH_G, de, channelConfigG);
+ configureBccuChannel(BCCU_CH_B, de, channelConfigB);
+}
+
+void BccuLampRGB::setColor(uint16_t r, uint16_t g, uint16_t b, uint32_t changeTime) {
+ if (isColorChanging()) {
+ abortColorChanging();
+ }
+ if (mLastChangeTime != (int32_t) changeTime) {
+ mLastChangeTime = (int32_t) changeTime;
+ uint32_t prescaler = calculateLinearPrescaller(changeTime);
+ XMC_BCCU_CH_SetLinearWalkPrescaler(BCCU_CH_R, prescaler);
+ XMC_BCCU_CH_SetLinearWalkPrescaler(BCCU_CH_G, prescaler);
+ XMC_BCCU_CH_SetLinearWalkPrescaler(BCCU_CH_B, prescaler);
+ }
+
+ XMC_BCCU_CH_SetTargetIntensity(BCCU_CH_R, r);
+ XMC_BCCU_CH_SetTargetIntensity(BCCU_CH_G, g);
+ XMC_BCCU_CH_SetTargetIntensity(BCCU_CH_B, b);
+
+ XMC_BCCU_ConcurrentStartLinearWalk(BCCU, mChannelsMask);
+}
+
+uint16_t BccuLampRGB::getColorR() {
+ return XMC_BCCU_CH_ReadIntensity(BCCU_CH_R);
+}
+
+uint16_t BccuLampRGB::getColorG() {
+ return XMC_BCCU_CH_ReadIntensity(BCCU_CH_G);
+}
+
+uint16_t BccuLampRGB::getColorB() {
+ return XMC_BCCU_CH_ReadIntensity(BCCU_CH_B);
+}
+
+} // namespace xmc
diff --git a/src/xmc1200/bccu.hpp b/src/xmc1200/bccu.hpp
new file mode 100644
index 0000000..7f917e6
--- /dev/null
+++ b/src/xmc1200/bccu.hpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_LAMP_HPP_
+#define XMC_LAMP_HPP_
+
+#include
+
+namespace xmc {
+
+class Bccu {
+public:
+
+ typedef enum {
+ DE0 = 0, // BCCU Dimming Engine 0
+ DE1 = 1, // BCCU Dimming Engine 1
+ DE2 = 2, // BCCU Dimming Engine 2
+ } DimmingEngine;
+
+ typedef enum {
+ CH0 = 0, // BCCU Channel 0
+ CH1 = 1, // BCCU Channel 1
+ CH2 = 2, // BCCU Channel 2
+ CH3 = 3, // BCCU Channel 3
+ CH4 = 4, // BCCU Channel 4
+ CH5 = 5, // BCCU Channel 5
+ CH6 = 6, // BCCU Channel 6
+ CH7 = 7, // BCCU Channel 7
+ CH8 = 8, // BCCU Channel 8
+ } Channel;
+
+ Bccu(DimmingEngine de, uint32_t engineMask, uint32_t channelsMask);
+
+ void enable();
+ void disable();
+
+ void setLevel(uint16_t level, uint32_t fadeTime);
+ uint16_t getLevel();
+
+ bool isFading();
+ void abortFading();
+ bool isColorChanging();
+ void abortColorChanging();
+
+protected:
+ BCCU_DE_Type* const BCCU_DE;
+ const uint32_t mEngineMask;
+ const uint32_t mChannelsMask;
+ int32_t mLastFadeTime; // not unsigned because up/down are different
+ int32_t mLastChangeTime;
+};
+
+
+class BccuLampRGB: public Bccu {
+public:
+ BccuLampRGB(DimmingEngine de, Channel r, Channel g, Channel b, const XMC_BCCU_CH_CONFIG_t* channelConfigR,
+ const XMC_BCCU_CH_CONFIG_t* channelConfigG, const XMC_BCCU_CH_CONFIG_t* channelConfigB);
+
+ ~BccuLampRGB() {
+ disable();
+ }
+
+ void setColor(uint16_t R, uint16_t G, uint16_t B, uint32_t changeTime);
+ uint16_t getColorR();
+ uint16_t getColorG();
+ uint16_t getColorB();
+
+private:
+ BCCU_CH_Type* BCCU_CH_R;
+ BCCU_CH_Type* BCCU_CH_G;
+ BCCU_CH_Type* BCCU_CH_B;
+};
+
+}// namespace xmc
+
+#endif // XMC_LAMP_HPP_
diff --git a/src/xmc1200/bccu_config.c b/src/xmc1200/bccu_config.c
new file mode 100644
index 0000000..afbccd9
--- /dev/null
+++ b/src/xmc1200/bccu_config.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "bccu_config.h"
+
+const XMC_BCCU_GLOBAL_CONFIG_t kBCCUGlobalConfig = {
+ trig_mode: XMC_BCCU_TRIGMODE0,
+ trig_delay: XMC_BCCU_TRIGDELAY_NO_DELAY,
+ maxzero_at_output: 256,
+ fclk_ps: 346,
+ bclk_sel: XMC_BCCU_BCLK_MODE_NORMAL,
+ dclk_ps: 154,
+ global_dimlevel: 0,
+};
+
+const XMC_BCCU_DIM_CONFIG_t kBCCUDimmingConfig = {
+ dim_div: 0,
+ dither_en: 0,
+ cur_sel: XMC_BCCU_DIM_CURVE_FINE,
+};
+
+const XMC_BCCU_CH_CONFIG_t kLampBCCUChannelConfig = {
+ pack_thresh: 3,
+ pack_en: 0,
+ dim_sel: XMC_BCCU_CH_DIMMING_SOURCE_GLOBAL,
+ dim_bypass: XMC_BCCU_CH_DIMMING_ENGINE_BYPASS_DISABLE,
+ gate_en: XMC_BCCU_CH_GATING_FUNC_DISABLE,
+ flick_wd_en: XMC_BCCU_CH_FLICKER_WD_EN,
+ trig_edge: XMC_BCCU_CH_TRIG_EDGE_PASS_TO_ACT,
+ force_trig_en: 0,
+ pack_offcmp_lev: 55,
+ pack_oncmp_lev: 55,
+ pack_offcnt_val: 0,
+ pack_oncnt_val: 0,
+};
diff --git a/src/xmc1200/bccu_config.h b/src/xmc1200/bccu_config.h
new file mode 100644
index 0000000..1079688
--- /dev/null
+++ b/src/xmc1200/bccu_config.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_LAMP_CONFIG_H_
+#define XMC_LAMP_CONFIG_H_
+
+
+#include
+#include
+
+// remove unused pins
+#define XMC_BCCU_CH0_PIN P0_4
+#define XMC_BCCU_CH0_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH1_PIN P0_5
+#define XMC_BCCU_CH1_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH2_PIN P0_6
+#define XMC_BCCU_CH2_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH3_PIN P0_7
+#define XMC_BCCU_CH3_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH4_PIN P0_8
+#define XMC_BCCU_CH4_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH5_PIN P0_9
+#define XMC_BCCU_CH5_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH6_PIN P0_10
+#define XMC_BCCU_CH6_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH7_PIN P0_11
+#define XMC_BCCU_CH7_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT1
+
+#define XMC_BCCU_CH8_PIN P0_1
+#define XMC_BCCU_CH8_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT6
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const XMC_BCCU_GLOBAL_CONFIG_t kBCCUGlobalConfig;
+extern const XMC_BCCU_DIM_CONFIG_t kBCCUDimmingConfig;
+extern const XMC_BCCU_CH_CONFIG_t kLampBCCUChannelConfig;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // XMC_LAMP_CONFIG_H_
diff --git a/src/xmc1200/clock.cpp b/src/xmc1200/clock.cpp
new file mode 100644
index 0000000..5e10070
--- /dev/null
+++ b/src/xmc1200/clock.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "clock.hpp"
+
+#include
+#include
+
+namespace xmc {
+
+void Clock::init(Clock::Frequency freq) {
+ XMC_SCU_CLOCK_CONFIG_t config;
+ config.pclk_src = XMC_SCU_CLOCK_PCLKSRC_MCLK;
+ config.rtc_src = XMC_SCU_CLOCK_RTCCLKSRC_DCO2;
+ config.fdiv = 0;
+ config.idiv = freq;
+ XMC_SCU_CLOCK_Init(&config);
+}
+
+uint32_t Clock::freq(void) {
+ return SystemCoreClock;
+}
+
+} // namespace xmc
diff --git a/src/xmc1200/clock.hpp b/src/xmc1200/clock.hpp
new file mode 100644
index 0000000..51b48a9
--- /dev/null
+++ b/src/xmc1200/clock.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_CLK_HPP_
+#define XMC_CLK_HPP_
+
+#include
+
+namespace xmc {
+
+class Clock {
+public:
+
+ typedef enum {
+ FREQ_32MHZ = 0x01,
+ FREQ_16MHZ = 0x02,
+ FREQ_10_67MHZ = 0x03,
+ FREQ_8MHZ = 0x04,
+ FREQ_126KHZ = 0xFE,
+ FREQ_125_5KHZ = 0xFF,
+ } Frequency;
+
+ // Initializes SCU Clock registers based on user configuration
+ static void init(Frequency freq);
+
+ // Returns current clock frequency
+ static uint32_t freq(void);
+
+};
+// class Clock
+
+}// namespace xmc
+
+#endif // XMC_CLK_HPP_
diff --git a/src/xmc1200/dali/bus.cpp b/src/xmc1200/dali/bus.cpp
new file mode 100644
index 0000000..d51e6fb
--- /dev/null
+++ b/src/xmc1200/dali/bus.cpp
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "bus.hpp"
+
+#include "bus_config.h"
+#include "timer.hpp"
+
+#include
+
+using namespace ::dali;
+
+namespace dali {
+namespace xmc {
+
+namespace {
+
+#define PULSE_GLITCH 500
+
+#define PULSE_TIME (13333)
+#define PULSE_TIME_MIN (8000)
+#define PULSE_TIME_MAX (18000)
+
+#define PULSE_TIME_SHORT_MIN PULSE_TIME_MIN
+#define PULSE_TIME_SHORT_MAX PULSE_TIME_MAX
+#define PULSE_TIME_LONG_MIN (PULSE_TIME_MIN * 2)
+#define PULSE_TIME_LONG_MAX (PULSE_TIME_MAX * 2)
+
+#define INVALID32 0xffffffffL
+#define INVALID16 0xffff
+
+enum class RxState {
+ IDLE, START_LOW, START_HIGHT, DATA_LOW, DATA_HIGHT, HAVE_DATA, ERROR
+};
+
+uint8_t gRxDataBit = 0;
+volatile RxState gRxState;
+volatile uint32_t gRxData32 = INVALID32;
+volatile uint32_t gRxDataTmp;
+uint16_t gTxData = INVALID16;
+volatile uint64_t gBusLowTime = 0;
+
+#define BUS_TIME_CONNECTED 0xffffffffffffffffUL
+
+#define MAX_CLIENTS 1
+
+IBus::IBusState gBusState = IBus::IBusState::UNKNOWN;
+IBus::IBusClient* gClients[MAX_CLIENTS];
+
+void onRisingEdge(uint16_t timer) {
+ gBusLowTime = BUS_TIME_CONNECTED;
+
+ if (timer == 0) {
+ return;
+ }
+
+ if (timer <= PULSE_GLITCH) {
+ return;
+ }
+
+ bool longPulse;
+ if ((timer >= PULSE_TIME_SHORT_MIN) && (timer <= PULSE_TIME_SHORT_MAX)) {
+ longPulse = false;
+ } else if ((timer >= PULSE_TIME_LONG_MIN) && (timer <= PULSE_TIME_LONG_MAX)) {
+ longPulse = true;
+ } else {
+ gRxState = RxState::ERROR;
+ return;
+ }
+
+ switch (gRxState) {
+ case RxState::START_LOW: // 2: check first half of start bit
+ if (longPulse) {
+ gRxState = RxState::ERROR;
+ return;
+ }
+ gRxState = RxState::START_HIGHT;
+ return;
+
+ case RxState::DATA_LOW:
+ gRxState = RxState::DATA_HIGHT;
+ if (longPulse) {
+ gRxDataBit += 2;
+ gRxDataTmp <<= 2;
+ } else {
+ gRxDataBit += 1;
+ gRxDataTmp <<= 1;
+ }
+ return;
+
+ default:
+ return;
+ }
+}
+
+void onFallingEdge(uint16_t timer) {
+ gBusLowTime = Timer::getTimeMs();
+
+ if (timer == 0) {
+ gRxState = RxState::START_LOW;
+ return;
+ }
+
+ if (timer <= PULSE_GLITCH) {
+ return;
+ }
+
+ bool longPulse;
+ if ((timer >= PULSE_TIME_SHORT_MIN) && (timer <= PULSE_TIME_SHORT_MAX)) {
+ longPulse = false;
+ } else if ((timer >= PULSE_TIME_LONG_MIN) && (timer <= PULSE_TIME_LONG_MAX)) {
+ longPulse = true;
+ } else {
+ gRxState = RxState::ERROR;
+ return;
+ }
+
+ switch (gRxState) {
+ case RxState::START_HIGHT:
+ gRxState = RxState::DATA_LOW;
+ if (longPulse) {
+ gRxDataBit = 1;
+ gRxDataTmp = 1;
+ } else {
+ gRxDataBit = 0;
+ gRxDataTmp = 0;
+ }
+ return;
+
+ case RxState::DATA_HIGHT:
+ gRxState = RxState::DATA_LOW;
+ if (longPulse) {
+ gRxDataBit += 2;
+ gRxDataTmp <<= 2;
+ gRxDataTmp |= 3;
+ } else {
+ gRxDataBit += 1;
+ gRxDataTmp <<= 1;
+ gRxDataTmp |= 1;
+ }
+ return;
+
+ default:
+ return;
+ }
+}
+
+void onTimeOut() {
+ if (gRxState == RxState::ERROR) {
+ gRxDataBit = -1; // prevent unexpected data
+ }
+
+ gRxState = RxState::IDLE;
+ gRxData32 = INVALID32;
+
+ switch (gRxDataBit) {
+ case 32:
+ gRxData32 = gRxDataTmp;
+ break;
+
+ case 32 - 1:
+ gRxData32 = gRxDataTmp;
+ gRxData32 <<= 1;
+ gRxData32 |= 1;
+ break;
+ }
+}
+
+} // namespace
+
+//static
+Bus* Bus::getInstance() {
+ static Bus gBus;
+ return &gBus;
+}
+
+Bus::Bus() {
+ Bus::initRx();
+ Bus::initTx();
+}
+
+Bus::~Bus() {
+// TODO clean up
+}
+
+Status Bus::registerClient(IBusClient* c) {
+ for (uint16_t i = 0; i < MAX_CLIENTS; ++i) {
+ if (gClients[i] == nullptr) {
+ gClients[i] = c;
+ c->onBusStateChanged(gBusState);
+ return Status::OK;
+ }
+ }
+ return Status::ERROR;
+}
+
+Status Bus::unregisterClient(IBusClient* c) {
+ for (uint16_t i = 0; i < MAX_CLIENTS; ++i) {
+ if (gClients[i] == c) {
+ gClients[i] = nullptr;
+ return Status::OK;
+ }
+ }
+ return Status::ERROR;
+}
+
+Status Bus::sendAck(uint8_t ack) {
+ Bus::tx(ack);
+ return Status::OK;
+}
+
+void Bus::runSlice() {
+ uint16_t data;
+ uint64_t time = Timer::getTimeMs();
+
+ __disable_irq();
+ uint64_t busLowTime = gBusLowTime;
+ __enable_irq();
+
+ if (busLowTime == BUS_TIME_CONNECTED) {
+ if (gBusState != IBus::IBusState::CONNECTED) {
+ onBusStateChanged(IBus::IBusState::CONNECTED);
+ }
+ } else {
+ if (time - busLowTime >= 500) {
+ if (gBusState != IBus::IBusState::DISCONNECTED) {
+ onBusStateChanged(IBus::IBusState::DISCONNECTED);
+ }
+ }
+ }
+
+ if (Bus::checkRxTx(time, &data)) {
+ onDataReceived(time, data);
+ }
+}
+
+// static
+void Bus::onDataReceived(uint64_t time, uint16_t data) {
+ for (uint8_t i = 0; i < MAX_CLIENTS; ++i) {
+ if (gClients[i] != nullptr) {
+ gClients[i]->onDataReceived(time, data);
+ }
+ }
+}
+
+// static
+void Bus::onBusStateChanged(IBusState state) {
+ gBusState = state;
+
+ for (uint8_t i = 0; i < MAX_CLIENTS; ++i) {
+ if (gClients[i] != nullptr) {
+ gClients[i]->onBusStateChanged(state);
+ }
+ }
+}
+
+//static
+void Bus::initRx() {
+ XMC_GPIO_SetMode(CCU40_RX_PIN, DALI_XMC_CCU40_RX_PIN_MODE);
+
+ XMC_CCU4_Init(CCU40, XMC_CCU4_SLICE_MCMS_ACTION_TRANSFER_PR_CR);
+ XMC_CCU4_StartPrescaler(CCU40);
+ XMC_CCU4_SetModuleClock(CCU40, XMC_CCU4_CLOCK_SCU);
+
+ XMC_CCU4_SLICE_CaptureInit(CCU40_SLICE, &kDaliRxCCU4CaptureConfig);
+
+ XMC_CCU4_SLICE_SetTimerPeriodMatch(CCU40_SLICE, 65535);
+ XMC_CCU4_EnableShadowTransfer(CCU40, CCU40_SLICE_SHADDOW_TRANSFER);
+
+ XMC_CCU4_SLICE_Capture0Config(CCU40_SLICE, XMC_CCU4_SLICE_EVENT_0);
+ XMC_CCU4_SLICE_Capture1Config(CCU40_SLICE, XMC_CCU4_SLICE_EVENT_1);
+ XMC_CCU4_SLICE_ConfigureEvent(CCU40_SLICE, XMC_CCU4_SLICE_EVENT_0, &kDaliRxCCU4CaptureRisingConfig);
+ XMC_CCU4_SLICE_ConfigureEvent(CCU40_SLICE, XMC_CCU4_SLICE_EVENT_1, &kDaliRxCCU4CaptureFallingConfig);
+
+ XMC_CCU4_SLICE_EnableEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_PERIOD_MATCH);
+ XMC_CCU4_SLICE_EnableEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT0);
+ XMC_CCU4_SLICE_EnableEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT1);
+
+ XMC_CCU4_SLICE_SetInterruptNode(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_PERIOD_MATCH, XMC_CCU4_SLICE_SR_ID_1);
+ XMC_CCU4_SLICE_SetInterruptNode(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT0, XMC_CCU4_SLICE_SR_ID_2);
+ XMC_CCU4_SLICE_SetInterruptNode(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT1, XMC_CCU4_SLICE_SR_ID_3);
+
+ NVIC_SetPriority(CCU40_1_IRQn, 2);
+ NVIC_SetPriority(CCU40_2_IRQn, 3);
+ NVIC_SetPriority(CCU40_3_IRQn, 3);
+ NVIC_EnableIRQ(CCU40_1_IRQn);
+ NVIC_EnableIRQ(CCU40_2_IRQn);
+ NVIC_EnableIRQ(CCU40_3_IRQn);
+
+ XMC_CCU4_EnableClock(CCU40, CCU40_SLICE_NUMBER);
+}
+
+//static
+bool Bus::checkRxTx(uint64_t time, uint16_t* data) {
+ static uint64_t gLastDataTime = 0;
+ bool rxResult = false;
+ __disable_irq();
+ uint32_t rxData32 = gRxData32;
+ gRxData32 = INVALID32;
+ __enable_irq();
+ if (rxData32 != INVALID32) {
+ gLastDataTime = time;
+
+ *data = manchesterDecode32(rxData32);
+ rxResult = true;
+ }
+
+ if (gTxData != INVALID16) {
+ uint64_t dTime = time - gLastDataTime;
+ if (dTime > 3) {
+ if (gRxState == RxState::IDLE) {
+ uint16_t tmpTxData = gTxData;
+ gTxData = INVALID16;
+ uint32_t txData = manchesterEncode16Inv(tmpTxData);
+ txData <<= 1;
+ txData |= 0x01;
+ XMC_UART_CH_Transmit(DALI_UART_CH, (uint16_t) (txData & 0xffff));
+ XMC_UART_CH_Transmit(DALI_UART_CH, (uint16_t) (txData >> 16));
+ } else {
+ gTxData = INVALID16;
+ }
+ }
+ }
+ return rxResult;
+}
+
+// static
+void Bus::initTx() {
+ XMC_UART_CH_Init(DALI_UART_CH, &kDaliTxUARTConfig);
+ XMC_USIC_CH_TXFIFO_Configure(DALI_UART_CH, 0, XMC_USIC_CH_FIFO_DISABLED, 0);
+ XMC_UART_CH_Start(DALI_UART_CH);
+ XMC_GPIO_SetMode(DALI_UART_TX_PIN, DALI_UART_TX_PIN_MODE);
+}
+
+// static
+void Bus::tx(uint8_t data) {
+ if (gTxData == INVALID16) {
+ gTxData = data;
+ }
+}
+
+extern "C" {
+
+void CCU40_1_IRQHandler(void) {
+ XMC_CCU4_SLICE_ClearEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_PERIOD_MATCH);
+ onTimeOut();
+}
+
+void CCU40_2_IRQHandler(void) {
+ uint32_t time0 = XMC_CCU4_SLICE_GetCaptureRegisterValue(CCU40_SLICE, 0);
+ uint32_t time1 = XMC_CCU4_SLICE_GetCaptureRegisterValue(CCU40_SLICE, 1);
+ XMC_CCU4_SLICE_ClearEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT0);
+ XMC_CCU4_SLICE_StartTimer(CCU40_SLICE);
+ if (time0 & CCU4_CC4_CV_FFL_Msk) {
+ onRisingEdge(time0 & CCU4_CC4_CV_CAPTV_Msk);
+ } else if (time1 & CCU4_CC4_CV_FFL_Msk) {
+ onRisingEdge(time1 & CCU4_CC4_CV_CAPTV_Msk);
+ }
+}
+
+void CCU40_3_IRQHandler(void) {
+ uint32_t time0 = XMC_CCU4_SLICE_GetCaptureRegisterValue(CCU40_SLICE, 2);
+ uint32_t time1 = XMC_CCU4_SLICE_GetCaptureRegisterValue(CCU40_SLICE, 3);
+ XMC_CCU4_SLICE_ClearEvent(CCU40_SLICE, XMC_CCU4_SLICE_IRQ_ID_EVENT1);
+ XMC_CCU4_SLICE_StartTimer(CCU40_SLICE);
+ if (time0 & CCU4_CC4_CV_FFL_Msk) {
+ onFallingEdge(time0 & CCU4_CC4_CV_CAPTV_Msk);
+ } else if (time1 & CCU4_CC4_CV_FFL_Msk) {
+ onFallingEdge(time1 & CCU4_CC4_CV_CAPTV_Msk);
+ }
+}
+
+} // extern "C"
+
+} // namespace xmc
+} // namespace dali
+
diff --git a/src/xmc1200/dali/bus.hpp b/src/xmc1200/dali/bus.hpp
new file mode 100644
index 0000000..e19a15e
--- /dev/null
+++ b/src/xmc1200/dali/bus.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_BUS_HPP_
+#define XMC_DALI_BUS_HPP_
+
+#include
+
+namespace dali {
+namespace xmc {
+
+class Bus: public dali::IBus {
+public:
+ static Bus* getInstance();
+
+ dali::Status registerClient(IBusClient* c) override;
+ dali::Status unregisterClient(IBusClient* c) override;
+ dali::Status sendAck(uint8_t ack) override;
+
+ static void runSlice();
+
+private:
+ Bus();
+ Bus(const Bus& other) = delete;
+ Bus& operator=(const Bus&) = delete;
+
+ ~Bus();
+
+ static void onDataReceived(uint64_t timeMs, uint16_t data);
+ static void onBusStateChanged(IBusState state);
+
+ static void initRx();
+ static bool checkRxTx(uint64_t time, uint16_t* data);
+
+ static void initTx();
+ static void tx(uint8_t data);
+};
+
+} // namespace xmc
+} // namespace dali
+
+#endif // XMC_DALI_BUS_HPP_
diff --git a/src/xmc1200/dali/bus_config.c b/src/xmc1200/dali/bus_config.c
new file mode 100644
index 0000000..546d6ae
--- /dev/null
+++ b/src/xmc1200/dali/bus_config.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "bus_config.h"
+
+const XMC_UART_CH_CONFIG_t kDaliTxUARTConfig = {
+ baudrate: 2400,
+ data_bits: 0,
+ frame_length: 19,
+ stop_bits: 2,
+ oversampling: 0,
+ parity_mode: XMC_USIC_CH_PARITY_MODE_NONE
+};
+
+const XMC_CCU4_SLICE_EVENT_CONFIG_t kDaliRxCCU4CaptureRisingConfig = {
+ mapped_input: CCU40_SLICE_INPUT,
+ edge: XMC_CCU4_SLICE_EVENT_EDGE_SENSITIVITY_RISING_EDGE,
+ level: XMC_CCU4_SLICE_EVENT_LEVEL_SENSITIVITY_ACTIVE_HIGH,
+ duration: XMC_CCU4_SLICE_EVENT_FILTER_7_CYCLES
+};
+
+const XMC_CCU4_SLICE_EVENT_CONFIG_t kDaliRxCCU4CaptureFallingConfig = {
+ mapped_input: CCU40_SLICE_INPUT,
+ edge: XMC_CCU4_SLICE_EVENT_EDGE_SENSITIVITY_FALLING_EDGE,
+ level: XMC_CCU4_SLICE_EVENT_LEVEL_SENSITIVITY_ACTIVE_HIGH,
+ duration: XMC_CCU4_SLICE_EVENT_FILTER_7_CYCLES
+};
+
+const XMC_CCU4_SLICE_CAPTURE_CONFIG_t kDaliRxCCU4CaptureConfig = {
+ tc: (1 << CCU4_CC4_TC_CMOD_Pos) | (1 << CCU4_CC4_TC_CLST_Pos) | (3 << CCU4_CC4_TC_CAPC_Pos) | (1 << CCU4_CC4_TC_CCS_Pos) | (1 << CCU4_CC4_TC_TSSM_Pos),
+ prescaler_initval: 0,
+ float_limit: 0,
+ timer_concatenation: 0
+};
diff --git a/src/xmc1200/dali/bus_config.h b/src/xmc1200/dali/bus_config.h
new file mode 100644
index 0000000..aa52e82
--- /dev/null
+++ b/src/xmc1200/dali/bus_config.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_BUS_CONFIG_H_
+#define XMC_DALI_BUS_CONFIG_H_
+
+#include
+#include
+#include
+
+// UART configuration - used for DALI TX
+# define DALI_UART_CH XMC_USIC0_CH0
+# define DALI_UART_TX_PIN_MODE XMC_GPIO_MODE_OUTPUT_PUSH_PULL_ALT2
+# define DALI_UART_TX_PIN P1_5
+
+extern const XMC_UART_CH_CONFIG_t kDaliTxUARTConfig;
+
+// CCU4 configuration - used for DALI TX
+# define CCU40_SLICE CCU40_CC42
+# define CCU40_SLICE_NUMBER 2
+# define CCU40_SLICE_INPUT XMC_CCU4_SLICE_INPUT_C
+# define CCU40_SLICE_SHADDOW_TRANSFER XMC_CCU4_SHADOW_TRANSFER_SLICE_2
+# define CCU40_RX_PIN P0_2
+# define DALI_XMC_CCU40_RX_PIN_MODE XMC_GPIO_MODE_INPUT_PULL_DOWN
+
+extern const XMC_CCU4_SLICE_EVENT_CONFIG_t kDaliRxCCU4CaptureRisingConfig;
+extern const XMC_CCU4_SLICE_EVENT_CONFIG_t kDaliRxCCU4CaptureFallingConfig;
+extern const XMC_CCU4_SLICE_CAPTURE_CONFIG_t kDaliRxCCU4CaptureConfig;
+
+#endif // XMC_DALI_BUS_CONFIG_H_
diff --git a/src/xmc1200/dali/lamp.cpp b/src/xmc1200/dali/lamp.cpp
new file mode 100644
index 0000000..9c3e04b
--- /dev/null
+++ b/src/xmc1200/dali/lamp.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "lamp.hpp"
+
+#include
+
+using namespace xmc;
+
+namespace dali {
+namespace xmc {
+
+// LED1
+#define LED1_RED Bccu::CH0
+#define LED1_GREEN Bccu::CH7
+#define LED1_BLUE Bccu::CH8
+
+#define LED1_ENGINE Bccu::DE0
+
+// LED2
+#define LED2_RED Bccu::CH1
+#define LED2_GREEN Bccu::CH2
+#define LED2_BLUE Bccu::CH3
+
+#define LED2_ENGINE Bccu::DE1
+
+// LED3
+#define LED3_RED Bccu::CH4
+#define LED3_GREEN Bccu::CH5
+#define LED3_BLUE Bccu::CH6
+
+#define LED3_ENGINE Bccu::DE2
+
+//static
+#define DRIVER_MAX 4096
+#define DALI_MAX 65536
+
+inline uint16_t dali2driver(uint16_t level) {
+ uint32_t result = ((uint32_t) level * DRIVER_MAX + DALI_MAX / 2) / DALI_MAX;
+ return result < DRIVER_MAX ? result : DRIVER_MAX - 1;
+}
+
+inline uint16_t driver2dali(uint16_t intensivity) {
+ uint32_t result = ((uint32_t) intensivity * DALI_MAX + DRIVER_MAX / 2) / DRIVER_MAX;
+ return result < DALI_MAX ? result : DALI_MAX - 1;
+}
+
+//static
+LampRGB* LampRGB::getInstance() {
+ static LampRGB gDaliLamp1(LED1_ENGINE, LED1_RED, LED1_GREEN, LED1_BLUE, &kLampBCCUChannelConfig);
+ return &gDaliLamp1;
+}
+
+LampRGB::LampRGB(Bccu::DimmingEngine de, Bccu::Channel r, Bccu::Channel g, Bccu::Channel b, const XMC_BCCU_CH_CONFIG_t* channelConfig) :
+ mLamp(de, r, g, b, channelConfig, channelConfig, channelConfig), mLevel(0) {
+ memset(mClients, 0, sizeof(mClients));
+ mLamp.enable();
+ mLamp.setColor(DRIVER_MAX - 1, DRIVER_MAX - 1, DRIVER_MAX - 1, 0);
+}
+
+LampRGB::~LampRGB() {
+ mLamp.disable();
+}
+
+Status LampRGB::registerClient(ILampClient* c) {
+ for (uint16_t i = 0; i < kMaxClients; ++i) {
+ if (mClients[i] == nullptr) {
+ mClients[i] = c;
+ return Status::OK;
+ }
+ }
+ return Status::ERROR;
+}
+
+Status LampRGB::unregisterClient(ILampClient* c) {
+ for (uint16_t i = 0; i < kMaxClients; ++i) {
+ if (mClients[i] == c) {
+ mClients[i] = nullptr;
+ return Status::OK;
+ }
+ }
+ return Status::ERROR;
+}
+
+void LampRGB::setLevel(uint16_t level, uint32_t fadeTime) {
+ mLevel = level;
+ mLamp.setLevel(dali2driver(level), fadeTime);
+}
+
+uint16_t LampRGB::getLevel() {
+ if (mLamp.isFading()) {
+ return driver2dali(mLamp.getLevel());
+ }
+ return mLevel;
+}
+
+bool LampRGB::isFading() {
+ return mLamp.isFading();
+}
+
+void LampRGB::abortFading() {
+ if (mLamp.isFading()) {
+ mLamp.abortFading();
+ mLevel = driver2dali(mLamp.getLevel());
+ }
+}
+
+void LampRGB::waitForFade() {
+ while (mLamp.isFading()) {
+ }
+}
+
+void LampRGB::onLampStateChnaged(ILampState state) {
+ for (uint16_t i = 0; i < kMaxClients; ++i) {
+ if (mClients[i] != nullptr) {
+ mClients[i]->onLampStateChnaged(state);
+ }
+ }
+}
+
+} // namespace xmc
+} // namespace dali
diff --git a/src/xmc1200/dali/lamp.hpp b/src/xmc1200/dali/lamp.hpp
new file mode 100644
index 0000000..bd134c2
--- /dev/null
+++ b/src/xmc1200/dali/lamp.hpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_LAMP_HPP_
+#define XMC_DALI_LAMP_HPP_
+
+#include
+#include
+
+namespace dali {
+namespace xmc {
+
+class LampRGB: public dali::ILamp {
+public:
+
+ static LampRGB* getInstance();
+
+ dali::Status registerClient(ILampClient* c) override;
+ dali::Status unregisterClient(ILampClient* c) override;
+ void setLevel(uint16_t level, uint32_t fadeTime) override;
+ uint16_t getLevel() override;
+ bool isFading() override;
+ void abortFading() override;
+ void waitForFade();
+
+ bool isOff() {
+ return getLevel() == 0;
+ }
+
+private:
+ LampRGB(::xmc::Bccu::DimmingEngine de, ::xmc::Bccu::Channel r, ::xmc::Bccu::Channel g, ::xmc::Bccu::Channel b, const XMC_BCCU_CH_CONFIG_t* channelConfig);
+ LampRGB(const LampRGB&) = delete;
+ LampRGB& operator=(const LampRGB&) = delete;
+
+ ~LampRGB();
+
+ void onLampStateChnaged(ILampState state);
+
+ static const uint8_t kMaxClients = 1;
+
+ ILampClient* mClients[kMaxClients];
+ ::xmc::BccuLampRGB mLamp;
+ uint16_t mLevel;
+};
+
+
+} // namespace xmc
+} // namespace dali
+
+#endif // XMC_DALI_LAMP_HPP_
diff --git a/src/xmc1200/dali/memory.cpp b/src/xmc1200/dali/memory.cpp
new file mode 100644
index 0000000..a7d1678
--- /dev/null
+++ b/src/xmc1200/dali/memory.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "memory.hpp"
+
+#include "memory_config.hpp"
+#include "timer.hpp"
+
+namespace dali {
+namespace xmc {
+namespace {
+
+#define FLASH_MEMORY_OFFSET 4
+#define FLASH_MEMORY_SIZE (XMC_FLASH_BYTES_PER_PAGE - FLASH_MEMORY_OFFSET)
+
+class FlashMemory {
+public:
+ FlashMemory(uint32_t* pageAddrA, uint32_t* pageAddrB, size_t words) :
+ mPageAddrA(pageAddrA), mPageAddrB(pageAddrB), mWords(words + 1), mState(State::UINTIALIZED) {
+ mData = new uint32_t[mWords];
+ }
+
+ ~FlashMemory() {
+ delete mData;
+ }
+
+ size_t write(uintptr_t addr, const uint8_t* data, size_t size) {
+ if (mState == State::UINTIALIZED) {
+ return 0;
+ }
+ FlashMetaData* metaData = (FlashMetaData*) mData;
+ uint8_t* writeData = (uint8_t*) mData + addr + FLASH_MEMORY_OFFSET;
+ bool changed = false;
+ for (size_t i = 0; i < size; ++i, ++writeData, ++data) {
+ if (*writeData != *data) {
+ changed = true;
+ }
+ // update checksum
+ metaData->crc16 += *writeData;
+ metaData->crc16 -= *data;
+ // store data
+ *writeData = *data;
+ }
+ if (changed) {
+ switch (mState) {
+ case State::SYNCHORONIZED_A:
+ case State::DATA_MODIFIED_A:
+ mState = State::DATA_MODIFIED_A;
+ break;
+
+ case State::SYNCHORONIZED_B:
+ case State::DATA_MODIFIED_B:
+ mState = State::DATA_MODIFIED_B;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return size;
+ }
+
+ size_t read(uintptr_t addr, uint8_t* data, size_t size) {
+ uint8_t* readData = (uint8_t*) mData + addr + FLASH_MEMORY_OFFSET;
+ memcpy(data, (uint8_t*) readData, size);
+ return size;
+ }
+
+ const uint8_t* getData(uintptr_t addr) {
+ return (uint8_t*) mData + addr + FLASH_MEMORY_OFFSET;
+ }
+
+ void erase() {
+ erasePage(mPageAddrA);
+ erasePage(mPageAddrB);
+ }
+
+ void synchronize(bool emergency) {
+ switch (mState) {
+ case State::SYNCHORONIZED_A:
+ case State::SYNCHORONIZED_B:
+ // do nothing
+ break;
+
+ case State::DATA_MODIFIED_A: {
+ const FlashMetaData* metaDataB = (FlashMetaData*) mPageAddrB;
+ if (metaDataB->metaData == 0xffffffff) { // fast check erased
+ synchronizePages(mPageAddrB, emergency ? nullptr : mPageAddrA);
+ mState = State::SYNCHORONIZED_B;
+ } else {
+ const FlashMetaData* metaDataA = (FlashMetaData*) mPageAddrA;
+ if (metaDataA->metaData == 0xffffffff) { // fast check erased
+ synchronizePages(mPageAddrA, emergency ? nullptr : mPageAddrB);
+ mState = State::SYNCHORONIZED_A;
+ } else {
+ // retry next time
+ erasePage(mPageAddrB);
+ }
+ }
+ break;
+ }
+ case State::DATA_MODIFIED_B: {
+ const FlashMetaData* metaDataA = (FlashMetaData*) mPageAddrA;
+ if (metaDataA->metaData == 0xffffffff) { // fast check erased
+ synchronizePages(mPageAddrA, emergency ? nullptr : mPageAddrB);
+ mState = State::SYNCHORONIZED_A;
+ } else {
+ const FlashMetaData* metaDataB = (FlashMetaData*) mPageAddrB;
+ if (metaDataB->metaData == 0xffffffff) { // fast check erased
+ synchronizePages(mPageAddrB, emergency ? nullptr : mPageAddrA);
+ mState = State::SYNCHORONIZED_B;
+ } else {
+ // retry next time
+ erasePage(mPageAddrA);
+ }
+ }
+ break;
+ }
+ case State::UINTIALIZED:
+ default: {
+ initialize();
+ break;
+ }
+ } // switch (mState)
+ }
+
+private:
+
+ enum class ReadState {
+ INVALID, ERASED, OK
+ };
+
+ enum class State {
+ UINTIALIZED, SYNCHORONIZED_A, SYNCHORONIZED_B, DATA_MODIFIED_A, DATA_MODIFIED_B,
+ };
+
+ typedef union {
+ struct {
+ uint32_t crc16 :16;
+ uint32_t index :16;
+ };
+ uint32_t metaData;
+ } FlashMetaData;
+
+ void writePage(uint32_t* flash) {
+ const size_t blocks = mWords / (XMC_FLASH_WORDS_PER_PAGE / XMC_FLASH_BLOCKS_PER_PAGE);
+ uint32_t* data = mData;
+ FlashMetaData* metaDataA = (FlashMetaData*) data;
+ metaDataA->index--;
+ for (uint16_t j = 0; j < blocks; j++) {
+ __disable_irq();
+
+ NVM->NVMPROG &= (uint16_t) (~(uint16_t) NVM_NVMPROG_ACTION_Msk);
+ NVM->NVMPROG |= (uint16_t) (NVM_NVMPROG_RSTVERR_Msk | NVM_NVMPROG_RSTECC_Msk);
+ NVM->NVMPROG |= (uint16_t) ((uint32_t) 0xa1 << NVM_NVMPROG_ACTION_Pos);
+
+ for (uint16_t i = 0; i < XMC_FLASH_WORDS_PER_BLOCK; ++i, ++data, ++flash) {
+ *flash = *data;
+ }
+
+ while (XMC_FLASH_IsBusy() == true) {
+ }
+
+ NVM->NVMPROG &= (uint16_t) (~(uint16_t) NVM_NVMPROG_ACTION_Msk);
+
+ __enable_irq();
+ }
+ }
+
+ bool verifyPage(uint32_t* flash) {
+ uint32_t* data = mData;
+ for (uint16_t i = 0; i < mWords; ++i, ++data, ++flash) {
+ if (*flash != *data) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ ReadState readPage(uint32_t* flash, uint32_t* data) {
+ const FlashMetaData* metaData = (FlashMetaData*) flash;
+ uint16_t crc16 = metaData->crc16;
+ *data++ = *flash++;
+ ReadState state = ReadState::ERASED;
+ for (uint16_t i = 1; i < mWords; ++i, ++data, ++flash) {
+ uint32_t word = *flash;
+ crc16 += (word >> 24) & 0xff;
+ crc16 += (word >> 16) & 0xff;
+ crc16 += (word >> 8) & 0xff;
+ crc16 += (word >> 0) & 0xff;
+ if (word != 0xffffffff) {
+ state = ReadState::INVALID;
+ }
+ *data = word;
+ }
+ if (crc16 == 0) {
+ state = ReadState::OK;
+ }
+ return state;
+ }
+
+ void erasePage(uint32_t* flash) {
+ __disable_irq();
+ XMC_FLASH_ErasePage(flash);
+ __enable_irq();
+ }
+
+ void initialize() {
+ uint32_t dataB[mWords];
+
+ ReadState readStateA = readPage(mPageAddrA, mData);
+ ReadState readStateB = readPage(mPageAddrB, dataB);
+
+ switch (readStateA) {
+ case ReadState::ERASED: {
+
+ switch (readStateB) {
+ case ReadState::ERASED:
+ mData[0] = (0 - (0xff * (mWords - 1) * sizeof(uint32_t))) | 0xffff0000;
+ mState = State::SYNCHORONIZED_A;
+ break;
+
+ case ReadState::INVALID:
+ erasePage(mPageAddrB);
+ mData[0] = (0 - (0xff * (mWords - 1) * sizeof(uint32_t))) | 0xffff0000;
+ mState = State::SYNCHORONIZED_B;
+ break;
+
+ case ReadState::OK:
+ memcpy(mData, dataB, mWords * sizeof(uint32_t));
+ mData[0] |= 0xffff0000;
+ mState = State::SYNCHORONIZED_B;
+ break;
+ }
+
+ break;
+ }
+
+ case ReadState::OK: {
+
+ switch (readStateB) {
+ case ReadState::ERASED:
+ mData[0] |= 0xffff0000;
+ mState = State::SYNCHORONIZED_A;
+ break;
+
+ case ReadState::INVALID:
+ erasePage(mPageAddrB);
+ mData[0] |= 0xffff0000;
+ mState = State::SYNCHORONIZED_A;
+ break;
+
+ case ReadState::OK: {
+ FlashMetaData* metaDataA = (FlashMetaData*) mData;
+ FlashMetaData* metaDataB = (FlashMetaData*) dataB;
+ if (metaDataA->index < metaDataB->index) {
+ erasePage(mPageAddrB);
+ mState = State::SYNCHORONIZED_A;
+ } else {
+ erasePage(mPageAddrA);
+ memcpy(mData, dataB, mWords * sizeof(uint32_t));
+ mState = State::SYNCHORONIZED_B;
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ case ReadState::INVALID: {
+ erasePage(mPageAddrA);
+
+ switch (readStateB) {
+ case ReadState::ERASED:
+ mData[0] = (0 - (0xff * (mWords - 1) * sizeof(uint32_t))) | 0xffff0000;
+ memset(&mData[1], 0xff, mWords * sizeof(uint32_t));
+ mState = State::SYNCHORONIZED_A;
+ break;
+
+ case ReadState::INVALID:
+ erasePage(mPageAddrB);
+
+ mData[0] = (0 - (0xff * (mWords - 1) * sizeof(uint32_t))) | 0xffff0000;
+ memset(&mData[1], 0xff, mWords * sizeof(uint32_t));
+ mState = State::SYNCHORONIZED_A;
+ break;
+
+ case ReadState::OK:
+ memcpy(mData, dataB, mWords * sizeof(uint32_t));
+ mData[0] |= 0xffff0000;
+ mState = State::SYNCHORONIZED_B;
+ break;
+ }
+
+ break;
+ }
+
+ } // switch (readStateA)
+ }
+
+ void synchronizePages(uint32_t* writePageAddr, uint32_t* erasePageAddr) {
+ writePage(writePageAddr);
+ if (verifyPage(writePageAddr)) {
+ if (erasePageAddr != nullptr) {
+ erasePage(erasePageAddr);
+ }
+ }
+ }
+
+ uint32_t* const mPageAddrA;
+ uint32_t* const mPageAddrB;
+ const size_t mWords;
+ uint32_t* mData;
+ State mState;
+};
+
+#define TEMP_SIZE 32
+
+FlashMemory gDataMemory((uint32_t*) (XMC_DALI_FLASH_START + XMC_DALI_FLASH_SIZE - XMC_FLASH_BYTES_PER_PAGE * 4),
+ (uint32_t*) (XMC_DALI_FLASH_START + XMC_DALI_FLASH_SIZE - XMC_FLASH_BYTES_PER_PAGE * 3),
+ FLASH_MEMORY_SIZE / sizeof(uint32_t));
+} // namespace
+
+//static
+Memory* Memory::getInstance() {
+ static Memory gMemory1(&gDataMemory, FLASH_MEMORY_SIZE - TEMP_SIZE, FLASH_MEMORY_SIZE - TEMP_SIZE);
+ return &gMemory1;
+}
+
+Memory::Memory(void* handle, size_t dataSize, uintptr_t tempAddr) :
+ mHandle(handle), mTempAddr(tempAddr) {
+ ((FlashMemory*) handle)->synchronize(false);
+}
+
+size_t Memory::dataSize() {
+ return FLASH_MEMORY_SIZE;
+}
+
+size_t Memory::dataWrite(uintptr_t addr, const uint8_t* data, size_t size) {
+ if (addr + size > FLASH_MEMORY_SIZE) {
+ return 0;
+ }
+ return ((FlashMemory*) mHandle)->write(addr, data, size);
+}
+
+const uint8_t* Memory::data(uintptr_t addr, size_t size) {
+ if (addr + size > FLASH_MEMORY_SIZE) {
+ return nullptr;
+ }
+ return ((FlashMemory*) mHandle)->getData(addr);
+}
+
+size_t Memory::tempSize() {
+ return TEMP_SIZE;
+}
+
+size_t Memory::tempWrite(uintptr_t addr, const uint8_t* data, size_t size) {
+ if (addr + size > TEMP_SIZE) {
+ return 0;
+ }
+ return ((FlashMemory*) mHandle)->write(mTempAddr + addr, data, size);
+}
+
+const uint8_t* Memory::tempData(uintptr_t addr, size_t size) {
+ if (addr + size > TEMP_SIZE) {
+ return nullptr;
+ }
+ return ((FlashMemory*) mHandle)->getData(mTempAddr + addr);
+}
+
+//static
+void Memory::synchronize(bool emergency) {
+ gDataMemory.synchronize(emergency);
+}
+
+//static
+void Memory::erase(bool temp) {
+ gDataMemory.erase();
+}
+
+}
+// namespace xmc
+}// namespace dali
diff --git a/src/xmc1200/dali/memory.hpp b/src/xmc1200/dali/memory.hpp
new file mode 100644
index 0000000..8f3f1de
--- /dev/null
+++ b/src/xmc1200/dali/memory.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_MEMORY_H_
+#define XMC_DALI_MEMORY_H_
+
+#include
+
+#include
+#include
+
+namespace dali {
+namespace xmc {
+
+class Memory: public dali::IMemory {
+public:
+ static Memory* getInstance();
+
+ size_t dataSize() override;
+ size_t dataWrite(uintptr_t addr, const uint8_t* data, size_t size) override;
+ const uint8_t* data(uintptr_t addr, size_t size) override;
+
+ size_t tempSize() override;
+ size_t tempWrite(uintptr_t addr, const uint8_t* data, size_t size) override;
+ const uint8_t* tempData(uintptr_t addr, size_t size) override;
+
+ static void synchronize(bool temp);
+ static void erase(bool temp);
+
+private:
+ Memory(void* handle, size_t dataSize, uintptr_t tempAddr);
+ Memory(const Memory& other) = delete;
+ Memory& operator=(const Memory&) = delete;
+
+ const void* mHandle;
+ const uintptr_t mTempAddr;
+};
+
+} // namespace xmc
+} // namespace dali
+
+#endif // XMC_DALI_MEMORY_H_
diff --git a/src/xmc1200/dali/memory_config.hpp b/src/xmc1200/dali/memory_config.hpp
new file mode 100644
index 0000000..20e588d
--- /dev/null
+++ b/src/xmc1200/dali/memory_config.hpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_MEMORY_CONFIG_H_
+#define XMC_DALI_MEMORY_CONFIG_H_
+
+# define XMC_DALI_FLASH_START 0x10001000
+# define XMC_DALI_FLASH_SIZE 0x32000
+
+#endif // XMC_DALI_MEMORY_CONFIG_H_
diff --git a/src/xmc1200/dali/timer.cpp b/src/xmc1200/dali/timer.cpp
new file mode 100644
index 0000000..bc4221b
--- /dev/null
+++ b/src/xmc1200/dali/timer.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#include "timer.hpp"
+
+#include
+
+namespace dali {
+namespace xmc {
+
+namespace {
+
+const uint16_t* kUniqeChipId = (uint16_t*) 0x10000FF0; // 8 elements
+
+#define MAX_TASKS (3)
+#define TICKS_PER_SECOND 1000
+
+typedef struct {
+ dali::ITimer::ITimerTask* task;
+ uint64_t time;
+ uint32_t period;
+} TaskInfo;
+
+TaskInfo gTasks[MAX_TASKS];
+volatile uint64_t gSystemTimeMs;
+
+}
+
+//static
+Timer* Timer::getInstance() {
+ static Timer gDaliTimer;
+ return &gDaliTimer;
+}
+
+Timer::Timer() {
+ XMC_PRNG_INIT_t prngConfig;
+ prngConfig.key_words[0] = kUniqeChipId[3];
+ prngConfig.key_words[1] = kUniqeChipId[4];
+ prngConfig.key_words[2] = kUniqeChipId[5];
+ prngConfig.key_words[3] = kUniqeChipId[6];
+ prngConfig.key_words[4] = kUniqeChipId[7];
+ prngConfig.block_size = XMC_PRNG_RDBS_WORD;
+ XMC_PRNG_Init(&prngConfig);
+
+ SysTick_Config(SystemCoreClock / TICKS_PER_SECOND);
+}
+
+Timer::~Timer() {
+ WR_REG(SysTick->CTRL, SysTick_CTRL_ENABLE_Msk, SysTick_CTRL_ENABLE_Pos, 0);
+
+ XMC_PRNG_DeInit();
+}
+
+dali::Status Timer::schedule(ITimerTask* task, uint32_t delay, uint32_t period) {
+ for (uint8_t i = 0; i < MAX_TASKS; ++i) {
+ TaskInfo* taskInfo = &gTasks[i];
+ if (taskInfo->task == nullptr) {
+ taskInfo->task = task;
+ taskInfo->time = gSystemTimeMs + delay;
+ taskInfo->period = period;
+ return dali::Status::OK;
+ }
+ }
+ return dali::Status::ERROR;
+}
+
+void Timer::cancel(ITimerTask* task) {
+ for (uint8_t i = 0; i < MAX_TASKS; ++i) {
+ TaskInfo* taskInfo = &gTasks[i];
+ if (taskInfo->task == task) {
+ taskInfo->task = nullptr;
+ }
+ }
+}
+
+uint32_t Timer::randomize() {
+ return ((uint32_t) XMC_PRNG_GetPseudoRandomNumber() << 8) + (uint32_t) gSystemTimeMs;
+}
+
+// static
+uint64_t Timer::getTimeMs() {
+ return gSystemTimeMs;
+}
+
+// static
+uint16_t Timer::freq() {
+ return TICKS_PER_SECOND;
+}
+
+// static
+void Timer::runSlice() {
+ for (uint8_t i = 0; i < MAX_TASKS; ++i) {
+ TaskInfo* taskInfo = &gTasks[i];
+
+ if (taskInfo->task != nullptr) {
+ if (taskInfo->time <= gSystemTimeMs) {
+ taskInfo->task->timerTaskRun();
+ if (taskInfo->period != 0) {
+ taskInfo->time += taskInfo->period;
+ } else {
+ taskInfo->task = nullptr;
+ }
+ }
+ }
+ }
+}
+
+extern "C" {
+
+void SysTick_Handler(void) {
+ gSystemTimeMs += 1000 / TICKS_PER_SECOND;
+}
+
+} // extern "C"
+
+} // namespace xmc
+} // namespace dali
diff --git a/src/xmc1200/dali/timer.hpp b/src/xmc1200/dali/timer.hpp
new file mode 100644
index 0000000..aeea90c
--- /dev/null
+++ b/src/xmc1200/dali/timer.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#ifndef XMC_DALI_TIMER_H_
+#define XMC_DALI_TIMER_H_
+
+#include
+
+namespace dali {
+namespace xmc {
+
+class Timer: public dali::ITimer {
+public:
+ static Timer* getInstance();
+
+ uint64_t getTime() override {
+ return getTimeMs();
+ }
+ dali::Status schedule(ITimerTask* task, uint32_t delay, uint32_t period) override;
+ void cancel(ITimerTask* task) override;
+ uint32_t randomize() override;
+
+ static uint64_t getTimeMs();
+ static uint16_t freq();
+ static void runSlice();
+
+private:
+ Timer();
+ Timer(const Timer& other) = delete;
+ Timer& operator=(const Timer&) = delete;
+
+ ~Timer();
+};
+
+} // namespace xmc
+} // namespace dali
+
+#endif // XMC_DALI_TIMER_H_
diff --git a/src/xmc1200/main.cpp b/src/xmc1200/main.cpp
new file mode 100644
index 0000000..834849d
--- /dev/null
+++ b/src/xmc1200/main.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2015-2016, Arkadiusz Materek (arekmat@poczta.fm)
+ *
+ * Licensed under GNU General Public License 3.0 or later.
+ *
+ * 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.
+ */
+
+#if (CPU_CLOCK == 32000000)
+#define XMC_CPU_FREQ xmc::Clock::FREQ_32MHZ
+#elif (CPU_CLOCK == 16000000)
+#define XMC_CPU_FREQ xmc::Clock::FREQ_16MHZ
+#else
+#error Unsupported CPU clock
+#endif
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+dali::Slave* gSlave;
+
+void waitForInterrupt() {
+ __WFI();
+}
+
+void initPowerDetector() {
+ XMC_SCU_SUPPLYMONITOR_t config;
+ config.ext_supply_threshold = 0b10;
+ config.ext_supply_monitor_speed = 0b00;
+ config.enable_prewarning_int = true;
+ config.enable_vdrop_int = false;
+ config.enable_vclip_int = false;
+ config.enable_at_init = true;
+
+ XMC_SCU_SupplyMonitorInit(&config);
+ NVIC_EnableIRQ(SCU_1_IRQn);
+}
+
+void onPowerUp() {
+ gSlave->notifyPowerUp();
+}
+
+void onPowerDown() {
+ gSlave->notifyPowerDown();
+ dali::xmc::Memory::synchronize(true);
+}
+
+class PowerOnTimerTask: public dali::ITimer::ITimerTask {
+public:
+
+ void timerTaskRun() override {
+ onPowerUp();
+ }
+};
+
+PowerOnTimerTask gPowerOnTimerTask;
+
+volatile bool gEmergencyMemorySynchronise;
+
+int main(void) {
+ xmc::Clock::init(XMC_CPU_FREQ);
+
+
+ initPowerDetector();
+
+ dali::xmc::Timer* daliTimer = dali::xmc::Timer::getInstance();
+ dali::xmc::Bus* daliBus = dali::xmc::Bus::getInstance();
+
+ dali::xmc::Memory* daliMemory1 = dali::xmc::Memory::getInstance();
+ dali::xmc::LampRGB* daliLamp1 = dali::xmc::LampRGB::getInstance();
+ gSlave = dali::Slave::create(daliMemory1, daliLamp1, daliBus, daliTimer);
+
+ daliTimer->schedule(&gPowerOnTimerTask, 600, 0);
+
+ XMC_GPIO_SetMode(XMC_GPIO_PORT0, 0, XMC_GPIO_MODE_OUTPUT_PUSH_PULL);
+ XMC_GPIO_SetOutputHigh(XMC_GPIO_PORT0, 0);
+
+ while (true) {
+ waitForInterrupt(); // Interrupts are triggered by SysTick 1kHz and from CCU4 (DALI RX) up to 2,4Khz
+ if (gEmergencyMemorySynchronise) {
+ gEmergencyMemorySynchronise = false;
+ onPowerDown();
+ }
+ dali::xmc::Timer::runSlice();
+ dali::xmc::Bus::runSlice();
+ }
+ return 0;
+}
+
+extern "C" {
+
+void HardFault_Handler(void) {
+ XMC_SCU_RESET_AssertMasterReset();
+}
+
+void SCU_1_IRQHandler(void) {
+ if (SCU_INTERRUPT->SRRAW & SCU_INTERRUPT_SRRAW_VDDPI_Msk) {
+ SCU_INTERRUPT->SRCLR = SCU_INTERRUPT_SRCLR_VDDPI_Msk;
+ gEmergencyMemorySynchronise = true;
+ }
+}
+
+} // extern "C"
+
diff --git a/src/xmc1200/startup_XMC1200.S b/src/xmc1200/startup_XMC1200.S
new file mode 100644
index 0000000..2f776cf
--- /dev/null
+++ b/src/xmc1200/startup_XMC1200.S
@@ -0,0 +1,485 @@
+/******************************************************************************
+ * @file startup_XMC1200.s
+ * @brief CMSIS Core Device Startup File for
+ * Infineon XMC1200 Device Series
+ * @version V1.13
+ * @date Dec 2014
+ *
+ * Copyright (C) 2014 Infineon Technologies AG. All rights reserved.
+ *
+ *
+ * @par
+ * Infineon Technologies AG (Infineon) is supplying this software for use with
+ * Infineon's microcontrollers. This file can be freely distributed
+ * within development tools that are supporting such microcontrollers.
+ *
+ * @par
+ * THIS SOFTWARE IS PROVIDED AS IS. NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * ARM SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR
+ * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *
+ ******************************************************************************/
+
+/********************** Version History ***************************************
+ * V1.0, Oct, 02, 2012 PKB:Startup file for XMC1
+ * V1.1, Oct, 19, 2012 PKB:ERU and MATH interrupt handlers
+ * V1.2, Nov, 02, 2012 PKB:Renamed AllowPLLInitByStartup to AllowClkInitByStartup
+ * V1.3, Dec, 11, 2012 PKB:Attributes of .XmcVeneerCode section changed
+ * V1.4, Dec, 13, 2012 PKB:Removed unwanted interrupts/veneers
+ * V1.5, Jan, 26, 2013 PKB:Corrected the SSW related entries
+ * V1.6, Feb, 13, 2013 PKB:Relative path to Device_Data.h
+ * V1.7, Feb, 19, 2013 PKB:Included XMC1100_SCU.inc
+ * V1.8, Jan, 24, 2014 PKB:Removed AllowClkInitStartup and DAVE Extended init
+ * V1.9, Feb, 05, 2014 PKB:Removed redundant alignment code from copy+clear funcs
+ * V1.10, Feb, 14, 2014 PKB:Added software_init_hook and hardware_init_hook
+ * V1.11, May, 06, 2014 JFT:__COPY_FLASH2RAM to initialize ram
+ * Added ram_code section initialization
+ * V1.12, Sep, 29, 2014 JFT:One single default handler
+ * Device_Data.h not included, user may use CLKVAL1_SSW
+ * and CLKVAL2_SSW.
+ * software_init_hook and hardware_init_hook removed
+ * Misc optimizations
+ * V1.13, Dec, 11,2014 JFT:Default clocking changed, MCLK=32MHz and PCLK=64MHz
+ ******************************************************************************/
+
+/*****************************************************************************
+ * Clock system handling by SSW
+ * CLK_VAL1 Configuration
+ * FDIV Fractional Divider Selection
+ * IDIV Divider Selection (limited to 1-16)
+ * <0=> Divider is bypassed
+ * <1=> MCLK = 32 MHz
+ * <2=> MCLK = 16 MHz
+ * <3=> MCLK = 10.67 MHz
+ * <4=> MCLK = 8 MHz
+ * <254=> MCLK = 126 kHz
+ * <255=> MCLK = 125.5 kHz
+ * PCLKSEL PCLK Clock Select
+ * <0=> PCLK = MCLK
+ * <1=> PCLK = 2 x MCLK
+ * RTCCLKSEL RTC Clock Select
+ * <0=> 32.768kHz standby clock
+ * <1=> 32.768kHz external clock from ERU0.IOUT0
+ * <2=> 32.768kHz external clock from ACMP0.OUT
+ * <3=> 32.768kHz external clock from ACMP1.OUT
+ * <4=> 32.768kHz external clock from ACMP2.OUT
+ * <5=> Reserved
+ * <6=> Reserved
+ * <7=> Reserved
+ * do not move CLK_VAL1 to SCU_CLKCR[0..19]
+ *
+ *****************************************************************************/
+#define CLKVAL1_SSW 0x00010100
+
+/*****************************************************************************
+ * CLK_VAL2 Configuration
+ * disable VADC and SHS Gating
+ * disable CCU80 Gating
+ * disable CCU40 Gating
+ * disable USIC0 Gating
+ * disable BCCU0 Gating
+ * disable LEDTS0 Gating
+ * disable LEDTS1 Gating
+ * disable POSIF0 Gating
+ * disable MATH Gating
+ * disable WDT Gating
+ * disable RTC Gating
+ * do not move CLK_VAL2 to SCU_CGATCLR0[0..10]
+ *
+ *****************************************************************************/
+#define CLKVAL2_SSW 0x80000000
+
+/* A macro to define vector table entries */
+.macro Entry Handler
+ .long \Handler
+.endm
+
+/* A couple of macros to ease definition of the various handlers */
+.macro Insert_ExceptionHandler Handler_Func
+ .weak \Handler_Func
+ .thumb_set \Handler_Func, Default_handler
+.endm
+
+/* ================== START OF VECTOR TABLE DEFINITION ====================== */
+/* Vector Table - This is indirectly branched to through the veneers */
+ .syntax unified
+ .cpu cortex-m0
+
+ .section ".reset"
+
+ .align 2
+
+ .globl __Vectors
+ .type __Vectors, %object
+__Vectors:
+ .long __initial_sp /* Top of Stack */
+ .long Reset_Handler /* Reset Handler */
+/*
+ * All entries below are redundant for M0, but are retained because they can
+ * in the future be directly ported to M0 Plus devices.
+ */
+ .long 0 /* Reserved */
+ Entry HardFault_Handler /* Hard Fault Handler */
+ .long CLKVAL1_SSW /* Reserved */
+ .long CLKVAL2_SSW /* Reserved */
+#ifdef RETAIN_VECTOR_TABLE
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ Entry SVC_Handler /* SVCall Handler */
+ .long 0 /* Reserved */
+ .long 0 /* Reserved */
+ Entry PendSV_Handler /* PendSV Handler */
+ Entry SysTick_Handler /* SysTick Handler */
+
+ /* Interrupt Handlers for Service Requests (SR) from XMC1200 Peripherals */
+ Entry SCU_0_IRQHandler /* Handler name for SR SCU_0 */
+ Entry SCU_1_IRQHandler /* Handler name for SR SCU_1 */
+ Entry SCU_2_IRQHandler /* Handler name for SR SCU_2 */
+ Entry ERU0_0_IRQHandler /* Handler name for SR ERU0_0 */
+ Entry ERU0_1_IRQHandler /* Handler name for SR ERU0_1 */
+ Entry ERU0_2_IRQHandler /* Handler name for SR ERU0_2 */
+ Entry ERU0_3_IRQHandler /* Handler name for SR ERU0_3 */
+ .long 0 /* Not Available */
+ .long 0 /* Not Available */
+ Entry USIC0_0_IRQHandler /* Handler name for SR USIC0_0 */
+ Entry USIC0_1_IRQHandler /* Handler name for SR USIC0_1 */
+ Entry USIC0_2_IRQHandler /* Handler name for SR USIC0_2 */
+ Entry USIC0_3_IRQHandler /* Handler name for SR USIC0_3 */
+ Entry USIC0_4_IRQHandler /* Handler name for SR USIC0_4 */
+ Entry USIC0_5_IRQHandler /* Handler name for SR USIC0_5 */
+ Entry VADC0_C0_0_IRQHandler /* Handler name for SR VADC0_C0_0 */
+ Entry VADC0_C0_1_IRQHandler /* Handler name for SR VADC0_C0_1 */
+ Entry VADC0_G0_0_IRQHandler /* Handler name for SR VADC0_G0_0 */
+ Entry VADC0_G0_1_IRQHandler /* Handler name for SR VADC0_G0_1 */
+ Entry VADC0_G1_0_IRQHandler /* Handler name for SR VADC0_G1_0 */
+ Entry VADC0_G1_1_IRQHandler /* Handler name for SR VADC0_G1_1 */
+ Entry CCU40_0_IRQHandler /* Handler name for SR CCU40_0 */
+ Entry CCU40_1_IRQHandler /* Handler name for SR CCU40_1 */
+ Entry CCU40_2_IRQHandler /* Handler name for SR CCU40_2 */
+ Entry CCU40_3_IRQHandler /* Handler name for SR CCU40_3 */
+ .long 0 /* Not Available */
+ .long 0 /* Not Available */
+ .long 0 /* Not Available */
+ .long 0 /* Not Available */
+ Entry LEDTS0_0_IRQHandler /* Handler name for SR LEDTS0_0 */
+ Entry LEDTS1_0_IRQHandler /* Handler name for SR LEDTS1_0 */
+ Entry BCCU0_0_IRQHandler /* Handler name for SR BCCU0_0 */
+#endif
+
+ .size __Vectors, . - __Vectors
+/* ================== END OF VECTOR TABLE DEFINITION ======================= */
+
+/* ================== START OF VECTOR ROUTINES ============================= */
+
+ .thumb
+ .align 1
+
+/* Reset Handler */
+ .thumb_func
+ .globl Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+/* Initialize interrupt veneer */
+ ldr r1, =eROData
+ ldr r2, =VeneerStart
+ ldr r3, =VeneerEnd
+ bl __copy_data
+
+ ldr r0, =SystemInit
+ blx r0
+
+/* Initialize data */
+ ldr r1, =DataLoadAddr
+ ldr r2, =__data_start
+ ldr r3, =__data_end
+ bl __copy_data
+
+/* RAM code */
+ ldr r1, =__ram_code_load
+ ldr r2, =__ram_code_start
+ ldr r3, =__ram_code_end
+ bl __copy_data
+
+/* Define __SKIP_BSS_CLEAR to disable zeroing uninitialzed data in startup.
+ * The BSS section is specified by following symbols
+ * __bss_start__: start of the BSS section.
+ * __bss_end__: end of the BSS section.
+ *
+ * Both addresses must be aligned to 4 bytes boundary.
+ */
+#ifndef __SKIP_BSS_CLEAR
+ ldr r1, =__bss_start
+ ldr r2, =__bss_end
+
+ movs r0, 0
+
+ subs r2, r1
+ ble .L_loop3_done
+
+.L_loop3:
+ subs r2, #4
+ str r0, [r1, r2]
+ bgt .L_loop3
+.L_loop3_done:
+#endif /* __SKIP_BSS_CLEAR */
+
+#ifndef __SKIP_LIBC_INIT_ARRAY
+ ldr r0, =__libc_init_array
+ blx r0
+#endif
+
+ ldr r0, =main
+ blx r0
+
+ .thumb_func
+ .type __copy_data, %function
+__copy_data:
+/* The ranges of copy from/to are specified by following symbols
+ * r1: start of the section to copy from.
+ * r2: start of the section to copy to
+ * r3: end of the section to copy to
+ *
+ * All addresses must be aligned to 4 bytes boundary.
+ * Uses r0
+ */
+ subs r3, r2
+ ble .L_loop_done
+
+.L_loop:
+ subs r3, #4
+ ldr r0, [r1,r3]
+ str r0, [r2,r3]
+ bgt .L_loop
+
+.L_loop_done:
+ bx lr
+
+ .pool
+ .size Reset_Handler,.-Reset_Handler
+/* ======================================================================== */
+/* ========== START OF EXCEPTION HANDLER DEFINITION ======================== */
+
+ .align 1
+
+ .thumb_func
+ .weak Default_handler
+ .type Default_handler, %function
+Default_handler:
+ b .
+ .size Default_handler, . - Default_handler
+
+ Insert_ExceptionHandler HardFault_Handler
+ Insert_ExceptionHandler SVC_Handler
+ Insert_ExceptionHandler PendSV_Handler
+ Insert_ExceptionHandler SysTick_Handler
+
+ Insert_ExceptionHandler SCU_0_IRQHandler
+ Insert_ExceptionHandler SCU_1_IRQHandler
+ Insert_ExceptionHandler SCU_2_IRQHandler
+ Insert_ExceptionHandler ERU0_0_IRQHandler
+ Insert_ExceptionHandler ERU0_1_IRQHandler
+ Insert_ExceptionHandler ERU0_2_IRQHandler
+ Insert_ExceptionHandler ERU0_3_IRQHandler
+ Insert_ExceptionHandler VADC0_C0_0_IRQHandler
+ Insert_ExceptionHandler VADC0_C0_1_IRQHandler
+ Insert_ExceptionHandler VADC0_G0_0_IRQHandler
+ Insert_ExceptionHandler VADC0_G0_1_IRQHandler
+ Insert_ExceptionHandler VADC0_G1_0_IRQHandler
+ Insert_ExceptionHandler VADC0_G1_1_IRQHandler
+ Insert_ExceptionHandler CCU40_0_IRQHandler
+ Insert_ExceptionHandler CCU40_1_IRQHandler
+ Insert_ExceptionHandler CCU40_2_IRQHandler
+ Insert_ExceptionHandler CCU40_3_IRQHandler
+ Insert_ExceptionHandler USIC0_0_IRQHandler
+ Insert_ExceptionHandler USIC0_1_IRQHandler
+ Insert_ExceptionHandler USIC0_2_IRQHandler
+ Insert_ExceptionHandler USIC0_3_IRQHandler
+ Insert_ExceptionHandler USIC0_4_IRQHandler
+ Insert_ExceptionHandler USIC0_5_IRQHandler
+ Insert_ExceptionHandler LEDTS0_0_IRQHandler
+ Insert_ExceptionHandler LEDTS1_0_IRQHandler
+ Insert_ExceptionHandler BCCU0_0_IRQHandler
+
+/* ======================================================================== */
+
+/* ==================VENEERS VENEERS VENEERS VENEERS VENEERS=============== */
+ .section ".XmcVeneerCode","ax",%progbits
+
+ .align 1
+
+ .globl HardFault_Veneer
+HardFault_Veneer:
+ LDR R0, =HardFault_Handler
+ MOV PC,R0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+/* ======================================================================== */
+ .globl SVC_Veneer
+SVC_Veneer:
+ LDR R0, =SVC_Handler
+ MOV PC,R0
+ .long 0
+ .long 0
+/* ======================================================================== */
+ .globl PendSV_Veneer
+PendSV_Veneer:
+ LDR R0, =PendSV_Handler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SysTick_Veneer
+SysTick_Veneer:
+ LDR R0, =SysTick_Handler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_0_Veneer
+SCU_0_Veneer:
+ LDR R0, =SCU_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_1_Veneer
+SCU_1_Veneer:
+ LDR R0, =SCU_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_2_Veneer
+SCU_2_Veneer:
+ LDR R0, =SCU_2_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_3_Veneer
+SCU_3_Veneer:
+ LDR R0, =ERU0_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_4_Veneer
+SCU_4_Veneer:
+ LDR R0, =ERU0_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_5_Veneer
+SCU_5_Veneer:
+ LDR R0, =ERU0_2_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl SCU_6_Veneer
+SCU_6_Veneer:
+ LDR R0, =ERU0_3_IRQHandler
+ MOV PC,R0
+ .long 0
+ .long 0
+/* ======================================================================== */
+ .globl USIC0_0_Veneer
+USIC0_0_Veneer:
+ LDR R0, =USIC0_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl USIC0_1_Veneer
+USIC0_1_Veneer:
+ LDR R0, =USIC0_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl USIC0_2_Veneer
+USIC0_2_Veneer:
+ LDR R0, =USIC0_2_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl USIC0_3_Veneer
+USIC0_3_Veneer:
+ LDR R0, =USIC0_3_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl USIC0_4_Veneer
+USIC0_4_Veneer:
+ LDR R0, =USIC0_4_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl USIC0_5_Veneer
+USIC0_5_Veneer:
+ LDR R0, =USIC0_5_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_C0_0_Veneer
+VADC0_C0_0_Veneer:
+ LDR R0, =VADC0_C0_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_C0_1_Veneer
+VADC0_C0_1_Veneer:
+ LDR R0, =VADC0_C0_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_G0_0_Veneer
+VADC0_G0_0_Veneer:
+ LDR R0, =VADC0_G0_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_G0_1_Veneer
+VADC0_G0_1_Veneer:
+ LDR R0, =VADC0_G0_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_G1_0_Veneer
+VADC0_G1_0_Veneer:
+ LDR R0, =VADC0_G1_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl VADC0_G1_1_Veneer
+VADC0_G1_1_Veneer:
+ LDR R0, =VADC0_G1_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl CCU40_0_Veneer
+CCU40_0_Veneer:
+ LDR R0, =CCU40_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl CCU40_1_Veneer
+CCU40_1_Veneer:
+ LDR R0, =CCU40_1_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl CCU40_2_Veneer
+CCU40_2_Veneer:
+ LDR R0, =CCU40_2_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl CCU40_3_Veneer
+CCU40_3_Veneer:
+ LDR R0, =CCU40_3_IRQHandler
+ MOV PC,R0
+ .long 0
+ .long 0
+ .long 0
+ .long 0
+/* ======================================================================== */
+ .globl LEDTS0_0_Veneer
+LEDTS0_0_Veneer:
+ LDR R0, =LEDTS0_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl LEDTS1_0_Veneer
+LEDTS1_0_Veneer:
+ LDR R0, =LEDTS1_0_IRQHandler
+ MOV PC,R0
+/* ======================================================================== */
+ .globl BCCU0_0_Veneer
+BCCU0_0_Veneer:
+ LDR R0, =BCCU0_0_IRQHandler
+ MOV PC,R0
+
+/* ======================================================================== */
+/* ======================================================================== */
+
+/* ============= END OF INTERRUPT HANDLER DEFINITION ======================== */
+
+ .end
diff --git a/src/xmc1200/system_XMC1200.c b/src/xmc1200/system_XMC1200.c
new file mode 100644
index 0000000..8a7e69c
--- /dev/null
+++ b/src/xmc1200/system_XMC1200.c
@@ -0,0 +1,115 @@
+/******************************************************************************
+ * @file system_XMC1200.c
+ * @brief Device specific initialization for the XMC1200-Series according
+ * to CMSIS
+ * @version V1.7
+ * @date 11 Dec 2014
+ *
+ * @note
+ * Copyright (C) 2012-2014 Infineon Technologies AG. All rights reserved.
+
+ *
+ * @par
+ * Infineon Technologies AG (Infineon) is supplying this software for use with
+ * Infineon’s microcontrollers.
+ *
+ * This file can be freely distributed within development tools that are
+ * supporting such microcontrollers.
+ *
+ *
+ * @par
+ * THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
+ * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
+ * INFINEON SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
+ * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
+ *
+ ******************************************************************************/
+/*
+ * *************************** Change history ********************************
+ * V1.2, 13 Dec 2012, PKB : Created change history table
+ * V1.3, 20 Dec 2012, PKB : Fixed SystemCoreClock computation
+ * V1.4, 02 Feb 2013, PKB : SCU_CLOCK -> SCU_CLK
+ * V1.5, 27 Nov 2013, DNE : Comments added in SystemInit function for MCLK support
+ * V1.6, 19 Feb 2014, JFT : Fixed SystemCoreClock when FDIV != 0
+ * V1.7, 11 Dec 2014, JFT : SystemCoreClockSetup, SystemCoreSetup as weak functions
+ */
+
+/*******************************************************************************
+ * HEADER FILES
+ *******************************************************************************/
+
+#include
+#include "system_XMC1200.h"
+
+/*******************************************************************************
+ * MACROS
+ *******************************************************************************/
+
+/* Define WEAK attribute */
+#if !defined(__WEAK)
+#if defined ( __CC_ARM )
+#define __WEAK __attribute__ ((weak))
+#elif defined ( __ICCARM__ )
+#define __WEAK __weak
+#elif defined ( __GNUC__ )
+#define __WEAK __attribute__ ((weak))
+#elif defined ( __TASKING__ )
+#define __WEAK __attribute__ ((weak))
+#endif
+#endif
+
+#define DCO1_FREQUENCY (64000000U)
+
+/*******************************************************************************
+ * GLOBAL VARIABLES
+ *******************************************************************************/
+
+#if defined ( __CC_ARM )
+uint32_t SystemCoreClock __attribute__((at(0x20003FFC)));
+#elif defined ( __ICCARM__ )
+__no_init uint32_t SystemCoreClock;
+#elif defined ( __GNUC__ )
+uint32_t SystemCoreClock __attribute__((section(".no_init")));
+#elif defined ( __TASKING__ )
+uint32_t SystemCoreClock __at( 0x20003FFC );
+#endif
+
+/*******************************************************************************
+ * API IMPLEMENTATION
+ *******************************************************************************/
+
+__WEAK void SystemInit(void)
+{
+ SystemCoreSetup();
+ SystemCoreClockSetup();
+}
+
+__WEAK void SystemCoreSetup(void)
+{
+}
+
+__WEAK void SystemCoreClockSetup(void)
+{
+ /* Clock setup done during SSW using the CLOCK_VAL1 and CLOCK_VAL2 defined in vector table */
+ SystemCoreClockUpdate();
+}
+
+__WEAK void SystemCoreClockUpdate(void)
+{
+ static uint32_t IDIV, FDIV;
+
+ IDIV = ((SCU_CLK->CLKCR) & SCU_CLK_CLKCR_IDIV_Msk) >> SCU_CLK_CLKCR_IDIV_Pos;
+ FDIV = ((SCU_CLK->CLKCR) & SCU_CLK_CLKCR_FDIV_Msk) >> SCU_CLK_CLKCR_FDIV_Pos;
+
+ if (IDIV != 0)
+ {
+ /* Fractional divider is enabled and used */
+ SystemCoreClock = ((DCO1_FREQUENCY << 6U) / ((IDIV << 8) + FDIV)) << 1U;
+ }
+ else
+ {
+ /* Fractional divider bypassed. Simply divide DCO_DCLK by 2 */
+ SystemCoreClock = DCO1_FREQUENCY >> 1U;
+ }
+}