Initial commit

This commit is contained in:
Jochen Friedrich 2021-01-01 14:06:20 +01:00
commit 66c5a26d69
1145 changed files with 938088 additions and 0 deletions

445
Relays/Core/Src/MySensors.c Normal file
View file

@ -0,0 +1,445 @@
#include "main.h"
#include <string.h>
#include <stdlib.h>
#include "MySensors.h"
#define ICSC_SYS_PACK 0x58
#define SOH 1
#define STX 2
#define ETX 3
#define EOT 4
// message buffers
MyMessage _msg; // Buffer for incoming messages
MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others)
// Receiving header information
char _header[6];
// Reception state machine control and storage variables
unsigned char _recPhase;
unsigned char _recPos;
unsigned char _recCommand;
unsigned char _recLen;
unsigned char _recStation;
unsigned char _recSender;
unsigned char _recCS;
unsigned char _recCalcCS;
unsigned char _packet_received;
UART_HandleTypeDef *_huart;
char _data[MY_RS485_MAX_MESSAGE_LENGTH];
uint8_t _packet_len;
unsigned char _packet_from;
_Bool send(MyMessage *message, uint8_t data_type)
{
message->last = MY_NODE_ID;
message->sender = MY_NODE_ID;
message->destination = GATEWAY_ADDRESS;
message->command_echo_payload = (data_type << 5) + C_SET;
return transportSend(message);
}
_Bool sendHeartbeat(void)
{
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_ULONG32 << 5) + C_INTERNAL;
_msgTmp.type = I_HEARTBEAT_RESPONSE;
_msgTmp.version_length = (4 << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
_msgTmp.ulValue = 0;
return transportSend(&_msgTmp);
}
_Bool present(const uint8_t childSensorId, const mysensors_sensor_t sensorType, char *desc)
{
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_STRING << 5) + C_PRESENTATION;
_msgTmp.type = sensorType;
_msgTmp.sensor = childSensorId;
_msgTmp.version_length = (strlen(desc) << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
strcpy((char *)_msgTmp.data, desc);
return transportSend(&_msgTmp);
}
void registerNode(void)
{
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_BYTE << 5) + C_INTERNAL;
_msgTmp.type = I_REGISTRATION_REQUEST;
_msgTmp.sensor = 0;
_msgTmp.version_length = (1 << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
_msgTmp.bValue = MY_CORE_VERSION;
transportSend(&_msgTmp);
}
void sendLibraryInfo(void)
{
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_STRING << 5) + C_INTERNAL;
_msgTmp.type = I_VERSION;
_msgTmp.version_length = (strlen(MY_LIBRARY_VERSION) << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
strcpy((char *)_msgTmp.data, MY_LIBRARY_VERSION);
transportSend(&_msgTmp);
}
_Bool sendSketchInfo(const char *name, const char *version)
{
_Bool result = 1;
if (name) {
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_STRING << 5) + C_INTERNAL;
_msgTmp.type = I_SKETCH_NAME;
_msgTmp.version_length = (strlen(name) << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
strcpy((char *)_msgTmp.data, name);
result &= transportSend(&_msgTmp);
}
if (version) {
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = GATEWAY_ADDRESS;
_msgTmp.command_echo_payload = (P_STRING << 5) + C_INTERNAL;
_msgTmp.type = I_SKETCH_VERSION;
_msgTmp.version_length = (strlen(name) << 3) + V2_MYS_HEADER_PROTOCOL_VERSION;
strcpy((char *)_msgTmp.data, version);
result &= transportSend(&_msgTmp);
}
sendLibraryInfo();
return result;
}
// Message delivered through _msg
_Bool _processInternalCoreMessage(void)
{
const uint8_t type = _msg.type;
if (_msg.sender == GATEWAY_ADDRESS) {
if (type == I_PRESENTATION) {
// Re-send node presentation to controller
present_node();
} else if (type == I_HEARTBEAT_REQUEST) {
(void)sendHeartbeat();
} else if (type == I_REBOOT) {
NVIC_SystemReset();
} else if (type == I_VERSION) {
sendLibraryInfo();
} else {
return 0; // further processing required
}
} else {
return 0; // further processing required
}
return 1; // if not GW or no further processing required
}
void transportProcessMessage(void)
{
// get message length and limit size
const uint8_t msgLength = (_msg.version_length & 0xF8) >> 3;
// calculate expected length
const uint8_t command = _msg.command_echo_payload & 0x07;
const uint8_t type = _msg.type;
const uint8_t sender = _msg.sender;
const uint8_t destination = _msg.destination;
// Is message addressed to this node?
if (destination == MY_NODE_ID) {
// null terminate data
_msg.data[msgLength] = 0u;
// Check if sender requests an echo.
if (_msg.command_echo_payload & 0x08) {
memcpy(&_msgTmp, &_msg, sizeof(_msg)); // Copy message
// Reply without echo flag (otherwise we would end up in an eternal loop)
_msgTmp.command_echo_payload = _msgTmp.command_echo_payload & 0xE7;
_msgTmp.command_echo_payload = _msgTmp.command_echo_payload | 0x10;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = sender;
transportSend(&_msgTmp);
}
if(!(_msg.command_echo_payload & 0x10)) {
// only process if not ECHO
if (command == C_INTERNAL) {
if (type == I_ID_RESPONSE) {
return; // no further processing required
}
// general
if (type == I_PING) {
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = sender;
_msgTmp.command_echo_payload = (P_BYTE << 5) + C_INTERNAL;
_msgTmp.type = I_PONG;
_msgTmp.bValue = 1;
transportSend(&_msgTmp);
return; // no further processing required
}
if (type == I_PONG) {
return; // no further processing required
}
if (_processInternalCoreMessage()) {
return; // no further processing required
}
}
}
// Call incoming message callback if available
receive(&_msg);
} else if (destination == BROADCAST_ADDRESS) {
if (command == C_INTERNAL) {
if (type == I_DISCOVER_REQUEST) {
HAL_Delay(MY_NODE_ID * 50);
_msgTmp.last = MY_NODE_ID;
_msgTmp.sender = MY_NODE_ID;
_msgTmp.destination = sender;
_msgTmp.command_echo_payload = (P_BYTE << 5) + C_INTERNAL;
_msgTmp.type = I_DISCOVER_RESPONSE;
_msgTmp.bValue = GATEWAY_ADDRESS;
transportSend(&_msgTmp);
return; // no further processing required
}
}
if (command != C_INTERNAL) {
receive(&_msg);
}
}
}
//Reset the state machine and release the data pointer
void _serialReset()
{
_recPhase = 0;
_recPos = 0;
_recLen = 0;
_recCommand = 0;
_recCS = 0;
_recCalcCS = 0;
}
// This is the main reception state machine. Progress through the states
// is keyed on either special control characters, or counted number of bytes
// received. If all the data is in the right format, and the calculated
// checksum matches the received checksum, AND the destination station is
// our station ID, then look for a registered command that matches the
// command code. If all the above is true, execute the command's
// function.
_Bool _serialProcess()
{
unsigned char i;
if (!_byte_received) {
return 0;
}
_byte_received = 0;
switch(_recPhase) {
// Case 0 looks for the header. Bytes arrive in the serial interface and get
// shifted through a header buffer. When the start and end characters in
// the buffer match the SOH/STX pair, and the destination station ID matches
// our ID, save the header information and progress to the next state.
case 0:
memcpy(&_header[0],&_header[1],5);
_header[5] = _byte;
if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) {
_recCalcCS = 0;
_recStation = _header[1];
_recSender = _header[2];
_recCommand = _header[3];
_recLen = _header[4];
for (i=1; i<=4; i++) {
_recCalcCS += _header[i];
}
_recPhase = 1;
_recPos = 0;
//Avoid _data[] overflow
if (_recLen >= MY_RS485_MAX_MESSAGE_LENGTH) {
_serialReset();
break;
}
//Check if we should process this message
//We reject the message if we are the sender
//We reject if we are not the receiver and message is not a broadcast
if ((_recSender == MY_NODE_ID) ||
(_recStation != MY_NODE_ID &&
_recStation != BROADCAST_ADDRESS)) {
_serialReset();
break;
}
if (_recLen == 0) {
_recPhase = 2;
}
}
break;
// Case 1 receives the data portion of the packet. Read in "_recLen" number
// of bytes and store them in the _data array.
case 1:
_data[_recPos++] = _byte;
_recCalcCS += _byte;
if (_recPos == _recLen) {
_recPhase = 2;
}
break;
// After the data comes a single ETX character. Do we have it? If not,
// reset the state machine to default and start looking for a new header.
case 2:
// Packet properly terminated?
if (_byte == ETX) {
_recPhase = 3;
} else {
_serialReset();
}
break;
// Next comes the checksum. We have already calculated it from the incoming
// data, so just store the incoming checksum byte for later.
case 3:
_recCS = _byte;
_recPhase = 4;
break;
// The final state - check the last character is EOT and that the checksum matches.
// If that test passes, then look for a valid command callback to execute.
// Execute it if found.
case 4:
if (_byte == EOT) {
if (_recCS == _recCalcCS) {
// First, check for system level commands. It is possible
// to register your own callback as well for system level
// commands which will be called after the system default
// hook.
switch (_recCommand) {
case ICSC_SYS_PACK:
_packet_from = _recSender;
_packet_len = _recLen;
_packet_received = 1;
break;
}
}
}
//Clear the data
_serialReset();
//Return true, we have processed one command
return 1;
break;
}
return 1;
}
_Bool transportSend(MyMessage* data)
{
const char *datap = (const char *)data;
unsigned char i;
unsigned char len;
unsigned char cs = 0;
// This is how many times to try and transmit before failing.
unsigned char timeout = 10;
// Let's start out by looking for a collision. If there has been anything seen in
// the last millisecond, then wait for a random time and check again.
while (_serialProcess()) {
unsigned char del;
del = rand() % 20;
for (i = 0; i < del; i++) {
HAL_Delay(1);
_serialProcess();
}
timeout--;
if (timeout == 0) {
// Failed to transmit!!!
return 0;
}
}
HAL_GPIO_WritePin(TEN_GPIO_Port, TEN_Pin, SET);
// Start of header by writing multiple SOH
i = SOH;
for(uint8_t w=0; w<MY_RS485_SOH_COUNT; w++) {
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
}
HAL_UART_Transmit(_huart, (uint8_t*)&data->destination, 1, 20);
cs += data->destination;
i = MY_NODE_ID;
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
cs += MY_NODE_ID;
i = ICSC_SYS_PACK; // Command code
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
cs += ICSC_SYS_PACK;
len = (data->version_length >> 3) + V2_MYS_HEADER_SIZE;
HAL_UART_Transmit(_huart, (uint8_t*)&len, 1, 20);
cs += len;
i = STX;
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
HAL_UART_Transmit(_huart, (uint8_t*)datap, len, len + 20);
for(i=0; i<len; i++) {
cs += datap[i];
}
i = ETX;
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
HAL_UART_Transmit(_huart, (uint8_t*)&cs, 1, 20);
i = EOT;
HAL_UART_Transmit(_huart, (uint8_t*)&i, 1, 20);
HAL_GPIO_WritePin(TEN_GPIO_Port, TEN_Pin, RESET);
return 1;
}
void transportInitialise(UART_HandleTypeDef *huart)
{
_huart = huart;
HAL_GPIO_WritePin(TEN_GPIO_Port, TEN_Pin, RESET);
_serialReset();
_byte_received = 0;
srand(MY_NODE_ID);
HAL_Delay(MY_NODE_ID * 50);
present_node();
}
void transportProcess(void)
{
_serialProcess();
if (transportReceive(&_msg))
transportProcessMessage();
}
uint8_t transportReceive(void* data)
{
if (_packet_received) {
memcpy(data,_data,_packet_len);
_packet_received = 0;
return _packet_len;
} else {
return (0);
}
}

