From 4b3e3a371031086da14f6f5a8341d91d08126a58 Mon Sep 17 00:00:00 2001 From: Wolfgang Hottgenroth Date: Sat, 9 Jan 2021 22:01:21 +0100 Subject: [PATCH] initial --- cube/User/Inc/cmdHandler.h | 9 + cube/User/Inc/cmdHelper.h | 23 ++ cube/User/Inc/config.h | 43 ++++ cube/User/Inc/eeprom.h | 50 ++++ cube/User/Inc/frontend.h | 13 + cube/User/Inc/logger.h | 42 ++++ cube/User/Inc/main2.h | 11 + cube/User/Inc/oled-fonts.h | 226 +++++++++++++++++ cube/User/Inc/oled.h | 32 +++ cube/User/Inc/ringbuffer.h | 26 ++ cube/User/Inc/show.h | 20 ++ cube/User/Inc/utils.h | 8 + cube/User/Inc/wizHelper.h | 13 + cube/User/Src/adminCmds.c | 81 ++++++ cube/User/Src/cmdHandler.c | 343 ++++++++++++++++++++++++++ cube/User/Src/config.c | 164 +++++++++++++ cube/User/Src/configCmds.c | 447 +++++++++++++++++++++++++++++++++ cube/User/Src/eeprom.c | 218 +++++++++++++++++ cube/User/Src/frontend.c | 59 +++++ cube/User/Src/logger.c | 198 +++++++++++++++ cube/User/Src/main2.c | 109 +++++++++ cube/User/Src/oled.c | 461 +++++++++++++++++++++++++++++++++++ cube/User/Src/ports.c | 11 + cube/User/Src/regularCmds.c | 57 +++++ cube/User/Src/ringbuffer.c | 75 ++++++ cube/User/Src/show.c | 46 ++++ cube/User/Src/utils.c | 10 + cube/User/Src/wizHelper.c | 232 ++++++++++++++++++ openocd.cfg | 8 + readme.md | 62 +++++ tools/insertMyCode.sh | 83 +++++++ tools/removeGeneratedCode.sh | 3 + tools/startBuildEnv.ps1 | 1 + tools/startBuildEnv.sh | 3 + tools/startCompleteEnv.sh | 32 +++ tools/startTestEnv.ps1 | 1 + tools/startTestEnv.sh | 3 + tools/upload.sh | 8 + 38 files changed, 3231 insertions(+) create mode 100644 cube/User/Inc/cmdHandler.h create mode 100644 cube/User/Inc/cmdHelper.h create mode 100644 cube/User/Inc/config.h create mode 100644 cube/User/Inc/eeprom.h create mode 100644 cube/User/Inc/frontend.h create mode 100644 cube/User/Inc/logger.h create mode 100644 cube/User/Inc/main2.h create mode 100644 cube/User/Inc/oled-fonts.h create mode 100644 cube/User/Inc/oled.h create mode 100644 cube/User/Inc/ringbuffer.h create mode 100644 cube/User/Inc/show.h create mode 100644 cube/User/Inc/utils.h create mode 100644 cube/User/Inc/wizHelper.h create mode 100644 cube/User/Src/adminCmds.c create mode 100644 cube/User/Src/cmdHandler.c create mode 100644 cube/User/Src/config.c create mode 100644 cube/User/Src/configCmds.c create mode 100644 cube/User/Src/eeprom.c create mode 100644 cube/User/Src/frontend.c create mode 100644 cube/User/Src/logger.c create mode 100644 cube/User/Src/main2.c create mode 100644 cube/User/Src/oled.c create mode 100644 cube/User/Src/ports.c create mode 100644 cube/User/Src/regularCmds.c create mode 100644 cube/User/Src/ringbuffer.c create mode 100644 cube/User/Src/show.c create mode 100644 cube/User/Src/utils.c create mode 100644 cube/User/Src/wizHelper.c create mode 100644 openocd.cfg create mode 100644 readme.md create mode 100755 tools/insertMyCode.sh create mode 100755 tools/removeGeneratedCode.sh create mode 100644 tools/startBuildEnv.ps1 create mode 100755 tools/startBuildEnv.sh create mode 100755 tools/startCompleteEnv.sh create mode 100644 tools/startTestEnv.ps1 create mode 100755 tools/startTestEnv.sh create mode 100755 tools/upload.sh diff --git a/cube/User/Inc/cmdHandler.h b/cube/User/Inc/cmdHandler.h new file mode 100644 index 0000000..41e14c0 --- /dev/null +++ b/cube/User/Inc/cmdHandler.h @@ -0,0 +1,9 @@ +#ifndef _CMDHANDLER_H_ +#define _CMDHANDLER_H_ + +#include + +void cmdHandlerInit(); + + +#endif /* _CMDHANDLER_H_ */ diff --git a/cube/User/Inc/cmdHelper.h b/cube/User/Inc/cmdHelper.h new file mode 100644 index 0000000..9bfa723 --- /dev/null +++ b/cube/User/Inc/cmdHelper.h @@ -0,0 +1,23 @@ +#ifndef _CMDHELPER_H_ +#define _CMDHELPER_H_ + +#include +#include + + +typedef bool (*cmdFunc_t)(uint8_t argc, char **args); + +typedef struct { + char name[24]; + char help[512]; + cmdFunc_t cmdFunc; +} cmd_t; + +void sendString(const char *buf); +bool sendFormatString(const char *format, ...); + +const cmd_t *getRegularCommands(); +const cmd_t *getAdminCommands(); +const cmd_t *getConfigCommands(); + +#endif /* _CMDHELPER_H_ */ diff --git a/cube/User/Inc/config.h b/cube/User/Inc/config.h new file mode 100644 index 0000000..e4c261b --- /dev/null +++ b/cube/User/Inc/config.h @@ -0,0 +1,43 @@ +#ifndef _CONFIG_H_ +#define _CONFIG_H_ + +#include +#include +#include + +#define CONFIG_MAGIC 0xdead000a +#define DEVICE_MAGIC 0xaffe0000 + +typedef struct __attribute__((__packed__)) s_configBlock { + uint32_t configMagic; + char deviceName[16]; + uint8_t macAddress[6]; + int32_t frontendThreshold; + char brokerName[64]; + char watchdogTopic[64]; + char startupTopic[64]; + char statusTopic[64]; + char mbusDataTopic[64]; + char syslogServerName[64]; + uint8_t numOfDeviceBlocks; + uint8_t filler[1]; +} t_configBlock; + + +#define MAX_MBUS_DEVICES 16 +#define MBUSDEVICE_NAMELENGTH 16 +#define MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS 4 + +typedef struct __attribute__((__packed__)) s_deviceBlock { + uint32_t deviceMagic; + char deviceName[MBUSDEVICE_NAMELENGTH]; + uint8_t address; + int8_t consideredField[MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS]; + int32_t period; + uint8_t filler[3]; +} t_deviceBlock; + +void configInit(); +t_configBlock* getConfig(); + +#endif /* _CONFIG_H_ */ diff --git a/cube/User/Inc/eeprom.h b/cube/User/Inc/eeprom.h new file mode 100644 index 0000000..fae6274 --- /dev/null +++ b/cube/User/Inc/eeprom.h @@ -0,0 +1,50 @@ +#ifndef EEPROM_H_ +#define EEPROM_H_ + +#include +#include +#include +#include + + + +#define EEPROM_WRITE_BLOCK_SIZE 32 +#define EEPROM_AFTER_WRITE_DELAY 7 + + +typedef struct __attribute__((__packed__)) s_eepromHeader { + uint32_t magic; + uint32_t writeCounter; +} t_eepromHeader; +static_assert((sizeof(t_eepromHeader) <= EEPROM_WRITE_BLOCK_SIZE), "t_eepromHeader has illegal size, must be less than or equal 32"); + +typedef struct __attribute__((__packed__)) s_deviceStats { + uint32_t totalRunningHours; + uint32_t totalPowercycles; + uint32_t totalRequests; + uint32_t totalFailures; +} t_deviceStats; +static_assert((sizeof(t_deviceStats) <= EEPROM_WRITE_BLOCK_SIZE), "t_deviceStats has illegal size, must be less than or equal 32"); + +static_assert((sizeof(t_configBlock) % 32 == 0), "t_configBlock has illegal size, must be dividable by 32"); +static_assert((sizeof(t_deviceBlock) % 32 == 0), "t_deviceBlock has illegal size, must be dividable by 32"); + + +#define EEPROM_BASE_ADDR 0 +#define EEPROM_DEVICE_STATS_ADDR 32 +#define EEPROM_CONFIG_BLOCK_ADDR 64 +#define EEPROM_DEVICE_BLOCK_BASE_ADDR (EEPROM_CONFIG_BLOCK_ADDR + sizeof(t_configBlock)) + + + +void eepromInit(); +void eepromWrite(uint16_t addr, uint8_t *buf, uint8_t len); +void eepromRead(uint16_t addr, uint8_t *buf, uint8_t len); +void eepromSpiTxCpltCallback(SPI_HandleTypeDef *hspi); +t_deviceStats* getGlobalDeviceStats(); +void eepromReadConfigBlock(t_configBlock *destConfigBlock); +void eepromWriteConfigBlock(t_configBlock *srcConfigBlock); +void eepromReadDeviceBlock(uint8_t blockNum, t_deviceBlock *destDeviceBlock); +void eepromWriteDeviceBlock(uint8_t blockNum, t_deviceBlock *srcDeviceBlock); + +#endif /* EEPROM_H_ */ diff --git a/cube/User/Inc/frontend.h b/cube/User/Inc/frontend.h new file mode 100644 index 0000000..9d5ad1d --- /dev/null +++ b/cube/User/Inc/frontend.h @@ -0,0 +1,13 @@ +#ifndef _FRONTEND_H_ +#define _FRONTEND_H_ + +#include +#include + + +void frontendInit(); +void frontendAdcCallback(ADC_HandleTypeDef* hadc); +void frontendEnable(); +void frontendDisable(); + +#endif // _FRONTEND_H_ \ No newline at end of file diff --git a/cube/User/Inc/logger.h b/cube/User/Inc/logger.h new file mode 100644 index 0000000..0ec1775 --- /dev/null +++ b/cube/User/Inc/logger.h @@ -0,0 +1,42 @@ +#ifndef _LOGGER_H_ +#define _LOGGER_H_ + +#include + +#include + + +// Disabling this option is preferred. However, when debugging system hangs +// this option needs to be enabled. +// #define LOGGER_OUTPUT_BY_INTERRUPT + +typedef enum { + LOG_NORMAL, + LOG_HIGH, + LOG_RED, + LOG_GREEN, + LOG_BLUE, + LOG_YELLOW +} t_logColor; + +// initialize the logger, creates a ringbuffer +void logInit(); + +// de-initialize the logger, free the ringbuffer +void logFree(); + +// log a message, make sure it is a null-terminated string +// return value can be ignored, it is only used in test +int logMsg(const char *format, ...); + +int coloredMsg(const t_logColor color, bool syslogToo, const char *format, ...); + +#ifdef LOGGER_OUTPUT_BY_INTERRUPT +void debugTxCpltCallback(UART_HandleTypeDef *huart); +#endif + +#ifndef LOGGER_OUTPUT_BY_INTERRUPT +int logExec(); +#endif + +#endif // _LOGGER_H_ diff --git a/cube/User/Inc/main2.h b/cube/User/Inc/main2.h new file mode 100644 index 0000000..49e85b0 --- /dev/null +++ b/cube/User/Inc/main2.h @@ -0,0 +1,11 @@ +#ifndef _MAIN2_H_ +#define _MAIN2_H_ + + +void my_setup_1(); +void my_setup_2(); +void my_loop(); +void my_errorHandler(); +void SYSTICK_Callback(); + +#endif // _MAIN2_H_ diff --git a/cube/User/Inc/oled-fonts.h b/cube/User/Inc/oled-fonts.h new file mode 100644 index 0000000..b0d935c --- /dev/null +++ b/cube/User/Inc/oled-fonts.h @@ -0,0 +1,226 @@ +/* + * oled-fonts.h + * + * Created on: May 29, 2017 + * Author: wn + */ + +#ifndef OLED_FONTS_H_ +#define OLED_FONTS_H_ + + +/* + * Code found at http://www.instructables.com/id/How-to-use-OLED-display-arduino-module/ + * Thank you very much! + * Adapted from Arduino to STM32 HAL by wollud1969 + */ + + + +const unsigned char F6x8[][6] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // sp + { 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 }, // ! + { 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 }, // " + { 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 }, // # + { 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 }, // $ + { 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 }, // % + { 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 }, // & + { 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 }, // ' + { 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 }, // ( + { 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 }, // ) + { 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 }, // * + { 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 }, // + + { 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 }, // , + { 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 }, // - + { 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 }, // . + { 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 }, // / + { 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E }, // 0 + { 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 }, // 1 + { 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 }, // 2 + { 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 }, // 3 + { 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 }, // 4 + { 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 }, // 5 + { 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 }, // 6 + { 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 }, // 7 + { 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 }, // 8 + { 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E }, // 9 + { 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 }, // : + { 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 }, // ; + { 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 }, // < + { 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 }, // = + { 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 }, // > + { 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 }, // ? + { 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E }, // @ + { 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C }, // A + { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 }, // B + { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 }, // C + { 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C }, // D + { 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 }, // E + { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 }, // F + { 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A }, // G + { 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F }, // H + { 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 }, // I + { 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 }, // J + { 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 }, // K + { 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 }, // L + { 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F }, // M + { 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F }, // N + { 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E }, // O + { 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 }, // P + { 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E }, // Q + { 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 }, // R + { 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 }, // S + { 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 }, // T + { 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F }, // U + { 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F }, // V + { 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F }, // W + { 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 }, // X + { 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 }, // Y + { 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 }, // Z + { 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 }, // [ 91 + { 0x00, 0x02, 0x04 ,0x08, 0x10, 0x20 }, // \92 + { 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 }, // ] + { 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 }, // ^ + { 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 }, // _ + { 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 }, // ' + { 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 }, // a + { 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 }, // b + { 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 }, // c + { 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F }, // d + { 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 }, // e + { 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 }, // f + { 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C }, // g + { 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 }, // h + { 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 }, // i + { 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 }, // j + { 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 }, // k + { 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 }, // l + { 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 }, // m + { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 }, // n + { 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 }, // o + { 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 }, // p + { 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC }, // q + { 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 }, // r + { 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 }, // s + { 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 }, // t + { 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C }, // u + { 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C }, // v + { 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C }, // w + { 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 }, // x + { 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C }, // y + { 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 }, // z + { 0x14, 0x14, 0x14, 0x14, 0x14, 0x14 } // horiz lines +}; + + + + + + + + +const unsigned char F8X16[]= +{ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0 + 0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//!1 + 0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//"2 + 0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//#3 + 0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$4 + 0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//%5 + 0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//&6 + 0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//'7 + 0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//(8 + 0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//)9 + 0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//*10 + 0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+11 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//,12 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//-13 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//.14 + 0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,///15 + 0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//016 + 0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//117 + 0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//218 + 0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//319 + 0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//420 + 0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//521 + 0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//622 + 0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//723 + 0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//824 + 0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//925 + 0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//:26 + 0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//;27 + 0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//<28 + 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//=29 + 0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//>30 + 0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//?31 + 0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@32 + 0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A33 + 0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B34 + 0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C35 + 0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D36 + 0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E37 + 0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F38 + 0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G39 + 0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H40 + 0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I41 + 0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J42 + 0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K43 + 0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L44 + 0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M45 + 0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N46 + 0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O47 + 0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P48 + 0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q49 + 0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R50 + 0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S51 + 0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T52 + 0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U53 + 0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V54 + 0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W55 + 0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X56 + 0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y57 + 0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z58 + 0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[59 + 0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\60 + 0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//]61 + 0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^62 + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_63 + 0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//`64 + 0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a65 + 0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b66 + 0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c67 + 0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d68 + 0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e69 + 0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f70 + 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g71 + 0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h72 + 0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i73 + 0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j74 + 0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k75 + 0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l76 + 0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m77 + 0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n78 + 0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o79 + 0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p80 + 0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q81 + 0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r82 + 0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s83 + 0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t84 + 0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//unsigned char5 + 0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v86 + 0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w87 + 0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x88 + 0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y89 + 0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z90 + 0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{91 + 0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//|92 + 0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//}93 + 0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~94 + +}; + + + + +#endif /* OLED_FONTS_H_ */ diff --git a/cube/User/Inc/oled.h b/cube/User/Inc/oled.h new file mode 100644 index 0000000..3a4c17c --- /dev/null +++ b/cube/User/Inc/oled.h @@ -0,0 +1,32 @@ +/* + * oled.h + * + * Created on: May 29, 2017 + * Author: wn + */ + +#ifndef OLED_H_ +#define OLED_H_ + + +/* + * Code found at http://www.instructables.com/id/How-to-use-OLED-display-arduino-module/ + * Thank you very much! + * Adapted from Arduino to STM32 HAL by wollud1969 + */ + + + +typedef enum { + OLED_SCREEN0 = 0, + OLED_SCREEN1 +} oledScreen_t; + +void oledInit(void); +void oledClearActiveScreen(); +void oledClearAllScreens(); +void oledPrint(oledScreen_t screen, char msg[]); +void oledPrintf(oledScreen_t screen, const char *format, ...); +void oledSetActiveScreen(oledScreen_t screen); + +#endif /* OLED_H_ */ diff --git a/cube/User/Inc/ringbuffer.h b/cube/User/Inc/ringbuffer.h new file mode 100644 index 0000000..6d48ab6 --- /dev/null +++ b/cube/User/Inc/ringbuffer.h @@ -0,0 +1,26 @@ +#ifndef _RINGBUFFER_H_ +#define _RINGBUFFER_H_ + +#include +#include + + +typedef struct { + uint32_t bufferReadIdx; + uint32_t bufferWriteIdx; + uint32_t bufferSize; + uint8_t* buffer; +} ringbuffer_t; + +void ringbufferInit(ringbuffer_t *handle, uint32_t bufferSize); +void ringbufferFree(ringbuffer_t *handle); + +int ringbufferPut(ringbuffer_t *handle, uint8_t *data, uint32_t dataLen); +bool ringbufferEmpty(ringbuffer_t *handle); +int ringbufferGetOne(ringbuffer_t *handle); // if positive, cast to uint8_t and be happy, if negative error + +// not yet implemented +uint8_t *ringbufferGet(ringbuffer_t *handle, uint32_t dataLen); + + +#endif // _RINGBUFFER_H_ diff --git a/cube/User/Inc/show.h b/cube/User/Inc/show.h new file mode 100644 index 0000000..7ccfa73 --- /dev/null +++ b/cube/User/Inc/show.h @@ -0,0 +1,20 @@ +#ifndef _SHOW_H_ +#define _SHOW_H_ + + +#include + +typedef enum { + DEBUG_1 = 0, + DEBUG_2 = 1, + LED_RED = 2, + LED_GREEN = 3 +} signalPin_t; + +typedef enum { ON, OFF, TOGGLE, BLINK } signalAction_t; + +void showInit(); +void show(signalPin_t signalPin, signalAction_t action); + + +#endif // _SHOW_H_ diff --git a/cube/User/Inc/utils.h b/cube/User/Inc/utils.h new file mode 100644 index 0000000..79e537c --- /dev/null +++ b/cube/User/Inc/utils.h @@ -0,0 +1,8 @@ +#ifndef _UTILS_H_ +#define _UTILS_H_ + +#include + +void activeDelay(uint8_t delay_ms); + +#endif // _UTILS_H_ \ No newline at end of file diff --git a/cube/User/Inc/wizHelper.h b/cube/User/Inc/wizHelper.h new file mode 100644 index 0000000..864cc61 --- /dev/null +++ b/cube/User/Inc/wizHelper.h @@ -0,0 +1,13 @@ +#ifndef _WIZHELPER_H_ +#define _WIZHELPER_H_ + +#include +#include + + +int wizInit(); +bool isNetworkAvailable(); +uint8_t* wizGetIPAddress(); +bool wizDnsQuery(char *name, uint8_t *ip); + +#endif // _WIZHELPER_H_ \ No newline at end of file diff --git a/cube/User/Src/adminCmds.c b/cube/User/Src/adminCmds.c new file mode 100644 index 0000000..92e9dca --- /dev/null +++ b/cube/User/Src/adminCmds.c @@ -0,0 +1,81 @@ +#include +#include +#include + +#include +#include + + +// clear statistics +static bool clearCmd(uint8_t argc, char **args) { + t_mbusCommStats zeroedStats = { .mbusRequestCnt = 0, .mbusErrorCnt = 0, .uartOctetCnt = 0, .uartOverrunCnt = 0, .uartFramingErrCnt = 0, .uartParityErrCnt = 0, .uartNoiseErrCnt = 0 }; + mbusCommSetStats(zeroedStats); + coloredMsg(LOG_YELLOW, true, "ch cc global statistics cleared"); + return true; +} + +static bool mbusCommEnableCmd(uint8_t argc, char **args) { + bool retCode = true; + if (argc == 2) { + if (0 == strcmp("false", args[1])) { + mbusCommEnable(false); + coloredMsg(LOG_YELLOW, true, "ch mcec Meterbus communication disabled"); + } else if (0 == strcmp("true", args[1])) { + mbusCommEnable(true); + coloredMsg(LOG_YELLOW, true, "ch mcec Meterbus communication enabled"); + } else { + retCode = false; + } + } else { + retCode = false; + } + return retCode; +} + +static bool loopEnableCmd(uint8_t argc, char **args) { + bool retCode = true; + if (argc == 2) { + if (0 == strcmp("false", args[1])) { + loopDisable(); + coloredMsg(LOG_YELLOW, true, "ch lec loop disabled"); + } else if (0 == strcmp("true", args[1])) { + loopEnable(); + coloredMsg(LOG_YELLOW, true, "ch lec loop enabled"); + } else { + retCode = false; + } + } else { + retCode = false; + } + return retCode; +} + + + +const cmd_t ADMIN_COMMANDS[] = { + { .name = "clear", .cmdFunc = clearCmd, + .help = \ + "clear ................................ Clears the global Meterbus\n\r" \ + " statistics\n\r" + }, + { .name = "mbusCommEnable", .cmdFunc = mbusCommEnableCmd, + .help = \ + "mbusCommEnable true|false ............ Enables or disables the Meterbus\n\r" \ + " communication\n\r" + }, + { .name = "loopEnable", .cmdFunc = loopEnableCmd, + .help = \ + "loopEnable true|false ................ Enables or disables the loop.\n\r" \ + " Disable Meterbus communication\n\r" \ + " first if you want to disable the\n\r" \ + " for a longer time, otherwise the\n\r" \ + " request will enable it again\n\r" + }, + { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL } +}; + + + +const cmd_t *getAdminCommands() { + return ADMIN_COMMANDS; +} \ No newline at end of file diff --git a/cube/User/Src/cmdHandler.c b/cube/User/Src/cmdHandler.c new file mode 100644 index 0000000..6985011 --- /dev/null +++ b/cube/User/Src/cmdHandler.c @@ -0,0 +1,343 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + + +extern const uint8_t CMD_SOCK; + +const uint16_t cmdPort = 23; + +typedef enum { + CH_INIT, + CH_LISTEN, + CH_WAITING, + CH_BANNER, + CH_PROMPT, + CH_RECEIVE, + CH_DISCONNECT, + CH_DISCONNECT_WAIT, + CH_ERROR +} chState_t; + +void sendString(const char *buf) { + send(CMD_SOCK, (uint8_t*)buf, strlen(buf)); +} + +bool sendFormatString(const char *format, ...) { + bool retCode = true; + va_list vl; + va_start(vl, format); + char buf[4096]; + int vcnt = vsnprintf(buf, sizeof(buf), format, vl); + retCode = (vcnt < sizeof(buf)); + va_end(vl); + sendString(buf); + return retCode; +} + +// returns 0 to continue waiting for input +// returns -1 to close the connection +// returns 1 to toggle to admin mode +// returns 2 to toggle to config mode +// returns 3 to toggle back to default mode +static int8_t cmdExecuteCommand(uint8_t *cmdLine, bool resetSpecialModes) { + const static char HELP_MSG[] = \ + "Usage\n\r" \ + "\n\r" \ + "help ................................. Show this help page\n\r" \ + "quit ................................. Terminate the console session\n\r" \ + "enable ............................... Enable admin mode\n\r" \ + "config ............................... Enter configuration mode\n\r" \ + "disable .............................. Disable admin/config mode\n\r" \ + ; + const static char CONFIG_INTRO_MSG[] = \ + "In configuration mode each command changing the configuration\n\r" \ + "will save changes directly to the EEPROM.\n\r" \ + "However, the system will only consider these changes after a\n\r" \ + "restart since only in this sitution the EEPROM is read.\n\r" \ + "\n\r" \ + ; + const static char GOODBYE_MSG[] = "Good bye\n\r"; + const static char OK_MSG[] = "OK\n\r"; + const static char FAILED_MSG[] = "Failed\n\r"; + const static char UNKNOWN_COMMAND[] = "Unknown command\n\r"; + uint8_t *messageToSend = NULL; + + static bool adminMode = false; + static bool configMode = false; + + if (resetSpecialModes) { + adminMode = false; + configMode = false; + } + + cmd_t const * commands = getRegularCommands(); + if (adminMode) { + commands = getAdminCommands(); + } else if (configMode) { + commands = getConfigCommands(); + } + + coloredMsg(LOG_YELLOW, true, "ch cec cmdLine is %s", cmdLine);; + + #define MAX_NUM_OF_ARGS 8 + char *args[MAX_NUM_OF_TASKS]; + uint8_t argc = 0; + char *inCmdLine = (char*)cmdLine; + do { + args[argc++] = strtok(inCmdLine, " "); + inCmdLine = NULL; + } while (args[argc - 1] != NULL); + if (argc > 0) { + argc--; + } + char *cmd = args[0]; + + int8_t retCode = 0; + coloredMsg(LOG_YELLOW, true, "ch cec cmd is %s, number of arguments %d", cmd, argc); + + if (0 == strcmp(cmd, "quit")) { + messageToSend = (uint8_t*)GOODBYE_MSG; + retCode = -1; + } else if (0 == strcmp(cmd, "help")) { + if (configMode) { + sendString(CONFIG_INTRO_MSG); + } + sendString(HELP_MSG); + uint8_t cmdIdx = 0; + while (true) { + cmd_t command = commands[cmdIdx]; + if (0 == strcmp("END_OF_CMDS", command.name)) { + break; + } + sendString(command.help); + cmdIdx++; + } + messageToSend = NULL; + } else if (0 == strcmp(cmd, "enable")) { + coloredMsg(LOG_YELLOW, true, "ch cec enable admin mode"); + adminMode = true; + retCode = 1; + } else if (0 == strcmp(cmd, "disable")) { + coloredMsg(LOG_YELLOW, true, "ch cec disable admin mode"); + adminMode = false; + configMode = false; + retCode = 3; + } else if (0 == strcmp(cmd, "config")) { + coloredMsg(LOG_YELLOW, true, "ch cec enable config mode"); + configMode = true; + retCode = 2; + } else { + uint8_t cmdIdx = 0; + while (true) { + cmd_t command = commands[cmdIdx]; + if (0 == strcmp("END_OF_CMDS", command.name)) { + messageToSend = (uint8_t*) UNKNOWN_COMMAND; + break; + } + if (0 == strcmp(cmd, command.name)) { + messageToSend = command.cmdFunc(argc, args) ? (uint8_t*)OK_MSG : (uint8_t*)FAILED_MSG; + break; + } + cmdIdx++; + } + } + + if (messageToSend) { + coloredMsg(LOG_YELLOW, true, "ch cec command finally returns %s", messageToSend); + send(CMD_SOCK, messageToSend, strlen((char*)messageToSend)); + } + + return retCode; +} + +static void cmdHandlerEngine(void *handle) { + static uint8_t receiveBuffer[256]; + + static chState_t state = CH_INIT; + static bool resetSpecialModes = false; + + static char banner[] = \ + "MBGW3\n\r" \ + "Type help for usage help\n\r" \ + "or quit to close the connection.\n\r"; + + static char *prompt; + static char defaultPrompt[] = " > "; + static char adminPrompt[] = " (admin) # "; + static char configPrompt[] = " (config) $ "; + + + int8_t res = 0; + uint8_t sockState; + int32_t resultSend; + int16_t receivedOctets; + int32_t resultRecv; + uint8_t resultDisconnect; + + + if (isNetworkAvailable()) { + switch (state) { + case CH_INIT: + coloredMsg(LOG_YELLOW, false, "ch che initializing socket"); + + res = socket(CMD_SOCK, Sn_MR_TCP, cmdPort, SF_IO_NONBLOCK); + coloredMsg(LOG_YELLOW, false, "ch che socket returns %d", res); + + if (res == CMD_SOCK) { + coloredMsg(LOG_YELLOW, false, "ch che socket is initialized"); + state = CH_LISTEN; + } else { + state = CH_ERROR; + } + break; + + case CH_LISTEN: + coloredMsg(LOG_YELLOW, false, "ch che listening"); + + res = listen(CMD_SOCK); + coloredMsg(LOG_YELLOW, false, "ch che listen returns %d", res); + + if (res == SOCK_OK) { + coloredMsg(LOG_YELLOW, false, "ch che ok, waiting for established"); + state = CH_WAITING; + } else { + state = CH_ERROR; + } + break; + + case CH_WAITING: + sockState = getSn_SR(CMD_SOCK); + if (sockState != SOCK_LISTEN) { + coloredMsg(LOG_YELLOW, false, "ch che socket state is 0x%02x", sockState); + state = CH_DISCONNECT; + } + + if (sockState == SOCK_ESTABLISHED) { + coloredMsg(LOG_YELLOW, true, "ch che connection is established"); + state = CH_BANNER; + } + break; + + case CH_BANNER: + coloredMsg(LOG_YELLOW, false, "ch che send banner"); + sockState = getSn_SR(CMD_SOCK); + if (sockState != SOCK_ESTABLISHED) { + coloredMsg(LOG_YELLOW, true, "ch che sockState is 0x%02x when trying to send banner", sockState); + state = CH_DISCONNECT; + } else { + resultSend = send(CMD_SOCK, (uint8_t*)banner, strlen(banner)); + coloredMsg(LOG_YELLOW, false, "ch che sent banner, send returns 0x%02x", resultSend); + prompt = defaultPrompt; + resetSpecialModes = true; + state = CH_PROMPT; + } + break; + + case CH_PROMPT: + coloredMsg(LOG_YELLOW, false, "ch che send prompt"); + sockState = getSn_SR(CMD_SOCK); + if (sockState != SOCK_ESTABLISHED) { + coloredMsg(LOG_YELLOW, true, "ch che sockState is 0x%02x when trying to send promt", sockState); + state = CH_DISCONNECT; + } else { + sendFormatString("%s %s", getConfig()->deviceName, prompt); + coloredMsg(LOG_YELLOW, false, "ch che sent prompt %s %s", getConfig()->deviceName, prompt); + state = CH_RECEIVE; + } + break; + + case CH_RECEIVE: + sockState = getSn_SR(CMD_SOCK); + if (sockState != SOCK_ESTABLISHED) { + coloredMsg(LOG_YELLOW, true, "ch che sockState is 0x%02x when trying to receive something", sockState); + state = CH_DISCONNECT; + } else { + receivedOctets = getSn_RX_RSR(CMD_SOCK); + + if (receivedOctets > 0) { + memset(receiveBuffer, 0, sizeof(receiveBuffer)); + resultRecv = recv(CMD_SOCK, receiveBuffer, sizeof(receiveBuffer)); + coloredMsg(LOG_YELLOW, false, "ch che recv returns 0x%02x", resultRecv); + if (resultRecv > 0) { + if ((receiveBuffer[strlen((char*)receiveBuffer) - 1] == 0x0a) || + (receiveBuffer[strlen((char*)receiveBuffer) - 1] == 0x0d)) { + receiveBuffer[strlen((char*)receiveBuffer) - 1] = 0; + } + if ((receiveBuffer[strlen((char*)receiveBuffer) - 1] == 0x0a) || + (receiveBuffer[strlen((char*)receiveBuffer) - 1] == 0x0d)) { + receiveBuffer[strlen((char*)receiveBuffer) - 1] = 0; + } + coloredMsg(LOG_YELLOW, false, "ch che received: %s", receiveBuffer); + int8_t resCEC = cmdExecuteCommand(receiveBuffer, resetSpecialModes); + resetSpecialModes = false; + switch (resCEC) { + case 0: + state = CH_PROMPT; + break; + case -1: + state = CH_DISCONNECT; + break; + case 1: + prompt = adminPrompt; + state = CH_PROMPT; + break; + case 2: + prompt = configPrompt; + state = CH_PROMPT; + break; + case 3: + prompt = defaultPrompt; + state = CH_PROMPT; + break; + } + } + } + } + break; + + case CH_DISCONNECT: + coloredMsg(LOG_YELLOW, true, "ch che close our end"); + resultDisconnect = disconnect(CMD_SOCK); + coloredMsg(LOG_YELLOW, true, "ch che disconnect returns 0x%02x", resultDisconnect); + state = CH_DISCONNECT_WAIT; + break; + + case CH_DISCONNECT_WAIT: + //coloredMsg(LOG_YELLOW, false, "ch che waiting after disconnect"); + sockState = getSn_SR(CMD_SOCK); + //coloredMsg(LOG_YELLOW, false, "ch che sockState is 0x%02x", sockState); + if (sockState == SOCK_CLOSED) { + coloredMsg(LOG_YELLOW, true, "ch che socket is closed now"); + state = CH_INIT; + } + break; + + + case CH_ERROR: + coloredMsg(LOG_YELLOW, true, "ch che error state, will stop here"); + schDel(cmdHandlerEngine, NULL); + state = CH_INIT; + schAdd(cmdHandlerEngine, NULL, 5000, 100); + coloredMsg(LOG_YELLOW, true, "ch che restart command handler engine in 5s"); + break; + } + } +} + +void cmdHandlerInit() { + schAdd(cmdHandlerEngine, NULL, 0, 100); +} \ No newline at end of file diff --git a/cube/User/Src/config.c b/cube/User/Src/config.c new file mode 100644 index 0000000..b43f431 --- /dev/null +++ b/cube/User/Src/config.c @@ -0,0 +1,164 @@ +#include +#include + +#include +#include +#include +#include + + + +#define NUM_OF_DEFAULT_DEVICES 8 +t_deviceBlock defaultDeviceBlock[] = { + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Total", + .address = 80, + .consideredField = { 0, 17, -1, -1 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Computer", + .address = 85, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Dryer", + .address = 81, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Laundry", + .address = 82, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Dishwasher", + .address = 83, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Light", + .address = 84, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Freezer", + .address = 86, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + }, + { + .deviceMagic = DEVICE_MAGIC, + .deviceName = "Fridge", + .address = 87, + .consideredField = { 0, 4, 2, 3 }, + .period = 10, + .filler = { 0, 0, 0 } + } +}; + + +t_configBlock defaultConfigBlock = { + .configMagic = CONFIG_MAGIC, + .deviceName = "MBGW3", + .macAddress = { 0x00, 0xA0, 0x57, 0x05, 0x3E, 0x0D }, + .frontendThreshold = 240, + .brokerName = "mqttbroker", + .watchdogTopic = "IoT/Watchdog", + .startupTopic = "IoT/MBGW3/Startup", + .statusTopic = "IoT/MBGW3/Status", + .mbusDataTopic = "IoT/MBGW3/Measurement", + .syslogServerName = "syslogserver", + .numOfDeviceBlocks = NUM_OF_DEFAULT_DEVICES, + .filler = { 0 } +}; + + + +t_configBlock mainConfigBlock; + + + +t_configBlock* getConfig() { + return &mainConfigBlock; +} + + +void configInit() { + coloredMsg(LOG_BLUE, false, "cfg ci Reading configuration block from eeprom"); + eepromReadConfigBlock(&mainConfigBlock); + + if (mainConfigBlock.configMagic != CONFIG_MAGIC) { + coloredMsg(LOG_BLUE, false, "cfg ci Invalid configuration block read from eeprom"); + + eepromWriteConfigBlock(&defaultConfigBlock); + coloredMsg(LOG_BLUE, false, "cfg ci Default configuration block written to eeprom"); + + for (uint8_t i = 0; i < NUM_OF_DEFAULT_DEVICES; i++) { + eepromWriteDeviceBlock(i, &defaultDeviceBlock[i]); + } + coloredMsg(LOG_BLUE, false, "cfg ci Default device blocks written to eeprom"); + + coloredMsg(LOG_BLUE, false, "cfg ci Reading configuration block from eeprom again"); + eepromReadConfigBlock(&mainConfigBlock); + } + coloredMsg(LOG_BLUE, false, "cfg ci configMagic: %lx", mainConfigBlock.configMagic); + coloredMsg(LOG_BLUE, false, "cfg ci deviceName: %s", mainConfigBlock.deviceName); + coloredMsg(LOG_BLUE, false, "cfg ci MAC address: %02x:%02x:%02x:%02x:%02x:%02x", mainConfigBlock.macAddress[0], + mainConfigBlock.macAddress[1], + mainConfigBlock.macAddress[2], + mainConfigBlock.macAddress[3], + mainConfigBlock.macAddress[4], + mainConfigBlock.macAddress[5]); + coloredMsg(LOG_BLUE, false, "cfg ci frontend threshold: %ld", mainConfigBlock.frontendThreshold); + coloredMsg(LOG_BLUE, false, "cfg ci broker: %s", mainConfigBlock.brokerName); + coloredMsg(LOG_BLUE, false, "cfg ci watchdogTopic: %s", mainConfigBlock.watchdogTopic); + coloredMsg(LOG_BLUE, false, "cfg ci startupTopic: %s", mainConfigBlock.startupTopic); + coloredMsg(LOG_BLUE, false, "cfg ci statusTopic: %s", mainConfigBlock.statusTopic); + coloredMsg(LOG_BLUE, false, "cfg ci mbusDataTopic: %s", mainConfigBlock.mbusDataTopic); + coloredMsg(LOG_BLUE, false, "cfg ci syslog server: %s", mainConfigBlock.syslogServerName); + coloredMsg(LOG_BLUE, false, "cfg ci device block cnt: %d", mainConfigBlock.numOfDeviceBlocks); + + for (uint8_t i = 0; i < mainConfigBlock.numOfDeviceBlocks; i++) { + t_deviceBlock tmpDeviceBlock; + eepromReadDeviceBlock(i, &tmpDeviceBlock); + if (tmpDeviceBlock.deviceMagic == DEVICE_MAGIC) { + coloredMsg(LOG_BLUE, false, "cfg ci device %d: ", i); + coloredMsg(LOG_BLUE, false, " Name: %s, Address: %d, Period: %d", + tmpDeviceBlock.deviceName, tmpDeviceBlock.address, tmpDeviceBlock.period); + coloredMsg(LOG_BLUE, false, " Considered Fields: %d %d %d %d", + tmpDeviceBlock.consideredField[0], + tmpDeviceBlock.consideredField[1], + tmpDeviceBlock.consideredField[2], + tmpDeviceBlock.consideredField[3]); + if (tmpDeviceBlock.period == 0) { + coloredMsg(LOG_BLUE, false, " device is marked as inactive"); + } else if (tmpDeviceBlock.period == -1) { + coloredMsg(LOG_BLUE, false, " device is marked as deleted"); + } else { + mbusCommAddDevice(&tmpDeviceBlock); + } + } else { + coloredMsg(LOG_BLUE, false, "magic of device %d does not match, ignored", i); + } + } +} \ No newline at end of file diff --git a/cube/User/Src/configCmds.c b/cube/User/Src/configCmds.c new file mode 100644 index 0000000..347f373 --- /dev/null +++ b/cube/User/Src/configCmds.c @@ -0,0 +1,447 @@ +#include +#include + +#include +#include + +#include +#include + + + +static bool showConfigCmd(uint8_t argc, char **args) { + bool retCode = true; + + t_configBlock configBlock; + eepromReadConfigBlock(&configBlock); + sendString("This is the saved configuration.\n\r"); + sendString("It is not necessarily the active configuration.\n\r"); + sendFormatString("configMagic: %lx\n\r", configBlock.configMagic); + sendFormatString("deviceName: %s\n\r", configBlock.deviceName); + sendFormatString("MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n\r", configBlock.macAddress[0], + configBlock.macAddress[1], + configBlock.macAddress[2], + configBlock.macAddress[3], + configBlock.macAddress[4], + configBlock.macAddress[5]); + sendFormatString("frontend threshold: %ld\n\r", configBlock.frontendThreshold); + sendFormatString("broker: %s\n\r", configBlock.brokerName); + sendFormatString("watchdogTopic: %s\n\r", configBlock.watchdogTopic); + sendFormatString("startupTopic: %s\n\r", configBlock.startupTopic); + sendFormatString("statusTopic: %s\n\r", configBlock.statusTopic); + sendFormatString("mbusDataTopic: %s\n\r", configBlock.mbusDataTopic); + sendFormatString("syslog server: %s\n\r", configBlock.syslogServerName); + sendFormatString("device block cnt: %d\n\r", configBlock.numOfDeviceBlocks); + + for (uint8_t i = 0; i < configBlock.numOfDeviceBlocks; i++) { + t_deviceBlock tmpDeviceBlock; + eepromReadDeviceBlock(i, &tmpDeviceBlock); + if (tmpDeviceBlock.deviceMagic == DEVICE_MAGIC) { + sendFormatString("device %d: \n\r", i); + sendFormatString(" Name: %s, Address: %d, Period: %d\n\r", + tmpDeviceBlock.deviceName, tmpDeviceBlock.address, tmpDeviceBlock.period); + sendFormatString(" Considered Fields: %d %d %d %d\n\r", + tmpDeviceBlock.consideredField[0], + tmpDeviceBlock.consideredField[1], + tmpDeviceBlock.consideredField[2], + tmpDeviceBlock.consideredField[3]); + if (tmpDeviceBlock.deviceMagic != DEVICE_MAGIC) { + sendString(" DEVICE MAGIC DOES NOT MATCH\n\r"); + } + } + } + + return retCode; +} + + + + +static bool setStringParameterCmd(uint8_t argc, char **args, size_t offset, size_t length) { + bool retCode = true; + + t_configBlock configBlock; + char *parameterName = args[1]; + char *newParameterValue = args[2]; + if (strlen(newParameterValue) >= length) { + sendString("given new value for is too long\n\r"); + retCode = false; + } else { + sendFormatString("set %s to %s\n\r", parameterName, newParameterValue); + + eepromReadConfigBlock(&configBlock); + strcpy((((char*)&configBlock) + offset), newParameterValue); + eepromWriteConfigBlock(&configBlock); + } + + return retCode; +} + +static bool setInt32ParameterCmd(uint8_t argc, char **args, size_t offset, int32_t minV, int32_t maxV) { + bool retCode = true; + + t_configBlock configBlock; + char *parameterName = args[1]; + char *newParameterValue = args[2]; + long int value = strtol(newParameterValue, NULL, 10); + if (value < minV) { + sendString("value is too small\n\r"); + retCode = false; + } else if (value > maxV) { + sendString("value is too large\n\r"); + } else { + int32_t v = (int32_t) value; + sendFormatString("set %s to %ld\n\r", parameterName, v); + + eepromReadConfigBlock(&configBlock); + *((int32_t*)(((uint8_t*)&configBlock) + offset)) = v; + eepromWriteConfigBlock(&configBlock); + } + + return retCode; +} + + +static bool setDeviceNameCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, deviceName), + sizeof(((t_configBlock*)0)->deviceName)); +} + +static bool setBrokerNameCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, brokerName), + sizeof(((t_configBlock*)0)->brokerName)); +} + +static bool setSyslogServerCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, syslogServerName), + sizeof(((t_configBlock*)0)->syslogServerName)); +} + +static bool setWatchdogTopicCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, watchdogTopic), + sizeof(((t_configBlock*)0)->watchdogTopic)); +} + +static bool setStartupTopicCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, startupTopic), + sizeof(((t_configBlock*)0)->startupTopic)); +} + +static bool setStatusTopicCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, statusTopic), + sizeof(((t_configBlock*)0)->statusTopic)); +} + +static bool setMbusDataTopicCmd(uint8_t argc, char **args) { + return setStringParameterCmd(argc, args, + offsetof(t_configBlock, mbusDataTopic), + sizeof(((t_configBlock*)0)->mbusDataTopic)); +} + +static bool setFrontendThresholdCmd(uint8_t argc, char **args) { + return setInt32ParameterCmd(argc, args, + offsetof(t_configBlock, frontendThreshold), + 0, 1023); +} + +static bool makeDevice(uint8_t argOffset, uint8_t argc, char **args, t_deviceBlock *deviceBlock) { + if (strcmp(args[1], "help") == 0) { + sendString("deviceName address period field1 field2 field3 field4\n\r"); + sendString("deviceName: max. length = 16\n\r"); + sendString("address: between 1 and 254\n\r"); + sendString("period: in seconds, between 0 (disabled) and 86400 (1 day)\n\r"); + sendString("fields: between -1 (not considered) and 254\n\r"); + return false; + } + + + if ((argc - argOffset) != 8) { + sendString("wrong number of arguments\n\r"); + return false; + } + + char *deviceName = args[1 + argOffset]; + if (strcmp(deviceName, "*") != 0) { + if (strlen(deviceName) >= sizeof(deviceBlock->deviceName)) { + sendString("devicename too long\n\r"); + return false; + } + strcpy(deviceBlock->deviceName, deviceName); + } + + char *rawAddressStr = args[2 + argOffset]; + if (strcmp(rawAddressStr, "*") != 0) { + long int rawAddress = strtol(rawAddressStr, NULL, 10); + if (rawAddress < 1 || rawAddress > 254) { + sendString("illegal address\n\r"); + return false; + } + deviceBlock->address = (uint8_t)rawAddress; + } + + char *rawPeriodStr = args[3 + argOffset]; + if (strcmp(rawPeriodStr, "*") != 0) { + long int rawPeriod = strtol(rawPeriodStr, NULL, 10); + if (rawPeriod < 0 || rawPeriod > 86400) { + sendString("illegal period\n\r"); + return false; + } + deviceBlock->period = (int32_t) rawPeriod; + } + + for (uint8_t i = 0; i < MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS; i++) { + char *rawFieldNumStr = args[4 + i + argOffset]; + if (strcmp(rawFieldNumStr, "*") != 0) { + long int rawFieldNum = strtol(rawFieldNumStr, NULL, 10); + if (rawFieldNum < -1 || rawFieldNum > 127) { + sendString("illegal considered field index\n\r"); + return false; + } + deviceBlock->consideredField[i] = (int8_t) rawFieldNum; + } + } + + return true; +} + +static bool addDeviceCmd(uint8_t argc, char **args) { + t_deviceBlock deviceBlock = { .deviceName = "", .address = 0, .period = 0, .consideredField = { -1, -1, -1, -1}}; + bool retCode = makeDevice(0, argc, args, &deviceBlock); + if (retCode) { + sendString("New device would be:\n\r"); + sendFormatString(" Name: %s, Address: %d, Period: %d\n\r", + deviceBlock.deviceName, deviceBlock.address, deviceBlock.period); + for (uint8_t i = 0; i < MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS; i++) { + sendFormatString(" Considered field: %d\n\r", deviceBlock.consideredField[i]); + } + } + deviceBlock.deviceMagic = DEVICE_MAGIC; + + uint8_t index = getConfig()->numOfDeviceBlocks; + for (uint8_t i = 0; i < getConfig()->numOfDeviceBlocks; i++) { + t_deviceBlock tmpDeviceBlock; + eepromReadDeviceBlock(i, &tmpDeviceBlock); + if (tmpDeviceBlock.period == -1) { + index = i; + break; + } + } + eepromWriteDeviceBlock(index, &deviceBlock); + if (index == getConfig()->numOfDeviceBlocks) { + t_configBlock configBlock; + eepromReadConfigBlock(&configBlock); + configBlock.numOfDeviceBlocks += 1; + eepromWriteConfigBlock(&configBlock); + } + + return retCode; +} + +static bool deleteDeviceCmd(uint8_t argc, char **args) { + long int rawIndex = strtol(args[1], NULL, 10); + if (rawIndex < 0 || rawIndex > getConfig()->numOfDeviceBlocks) { + sendFormatString("illegal index, must be greater 0 and less %d\n\r", getConfig()->numOfDeviceBlocks); + return false; + } + uint8_t index = (uint8_t) rawIndex; + + t_deviceBlock deviceBlock; + eepromReadDeviceBlock(index, &deviceBlock); + deviceBlock.period = -1; + eepromWriteDeviceBlock(index, &deviceBlock); + + return true; +} + +static bool changeDeviceCmd(uint8_t argc, char **args) { + if (strcmp(args[1], "help") == 0) { + sendString("First argument: index of device in list\n\r"); + sendFormatString("Between 0 and %d\n\r", getConfig()->numOfDeviceBlocks); + sendString("For further arguments use a * to keep the value\n\r"); + return makeDevice(0, argc, args, NULL); + } + + long int rawIndex = strtol(args[1], NULL, 10); + if (rawIndex < 0 || rawIndex > getConfig()->numOfDeviceBlocks) { + sendFormatString("illegal index, must be greater 0 and less %d\n\r", getConfig()->numOfDeviceBlocks); + return false; + } + uint8_t index = (uint8_t) rawIndex; + + t_deviceBlock deviceBlock; + eepromReadDeviceBlock(index, &deviceBlock); + + bool retCode = makeDevice(1, argc, args, &deviceBlock); + if (retCode) { + sendString("Changed device will be:\n\r"); + sendFormatString(" Index: %d\n\r", index); + sendFormatString(" Name: %s, Address: %d, Period: %d\n\r", + deviceBlock.deviceName, deviceBlock.address, deviceBlock.period); + for (uint8_t i = 0; i < MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS; i++) { + sendFormatString(" Considered field: %d\n\r", deviceBlock.consideredField[i]); + } + if (deviceBlock.period == 0) { + sendString(" Device is marked as inactive\n\r"); + } + eepromWriteDeviceBlock(index, &deviceBlock); + } + + return retCode; +} + +static bool listDevicesCmd(uint8_t argc, char **args) { + for (uint8_t i = 0; i < getConfig()->numOfDeviceBlocks; i++) { + t_deviceBlock deviceBlock; + eepromReadDeviceBlock(i, &deviceBlock); + sendFormatString("Index: %d\n\r", i); + sendFormatString(" Name: %s, Address: %d, Period: %d\n\r", + deviceBlock.deviceName, deviceBlock.address, deviceBlock.period); + for (uint8_t i = 0; i < MBUSDEVICE_NUM_OF_CONSIDEREDFIELDS; i++) { + sendFormatString(" Considered field: %d\n\r", deviceBlock.consideredField[i]); + } + if (deviceBlock.period == 0) { + sendString(" Device is marked as inactive\n\r"); + } else if (deviceBlock.period == -1) { + sendString(" Device is marked as deleted\n\r"); + } + } + return true; +} + + +const static cmd_t SET_COMMANDS[] = { + { .name = "devicename", .cmdFunc = setDeviceNameCmd, + .help = \ + "devicename ........................... Name of this device\n\r" + }, + { .name = "brokername", .cmdFunc = setBrokerNameCmd, + .help = \ + "brokername ........................... Hostname of the MQTT broker\n\r" + }, + { .name = "syslogserver", .cmdFunc = setSyslogServerCmd, + .help = \ + "syslogserver ......................... Hostname of the Syslog server\n\r" + }, + { .name = "watchdogtopic", .cmdFunc = setWatchdogTopicCmd, + .help = \ + "watchdogtopic ........................ Watchdog Topic\n\r" + }, + { .name = "startuptopic", .cmdFunc = setStartupTopicCmd, + .help = \ + "startuptopic ......................... Startup Topic\n\r" + }, + { .name = "statustopic", .cmdFunc = setStatusTopicCmd, + .help = \ + "statustopic .......................... Status Topic\n\r" + }, + { .name = "mbusdatatopic", .cmdFunc = setMbusDataTopicCmd, + .help = \ + "mbusdatatopic ........................ MBus Data Topic\n\r" + }, + { .name = "frontendthreshold", .cmdFunc = setFrontendThresholdCmd, + .help = \ + "frontendthreshold .................... Frontend Threshold (default: 240)\n\r" + }, + { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL } +}; + +const static char UNKNOWN_PARAMETER[] = "unknown parameter\n\r"; +const static char OK_MSG[] = "OK\n\r"; +const static char FAILED_MSG[] = "Failed\n\r"; + +static bool setCmd(uint8_t argc, char **args) { + bool retCode = false; + uint8_t *messageToSend = NULL; + + char *cmd = args[1]; + if (argc >= 2) { + if (0 == strcmp("help", cmd)) { + sendString("You can set the following parameters:\n\r"); + uint8_t cmdIdx = 0; + while (true) { + cmd_t command = SET_COMMANDS[cmdIdx]; + if (0 == strcmp("END_OF_CMDS", command.name)) { + break; + } + sendString(command.help); + cmdIdx++; + } + retCode = true; + } else { + uint8_t cmdIdx = 0; + while (true) { + cmd_t command = SET_COMMANDS[cmdIdx]; + if (0 == strcmp("END_OF_CMDS", command.name)) { + messageToSend = (uint8_t*) UNKNOWN_PARAMETER; + break; + } + if (0 == strcmp(cmd, command.name)) { + retCode = command.cmdFunc(argc, args); + messageToSend = retCode ? (uint8_t*)OK_MSG : (uint8_t*)FAILED_MSG; + sendString("Remember you need to restart to active this change.\n\r"); + break; + } + cmdIdx++; + } + sendString((const char*)messageToSend); + } + } + + return retCode; +} + +static bool restartCmd(uint8_t argc, char **args) { + HAL_NVIC_SystemReset(); + // you won't come here ... + return true; +} + + + +const cmd_t CONFIG_COMMANDS[] = { + { .name = "show", .cmdFunc = showConfigCmd, + .help = \ + "show ................................. Show the configuration\n\r" + }, + { .name = "set", .cmdFunc = setCmd, + .help = \ + "set .................................. Set configuration parameters\n\r" \ + " Argument help gives a list of \n\r" \ + " parameters\n\r" + }, + { .name = "addDevice", .cmdFunc = addDeviceCmd, + .help = \ + "addDevice ............................ Add a new device to the end of the list\n\r" + }, + { .name = "changeDevice", .cmdFunc = changeDeviceCmd, + .help = \ + "changeDevice ......................... Change a new device by index\n\r" + }, + { .name = "listDevices", .cmdFunc = listDevicesCmd, + .help = \ + "listDevices .......................... List the configured devices\n\r" + }, + { .name = "deleteDevice", .cmdFunc = deleteDeviceCmd, + .help = \ + "deleteDevice ......................... Delete a device\n\r" \ + " Argument: index\n\r" + }, + { .name = "restart", .cmdFunc = restartCmd, + .help = \ + "restart .............................. Restart the system,\n\r" \ + " Required to reload config\n\r" + }, + { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL } +}; + + + +const cmd_t *getConfigCommands() { + return CONFIG_COMMANDS; +} \ No newline at end of file diff --git a/cube/User/Src/eeprom.c b/cube/User/Src/eeprom.c new file mode 100644 index 0000000..0b47707 --- /dev/null +++ b/cube/User/Src/eeprom.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define HIGH GPIO_PIN_SET +#define LOW GPIO_PIN_RESET + + + +static const uint8_t EEPROM_READ = 0x03; +static const uint8_t EEPROM_WRITE = 0x02; +// static const uint8_t EEPROM_WRDI = 0x04; +static const uint8_t EEPROM_WREN = 0x06; +// static const uint8_t EEPROM_RDSR = 0x05; +// static const uint8_t EEPROM_WRSR = 0x01; + + +static const uint32_t EEPROM_MAGIC = 0xaffe0009; + + +static const uint16_t EEPROM_HEADER_ADDR = EEPROM_BASE_ADDR; + + +typedef union { + t_eepromHeader s; + uint8_t b[sizeof(struct s_eepromHeader)]; +} t_eepromHeaderBlock; + +static t_eepromHeaderBlock eepromHeader; + + +typedef union { + t_deviceStats s; + uint8_t b[sizeof(t_deviceStats)]; +} t_deviceStatsBlock; + +static const uint16_t DEVICE_STATS_ADDR = EEPROM_DEVICE_STATS_ADDR; +static t_deviceStatsBlock deviceStats; + +static const uint16_t CONFIG_BLOCK_ADDR = EEPROM_CONFIG_BLOCK_ADDR; +static const uint16_t DEVICE_BLOCK_ADDR = EEPROM_DEVICE_BLOCK_BASE_ADDR; + + + + +typedef union { + struct __attribute__((__packed__)) s_spiMsg { + uint8_t cmd; + uint16_t addr; + uint8_t data[32]; + } s; + uint8_t b[sizeof(struct s_spiMsg)]; +} t_spiMsg; + +t_deviceStats* getGlobalDeviceStats() { + return &(deviceStats.s); +} + +inline static void __EEPROM_CS(GPIO_PinState v) { + HAL_GPIO_WritePin(EEPROM_CS_GPIO_Port, EEPROM_CS_Pin, v); +} + +static uint16_t swap(uint16_t i) { + return ((i & 0x00ff) << 8) | ((i & 0xff00) >> 8); +} + + +// active waiting, use only during initialization! +static void eepromActiveDelay(uint8_t delay_ms) { + activeDelay(delay_ms); +} + +void eepromWrite(uint16_t addr, uint8_t *buf, uint8_t len) { + t_spiMsg msg = { + .s.cmd = EEPROM_WRITE, + .s.addr = swap(addr) + }; + memcpy(msg.s.data, buf, len); + + + uint8_t writeEnable = EEPROM_WREN; + __EEPROM_CS(LOW); + HAL_SPI_Transmit(&eepromSpi, &writeEnable, 1, HAL_MAX_DELAY); + __EEPROM_CS(HIGH); + + __EEPROM_CS(LOW); + HAL_SPI_Transmit(&eepromSpi, msg.b, ((uint16_t)(len+3)), HAL_MAX_DELAY); + __EEPROM_CS(HIGH); +} + +void eepromRead(uint16_t addr, uint8_t *buf, uint8_t len) { + t_spiMsg txMsg = { + .s.cmd = EEPROM_READ, + .s.addr = swap(addr) + }; + + t_spiMsg rxMsg; + + __EEPROM_CS(LOW); + HAL_SPI_TransmitReceive(&eepromSpi, txMsg.b, rxMsg.b, ((uint16_t)(len+3)), HAL_MAX_DELAY); + __EEPROM_CS(HIGH); + + memcpy(buf, rxMsg.s.data, len); +} + +void eepromSpiTxCpltCallback(SPI_HandleTypeDef *hspi) { + +} + +static void eepromHourlyUpdateDeviceStats(void *handle) { + deviceStats.s.totalRunningHours += 1; + + t_mbusCommStats *stats = mbusCommGetStats(); + + deviceStats.s.totalRequests += stats->mbusRequestCnt; + deviceStats.s.totalFailures += stats->mbusErrorCnt; + + logMsg("eeHUDS, about to write updated device stats"); + logMsg("eeHUDS, total powercycles so far: %d", deviceStats.s.totalPowercycles); + logMsg("eeHUDS, total running hours so far: %d", deviceStats.s.totalRunningHours); + logMsg("eeHUDS, total requests so far: %d", deviceStats.s.totalRequests); + logMsg("eeHUDS, total failures so far: %d", deviceStats.s.totalFailures); + + eepromWrite(DEVICE_STATS_ADDR, deviceStats.b, sizeof(deviceStats)); +} + +void eepromReadConfigBlock(t_configBlock *destConfigBlock) { +// static_assert((sizeof(*destConfigBlock) % EEPROM_WRITE_BLOCK_SIZE == 0), "config block has illegal size, must be dividable by 32"); + + for (uint8_t i = 0; i < (sizeof(*destConfigBlock) / EEPROM_WRITE_BLOCK_SIZE); i++) { + eepromRead(CONFIG_BLOCK_ADDR + (i * EEPROM_WRITE_BLOCK_SIZE), ((uint8_t*)destConfigBlock) + (i * EEPROM_WRITE_BLOCK_SIZE), EEPROM_WRITE_BLOCK_SIZE); + } +} + +void eepromWriteConfigBlock(t_configBlock *srcConfigBlock) { + for (uint8_t i = 0; i < (sizeof(*srcConfigBlock) / EEPROM_WRITE_BLOCK_SIZE); i++) { + eepromWrite(CONFIG_BLOCK_ADDR + (i * EEPROM_WRITE_BLOCK_SIZE), ((uint8_t*)srcConfigBlock) + (i * EEPROM_WRITE_BLOCK_SIZE), EEPROM_WRITE_BLOCK_SIZE); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + } +} + +void eepromReadDeviceBlock(uint8_t blockNum, t_deviceBlock *destDeviceBlock) { + static_assert((sizeof(*destDeviceBlock) % EEPROM_WRITE_BLOCK_SIZE == 0), "device block has illegal size, must be dividable by 32"); + + for (uint8_t i = 0; i < (sizeof(*destDeviceBlock) / EEPROM_WRITE_BLOCK_SIZE); i++) { + eepromRead(DEVICE_BLOCK_ADDR + (blockNum * sizeof(*destDeviceBlock)) + (i * EEPROM_WRITE_BLOCK_SIZE), + ((uint8_t*)destDeviceBlock) + (i * EEPROM_WRITE_BLOCK_SIZE), + EEPROM_WRITE_BLOCK_SIZE); + } +} + +void eepromWriteDeviceBlock(uint8_t blockNum, t_deviceBlock *srcDeviceBlock) { + for (uint8_t i = 0; i < (sizeof(*srcDeviceBlock) / EEPROM_WRITE_BLOCK_SIZE); i++) { + eepromWrite(DEVICE_BLOCK_ADDR + (blockNum * sizeof(*srcDeviceBlock)) + (i * EEPROM_WRITE_BLOCK_SIZE), + ((uint8_t*)srcDeviceBlock) + (i * EEPROM_WRITE_BLOCK_SIZE), + EEPROM_WRITE_BLOCK_SIZE); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + } +} + + + +void eepromInit() { + __EEPROM_CS(HIGH); + + logMsg("eeI, read header"); + eepromRead(EEPROM_HEADER_ADDR, eepromHeader.b, sizeof(eepromHeader)); + logMsg("eeI, magic: %08x", eepromHeader.s.magic); + + if (eepromHeader.s.magic != EEPROM_MAGIC) { + logMsg("eeI, eeprom is uninitialized"); + + deviceStats.s.totalPowercycles = 0; + deviceStats.s.totalRunningHours = 0; + deviceStats.s.totalRequests = 0; + deviceStats.s.totalFailures = 0; + logMsg("eeI, about to write device stats for the first time"); + eepromWrite(DEVICE_STATS_ADDR, deviceStats.b, sizeof(deviceStats)); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + + uint8_t emptyBlock[EEPROM_WRITE_BLOCK_SIZE]; + memset(emptyBlock, 0, sizeof(emptyBlock)); + eepromWrite(CONFIG_BLOCK_ADDR, emptyBlock, EEPROM_WRITE_BLOCK_SIZE); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + logMsg("eeI, config block initialized"); + + eepromHeader.s.magic = EEPROM_MAGIC; + eepromHeader.s.writeCounter = 1; + logMsg("eeI, about to write header for the first time"); + eepromWrite(EEPROM_HEADER_ADDR, eepromHeader.b, sizeof(eepromHeader)); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + logMsg("eeI, eeprom has been initialized"); + } else { + logMsg("eeI, eeprom is initialized"); + } + + logMsg("eeI, about to read device stats"); + eepromRead(DEVICE_STATS_ADDR, deviceStats.b, sizeof(deviceStats)); + logMsg("eeI, total powercycles so far: %d", deviceStats.s.totalPowercycles); + logMsg("eeI, total running hours so far: %d", deviceStats.s.totalRunningHours); + logMsg("eeI, total requests so far: %d", deviceStats.s.totalRequests); + logMsg("eeI, total failures so far: %d", deviceStats.s.totalFailures); + + deviceStats.s.totalPowercycles += 1; + logMsg("eeI, about to write device stats with updated power cycles counter"); + eepromWrite(DEVICE_STATS_ADDR, deviceStats.b, sizeof(deviceStats)); + eepromActiveDelay(EEPROM_AFTER_WRITE_DELAY); + + schAdd(eepromHourlyUpdateDeviceStats, NULL, 0, 60 * 60 * 1000); + logMsg("eeI, hourly device stats update scheduled"); +} diff --git a/cube/User/Src/frontend.c b/cube/User/Src/frontend.c new file mode 100644 index 0000000..b7cc705 --- /dev/null +++ b/cube/User/Src/frontend.c @@ -0,0 +1,59 @@ +#include + +#include +#include + +#include +#include +#include +#include + + +static t_configBlock *config; + + +static volatile int32_t frontendAdcThreshold = 0; +static volatile bool frontendEnabled = false; + + +void frontendInit() { + config = getConfig(); + frontendAdcThreshold = config->frontendThreshold; + + HAL_ADCEx_Calibration_Start(&frontendAdc); + logMsg("frontendInit, calibration done"); + HAL_ADC_Start_IT(&frontendAdc); + logMsg("frontendInit, adc started"); +} + +void frontendEnable() { + frontendEnabled = true; +} + +void frontendDisable() { + frontendEnabled = false; +} + +void frontendAdcCallback(ADC_HandleTypeDef* hadc) { + static int32_t holdValue = 0; + + if (frontendEnabled) { + int32_t currentValue = (int32_t) HAL_ADC_GetValue(hadc); + + if (holdValue == 0) { + holdValue = currentValue; + } + + if (currentValue - holdValue > frontendAdcThreshold) { + HAL_GPIO_WritePin(Frontend_Out_GPIO_Port, Frontend_Out_Pin, GPIO_PIN_RESET); + } else { + HAL_GPIO_WritePin(Frontend_Out_GPIO_Port, Frontend_Out_Pin, GPIO_PIN_SET); + } + } else { + if (holdValue != 0) { + holdValue = 0; + HAL_GPIO_WritePin(Frontend_Out_GPIO_Port, Frontend_Out_Pin, GPIO_PIN_SET); + } + } + +} diff --git a/cube/User/Src/logger.c b/cube/User/Src/logger.c new file mode 100644 index 0000000..2c67ec4 --- /dev/null +++ b/cube/User/Src/logger.c @@ -0,0 +1,198 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef LOGGER_OUTPUT_BY_INTERRUPT +#include +#endif //LOGGER_OUTPUT_BY_INTERRUPT + +#ifndef LOGGER_OUTPUT_BY_INTERRUPT +#include +#endif //LOGGER_OUTPUT_BY_INTERRUPT + + +#define LOGBUFFER_SIZE 4096 +#define MSGBUFFER_SIZE 256 + + +static t_configBlock *config; + +extern const uint8_t SYSLOG_SOCK; +uint8_t syslogAddr[4]; + +uint8_t singleOctetTXBuffer; + +static ringbuffer_t logBuffer; + +void logInit() { + config = getConfig(); + ringbufferInit(&logBuffer, LOGBUFFER_SIZE); +} + +void logFree() { + ringbufferFree(&logBuffer); +} + +#ifdef LOGGER_OUTPUT_BY_INTERRUPT +void debugTxCpltCallback(UART_HandleTypeDef *huart) { + int c = ringbufferGetOne(&logBuffer); + if (c > 0) { + singleOctetTXBuffer = (uint8_t) c; + HAL_UART_Transmit_IT(&debugUart, &singleOctetTXBuffer, 1); + } +} +#endif //LOGGER_OUTPUT_BY_INTERRUPT + +#ifndef LOGGER_OUTPUT_BY_INTERRUPT +int logExec() { + int c = -1; + if (__HAL_UART_GET_FLAG(&debugUart, UART_FLAG_TXE)) { // is the TX channel free + c = ringbufferGetOne(&logBuffer); + if (c > 0) { + // transfer to TX channel + uint8_t cc = (uint8_t) c; + HAL_UART_Transmit(&debugUart, &cc, 1, HAL_MAX_DELAY); + } + } + return c; +} +#endif //LOGGER_OUTPUT_BY_INTERRUPT + +void syslog(char *msg) { + static uint8_t state = 0; + int8_t res8 = 0; + int32_t res32 = 0; + + if (isNetworkAvailable()) { + switch (state) { + case 0: + res8 = socket(SYSLOG_SOCK, Sn_MR_UDP, 514, SF_IO_NONBLOCK); + if (res8 != SYSLOG_SOCK) { + break; + } + state = 1; + // no break + case 1: + if (! wizDnsQuery(config->syslogServerName, syslogAddr)) { + disconnect(SYSLOG_SOCK); + state = 0; + break; + } + state = 2; + // no break + case 2: + res32 = sendto(SYSLOG_SOCK, (uint8_t*)msg, strlen(msg), syslogAddr, 514); + if (res32 != strlen(msg)) { + disconnect(SYSLOG_SOCK); + state = 0; + } + break; + } + } +} + +static int innerLogMsg(const char *pre, const char *post, bool syslogToo, const char *format, va_list vl) { + const static char SYSLOG_HEADER[] = "<133>1 "; + #define MAX_PREFIX_SIZE 20 + int res = -1; + char msgBuffer[MSGBUFFER_SIZE+MAX_PREFIX_SIZE]; + char *bufferStart; + + memset(msgBuffer, 0, MSGBUFFER_SIZE+MAX_PREFIX_SIZE); + + uint16_t syslogHeaderSize = strlen(SYSLOG_HEADER); + uint16_t preSize = (pre) ? strlen(pre) : 0; + uint16_t prefixSize = (syslogHeaderSize > preSize) ? syslogHeaderSize : preSize; + if (prefixSize > MAX_PREFIX_SIZE) { + return -1; + } + bufferStart = msgBuffer + prefixSize; + + int vcnt = vsnprintf(bufferStart, MSGBUFFER_SIZE, format, vl); + if (vcnt < MSGBUFFER_SIZE) { + if (syslogToo) { + memcpy(bufferStart - syslogHeaderSize, SYSLOG_HEADER, syslogHeaderSize); + syslog(bufferStart - syslogHeaderSize); + } + + if (pre) { + memcpy(bufferStart - preSize, pre, preSize); + } + if (post) { + strcat(bufferStart - preSize, post); + } +#ifdef LOGGER_OUTPUT_BY_INTERRUPT + HAL_NVIC_DisableIRQ(UART4_IRQn); +#endif //LOGGER_OUTPUT_BY_INTERRUPT + + res = ringbufferPut(&logBuffer, (uint8_t*) (bufferStart - preSize), strlen(bufferStart - preSize)); + +#ifdef LOGGER_OUTPUT_BY_INTERRUPT + HAL_NVIC_EnableIRQ(UART4_IRQn); +#endif //LOGGER_OUTPUT_BY_INTERRUPT + +#ifdef LOGGER_OUTPUT_BY_INTERRUPT + debugTxCpltCallback(NULL); +#endif //LOGGER_OUTPUT_BY_INTERRUPT + } + + return res; +} + +int logMsg(const char *format, ...) { + va_list vl; + va_start(vl, format); + int res = innerLogMsg(NULL, "\r\n", false, format, vl); + va_end(vl); + return res; +} + +int coloredMsg(const t_logColor color, bool syslogToo, const char *format, ...) { + const static char POST[] = "\x1b[0m\r\n"; + const static char HIGH[] = "\x1b[1m"; + const static char RED[] = "\x1b[31;1m"; + const static char GREEN[] = "\x1b[32;1m"; + const static char BLUE[] = "\x1b[34;1m"; + const static char YELLOW[] = "\x1b[33;1m"; + const char *pre = NULL; + switch (color) { + case LOG_HIGH: + pre = HIGH; + break; + case LOG_RED: + pre = RED; + break; + case LOG_BLUE: + pre = BLUE; + break; + case LOG_GREEN: + pre = GREEN; + break; + case LOG_YELLOW: + pre = YELLOW; + break; + case LOG_NORMAL: + pre = NULL; + break; + } + va_list vl; + va_start(vl, format); + int res = innerLogMsg(pre, POST, syslogToo, format, vl); + va_end(vl); + return res; +} + + + diff --git a/cube/User/Src/main2.c b/cube/User/Src/main2.c new file mode 100644 index 0000000..f902c82 --- /dev/null +++ b/cube/User/Src/main2.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +void my_setup_1() { + schInit(); + logInit(); + showInit(); +} + +void my_errorHandler() { + show(LED_RED, ON); +} + + +void my_setup_2() { + show(LED_RED, OFF); + show(LED_GREEN, BLINK); + logMsg("Application starting"); + + oledInit(); + oledClearAllScreens(); + oledSetActiveScreen(OLED_SCREEN0); + oledPrint(OLED_SCREEN0, "App starting"); + + eepromInit(); + oledPrint(OLED_SCREEN0, "eeprom init"); + + configInit(); + oledPrint(OLED_SCREEN0, "config init"); + + wizInit(); + oledPrint(OLED_SCREEN0, "network init"); + + mqttCommInit(); + oledPrint(OLED_SCREEN0, "mqtt init"); + cmdHandlerInit(); + oledPrint(OLED_SCREEN0, "cmdhandler init"); + + frontendInit(); + oledPrint(OLED_SCREEN0, "frontend init"); + + mbusCommInit(); + oledPrint(OLED_SCREEN0, "Meterbus init"); + oledPrint(OLED_SCREEN0, "App running"); +} + +void my_loop() { + // show(DEBUG_2, TOGGLE); + + schExec(); + +#ifndef LOGGER_OUTPUT_BY_INTERRUPT + logExec(); +#endif //LOGGER_OUTPUT_BY_INTERRUPT + + mbusCommExec(); +} + +void SYSTICK_Callback() { + schUpdate(); +} + +void HAL_GPIO_EXTI_Callback(uint16_t pin) { + if (pin == Loop_Status_Pin) { + loopStatusCallback(); + } +} + +void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { + if (hadc == &frontendAdc) { + frontendAdcCallback(hadc); + } +} + +void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { +#ifdef LOGGER_OUTPUT_BY_INTERRUPT + if (huart == &debugUart) { + debugTxCpltCallback(huart); + } +#endif //LOGGER_OUTPUT_BY_INTERRUPT +} + +void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { + if (hspi == &eepromSpi) { + eepromSpiTxCpltCallback(hspi); + } +} diff --git a/cube/User/Src/oled.c b/cube/User/Src/oled.c new file mode 100644 index 0000000..1221787 --- /dev/null +++ b/cube/User/Src/oled.c @@ -0,0 +1,461 @@ +/* + * Code found at http://www.instructables.com/id/How-to-use-OLED-display-arduino-module/ + * Thank you very much! + * Adapted from Arduino to STM32 HAL by wollud1969 + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#define HIGH GPIO_PIN_SET +#define LOW GPIO_PIN_RESET + +static void __LEDPIN_RST(GPIO_PinState v) { + HAL_GPIO_WritePin(Display_RES_GPIO_Port, Display_RES_Pin, v); +} + +static void __LEDPIN_DC(GPIO_PinState v) { + HAL_GPIO_WritePin(Display_DC_GPIO_Port, Display_DC_Pin, v); +} + +static void __LEDPIN_CS(GPIO_PinState v) { + HAL_GPIO_WritePin(Display_CS_GPIO_Port, Display_CS_Pin, v); +} + +static void oled_WrDat(unsigned char data) +{ + __LEDPIN_CS(LOW); + __LEDPIN_DC(HIGH); + + HAL_SPI_Transmit(&displaySpi, &data, 1, 0); + + __LEDPIN_CS(HIGH); +} + +static void oled_WrCmd(unsigned char cmd) +{ + __LEDPIN_CS(LOW); + __LEDPIN_DC(LOW); + + HAL_SPI_Transmit(&displaySpi, &cmd, 1, 0); + + __LEDPIN_CS(HIGH); +} + +static void oled_Set_Pos(unsigned char x, unsigned char y) +{ + oled_WrCmd(0xb0+y); + oled_WrCmd(((x&0xf0)>>4)|0x10); + oled_WrCmd((x&0x0f)|0x00); +} + + +static void oled_Fill(unsigned char bmp_data) +{ + unsigned char y,x; + + for(y=0;y<8;y++) + { + oled_WrCmd(0xb0+y); + oled_WrCmd(0x00); + oled_WrCmd(0x10); + for(x=0;x<128;x++) + oled_WrDat(bmp_data); + } +} + + + +static void oled_CLS(void) +{ + unsigned char y,x; + for(y=0;y<8;y++) + { + oled_WrCmd(0xb0+y); + oled_WrCmd(0x00); + oled_WrCmd(0x10); + for(x=0;x<128;x++) + oled_WrDat(0); + } +} + +static void oled_DLY_ms(unsigned int ms) +{ + uint32_t start = HAL_GetTick(); + while (HAL_GetTick() < start + ms); +} + +/* + * unused +static void SetStartColumn(unsigned char d) +{ + oled_WrCmd(0x00+d%16); // Set Lower Column Start Address for Page Addressing Mode + // Default => 0x00 + oled_WrCmd(0x10+d/16); // Set Higher Column Start Address for Page Addressing Mode + // Default => 0x10 +} +*/ + +static void SetAddressingMode(unsigned char d) +{ + oled_WrCmd(0x20); // Set Memory Addressing Mode + oled_WrCmd(d); // Default => 0x02 + // 0x00 => Horizontal Addressing Mode + // 0x01 => Vertical Addressing Mode + // 0x02 => Page Addressing Mode +} + +/* + * unused +static void SetColumnAddress(unsigned char a, unsigned char b) +{ + oled_WrCmd(0x21); // Set Column Address + oled_WrCmd(a); // Default => 0x00 (Column Start Address) + oled_WrCmd(b); // Default => 0x7F (Column End Address) +} +*/ +/* + * unused +static void SetPageAddress(unsigned char a, unsigned char b) +{ + oled_WrCmd(0x22); // Set Page Address + oled_WrCmd(a); // Default => 0x00 (Page Start Address) + oled_WrCmd(b); // Default => 0x07 (Page End Address) +} +*/ + +static void SetStartLine(unsigned char d) +{ + oled_WrCmd(0x40|d); // Set Display Start Line + // Default => 0x40 (0x00) +} + +static void SetContrastControl(unsigned char d) +{ + oled_WrCmd(0x81); // Set Contrast Control + oled_WrCmd(d); // Default => 0x7F +} + +static void Set_Charge_Pump(unsigned char d) +{ + oled_WrCmd(0x8D); // Set Charge Pump + oled_WrCmd(0x10|d); // Default => 0x10 + // 0x10 (0x00) => Disable Charge Pump + // 0x14 (0x04) => Enable Charge Pump +} + +static void Set_Segment_Remap(unsigned char d) +{ + oled_WrCmd(0xA0|d); // Set Segment Re-Map + // Default => 0xA0 + // 0xA0 (0x00) => Column Address 0 Mapped to SEG0 + // 0xA1 (0x01) => Column Address 0 Mapped to SEG127 +} + +static void Set_Entire_Display(unsigned char d) +{ + oled_WrCmd(0xA4|d); // Set Entire Display On / Off + // Default => 0xA4 + // 0xA4 (0x00) => Normal Display + // 0xA5 (0x01) => Entire Display On +} + +static void Set_Inverse_Display(unsigned char d) +{ + oled_WrCmd(0xA6|d); // Set Inverse Display On/Off + // Default => 0xA6 + // 0xA6 (0x00) => Normal Display + // 0xA7 (0x01) => Inverse Display On +} + +static void Set_Multiplex_Ratio(unsigned char d) +{ + oled_WrCmd(0xA8); // Set Multiplex Ratio + oled_WrCmd(d); // Default => 0x3F (1/64 Duty) +} + +static void Set_Display_On_Off(unsigned char d) +{ + oled_WrCmd(0xAE|d); // Set Display On/Off + // Default => 0xAE + // 0xAE (0x00) => Display Off + // 0xAF (0x01) => Display On +} + +/* + * unused +static void SetStartPage(unsigned char d) +{ + oled_WrCmd(0xB0|d); // Set Page Start Address for Page Addressing Mode + // Default => 0xB0 (0x00) +} +*/ + +static void Set_Common_Remap(unsigned char d) +{ + oled_WrCmd(0xC0|d); // Set COM Output Scan Direction + // Default => 0xC0 + // 0xC0 (0x00) => Scan from COM0 to 63 + // 0xC8 (0x08) => Scan from COM63 to 0 +} + +static void Set_Display_Offset(unsigned char d) +{ + oled_WrCmd(0xD3); // Set Display Offset + oled_WrCmd(d); // Default => 0x00 +} + +static void Set_Display_Clock(unsigned char d) +{ + oled_WrCmd(0xD5); // Set Display Clock Divide Ratio / Oscillator Frequency + oled_WrCmd(d); // Default => 0x80 + // D[3:0] => Display Clock Divider + // D[7:4] => Oscillator Frequency +} + +static void Set_Precharge_Period(unsigned char d) +{ + oled_WrCmd(0xD9); // Set Pre-Charge Period + oled_WrCmd(d); // Default => 0x22 (2 Display Clocks [Phase 2] / 2 Display Clocks [Phase 1]) + // D[3:0] => Phase 1 Period in 1~15 Display Clocks + // D[7:4] => Phase 2 Period in 1~15 Display Clocks +} + +static void Set_Common_Config(unsigned char d) +{ + oled_WrCmd(0xDA); // Set COM Pins Hardware Configuration + oled_WrCmd(0x02|d); // Default => 0x12 (0x10) + // Alternative COM Pin Configuration + // Disable COM Left/Right Re-Map +} + +static void Set_VCOMH(unsigned char d) +{ + oled_WrCmd(0xDB); // Set VCOMH Deselect Level + oled_WrCmd(d); // Default => 0x20 (0.77*VCC) +} + +/* + * unused +static void Set_NOP(void) +{ + oled_WrCmd(0xE3); // Command for No Operation +} +*/ + +void oledInit(void) +{ + // LEDPIN_Init(); + // LED_PORT=0X0F; + //LED_SCLH;;; + //LED_RSTL;;; + //digitalWrite(SCL_PIN,HIGH);;; + __LEDPIN_RST(LOW); + // for(i=0;i<100;i++)asm("nop"); + oled_DLY_ms(50); + //LED_RSTH;;; + __LEDPIN_RST(HIGH); + + Set_Display_On_Off(0x00); // Display Off (0x00/0x01) + Set_Display_Clock(0x80); // Set Clock as 100 Frames/Sec + Set_Multiplex_Ratio(0x3F); // 1/64 Duty (0x0F~0x3F) + Set_Display_Offset(0x00); // Shift Mapping RAM Counter (0x00~0x3F) + SetStartLine(0x00); // Set Mapping RAM Display Start Line (0x00~0x3F) + Set_Charge_Pump(0x04); // Enable Embedded DC/DC Converter (0x00/0x04) + SetAddressingMode(0x02); // Set Page Addressing Mode (0x00/0x01/0x02) + Set_Segment_Remap(0x01); // Set SEG/Column Mapping + Set_Common_Remap(0x08); // Set COM/Row Scan Direction + Set_Common_Config(0x10); // Set Sequential Configuration (0x00/0x10) + SetContrastControl(0xCF); // Set SEG Output Current + Set_Precharge_Period(0xF1); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock + Set_VCOMH(0x40); // Set VCOM Deselect Level + Set_Entire_Display(0x00); // Disable Entire Display On (0x00/0x01) + Set_Inverse_Display(0x00); // Disable Inverse Display On (0x00/0x01) + Set_Display_On_Off(0x01); // Display On (0x00/0x01) + oled_Fill(0x00); //clear all + oled_Set_Pos(0,0); +} + +/* + * unused +static void oled_P6x8Char(unsigned char x,unsigned char y,unsigned char ch) +{ + unsigned char c=0,i=0; + + c =ch-32; + if(x>122) + { + x=0; + y++; + } + oled_Set_Pos(x,y); + for(i=0;i<6;i++) + { + oled_WrDat(F6x8[c][i]); + } +} +*/ + +static void oled_P6x8Str(unsigned char x,unsigned char y,char ch[]) +{ + // coloredMsg(LOG_BLUE, false, "OLED: %d %d %s", x, y, ch); + + unsigned char c=0,i=0,j=0; + while (ch[j]!='\0') + { + c =ch[j]-32; + if(x>126) + { + x=0; + y++; + } + oled_Set_Pos(x,y); + for(i=0;i<6;i++) + { + oled_WrDat(F6x8[c][i]); + } + x+=6; + j++; + } +} + +/* + * unused +static void oled_P8x16Str(unsigned char x,unsigned char y,char ch[]) +{ + unsigned char c=0,i=0,j=0; + while (ch[j]!='\0') + { + c =ch[j]-32; + if(x>120) + { + x=0; + y++; + } + oled_Set_Pos(x,y); + for(i=0;i<8;i++) + { + oled_WrDat(F8X16[(c<<4)+i]); + } + oled_Set_Pos(x,y+1); + for(i=0;i<8;i++) + { + oled_WrDat(F8X16[(c<<4)+i+8]); + } + x+=8; + j++; + } +} +*/ + + +/* + * unused +static void oled_PrintBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char bmp[]) +{ + int ii=0; + unsigned char x,y; + for(y=y0;y<=y1;y++) + { + oled_Set_Pos(x0,y); + for(x=x0;x + + + +// on the W5500 there are eight ports available + +const uint8_t DHCP_SOCK = 0; +const uint8_t MQTT_SOCK = 1; +const uint8_t CMD_SOCK = 2; +const uint8_t SYSLOG_SOCK = 3; +const uint8_t DNS_SOCK = 4; diff --git a/cube/User/Src/regularCmds.c b/cube/User/Src/regularCmds.c new file mode 100644 index 0000000..12b9cac --- /dev/null +++ b/cube/User/Src/regularCmds.c @@ -0,0 +1,57 @@ +#include +#include + +#include +#include + + +static bool globalStatsCmd(uint8_t argc, char **args) { + uint32_t uptime = HAL_GetTick() / 1000; + sendFormatString(\ + "Current uptime: %ld\n\r" \ + "\n\r", + uptime + ); + + t_deviceStats *deviceStats = getGlobalDeviceStats(); + sendFormatString(\ + "Global Device statistics\n\r" \ + " Total running hours: %ld\n\r" \ + " Total power cycles: %ld\n\r" \ + " Total requests: %ld\n\r" \ + " Total failures: %ld\n\r" \ + "\n\r", + deviceStats->totalRunningHours, deviceStats->totalPowercycles, + deviceStats->totalRequests, deviceStats->totalFailures + ); + + t_mbusCommStats *mbusStats = mbusCommGetStats(); + sendFormatString(\ + "Global Meterbus/UART statistics\n\r" \ + " Meterbus Requests: %ld\n\r" \ + " Meterbus Errors: %ld\n\r" \ + " UART Octets: %ld\n\r" \ + " UART Overruns: %ld\n\r" \ + " UART Framing Errs: %ld\n\r" \ + " UART Parity Errs: %ld\n\r" \ + " UART Noise Errs: %ld\n\r", + mbusStats->mbusRequestCnt, mbusStats->mbusErrorCnt, + mbusStats->uartOctetCnt, mbusStats->uartOverrunCnt, mbusStats->uartFramingErrCnt, mbusStats->uartParityErrCnt, mbusStats->uartNoiseErrCnt + ); + return true; +} + + + +const cmd_t COMMANDS[] = { + { .name = "globalStats", .cmdFunc = globalStatsCmd, + .help = \ + "globalStats .......................... Show the global statistics\n\r" \ + " counters requestCnt and errorCnt\n\r" + }, + { .name = "END_OF_CMDS", .help = "",.cmdFunc = NULL } +}; + +const cmd_t *getRegularCommands() { + return COMMANDS; +} \ No newline at end of file diff --git a/cube/User/Src/ringbuffer.c b/cube/User/Src/ringbuffer.c new file mode 100644 index 0000000..b98105f --- /dev/null +++ b/cube/User/Src/ringbuffer.c @@ -0,0 +1,75 @@ +#include +#include +#include + + +void ringbufferInit(ringbuffer_t *handle, uint32_t bufferSize) { + handle->bufferSize = bufferSize; + handle->buffer = (uint8_t*) malloc(handle->bufferSize); + memset(handle->buffer, 0, handle->bufferSize); + handle->bufferReadIdx = 0; + handle->bufferWriteIdx = 0; +} + +void ringbufferFree(ringbuffer_t *handle) { + free(handle->buffer); + handle->buffer = NULL; + handle->bufferSize = 0; + handle->bufferReadIdx = 0; + handle->bufferWriteIdx = 0; +} + + +int ringbufferPut(ringbuffer_t *handle, uint8_t *data, uint32_t dataLen) { + uint32_t freeSpace = 0; + if (handle->bufferReadIdx == handle->bufferWriteIdx) { + freeSpace = handle->bufferSize; + } else if (handle->bufferReadIdx > handle->bufferWriteIdx) { + freeSpace = handle->bufferReadIdx - handle->bufferWriteIdx; + } else { + freeSpace = (handle->bufferSize - handle->bufferWriteIdx) + handle->bufferReadIdx; + } + + freeSpace--; + + if (dataLen > freeSpace) { + return -1; + } + + if (dataLen <= (handle->bufferSize - handle->bufferWriteIdx)) { + memcpy(handle->buffer + handle->bufferWriteIdx, data, dataLen); + handle->bufferWriteIdx += dataLen; + if (handle->bufferWriteIdx == handle->bufferSize) { + handle->bufferWriteIdx = 0; + } + } else { + uint32_t remainingToTop = handle->bufferSize - handle->bufferWriteIdx; + memcpy(handle->buffer + handle->bufferWriteIdx, data, remainingToTop); + memcpy(handle->buffer, data + remainingToTop, dataLen - remainingToTop); + handle->bufferWriteIdx = dataLen - remainingToTop; + } + + return 0; +} + +bool ringbufferEmpty(ringbuffer_t *handle) { + return handle->bufferReadIdx == handle->bufferWriteIdx; +} + +uint8_t *ringbufferGet(ringbuffer_t *handle, uint32_t dataLen) { + return NULL; +} + +int ringbufferGetOne(ringbuffer_t *handle) { + int res = -1; + if (handle->bufferReadIdx != handle->bufferWriteIdx) { + uint8_t r = *(handle->buffer + handle->bufferReadIdx); + handle->bufferReadIdx += 1; + if (handle->bufferReadIdx == handle->bufferSize) { + handle->bufferReadIdx = 0; + } + res = (int) r; + } + return res; +} + diff --git a/cube/User/Src/show.c b/cube/User/Src/show.c new file mode 100644 index 0000000..2b99516 --- /dev/null +++ b/cube/User/Src/show.c @@ -0,0 +1,46 @@ +#include +#include +#include + +#include +#include + +#include + + +typedef struct { + GPIO_TypeDef *port; + uint16_t pin; + signalAction_t currentState; +} showElement_t; + +showElement_t showElement[] = { + { .port = Debug_Signal_1_GPIO_Port, .pin = Debug_Signal_1_Pin, .currentState = OFF }, + { .port = Debug_Signal_2_GPIO_Port, .pin = Debug_Signal_2_Pin, .currentState = OFF }, + { .port = LED_Red_GPIO_Port, .pin = LED_Red_Pin, .currentState = OFF }, + { .port = LED_Green_GPIO_Port, .pin = LED_Green_Pin, .currentState = OFF }, + { .port = NULL, .pin = 0, .currentState = OFF } +}; + +static void showHandler(void *handle) { + uint8_t idx = 0; + while (showElement[idx].port) { + if (showElement[idx].currentState == BLINK) { + HAL_GPIO_TogglePin(showElement[idx].port, showElement[idx].pin); + } + idx++; + } +} + +void show(signalPin_t signalPin, signalAction_t action) { + showElement[signalPin].currentState = action; + if (action == ON || action == OFF) { + HAL_GPIO_WritePin(showElement[signalPin].port, showElement[signalPin].pin, ((action == ON) ? GPIO_PIN_SET : GPIO_PIN_RESET)); + } else if (action == TOGGLE) { + HAL_GPIO_TogglePin(showElement[signalPin].port, showElement[signalPin].pin); + } +} + +void showInit() { + schAdd(showHandler, NULL, 0, 250); +} \ No newline at end of file diff --git a/cube/User/Src/utils.c b/cube/User/Src/utils.c new file mode 100644 index 0000000..f71bc21 --- /dev/null +++ b/cube/User/Src/utils.c @@ -0,0 +1,10 @@ +#include +#include +#include + + +// active waiting, use only during initialization! +void activeDelay(uint8_t delay_ms) { + uint32_t startTime = HAL_GetTick(); + while (startTime + delay_ms > HAL_GetTick()); +} \ No newline at end of file diff --git a/cube/User/Src/wizHelper.c b/cube/User/Src/wizHelper.c new file mode 100644 index 0000000..65a391f --- /dev/null +++ b/cube/User/Src/wizHelper.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +static t_configBlock *config; + +wiz_NetInfo netInfo; + +#define DHCP_BUFFER_SIZE 2048 +static uint8_t dhcpBuffer[DHCP_BUFFER_SIZE]; + +#define DNS_BUFFER_SIZE MAX_DNS_BUF_SIZE +static uint8_t dnsBuffer[DNS_BUFFER_SIZE]; + +extern const uint8_t DHCP_SOCK; +extern const uint8_t DNS_SOCK; + +static bool networkAvailable = false; + +bool isNetworkAvailable() { + return networkAvailable; +} + +uint8_t* wizGetIPAddress() { + return netInfo.ip; +} +static void wiz_cs_select(void) { + HAL_GPIO_WritePin(ETHER_CS_GPIO_Port, ETHER_CS_Pin, GPIO_PIN_RESET); +} + +static void wiz_cs_deselect(void) { + HAL_GPIO_WritePin(ETHER_CS_GPIO_Port, ETHER_CS_Pin, GPIO_PIN_SET); +} + +static uint8_t wiz_spi_readbyte(void) { + uint8_t rbuf; + HAL_SPI_Receive(ðerSpi, &rbuf, 1, HAL_MAX_DELAY); + return rbuf; +} + +static void wiz_spi_writebyte(uint8_t wb) { + HAL_SPI_Transmit(ðerSpi, &wb, 1, HAL_MAX_DELAY); +} + +static void wiz_spi_readburst(uint8_t* pBuf, uint16_t len) { + HAL_SPI_Receive(ðerSpi, pBuf, len, HAL_MAX_DELAY); +} + +static void wiz_spi_writeburst(uint8_t* pBuf, uint16_t len) { + HAL_SPI_Transmit(ðerSpi, pBuf, len, HAL_MAX_DELAY); +} + +static void wizReset(bool b) { + HAL_GPIO_WritePin(ETHER_RES_GPIO_Port, ETHER_RES_Pin, b ? GPIO_PIN_RESET : GPIO_PIN_SET); +} + + +static void wizDHCPAssign() { + coloredMsg(LOG_BLUE, false, "wizda"); + getIPfromDHCP(netInfo.ip); + coloredMsg(LOG_BLUE, false, "wizda, IP: %d.%d.%d.%d", netInfo.ip[0], netInfo.ip[1], netInfo.ip[2], netInfo.ip[3]); + getGWfromDHCP(netInfo.gw); + coloredMsg(LOG_BLUE, false, "wizda, GW: %d.%d.%d.%d", netInfo.gw[0], netInfo.gw[1], netInfo.gw[2], netInfo.gw[3]); + getSNfromDHCP(netInfo.sn); + coloredMsg(LOG_BLUE, false, "wizda, SN: %d.%d.%d.%d", netInfo.sn[0], netInfo.sn[1], netInfo.sn[2], netInfo.sn[3]); + getDNSfromDHCP(netInfo.dns); + coloredMsg(LOG_BLUE, false, "wizda, DNS: %d.%d.%d.%d", netInfo.dns[0], netInfo.dns[1], netInfo.dns[2], netInfo.dns[3]); + + wizchip_setnetinfo(&netInfo); + coloredMsg(LOG_BLUE, false, "wizda, set netinfo again"); + + networkAvailable = true; + show(LED_GREEN, ON); + coloredMsg(LOG_BLUE, false, "wizda, network is available"); + + oledPrintf(OLED_SCREEN0, "Addr:%d.%d.%d.%d", netInfo.ip[0], netInfo.ip[1], netInfo.ip[2], netInfo.ip[3]); +} + +static void wizDHCPUpdate() { + coloredMsg(LOG_BLUE, false, "wizdu"); + getIPfromDHCP(netInfo.ip); + coloredMsg(LOG_BLUE, false, "wizdu, IP: %d.%d.%d.%d", netInfo.ip[0], netInfo.ip[1], netInfo.ip[2], netInfo.ip[3]); + getGWfromDHCP(netInfo.gw); + coloredMsg(LOG_BLUE, false, "wizdu, GW: %d.%d.%d.%d", netInfo.gw[0], netInfo.gw[1], netInfo.gw[2], netInfo.gw[3]); + getSNfromDHCP(netInfo.sn); + coloredMsg(LOG_BLUE, false, "wizdu, SN: %d.%d.%d.%d", netInfo.sn[0], netInfo.sn[1], netInfo.sn[2], netInfo.sn[3]); + getDNSfromDHCP(netInfo.dns); + coloredMsg(LOG_BLUE, false, "wizdu, DNS: %d.%d.%d.%d", netInfo.dns[0], netInfo.dns[1], netInfo.dns[2], netInfo.dns[3]); + + wizchip_setnetinfo(&netInfo); + coloredMsg(LOG_BLUE, false, "wizdu, netinfo updated"); +} + +static void wizDHCPHandler(void *handle) { + static uint8_t lastDhcpRes = 255; + + uint8_t res = DHCP_run(); + + if (lastDhcpRes != res) { + coloredMsg(LOG_BLUE, false, "wizdh, dhcp state has changed: %d", res); + lastDhcpRes = res; + } +} + +bool wizDnsQuery(char *name, uint8_t *ip) { + bool retCode = false; + coloredMsg(LOG_BLUE, false, "wizdq, querying for %s", name); + int8_t res = DNS_run(netInfo.dns, (uint8_t*) name, ip); + coloredMsg(LOG_BLUE, false, "wizdq, DNS_run returns %d", res); + retCode = (res == 1); + if (retCode) { + coloredMsg(LOG_BLUE, false, "wizdq, got address %d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + } + return retCode; +} + +static void wizPhyLinkHandler(void *handle) { + // this handler is anyhow called with a 1s period, so we reuse it for the DNS timer + DNS_time_handler(); + + static uint8_t lastStablePhyLink = 255; + static bool dhcpInitialized = false; + + uint8_t phyLink = 0; + int8_t res = ctlwizchip(CW_GET_PHYLINK, (void*) &phyLink); + if (lastStablePhyLink != phyLink) { + coloredMsg(LOG_BLUE, false, "wizplh, ctlwizchip returns %d, phy link changed to %d", res, phyLink); + lastStablePhyLink = phyLink; + + if (phyLink == PHY_LINK_ON) { + oledPrint(OLED_SCREEN0, "Link available"); + // start DHCP handler + memset(dhcpBuffer, 0, DHCP_BUFFER_SIZE); + reg_dhcp_cbfunc(wizDHCPAssign, wizDHCPUpdate, NULL); + DHCP_init(DHCP_SOCK, dhcpBuffer); + coloredMsg(LOG_BLUE, false, "wizplh, DHCP initialized"); + + // run the dhcp handler the first time after 1s and then every 100ms + schAdd(wizDHCPHandler, NULL, 1000, 1000); + coloredMsg(LOG_BLUE, false, "wizplh, DHCP handler scheduled"); + + dhcpInitialized = true; + } else { + oledPrint(OLED_SCREEN0, "Link lost"); + + networkAvailable = false; + show(LED_GREEN, BLINK); + coloredMsg(LOG_BLUE, false, "wizplh, network is unavailable"); + + // stop DHCP handler + if (dhcpInitialized) { + DHCP_stop(); + coloredMsg(LOG_BLUE, false, "wizplh, DHCP stopped"); + + schDel(wizDHCPHandler, NULL); + coloredMsg(LOG_BLUE, false, "wizplh, DHCP handler unscheduled"); + + dhcpInitialized = false; + } + } + } +} + + +int wizInit() { + config = getConfig(); + netInfo.dhcp = NETINFO_DHCP; + memcpy(netInfo.mac, config->macAddress, 6); + + coloredMsg(LOG_BLUE, false, "wizI, resetting Ethernet module"); + wizReset(true); + activeDelay(2); + wizReset(false); + activeDelay(50); + + coloredMsg(LOG_BLUE, false, "wizI, registering callbacks"); + reg_wizchip_cs_cbfunc(wiz_cs_select, wiz_cs_deselect); + coloredMsg(LOG_BLUE, false, "wizI, cs funcs registed"); + reg_wizchip_spi_cbfunc(wiz_spi_readbyte, wiz_spi_writebyte); + coloredMsg(LOG_BLUE, false, "wizI, spi funcs registed"); + reg_wizchip_spiburst_cbfunc(wiz_spi_readburst, wiz_spi_writeburst); + coloredMsg(LOG_BLUE, false, "wizI, spi burst funcs registed"); + + + coloredMsg(LOG_BLUE, false, "wizI, initializing Ethernet module"); + uint8_t bufSizes[] = { 2, 2, 2, 2, 2, 2, 2, 2 }; + int8_t res = wizchip_init(bufSizes, bufSizes); + coloredMsg(LOG_BLUE, false, "wizI, module driver returned %d", res); + + wizphy_reset(); + activeDelay(5); + coloredMsg(LOG_BLUE, false, "wizI, reset phy"); + + wiz_PhyConf wpc; + wpc.mode = PHY_MODE_MANUAL; + wpc.speed = PHY_MODE_MANUAL; + wpc.duplex = PHY_DUPLEX_FULL; + wizphy_setphyconf(&wpc); + activeDelay(5); + coloredMsg(LOG_BLUE, false, "wizI, phy config set"); + + wizchip_setnetinfo(&netInfo); + coloredMsg(LOG_BLUE, false, "wizI, netinfo set to Ethernet module"); + + res = wizchip_setnetmode(NM_FORCEARP); // and not NM_PINGBLOCK + coloredMsg(LOG_BLUE, false, "wizI, set netmode, result is %d", res); + + uint8_t buf[6]; + res = ctlwizchip(CW_GET_ID, (void*) buf); + coloredMsg(LOG_BLUE, false, "wizI, CW_GET_ID: %d %02x %02x %02x %02x %02x %02x", res, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); + + DNS_init(DNS_SOCK, dnsBuffer); + + schAdd(wizPhyLinkHandler, NULL, 0, 1000); + coloredMsg(LOG_BLUE, false, "wizI, PhyLink handler scheduled"); + + return 0; +} diff --git a/openocd.cfg b/openocd.cfg new file mode 100644 index 0000000..540ec5d --- /dev/null +++ b/openocd.cfg @@ -0,0 +1,8 @@ +source /usr/share/openocd/scripts/interface/stlink-v2.cfg +source /usr/share/openocd/scripts/target/stm32f1x.cfg +reset_config srst_nogate +# reset_config connect_assert_srst +# reset_config none separate +# set CONNECT_UNDER_RESET 0 + + diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b8c46f5 --- /dev/null +++ b/readme.md @@ -0,0 +1,62 @@ +## Build environment + +On Ubuntu/Debian install + +* ``gcc-arm-none-eabi`` +* ``openocd`` + + +Alternatively use a prepared Docker image + + docker run -it --rm -u ${UID} -v ${PWD}:/mnt wollud1969/build-env-arm-none-eabi:1.1.0 bash + +Start the container from the project root. Or use the script ``startBuildEnv.sh`` from the tools directory. + + +Get the STM32CubeMX tool from the ST homepage. You may use this [link](https://www.st.com/en/development-tools/stm32cubemx.html). + + +## Preparing generated code to include user code + +After code generation in CubeMX the ``Makefile`` and the file ``main.c`` in ``Core/Src`` needs +to be edited to include user code. From the ``cube`` directory in the project root run: + + ../tools/insertMyCode.sh + +User code has to life in ``User/Src`` and ``User/Inc``. All ``*.c`` file from ``User/Src`` will be +attached to the ``C_SOURCES`` variable in the ``Makefile``. + + +## Building + +From the ``cube`` directory in the project root simply run + + make + + +## Uploading to the target + +Start ``openocd`` from the project root using the existing configuration file (for derived projects +adjust the configuration concerning the use MCU) + + openocd -f openocd.cfg + +Connect to the started ``openocd`` server using + + nc localhost 4444 + +To upload a built binary enter + + reset init + reset halt + flash write_image erase /home/wn/Workspaces/$PROJECT/cube/build/cube.elf + reset run + +Make sure to use the absolute path. Alternatively, use the script ``upload.sh`` from the tools directory. + + + + + + + diff --git a/tools/insertMyCode.sh b/tools/insertMyCode.sh new file mode 100755 index 0000000..3c4d163 --- /dev/null +++ b/tools/insertMyCode.sh @@ -0,0 +1,83 @@ +#!/bin/bash + +MAIN_C=./Core/Src/main.c +MAIN_C_BAK=${MAIN_C}-bak + +IT_C=./Core/Src/stm32f1xx_it.c +IT_C_BAK=${IT_C}-bak + +MAKEFILE=./Makefile +MAKEFILE_BAK=${MAKEFILE}-bak + +PROCESSED="Processed by $0" + +checkFile () { + FILE=$1 + BAK_FILE=$2 + if [ ! -f $FILE ]; then + echo "no $FILE available" + exit 1 + fi + if [ -f $BAK_FILE ]; then + echo "$BAK_FILE already available, delete manually" + exit 1 + fi + grep -q "$PROCESSED" $FILE + if [ "$?" = "0" ]; then + echo "$FILE has already been processed" + exit 1 + fi +} + + +checkFile $MAIN_C $MAIN_C_BAK +checkFile $MAKEFILE $MAKEFILE_BAK +checkFile $IT_C $IT_C_BAK + +cp $MAIN_C $MAIN_C_BAK +echo "// $PROCESSED" > $MAIN_C +cat $MAIN_C_BAK | \ + sed -e 's,\(/\* USER CODE BEGIN Includes \*/\),\1\n#include "main2.h"\n,' \ + -e 's,\(/\* USER CODE BEGIN 1 \*/\),\1\n my_setup_1();\n,' \ + -e 's,\(/\* USER CODE BEGIN 2 \*/\),\1\n my_setup_2();\n,' \ + -e 's,\(/\* USER CODE BEGIN 3 \*/\),\1\n my_loop();\n,' \ + -e 's,\(/\* USER CODE BEGIN Error_Handler_Debug \*/\),\1\n my_errorHandler();\n,' \ + -e 's,\(/\* USER CODE END Error_Handler_Debug \*/\),\1\n while(1) { };\n,' \ + >> $MAIN_C + +cp $IT_C $IT_C_BAK +echo "// $PROCESSED" > $IT_C +cat $IT_C_BAK | \ + sed -e 's,\(/\* USER CODE BEGIN Includes \*/\),\1\n#include "main2.h"\n,' \ + -e 's,\(/\* USER CODE BEGIN SysTick_IRQn 1 \*/\),\1\n SYSTICK_Callback();\n,' \ + >> $IT_C + + + +SRC_EXT='' +for I in User/Src/*.c; do + SRC_EXT+="$I " +done +for I in hottislib/*.c; do + SRC_EXT+="$I " +done + +cp $MAKEFILE $MAKEFILE_BAK +echo "# $PROCESSED" > $MAKEFILE +cat $MAKEFILE_BAK | \ + sed -e 's/\(-specs=nano.specs\)/\1 -u _printf_float/' \ + -e 's/\(-Wall\)/\1 -Werror/' \ + -e 's%\(# list of ASM program objects\)%OBJECTS += $(addprefix $(BUILD_DIR)/,w5500.a pubsubc.a)\n\1%' \ + -e 's,\($(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)\),$(BUILD_DIR)/w5500.a:\n\t(cd ioLibrary_Driver \&\& $(MAKE) \&\& cp w5500.a ../$(BUILD_DIR) \&\& cd ..)\n\n\1,' \ + -e 's,\(C_SOURCES = \\\),\1\n'"$SRC_EXT"' \\,' \ + -e 's,\(C_INCLUDES = \\\),\1\n-IioLibrary_Driver/Ethernet \\,' \ + -e 's,\(C_INCLUDES = \\\),\1\n-IioLibrary_Driver/Internet/DHCP \\,' \ + -e 's,\(C_INCLUDES = \\\),\1\n-IioLibrary_Driver/Internet/DNS \\,' \ + -e 's,\(C_INCLUDES = \\\),\1\n-IUser/Inc \\,' \ + -e 's,\(C_INCLUDES = \\\),\1\n-Ihottislib \\,' \ + >> $MAKEFILE + + + + + \ No newline at end of file diff --git a/tools/removeGeneratedCode.sh b/tools/removeGeneratedCode.sh new file mode 100755 index 0000000..e87a462 --- /dev/null +++ b/tools/removeGeneratedCode.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +rm -rf build/ Core/ Drivers/ Makefile Makefile-bak startup_stm32f103xe.s STM32F103VCTx_FLASH.ld diff --git a/tools/startBuildEnv.ps1 b/tools/startBuildEnv.ps1 new file mode 100644 index 0000000..d0b2d40 --- /dev/null +++ b/tools/startBuildEnv.ps1 @@ -0,0 +1 @@ +docker run -it --rm -v ${PWD}:/mnt wollud1969/build-env-arm-none-eabi:1.1.0 bash diff --git a/tools/startBuildEnv.sh b/tools/startBuildEnv.sh new file mode 100755 index 0000000..5df0894 --- /dev/null +++ b/tools/startBuildEnv.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run -it --rm -u ${UID} -v ${PWD}:/mnt wollud1969/build-env-arm-none-eabi:1.1.0 bash diff --git a/tools/startCompleteEnv.sh b/tools/startCompleteEnv.sh new file mode 100755 index 0000000..e640de2 --- /dev/null +++ b/tools/startCompleteEnv.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +SESSIONNAME=mbusmaster-dev + +screen -d -m -S $SESSIONNAME +screen -S $SESSIONNAME -p 0 -X title main + +screen -S $SESSIONNAME -X screen 1 +screen -S $SESSIONNAME -p 1 -X title build +screen -S $SESSIONNAME -p 1 -X exec ./tools/startBuildEnv.sh + +screen -S $SESSIONNAME -X screen 2 +screen -S $SESSIONNAME -p 2 -X title test +screen -S $SESSIONNAME -p 2 -X exec ./tools/startTestEnv.sh + +screen -S $SESSIONNAME -X screen 3 +screen -S $SESSIONNAME -p 3 -X title minicom +screen -S $SESSIONNAME -p 3 -X exec minicom + +screen -S $SESSIONNAME -X screen 4 +screen -S $SESSIONNAME -p 4 -X title openocd +screen -S $SESSIONNAME -p 4 -X exec openocd -f ./openocd.cfg + +screen -S $SESSIONNAME -X screen 5 +screen -S $SESSIONNAME -p 5 -X title upload + +screen -S $SESSIONNAME -X screen 6 +screen -S $SESSIONNAME -p 6 -X title edit +screen -S $SESSIONNAME -p 6 -X chdir ./cube + +screen -r $SESSIONNAME + diff --git a/tools/startTestEnv.ps1 b/tools/startTestEnv.ps1 new file mode 100644 index 0000000..335ee03 --- /dev/null +++ b/tools/startTestEnv.ps1 @@ -0,0 +1 @@ +docker run -it --rm -v ${PWD}:/work wollud1969/build-env-c:1.2.0 bash diff --git a/tools/startTestEnv.sh b/tools/startTestEnv.sh new file mode 100755 index 0000000..5da781f --- /dev/null +++ b/tools/startTestEnv.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run -it --rm -u ${UID} -v ${PWD}:/work wollud1969/build-env-c:1.2.0 bash diff --git a/tools/upload.sh b/tools/upload.sh new file mode 100755 index 0000000..95f6c56 --- /dev/null +++ b/tools/upload.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +cat << EOF | nc localhost 4444 +reset halt +flash write_image erase /home/wn/Workspaces/mbusgateway3variant/cube/build/cube.elf +reset run +exit +EOF