Added modbus lib and test
This commit is contained in:
164
software/lib/modbus.c
Normal file
164
software/lib/modbus.c
Normal file
@@ -0,0 +1,164 @@
|
||||
#include "modbus.h"
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/util.h>
|
||||
#include <zephyr/modbus/modbus.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
// LOG_MODULE_REGISTER(mbc, CONFIG_LOG_DEFAULT_LEVEL);
|
||||
LOG_MODULE_REGISTER(mbc, 4); // Set log level to 4 (Debug)
|
||||
|
||||
#define MODBUS_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_modbus_serial)
|
||||
|
||||
static int client_iface;
|
||||
|
||||
static struct
|
||||
{
|
||||
int level; // Water level value
|
||||
int minimum; // Minimum value
|
||||
int maximum; // Maximum value
|
||||
int factor; // Factor for unit conversion
|
||||
} measurement;
|
||||
|
||||
int mb_init_client(void)
|
||||
{
|
||||
const char iface_name[] = {DEVICE_DT_NAME(MODBUS_NODE)};
|
||||
client_iface = modbus_iface_get_by_name(iface_name);
|
||||
LOG_DBG("Modbus client interface: %d", client_iface);
|
||||
if (client_iface < 0)
|
||||
{
|
||||
LOG_ERR("Failed to get Modbus interface by name: %s", iface_name);
|
||||
return client_iface;
|
||||
}
|
||||
return modbus_init_client(client_iface, client_param);
|
||||
}
|
||||
|
||||
int mb_read_holding_registers(int node, uint16_t reg_addr, uint16_t *data, size_t len)
|
||||
{
|
||||
return modbus_read_holding_regs(client_iface, node, reg_addr, data, len);
|
||||
}
|
||||
|
||||
int mb_read()
|
||||
{
|
||||
int rc;
|
||||
int16_t data[5] = {0};
|
||||
rc = mb_read_holding_registers(1, 0x0002, data, sizeof(data) / sizeof(data[0]));
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read holding registers: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
LOG_HEXDUMP_DBG(data, sizeof(data), "Holding Registers Data");
|
||||
|
||||
int unit, decimals;
|
||||
unit = data[0];
|
||||
decimals = data[1];
|
||||
int factor;
|
||||
switch (unit)
|
||||
{
|
||||
case 1: // cm
|
||||
factor = 10;
|
||||
break;
|
||||
case 2: // mm
|
||||
factor = 1;
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unknown unit: %d", unit);
|
||||
return -EINVAL;
|
||||
}
|
||||
switch(decimals)
|
||||
{
|
||||
case 0: // no decimals
|
||||
factor /= 1;
|
||||
break;
|
||||
case 1: // one decimal
|
||||
factor /= 10;
|
||||
break;
|
||||
case 2: // two decimals
|
||||
factor /= 100;
|
||||
break;
|
||||
default:
|
||||
LOG_ERR("Unknown decimals: %d", decimals);
|
||||
return -EINVAL;
|
||||
}
|
||||
measurement.factor = factor;
|
||||
measurement.level = data[2] * factor;
|
||||
measurement.minimum = data[3] * factor;
|
||||
measurement.maximum = data[4] * factor;
|
||||
LOG_DBG("Water level: %dmm, Minimum: %dmm, Maximum: %dmm",
|
||||
measurement.level, measurement.minimum, measurement.maximum);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_read_water_level(double *mb_read_water_level)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
*mb_read_water_level = (double)measurement.level / 1000.0; // Convert to meters
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_read_water_level_mm(int *mb_read_water_level)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
*mb_read_water_level = measurement.level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_read_minimum_mm(int *mb_read_minimum)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
*mb_read_minimum = measurement.minimum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_read_maximum_mm(int *mb_read_maximum)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
*mb_read_maximum = measurement.maximum;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_write_minimum_mm(int minimum)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
modbus_write_holding_reg(client_iface, 1, 0x0005, minimum / measurement.factor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mb_write_maximum_mm(int maximum)
|
||||
{
|
||||
int rc = mb_read();
|
||||
if (rc < 0)
|
||||
{
|
||||
LOG_ERR("Failed to read water level: %d", rc);
|
||||
return rc;
|
||||
}
|
||||
modbus_write_holding_reg(client_iface, 1, 0x0006, maximum / measurement.factor);
|
||||
return 0;
|
||||
}
|
||||
24
software/lib/modbus.h
Normal file
24
software/lib/modbus.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef __waterlevel_h
|
||||
#define __waterlevel_h
|
||||
|
||||
#include <zephyr/modbus/modbus.h>
|
||||
|
||||
const static struct modbus_iface_param client_param = {
|
||||
.mode = MODBUS_MODE_RTU,
|
||||
.rx_timeout = 50000,
|
||||
.serial = {
|
||||
.baud = 9600,
|
||||
.parity = UART_CFG_PARITY_NONE,
|
||||
},
|
||||
};
|
||||
|
||||
int mb_init_client(void);
|
||||
int mb_read_holding_registers(int node, uint16_t reg_addr, uint16_t *data, size_t len);
|
||||
int mb_read_water_level(double *mb_read_water_level);
|
||||
int mb_read_water_level_mm(int *mb_read_water_level_mm);
|
||||
int mb_read_minimum_mm(int *mb_read_minimum);
|
||||
int mb_read_maximum_mm(int *mb_read_maximum);
|
||||
int mb_write_minimum_mm(int minimum);
|
||||
int mb_write_maximum_mm(int maximum);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user