310
Relays/Core/Src/MySensors.h Normal file
View file

@ -0,0 +1,310 @@
#ifndef MySensors_h
#define MySensors_h
#include <stddef.h>
#include <stdarg.h>
#define MY_LIBRARY_VERSION "STM 1.0"
#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch
#define MY_NODE_ID ((uint8_t)200)
#define NODE_SENSOR_ID ((uint8_t)255) //!< Node child is always created/presented when a node is started
#define MY_CORE_VERSION ((uint8_t)2) //!< core version
#define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility
#define V2_MYS_HEADER_PROTOCOL_VERSION (2u) //!< Protocol version
#define V2_MYS_HEADER_SIZE (7u) //!< Header size
#define V2_MYS_HEADER_MAX_MESSAGE_SIZE (32u) //!< Max payload size
#define V2_MYS_HEADER_VSL_VERSION_POS (0) //!< bitfield position version
#define V2_MYS_HEADER_VSL_VERSION_SIZE (2u) //!< size version field
#define V2_MYS_HEADER_VSL_SIGNED_POS (2u) //!< bitfield position signed field
#define V2_MYS_HEADER_VSL_SIGNED_SIZE (1u) //!< size signed field
#define V2_MYS_HEADER_VSL_LENGTH_POS (3u) //!< bitfield position length field
#define V2_MYS_HEADER_VSL_LENGTH_SIZE (5u) //!< size length field
#define V2_MYS_HEADER_CEP_COMMAND_POS (0) //!< bitfield position command field
#define V2_MYS_HEADER_CEP_COMMAND_SIZE (3u) //!< size command field
#define V2_MYS_HEADER_CEP_ECHOREQUEST_POS (3u) //!< bitfield position echo request field
#define V2_MYS_HEADER_CEP_ECHOREQUEST_SIZE (1u) //!< size echo request field
#define V2_MYS_HEADER_CEP_ECHO_POS (4u) //!< bitfield position echo field
#define V2_MYS_HEADER_CEP_ECHO_SIZE (1u) //!< size echo field
#define V2_MYS_HEADER_CEP_PAYLOADTYPE_POS (5u) //!< bitfield position payload type field
#define V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE (3u) //!< size payload type field
#define MAX_MESSAGE_SIZE V2_MYS_HEADER_MAX_MESSAGE_SIZE //!< The maximum size of a message (including header)
#define HEADER_SIZE V2_MYS_HEADER_SIZE //!< The size of the header
#define MAX_PAYLOAD_SIZE (MAX_MESSAGE_SIZE - HEADER_SIZE) //!< The maximum size of a payload depends on #MAX_MESSAGE_SIZE and #HEADER_SIZE
#define MY_RS485_MAX_MESSAGE_LENGTH MAX_MESSAGE_SIZE
#define MY_RS485_SOH_COUNT 1
#define MY_CAP_RESET "N"
#define MY_CAP_OTA_FW "N"
#define MY_CAP_RADIO "S"
#define MY_CAP_TYPE "N"
#define MY_CAP_ARCH "F"
#define MY_CAP_SIGN "-"
#define MY_CAP_RXBUF "-"
#define MY_CAP_ENCR "-"
#define MY_CAPABILITIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN MY_CAP_RXBUF MY_CAP_ENCR
#define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes
#define MY_TRANSPORT_MAX_TSM_FAILURES (7u) //!< Max. number of consecutive TSM failure state entries (3bits)
#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE_MS (60*1000ul) //!< Duration extended failure state (in ms)
#define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms)
#define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms)
#define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE
#define BROADCAST_ADDRESS (255u) //!< broadcasts are addressed to ID 255
#define MAX_SUBSEQ_MSGS (5u) //!< Maximum number of subsequently processed messages in FIFO (to prevent transport deadlock if HW issue)
/**
* @brief Node core configuration
*/
/// @brief The command field (message-type) defines the overall properties of a message
typedef enum {
C_PRESENTATION = 0, //!< Sent by a node when they present attached sensors. This is usually done in presentation() at startup.
C_SET = 1, //!< This message is sent from or to a sensor when a sensor value should be updated.
C_REQ = 2, //!< Requests a variable value (usually from an actuator destined for controller).
C_INTERNAL = 3, //!< Internal MySensors messages (also include common messages provided/generated by the library).
C_STREAM = 4, //!< For firmware and other larger chunks of data that need to be divided into pieces.
C_RESERVED_5 = 5, //!< C_RESERVED_5
C_RESERVED_6 = 6, //!< C_RESERVED_6
C_INVALID_7 = 7 //!< C_INVALID_7
} mysensors_command_t;
/// @brief Type of sensor (used when presenting sensors)
typedef enum {
S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED
S_MOTION = 1, //!< Motion sensor, V_TRIPPED, V_ARMED
S_SMOKE = 2, //!< Smoke sensor, V_TRIPPED, V_ARMED
S_BINARY = 3, //!< Binary light or relay, V_STATUS, V_WATT
S_LIGHT = 3, //!< \deprecated Same as S_BINARY
S_DIMMER = 4, //!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT
S_COVER = 5, //!< Blinds or window cover, V_UP, V_DOWN, V_STOP, V_PERCENTAGE (open/close to a percentage)
S_TEMP = 6, //!< Temperature sensor, V_TEMP
S_HUM = 7, //!< Humidity sensor, V_HUM
S_BARO = 8, //!< Barometer sensor, V_PRESSURE, V_FORECAST
S_WIND = 9, //!< Wind sensor, V_WIND, V_GUST
S_RAIN = 10, //!< Rain sensor, V_RAIN, V_RAINRATE
S_UV = 11, //!< Uv sensor, V_UV
S_WEIGHT = 12, //!< Personal scale sensor, V_WEIGHT, V_IMPEDANCE
S_POWER = 13, //!< Power meter, V_WATT, V_KWH, V_VAR, V_VA, V_POWER_FACTOR
S_HEATER = 14, //!< Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP
S_DISTANCE = 15, //!< Distance sensor, V_DISTANCE
S_LIGHT_LEVEL = 16, //!< Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux)
S_ARDUINO_NODE = 17, //!< Used (internally) for presenting a non-repeating Arduino node
S_ARDUINO_REPEATER_NODE = 18, //!< Used (internally) for presenting a repeating Arduino node
S_LOCK = 19, //!< Lock device, V_LOCK_STATUS
S_IR = 20, //!< IR device, V_IR_SEND, V_IR_RECEIVE
S_WATER = 21, //!< Water meter, V_FLOW, V_VOLUME
S_AIR_QUALITY = 22, //!< Air quality sensor, V_LEVEL
S_CUSTOM = 23, //!< Custom sensor
S_DUST = 24, //!< Dust sensor, V_LEVEL
S_SCENE_CONTROLLER = 25, //!< Scene controller device, V_SCENE_ON, V_SCENE_OFF.
S_RGB_LIGHT = 26, //!< RGB light. Send color component data using V_RGB. Also supports V_WATT
S_RGBW_LIGHT = 27, //!< RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT
S_COLOR_SENSOR = 28, //!< Color sensor, send color information using V_RGB
S_HVAC = 29, //!< Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP
S_MULTIMETER = 30, //!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE
S_SPRINKLER = 31, //!< Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
S_WATER_LEAK = 32, //!< Water leak sensor, V_TRIPPED, V_ARMED
S_SOUND = 33, //!< Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB)
S_VIBRATION = 34, //!< Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz)
S_MOISTURE = 35, //!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?)
S_INFO = 36, //!< LCD text device / Simple information device on controller, V_TEXT
S_GAS = 37, //!< Gas meter, V_FLOW, V_VOLUME
S_GPS = 38, //!< GPS Sensor, V_POSITION
S_WATER_QUALITY = 39 //!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS
} mysensors_sensor_t;
/// @brief Type of sensor data (for set/req/echo messages)
typedef enum {
V_TEMP = 0, //!< S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC
V_HUM = 1, //!< S_HUM. Humidity
V_STATUS = 2, //!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off
V_LIGHT = 2, //!< \deprecated Same as V_STATUS
V_PERCENTAGE = 3, //!< S_DIMMER. Used for sending a percentage value 0-100 (%).
V_DIMMER = 3, //!< \deprecated Same as V_PERCENTAGE
V_PRESSURE = 4, //!< S_BARO. Atmospheric Pressure
V_FORECAST = 5, //!< S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
V_RAIN = 6, //!< S_RAIN. Amount of rain
V_RAINRATE = 7, //!< S_RAIN. Rate of rain
V_WIND = 8, //!< S_WIND. Wind speed
V_GUST = 9, //!< S_WIND. Gust
V_DIRECTION = 10, //!< S_WIND. Wind direction 0-360 (degrees)
V_UV = 11, //!< S_UV. UV light level
V_WEIGHT = 12, //!< S_WEIGHT. Weight(for scales etc)
V_DISTANCE = 13, //!< S_DISTANCE. Distance
V_IMPEDANCE = 14, //!< S_MULTIMETER, S_WEIGHT. Impedance value
V_ARMED = 15, //!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed
V_TRIPPED = 16, //!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0
V_WATT = 17, //!< S_POWER, S_BINARY, S_DIMMER, S_RGB_LIGHT, S_RGBW_LIGHT. Watt value for power meters
V_KWH = 18, //!< S_POWER. Accumulated number of KWH for a power meter
V_SCENE_ON = 19, //!< S_SCENE_CONTROLLER. Turn on a scene
V_SCENE_OFF = 20, //!< S_SCENE_CONTROLLER. Turn of a scene
V_HVAC_FLOW_STATE = 21, //!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver")
V_HEATER = 21, //!< \deprecated Same as V_HVAC_FLOW_STATE
V_HVAC_SPEED = 22, //!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
V_LIGHT_LEVEL = 23, //!< S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux
V_VAR1 = 24, //!< VAR1
V_VAR2 = 25, //!< VAR2
V_VAR3 = 26, //!< VAR3
V_VAR4 = 27, //!< VAR4
V_VAR5 = 28, //!< VAR5
V_UP = 29, //!< S_COVER. Window covering. Up
V_DOWN = 30, //!< S_COVER. Window covering. Down
V_STOP = 31, //!< S_COVER. Window covering. Stop
V_IR_SEND = 32, //!< S_IR. Send out an IR-command
V_IR_RECEIVE = 33, //!< S_IR. This message contains a received IR-command
V_FLOW = 34, //!< S_WATER. Flow of water (in meter)
V_VOLUME = 35, //!< S_WATER. Water volume
V_LOCK_STATUS = 36, //!< S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked
V_LEVEL = 37, //!< S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux)
V_VOLTAGE = 38, //!< S_MULTIMETER
V_CURRENT = 39, //!< S_MULTIMETER
V_RGB = 40, //!< S_RGB_LIGHT, S_COLOR_SENSOR. Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component)
V_RGBW = 41, //!< S_RGBW_LIGHT. Sent as ASCII hex: RRGGBBWW (WW=white component)
V_ID = 42, //!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b).
V_UNIT_PREFIX = 43, //!< Allows sensors to send in a string representing the unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
V_HVAC_SETPOINT_COOL = 44, //!< S_HVAC. HVAC cool setpoint (Integer between 0-100)
V_HVAC_SETPOINT_HEAT = 45, //!< S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100)
V_HVAC_FLOW_MODE = 46, //!< S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
V_TEXT = 47, //!< S_INFO. Text message to display on LCD or controller device
V_CUSTOM = 48, //!< Custom messages used for controller/inter node specific commands, preferably using S_CUSTOM device type.
V_POSITION = 49, //!< GPS position and altitude. Payload: latitude;longitude;altitude(m). E.g. "55.722526;13.017972;18"
V_IR_RECORD = 50, //!< Record IR codes S_IR for playback
V_PH = 51, //!< S_WATER_QUALITY, water PH
V_ORP = 52, //!< S_WATER_QUALITY, water ORP : redox potential in mV
V_EC = 53, //!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm)
V_VAR = 54, //!< S_POWER, Reactive power: volt-ampere reactive (var)
V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA)
V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
} mysensors_data_t;
/// @brief Type of internal messages (for internal messages)
typedef enum {
I_BATTERY_LEVEL = 0, //!< Battery level
I_TIME = 1, //!< Time (request/response)
I_VERSION = 2, //!< Version
I_ID_REQUEST = 3, //!< ID request
I_ID_RESPONSE = 4, //!< ID response
I_INCLUSION_MODE = 5, //!< Inclusion mode
I_CONFIG = 6, //!< Config (request/response)
I_FIND_PARENT_REQUEST = 7, //!< Find parent
I_FIND_PARENT_RESPONSE = 8, //!< Find parent response
I_LOG_MESSAGE = 9, //!< Log message
I_CHILDREN = 10, //!< Children
I_SKETCH_NAME = 11, //!< Sketch name
I_SKETCH_VERSION = 12, //!< Sketch version
I_REBOOT = 13, //!< Reboot request
I_GATEWAY_READY = 14, //!< Gateway ready
I_SIGNING_PRESENTATION = 15, //!< Provides signing related preferences (first byte is preference version)
I_NONCE_REQUEST = 16, //!< Request for a nonce
I_NONCE_RESPONSE = 17, //!< Payload is nonce data
I_HEARTBEAT_REQUEST = 18, //!< Heartbeat request
I_PRESENTATION = 19, //!< Presentation message
I_DISCOVER_REQUEST = 20, //!< Discover request
I_DISCOVER_RESPONSE = 21, //!< Discover response
I_HEARTBEAT_RESPONSE = 22, //!< Heartbeat response
I_LOCKED = 23, //!< Node is locked (reason in string-payload)
I_PING = 24, //!< Ping sent to node, payload incremental hop counter
I_PONG = 25, //!< In return to ping, sent back to sender, payload incremental hop counter
I_REGISTRATION_REQUEST = 26, //!< Register request to GW
I_REGISTRATION_RESPONSE = 27, //!< Register response from GW
I_DEBUG = 28, //!< Debug message
I_SIGNAL_REPORT_REQUEST = 29, //!< Device signal strength request
I_SIGNAL_REPORT_REVERSE = 30, //!< Internal
I_SIGNAL_REPORT_RESPONSE = 31, //!< Device signal strength response (RSSI)
I_PRE_SLEEP_NOTIFICATION = 32, //!< Message sent before node is going to sleep
I_POST_SLEEP_NOTIFICATION = 33 //!< Message sent after node woke up (if enabled)
} mysensors_internal_t;
/// @brief Type of data stream (for streamed message)
typedef enum {
ST_FIRMWARE_CONFIG_REQUEST = 0, //!< Request new FW, payload contains current FW details
ST_FIRMWARE_CONFIG_RESPONSE = 1, //!< New FW details to initiate OTA FW update
ST_FIRMWARE_REQUEST = 2, //!< Request FW block
ST_FIRMWARE_RESPONSE = 3, //!< Response FW block
ST_SOUND = 4, //!< Sound
ST_IMAGE = 5, //!< Image
ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data
} mysensors_stream_t;
/// @brief Type of payload
typedef enum {
P_STRING = 0, //!< Payload type is string
P_BYTE = 1, //!< Payload type is byte
P_INT16 = 2, //!< Payload type is INT16
P_UINT16 = 3, //!< Payload type is UINT16
P_LONG32 = 4, //!< Payload type is INT32
P_ULONG32 = 5, //!< Payload type is UINT32
P_CUSTOM = 6, //!< Payload type is binary
P_FLOAT32 = 7 //!< Payload type is float32
} mysensors_payload_t;
typedef union {
struct {
uint8_t last; //!< 8 bit - Id of last node this message passed
uint8_t sender; //!< 8 bit - Id of sender node (origin)
uint8_t destination; //!< 8 bit - Id of destination node
/**
* 2 bit - Protocol version<br>
* 1 bit - Signed flag<br>
* 5 bit - Length of payload
*/
uint8_t version_length;
/**
* 3 bit - Command type<br>
* 1 bit - Request an echo - Indicator that receiver should echo the message back to the sender<br>
* 1 bit - Is echo message - Indicator that this is the echoed message<br>
* 3 bit - Payload data type
*/
uint8_t command_echo_payload;
uint8_t type; //!< 8 bit - Type varies depending on command
uint8_t sensor; //!< 8 bit - Id of sensor that this message concerns.
/*
* Each message can transfer a payload. We add one extra byte for string
* terminator \0 to be "printable" this is not transferred OTA
* This union is used to simplify the construction of the binary data types transferred.
*/
union {
uint8_t bValue; //!< unsigned byte value (8-bit)
uint16_t uiValue; //!< unsigned integer value (16-bit)
int16_t iValue; //!< signed integer value (16-bit)
uint32_t ulValue; //!< unsigned long value (32-bit)
int32_t lValue; //!< signed long value (32-bit)
struct { //!< Float messages
float fValue;
uint8_t fPrecision; //!< Number of decimals when serializing
};
char data[MAX_PAYLOAD_SIZE + 1]; //!< Buffer for raw payload data
} __attribute__((packed)); //!< Doxygen will complain without this comment
};
uint8_t array[HEADER_SIZE + MAX_PAYLOAD_SIZE + 1]; //!< buffer for entire message
} __attribute__((packed)) MyMessage;
void registerNode(void);
void present_node(void);
_Bool present(const uint8_t sensorId, const mysensors_sensor_t sensorType, char *desc);
_Bool sendSketchInfo(const char *name, const char *version);
_Bool send(MyMessage *msg,uint8_t data_type);
_Bool sendHeartbeat(void);
void receive(const MyMessage*);
void transportProcessMessage(void);
_Bool transportSend(MyMessage *message);
void transportInitialise(UART_HandleTypeDef *huart);
void transportProcess(void);
uint8_t transportReceive(void *data);
_Bool isMessageReceived(void);
void resetMessageReceived(void);
uint32_t transportGetHeartbeat(void);
#endif // MySensors_h

