core/modbus: support bytes

This commit is contained in:
fengzero
2023-08-25 09:07:07 +00:00
parent f8ebf93df1
commit 88a96c63fd
16 changed files with 239 additions and 47 deletions
+14 -7
View File
@@ -37,17 +37,24 @@ typedef enum neu_json_type {
NEU_JSON_FLOAT,
NEU_JSON_BOOL,
NEU_JSON_OBJECT,
NEU_JSON_BYTES,
NEU_JSON_VALUE = NEU_JSON_UNDEFINE
} neu_json_type_e;
typedef struct {
uint8_t *bytes;
uint8_t length;
} neu_json_value_bytes_t;
typedef union neu_json_value {
int64_t val_int;
uint8_t val_bit;
float val_float;
double val_double;
bool val_bool;
char * val_str;
void * val_object;
int64_t val_int;
uint8_t val_bit;
float val_float;
double val_double;
bool val_bool;
char * val_str;
void * val_object;
neu_json_value_bytes_t val_bytes;
} neu_json_value_u;
typedef enum neu_json_attribute {
+4
View File
@@ -68,6 +68,10 @@ typedef union {
neu_datatag_string_type_e type;
} string;
struct {
uint8_t length;
} bytes;
struct {
bool op;
uint8_t bit;
+20 -14
View File
@@ -105,21 +105,27 @@ typedef struct {
} neu_value_ptr_t;
#define NEU_VALUE_SIZE 128
typedef struct {
uint8_t bytes[NEU_VALUE_SIZE];
uint8_t length;
} __attribute__((packed)) neu_value_bytes_t;
typedef union {
bool boolean;
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
float f32;
double d64;
char str[NEU_VALUE_SIZE];
uint8_t bytes[NEU_VALUE_SIZE];
neu_value_ptr_t ptr;
bool boolean;
int8_t i8;
uint8_t u8;
int16_t i16;
uint16_t u16;
int32_t i32;
uint32_t u32;
int64_t i64;
uint64_t u64;
float f32;
double d64;
char str[NEU_VALUE_SIZE];
neu_value_bytes_t bytes;
neu_value_ptr_t ptr;
} neu_value_u;
static inline char *neu_value_str(neu_type_e type, neu_value_u value)
+5
View File
@@ -118,6 +118,11 @@ int wrap_tag_data(neu_json_read_resp_tag_t * json_tag,
json_tag->value.val_int = tag_value->value.value.i32;
json_tag->error = tag_value->value.value.i32;
break;
case NEU_TYPE_BYTES:
json_tag->t = NEU_JSON_BYTES;
json_tag->value.val_bytes.length = tag_value->value.value.bytes.length;
json_tag->value.val_bytes.bytes = tag_value->value.value.bytes.bytes;
break;
default:
break;
}
+6
View File
@@ -144,6 +144,12 @@ int write_data(neu_plugin_t *plugin, json_write_req_t *write_req)
cmd.value.type = NEU_TYPE_BOOL;
cmd.value.value.boolean = write_req->value.val_bool;
break;
case NEU_JSON_BYTES:
cmd.value.type = NEU_TYPE_BYTES;
cmd.value.value.bytes.length = write_req->value.val_bytes.length;
memcpy(cmd.value.value.bytes.bytes, write_req->value.val_bytes.bytes,
write_req->value.val_bytes.length);
break;
default:
assert(false);
break;
+4
View File
@@ -39,6 +39,10 @@
{
"type": 13,
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$"
},
{
"type": 14,
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+$"
}
],
"group_interval": 1000,
+4
View File
@@ -39,6 +39,10 @@
{
"type": 13,
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+(H|L|)$"
},
{
"type": 14,
"regex": "^[0-9]+![3-4][0-9]+\\.[0-9]+$"
}
],
"group_interval": 1000,
+19
View File
@@ -96,6 +96,9 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point)
point->option.string.length <= 0) {
return NEU_ERR_TAG_ADDRESS_FORMAT_INVALID;
}
if (point->type == NEU_TYPE_BYTES && point->option.bytes.length <= 0) {
return NEU_ERR_TAG_ADDRESS_FORMAT_INVALID;
}
if (point->type == NEU_TYPE_BIT && point->option.bit.bit > 15) {
return NEU_ERR_TAG_ADDRESS_FORMAT_INVALID;
}
@@ -160,6 +163,18 @@ int modbus_tag_to_point(const neu_datatag_t *tag, modbus_point_t *point)
}
}
break;
case NEU_TYPE_BYTES:
if (point->area == MODBUS_AREA_COIL ||
point->area == MODBUS_AREA_INPUT) {
ret = NEU_ERR_TAG_TYPE_NOT_SUPPORT;
} else {
if (point->option.bytes.length > 128) {
return NEU_ERR_TAG_ADDRESS_FORMAT_INVALID;
}
point->n_register =
point->option.bytes.length / 2 + point->option.bytes.length % 2;
}
break;
default:
return NEU_ERR_TAG_TYPE_NOT_SUPPORT;
}
@@ -246,6 +261,10 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
}
break;
}
case NEU_TYPE_BYTES: {
n = option.bytes.length;
break;
}
default:
assert(1 == 0);
break;
+10 -5
View File
@@ -367,10 +367,11 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
case MODBUS_AREA_INPUT_REGISTER:
if (n_byte >= ((*p_tag)->start_address - start_address) * 2 +
(*p_tag)->n_register * 2) {
memcpy(dvalue.value.bytes,
memcpy(dvalue.value.bytes.bytes,
bytes +
((*p_tag)->start_address - start_address) * 2,
(*p_tag)->n_register * 2);
dvalue.value.bytes.length = (*p_tag)->n_register * 2;
}
break;
case MODBUS_AREA_COIL:
@@ -406,7 +407,7 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
case MODBUS_AREA_HOLD_REGISTER:
case MODBUS_AREA_INPUT_REGISTER: {
neu_value16_u v16 = { 0 };
v16.value = htons(*(uint16_t *) dvalue.value.bytes);
v16.value = htons(*(uint16_t *) dvalue.value.bytes.bytes);
dvalue.value.u8 =
neu_value16_get_bit(v16, (*p_tag)->option.bit.bit);
break;
@@ -495,15 +496,19 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
n_byte = point.option.string.length;
break;
}
case NEU_TYPE_BYTES: {
n_byte = point.option.bytes.length;
break;
}
default:
assert(1 == 0);
break;
}
uint16_t response_size = 0;
ret = modbus_stack_write(plugin->stack, req, point.slave_id, point.area,
point.start_address, point.n_register, value.bytes,
n_byte, &response_size, response);
ret = modbus_stack_write(
plugin->stack, req, point.slave_id, point.area, point.start_address,
point.n_register, value.bytes.bytes, n_byte, &response_size, response);
if (ret > 0) {
process_protocol_buf(plugin, point.slave_id, response_size);
}
+20
View File
@@ -129,6 +129,12 @@ static int tag_values_to_json(neu_resp_tag_value_meta_t *tags, uint16_t len,
json->tags[i].t = NEU_JSON_STR;
json->tags[i].value.val_str = (char *) tag->value.value.ptr.ptr;
break;
case NEU_TYPE_BYTES:
json->tags[i].t = NEU_JSON_BYTES;
json->tags[i].value.val_bytes.length =
tag->value.value.bytes.length;
json->tags[i].value.val_bytes.bytes = tag->value.value.bytes.bytes;
break;
default:
break;
}
@@ -269,6 +275,12 @@ static int send_write_tag_req(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt,
cmd.value.type = NEU_TYPE_BOOL;
cmd.value.value.boolean = req->value.val_bool;
break;
case NEU_JSON_BYTES:
cmd.value.type = NEU_TYPE_BYTES;
cmd.value.value.bytes.length = req->value.val_bytes.length;
memcpy(cmd.value.value.bytes.bytes, req->value.val_bytes.bytes,
req->value.val_bytes.length);
break;
default:
plog_error(plugin, "invalid tag value type: %d", req->t);
return -1;
@@ -329,6 +341,14 @@ static int send_write_tags_req(neu_plugin_t *plugin, neu_json_mqtt_t *mqtt,
cmd.tags[i].value.type = NEU_TYPE_BOOL;
cmd.tags[i].value.value.boolean = req->tags[i].value.val_bool;
break;
case NEU_JSON_BYTES:
cmd.tags[i].value.type = NEU_TYPE_BYTES;
cmd.tags[i].value.value.bytes.length =
req->tags[i].value.val_bytes.length;
memcpy(cmd.tags[i].value.value.bytes.bytes,
req->tags[i].value.val_bytes.bytes,
req->tags[i].value.val_bytes.length);
break;
default:
plog_error(plugin, "invalid tag value type: %d", req->tags[i].t);
free(cmd.tags);
+30
View File
@@ -70,6 +70,15 @@ void handle_write(nng_aio *aio)
return;
}
if (req->t == NEU_JSON_BYTES &&
req->value.val_bytes.length > NEU_VALUE_SIZE) {
NEU_JSON_RESPONSE_ERROR(NEU_ERR_STRING_TOO_LONG, {
neu_http_response(aio, NEU_ERR_STRING_TOO_LONG,
result_error);
});
return;
}
header.ctx = aio;
header.type = NEU_REQ_WRITE_TAG;
@@ -86,6 +95,12 @@ void handle_write(nng_aio *aio)
cmd.value.type = NEU_TYPE_STRING;
strcpy(cmd.value.value.str, req->value.val_str);
break;
case NEU_JSON_BYTES:
cmd.value.type = NEU_TYPE_BYTES;
cmd.value.value.bytes.length = req->value.val_bytes.length;
memcpy(cmd.value.value.bytes.bytes, req->value.val_bytes.bytes,
req->value.val_bytes.length);
break;
case NEU_JSON_DOUBLE:
cmd.value.type = NEU_TYPE_DOUBLE;
cmd.value.value.d64 = req->value.val_double;
@@ -158,6 +173,14 @@ void handle_write_tags(nng_aio *aio)
cmd.tags[i].value.value.boolean =
req->tags[i].value.val_bool;
break;
case NEU_JSON_BYTES:
cmd.tags[i].value.type = NEU_TYPE_BYTES;
cmd.tags[i].value.value.bytes.length =
req->tags[i].value.val_bytes.length;
memcpy(cmd.tags[i].value.value.bytes.bytes,
req->tags[i].value.val_bytes.bytes,
req->tags[i].value.val_bytes.length);
break;
default:
assert(false);
break;
@@ -260,6 +283,13 @@ void handle_read_resp(nng_aio *aio, neu_resp_read_group_t *resp)
api_res.tags[i].t = NEU_JSON_STR;
api_res.tags[i].value.val_str = resp->tags[i].value.value.str;
break;
case NEU_TYPE_BYTES:
api_res.tags[i].t = NEU_JSON_BYTES;
api_res.tags[i].value.val_bytes.length =
resp->tags[i].value.value.bytes.length;
api_res.tags[i].value.val_bytes.bytes =
resp->tags[i].value.value.bytes.bytes;
break;
case NEU_TYPE_ERROR:
api_res.tags[i].t = NEU_JSON_INT;
api_res.tags[i].value.val_int = resp->tags[i].value.value.i32;
+36 -5
View File
@@ -159,7 +159,6 @@ void neu_driver_cache_update_change(neu_driver_cache_t *cache,
case NEU_TYPE_BIT:
case NEU_TYPE_BOOL:
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
case NEU_TYPE_WORD:
case NEU_TYPE_DWORD:
case NEU_TYPE_LWORD:
@@ -168,6 +167,18 @@ void neu_driver_cache_update_change(neu_driver_cache_t *cache,
elem->changed = true;
}
break;
case NEU_TYPE_BYTES:
if (elem->value.value.bytes.length !=
value.value.bytes.length) {
elem->changed = true;
} else {
if (memcpy(elem->value.value.bytes.bytes,
value.value.bytes.bytes,
value.value.bytes.length) != 0) {
elem->changed = true;
}
}
break;
case NEU_TYPE_PTR: {
if (elem->value.value.ptr.length != value.value.ptr.length) {
elem->changed = true;
@@ -290,10 +301,15 @@ int neu_driver_cache_meta_get(neu_driver_cache_t *cache, const char *group,
value->value.value.boolean = elem->value.value.boolean;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
memcpy(value->value.value.str, elem->value.value.str,
sizeof(elem->value.value.str));
break;
case NEU_TYPE_BYTES:
value->value.value.bytes.length = elem->value.value.bytes.length;
memcpy(value->value.value.bytes.bytes,
elem->value.value.bytes.bytes,
elem->value.value.bytes.length);
break;
case NEU_TYPE_PTR:
value->value.value.ptr.length = elem->value.value.ptr.length;
value->value.value.ptr.type = elem->value.value.ptr.type;
@@ -368,10 +384,15 @@ int neu_driver_cache_meta_get_changed(neu_driver_cache_t *cache,
value->value.value.boolean = elem->value.value.boolean;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
memcpy(value->value.value.str, elem->value.value.str,
sizeof(elem->value.value.str));
break;
case NEU_TYPE_BYTES:
value->value.value.bytes.length = elem->value.value.bytes.length;
memcpy(value->value.value.bytes.bytes,
elem->value.value.bytes.bytes,
elem->value.value.bytes.length);
break;
case NEU_TYPE_PTR:
value->value.value.ptr.length = elem->value.value.ptr.length;
value->value.value.ptr.type = elem->value.value.ptr.type;
@@ -444,10 +465,15 @@ int neu_driver_cache_get(neu_driver_cache_t *cache, const char *group,
value->value.value.boolean = elem->value.value.boolean;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
memcpy(value->value.value.str, elem->value.value.str,
sizeof(elem->value.value.str));
break;
case NEU_TYPE_BYTES:
value->value.value.bytes.length = elem->value.value.bytes.length;
memcpy(value->value.value.bytes.bytes,
elem->value.value.bytes.bytes,
elem->value.value.bytes.length);
break;
case NEU_TYPE_PTR:
value->value.value.ptr.length = elem->value.value.ptr.length;
value->value.value.ptr.type = elem->value.value.ptr.type;
@@ -518,10 +544,15 @@ int neu_driver_cache_get_changed(neu_driver_cache_t *cache, const char *group,
value->value.value.boolean = elem->value.value.boolean;
break;
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
memcpy(value->value.value.str, elem->value.value.str,
sizeof(elem->value.value.str));
break;
case NEU_TYPE_BYTES:
value->value.value.bytes.length = elem->value.value.bytes.length;
memcpy(value->value.value.bytes.bytes,
elem->value.value.bytes.bytes,
elem->value.value.bytes.length);
break;
case NEU_TYPE_PTR:
value->value.value.ptr.length = elem->value.value.ptr.length;
value->value.value.ptr.type = elem->value.value.ptr.type;
+17 -16
View File
@@ -378,6 +378,7 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
switch (tag->type) {
case NEU_TYPE_BOOL:
case NEU_TYPE_STRING:
case NEU_TYPE_BYTES:
break;
case NEU_TYPE_BIT:
value->type = NEU_TYPE_BIT;
@@ -404,16 +405,16 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
value->value.u32 = (uint32_t) value->value.u64;
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32:
neu_ntohs_p((uint16_t *) value->value.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes + 2);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
break;
case NEU_DATATAG_ENDIAN_BB32:
value->value.u32 = htonl(value->value.u32);
break;
case NEU_DATATAG_ENDIAN_BL32:
value->value.u32 = htonl(value->value.u32);
neu_ntohs_p((uint16_t *) value->value.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes + 2);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
break;
case NEU_DATATAG_ENDIAN_LL32:
default:
@@ -428,16 +429,16 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32:
neu_ntohs_p((uint16_t *) value->value.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes + 2);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
break;
case NEU_DATATAG_ENDIAN_BB32:
value->value.u32 = htonl(value->value.u32);
break;
case NEU_DATATAG_ENDIAN_BL32:
value->value.u32 = htonl(value->value.u32);
neu_ntohs_p((uint16_t *) value->value.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes + 2);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes);
neu_ntohs_p((uint16_t *) value->value.bytes.bytes + 2);
break;
case NEU_DATATAG_ENDIAN_LL32:
default:
@@ -1374,8 +1375,8 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
case NEU_TYPE_INT32:
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32: {
uint16_t *v1 = (uint16_t *) value.value.value.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes + 2);
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
@@ -1386,8 +1387,8 @@ static int read_report_group(int64_t timestamp, int64_t timeout,
break;
case NEU_DATATAG_ENDIAN_BL32:
value.value.value.u32 = htonl(value.value.value.u32);
uint16_t *v1 = (uint16_t *) value.value.value.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes + 2);
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
@@ -1523,8 +1524,8 @@ static void read_group(int64_t timestamp, int64_t timeout,
case NEU_TYPE_INT32:
switch (tag->option.value32.endian) {
case NEU_DATATAG_ENDIAN_LB32: {
uint16_t *v1 = (uint16_t *) value.value.value.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes + 2);
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
@@ -1535,8 +1536,8 @@ static void read_group(int64_t timestamp, int64_t timeout,
break;
case NEU_DATATAG_ENDIAN_BL32:
value.value.value.u32 = htonl(value.value.value.u32);
uint16_t *v1 = (uint16_t *) value.value.value.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes + 2);
uint16_t *v1 = (uint16_t *) value.value.value.bytes.bytes;
uint16_t *v2 = (uint16_t *) (value.value.value.bytes.bytes + 2);
neu_htons_p(v1);
neu_htons_p(v2);
+13
View File
@@ -137,6 +137,19 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
int ret = 0;
switch (datatag->type) {
case NEU_TYPE_BYTES: {
char *op = find_last_character(datatag->address, '.');
if (op == NULL) {
ret = -1;
} else {
int n = sscanf(op, ".%hhd", &option->bytes.length);
if (n != 1 || option->string.length <= 0) {
ret = -1;
}
}
break;
}
case NEU_TYPE_STRING: {
char *op = find_last_character(datatag->address, '.');
+7
View File
@@ -233,6 +233,9 @@ void neu_json_decode_write_req_free(neu_json_write_req_t *req)
if (req->t == NEU_JSON_STR) {
free(req->value.val_str);
}
if (req->t == NEU_JSON_BYTES && req->value.val_bytes.length > 0) {
free(req->value.val_bytes.bytes);
}
free(req);
}
@@ -346,6 +349,10 @@ void neu_json_decode_write_tags_req_free(neu_json_write_tags_req_t *req)
if (req->tags[i].t == NEU_JSON_STR) {
free(req->tags[i].value.val_str);
}
if (req->tags[i].t == NEU_JSON_BYTES &&
req->tags[i].value.val_bytes.length > 0) {
free(req->tags[i].value.val_bytes.bytes);
}
}
free(req->tags);
free(req);
+30
View File
@@ -80,6 +80,17 @@ static json_t *encode_object(json_t *object, neu_json_elem_t ele)
case NEU_JSON_BOOL:
json_object_set_new(ob, ele.name, json_boolean(ele.v.val_bool));
break;
case NEU_JSON_BYTES: {
void *bytes = json_array();
for (int i = 0; i < ele.v.val_bytes.length; i++) {
json_array_append_new(bytes,
json_integer(ele.v.val_bytes.bytes[i]));
}
json_object_set_new(ob, ele.name, bytes);
break;
}
case NEU_JSON_OBJECT:
json_object_set_new(ob, ele.name, ele.v.val_object);
break;
@@ -117,6 +128,8 @@ static int decode_object(json_t *root, neu_json_elem_t *ele)
ele->t = NEU_JSON_BOOL;
} else if (json_is_integer(ob)) {
ele->t = NEU_JSON_INT;
} else if (json_is_array(ob)) {
ele->t = NEU_JSON_BYTES;
}
}
@@ -147,6 +160,23 @@ static int decode_object(json_t *root, neu_json_elem_t *ele)
case NEU_JSON_BOOL:
ele->v.val_bool = json_boolean_value(ob);
break;
case NEU_JSON_BYTES: {
json_t *value = NULL;
ele->v.val_bytes.length = json_array_size(ob);
if (ele->v.val_bytes.length > 0) {
int index = 0;
ele->v.val_bytes.bytes =
calloc(ele->v.val_bytes.length, sizeof(uint8_t));
json_array_foreach(ob, index, value)
{
ele->v.val_bytes.bytes[index] =
(uint8_t) json_integer_value(value);
}
}
break;
}
case NEU_JSON_OBJECT:
ele->v.val_object = ob;
break;