This commit is contained in:
Wolfgang Hottgenroth 2021-01-09 22:01:21 +01:00
commit 4b3e3a3710
Signed by: wn
GPG Key ID: E49AF3B9EF6DD469
38 changed files with 3231 additions and 0 deletions

View File

@ -0,0 +1,9 @@
#ifndef _CMDHANDLER_H_
#define _CMDHANDLER_H_
#include <stdint.h>
void cmdHandlerInit();
#endif /* _CMDHANDLER_H_ */

23
cube/User/Inc/cmdHelper.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef _CMDHELPER_H_
#define _CMDHELPER_H_
#include <stdint.h>
#include <stdbool.h>
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_ */

43
cube/User/Inc/config.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include <stdint.h>
#include <spi.h>
#include <assert.h>
#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_ */

50
cube/User/Inc/eeprom.h Normal file
View File

@ -0,0 +1,50 @@
#ifndef EEPROM_H_
#define EEPROM_H_
#include <stdint.h>
#include <spi.h>
#include <config.h>
#include <assert.h>
#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_ */

13
cube/User/Inc/frontend.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _FRONTEND_H_
#define _FRONTEND_H_
#include <stdint.h>
#include <adc.h>
void frontendInit();
void frontendAdcCallback(ADC_HandleTypeDef* hadc);
void frontendEnable();
void frontendDisable();
#endif // _FRONTEND_H_

42
cube/User/Inc/logger.h Normal file
View File

@ -0,0 +1,42 @@
#ifndef _LOGGER_H_
#define _LOGGER_H_
#include <main.h>
#include <stdbool.h>
// 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_

11
cube/User/Inc/main2.h Normal file
View File

@ -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_

226
cube/User/Inc/oled-fonts.h Normal file
View File

@ -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_ */

32
cube/User/Inc/oled.h Normal file
View File

@ -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_ */

View File

@ -0,0 +1,26 @@
#ifndef _RINGBUFFER_H_
#define _RINGBUFFER_H_
#include <stdint.h>
#include <stdbool.h>
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_

20
cube/User/Inc/show.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _SHOW_H_
#define _SHOW_H_
#include <stdint.h>
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_

8
cube/User/Inc/utils.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stdint.h>
void activeDelay(uint8_t delay_ms);
#endif // _UTILS_H_

13
cube/User/Inc/wizHelper.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef _WIZHELPER_H_
#define _WIZHELPER_H_
#include <stdbool.h>
#include <stdint.h>
int wizInit();
bool isNetworkAvailable();
uint8_t* wizGetIPAddress();
bool wizDnsQuery(char *name, uint8_t *ip);
#endif // _WIZHELPER_H_

81
cube/User/Src/adminCmds.c Normal file
View File

@ -0,0 +1,81 @@
#include <cmdHelper.h>
#include <logger.h>
#include <string.h>
#include <mbusComm.h>
#include <loopCtrl.h>
// 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;
}

343
cube/User/Src/cmdHandler.c Normal file
View File

@ -0,0 +1,343 @@
#include <cmdHandler.h>
#include <cmdHelper.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <socket.h>
#include <logger.h>
#include <PontCoopScheduler.h>
#include <wizHelper.h>
#include <config.h>
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);
}

164
cube/User/Src/config.c Normal file
View File

@ -0,0 +1,164 @@
#include <stdint.h>
#include <stdbool.h>
#include <config.h>
#include <eeprom.h>
#include <logger.h>
#include <mbusComm.h>
#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);
}
}
}

447
cube/User/Src/configCmds.c Normal file
View File

@ -0,0 +1,447 @@
#include <cmdHelper.h>
#include <logger.h>
#include <eeprom.h>
#include <config.h>
#include <string.h>
#include <stdlib.h>
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;
}

218
cube/User/Src/eeprom.c Normal file
View File

@ -0,0 +1,218 @@
#include <main.h>
#include <spi.h>
#include <eeprom.h>
#include <string.h>
#include <logger.h>
#include <mbusComm.h>
#include <PontCoopScheduler.h>
#include <utils.h>
#include <assert.h>
#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");
}

