mirror of
https://github.com/emqx/neuron.git
synced 2026-10-31 00:19:15 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa90052653 | ||
|
|
2824197538 | ||
|
|
72cab4a0c8 | ||
|
|
c21df74a33 | ||
|
|
3d81d072d9 | ||
|
|
534c699da3 | ||
|
|
52e30c87ad | ||
|
|
f4a36fe47e | ||
|
|
7696321182 | ||
|
|
e4954c40a9 | ||
|
|
a8c9dccab7 | ||
|
|
33519663f0 | ||
|
|
0125fcfe17 | ||
|
|
ac9b57fff4 | ||
|
|
71d93753f5 | ||
|
|
639c55ea97 | ||
|
|
5b7724bdfe | ||
|
|
a420e91048 | ||
|
|
1a5a8e0b8a | ||
|
|
206c3055ed | ||
|
|
cc32019de9 | ||
|
|
919a24f264 | ||
|
|
9d0ee222d0 | ||
|
|
bd49739b39 | ||
|
|
0e87862532 | ||
|
|
f7a5604047 | ||
|
|
69ca20eb37 | ||
|
|
ca444a71c1 | ||
|
|
2d230366a1 | ||
|
|
0789deb82a | ||
|
|
12c8046301 | ||
|
|
ccf61815d0 | ||
|
|
9bf877a8e7 | ||
|
|
3b98edebe3 | ||
|
|
99309d2695 | ||
|
|
2e1444573c | ||
|
|
367e0a9842 | ||
|
|
7ae3aa6fca | ||
|
|
7305df4117 | ||
|
|
7d96187cf9 | ||
|
|
10acec6836 | ||
|
|
0ab902edd9 | ||
|
|
3398c2ff69 | ||
|
|
c7b9381252 | ||
|
|
18da977187 | ||
|
|
b5b3a9a0bc | ||
|
|
109257c928 | ||
|
|
cd59eccf89 | ||
|
|
2b9daee95c | ||
|
|
f8d92f22e3 | ||
|
|
f3e39e8325 |
@@ -9,7 +9,7 @@ on:
|
||||
|
||||
jobs:
|
||||
clang_format_check:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
steps:
|
||||
# checkout
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Run clang-format style check for C/C++ programs.
|
||||
uses: DoozyX/clang-format-lint-action@v0.12
|
||||
uses: DoozyX/clang-format-lint-action@v0.18
|
||||
with:
|
||||
source: 'src plugins include tests'
|
||||
exclude: 'include/neuron/utils/uthash.h include/neuron/utils/utarray.h include/neuron/utils/utlist.h include/neuron/utils/zlog.h'
|
||||
|
||||
@@ -8,13 +8,13 @@ on:
|
||||
- published
|
||||
|
||||
env:
|
||||
VERSION: 2.9.2
|
||||
VERSION: 2.9.5
|
||||
UI_VERSION: 2.6.1
|
||||
BRANCH: v2.9
|
||||
|
||||
jobs:
|
||||
cross-build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
@@ -52,14 +52,14 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
name: neuron-sdk-${{ matrix.arch[2] }}
|
||||
path: |
|
||||
neuron-sdk-*.tar.gz
|
||||
|
||||
build-debug-sdk:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
matrix:
|
||||
arch:
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
run: |
|
||||
./package-sdk.sh -p ${{ matrix.arch[2] }} -n neuron-sdk-debug-$VERSION
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
path: |
|
||||
@@ -102,7 +102,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: neuron-sdk
|
||||
|
||||
|
||||
@@ -85,25 +85,26 @@ bool neu_mqtt_client_is_open(neu_mqtt_client_t *client);
|
||||
bool neu_mqtt_client_is_connected(neu_mqtt_client_t *client);
|
||||
size_t neu_mqtt_client_get_cached_msgs_num(neu_mqtt_client_t *client);
|
||||
|
||||
int neu_mqtt_client_set_addr(neu_mqtt_client_t *client, const char *host,
|
||||
uint16_t port);
|
||||
int neu_mqtt_client_set_id(neu_mqtt_client_t *client, const char *id);
|
||||
int neu_mqtt_client_set_will_msg(neu_mqtt_client_t *client, const char *topic,
|
||||
uint8_t *msg, uint32_t len, bool retain,
|
||||
uint8_t qos);
|
||||
int neu_mqtt_client_set_user(neu_mqtt_client_t *client, const char *username,
|
||||
const char *password);
|
||||
int neu_mqtt_client_set_connect_cb(neu_mqtt_client_t * client,
|
||||
neu_mqtt_client_connection_cb_t cb,
|
||||
void * data);
|
||||
int neu_mqtt_client_set_disconnect_cb(neu_mqtt_client_t * client,
|
||||
neu_mqtt_client_connection_cb_t cb,
|
||||
void * data);
|
||||
int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
|
||||
const char *ca, const char *cert, const char *key,
|
||||
const char *keypass);
|
||||
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
size_t mem_size_bytes, size_t db_size_bytes);
|
||||
int neu_mqtt_client_set_addr(neu_mqtt_client_t *client, const char *host,
|
||||
uint16_t port);
|
||||
int neu_mqtt_client_set_id(neu_mqtt_client_t *client, const char *id);
|
||||
int neu_mqtt_client_set_will_msg(neu_mqtt_client_t *client, const char *topic,
|
||||
uint8_t *msg, uint32_t len, bool retain,
|
||||
uint8_t qos);
|
||||
int neu_mqtt_client_set_user(neu_mqtt_client_t *client, const char *username,
|
||||
const char *password);
|
||||
int neu_mqtt_client_set_connect_cb(neu_mqtt_client_t * client,
|
||||
neu_mqtt_client_connection_cb_t cb,
|
||||
void * data);
|
||||
int neu_mqtt_client_set_disconnect_cb(neu_mqtt_client_t * client,
|
||||
neu_mqtt_client_connection_cb_t cb,
|
||||
void * data);
|
||||
int neu_mqtt_client_set_tls(neu_mqtt_client_t *client, bool enabled,
|
||||
const char *ca, const char *cert, const char *key,
|
||||
const char *keypass);
|
||||
void neu_mqtt_client_remove_cache_db(neu_mqtt_client_t *client);
|
||||
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
size_t mem_size_bytes, size_t db_size_bytes);
|
||||
// default to NEU_MQTT_CACHE_SYNC_INTERVAL_DEFAULT if not set
|
||||
int neu_mqtt_client_set_cache_sync_interval(neu_mqtt_client_t *client,
|
||||
uint32_t interval);
|
||||
|
||||
@@ -254,6 +254,8 @@ ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len);
|
||||
ssize_t neu_conn_udp_recvfrom(neu_conn_t *conn, uint8_t *buf, ssize_t len,
|
||||
void *src);
|
||||
|
||||
void neu_conn_clear_recv_buffer(neu_conn_t *conn);
|
||||
|
||||
/**
|
||||
* @brief Specify the client to send data.
|
||||
*
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
#define NEU_VERSION_MAJOR 2
|
||||
#define NEU_VERSION_MINOR 9
|
||||
#define NEU_VERSION_FIX 2
|
||||
#define NEU_VERSION_FIX 5
|
||||
|
||||
#define NEU_GET_VERSION_MAJOR(V) ((0xffff0000 & V) >> 16)
|
||||
#define NEU_GET_VERSION_MINOR(V) ((0x0000ff00 & V) >> 8)
|
||||
@@ -34,7 +34,7 @@
|
||||
#define NEU_TAG_NAME_LEN 128
|
||||
#define NEU_TAG_ADDRESS_LEN 128
|
||||
#define NEU_TAG_DESCRIPTION_LEN 128
|
||||
#define NEU_GROUP_MAX_PER_NODE 512
|
||||
#define NEU_GROUP_MAX_PER_NODE 1024
|
||||
#define NEU_GROUP_NAME_LEN 128
|
||||
#define NEU_GROUP_INTERVAL_LIMIT 100
|
||||
#define NEU_DEFAULT_GROUP_INTERVAL 100
|
||||
|
||||
@@ -63,6 +63,7 @@ typedef struct {
|
||||
|
||||
int neu_json_encode_read_resp(void *json_object, void *param);
|
||||
int neu_json_encode_read_resp1(void *json_object, void *param);
|
||||
int neu_json_encode_read_resp2(void *json_object, void *param);
|
||||
int neu_json_encode_read_paginate_resp(void *json_object, void *param);
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -44,6 +44,10 @@ typedef enum {
|
||||
NEU_DATATAG_ENDIAN_BL32 = 5, // #BL 2,1,4,3
|
||||
NEU_DATATAG_ENDIAN_L64 = 6, // #L 8,7,6,5,4,3,2,1
|
||||
NEU_DATATAG_ENDIAN_B64 = 7, // #B 1,2,3,4,5,6,7,8
|
||||
NEU_DATATAG_ENDIAN_LL64 = 8,
|
||||
NEU_DATATAG_ENDIAN_LB64 = 9,
|
||||
NEU_DATATAG_ENDIAN_BB64 = 10,
|
||||
NEU_DATATAG_ENDIAN_BL64 = 11,
|
||||
} neu_datatag_endian_e;
|
||||
|
||||
typedef enum {
|
||||
@@ -63,6 +67,7 @@ typedef union {
|
||||
} value32;
|
||||
struct {
|
||||
neu_datatag_endian_e endian;
|
||||
bool is_default;
|
||||
} value64;
|
||||
struct {
|
||||
uint16_t length;
|
||||
|
||||
+274
-131
@@ -474,6 +474,238 @@ static inline void neu_value16_set_bit(neu_value16_u *value, uint8_t index,
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint16_t neu_get_u16(uint8_t *bytes)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_u16(uint8_t *bytes, uint16_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
}
|
||||
|
||||
static inline int16_t neu_get_i16(uint8_t *bytes)
|
||||
{
|
||||
int16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_i16(uint8_t *bytes, int16_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
}
|
||||
|
||||
static inline uint32_t neu_get_u32(uint8_t *bytes)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_u32(uint8_t *bytes, uint32_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
}
|
||||
|
||||
static inline int32_t neu_get_i32(uint8_t *bytes)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_i32(uint8_t *bytes, int32_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
}
|
||||
|
||||
static inline float neu_get_f32(uint8_t *bytes)
|
||||
{
|
||||
float ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_f32(uint8_t *bytes, float val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
}
|
||||
|
||||
static inline uint64_t neu_get_u64(uint8_t *bytes)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_u64(uint8_t *bytes, uint64_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
bytes[4] = t[4];
|
||||
bytes[5] = t[5];
|
||||
bytes[6] = t[6];
|
||||
bytes[7] = t[7];
|
||||
}
|
||||
|
||||
static inline int64_t neu_get_i64(uint8_t *bytes)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_i64(uint8_t *bytes, int64_t val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
bytes[4] = t[4];
|
||||
bytes[5] = t[5];
|
||||
bytes[6] = t[6];
|
||||
bytes[7] = t[7];
|
||||
}
|
||||
|
||||
static inline double neu_get_f64(uint8_t *bytes)
|
||||
{
|
||||
double ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void neu_set_f64(uint8_t *bytes, double val)
|
||||
{
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &val;
|
||||
|
||||
bytes[0] = t[0];
|
||||
bytes[1] = t[1];
|
||||
bytes[2] = t[2];
|
||||
bytes[3] = t[3];
|
||||
bytes[4] = t[4];
|
||||
bytes[5] = t[5];
|
||||
bytes[6] = t[6];
|
||||
bytes[7] = t[7];
|
||||
}
|
||||
|
||||
static inline void neu_ntohs24_p(uint8_t *value)
|
||||
{
|
||||
uint8_t t = 0;
|
||||
@@ -506,6 +738,42 @@ static inline uint64_t neu_htonll(uint64_t u)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonlb(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[1];
|
||||
out_bytes[1] = in[0];
|
||||
out_bytes[2] = in[3];
|
||||
out_bytes[3] = in[2];
|
||||
out_bytes[4] = in[5];
|
||||
out_bytes[5] = in[4];
|
||||
out_bytes[6] = in[7];
|
||||
out_bytes[7] = in[6];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_htonbl(uint64_t u)
|
||||
{
|
||||
uint8_t *in = (uint8_t *) &u;
|
||||
uint64_t out = 0;
|
||||
uint8_t *out_bytes = (uint8_t *) &out;
|
||||
|
||||
out_bytes[0] = in[6];
|
||||
out_bytes[1] = in[7];
|
||||
out_bytes[2] = in[4];
|
||||
out_bytes[3] = in[5];
|
||||
out_bytes[4] = in[2];
|
||||
out_bytes[5] = in[3];
|
||||
out_bytes[6] = in[0];
|
||||
out_bytes[7] = in[1];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_ntohll(uint64_t u)
|
||||
{
|
||||
return neu_htonll(u);
|
||||
@@ -513,7 +781,8 @@ static inline uint64_t neu_ntohll(uint64_t u)
|
||||
|
||||
static inline void neu_ntonll_p(uint64_t *pu)
|
||||
{
|
||||
*pu = neu_htonll(*pu);
|
||||
uint64_t ret = neu_htonll(neu_get_u64((uint8_t *) pu));
|
||||
neu_set_u64((uint8_t *) pu, ret);
|
||||
}
|
||||
|
||||
static inline void neu_htonll_p(uint64_t *pu)
|
||||
@@ -523,7 +792,8 @@ static inline void neu_htonll_p(uint64_t *pu)
|
||||
|
||||
static inline void neu_ntohl_p(uint32_t *pu)
|
||||
{
|
||||
*pu = ntohl(*pu);
|
||||
uint32_t ret = ntohl(neu_get_u32((uint8_t *) pu));
|
||||
neu_set_u32((uint8_t *) pu, ret);
|
||||
}
|
||||
|
||||
static inline void neu_htonl_p(uint32_t *pu)
|
||||
@@ -533,7 +803,8 @@ static inline void neu_htonl_p(uint32_t *pu)
|
||||
|
||||
static inline void neu_ntohs_p(uint16_t *pu)
|
||||
{
|
||||
*pu = ntohs(*pu);
|
||||
uint16_t ret = ntohs(neu_get_u16((uint8_t *) pu));
|
||||
neu_set_u16((uint8_t *) pu, ret);
|
||||
}
|
||||
|
||||
static inline void neu_htons_p(uint16_t *pu)
|
||||
@@ -541,134 +812,6 @@ static inline void neu_htons_p(uint16_t *pu)
|
||||
neu_ntohs_p(pu);
|
||||
}
|
||||
|
||||
static inline uint16_t neu_get_u16(uint8_t *bytes)
|
||||
{
|
||||
uint16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int16_t neu_get_i16(uint8_t *bytes)
|
||||
{
|
||||
int16_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint32_t neu_get_u32(uint8_t *bytes)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int32_t neu_get_i32(uint8_t *bytes)
|
||||
{
|
||||
int32_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline float neu_get_f32(uint8_t *bytes)
|
||||
{
|
||||
float ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline uint64_t neu_get_u64(uint8_t *bytes)
|
||||
{
|
||||
uint64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int64_t neu_get_i64(uint8_t *bytes)
|
||||
{
|
||||
int64_t ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline double neu_get_f64(uint8_t *bytes)
|
||||
{
|
||||
double ret = 0;
|
||||
uint8_t *t = NULL;
|
||||
|
||||
t = (uint8_t *) &ret;
|
||||
|
||||
t[0] = bytes[0];
|
||||
t[1] = bytes[1];
|
||||
t[2] = bytes[2];
|
||||
t[3] = bytes[3];
|
||||
t[4] = bytes[4];
|
||||
t[5] = bytes[5];
|
||||
t[6] = bytes[6];
|
||||
t[7] = bytes[7];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -106,6 +106,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
},
|
||||
{
|
||||
"type": 7,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 8,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 9,
|
||||
@@ -30,7 +30,7 @@
|
||||
},
|
||||
{
|
||||
"type": 10,
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|)$"
|
||||
"regex": "^[0-9]+![3-4][0-9]+(#B|#L|#BB|#BL|#LL|#LB|)$"
|
||||
},
|
||||
{
|
||||
"type": 11,
|
||||
@@ -112,6 +112,35 @@
|
||||
"max": 10000
|
||||
}
|
||||
},
|
||||
"endianess_64": {
|
||||
"name": "Endianess of 8-Byte Data",
|
||||
"name_zh": "8 字节数据字节序",
|
||||
"description": "Tag byte order, applicable to int64, uint64 and double types",
|
||||
"description_zh": "点位字节序,适用于 int64,uint64 和 double 类型",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 1,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "12 34 56 78",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "21 43 65 87",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "87 65 43 21",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "78 56 34 12",
|
||||
"value": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"interval": {
|
||||
"name": "Send Interval",
|
||||
"name_zh": "指令发送间隔",
|
||||
|
||||
@@ -66,6 +66,13 @@ typedef enum modbus_area {
|
||||
MODBUS_AREA_HOLD_REGISTER = 4,
|
||||
} modbus_area_e;
|
||||
|
||||
typedef enum modbus_endianess_64 {
|
||||
MODBUS_LL = 1, // 12 34 56 78
|
||||
MODBUS_LB = 2, // 21 43 65 87
|
||||
MODBUS_BB = 3, // 87 65 43 21
|
||||
MODBUS_BL = 4, // 78 56 34 12
|
||||
} modbus_endianess_64;
|
||||
|
||||
struct modbus_header {
|
||||
uint16_t seq;
|
||||
uint16_t protocol;
|
||||
|
||||
@@ -230,7 +230,8 @@ modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte)
|
||||
return sort_result;
|
||||
}
|
||||
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option,
|
||||
modbus_endianess_64 endianess_64, bool default_tag_endian_64)
|
||||
{
|
||||
int n = 0;
|
||||
switch (type) {
|
||||
@@ -249,6 +250,9 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (default_tag_endian_64) {
|
||||
modbus_convert_endianess_64(value, endianess_64);
|
||||
}
|
||||
n = sizeof(uint64_t);
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
@@ -282,7 +286,8 @@ int cal_n_byte(int type, neu_value_u *value, neu_datatag_addr_option_u option)
|
||||
return n;
|
||||
}
|
||||
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64)
|
||||
{
|
||||
neu_tag_sort_result_t *result =
|
||||
neu_tag_sort(tags, tag_sort_write, tag_cmp_write);
|
||||
@@ -304,14 +309,17 @@ modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags)
|
||||
utarray_foreach(result->sorts[i].tags, modbus_point_write_t **, tag_s)
|
||||
{
|
||||
if ((*tag_s)->point.area == MODBUS_AREA_COIL) {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64, true);
|
||||
data_bit[k / 8] += ((*tag_s)->value.i8) << k % 8;
|
||||
n_byte += n_byte_tag;
|
||||
k++;
|
||||
} else {
|
||||
n_byte_tag = cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option);
|
||||
n_byte_tag =
|
||||
cal_n_byte((*tag_s)->point.type, &(*tag_s)->value,
|
||||
(*tag_s)->point.option, endianess_64,
|
||||
(*tag_s)->point.option.value64.is_default);
|
||||
memcpy(sort_result->cmd[i].bytes +
|
||||
2 *
|
||||
((*tag_s)->point.start_address -
|
||||
@@ -521,4 +529,24 @@ static bool tag_sort_write(neu_tag_sort_t *sort, void *tag,
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64)
|
||||
{
|
||||
switch (endianess_64) {
|
||||
case MODBUS_LL:
|
||||
break;
|
||||
case MODBUS_BB:
|
||||
value->u64 = neu_htonll(value->u64);
|
||||
break;
|
||||
case MODBUS_LB:
|
||||
value->u64 = neu_htonlb(value->u64);
|
||||
break;
|
||||
case MODBUS_BL:
|
||||
value->u64 = neu_htonbl(value->u64);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -79,9 +79,13 @@ typedef struct modbus_write_cmd_sort {
|
||||
modbus_write_cmd_t *cmd;
|
||||
} modbus_write_cmd_sort_t;
|
||||
|
||||
modbus_read_cmd_sort_t * modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *modbus_write_tags_sort(UT_array *tags);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
modbus_read_cmd_sort_t *modbus_tag_sort(UT_array *tags, uint16_t max_byte);
|
||||
modbus_write_cmd_sort_t *
|
||||
modbus_write_tags_sort(UT_array *tags, modbus_endianess_64 endianess_64);
|
||||
void modbus_tag_sort_free(modbus_read_cmd_sort_t *cs);
|
||||
|
||||
void modbus_convert_endianess_64(neu_value_u * value,
|
||||
modbus_endianess_64 endianess_64);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -107,6 +107,8 @@ int modbus_send_msg(void *ctx, uint16_t n_byte, uint8_t *bytes)
|
||||
neu_plugin_t *plugin = (neu_plugin_t *) ctx;
|
||||
int ret = 0;
|
||||
|
||||
neu_conn_clear_recv_buffer(plugin->conn);
|
||||
|
||||
plog_send_protocol(plugin, bytes, n_byte);
|
||||
|
||||
if (plugin->is_server) {
|
||||
@@ -412,6 +414,10 @@ int modbus_value_handle(void *ctx, uint8_t slave_id, uint16_t n_byte,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if ((*p_tag)->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&dvalue.value,
|
||||
plugin->endianess_64);
|
||||
}
|
||||
dvalue.value.u64 = neu_ntohll(dvalue.value.u64);
|
||||
break;
|
||||
case NEU_TYPE_BIT: {
|
||||
@@ -675,6 +681,9 @@ int modbus_write(neu_plugin_t *plugin, void *req, neu_datatag_t *tag,
|
||||
case NEU_TYPE_DOUBLE:
|
||||
case NEU_TYPE_INT64:
|
||||
case NEU_TYPE_UINT64:
|
||||
if (tag->option.value64.is_default) {
|
||||
modbus_convert_endianess_64(&value, plugin->endianess_64);
|
||||
}
|
||||
value.u64 = neu_htonll(value.u64);
|
||||
n_byte = sizeof(uint64_t);
|
||||
break;
|
||||
@@ -742,7 +751,7 @@ int modbus_write_tags(neu_plugin_t *plugin, void *req, UT_array *tags)
|
||||
|
||||
utarray_push_back(gtags->tags, &p);
|
||||
}
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags);
|
||||
gtags->cmd_sort = modbus_write_tags_sort(gtags->tags, plugin->endianess_64);
|
||||
for (uint16_t i = 0; i < gtags->cmd_sort->n_cmd; i++) {
|
||||
uint16_t response_size = 0;
|
||||
|
||||
|
||||
@@ -43,7 +43,9 @@ struct neu_plugin {
|
||||
uint16_t interval;
|
||||
uint16_t retry_interval;
|
||||
uint16_t max_retries;
|
||||
uint16_t check_header;
|
||||
|
||||
modbus_endianess_64 endianess_64;
|
||||
uint16_t check_header;
|
||||
};
|
||||
|
||||
void modbus_conn_connected(void *data, int fd);
|
||||
|
||||
@@ -167,6 +167,9 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
neu_json_elem_t retry_interval = { .name = "retry_interval",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
neu_json_elem_t endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 3, &link, &timeout,
|
||||
&interval);
|
||||
if (ret != 0) {
|
||||
@@ -206,9 +209,16 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
retry_interval.v.val_int = 0;
|
||||
}
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
param.log = plugin->common.log;
|
||||
plugin->max_retries = max_retries.v.val_int;
|
||||
plugin->retry_interval = retry_interval.v.val_int;
|
||||
plugin->endianess_64 = endianess_64.v.val_int;
|
||||
|
||||
if (link.v.val_int == 0) {
|
||||
param.type = NEU_CONN_TTY_CLIENT;
|
||||
|
||||
@@ -163,6 +163,8 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
.t = NEU_JSON_INT };
|
||||
neu_json_elem_t check_header = { .name = "check_header",
|
||||
.t = NEU_JSON_INT };
|
||||
neu_json_elem_t endianess_64 = { .name = "endianess_64",
|
||||
.t = NEU_JSON_INT };
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 5, &port, &host, &mode,
|
||||
&timeout, &interval);
|
||||
@@ -191,6 +193,12 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
retry_interval.v.val_int = 0;
|
||||
}
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 1, &endianess_64);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
endianess_64.v.val_int = MODBUS_LL;
|
||||
}
|
||||
|
||||
ret = neu_parse_param((char *) config, &err_param, 1, &check_header);
|
||||
if (ret != 0) {
|
||||
free(err_param);
|
||||
@@ -201,6 +209,7 @@ static int driver_config(neu_plugin_t *plugin, const char *config)
|
||||
plugin->interval = interval.v.val_int;
|
||||
plugin->max_retries = max_retries.v.val_int;
|
||||
plugin->retry_interval = retry_interval.v.val_int;
|
||||
plugin->endianess_64 = endianess_64.v.val_int;
|
||||
plugin->check_header = check_header.v.val_int;
|
||||
|
||||
if (mode.v.val_int == 1) {
|
||||
|
||||
+246
-246
@@ -1,247 +1,247 @@
|
||||
{
|
||||
"client-id": {
|
||||
"name": "Client ID",
|
||||
"name_zh": "客户端 ID",
|
||||
"description": "MQTT client id",
|
||||
"description_zh": "MQTT 客户端 ID",
|
||||
"type": "string",
|
||||
"attribute": "required",
|
||||
"default": "neuron_${random_str}",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"qos": {
|
||||
"name": "QoS Level",
|
||||
"name_zh": "QoS 等级",
|
||||
"description": "MQTT QoS level for message delivery",
|
||||
"description_zh": "MQTT 消息传输使用的服务质量等级",
|
||||
"type": "map",
|
||||
"attribute": "optional",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "QoS 0",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "QoS 1",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "QoS 2",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"format": {
|
||||
"name": "Upload Format",
|
||||
"name_zh": "上报数据格式",
|
||||
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
|
||||
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "values-format",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "tags-format",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"write-req-topic": {
|
||||
"name": "Write Request Topic",
|
||||
"name_zh": "写请求主题",
|
||||
"description": "MQTT topic to receive write request messages.",
|
||||
"description_zh": "接收点位写入请求的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${random_str}/write/req",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"write-resp-topic": {
|
||||
"name": "Write Response Topic",
|
||||
"name_zh": "写响应主题",
|
||||
"description": "MQTT topic to send write response messages.",
|
||||
"description_zh": "发送点位写入响应的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${random_str}/write/resp",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"offline-cache": {
|
||||
"name": "Offline Data Caching",
|
||||
"name_zh": "离线缓存",
|
||||
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
|
||||
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
|
||||
"attribute": "optional",
|
||||
"type": "bool",
|
||||
"default": false,
|
||||
"valid": {}
|
||||
},
|
||||
"cache-mem-size": {
|
||||
"name": "Cache Memory Size (MB)",
|
||||
"name_zh": "缓存内存大小(MB)",
|
||||
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
|
||||
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 1024
|
||||
}
|
||||
},
|
||||
"cache-disk-size": {
|
||||
"name": "Cache Disk Size (MB)",
|
||||
"name_zh": "缓存磁盘大小(MB)",
|
||||
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
|
||||
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 10240
|
||||
}
|
||||
},
|
||||
"cache-sync-interval": {
|
||||
"name": "Cache Sync Interval (MS)",
|
||||
"name_zh": "缓存消息重传间隔(MS)",
|
||||
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
|
||||
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"default": 100,
|
||||
"valid": {
|
||||
"min": 10,
|
||||
"max": 120000
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"name": "Broker Host",
|
||||
"name_zh": "服务器地址",
|
||||
"description": "MQTT broker host",
|
||||
"description_zh": "MQTT 服务器地址",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "broker.emqx.io",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Broker Port",
|
||||
"name_zh": "服务器端口",
|
||||
"description": "MQTT broker port",
|
||||
"description_zh": "MQTT 服务器端口",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 1883,
|
||||
"valid": {
|
||||
"min": 1024,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"name": "Username",
|
||||
"name_zh": "用户名",
|
||||
"description": "MQTT user name",
|
||||
"description_zh": "MQTT 用户名",
|
||||
"attribute": "optional",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"name": "Password",
|
||||
"name_zh": "密码",
|
||||
"description": "MQTT user password",
|
||||
"description_zh": "MQTT 用户密码",
|
||||
"attribute": "optional",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"ssl": {
|
||||
"name": "SSL",
|
||||
"name_zh": "SSL",
|
||||
"description": "Enable SSL connection",
|
||||
"description_zh": "是否启用 SSL 连接",
|
||||
"attribute": "optional",
|
||||
"type": "bool",
|
||||
"default": false,
|
||||
"valid": {}
|
||||
},
|
||||
"ca": {
|
||||
"name": "CA",
|
||||
"name_zh": "CA 证书",
|
||||
"description": "CA certificate which signs the server certificate",
|
||||
"description_zh": "签发服务器证书的 CA 证书",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
},
|
||||
"cert": {
|
||||
"name": "Client Cert",
|
||||
"name_zh": "客户端证书",
|
||||
"description": "Client x509 certificate when using two way authentication",
|
||||
"description_zh": "使用双向认证时,客户端的 x509 证书",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
},
|
||||
"key": {
|
||||
"name": "Client Private Key",
|
||||
"name_zh": "客户端私钥",
|
||||
"description": "Client private key when using two way authentication",
|
||||
"description_zh": "使用双向认证时,客户端的私钥",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
}
|
||||
}
|
||||
"client-id": {
|
||||
"name": "Client ID",
|
||||
"name_zh": "客户端 ID",
|
||||
"description": "MQTT client id",
|
||||
"description_zh": "MQTT 客户端 ID",
|
||||
"type": "string",
|
||||
"attribute": "required",
|
||||
"default": "neuron_${random_str}",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"qos": {
|
||||
"name": "QoS Level",
|
||||
"name_zh": "QoS 等级",
|
||||
"description": "MQTT QoS level for message delivery",
|
||||
"description_zh": "MQTT 消息传输使用的服务质量等级",
|
||||
"type": "map",
|
||||
"attribute": "optional",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "QoS 0",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "QoS 1",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "QoS 2",
|
||||
"value": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"format": {
|
||||
"name": "Upload Format",
|
||||
"name_zh": "上报数据格式",
|
||||
"description": "JSON format of the data reported. In values-mode, data are split into `values` and `errors` sub objects. In tags-mode, tag data are put in a single array.",
|
||||
"description_zh": "上报数据的 JSON 格式。在 values-format 格式下,数据被分为 `values` 和 `errors` 两个子对象。在 tags-format 格式下,数据被放在一个数组中。",
|
||||
"attribute": "required",
|
||||
"type": "map",
|
||||
"default": 0,
|
||||
"valid": {
|
||||
"map": [
|
||||
{
|
||||
"key": "values-format",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "tags-format",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"write-req-topic": {
|
||||
"name": "Write Request Topic",
|
||||
"name_zh": "写请求主题",
|
||||
"description": "MQTT topic to receive write request messages.",
|
||||
"description_zh": "接收点位写入请求的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${random_str}/write/req",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"write-resp-topic": {
|
||||
"name": "Write Response Topic",
|
||||
"name_zh": "写响应主题",
|
||||
"description": "MQTT topic to send write response messages.",
|
||||
"description_zh": "发送点位写入响应的 MQTT 主题。",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "/neuron/${random_str}/write/resp",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"offline-cache": {
|
||||
"name": "Offline Data Caching",
|
||||
"name_zh": "离线缓存",
|
||||
"description": "Offline caching switch. Cache MQTT messages when offline, and sync cached messages when back online.",
|
||||
"description_zh": "离线缓存开关。连接断开时缓存 MQTT 消息,连接重建时同步缓存的 MQTT 消息到服务器。",
|
||||
"attribute": "optional",
|
||||
"type": "bool",
|
||||
"default": false,
|
||||
"valid": {}
|
||||
},
|
||||
"cache-mem-size": {
|
||||
"name": "Cache Memory Size (MB)",
|
||||
"name_zh": "缓存内存大小(MB)",
|
||||
"description": "Max in-memory cache size in megabytes when MQTT connection exception occurs. Should be smaller than cache disk size.",
|
||||
"description_zh": "当 MQTT 连接异常时,最大的内存缓存大小(单位:MB)。应该小于缓存磁盘大小。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 1024
|
||||
}
|
||||
},
|
||||
"cache-disk-size": {
|
||||
"name": "Cache Disk Size (MB)",
|
||||
"name_zh": "缓存磁盘大小(MB)",
|
||||
"description": "Max in-disk cache size in megabytes when MQTT connection exception occurs. Should be larger than cache memory size. If nonzero, cache memory size should also be nonzero.",
|
||||
"description_zh": "当 MQTT 连接异常时,最大的磁盘缓存大小(单位:MB)。应该大于缓存内存大小。如果不为 0,缓存内存大小也应该不为 0。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 10240
|
||||
}
|
||||
},
|
||||
"cache-sync-interval": {
|
||||
"name": "Cache Sync Interval (MS)",
|
||||
"name_zh": "缓存消息重传间隔(MS)",
|
||||
"description": "When MQTT connection restores, cached messages will be synchronised to the broker. This controls the interval in milliseconds between each message to synchronise.",
|
||||
"description_zh": "当 MQTT 连接重建后,缓存的消息会被同步到服务器。此配置项控制消息重传时每条消息之间的时间间隔,以毫秒为单位。",
|
||||
"type": "int",
|
||||
"attribute": "required",
|
||||
"condition": {
|
||||
"field": "offline-cache",
|
||||
"value": true
|
||||
},
|
||||
"default": 100,
|
||||
"valid": {
|
||||
"min": 10,
|
||||
"max": 120000
|
||||
}
|
||||
},
|
||||
"host": {
|
||||
"name": "Broker Host",
|
||||
"name_zh": "服务器地址",
|
||||
"description": "MQTT broker host",
|
||||
"description_zh": "MQTT 服务器地址",
|
||||
"attribute": "required",
|
||||
"type": "string",
|
||||
"default": "broker.emqx.io",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"port": {
|
||||
"name": "Broker Port",
|
||||
"name_zh": "服务器端口",
|
||||
"description": "MQTT broker port",
|
||||
"description_zh": "MQTT 服务器端口",
|
||||
"attribute": "required",
|
||||
"type": "int",
|
||||
"default": 1883,
|
||||
"valid": {
|
||||
"min": 1,
|
||||
"max": 65535
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"name": "Username",
|
||||
"name_zh": "用户名",
|
||||
"description": "MQTT user name",
|
||||
"description_zh": "MQTT 用户名",
|
||||
"attribute": "optional",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"password": {
|
||||
"name": "Password",
|
||||
"name_zh": "密码",
|
||||
"description": "MQTT user password",
|
||||
"description_zh": "MQTT 用户密码",
|
||||
"attribute": "optional",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"valid": {
|
||||
"length": 255
|
||||
}
|
||||
},
|
||||
"ssl": {
|
||||
"name": "SSL",
|
||||
"name_zh": "SSL",
|
||||
"description": "Enable SSL connection",
|
||||
"description_zh": "是否启用 SSL 连接",
|
||||
"attribute": "optional",
|
||||
"type": "bool",
|
||||
"default": false,
|
||||
"valid": {}
|
||||
},
|
||||
"ca": {
|
||||
"name": "CA",
|
||||
"name_zh": "CA 证书",
|
||||
"description": "CA certificate which signs the server certificate",
|
||||
"description_zh": "签发服务器证书的 CA 证书",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
},
|
||||
"cert": {
|
||||
"name": "Client Cert",
|
||||
"name_zh": "客户端证书",
|
||||
"description": "Client x509 certificate when using two way authentication",
|
||||
"description_zh": "使用双向认证时,客户端的 x509 证书",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
},
|
||||
"key": {
|
||||
"name": "Client Private Key",
|
||||
"name_zh": "客户端私钥",
|
||||
"description": "Client private key when using two way authentication",
|
||||
"description_zh": "使用双向认证时,客户端的私钥",
|
||||
"attribute": "optional",
|
||||
"type": "file",
|
||||
"condition": {
|
||||
"field": "ssl",
|
||||
"value": true
|
||||
},
|
||||
"valid": {
|
||||
"length": 81960
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -70,7 +70,7 @@ char *generate_upload_json(neu_plugin_t *plugin, neu_reqresp_trans_data_t *data,
|
||||
neu_json_encode_read_periodic_resp,
|
||||
&json_str);
|
||||
} else if (MQTT_UPLOAD_FORMAT_TAGS == format) { // tags
|
||||
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp, &header,
|
||||
neu_json_encode_with_mqtt(&json, neu_json_encode_read_resp2, &header,
|
||||
neu_json_encode_read_periodic_resp,
|
||||
&json_str);
|
||||
} else {
|
||||
|
||||
@@ -402,9 +402,17 @@ int mqtt_plugin_request(neu_plugin_t *plugin, neu_reqresp_head_t *head,
|
||||
case NEU_REQ_UPDATE_NODE:
|
||||
error = handle_update_driver(plugin, data);
|
||||
break;
|
||||
case NEU_REQRESP_NODE_DELETED:
|
||||
error = handle_del_driver(plugin, data);
|
||||
case NEU_REQRESP_NODE_DELETED: {
|
||||
neu_reqresp_node_deleted_t *req = data;
|
||||
if (0 != strcmp(plugin->common.name, req->node)) {
|
||||
error = handle_del_driver(plugin, data);
|
||||
} else {
|
||||
if (plugin->client) {
|
||||
neu_mqtt_client_remove_cache_db(plugin->client);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
error = NEU_ERR_MQTT_FAILURE;
|
||||
break;
|
||||
|
||||
@@ -40,7 +40,7 @@ void handle_add_plugin(nng_aio *aio)
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_ADD_PLUGIN;
|
||||
strcpy(cmd.library, req->library);
|
||||
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
|
||||
cmd.schema_file = req->schema_file;
|
||||
cmd.so_file = req->so_file;
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
@@ -64,7 +64,7 @@ void handle_update_plugin(nng_aio *aio)
|
||||
|
||||
header.ctx = aio;
|
||||
header.type = NEU_REQ_UPDATE_PLUGIN;
|
||||
strcpy(cmd.library, req->library);
|
||||
strncpy(cmd.library, req->library, NEU_PLUGIN_LIBRARY_LEN);
|
||||
cmd.schema_file = req->schema_file;
|
||||
cmd.so_file = req->so_file;
|
||||
ret = neu_plugin_op(plugin, header, &cmd);
|
||||
|
||||
+54
-17
@@ -237,8 +237,7 @@ static void update_im(neu_adapter_t *adapter, const char *group,
|
||||
}
|
||||
neu_datatag_t *first = utarray_front(tags);
|
||||
|
||||
if (first == NULL ||
|
||||
!neu_tag_attribute_test(first, NEU_ATTRIBUTE_SUBSCRIBE)) {
|
||||
if (first == NULL) {
|
||||
utarray_free(tags);
|
||||
nlog_debug("update immediately, driver: %s, "
|
||||
"group: %s, tag: %s, type: %s, "
|
||||
@@ -757,9 +756,17 @@ static void fix_value(neu_datatag_t *tag, neu_type_e value_type,
|
||||
case NEU_TYPE_LWORD:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value->value.u64 = neu_ntohll(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value->value.u64 = neu_htonlb(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value->value.u64 = neu_htonbl(value->value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -860,7 +867,8 @@ int check_value_decimal(neu_type_e write_type, double result, int64_t value_min,
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else if (result < value_min || result > value_max) {
|
||||
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
|
||||
} else if (almost_equal(ceil(result), result, EPSILON)) {
|
||||
} else if (almost_equal(ceil(result), result, EPSILON) ||
|
||||
almost_equal(floor(result), result, EPSILON)) {
|
||||
return NEU_ERR_SUCCESS;
|
||||
} else {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
@@ -910,27 +918,26 @@ int is_value_in_range(neu_type_e tag_type, int64_t value, double value_d,
|
||||
case NEU_TYPE_UINT64:
|
||||
if (write_type != NEU_TYPE_INT64 && write_type != NEU_TYPE_DOUBLE) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else if (almost_equal(ceil(result), result, EPSILON)) {
|
||||
} else if (almost_equal(ceil(result), result, EPSILON) ||
|
||||
almost_equal(floor(result), result, EPSILON)) {
|
||||
return NEU_ERR_SUCCESS;
|
||||
} else {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
}
|
||||
case NEU_TYPE_FLOAT:
|
||||
if (write_type != NEU_TYPE_DOUBLE) {
|
||||
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else if (result < (int64_t) -FLT_MAX ||
|
||||
result > (int64_t) FLT_MAX) {
|
||||
}
|
||||
if (result < (int64_t) -FLT_MAX || result > (int64_t) FLT_MAX) {
|
||||
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
|
||||
} else {
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
case NEU_TYPE_DOUBLE:
|
||||
if (write_type != NEU_TYPE_DOUBLE) {
|
||||
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else {
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
return check_value(write_type, result, INT16_MIN, INT16_MAX);
|
||||
return NEU_ERR_SUCCESS;
|
||||
case NEU_TYPE_STRING:
|
||||
case NEU_TYPE_BOOL:
|
||||
case NEU_TYPE_BIT:
|
||||
@@ -974,20 +981,19 @@ int is_value_in_range(neu_type_e tag_type, int64_t value, double value_d,
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
}
|
||||
case NEU_TYPE_FLOAT:
|
||||
if (write_type != NEU_TYPE_DOUBLE) {
|
||||
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else if (value < (int64_t) -FLT_MAX ||
|
||||
value > (int64_t) FLT_MAX) {
|
||||
}
|
||||
if (value < (int64_t) -FLT_MAX || value > (int64_t) FLT_MAX) {
|
||||
return NEU_ERR_PLUGIN_TAG_VALUE_OUT_OF_RANGE;
|
||||
} else {
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
case NEU_TYPE_DOUBLE:
|
||||
if (write_type != NEU_TYPE_DOUBLE) {
|
||||
if (write_type != NEU_TYPE_DOUBLE && write_type != NEU_TYPE_INT64) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
} else {
|
||||
return NEU_ERR_SUCCESS;
|
||||
}
|
||||
return NEU_ERR_SUCCESS;
|
||||
case NEU_TYPE_STRING:
|
||||
if (write_type != NEU_TYPE_STRING) {
|
||||
return NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH;
|
||||
@@ -2180,9 +2186,17 @@ static void read_report_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2345,9 +2359,17 @@ static void read_group(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -2456,6 +2478,13 @@ static void read_group_paginate(int64_t timestamp, int64_t timeout,
|
||||
tag_value.datatag.option = tag->option;
|
||||
memcpy(tag_value.datatag.meta, tag->meta, NEU_TAG_META_LENGTH);
|
||||
|
||||
if (tag->attribute == NEU_ATTRIBUTE_WRITE) {
|
||||
tag_value.value.type = NEU_TYPE_STRING;
|
||||
tag_value.value.value.str[0] = 0;
|
||||
utarray_push_back(tag_values, &tag_value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (neu_driver_cache_meta_get(cache, group, tag->name, &value,
|
||||
tag_value.metas,
|
||||
NEU_TAG_META_SIZE) != 0) {
|
||||
@@ -2517,9 +2546,17 @@ static void read_group_paginate(int64_t timestamp, int64_t timeout,
|
||||
case NEU_TYPE_UINT64:
|
||||
switch (tag->option.value64.endian) {
|
||||
case NEU_DATATAG_ENDIAN_B64:
|
||||
case NEU_DATATAG_ENDIAN_BB64:
|
||||
value.value.value.u64 = neu_htonll(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_LB64:
|
||||
value.value.value.u64 = neu_htonlb(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_BL64:
|
||||
value.value.value.u64 = neu_htonbl(value.value.value.u64);
|
||||
break;
|
||||
case NEU_DATATAG_ENDIAN_L64:
|
||||
case NEU_DATATAG_ENDIAN_LL64:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+2
-2
@@ -315,8 +315,8 @@ UT_array *neu_group_query_read_tag_paginate(neu_group_t *group,
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&group->mtx);
|
||||
array = filter_tags_by_page(group->tags, is_readable_and_match_query, &q,
|
||||
current_page, page_size, total_count);
|
||||
array = filter_tags_by_page(group->tags, match_query, &q, current_page,
|
||||
page_size, total_count);
|
||||
pthread_mutex_unlock(&group->mtx);
|
||||
|
||||
return array;
|
||||
|
||||
+27
-13
@@ -255,21 +255,35 @@ int neu_datatag_parse_addr_option(const neu_datatag_t * datatag,
|
||||
case NEU_TYPE_UINT64: {
|
||||
char *op = find_last_character(datatag->address, '#');
|
||||
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = true;
|
||||
if (op != NULL) {
|
||||
char e = 0;
|
||||
sscanf(op, "#%c", &e);
|
||||
char e1 = 0;
|
||||
char e2 = 0;
|
||||
int n = sscanf(op, "#%c%c", &e1, &e2);
|
||||
|
||||
switch (e) {
|
||||
case 'B':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
break;
|
||||
case 'L':
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
default:
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
break;
|
||||
if (n == 2) {
|
||||
if (e1 == 'B' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BB64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'B' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_BL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LL64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L' && e2 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_LB64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
} else if (n == 1) {
|
||||
if (e1 == 'B') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_B64;
|
||||
option->value64.is_default = false;
|
||||
} else if (e1 == 'L') {
|
||||
option->value64.endian = NEU_DATATAG_ENDIAN_L64;
|
||||
option->value64.is_default = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ neu_conn_t *neu_conn_new(neu_conn_param_t *param, void *data,
|
||||
conn->disconnected = disconnected;
|
||||
conn->connected = connected;
|
||||
|
||||
conn->buf_size = 2048;
|
||||
conn->buf_size = 8192;
|
||||
conn->buf = calloc(conn->buf_size, 1);
|
||||
conn->offset = 0;
|
||||
conn->stop = false;
|
||||
@@ -407,6 +407,40 @@ ssize_t neu_conn_send(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void neu_conn_clear_recv_buffer(neu_conn_t *conn)
|
||||
{
|
||||
if (!conn->is_connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t temp_buf[256];
|
||||
ssize_t ret;
|
||||
|
||||
switch (conn->param.type) {
|
||||
case NEU_CONN_TCP_CLIENT:
|
||||
do {
|
||||
ret = recv(conn->fd, temp_buf, sizeof(temp_buf), MSG_DONTWAIT);
|
||||
|
||||
if (ret > 0) {
|
||||
continue;
|
||||
} else if (ret == 0) {
|
||||
zlog_info(conn->param.log,
|
||||
"Connection closed while clearing buffer.");
|
||||
break;
|
||||
} else if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
break;
|
||||
} else {
|
||||
zlog_error(conn->param.log, "Error clearing buffer: %s",
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
} while (ret > 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t neu_conn_recv(neu_conn_t *conn, uint8_t *buf, ssize_t len)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
|
||||
@@ -123,6 +123,7 @@ struct neu_mqtt_client_s {
|
||||
neu_mqtt_client_connection_cb_t disconnect_cb;
|
||||
void * disconnect_cb_data;
|
||||
nng_mqtt_sqlite_option * sqlite_cfg;
|
||||
char * db;
|
||||
bool receiving;
|
||||
nng_aio * recv_aio;
|
||||
subscription_t * subscriptions;
|
||||
@@ -541,8 +542,10 @@ static void connect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
neu_mqtt_client_t * client = arg;
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
int reason = 0;
|
||||
|
||||
log(notice, "mqtt client connected");
|
||||
nng_pipe_get_int(p, NNG_OPT_MQTT_CONNECT_REASON, &reason);
|
||||
log(notice, "mqtt client connected, reason: %d", reason);
|
||||
|
||||
nng_mtx_lock(client->mtx);
|
||||
// start receiving
|
||||
@@ -567,8 +570,11 @@ static void disconnect_cb(nng_pipe p, nng_pipe_ev ev, void *arg)
|
||||
subscription_t * sub = NULL;
|
||||
neu_mqtt_client_connection_cb_t cb = NULL;
|
||||
void * data = NULL;
|
||||
int reason = 0;
|
||||
|
||||
nng_pipe_get_int(p, NNG_OPT_MQTT_DISCONNECT_REASON, &reason);
|
||||
log(notice, "mqtt client disconnected, reason: %d", reason);
|
||||
|
||||
log(notice, "mqtt client disconnected");
|
||||
nng_mtx_lock(client->mtx);
|
||||
client->connected = false;
|
||||
cb = client->disconnect_cb;
|
||||
@@ -901,26 +907,10 @@ static inline nng_mqtt_sqlite_option *
|
||||
alloc_sqlite_config(neu_mqtt_client_t *client)
|
||||
{
|
||||
int rv;
|
||||
char * db = NULL;
|
||||
nng_mqtt_sqlite_option *cfg = NULL;
|
||||
const mqtt_buf client_id =
|
||||
nng_mqtt_msg_get_connect_client_id(client->conn_msg);
|
||||
|
||||
if (NULL == client_id.buf || 0 == client_id.length) {
|
||||
log(error, "nng_mqtt_msg_get_connect_client_id fail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
neu_asprintf(&db, "neuron-mqtt-client-%.*s.db", (unsigned) client_id.length,
|
||||
(char *) client_id.buf);
|
||||
if (NULL == db) {
|
||||
log(error, "neu_asprintf nano-mqtt cilent db fail");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((rv = nng_mqtt_alloc_sqlite_opt(&cfg)) != 0) {
|
||||
log(error, "nng_mqtt_alloc_sqlite_opt fail: %s", nng_strerror(rv));
|
||||
free(db);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -928,9 +918,7 @@ alloc_sqlite_config(neu_mqtt_client_t *client)
|
||||
nng_mqtt_set_sqlite_flush_threshold(cfg, 256);
|
||||
nng_mqtt_set_sqlite_max_rows(cfg, 256);
|
||||
nng_mqtt_set_sqlite_db_dir(cfg, "persistence/");
|
||||
nng_mqtt_sqlite_db_init(cfg, db, client->version);
|
||||
|
||||
free(db);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@@ -989,6 +977,7 @@ void neu_mqtt_client_free(neu_mqtt_client_t *client)
|
||||
subscriptions_free(client->subscriptions);
|
||||
tasks_free(client->task_free_list);
|
||||
nng_msg_free(client->conn_msg);
|
||||
free(client->db);
|
||||
free(client->url);
|
||||
free(client->host);
|
||||
nng_mtx_free(client->mtx);
|
||||
@@ -1213,6 +1202,76 @@ end:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void rand_str(char *dst, size_t len)
|
||||
{
|
||||
char alphabet[] = "0123456789"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
while (len-- > 1) {
|
||||
size_t i = (double) rand() / RAND_MAX * ((sizeof alphabet) - 1);
|
||||
*dst++ = alphabet[i];
|
||||
}
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
static int neu_mqtt_client_set_cache_db(neu_mqtt_client_t *client)
|
||||
{
|
||||
char str[8] = { 0 };
|
||||
rand_str(str, sizeof(str));
|
||||
|
||||
char *db = NULL;
|
||||
neu_asprintf(&db, "neuron-mqtt-client-%s.db", str);
|
||||
if (NULL == db) {
|
||||
log(error, "neu_asprintf nano-mqtt cilent db fail");
|
||||
return NEU_ERR_EINTERNAL;
|
||||
}
|
||||
|
||||
if (client->db && 0 == strcmp(client->db, db)) {
|
||||
free(db);
|
||||
return 0;
|
||||
}
|
||||
|
||||
neu_mqtt_client_remove_cache_db(client);
|
||||
|
||||
free(client->db);
|
||||
client->db = db;
|
||||
|
||||
if (client->sqlite_cfg) {
|
||||
nng_mqtt_sqlite_db_init(client->sqlite_cfg, db, client->version);
|
||||
}
|
||||
|
||||
log(notice, "set cache db %s", db);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void neu_mqtt_client_remove_cache_db(neu_mqtt_client_t *client)
|
||||
{
|
||||
if (NULL == client->db) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *dir = "persistence";
|
||||
int path_size = strlen(dir) + strlen(client->db) + 6;
|
||||
char * path = calloc(path_size, 1);
|
||||
if (NULL == path) {
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(path, path_size, "%s/%s", dir, client->db);
|
||||
log(notice, "rm cache db %s", path);
|
||||
remove(path);
|
||||
snprintf(path, path_size, "%s/%s-shm", dir, client->db);
|
||||
log(notice, "rm cache db %s", path);
|
||||
remove(path);
|
||||
snprintf(path, path_size, "%s/%s-wal", dir, client->db);
|
||||
log(notice, "rm cache db %s", path);
|
||||
remove(path);
|
||||
|
||||
free(path);
|
||||
}
|
||||
|
||||
int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
size_t mem_size_bytes, size_t db_size_bytes)
|
||||
{
|
||||
@@ -1227,6 +1286,7 @@ int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
if (client->sqlite_cfg) {
|
||||
nng_mqtt_free_sqlite_opt(client->sqlite_cfg);
|
||||
client->sqlite_cfg = NULL;
|
||||
neu_mqtt_client_remove_cache_db(client);
|
||||
}
|
||||
goto end;
|
||||
}
|
||||
@@ -1240,6 +1300,10 @@ int neu_mqtt_client_set_cache_size(neu_mqtt_client_t *client,
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != (rv = neu_mqtt_client_set_cache_db(client))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// FIXME: until NanoSDK cache size limit feature out
|
||||
// Assume that,
|
||||
// 1. every upload message follows the below template
|
||||
|
||||
@@ -801,10 +801,22 @@ static int manager_loop(enum neu_event_io_type type, int fd, void *usr_data)
|
||||
}
|
||||
utarray_free(subscriptions);
|
||||
}
|
||||
|
||||
neu_reqresp_node_deleted_t resp = { 0 };
|
||||
strcpy(resp.node, header->receiver);
|
||||
// notify MQTT about node removal
|
||||
if (0 == strcmp(adapter->module->module_name, "MQTT")) {
|
||||
msg = neu_msg_new(NEU_REQRESP_NODE_DELETED, NULL, &resp);
|
||||
if (NULL != msg) {
|
||||
neu_reqresp_head_t *hd = neu_msg_get_header(msg);
|
||||
strcpy(hd->receiver, cmd->node);
|
||||
strcpy(hd->sender, "manager");
|
||||
reply(manager, hd, &resp);
|
||||
}
|
||||
}
|
||||
header->type = NEU_REQ_NODE_UNINIT;
|
||||
forward_msg(manager, header, header->receiver);
|
||||
|
||||
if (neu_adapter_get_type(adapter) == NEU_NA_TYPE_DRIVER) {
|
||||
UT_array *apps = neu_subscribe_manager_find_by_driver(
|
||||
manager->subscribe_manager, resp.node);
|
||||
|
||||
@@ -243,9 +243,11 @@ int neu_manager_subscribe(neu_manager_t *manager, const char *app,
|
||||
// guard against empty mqtt topic parameter
|
||||
// this is not an elegant solution due to the current architecture
|
||||
if (params && 0 == strcmp(adapter->module->module_name, "MQTT")) {
|
||||
neu_json_elem_t elem = { .name = "topic", .t = NEU_JSON_STR };
|
||||
neu_parse_param(params, NULL, 1, &elem);
|
||||
if (elem.v.val_str && 0 == strlen(elem.v.val_str)) {
|
||||
neu_json_elem_t elem = { .name = "topic",
|
||||
.t = NEU_JSON_STR,
|
||||
.v.val_str = NULL };
|
||||
int ret = neu_parse_param(params, NULL, 1, &elem);
|
||||
if (ret != 0 || (elem.v.val_str && 0 == strlen(elem.v.val_str))) {
|
||||
free(elem.v.val_str);
|
||||
return NEU_ERR_MQTT_SUBSCRIBE_FAILURE;
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ struct event_data {
|
||||
bool use;
|
||||
};
|
||||
|
||||
#define EVENT_SIZE 1400
|
||||
#define EVENT_SIZE 2800
|
||||
|
||||
struct neu_events {
|
||||
int epoll_fd;
|
||||
|
||||
@@ -291,6 +291,53 @@ int neu_json_encode_read_resp1(void *json_object, void *param)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_encode_read_resp2(void *json_object, void *param)
|
||||
{
|
||||
int ret = 0;
|
||||
neu_json_read_resp_t *resp = (neu_json_read_resp_t *) param;
|
||||
|
||||
void * tag_array = neu_json_array();
|
||||
neu_json_read_resp_tag_t *p_tag = resp->tags;
|
||||
for (int i = 0; i < resp->n_tag; i++) {
|
||||
neu_json_elem_t tag_elems[2 + NEU_TAG_META_SIZE] = { 0 };
|
||||
|
||||
tag_elems[0].name = "name";
|
||||
tag_elems[0].t = NEU_JSON_STR;
|
||||
tag_elems[0].v.val_str = p_tag->name;
|
||||
|
||||
if (p_tag->error != 0) {
|
||||
tag_elems[1].name = "error";
|
||||
tag_elems[1].t = NEU_JSON_INT;
|
||||
tag_elems[1].v.val_int = p_tag->error;
|
||||
} else {
|
||||
tag_elems[1].name = "value";
|
||||
tag_elems[1].t = p_tag->t;
|
||||
tag_elems[1].v = p_tag->value;
|
||||
tag_elems[1].precision = p_tag->precision;
|
||||
}
|
||||
|
||||
for (int k = 0; k < p_tag->n_meta; k++) {
|
||||
tag_elems[2 + k].name = p_tag->metas[k].name;
|
||||
tag_elems[2 + k].t = p_tag->metas[k].t;
|
||||
tag_elems[2 + k].v = p_tag->metas[k].value;
|
||||
}
|
||||
|
||||
tag_array =
|
||||
neu_json_encode_array(tag_array, tag_elems, 2 + p_tag->n_meta);
|
||||
p_tag++;
|
||||
}
|
||||
|
||||
neu_json_elem_t resp_elems[] = { {
|
||||
.name = "tags",
|
||||
.t = NEU_JSON_OBJECT,
|
||||
.v.val_object = tag_array,
|
||||
} };
|
||||
ret = neu_json_encode_field(json_object, resp_elems,
|
||||
NEU_JSON_ELEM_SIZE(resp_elems));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int neu_json_decode_write_req(char *buf, neu_json_write_req_t **result)
|
||||
{
|
||||
void *json_obj = neu_json_decode_new(buf);
|
||||
|
||||
@@ -563,10 +563,6 @@ class TestModbus:
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH == response.json()['error']
|
||||
|
||||
response = api.write_tag(node=param[0], group='group', tag=hold_float[0]['name'], value=1)
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_PLUGIN_TAG_TYPE_MISMATCH == response.json()['error']
|
||||
|
||||
response = api.write_tags(node=param[0], group='group', tag_values=[
|
||||
{"tag": hold_int16[0]['name'], "value": 32768},
|
||||
{"tag": hold_uint16[0]['name'], "value": 2},
|
||||
|
||||
@@ -348,12 +348,16 @@ class TestHttp:
|
||||
|
||||
@description(given="running neuron", when="put drivers with too many groups", then="should fail")
|
||||
def test_put_drivers_with_too_many_groups(self):
|
||||
|
||||
driver = {
|
||||
"name": driver_1["name"],
|
||||
"plugin": driver_1["plugin"],
|
||||
"params": driver_1["params"],
|
||||
"groups": [{"group": "grp", "interval": 1000, "tags": []} for _ in range(1000)]
|
||||
"groups": []
|
||||
}
|
||||
for i in range(1025):
|
||||
driver["groups"].append({"group": "grp" + str(i), "interval": 1000, "tags": []})
|
||||
|
||||
response = api.put_drivers([driver])
|
||||
assert 400 == response.status_code
|
||||
assert error.NEU_ERR_GROUP_MAX_GROUPS == response.json()['error']
|
||||
|
||||
@@ -247,12 +247,12 @@ def get_subscribe_group(app, driver=None, group=None):
|
||||
|
||||
|
||||
@gen_check
|
||||
def subscribe_group(app, driver, group, params={}):
|
||||
def subscribe_group(app, driver, group, params={"topic": "/neuron/mqtt/test"}):
|
||||
return requests.post(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group, "params": params})
|
||||
|
||||
|
||||
@gen_check
|
||||
def subscribe_group_update(app, driver, group, params={}):
|
||||
def subscribe_group_update(app, driver, group, params={"topic": "/neuron/mqtt/test"}):
|
||||
return requests.put(url=config.BASE_URL + "/api/v2/subscribe", headers={"Authorization": config.default_jwt}, json={"app": app, "driver": driver, "group": group, "params": params})
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user