Commit 76433dcd authored by Eric Duminil's avatar Eric Duminil
Browse files

Adding S8_UART library

parent 25b41d2e
......@@ -9,6 +9,7 @@
// The SCD30 from Sensirion is a high quality Nondispersive Infrared (NDIR) based CO₂ sensor capable of detecting 400 to 10000ppm with an accuracy of ±(30ppm+3%).
// https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library
#include "src/lib/SparkFun_SCD30_Arduino_Library/src/SparkFun_SCD30_Arduino_Library.h" // From: http://librarymanager/All#SparkFun_SCD30
#include "src/lib/S8_UART/s8_uart.h"
namespace config {
const uint16_t measurement_timestep_bootup = 5; // [s] Measurement timestep during acclimatization.
......
MIT License
Copyright (c) 2021 Josep Comas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
# S8_UART
S8 Library for serial communication (UART)
This library is for **Senseair S8 CO2** sensor to use with Arduino framework using serial communication (UART).
**Senseair S8 LP (004-0-0053)** is recommended for CO2 measurement in indoors for air quality application.
## Installation
### PlatformIO
Download S8_UART library and copy extracted folder into **PlatformIO\Projects** folder. Open **Visual Studio Code** and select the directory of the project. Modify **platformio.ini** file according your board and requirements. Open .cpp file of example and modify the parameters of **configuration section**. Build and upload the example selected of platformio.ini file.
### Arduino IDE
Go to **Documents\Arduino\libraries** and create the **S8_UART** directory. Download S8_UART library and copy the files of **src** folder into the new created folder.
To test the examples, copy the folder of the example into **Documents\Arduino\Projects** folder, rename the **.cpp** file of the example to **.ino**. Open the .ino file and modify the parameters of **configuration section**. In the menu of IDE select your board and compile and upload the program.
## Debug
Modify **CORE_DEBUG_LEVEL** variable to **1** in platformio.ini file to show only errors (in console) and to **5** value for full messages.
\ No newline at end of file
#include <stdint.h>
/* ModBus CRC routine extracted from https://modbus.org/docs/Modbus_over_serial_line_V1_02.pdf */
/* Table of CRC values for high–order byte */
static const uint8_t auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40
} ;
/* Table of CRC values for low–order byte */
static const uint8_t auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD,
0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36, 0xF6, 0xF7,
0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE,
0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2,
0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90, 0x91,
0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88,
0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80,
0x40
};
/* The function returns the CRC as a unsigned short type */
uint16_t modbus_CRC16 (uint8_t *puchMsg, uint16_t usDataLen ) {
/*
puchMsg -> message to calculate CRC upon
usDataLen -> quantity of bytes in message
*/
uint8_t uchCRCHi = 0xFF ; /* high byte of CRC initialized */
uint8_t uchCRCLo = 0xFF ; /* low byte of CRC initialized */
uint16_t uIndex ; /* will index into CRC lookup table */
while (usDataLen--) /* pass through message buffer */
{
uIndex = uchCRCLo ^ *puchMsg++ ; /* calculate the CRC */
uchCRCLo = uchCRCHi ^ auchCRCHi[uIndex] ;
uchCRCHi = auchCRCLo[uIndex] ;
}
return (uchCRCHi << 8 | uchCRCLo) ;
}
#ifndef _MODBUS_H
#define _MODBUS_H
/* The function returns the CRC as a unsigned short type
puchMsg -> message to calculate CRC upon
usDataLen -> quantity of bytes in message */
uint16_t modbus_CRC16 (uint8_t *puchMsg, uint16_t usDataLen );
#endif
/***************************************************************************************************************************
SenseAir S8 Library for Serial Modbus Communication
Copyright (c) 2021 Josep Comas
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***************************************************************************************************************************/
#include "s8_uart.h"
#include "modbus_crc.h"
#include "utils.h"
/* Initialize */
S8_UART::S8_UART(Stream &serial)
{
mySerial = &serial;
}
/* Get firmware version */
void S8_UART::get_firmware_version(char firmver[]) {
if (firmver == NULL) {
return;
}
strcpy(firmver, "");
// Ask software version
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR29, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
snprintf(firmver, S8_LEN_FIRMVER, "%0u.%0u", buf_msg[3], buf_msg[4]);
LOG_DEBUG_INFO("Firmware version: ", firmver);
} else {
LOG_DEBUG_ERROR("Firmware version not available!");
}
}
/* Get CO2 value in ppm */
int16_t S8_UART::get_co2() {
int16_t co2 = 0;
// Ask CO2 value
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR4, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
co2 = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO("CO2 value = ", co2, " ppm");
} else {
LOG_DEBUG_ERROR("Error getting CO2 value!");
}
return co2;
}
/* Read ABC period */
int16_t S8_UART::get_ABC_period() {
int16_t period = 0;
// Ask ABC period
send_cmd(MODBUS_FUNC_READ_HOLDING_REGISTERS, MODBUS_HR32, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_HOLDING_REGISTERS, nb, 7)) {
period = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO("ABC period = ", period, " hours");
} else {
LOG_DEBUG_ERROR("Error getting ABC period!");
}
return period;
}
/* Setup ABC period, default 180 hours (7.5 days) */
bool S8_UART::set_ABC_period(int16_t period) {
uint8_t buf_msg_sent[8];
bool result = false;
if (period >= 0 && period <= 4800) { // 0 = disable ABC algorithm
// Ask set ABC period
send_cmd(MODBUS_FUNC_WRITE_SINGLE_REGISTER, MODBUS_HR32, period);
// Save bytes sent
memcpy(buf_msg_sent, buf_msg, 8);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
serial_read_bytes(8, S8_TIMEOUT);
// Check response
if (memcmp(buf_msg_sent, buf_msg, 8) == 0) {
result = true;
LOG_DEBUG_INFO("Successful setting of ABC period");
} else {
LOG_DEBUG_ERROR("Error in setting of ABC period!");
}
} else {
LOG_DEBUG_ERROR("Invalid ABC period!");
}
return result;
}
/* Read acknowledgement flags */
int16_t S8_UART::get_acknowledgement() {
int16_t flags = 0;
// Ask acknowledgement flags
send_cmd(MODBUS_FUNC_READ_HOLDING_REGISTERS, MODBUS_HR1, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_HOLDING_REGISTERS, nb, 7)) {
flags = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO_BINARY("Acknowledgement flags = b", flags);
} else {
LOG_DEBUG_ERROR("Error getting acknowledgement flags!");
}
return flags;
}
/* Read acknowledgement flags */
bool S8_UART::clear_acknowledgement() {
uint8_t buf_msg_sent[8];
bool result = false;
// Ask clear acknowledgement flags
send_cmd(MODBUS_FUNC_WRITE_SINGLE_REGISTER, MODBUS_HR1, 0x0000);
// Save bytes sent
memcpy(buf_msg_sent, buf_msg, 8);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
serial_read_bytes(8, S8_TIMEOUT);
// Check response
if (memcmp(buf_msg_sent, buf_msg, 8) == 0) {
result = true;
LOG_DEBUG_INFO("Successful clearing acknowledgement flags");
} else {
LOG_DEBUG_ERROR("Error clearing acknowledgement flags!");
}
return result;
}
/* Start a manual calibration (go to outdoors, wait 5 minutes o more and then you issue this command) */
bool S8_UART::manual_calibration() {
bool result = clear_acknowledgement();
if (result) {
result = send_special_command(S8_CO2_BACKGROUND_CALIBRATION);
if (result) {
LOG_DEBUG_INFO("Manual calibration in background has started");
} else {
LOG_DEBUG_ERROR("Error starting manual calibration!");
}
}
return result;
}
/* Send special command (high = command, low = parameter) */
/*
Command = 0x7C,
Parameter = 0x06 CO2 background calibration
Parameter = 0x07 CO2 zero calibration
*/
bool S8_UART::send_special_command(int16_t command) {
uint8_t buf_msg_sent[8];
bool result = false;
// Ask set user special command
send_cmd(MODBUS_FUNC_WRITE_SINGLE_REGISTER, MODBUS_HR2, command);
// Save bytes sent
memcpy(buf_msg_sent, buf_msg, 8);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
serial_read_bytes(8, S8_TIMEOUT);
// Check response
if (memcmp(buf_msg_sent, buf_msg, 8) == 0) {
result = true;
LOG_DEBUG_INFO("Successful setting user special command");
} else {
LOG_DEBUG_ERROR("Error in setting user special command!");
}
return result;
}
/* Read meter status */
int16_t S8_UART::get_meter_status() {
int16_t status = 0;
// Ask meter status
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR1, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
status = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO_BINARY("Meter status = b", status);
} else {
LOG_DEBUG_ERROR("Error getting meter status!");
}
return status;
}
/* Read alarm status */
int16_t S8_UART::get_alarm_status() {
int16_t status = 0;
// Ask alarm status
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR2, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
status = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO_BINARY("Alarm status = b", status);
} else {
LOG_DEBUG_ERROR("Error getting alarm status!");
}
return status;
}
/* Read output status */
int16_t S8_UART::get_output_status() {
int16_t status = 0;
// Ask output status
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR3, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
status = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO_BINARY("Output status = b", status);
} else {
LOG_DEBUG_ERROR("Error getting output status!");
}
return status;
}
/* Read PWM output (0x3FFF = 100%)
Raw PWM output to ppm: (raw_PWM_output / 16383.0) * 2000.0)
2000.0 is max range of sensor (2000 ppm for normal version, extended version is 10000 ppm)
*/
int16_t S8_UART::get_PWM_output() {
int16_t pwm = 0;
// Ask PWM output
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR22, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
pwm = ((buf_msg[3] << 8) & 0xFF00) | (buf_msg[4] & 0x00FF);
LOG_DEBUG_INFO("PWM output (raw) = ", pwm);
LOG_DEBUG_INFO("PWM output (to ppm, normal version) = ", (pwm / 16383.0) * 2000.0, " ppm");
//LOG_DEBUG_INFO("PWM output (to ppm, extended version) = ", (pwm / 16383.0) * 10000.0, " ppm");
} else {
LOG_DEBUG_ERROR("Error getting PWM output!");
}
return pwm;
}
/* Read sensor type ID */
int32_t S8_UART::get_sensor_type_ID() {
int32_t sensorType = 0;
// Ask sensor type ID (high)
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR26, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
// Save sensor type ID (high)
sensorType = (((int32_t)buf_msg[4] << 16) & 0x00FF0000);
// Ask sensor type ID (low)
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR27, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
sensorType |= ((buf_msg[3] << 8) & 0x0000FF00) | (buf_msg[4] & 0x000000FF);
LOG_DEBUG_INFO_HEX("Sensor type ID = 0x", sensorType, 3);
} else {
LOG_DEBUG_ERROR("Error getting sensor type ID (low)!");
}
} else {
LOG_DEBUG_ERROR("Error getting sensor type ID (high)!");
}
return sensorType;
}
/* Read sensor ID */
int32_t S8_UART::get_sensor_ID() {
int32_t sensorID = 0;
// Ask sensor ID (high)
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR30, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
uint8_t nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
// Save sensor ID (high)
sensorID = (((int32_t)buf_msg[3] << 24) & 0xFF000000) | (((int32_t)buf_msg[4] << 16) & 0x00FF0000);
// Ask sensor ID (low)
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR31, 0x0001);
// Wait response
memset(buf_msg, 0, S8_LEN_BUF_MSG);
nb = serial_read_bytes(7, S8_TIMEOUT);
// Check response and get data
if (valid_response_len(MODBUS_FUNC_READ_INPUT_REGISTERS, nb, 7)) {
sensorID |= ((buf_msg[3] << 8) & 0x0000FF00) | (buf_msg[4] & 0x000000FF);
LOG_DEBUG_INFO_HEX("Sensor ID = 0x", sensorID, 4);
} else {
LOG_DEBUG_ERROR("Error getting sensor ID (low)!");
}
} else {
LOG_DEBUG_ERROR("Error getting sensor ID (high)!");
}
return sensorID;
}
/* Read memory map version */
int16_t S8_UART::get_memory_map_version() {
int16_t mmVersion = 0;
// Ask memory map version
send_cmd(MODBUS_FUNC_READ_INPUT_REGISTERS, MODBUS_IR28, 0x0001);
// Wait response