#include "knx_facade.h" #include "knx/bau57B0.h" #include "knx/bau27B0.h" #include "knx/bau07B0.h" #include "knx/group_object_table_object.h" #include "knx/bits.h" #include #include #include #include #include #include #include volatile sig_atomic_t loopActive = 1; void signalHandler(int sig) { (void)sig; // can be called asynchronously loopActive = 0; } bool sendHidReport(uint8_t* data, uint16_t length) { return false; } bool isSendHidReportPossible() { return false; } #if MEDIUM_TYPE == 5 KnxFacade knx; #elif MEDIUM_TYPE == 2 KnxFacade knx; #else #error Only MEDIUM_TYPE IP and RF supported #endif long lastsend = 0; #define CURR knx.getGroupObject(1) #define MAX knx.getGroupObject(2) #define MIN knx.getGroupObject(3) #define RESET knx.getGroupObject(4) int ceil(float num) { int inum = (int)num; if (num == (float)inum) { return inum; } return inum + 1; } int toBase32(uint8_t* in, long length, uint8_t*& out, bool usePadding) { char base32StandardAlphabet[] = {"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"}; char standardPaddingChar = '='; int result = 0; int count = 0; int bufSize = 8; int index = 0; int size = 0; // size of temporary array uint8_t* temp = NULL; if (length < 0 || length > 268435456LL) { return 0; } size = 8 * ceil(length / 4.0); // Calculating size of temporary array. Not very precise. temp = (uint8_t*)malloc(size); // Allocating temporary array. if (length > 0) { int buffer = in[0]; int next = 1; int bitsLeft = 8; while (count < bufSize && (bitsLeft > 0 || next < length)) { if (bitsLeft < 5) { if (next < length) { buffer <<= 8; buffer |= in[next] & 0xFF; next++; bitsLeft += 8; } else { int pad = 5 - bitsLeft; buffer <<= pad; bitsLeft += pad; } } index = 0x1F & (buffer >> (bitsLeft -5)); bitsLeft -= 5; temp[result] = (uint8_t)base32StandardAlphabet[index]; result++; } } if (usePadding) { int pads = (result % 8); if (pads > 0) { pads = (8 - pads); for (int i = 0; i < pads; i++) { temp[result] = standardPaddingChar; result++; } } } out = (uint8_t*)malloc(result); memcpy(out, temp, result); free(temp); return result; } int fromBase32(uint8_t* in, long length, uint8_t*& out) { int result = 0; // Length of the array of decoded values. int buffer = 0; int bitsLeft = 0; uint8_t* temp = NULL; temp = (uint8_t*)malloc(length); // Allocating temporary array. for (int i = 0; i < length; i++) { uint8_t ch = in[i]; // ignoring some characters: ' ', '\t', '\r', '\n', '=' if (ch == 0xA0 || ch == 0x09 || ch == 0x0A || ch == 0x0D || ch == 0x3D) continue; // recovering mistyped: '0' -> 'O', '1' -> 'L', '8' -> 'B' if (ch == 0x30) { ch = 0x4F; } else if (ch == 0x31) { ch = 0x4C; } else if (ch == 0x38) { ch = 0x42; } // look up one base32 symbols: from 'A' to 'Z' or from 'a' to 'z' or from '2' to '7' if ((ch >= 0x41 && ch <= 0x5A) || (ch >= 0x61 && ch <= 0x7A)) { ch = ((ch & 0x1F) - 1); } else if (ch >= 0x32 && ch <= 0x37) { ch -= (0x32 - 26); } else { free(temp); return 0; } buffer <<= 5; buffer |= ch; bitsLeft += 5; if (bitsLeft >= 8) { temp[result] = (unsigned char)((unsigned int)(buffer >> (bitsLeft - 8)) & 0xFF); result++; bitsLeft -= 8; } } out = (uint8_t*)malloc(result); memcpy(out, temp, result); free(temp); return result; } void measureTemp() { long now = millis(); if ((now - lastsend) < 10000) return; lastsend = now; int r = rand(); double currentValue = (r * 1.0) / (RAND_MAX * 1.0); currentValue *= 100; currentValue -= 50; // currentValue *= (670433.28 + 273); // currentValue -= 273; println(currentValue); CURR.value(currentValue); double max = MAX.value(); if (currentValue > max) MAX.value(currentValue); if (currentValue < (double)MIN.value()) MIN.value(currentValue); } void resetCallback(GroupObject& go) { if (go.value()) { MAX.valueNoSend(-273.0); MIN.valueNoSend(670433.28); } } void appLoop() { if (!knx.configured()) return; measureTemp(); } void setup() { srand((unsigned int)time(NULL)); knx.readMemory(); if (knx.induvidualAddress() == 0) knx.progMode(true); if (knx.configured()) { CURR.dataPointType(Dpt(9, 1)); MIN.dataPointType(Dpt(9, 1)); MIN.value(670433.28); MAX.dataPointType(Dpt(9, 1)); MAX.valueNoSend(-273.0); RESET.dataPointType(Dpt(1, 15)); RESET.callback(resetCallback); printf("Timeout: %d\n", knx.paramWord(0)); printf("Zykl. senden: %d\n", knx.paramByte(2)); printf("Min/Max senden: %d\n", knx.paramByte(3)); printf("Aenderung senden: %d\n", knx.paramByte(4)); printf("Abgleich %d\n", knx.paramByte(5)); } else println("not configured"); knx.start(); } int main(int argc, char **argv) { printf("main() start.\n"); if (argc > 1) { EraseCode eraseCode = (EraseCode) atoi(argv[2]); print("Performing factory reset with erase code: "); println(eraseCode, HEX); knx.masterReset(eraseCode, 0); } uint8_t inPlain[] { 0x00, 0xFA, 0x01, 0x02, 0x03, 0x04, // KNX Serial 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; // Key uint8_t* outEncoded = NULL; uint8_t len = toBase32(inPlain, sizeof(inPlain), outEncoded, false); printf("FDSK(len: %d): %s\n", len, outEncoded); // Prevent swapping of this process struct sched_param sp; memset(&sp, 0, sizeof(sp)); sp.sched_priority = sched_get_priority_max(SCHED_FIFO); sched_setscheduler(0, SCHED_FIFO, &sp); mlockall(MCL_CURRENT | MCL_FUTURE); // Register signals signal(SIGINT, signalHandler); signal(SIGTERM, signalHandler); knx.platform().cmdLineArgs(argc, argv); setup(); while (loopActive) { knx.loop(); if(knx.configured()) appLoop(); delayMicroseconds(100); } // pinMode() will automatically export GPIO pin in sysfs // Read or writing the GPIO pin for the first time automatically // opens the "value" sysfs file to read or write the GPIO pin value. // The following calls will close the "value" sysfs fiel for the pin // and unexport the GPIO pin. #ifdef USE_RF gpio_unexport(SPI_SS_PIN); gpio_unexport(GPIO_GDO2_PIN); gpio_unexport(GPIO_GDO0_PIN); #endif printf("main() exit.\n"); }