390
Relays/Core/Src/main.c Normal file
View file

@ -0,0 +1,390 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include "MySensors.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define IN_ID1 1
#define IN_ID2 2
#define RELAY_ID1 3
#define RELAY_ID2 4
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
//MyMessage msg;
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(Relay1_GPIO_Port, Relay1_Pin, RESET);
HAL_GPIO_WritePin(Relay2_GPIO_Port, Relay2_Pin, RESET);
HAL_GPIO_WritePin(TEN_GPIO_Port, TEN_Pin, RESET);
transportInitialise(&huart1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
uint8_t value;
static uint16_t loopv;
static uint16_t counter;
static uint8_t sentValue1=2;
static uint8_t sentValue2=2;
static uint8_t sentStatus=0;
static uint8_t button=0;
MyMessage msg;
transportProcess(); // Process incoming data
loopv++;
value = HAL_GPIO_ReadPin(IN1_GPIO_Port, IN1_Pin);
if (value != sentValue1) {
// Value has changed from last transmission, send the updated value
msg.version_length = V2_MYS_HEADER_PROTOCOL_VERSION + (1 << 3);
msg.sensor = IN_ID1;
msg.type = V_TRIPPED;
msg.bValue = value;
send(&msg, P_BYTE);
sentValue1 = value;
}
value = HAL_GPIO_ReadPin(IN2_GPIO_Port, IN2_Pin);
if (value != sentValue2) {
// Value has changed from last transmission, send the updated value
msg.version_length = V2_MYS_HEADER_PROTOCOL_VERSION + (1 << 3);
msg.sensor = IN_ID2;
msg.type = V_TRIPPED;
msg.bValue = value;
send(&msg, P_BYTE);
sentValue2 = value;
}
value = HAL_GPIO_ReadPin(Button_GPIO_Port, Button_Pin);
if (value != button) {
button = value;
if (button) {
sentValue1 = 2;
sentValue2 = 2;
sentStatus = 0;
present_node();
}
}
if (sentStatus == 0) {
sentStatus = 1;
value = HAL_GPIO_ReadPin(Relay1_GPIO_Port, Relay1_Pin);
msg.version_length = V2_MYS_HEADER_PROTOCOL_VERSION + (1 << 3);
msg.sensor = RELAY_ID1;
msg.type = V_STATUS;
if (value)
strcpy(msg.data, "1");
else
strcpy(msg.data, "0");
send(&msg, P_STRING);
value = HAL_GPIO_ReadPin(Relay2_GPIO_Port, Relay2_Pin);
msg.version_length = V2_MYS_HEADER_PROTOCOL_VERSION + (1 << 3);
msg.sensor = RELAY_ID2;
msg.type = V_STATUS;
if (value)
strcpy(msg.data, "1");
else
strcpy(msg.data, "0");
send(&msg, P_STRING);
}
if (loopv == 0) {
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
counter++;
if (counter > 3600) {
sentValue1 = 2;
sentValue2 = 2;
sentStatus = 0;
counter = 0;
}
}
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL3;
RCC_OscInitStruct.PLL.PREDIV = RCC_PREDIV_DIV1;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 9600;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
/* USER CODE END USART1_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, LED_Pin|TEN_Pin|Relay1_Pin, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(Relay2_GPIO_Port, Relay2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : IN2_Pin IN1_Pin Button_Pin */
GPIO_InitStruct.Pin = IN2_Pin|IN1_Pin|Button_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pins : LED_Pin Relay1_Pin */
GPIO_InitStruct.Pin = LED_Pin|Relay1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : TEN_Pin */
GPIO_InitStruct.Pin = TEN_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TEN_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : Relay2_Pin */
GPIO_InitStruct.Pin = Relay2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(Relay2_GPIO_Port, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
void present_node(void)
{
present(NODE_SENSOR_ID, S_ARDUINO_NODE,"STM Relay Board");
sendSketchInfo("Relay_STM", "1.1");
present(IN_ID1, S_DOOR, "Input ID1");
present(IN_ID2, S_DOOR, "Input ID2");
present(RELAY_ID1, S_BINARY, "Relay 1");
present(RELAY_ID2, S_BINARY, "Relay 2");
registerNode();
HAL_Delay(20);
}
void receive(const MyMessage* mymsg)
{
uint8_t sensor;
// We only expect one type of message from controller. But we better check anyway.
if (mymsg->type == V_STATUS) {
sensor = mymsg->sensor;
if (sensor == 3)
HAL_GPIO_WritePin(Relay1_GPIO_Port, Relay1_Pin, (mymsg->data[0]=='1')?SET:RESET);
if (sensor == 4)
HAL_GPIO_WritePin(Relay2_GPIO_Port, Relay2_Pin, (mymsg->data[0]=='1')?SET:RESET);
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,154 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f0xx_hal_msp.c
* @brief This file provides code for the MSP Initialization
* and de-Initialization codes.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN Define */
/* USER CODE END Define */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN Macro */
/* USER CODE END Macro */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* External functions --------------------------------------------------------*/
/* USER CODE BEGIN ExternalFunctions */
/* USER CODE END ExternalFunctions */
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* Initializes the Global MSP.
*/
void HAL_MspInit(void)
{
/* USER CODE BEGIN MspInit 0 */
/* USER CODE END MspInit 0 */
__HAL_RCC_SYSCFG_CLK_ENABLE();
__HAL_RCC_PWR_CLK_ENABLE();
/* System interrupt init*/
/* USER CODE BEGIN MspInit 1 */
/* USER CODE END MspInit 1 */
}
/**
* @brief UART MSP Initialization
* This function configures the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspInit(UART_HandleTypeDef* huart)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspInit 0 */
/* USER CODE END USART1_MspInit 0 */
/* Peripheral clock enable */
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF1_USART1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspInit 1 */
/* USER CODE END USART1_MspInit 1 */
}
}
/**
* @brief UART MSP De-Initialization
* This function freeze the hardware resources used in this example
* @param huart: UART handle pointer
* @retval None
*/
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart)
{
if(huart->Instance==USART1)
{
/* USER CODE BEGIN USART1_MspDeInit 0 */
/* USER CODE END USART1_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART1_CLK_DISABLE();
/**USART1 GPIO Configuration
PA9 ------> USART1_TX
PA10 ------> USART1_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
/* USART1 interrupt DeInit */
HAL_NVIC_DisableIRQ(USART1_IRQn);
/* USER CODE BEGIN USART1_MspDeInit 1 */
/* USER CODE END USART1_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View file

@ -0,0 +1,164 @@
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file stm32f0xx_it.c
* @brief Interrupt Service Routines.
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f0xx_it.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN TD */
/* USER CODE END TD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/* External variables --------------------------------------------------------*/
extern UART_HandleTypeDef huart1;
/* USER CODE BEGIN EV */
/* USER CODE END EV */
/******************************************************************************/
/* Cortex-M0 Processor Interruption and Exception Handlers */
/******************************************************************************/
/**
* @brief This function handles Non maskable interrupt.
*/
void NMI_Handler(void)
{
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
/* USER CODE END NonMaskableInt_IRQn 0 */
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
while (1)
{
}
/* USER CODE END NonMaskableInt_IRQn 1 */
}
/**
* @brief This function handles Hard fault interrupt.
*/
void HardFault_Handler(void)
{
/* USER CODE BEGIN HardFault_IRQn 0 */
/* USER CODE END HardFault_IRQn 0 */
while (1)
{
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
/* USER CODE END W1_HardFault_IRQn 0 */
}
}
/**
* @brief This function handles System service call via SWI instruction.
*/
void SVC_Handler(void)
{
/* USER CODE BEGIN SVC_IRQn 0 */
/* USER CODE END SVC_IRQn 0 */
/* USER CODE BEGIN SVC_IRQn 1 */
/* USER CODE END SVC_IRQn 1 */
}
/**
* @brief This function handles Pendable request for system service.
*/
void PendSV_Handler(void)
{
/* USER CODE BEGIN PendSV_IRQn 0 */
/* USER CODE END PendSV_IRQn 0 */
/* USER CODE BEGIN PendSV_IRQn 1 */
/* USER CODE END PendSV_IRQn 1 */
}
/**
* @brief This function handles System tick timer.
*/
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
/******************************************************************************/
/* STM32F0xx Peripheral Interrupt Handlers */
/* Add here the Interrupt Handlers for the used peripherals. */
/* For the available peripheral interrupt handler names, */
/* please refer to the startup file (startup_stm32f0xx.s). */
/******************************************************************************/
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
_byte = USART1->RDR;
_byte_received = 1;
return; // To avoid calling the handler at all
// (in case you want to save the time)
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

159
Relays/Core/Src/syscalls.c Normal file
View file

@ -0,0 +1,159 @@
/**
******************************************************************************
* @file syscalls.c
* @author Auto-generated by STM32CubeIDE
* @brief STM32CubeIDE Minimal System calls file
*
* For more information about which c-functions
* need which of these lowlevel functions
* please consult the Newlib libc-manual
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>
/* Variables */
//#undef errno
extern int errno;
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));
register char * stack_ptr asm("sp");
char *__env[1] = { 0 };
char **environ = __env;
/* Functions */
void initialise_monitor_handles()
{
}
int _getpid(void)
{
return 1;
}
int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}
void _exit (int status)
{
_kill(status, -1);
while (1) {} /* Make sure we hang here */
}
__attribute__((weak)) int _read(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}
return len;
}
__attribute__((weak)) int _write(int file, char *ptr, int len)
{
int DataIdx;
for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}
int _close(int file)
{
return -1;
}
int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _isatty(int file)
{
return 1;
}
int _lseek(int file, int ptr, int dir)
{
return 0;
}
int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}
int _wait(int *status)
{
errno = ECHILD;
return -1;
}
int _unlink(char *name)
{
errno = ENOENT;
return -1;
}
int _times(struct tms *buf)
{
return -1;
}
int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}
int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}
int _fork(void)
{
errno = EAGAIN;
return -1;
}
int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}

