877 lines
23 KiB
C
877 lines
23 KiB
C
#include "modbus_memory.h"
|
|
#include "modbus_points.h"
|
|
|
|
#include <string.h>
|
|
|
|
static modbus_point_type_t mem_to_point_type(modbus_mem_type_t type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case MB_MEM_COIL:
|
|
return MB_POINT_COIL;
|
|
|
|
case MB_MEM_DISCRETE_INPUT:
|
|
return MB_POINT_DISCRETE_INPUT;
|
|
|
|
case MB_MEM_INPUT_REGISTER:
|
|
return MB_POINT_INPUT_REGISTER;
|
|
|
|
case MB_MEM_HOLDING_REGISTER:
|
|
return MB_POINT_HOLDING_REGISTER;
|
|
|
|
default:
|
|
return MB_POINT_INVALID;
|
|
}
|
|
}
|
|
|
|
static modbus_point_t *find_point_rw(modbus_memory_t *mem,
|
|
modbus_mem_type_t mem_type,
|
|
uint16_t offset)
|
|
{
|
|
size_t i;
|
|
modbus_point_type_t point_type;
|
|
|
|
if (mem == NULL || mem->db == NULL)
|
|
return NULL;
|
|
|
|
point_type = mem_to_point_type(mem_type);
|
|
if (point_type == MB_POINT_INVALID)
|
|
return NULL;
|
|
|
|
for (i = 0; i < mem->db->count; i++)
|
|
{
|
|
if (mem->db->points[i].type == point_type &&
|
|
mem->db->points[i].offset == offset)
|
|
{
|
|
return &mem->db->points[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const modbus_point_t *find_point_ro(modbus_memory_t *mem,
|
|
modbus_mem_type_t mem_type,
|
|
uint16_t offset)
|
|
{
|
|
size_t i;
|
|
modbus_point_type_t point_type;
|
|
|
|
if (mem == NULL || mem->db == NULL)
|
|
return NULL;
|
|
|
|
point_type = mem_to_point_type(mem_type);
|
|
if (point_type == MB_POINT_INVALID)
|
|
return NULL;
|
|
|
|
for (i = 0; i < mem->db->count; i++)
|
|
{
|
|
if (mem->db->points[i].type == point_type &&
|
|
mem->db->points[i].offset == offset)
|
|
{
|
|
return &mem->db->points[i];
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static modbus_point_t *find_pics_point_rw(modbus_memory_t *mem,
|
|
modbus_mem_type_t mem_type,
|
|
uint16_t offset)
|
|
{
|
|
modbus_point_type_t point_type;
|
|
const modbus_point_t *pt;
|
|
|
|
if (mem == NULL || mem->db == NULL)
|
|
return NULL;
|
|
|
|
point_type = mem_to_point_type(mem_type);
|
|
if (point_type == MB_POINT_INVALID)
|
|
return NULL;
|
|
|
|
pt = modbus_points_find_by_pics_range(mem->db, point_type, offset);
|
|
return (modbus_point_t *)pt;
|
|
}
|
|
|
|
static bool write_point_words(modbus_memory_t *mem,
|
|
modbus_point_t *pt,
|
|
const uint16_t *words,
|
|
uint8_t span)
|
|
{
|
|
uint8_t i;
|
|
modbus_mem_type_t mem_type;
|
|
|
|
if (mem == NULL || pt == NULL || words == NULL)
|
|
return false;
|
|
|
|
if (modbus_points_is_bit_type(pt->type))
|
|
{
|
|
pt->bit_value = (words[0] != 0U) ? 1U : 0U;
|
|
return true;
|
|
}
|
|
|
|
mem_type = modbus_points_type_to_mem(pt->type);
|
|
|
|
for (i = 0; i < span; i++)
|
|
{
|
|
modbus_point_t *word_pt;
|
|
|
|
word_pt = find_point_rw(mem, mem_type, (uint16_t)(pt->offset + i));
|
|
if (word_pt == NULL)
|
|
return false;
|
|
|
|
word_pt->reg_value = words[i];
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static void sync_points_controlled_by(modbus_memory_t *mem,
|
|
const modbus_point_t *control_pt)
|
|
{
|
|
size_t i;
|
|
uint8_t j;
|
|
modbus_mem_type_t control_mem_type;
|
|
modbus_mem_type_t target_mem_type;
|
|
|
|
if (mem == NULL || mem->db == NULL || control_pt == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < mem->db->count; i++)
|
|
{
|
|
modbus_point_t *target_pt = &mem->db->points[i];
|
|
|
|
if (!target_pt->has_control_address)
|
|
continue;
|
|
|
|
if (target_pt->control_type != control_pt->type)
|
|
continue;
|
|
|
|
if (target_pt->control_offset != control_pt->offset)
|
|
continue;
|
|
|
|
if (modbus_points_is_bit_type(target_pt->type))
|
|
{
|
|
target_pt->bit_value = control_pt->bit_value;
|
|
continue;
|
|
}
|
|
|
|
control_mem_type = modbus_points_type_to_mem(control_pt->type);
|
|
target_mem_type = modbus_points_type_to_mem(target_pt->type);
|
|
|
|
for (j = 0; j < target_pt->reg_span; j++)
|
|
{
|
|
const modbus_point_t *src_pt;
|
|
modbus_point_t *dst_pt;
|
|
|
|
src_pt = find_point_ro(mem, control_mem_type,
|
|
(uint16_t)(control_pt->offset + j));
|
|
dst_pt = find_point_rw(mem, target_mem_type,
|
|
(uint16_t)(target_pt->offset + j));
|
|
|
|
if (src_pt == NULL || dst_pt == NULL)
|
|
break;
|
|
|
|
dst_pt->reg_value = src_pt->reg_value;
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool apply_pics_to_official_point(modbus_memory_t *mem, modbus_point_t *pt)
|
|
{
|
|
uint16_t out_words[4] = {0U, 0U, 0U, 0U};
|
|
|
|
if (mem == NULL || pt == NULL || !pt->has_pics_address)
|
|
return false;
|
|
|
|
switch (pt->pics_data_type)
|
|
{
|
|
case PICS_DATA_BOOLEAN:
|
|
{
|
|
uint16_t v = (pt->pics_words[0] != 0U) ? 1U : 0U;
|
|
|
|
if (modbus_points_is_bit_type(pt->type))
|
|
{
|
|
pt->bit_value = (v != 0U) ? 1U : 0U;
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
out_words[0] = v;
|
|
if (!write_point_words(mem, pt, out_words, 1U))
|
|
return false;
|
|
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
case PICS_DATA_INTEGER:
|
|
{
|
|
uint32_t raw_u32;
|
|
int32_t pics_i32;
|
|
|
|
raw_u32 = ((uint32_t)pt->pics_words[1] << 16) |
|
|
(uint32_t)pt->pics_words[0];
|
|
pics_i32 = (int32_t)raw_u32;
|
|
|
|
switch (pt->data_type)
|
|
{
|
|
case MB_DATA_UINT16:
|
|
{
|
|
uint32_t v = (pics_i32 < 0) ? 0U : (uint32_t)pics_i32;
|
|
if (v > 65535U)
|
|
v = 65535U;
|
|
|
|
out_words[0] = (uint16_t)v;
|
|
if (!write_point_words(mem, pt, out_words, 1U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_UINT32:
|
|
{
|
|
uint32_t v = (pics_i32 < 0) ? 0U : (uint32_t)pics_i32;
|
|
|
|
out_words[0] = (uint16_t)((v >> 16) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)(v & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 2U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_FLOAT:
|
|
{
|
|
float f = (float)pics_i32;
|
|
uint32_t raw_f32;
|
|
|
|
memcpy(&raw_f32, &f, sizeof(raw_f32));
|
|
|
|
out_words[0] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)(raw_f32 & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 2U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_DOUBLE:
|
|
{
|
|
double d = (double)pics_i32;
|
|
uint64_t raw_f64;
|
|
|
|
memcpy(&raw_f64, &d, sizeof(raw_f64));
|
|
|
|
out_words[0] = (uint16_t)((raw_f64 >> 48) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)((raw_f64 >> 32) & 0xFFFFU);
|
|
out_words[2] = (uint16_t)((raw_f64 >> 16) & 0xFFFFU);
|
|
out_words[3] = (uint16_t)(raw_f64 & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 4U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
case PICS_DATA_FLOAT:
|
|
{
|
|
uint64_t raw_f64;
|
|
double pics_d;
|
|
|
|
raw_f64 = ((uint64_t)pt->pics_words[0] << 48) |
|
|
((uint64_t)pt->pics_words[1] << 32) |
|
|
((uint64_t)pt->pics_words[2] << 16) |
|
|
(uint64_t)pt->pics_words[3];
|
|
|
|
memcpy(&pics_d, &raw_f64, sizeof(pics_d));
|
|
|
|
switch (pt->data_type)
|
|
{
|
|
case MB_DATA_UINT16:
|
|
{
|
|
double v = pics_d;
|
|
if (v < 0.0)
|
|
v = 0.0;
|
|
if (v > 65535.0)
|
|
v = 65535.0;
|
|
|
|
out_words[0] = (uint16_t)v;
|
|
if (!write_point_words(mem, pt, out_words, 1U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_UINT32:
|
|
{
|
|
double v = pics_d;
|
|
uint32_t u32;
|
|
|
|
if (v < 0.0)
|
|
v = 0.0;
|
|
if (v > 4294967295.0)
|
|
v = 4294967295.0;
|
|
|
|
u32 = (uint32_t)v;
|
|
|
|
out_words[0] = (uint16_t)((u32 >> 16) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)(u32 & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 2U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_FLOAT:
|
|
{
|
|
float f = (float)pics_d;
|
|
uint32_t raw_f32;
|
|
|
|
memcpy(&raw_f32, &f, sizeof(raw_f32));
|
|
|
|
out_words[0] = (uint16_t)((raw_f32 >> 16) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)(raw_f32 & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 2U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
case MB_DATA_DOUBLE:
|
|
{
|
|
uint64_t raw_out_f64;
|
|
|
|
memcpy(&raw_out_f64, &pics_d, sizeof(raw_out_f64));
|
|
|
|
out_words[0] = (uint16_t)((raw_out_f64 >> 48) & 0xFFFFU);
|
|
out_words[1] = (uint16_t)((raw_out_f64 >> 32) & 0xFFFFU);
|
|
out_words[2] = (uint16_t)((raw_out_f64 >> 16) & 0xFFFFU);
|
|
out_words[3] = (uint16_t)(raw_out_f64 & 0xFFFFU);
|
|
|
|
if (!write_point_words(mem, pt, out_words, 4U))
|
|
return false;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
static bool write_pics_staging_word(modbus_memory_t *mem,
|
|
modbus_mem_type_t mem_type,
|
|
uint16_t offset,
|
|
uint16_t value)
|
|
{
|
|
modbus_point_t *pt;
|
|
uint16_t word_index;
|
|
|
|
pt = find_pics_point_rw(mem, mem_type, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
if (!pt->has_pics_address || pt->pics_reg_span == 0U)
|
|
return false;
|
|
|
|
if (offset < pt->pics_offset)
|
|
return false;
|
|
|
|
word_index = (uint16_t)(offset - pt->pics_offset);
|
|
if (word_index >= pt->pics_reg_span || word_index >= 4U)
|
|
return false;
|
|
|
|
pt->pics_words[word_index] = value;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_init(modbus_memory_t *mem, modbus_db_t *db)
|
|
{
|
|
if (mem == NULL || db == NULL)
|
|
return false;
|
|
|
|
mem->db = db;
|
|
modbus_memory_reset(mem);
|
|
return true;
|
|
}
|
|
|
|
void modbus_memory_deinit(modbus_memory_t *mem)
|
|
{
|
|
if (mem == NULL)
|
|
return;
|
|
|
|
mem->db = NULL;
|
|
}
|
|
|
|
void modbus_memory_reset(modbus_memory_t *mem)
|
|
{
|
|
size_t i;
|
|
|
|
if (mem == NULL || mem->db == NULL)
|
|
return;
|
|
|
|
for (i = 0; i < mem->db->count; i++)
|
|
{
|
|
mem->db->points[i].bit_value = 0U;
|
|
mem->db->points[i].reg_value = 0U;
|
|
memset(mem->db->points[i].pics_words, 0, sizeof(mem->db->points[i].pics_words));
|
|
}
|
|
}
|
|
|
|
bool modbus_memory_read_coil(modbus_memory_t *mem, uint16_t offset, uint8_t *value)
|
|
{
|
|
const modbus_point_t *pt;
|
|
|
|
if (mem == NULL || value == NULL)
|
|
return false;
|
|
|
|
pt = find_point_ro(mem, MB_MEM_COIL, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
*value = (pt->bit_value != 0U) ? 1U : 0U;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_coil(modbus_memory_t *mem, uint16_t offset, uint8_t value)
|
|
{
|
|
modbus_point_t *pt;
|
|
|
|
if (mem == NULL)
|
|
return false;
|
|
|
|
pt = find_point_rw(mem, MB_MEM_COIL, offset);
|
|
if (pt != NULL)
|
|
{
|
|
pt->bit_value = (value != 0U) ? 1U : 0U;
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
pt = find_pics_point_rw(mem, MB_MEM_COIL, offset);
|
|
if (pt != NULL)
|
|
{
|
|
uint16_t staged = (value != 0U) ? 1U : 0U;
|
|
return write_pics_staging_word(mem, MB_MEM_COIL, offset, staged);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool modbus_memory_read_discrete_input(modbus_memory_t *mem, uint16_t offset, uint8_t *value)
|
|
{
|
|
const modbus_point_t *pt;
|
|
|
|
if (mem == NULL || value == NULL)
|
|
return false;
|
|
|
|
pt = find_point_ro(mem, MB_MEM_DISCRETE_INPUT, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
*value = (pt->bit_value != 0U) ? 1U : 0U;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_discrete_input(modbus_memory_t *mem, uint16_t offset, uint8_t value)
|
|
{
|
|
modbus_point_t *pt;
|
|
|
|
if (mem == NULL)
|
|
return false;
|
|
|
|
pt = find_point_rw(mem, MB_MEM_DISCRETE_INPUT, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
pt->bit_value = (value != 0U) ? 1U : 0U;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_input_register(modbus_memory_t *mem, uint16_t offset, uint16_t *value)
|
|
{
|
|
const modbus_point_t *pt;
|
|
|
|
if (mem == NULL || value == NULL)
|
|
return false;
|
|
|
|
pt = find_point_ro(mem, MB_MEM_INPUT_REGISTER, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
*value = pt->reg_value;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_input_register(modbus_memory_t *mem, uint16_t offset, uint16_t value)
|
|
{
|
|
modbus_point_t *pt;
|
|
|
|
if (mem == NULL)
|
|
return false;
|
|
|
|
pt = find_point_rw(mem, MB_MEM_INPUT_REGISTER, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
pt->reg_value = value;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_holding_register(modbus_memory_t *mem, uint16_t offset, uint16_t *value)
|
|
{
|
|
const modbus_point_t *pt;
|
|
|
|
if (mem == NULL || value == NULL)
|
|
return false;
|
|
|
|
pt = find_point_ro(mem, MB_MEM_HOLDING_REGISTER, offset);
|
|
if (pt == NULL)
|
|
return false;
|
|
|
|
*value = pt->reg_value;
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_holding_register(modbus_memory_t *mem, uint16_t offset, uint16_t value)
|
|
{
|
|
modbus_point_t *pt;
|
|
|
|
if (mem == NULL)
|
|
return false;
|
|
|
|
pt = find_point_rw(mem, MB_MEM_HOLDING_REGISTER, offset);
|
|
if (pt != NULL)
|
|
{
|
|
pt->reg_value = value;
|
|
sync_points_controlled_by(mem, pt);
|
|
return true;
|
|
}
|
|
|
|
if (write_pics_staging_word(mem, MB_MEM_HOLDING_REGISTER, offset, value))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool modbus_memory_read_bit(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t offset,
|
|
uint8_t *value)
|
|
{
|
|
switch (type)
|
|
{
|
|
case MB_MEM_COIL:
|
|
return modbus_memory_read_coil(mem, offset, value);
|
|
|
|
case MB_MEM_DISCRETE_INPUT:
|
|
return modbus_memory_read_discrete_input(mem, offset, value);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool modbus_memory_write_bit(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t offset,
|
|
uint8_t value)
|
|
{
|
|
switch (type)
|
|
{
|
|
case MB_MEM_COIL:
|
|
return modbus_memory_write_coil(mem, offset, value);
|
|
|
|
case MB_MEM_DISCRETE_INPUT:
|
|
return modbus_memory_write_discrete_input(mem, offset, value);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool modbus_memory_read_reg(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t offset,
|
|
uint16_t *value)
|
|
{
|
|
switch (type)
|
|
{
|
|
case MB_MEM_INPUT_REGISTER:
|
|
return modbus_memory_read_input_register(mem, offset, value);
|
|
|
|
case MB_MEM_HOLDING_REGISTER:
|
|
return modbus_memory_read_holding_register(mem, offset, value);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool modbus_memory_write_reg(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t offset,
|
|
uint16_t value)
|
|
{
|
|
switch (type)
|
|
{
|
|
case MB_MEM_INPUT_REGISTER:
|
|
return modbus_memory_write_input_register(mem, offset, value);
|
|
|
|
case MB_MEM_HOLDING_REGISTER:
|
|
return modbus_memory_write_holding_register(mem, offset, value);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool modbus_memory_valid_bit_range(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t start_offset,
|
|
uint16_t quantity)
|
|
{
|
|
uint32_t end_offset;
|
|
|
|
(void)type;
|
|
|
|
if (mem == NULL || mem->db == NULL || quantity == 0U)
|
|
return false;
|
|
|
|
end_offset = (uint32_t)start_offset + (uint32_t)quantity - 1U;
|
|
if (end_offset > 0xFFFFU)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_valid_reg_range(modbus_memory_t *mem,
|
|
modbus_mem_type_t type,
|
|
uint16_t start_offset,
|
|
uint16_t quantity)
|
|
{
|
|
uint32_t end_offset;
|
|
|
|
(void)type;
|
|
|
|
if (mem == NULL || mem->db == NULL || quantity == 0U)
|
|
return false;
|
|
|
|
end_offset = (uint32_t)start_offset + (uint32_t)quantity - 1U;
|
|
if (end_offset > 0xFFFFU)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_coils(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
uint8_t *dest)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (dest == NULL || !modbus_memory_valid_bit_range(mem, MB_MEM_COIL, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
uint8_t value = 0U;
|
|
|
|
if (!modbus_memory_read_coil(mem, (uint16_t)(start_offset + i), &value))
|
|
value = 0U;
|
|
|
|
dest[i] = value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_coils(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
const uint8_t *src)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (src == NULL || !modbus_memory_valid_bit_range(mem, MB_MEM_COIL, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
if (!modbus_memory_write_coil(mem, (uint16_t)(start_offset + i), src[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_discrete_inputs(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
uint8_t *dest)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (dest == NULL || !modbus_memory_valid_bit_range(mem, MB_MEM_DISCRETE_INPUT, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
uint8_t value = 0U;
|
|
|
|
if (!modbus_memory_read_discrete_input(mem, (uint16_t)(start_offset + i), &value))
|
|
value = 0U;
|
|
|
|
dest[i] = value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_discrete_inputs(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
const uint8_t *src)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (src == NULL || !modbus_memory_valid_bit_range(mem, MB_MEM_DISCRETE_INPUT, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
if (!modbus_memory_write_discrete_input(mem, (uint16_t)(start_offset + i), src[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_input_registers(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
uint16_t *dest)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (dest == NULL || !modbus_memory_valid_reg_range(mem, MB_MEM_INPUT_REGISTER, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
uint16_t value = 0U;
|
|
|
|
if (!modbus_memory_read_input_register(mem, (uint16_t)(start_offset + i), &value))
|
|
value = 0U;
|
|
|
|
dest[i] = value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_input_registers(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
const uint16_t *src)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (src == NULL || !modbus_memory_valid_reg_range(mem, MB_MEM_INPUT_REGISTER, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
if (!modbus_memory_write_input_register(mem, (uint16_t)(start_offset + i), src[i]))
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_read_holding_registers(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
uint16_t *dest)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (dest == NULL || !modbus_memory_valid_reg_range(mem, MB_MEM_HOLDING_REGISTER, start_offset, quantity))
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
uint16_t value = 0U;
|
|
|
|
if (!modbus_memory_read_holding_register(mem, (uint16_t)(start_offset + i), &value))
|
|
value = 0U;
|
|
|
|
dest[i] = value;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool modbus_memory_write_holding_registers(modbus_memory_t *mem,
|
|
uint16_t start_offset,
|
|
uint16_t quantity,
|
|
const uint16_t *src)
|
|
{
|
|
uint16_t i;
|
|
|
|
if (src == NULL || quantity == 0U || mem == NULL || mem->db == NULL)
|
|
return false;
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
uint16_t off = (uint16_t)(start_offset + i);
|
|
|
|
if (find_point_rw(mem, MB_MEM_HOLDING_REGISTER, off) == NULL)
|
|
{
|
|
if (modbus_points_find_by_pics_range(mem->db,
|
|
MB_POINT_HOLDING_REGISTER,
|
|
off) == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < quantity; i++)
|
|
{
|
|
if (!modbus_memory_write_holding_register(mem,
|
|
(uint16_t)(start_offset + i),
|
|
src[i]))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
{
|
|
modbus_point_t *pics_pt;
|
|
|
|
pics_pt = find_pics_point_rw(mem, MB_MEM_HOLDING_REGISTER, start_offset);
|
|
if (pics_pt != NULL)
|
|
{
|
|
if (!apply_pics_to_official_point(mem, pics_pt))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
} |