mirror of
https://github.com/mysensors/MySensors.git
synced 2026-02-19 17:11:28 +01:00
226 lines
5.7 KiB
C++
226 lines
5.7 KiB
C++
/*
|
|
* The MySensors Arduino library handles the wireless radio link and protocol
|
|
* between your home built sensors/actuators and HA controller of choice.
|
|
* The sensors forms a self healing radio network with optional repeaters. Each
|
|
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
|
* network topology allowing messages to be routed to nodes.
|
|
*
|
|
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
|
|
* Copyright (C) 2013-2026 Sensnology AB
|
|
* Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
|
|
*
|
|
* Documentation: http://www.mysensors.org
|
|
* Support Forum: http://forum.mysensors.org
|
|
*
|
|
* Multi message feature added by Constantin Petra <constantin.petra@gmail.com>
|
|
* Copyright (C) 2022 Constantin Petra
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* version 2 as published by the Free Software Foundation.
|
|
*/
|
|
|
|
#include "MyVersion.h"
|
|
#include "MyConfig.h"
|
|
#include "MyEepromAddresses.h"
|
|
#include "MyMessage.h"
|
|
#include "MyMultiMessage.h"
|
|
#include "stddef.h"
|
|
|
|
#define SET_PAYLOAD_TYPE(u, type) BF_SET(u, type, V2_MYS_HEADER_CEP_PAYLOADTYPE_POS, \
|
|
V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE)
|
|
#define GET_PAYLOAD_TYPE(u) BF_GET(u, V2_MYS_HEADER_CEP_PAYLOADTYPE_POS, \
|
|
V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE)
|
|
#define SET_COMMAND(u, command) BF_SET(u, command, V2_MYS_HEADER_CEP_COMMAND_POS, \
|
|
V2_MYS_HEADER_CEP_COMMAND_SIZE)
|
|
#define GET_COMMAND(u) BF_GET(u, V2_MYS_HEADER_CEP_COMMAND_POS, \
|
|
V2_MYS_HEADER_CEP_COMMAND_SIZE)
|
|
#define SET_LENGTH(u, finalLength) BF_SET(u, finalLength, V2_MYS_HEADER_VSL_LENGTH_POS, \
|
|
V2_MYS_HEADER_VSL_LENGTH_SIZE)
|
|
#define GET_LENGTH(u) BF_GET(u, V2_MYS_HEADER_VSL_LENGTH_POS, \
|
|
V2_MYS_HEADER_VSL_LENGTH_SIZE)
|
|
#define SET_VERSION(u) BF_SET(u, V2_MYS_HEADER_PROTOCOL_VERSION, \
|
|
V2_MYS_HEADER_VSL_VERSION_POS, V2_MYS_HEADER_VSL_VERSION_SIZE);
|
|
|
|
#define MAX_BLOB_SIZE (MAX_PAYLOAD_SIZE)
|
|
|
|
// replicates part of the MyMesgage structure related to a single sensor data.
|
|
typedef struct {
|
|
uint8_t command_echo_payload;
|
|
uint8_t type;
|
|
uint8_t sensor;
|
|
union {
|
|
uint8_t bValue;
|
|
uint16_t uiValue;
|
|
int16_t iValue;
|
|
uint32_t ulValue;
|
|
int32_t lValue;
|
|
struct {
|
|
float fValue;
|
|
uint8_t fPrecision;
|
|
};
|
|
} __attribute__((packed));
|
|
} __attribute__((packed)) blob;
|
|
|
|
MyMultiMessage::~MyMultiMessage()
|
|
{
|
|
|
|
}
|
|
|
|
MyMultiMessage::MyMultiMessage(MyMessage *msg)
|
|
{
|
|
_msg = msg;
|
|
_offset = 0;
|
|
_msg->setPayloadType(P_CUSTOM);
|
|
}
|
|
|
|
void *MyMultiMessage::common(uint8_t messageType, uint8_t sensor, uint8_t ptype, uint8_t size,
|
|
uint8_t cmd)
|
|
{
|
|
blob *b;
|
|
if (_offset + size > MAX_BLOB_SIZE) {
|
|
return NULL;
|
|
}
|
|
b = (blob *)(_msg->data + _offset);
|
|
SET_PAYLOAD_TYPE(b->command_echo_payload, ptype);
|
|
SET_COMMAND(b->command_echo_payload, cmd);
|
|
b->type = messageType;
|
|
b->sensor = sensor;
|
|
_offset += size;
|
|
SET_LENGTH(_msg->version_length, _offset);
|
|
SET_VERSION(_msg->version_length);
|
|
return b;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint8_t value)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_BYTE, 4, C_SET);
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->bValue = value;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint16_t value)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_UINT16, 5, C_SET);
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->uiValue = value;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, int16_t value)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_INT16, 5, C_SET);
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->uiValue = value;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, uint32_t value)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_ULONG32, 7, C_SET);
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->ulValue = value;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, int32_t value)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_LONG32, 7, C_SET);
|
|
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->lValue = value;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::set(uint8_t messageType, uint8_t sensor, float value, uint8_t decimals)
|
|
{
|
|
blob *b = (blob *)common(messageType, sensor, P_FLOAT32, 8, C_SET);
|
|
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->fValue = value;
|
|
b->fPrecision = decimals;
|
|
return true;
|
|
}
|
|
|
|
bool MyMultiMessage::setBattery(uint8_t value)
|
|
{
|
|
blob *b = (blob *)common(I_BATTERY_LEVEL, NODE_SENSOR_ID, P_BYTE, 4, C_INTERNAL);
|
|
|
|
if (b == NULL) {
|
|
return false;
|
|
}
|
|
b->bValue = value;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool MyMultiMessage::getNext(MyMessage &m)
|
|
{
|
|
uint8_t size = GET_LENGTH(_msg->version_length);
|
|
uint8_t type;
|
|
|
|
blob *b;
|
|
if (_offset >= size) {
|
|
return false;
|
|
}
|
|
|
|
m.last = _msg->last;
|
|
m.sender = _msg->sender;
|
|
m.destination = _msg->destination;
|
|
m.version_length = _msg->version_length;
|
|
|
|
b = (blob *)(_msg->data + _offset);
|
|
m.type = b->type;
|
|
m.sensor = b->sensor;
|
|
|
|
type = GET_PAYLOAD_TYPE(b->command_echo_payload);
|
|
m.command_echo_payload = b->command_echo_payload;
|
|
|
|
if (type == P_BYTE) {
|
|
m.bValue = b->bValue;
|
|
_offset += 4;
|
|
return true;
|
|
} else if (type == P_UINT16) {
|
|
m.uiValue = b->uiValue;
|
|
_offset += 5;
|
|
return true;
|
|
} else if (type == P_INT16) {
|
|
m.iValue = b->iValue;
|
|
_offset += 5;
|
|
return true;
|
|
} else if (type == P_ULONG32) {
|
|
m.ulValue = b->ulValue;
|
|
_offset += 7;
|
|
return true;
|
|
} else if (type == P_LONG32) {
|
|
m.lValue = b->lValue;
|
|
_offset += 7;
|
|
return true;
|
|
} else if (type == P_FLOAT32) {
|
|
m.fValue = b->fValue;
|
|
m.fPrecision = b->fPrecision;
|
|
_offset += 8;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void MyMultiMessage::reset()
|
|
{
|
|
_offset = 0;
|
|
SET_LENGTH(_msg->version_length, _offset);
|
|
}
|