59
cube/User/Src/frontend.c Normal file
View File

@ -0,0 +1,59 @@
#include <stdbool.h>
#include <main.h>
#include <adc.h>
#include <frontend.h>
#include <logger.h>
#include <show.h>
#include <config.h>
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);
}
}
}

198
cube/User/Src/logger.c Normal file
View File

@ -0,0 +1,198 @@
#include <main.h>
#include <usart.h>
#include <show.h>
#include <PontCoopScheduler.h>
#include <logger.h>
#include <ringbuffer.h>
#include <wizHelper.h>
#include <socket.h>
#include <config.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#ifdef LOGGER_OUTPUT_BY_INTERRUPT
#include <stm32f103xe.h>
#endif //LOGGER_OUTPUT_BY_INTERRUPT
#ifndef LOGGER_OUTPUT_BY_INTERRUPT
#include <stm32f1xx_hal_uart.h>
#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;
}

109
cube/User/Src/main2.c Normal file
View File

@ -0,0 +1,109 @@
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#include <main.h>
#include <usart.h>
#include <adc.h>
#include <spi.h>
#include <PontCoopScheduler.h>
#include <show.h>
#include <loopCtrl.h>
#include <mbusComm.h>
#include <logger.h>
#include <frontend.h>
#include <eeprom.h>
#include <wizHelper.h>
#include <mqttComm.h>
#include <cmdHandler.h>
#include <oled.h>
#include <config.h>
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);
}
}

461
cube/User/Src/oled.c Normal file
View File

@ -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 <main.h>
#include <spi.h>
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <oled.h>
#include <oled-fonts.h>
#include <stm32f1xx_hal.h>
#include <logger.h>
#include <PontCoopScheduler.h>
#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<x1;x++)
{
oled_WrDat(bmp[ii++]);
}
}
}
*/
/*
* unused
static void oled_Cursor(unsigned char cursor_column, unsigned char cursor_row)
{
if(cursor_row != 0)
{
if(cursor_column == 1) oled_Set_Pos(0, cursor_row + 2);
else oled_Set_Pos(80 + (cursor_column - 2)*6, cursor_row + 2);
oled_WrDat(0xFF);
oled_WrDat(0xFF);
oled_WrDat(0xFF);
oled_WrDat(0xFF);
oled_WrDat(0xFF);
oled_WrDat(0xFF);
}
}
*/
#define MAX_LINES 8
#define MAX_CHARS 21
#define NUM_OF_SCREENS 2
static uint8_t currentLine = 0;
static char lines[NUM_OF_SCREENS][MAX_LINES+1][MAX_CHARS+1];
static oledScreen_t activeScreen = OLED_SCREEN0;
void oledClearActiveScreen() {
oled_CLS();
memset(lines[activeScreen], 0, sizeof(lines[activeScreen]));
currentLine = 0;
}
void oledClearAllScreens() {
oled_CLS();
memset(lines, 0, sizeof(lines));
currentLine = 0;
}
void oledPrint(oledScreen_t screen, char msg[]) {
if (currentLine < MAX_LINES) {
strncpy(lines[screen][currentLine], msg, MAX_CHARS);
memset(lines[screen][currentLine] + strlen(msg), ' ', MAX_CHARS - strlen(msg) - 1);
lines[screen][currentLine][MAX_CHARS - 1] = 0;
currentLine++;
} else {
for (uint8_t i = 1; i < MAX_LINES; i++) {
memcpy(lines[screen][i-1], lines[screen][i], MAX_CHARS);
}
strncpy(lines[screen][MAX_LINES - 1], msg, MAX_CHARS);
memset(lines[screen][MAX_LINES - 1] + strlen(msg), ' ', MAX_CHARS - strlen(msg) - 1);
lines[screen][MAX_LINES - 1][MAX_CHARS - 1] = 0;
}
if (screen == activeScreen) {
for (uint8_t line = 0; line < MAX_LINES; line++) {
oled_P6x8Str(1, line, lines[activeScreen][line]);
}
}
}
static void oledSwitchBackToScreen0(void *handle) {
oledSetActiveScreen(OLED_SCREEN0);
}
void oledSetActiveScreen(oledScreen_t screen) {
activeScreen = screen;
if (screen == OLED_SCREEN1) {
schAdd(oledSwitchBackToScreen0, NULL, 10000, 0);
}
}
void oledPrintf(oledScreen_t screen, const char *format, ...) {
va_list vl;
va_start(vl, format);
char buf[MAX_CHARS+1];
vsnprintf(buf, MAX_CHARS, format, vl);
va_end(vl);
oledPrint(screen, buf);
}