80
Relays/Core/Src/sysmem.c Normal file
View file

@ -0,0 +1,80 @@
/**
******************************************************************************
* @file sysmem.c
* @author Generated by STM32CubeIDE
* @brief STM32CubeIDE System Memory calls file
*
* For more information about which C functions
* need which of these lowlevel functions
* please consult the newlib libc manual
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* Includes */
#include <errno.h>
#include <stdint.h>
/**
* Pointer to the current high watermark of the heap usage
*/
static uint8_t *__sbrk_heap_end = NULL;
/**
* @brief _sbrk() allocates memory to the newlib heap and is used by malloc
* and others from the C library
*
* @verbatim
* ############################################################################
* # .data # .bss # newlib heap # MSP stack #
* # # # # Reserved by _Min_Stack_Size #
* ############################################################################
* ^-- RAM start ^-- _end _estack, RAM end --^
* @endverbatim
*
* This implementation starts allocating at the '_end' linker symbol
* The '_Min_Stack_Size' linker symbol reserves a memory for the MSP stack
* The implementation considers '_estack' linker symbol to be RAM end
* NOTE: If the MSP stack, at any point during execution, grows larger than the
* reserved size, please increase the '_Min_Stack_Size'.
*
* @param incr Memory size
* @return Pointer to allocated memory
*/
void *_sbrk(ptrdiff_t incr)
{
extern uint8_t _end; /* Symbol defined in the linker script */
extern uint8_t _estack; /* Symbol defined in the linker script */
extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
const uint8_t *max_heap = (uint8_t *)stack_limit;
uint8_t *prev_heap_end;
/* Initialize heap end at first call */
if (NULL == __sbrk_heap_end)
{
__sbrk_heap_end = &_end;
}
/* Protect heap from growing into the reserved MSP stack */
if (__sbrk_heap_end + incr > max_heap)
{
errno = ENOMEM;
return (void *)-1;
}
prev_heap_end = __sbrk_heap_end;
__sbrk_heap_end += incr;
return (void *)prev_heap_end;
}

View file

@ -0,0 +1,247 @@
/**
******************************************************************************
* @file system_stm32f0xx.c
* @author MCD Application Team
* @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
*
* 1. This file provides two functions and one global variable to be called from
* user application:
* - SystemInit(): This function is called at startup just after reset and
* before branch to main program. This call is made inside
* the "startup_stm32f0xx.s" file.
*
* - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
* by the user application to setup the SysTick
* timer or configure other parameters.
*
* - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
* be called whenever the core clock is changed
* during program execution.
*
*
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup stm32f0xx_system
* @{
*/
/** @addtogroup STM32F0xx_System_Private_Includes
* @{
*/
#include "stm32f0xx.h"
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_TypesDefinitions
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Defines
* @{
*/
#if !defined (HSE_VALUE)
#define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSE_VALUE */
#if !defined (HSI_VALUE)
#define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSI_VALUE */
#if !defined (HSI48_VALUE)
#define HSI48_VALUE ((uint32_t)48000000) /*!< Default value of the HSI48 Internal oscillator in Hz.
This value can be provided and adapted by the user application. */
#endif /* HSI48_VALUE */
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Macros
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Variables
* @{
*/
/* This variable is updated in three ways:
1) by calling CMSIS function SystemCoreClockUpdate()
2) by calling HAL API function HAL_RCC_GetHCLKFreq()
3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
Note: If you use this function to configure the system clock; then there
is no need to call the 2 first functions listed above, since SystemCoreClock
variable is updated automatically.
*/
uint32_t SystemCoreClock = 8000000;
const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_FunctionPrototypes
* @{
*/
/**
* @}
*/
/** @addtogroup STM32F0xx_System_Private_Functions
* @{
*/
/**
* @brief Setup the microcontroller system
* @param None
* @retval None
*/
void SystemInit(void)
{
/* NOTE :SystemInit(): This function is called at startup just after reset and
before branch to main program. This call is made inside
the "startup_stm32f0xx.s" file.
User can setups the default system clock (System clock source, PLL Multiplier
and Divider factors, AHB/APBx prescalers and Flash settings).
*/
}
/**
* @brief Update SystemCoreClock variable according to Clock Register Values.
* The SystemCoreClock variable contains the core clock (HCLK), it can
* be used by the user application to setup the SysTick timer or configure
* other parameters.
*
* @note Each time the core clock (HCLK) changes, this function must be called
* to update SystemCoreClock variable value. Otherwise, any configuration
* based on this variable will be incorrect.
*
* @note - The system frequency computed by this function is not the real
* frequency in the chip. It is calculated based on the predefined
* constant and the selected clock source:
*
* - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
*
* - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
*
* - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
* or HSI_VALUE(*) multiplied/divided by the PLL factors.
*
* (*) HSI_VALUE is a constant defined in stm32f0xx_hal_conf.h file (default value
* 8 MHz) but the real value may vary depending on the variations
* in voltage and temperature.
*
* (**) HSE_VALUE is a constant defined in stm32f0xx_hal_conf.h file (its value
* depends on the application requirements), user has to ensure that HSE_VALUE
* is same as the real frequency of the crystal used. Otherwise, this function
* may have wrong result.
*
* - The result of this function could be not correct when using fractional
* value for HSE crystal.
*
* @param None
* @retval None
*/
void SystemCoreClockUpdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
/* Get SYSCLK source -------------------------------------------------------*/
tmp = RCC->CFGR & RCC_CFGR_SWS;
switch (tmp)
{
case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
SystemCoreClock = HSE_VALUE;
break;
case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
/* Get PLL clock source and multiplication factor ----------------------*/
pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
pllmull = ( pllmull >> 18) + 2;
predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
{
/* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
}
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV)
{
/* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
}
#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || STM32F091xC || STM32F098xx */
else
{
#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
|| defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
|| defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
/* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
SystemCoreClock = (HSI_VALUE/predivfactor) * pllmull;
#else
/* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 ||
STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB ||
STM32F091xC || STM32F098xx || STM32F030xC */
}
break;
default: /* HSI used as system clock */
SystemCoreClock = HSI_VALUE;
break;
}
/* Compute HCLK clock frequency ----------------*/
/* Get HCLK prescaler */
tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
/* HCLK clock frequency */
SystemCoreClock >>= tmp;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/