11
cube/User/Src/ports.c Normal file
View File

@ -0,0 +1,11 @@
#include <stdint.h>
// 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;

View File

@ -0,0 +1,57 @@
#include <cmdHelper.h>
#include <logger.h>
#include <mbusComm.h>
#include <eeprom.h>
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;
}

View File

@ -0,0 +1,75 @@
#include <stdlib.h>
#include <string.h>
#include <ringbuffer.h>
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;
}

46
cube/User/Src/show.c Normal file
View File

@ -0,0 +1,46 @@
#include <main.h>
#include <show.h>
#include <PontCoopScheduler.h>
#include <stdint.h>
#include <stdlib.h>
#include <stm32f103xe.h>
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);
}

10
cube/User/Src/utils.c Normal file
View File

@ -0,0 +1,10 @@
#include <utils.h>
#include <main.h>
#include <stdint.h>
// active waiting, use only during initialization!
void activeDelay(uint8_t delay_ms) {
uint32_t startTime = HAL_GetTick();
while (startTime + delay_ms > HAL_GetTick());
}

232
cube/User/Src/wizHelper.c Normal file
View File

@ -0,0 +1,232 @@
#include <wizHelper.h>
#include <stdint.h>
#include <main2.h>
#include <spi.h>
#include <stdbool.h>
#include <logger.h>
#include <PontCoopScheduler.h>
#include <utils.h>
#include <wizchip_conf.h>
#include <string.h>
#include <dhcp.h>
#include <show.h>
#include <oled.h>
#include <dns.h>
#include <config.h>
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(&etherSpi, &rbuf, 1, HAL_MAX_DELAY);
return rbuf;
}
static void wiz_spi_writebyte(uint8_t wb) {
HAL_SPI_Transmit(&etherSpi, &wb, 1, HAL_MAX_DELAY);
}
static void wiz_spi_readburst(uint8_t* pBuf, uint16_t len) {
HAL_SPI_Receive(&etherSpi, pBuf, len, HAL_MAX_DELAY);
}
static void wiz_spi_writeburst(uint8_t* pBuf, uint16_t len) {
HAL_SPI_Transmit(&etherSpi, 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;
}

8
openocd.cfg Normal file
View File

@ -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

62
readme.md Normal file
View File

@ -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.

83
tools/insertMyCode.sh Executable file
View File

@ -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

3
tools/removeGeneratedCode.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
rm -rf build/ Core/ Drivers/ Makefile Makefile-bak startup_stm32f103xe.s STM32F103VCTx_FLASH.ld

1
tools/startBuildEnv.ps1 Normal file
View File

@ -0,0 +1 @@
docker run -it --rm -v ${PWD}:/mnt wollud1969/build-env-arm-none-eabi:1.1.0 bash

3
tools/startBuildEnv.sh Executable file
View File

@ -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

32
tools/startCompleteEnv.sh Executable file
View File

@ -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

1
tools/startTestEnv.ps1 Normal file
View File

@ -0,0 +1 @@
docker run -it --rm -v ${PWD}:/work wollud1969/build-env-c:1.2.0 bash

3
tools/startTestEnv.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/bash
docker run -it --rm -u ${UID} -v ${PWD}:/work wollud1969/build-env-c:1.2.0 bash

8
tools/upload.sh Executable file
View File

@ -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