Adicionar primeiro
This commit is contained in:
18
components/serial_sync/CMakeLists.txt
Executable file
18
components/serial_sync/CMakeLists.txt
Executable file
@@ -0,0 +1,18 @@
|
||||
set(srcs
|
||||
"protobuf/nanopb/pb_common.c"
|
||||
"protobuf/nanopb/pb_decode.c"
|
||||
"protobuf/nanopb/pb_encode.c"
|
||||
"protobuf/LoToHi.pb.c"
|
||||
"protobuf/HiToLo.pb.c"
|
||||
"src/sync_slave.c"
|
||||
"src/sync_master.c"
|
||||
)
|
||||
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include" "protobuf"
|
||||
PRIV_REQUIRES driver esp_timer
|
||||
REQUIRES config evse currentshaper)
|
||||
|
||||
|
||||
|
||||
23
components/serial_sync/include/sync_master.h
Executable file
23
components/serial_sync/include/sync_master.h
Executable file
@@ -0,0 +1,23 @@
|
||||
#ifndef SYNC_MASTER_H_
|
||||
#define SYNC_MASTER_H_
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send Grid Current
|
||||
*
|
||||
*/
|
||||
void send_grid_current(uint32_t grid_current);
|
||||
|
||||
/**
|
||||
* @brief Start master SYNC
|
||||
*
|
||||
*/
|
||||
void master_sync_start();
|
||||
|
||||
/**
|
||||
* @brief Stop master SYNC
|
||||
*
|
||||
*/
|
||||
void master_sync_stop(void);
|
||||
|
||||
#endif /* SYNC_MASTER_H_ */
|
||||
18
components/serial_sync/include/sync_slave.h
Executable file
18
components/serial_sync/include/sync_slave.h
Executable file
@@ -0,0 +1,18 @@
|
||||
#ifndef SYNC_SLAVE_H_
|
||||
#define SYNC_SLAVE_H_
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start slave SYNC
|
||||
*
|
||||
*/
|
||||
void slave_sync_start();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Stop slave SYNC
|
||||
*
|
||||
*/
|
||||
void slave_sync_stop(void);
|
||||
|
||||
#endif /* SYNC_SLAVE_H_ */
|
||||
12
components/serial_sync/protobuf/HiToLo.pb.c
Executable file
12
components/serial_sync/protobuf/HiToLo.pb.c
Executable file
@@ -0,0 +1,12 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.9-dev */
|
||||
|
||||
#include "HiToLo.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(HiToLo, HiToLo, AUTO)
|
||||
|
||||
|
||||
|
||||
70
components/serial_sync/protobuf/HiToLo.pb.h
Executable file
70
components/serial_sync/protobuf/HiToLo.pb.h
Executable file
@@ -0,0 +1,70 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.9-dev */
|
||||
|
||||
#ifndef PB_HITOLO_PB_H_INCLUDED
|
||||
#define PB_HITOLO_PB_H_INCLUDED
|
||||
#include <nanopb/pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
/* Struct definitions */
|
||||
/* This container message is send from Hi To Lo and may contain any allowed message in that direction. */
|
||||
typedef struct _HiToLo {
|
||||
pb_size_t which_payload;
|
||||
union {
|
||||
uint32_t time_stamp;
|
||||
bool connector_lock; /* false: unlock, true: lock */
|
||||
uint32_t max_charging_current;
|
||||
bool allow_power_on;
|
||||
bool reset;
|
||||
uint32_t grid_current;
|
||||
uint32_t max_grid_current;
|
||||
} payload;
|
||||
} HiToLo;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define HiToLo_init_default {0, {0}}
|
||||
#define HiToLo_init_zero {0, {0}}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define HiToLo_time_stamp_tag 1
|
||||
#define HiToLo_connector_lock_tag 2
|
||||
#define HiToLo_max_charging_current_tag 3
|
||||
#define HiToLo_allow_power_on_tag 4
|
||||
#define HiToLo_reset_tag 5
|
||||
#define HiToLo_grid_current_tag 6
|
||||
#define HiToLo_max_grid_current_tag 7
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define HiToLo_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,time_stamp,payload.time_stamp), 1) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,connector_lock,payload.connector_lock), 2) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,max_charging_current,payload.max_charging_current), 3) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,allow_power_on,payload.allow_power_on), 4) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,reset,payload.reset), 5) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,grid_current,payload.grid_current), 6) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,max_grid_current,payload.max_grid_current), 7)
|
||||
#define HiToLo_CALLBACK NULL
|
||||
#define HiToLo_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t HiToLo_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define HiToLo_fields &HiToLo_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define HITOLO_PB_H_MAX_SIZE HiToLo_size
|
||||
#define HiToLo_size 6
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
16
components/serial_sync/protobuf/HiToLo.proto
Executable file
16
components/serial_sync/protobuf/HiToLo.proto
Executable file
@@ -0,0 +1,16 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from Hi To Lo and may contain any allowed message in that direction.
|
||||
*/
|
||||
message HiToLo {
|
||||
oneof payload {
|
||||
uint32 time_stamp = 1;
|
||||
bool connector_lock = 2; // false: unlock, true: lock
|
||||
uint32 max_charging_current = 3;
|
||||
bool allow_power_on = 4;
|
||||
bool reset = 5;
|
||||
uint32 grid_current = 6;
|
||||
uint32 max_grid_current = 7;
|
||||
}
|
||||
}
|
||||
21
components/serial_sync/protobuf/LoToHi.pb.c
Executable file
21
components/serial_sync/protobuf/LoToHi.pb.c
Executable file
@@ -0,0 +1,21 @@
|
||||
/* Automatically generated nanopb constant definitions */
|
||||
/* Generated by nanopb-0.4.9-dev */
|
||||
|
||||
#include "LoToHi.pb.h"
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
PB_BIND(LoToHi, LoToHi, AUTO)
|
||||
|
||||
|
||||
PB_BIND(ErrorFlags, ErrorFlags, AUTO)
|
||||
|
||||
|
||||
PB_BIND(PowerMeter, PowerMeter, AUTO)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
237
components/serial_sync/protobuf/LoToHi.pb.h
Executable file
237
components/serial_sync/protobuf/LoToHi.pb.h
Executable file
@@ -0,0 +1,237 @@
|
||||
/* Automatically generated nanopb header */
|
||||
/* Generated by nanopb-0.4.9-dev */
|
||||
|
||||
#ifndef PB_LOTOHI_PB_H_INCLUDED
|
||||
#define PB_LOTOHI_PB_H_INCLUDED
|
||||
#include <nanopb/pb.h>
|
||||
|
||||
#if PB_PROTO_HEADER_VERSION != 40
|
||||
#error Regenerate this file with the current version of nanopb generator.
|
||||
#endif
|
||||
|
||||
/* Enum definitions */
|
||||
typedef enum _CpState {
|
||||
CpState_EVSE_STATE_A = 0,
|
||||
CpState_EVSE_STATE_B1 = 1,
|
||||
CpState_EVSE_STATE_B2 = 2,
|
||||
CpState_EVSE_STATE_C1 = 3,
|
||||
CpState_EVSE_STATE_C2 = 4,
|
||||
CpState_EVSE_STATE_D1 = 5,
|
||||
CpState_EVSE_STATE_D2 = 6,
|
||||
CpState_EVSE_STATE_E = 7,
|
||||
CpState_EVSE_STATE_F = 8
|
||||
} CpState;
|
||||
|
||||
typedef enum _PpState {
|
||||
PpState_STATE_NC = 0,
|
||||
PpState_STATE_13A = 1,
|
||||
PpState_STATE_20A = 2,
|
||||
PpState_STATE_32A = 3,
|
||||
PpState_STATE_70A = 4,
|
||||
PpState_STATE_FAULT = 5
|
||||
} PpState;
|
||||
|
||||
typedef enum _LockState {
|
||||
LockState_UNDEFINED = 0,
|
||||
LockState_UNLOCKED = 1,
|
||||
LockState_LOCKED = 2
|
||||
} LockState;
|
||||
|
||||
/* Struct definitions */
|
||||
typedef struct _ErrorFlags {
|
||||
bool diode_fault;
|
||||
bool rcd_selftest_failed;
|
||||
bool rcd_triggered;
|
||||
bool ventilation_not_available;
|
||||
bool connector_lock_failed;
|
||||
bool cp_signal_fault;
|
||||
} ErrorFlags;
|
||||
|
||||
typedef struct _PowerMeter {
|
||||
uint32_t time_stamp;
|
||||
float vrmsL1;
|
||||
float vrmsL2;
|
||||
float vrmsL3;
|
||||
float irmsL1;
|
||||
float irmsL2;
|
||||
float irmsL3;
|
||||
float irmsN;
|
||||
float wattHrL1;
|
||||
float wattHrL2;
|
||||
float wattHrL3;
|
||||
float totalWattHr;
|
||||
float tempL1;
|
||||
float tempL2;
|
||||
float tempL3;
|
||||
float tempN;
|
||||
float wattL1;
|
||||
float wattL2;
|
||||
float wattL3;
|
||||
float freqL1;
|
||||
float freqL2;
|
||||
float freqL3;
|
||||
bool phaseSeqError;
|
||||
} PowerMeter;
|
||||
|
||||
/* This container message is send from Lo To Hi and may contain any allowed message in that direction. */
|
||||
typedef struct _LoToHi {
|
||||
pb_size_t which_payload;
|
||||
union {
|
||||
uint32_t time_stamp;
|
||||
bool relais_state; /* false: relais are off, true: relais are on */
|
||||
ErrorFlags error_flags;
|
||||
CpState cp_state;
|
||||
PpState pp_state;
|
||||
uint32_t max_charging_current;
|
||||
uint32_t max_grid_current;
|
||||
LockState lock_state;
|
||||
PowerMeter power_meter;
|
||||
} payload;
|
||||
} LoToHi;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Helper constants for enums */
|
||||
#define _CpState_MIN CpState_EVSE_STATE_A
|
||||
#define _CpState_MAX CpState_EVSE_STATE_F
|
||||
#define _CpState_ARRAYSIZE ((CpState)(CpState_EVSE_STATE_F+1))
|
||||
|
||||
#define _PpState_MIN PpState_STATE_NC
|
||||
#define _PpState_MAX PpState_STATE_FAULT
|
||||
#define _PpState_ARRAYSIZE ((PpState)(PpState_STATE_FAULT+1))
|
||||
|
||||
#define _LockState_MIN LockState_UNDEFINED
|
||||
#define _LockState_MAX LockState_LOCKED
|
||||
#define _LockState_ARRAYSIZE ((LockState)(LockState_LOCKED+1))
|
||||
|
||||
#define LoToHi_payload_cp_state_ENUMTYPE CpState
|
||||
#define LoToHi_payload_pp_state_ENUMTYPE PpState
|
||||
#define LoToHi_payload_lock_state_ENUMTYPE LockState
|
||||
|
||||
|
||||
|
||||
|
||||
/* Initializer values for message structs */
|
||||
#define LoToHi_init_default {0, {0}}
|
||||
#define ErrorFlags_init_default {0, 0, 0, 0, 0, 0}
|
||||
#define PowerMeter_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
#define LoToHi_init_zero {0, {0}}
|
||||
#define ErrorFlags_init_zero {0, 0, 0, 0, 0, 0}
|
||||
#define PowerMeter_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||
|
||||
/* Field tags (for use in manual encoding/decoding) */
|
||||
#define ErrorFlags_diode_fault_tag 1
|
||||
#define ErrorFlags_rcd_selftest_failed_tag 2
|
||||
#define ErrorFlags_rcd_triggered_tag 3
|
||||
#define ErrorFlags_ventilation_not_available_tag 4
|
||||
#define ErrorFlags_connector_lock_failed_tag 5
|
||||
#define ErrorFlags_cp_signal_fault_tag 6
|
||||
#define PowerMeter_time_stamp_tag 1
|
||||
#define PowerMeter_vrmsL1_tag 2
|
||||
#define PowerMeter_vrmsL2_tag 3
|
||||
#define PowerMeter_vrmsL3_tag 4
|
||||
#define PowerMeter_irmsL1_tag 5
|
||||
#define PowerMeter_irmsL2_tag 6
|
||||
#define PowerMeter_irmsL3_tag 7
|
||||
#define PowerMeter_irmsN_tag 8
|
||||
#define PowerMeter_wattHrL1_tag 9
|
||||
#define PowerMeter_wattHrL2_tag 10
|
||||
#define PowerMeter_wattHrL3_tag 11
|
||||
#define PowerMeter_totalWattHr_tag 12
|
||||
#define PowerMeter_tempL1_tag 13
|
||||
#define PowerMeter_tempL2_tag 14
|
||||
#define PowerMeter_tempL3_tag 15
|
||||
#define PowerMeter_tempN_tag 16
|
||||
#define PowerMeter_wattL1_tag 17
|
||||
#define PowerMeter_wattL2_tag 18
|
||||
#define PowerMeter_wattL3_tag 19
|
||||
#define PowerMeter_freqL1_tag 20
|
||||
#define PowerMeter_freqL2_tag 21
|
||||
#define PowerMeter_freqL3_tag 22
|
||||
#define PowerMeter_phaseSeqError_tag 23
|
||||
#define LoToHi_time_stamp_tag 1
|
||||
#define LoToHi_relais_state_tag 2
|
||||
#define LoToHi_error_flags_tag 3
|
||||
#define LoToHi_cp_state_tag 4
|
||||
#define LoToHi_pp_state_tag 5
|
||||
#define LoToHi_max_charging_current_tag 6
|
||||
#define LoToHi_max_grid_current_tag 7
|
||||
#define LoToHi_lock_state_tag 8
|
||||
#define LoToHi_power_meter_tag 9
|
||||
|
||||
/* Struct field encoding specification for nanopb */
|
||||
#define LoToHi_FIELDLIST(X, a) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,time_stamp,payload.time_stamp), 1) \
|
||||
X(a, STATIC, ONEOF, BOOL, (payload,relais_state,payload.relais_state), 2) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,error_flags,payload.error_flags), 3) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,cp_state,payload.cp_state), 4) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,pp_state,payload.pp_state), 5) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,max_charging_current,payload.max_charging_current), 6) \
|
||||
X(a, STATIC, ONEOF, UINT32, (payload,max_grid_current,payload.max_grid_current), 7) \
|
||||
X(a, STATIC, ONEOF, UENUM, (payload,lock_state,payload.lock_state), 8) \
|
||||
X(a, STATIC, ONEOF, MESSAGE, (payload,power_meter,payload.power_meter), 9)
|
||||
#define LoToHi_CALLBACK NULL
|
||||
#define LoToHi_DEFAULT NULL
|
||||
#define LoToHi_payload_error_flags_MSGTYPE ErrorFlags
|
||||
#define LoToHi_payload_power_meter_MSGTYPE PowerMeter
|
||||
|
||||
#define ErrorFlags_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, BOOL, diode_fault, 1) \
|
||||
X(a, STATIC, SINGULAR, BOOL, rcd_selftest_failed, 2) \
|
||||
X(a, STATIC, SINGULAR, BOOL, rcd_triggered, 3) \
|
||||
X(a, STATIC, SINGULAR, BOOL, ventilation_not_available, 4) \
|
||||
X(a, STATIC, SINGULAR, BOOL, connector_lock_failed, 5) \
|
||||
X(a, STATIC, SINGULAR, BOOL, cp_signal_fault, 6)
|
||||
#define ErrorFlags_CALLBACK NULL
|
||||
#define ErrorFlags_DEFAULT NULL
|
||||
|
||||
#define PowerMeter_FIELDLIST(X, a) \
|
||||
X(a, STATIC, SINGULAR, UINT32, time_stamp, 1) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL1, 2) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL2, 3) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, vrmsL3, 4) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL1, 5) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL2, 6) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsL3, 7) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, irmsN, 8) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL1, 9) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL2, 10) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattHrL3, 11) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, totalWattHr, 12) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL1, 13) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL2, 14) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempL3, 15) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, tempN, 16) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL1, 17) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL2, 18) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, wattL3, 19) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL1, 20) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL2, 21) \
|
||||
X(a, STATIC, SINGULAR, FLOAT, freqL3, 22) \
|
||||
X(a, STATIC, SINGULAR, BOOL, phaseSeqError, 23)
|
||||
#define PowerMeter_CALLBACK NULL
|
||||
#define PowerMeter_DEFAULT NULL
|
||||
|
||||
extern const pb_msgdesc_t LoToHi_msg;
|
||||
extern const pb_msgdesc_t ErrorFlags_msg;
|
||||
extern const pb_msgdesc_t PowerMeter_msg;
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define LoToHi_fields &LoToHi_msg
|
||||
#define ErrorFlags_fields &ErrorFlags_msg
|
||||
#define PowerMeter_fields &PowerMeter_msg
|
||||
|
||||
/* Maximum encoded size of messages (where known) */
|
||||
#define ErrorFlags_size 12
|
||||
#define LOTOHI_PB_H_MAX_SIZE LoToHi_size
|
||||
#define LoToHi_size 123
|
||||
#define PowerMeter_size 121
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
80
components/serial_sync/protobuf/LoToHi.proto
Executable file
80
components/serial_sync/protobuf/LoToHi.proto
Executable file
@@ -0,0 +1,80 @@
|
||||
syntax = "proto3";
|
||||
|
||||
/*
|
||||
This container message is send from Lo To Hi and may contain any allowed message in that direction.
|
||||
*/
|
||||
message LoToHi {
|
||||
oneof payload {
|
||||
uint32 time_stamp = 1;
|
||||
bool relais_state = 2; // false: relais are off, true: relais are on
|
||||
ErrorFlags error_flags = 3;
|
||||
CpState cp_state = 4;
|
||||
PpState pp_state = 5;
|
||||
uint32 max_charging_current = 6;
|
||||
uint32 max_grid_current = 7;
|
||||
LockState lock_state = 8;
|
||||
PowerMeter power_meter = 9;
|
||||
}
|
||||
}
|
||||
|
||||
message ErrorFlags {
|
||||
bool diode_fault = 1;
|
||||
bool rcd_selftest_failed = 2;
|
||||
bool rcd_triggered = 3;
|
||||
bool ventilation_not_available = 4;
|
||||
bool connector_lock_failed = 5;
|
||||
bool cp_signal_fault = 6;
|
||||
}
|
||||
|
||||
enum CpState {
|
||||
EVSE_STATE_A = 0;
|
||||
EVSE_STATE_B1 = 1;
|
||||
EVSE_STATE_B2 = 2;
|
||||
EVSE_STATE_C1 = 3;
|
||||
EVSE_STATE_C2 = 4;
|
||||
EVSE_STATE_D1 = 5;
|
||||
EVSE_STATE_D2 = 6;
|
||||
EVSE_STATE_E = 7;
|
||||
EVSE_STATE_F = 8;
|
||||
}
|
||||
|
||||
enum PpState {
|
||||
STATE_NC = 0;
|
||||
STATE_13A = 1;
|
||||
STATE_20A = 2;
|
||||
STATE_32A = 3;
|
||||
STATE_70A = 4;
|
||||
STATE_FAULT = 5;
|
||||
}
|
||||
|
||||
enum LockState {
|
||||
UNDEFINED = 0;
|
||||
UNLOCKED = 1;
|
||||
LOCKED = 2;
|
||||
}
|
||||
|
||||
message PowerMeter {
|
||||
uint32 time_stamp = 1;
|
||||
float vrmsL1 = 2;
|
||||
float vrmsL2 = 3;
|
||||
float vrmsL3 = 4;
|
||||
float irmsL1 = 5;
|
||||
float irmsL2 = 6;
|
||||
float irmsL3 = 7;
|
||||
float irmsN = 8;
|
||||
float wattHrL1 = 9;
|
||||
float wattHrL2 = 10;
|
||||
float wattHrL3 = 11;
|
||||
float totalWattHr = 12;
|
||||
float tempL1 = 13;
|
||||
float tempL2 = 14;
|
||||
float tempL3 = 15;
|
||||
float tempN = 16;
|
||||
float wattL1 = 17;
|
||||
float wattL2 = 18;
|
||||
float wattL3 = 19;
|
||||
float freqL1 = 20;
|
||||
float freqL2 = 21;
|
||||
float freqL3 = 22;
|
||||
bool phaseSeqError = 23;
|
||||
}
|
||||
2
components/serial_sync/protobuf/generate_nanopb.sh
Executable file
2
components/serial_sync/protobuf/generate_nanopb.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
/home/ricar/Transferências/nanopb-master/generator/nanopb_generator.py -L "#include <nanopb/%s>" -I . -D . LoToHi.proto HiToLo.proto
|
||||
7
components/serial_sync/protobuf/generate_version_h.sh
Executable file
7
components/serial_sync/protobuf/generate_version_h.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
VERSION=$(git describe --dirty --always --tags)
|
||||
echo "#ifndef _VERSION_AUTOGEN_H_" > ../Yeti/Inc/version_autogen.h
|
||||
echo "#define _VERSION_AUTOGEN_H_" >> ../Yeti/Inc/version_autogen.h
|
||||
echo "#define VERSION_STRING \"$VERSION\"" >> ../Yeti/Inc/version_autogen.h
|
||||
echo "#endif" >> ../Yeti/Inc/version_autogen.h
|
||||
875
components/serial_sync/protobuf/nanopb/pb.h
Executable file
875
components/serial_sync/protobuf/nanopb/pb.h
Executable file
@@ -0,0 +1,875 @@
|
||||
/* Common parts of the nanopb library. Most of these are quite low-level
|
||||
* stuff. For the high-level interface, see pb_encode.h and pb_decode.h.
|
||||
*/
|
||||
|
||||
#ifndef PB_H_INCLUDED
|
||||
#define PB_H_INCLUDED
|
||||
|
||||
/*****************************************************************
|
||||
* Nanopb compilation time options. You can change these here by *
|
||||
* uncommenting the lines, or on the compiler command line. *
|
||||
*****************************************************************/
|
||||
|
||||
/* Enable support for dynamically allocated fields */
|
||||
/* #define PB_ENABLE_MALLOC 1 */
|
||||
|
||||
/* Define this if your CPU / compiler combination does not support
|
||||
* unaligned memory access to packed structures. */
|
||||
/* #define PB_NO_PACKED_STRUCTS 1 */
|
||||
|
||||
/* Increase the number of required fields that are tracked.
|
||||
* A compiler warning will tell if you need this. */
|
||||
/* #define PB_MAX_REQUIRED_FIELDS 256 */
|
||||
|
||||
/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */
|
||||
/* #define PB_FIELD_32BIT 1 */
|
||||
|
||||
/* Disable support for error messages in order to save some code space. */
|
||||
/* #define PB_NO_ERRMSG 1 */
|
||||
|
||||
/* Disable support for custom streams (support only memory buffers). */
|
||||
/* #define PB_BUFFER_ONLY 1 */
|
||||
|
||||
/* Disable support for 64-bit datatypes, for compilers without int64_t
|
||||
or to save some code space. */
|
||||
/* #define PB_WITHOUT_64BIT 1 */
|
||||
|
||||
/* Don't encode scalar arrays as packed. This is only to be used when
|
||||
* the decoder on the receiving side cannot process packed scalar arrays.
|
||||
* Such example is older protobuf.js. */
|
||||
/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */
|
||||
|
||||
/* Enable conversion of doubles to floats for platforms that do not
|
||||
* support 64-bit doubles. Most commonly AVR. */
|
||||
/* #define PB_CONVERT_DOUBLE_FLOAT 1 */
|
||||
|
||||
/* Check whether incoming strings are valid UTF-8 sequences. Slows down
|
||||
* the string processing slightly and slightly increases code size. */
|
||||
/* #define PB_VALIDATE_UTF8 1 */
|
||||
|
||||
/******************************************************************
|
||||
* You usually don't need to change anything below this line. *
|
||||
* Feel free to look around and use the defined macros, though. *
|
||||
******************************************************************/
|
||||
|
||||
|
||||
/* Version of the nanopb library. Just in case you want to check it in
|
||||
* your own program. */
|
||||
#define NANOPB_VERSION nanopb-0.4.5
|
||||
|
||||
/* Include all the system headers needed by nanopb. You will need the
|
||||
* definitions of the following:
|
||||
* - strlen, memcpy, memset functions
|
||||
* - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t
|
||||
* - size_t
|
||||
* - bool
|
||||
*
|
||||
* If you don't have the standard header files, you can instead provide
|
||||
* a custom header that defines or includes all this. In that case,
|
||||
* define PB_SYSTEM_HEADER to the path of this file.
|
||||
*/
|
||||
#ifdef PB_SYSTEM_HEADER
|
||||
#include PB_SYSTEM_HEADER
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef PB_ENABLE_MALLOC
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Macro for defining packed structures (compiler dependent).
|
||||
* This just reduces memory requirements, but is not required.
|
||||
*/
|
||||
#if defined(PB_NO_PACKED_STRUCTS)
|
||||
/* Disable struct packing */
|
||||
# define PB_PACKED_STRUCT_START
|
||||
# define PB_PACKED_STRUCT_END
|
||||
# define pb_packed
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
/* For GCC and clang */
|
||||
# define PB_PACKED_STRUCT_START
|
||||
# define PB_PACKED_STRUCT_END
|
||||
# define pb_packed __attribute__((packed))
|
||||
#elif defined(__ICCARM__) || defined(__CC_ARM)
|
||||
/* For IAR ARM and Keil MDK-ARM compilers */
|
||||
# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)")
|
||||
# define PB_PACKED_STRUCT_END _Pragma("pack(pop)")
|
||||
# define pb_packed
|
||||
#elif defined(_MSC_VER) && (_MSC_VER >= 1500)
|
||||
/* For Microsoft Visual C++ */
|
||||
# define PB_PACKED_STRUCT_START __pragma(pack(push, 1))
|
||||
# define PB_PACKED_STRUCT_END __pragma(pack(pop))
|
||||
# define pb_packed
|
||||
#else
|
||||
/* Unknown compiler */
|
||||
# define PB_PACKED_STRUCT_START
|
||||
# define PB_PACKED_STRUCT_END
|
||||
# define pb_packed
|
||||
#endif
|
||||
|
||||
/* Handly macro for suppressing unreferenced-parameter compiler warnings. */
|
||||
#ifndef PB_UNUSED
|
||||
#define PB_UNUSED(x) (void)(x)
|
||||
#endif
|
||||
|
||||
/* Harvard-architecture processors may need special attributes for storing
|
||||
* field information in program memory. */
|
||||
#ifndef PB_PROGMEM
|
||||
#ifdef __AVR__
|
||||
#include <avr/pgmspace.h>
|
||||
#define PB_PROGMEM PROGMEM
|
||||
#define PB_PROGMEM_READU32(x) pgm_read_dword(&x)
|
||||
#else
|
||||
#define PB_PROGMEM
|
||||
#define PB_PROGMEM_READU32(x) (x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Compile-time assertion, used for checking compatible compilation options.
|
||||
* If this does not work properly on your compiler, use
|
||||
* #define PB_NO_STATIC_ASSERT to disable it.
|
||||
*
|
||||
* But before doing that, check carefully the error message / place where it
|
||||
* comes from to see if the error has a real cause. Unfortunately the error
|
||||
* message is not always very clear to read, but you can see the reason better
|
||||
* in the place where the PB_STATIC_ASSERT macro was called.
|
||||
*/
|
||||
#ifndef PB_NO_STATIC_ASSERT
|
||||
# ifndef PB_STATIC_ASSERT
|
||||
# if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||
/* C11 standard _Static_assert mechanism */
|
||||
# define PB_STATIC_ASSERT(COND,MSG) _Static_assert(COND,#MSG);
|
||||
# else
|
||||
/* Classic negative-size-array static assert mechanism */
|
||||
# define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1];
|
||||
# define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER)
|
||||
# define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##_##LINE##_##COUNTER
|
||||
# endif
|
||||
# endif
|
||||
#else
|
||||
/* Static asserts disabled by PB_NO_STATIC_ASSERT */
|
||||
# define PB_STATIC_ASSERT(COND,MSG)
|
||||
#endif
|
||||
|
||||
/* Number of required fields to keep track of. */
|
||||
#ifndef PB_MAX_REQUIRED_FIELDS
|
||||
#define PB_MAX_REQUIRED_FIELDS 64
|
||||
#endif
|
||||
|
||||
#if PB_MAX_REQUIRED_FIELDS < 64
|
||||
#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64).
|
||||
#endif
|
||||
|
||||
#ifdef PB_WITHOUT_64BIT
|
||||
#ifdef PB_CONVERT_DOUBLE_FLOAT
|
||||
/* Cannot use doubles without 64-bit types */
|
||||
#undef PB_CONVERT_DOUBLE_FLOAT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* List of possible field types. These are used in the autogenerated code.
|
||||
* Least-significant 4 bits tell the scalar type
|
||||
* Most-significant 4 bits specify repeated/required/packed etc.
|
||||
*/
|
||||
|
||||
typedef uint_least8_t pb_type_t;
|
||||
|
||||
/**** Field data types ****/
|
||||
|
||||
/* Numeric types */
|
||||
#define PB_LTYPE_BOOL 0x00U /* bool */
|
||||
#define PB_LTYPE_VARINT 0x01U /* int32, int64, enum, bool */
|
||||
#define PB_LTYPE_UVARINT 0x02U /* uint32, uint64 */
|
||||
#define PB_LTYPE_SVARINT 0x03U /* sint32, sint64 */
|
||||
#define PB_LTYPE_FIXED32 0x04U /* fixed32, sfixed32, float */
|
||||
#define PB_LTYPE_FIXED64 0x05U /* fixed64, sfixed64, double */
|
||||
|
||||
/* Marker for last packable field type. */
|
||||
#define PB_LTYPE_LAST_PACKABLE 0x05U
|
||||
|
||||
/* Byte array with pre-allocated buffer.
|
||||
* data_size is the length of the allocated PB_BYTES_ARRAY structure. */
|
||||
#define PB_LTYPE_BYTES 0x06U
|
||||
|
||||
/* String with pre-allocated buffer.
|
||||
* data_size is the maximum length. */
|
||||
#define PB_LTYPE_STRING 0x07U
|
||||
|
||||
/* Submessage
|
||||
* submsg_fields is pointer to field descriptions */
|
||||
#define PB_LTYPE_SUBMESSAGE 0x08U
|
||||
|
||||
/* Submessage with pre-decoding callback
|
||||
* The pre-decoding callback is stored as pb_callback_t right before pSize.
|
||||
* submsg_fields is pointer to field descriptions */
|
||||
#define PB_LTYPE_SUBMSG_W_CB 0x09U
|
||||
|
||||
/* Extension pseudo-field
|
||||
* The field contains a pointer to pb_extension_t */
|
||||
#define PB_LTYPE_EXTENSION 0x0AU
|
||||
|
||||
/* Byte array with inline, pre-allocated byffer.
|
||||
* data_size is the length of the inline, allocated buffer.
|
||||
* This differs from PB_LTYPE_BYTES by defining the element as
|
||||
* pb_byte_t[data_size] rather than pb_bytes_array_t. */
|
||||
#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0BU
|
||||
|
||||
/* Number of declared LTYPES */
|
||||
#define PB_LTYPES_COUNT 0x0CU
|
||||
#define PB_LTYPE_MASK 0x0FU
|
||||
|
||||
/**** Field repetition rules ****/
|
||||
|
||||
#define PB_HTYPE_REQUIRED 0x00U
|
||||
#define PB_HTYPE_OPTIONAL 0x10U
|
||||
#define PB_HTYPE_SINGULAR 0x10U
|
||||
#define PB_HTYPE_REPEATED 0x20U
|
||||
#define PB_HTYPE_FIXARRAY 0x20U
|
||||
#define PB_HTYPE_ONEOF 0x30U
|
||||
#define PB_HTYPE_MASK 0x30U
|
||||
|
||||
/**** Field allocation types ****/
|
||||
|
||||
#define PB_ATYPE_STATIC 0x00U
|
||||
#define PB_ATYPE_POINTER 0x80U
|
||||
#define PB_ATYPE_CALLBACK 0x40U
|
||||
#define PB_ATYPE_MASK 0xC0U
|
||||
|
||||
#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK)
|
||||
#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK)
|
||||
#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK)
|
||||
#define PB_LTYPE_IS_SUBMSG(x) (PB_LTYPE(x) == PB_LTYPE_SUBMESSAGE || \
|
||||
PB_LTYPE(x) == PB_LTYPE_SUBMSG_W_CB)
|
||||
|
||||
/* Data type used for storing sizes of struct fields
|
||||
* and array counts.
|
||||
*/
|
||||
#if defined(PB_FIELD_32BIT)
|
||||
typedef uint32_t pb_size_t;
|
||||
typedef int32_t pb_ssize_t;
|
||||
#else
|
||||
typedef uint_least16_t pb_size_t;
|
||||
typedef int_least16_t pb_ssize_t;
|
||||
#endif
|
||||
#define PB_SIZE_MAX ((pb_size_t)-1)
|
||||
|
||||
/* Data type for storing encoded data and other byte streams.
|
||||
* This typedef exists to support platforms where uint8_t does not exist.
|
||||
* You can regard it as equivalent on uint8_t on other platforms.
|
||||
*/
|
||||
typedef uint_least8_t pb_byte_t;
|
||||
|
||||
/* Forward declaration of struct types */
|
||||
typedef struct pb_istream_s pb_istream_t;
|
||||
typedef struct pb_ostream_s pb_ostream_t;
|
||||
typedef struct pb_field_iter_s pb_field_iter_t;
|
||||
|
||||
/* This structure is used in auto-generated constants
|
||||
* to specify struct fields.
|
||||
*/
|
||||
typedef struct pb_msgdesc_s pb_msgdesc_t;
|
||||
struct pb_msgdesc_s {
|
||||
const uint32_t *field_info;
|
||||
const pb_msgdesc_t * const * submsg_info;
|
||||
const pb_byte_t *default_value;
|
||||
|
||||
bool (*field_callback)(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field);
|
||||
|
||||
pb_size_t field_count;
|
||||
pb_size_t required_field_count;
|
||||
pb_size_t largest_tag;
|
||||
};
|
||||
|
||||
/* Iterator for message descriptor */
|
||||
struct pb_field_iter_s {
|
||||
const pb_msgdesc_t *descriptor; /* Pointer to message descriptor constant */
|
||||
void *message; /* Pointer to start of the structure */
|
||||
|
||||
pb_size_t index; /* Index of the field */
|
||||
pb_size_t field_info_index; /* Index to descriptor->field_info array */
|
||||
pb_size_t required_field_index; /* Index that counts only the required fields */
|
||||
pb_size_t submessage_index; /* Index that counts only submessages */
|
||||
|
||||
pb_size_t tag; /* Tag of current field */
|
||||
pb_size_t data_size; /* sizeof() of a single item */
|
||||
pb_size_t array_size; /* Number of array entries */
|
||||
pb_type_t type; /* Type of current field */
|
||||
|
||||
void *pField; /* Pointer to current field in struct */
|
||||
void *pData; /* Pointer to current data contents. Different than pField for arrays and pointers. */
|
||||
void *pSize; /* Pointer to count/has field */
|
||||
|
||||
const pb_msgdesc_t *submsg_desc; /* For submessage fields, pointer to field descriptor for the submessage. */
|
||||
};
|
||||
|
||||
/* For compatibility with legacy code */
|
||||
typedef pb_field_iter_t pb_field_t;
|
||||
|
||||
/* Make sure that the standard integer types are of the expected sizes.
|
||||
* Otherwise fixed32/fixed64 fields can break.
|
||||
*
|
||||
* If you get errors here, it probably means that your stdint.h is not
|
||||
* correct for your platform.
|
||||
*/
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE)
|
||||
PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE)
|
||||
#endif
|
||||
|
||||
/* This structure is used for 'bytes' arrays.
|
||||
* It has the number of bytes in the beginning, and after that an array.
|
||||
* Note that actual structs used will have a different length of bytes array.
|
||||
*/
|
||||
#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; }
|
||||
#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes))
|
||||
|
||||
struct pb_bytes_array_s {
|
||||
pb_size_t size;
|
||||
pb_byte_t bytes[1];
|
||||
};
|
||||
typedef struct pb_bytes_array_s pb_bytes_array_t;
|
||||
|
||||
/* This structure is used for giving the callback function.
|
||||
* It is stored in the message structure and filled in by the method that
|
||||
* calls pb_decode.
|
||||
*
|
||||
* The decoding callback will be given a limited-length stream
|
||||
* If the wire type was string, the length is the length of the string.
|
||||
* If the wire type was a varint/fixed32/fixed64, the length is the length
|
||||
* of the actual value.
|
||||
* The function may be called multiple times (especially for repeated types,
|
||||
* but also otherwise if the message happens to contain the field multiple
|
||||
* times.)
|
||||
*
|
||||
* The encoding callback will receive the actual output stream.
|
||||
* It should write all the data in one call, including the field tag and
|
||||
* wire type. It can write multiple fields.
|
||||
*
|
||||
* The callback can be null if you want to skip a field.
|
||||
*/
|
||||
typedef struct pb_callback_s pb_callback_t;
|
||||
struct pb_callback_s {
|
||||
/* Callback functions receive a pointer to the arg field.
|
||||
* You can access the value of the field as *arg, and modify it if needed.
|
||||
*/
|
||||
union {
|
||||
bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg);
|
||||
bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg);
|
||||
} funcs;
|
||||
|
||||
/* Free arg for use by callback */
|
||||
void *arg;
|
||||
};
|
||||
|
||||
extern bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field);
|
||||
|
||||
/* Wire types. Library user needs these only in encoder callbacks. */
|
||||
typedef enum {
|
||||
PB_WT_VARINT = 0,
|
||||
PB_WT_64BIT = 1,
|
||||
PB_WT_STRING = 2,
|
||||
PB_WT_32BIT = 5
|
||||
} pb_wire_type_t;
|
||||
|
||||
/* Structure for defining the handling of unknown/extension fields.
|
||||
* Usually the pb_extension_type_t structure is automatically generated,
|
||||
* while the pb_extension_t structure is created by the user. However,
|
||||
* if you want to catch all unknown fields, you can also create a custom
|
||||
* pb_extension_type_t with your own callback.
|
||||
*/
|
||||
typedef struct pb_extension_type_s pb_extension_type_t;
|
||||
typedef struct pb_extension_s pb_extension_t;
|
||||
struct pb_extension_type_s {
|
||||
/* Called for each unknown field in the message.
|
||||
* If you handle the field, read off all of its data and return true.
|
||||
* If you do not handle the field, do not read anything and return true.
|
||||
* If you run into an error, return false.
|
||||
* Set to NULL for default handler.
|
||||
*/
|
||||
bool (*decode)(pb_istream_t *stream, pb_extension_t *extension,
|
||||
uint32_t tag, pb_wire_type_t wire_type);
|
||||
|
||||
/* Called once after all regular fields have been encoded.
|
||||
* If you have something to write, do so and return true.
|
||||
* If you do not have anything to write, just return true.
|
||||
* If you run into an error, return false.
|
||||
* Set to NULL for default handler.
|
||||
*/
|
||||
bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension);
|
||||
|
||||
/* Free field for use by the callback. */
|
||||
const void *arg;
|
||||
};
|
||||
|
||||
struct pb_extension_s {
|
||||
/* Type describing the extension field. Usually you'll initialize
|
||||
* this to a pointer to the automatically generated structure. */
|
||||
const pb_extension_type_t *type;
|
||||
|
||||
/* Destination for the decoded data. This must match the datatype
|
||||
* of the extension field. */
|
||||
void *dest;
|
||||
|
||||
/* Pointer to the next extension handler, or NULL.
|
||||
* If this extension does not match a field, the next handler is
|
||||
* automatically called. */
|
||||
pb_extension_t *next;
|
||||
|
||||
/* The decoder sets this to true if the extension was found.
|
||||
* Ignored for encoding. */
|
||||
bool found;
|
||||
};
|
||||
|
||||
#define pb_extension_init_zero {NULL,NULL,NULL,false}
|
||||
|
||||
/* Memory allocation functions to use. You can define pb_realloc and
|
||||
* pb_free to custom functions if you want. */
|
||||
#ifdef PB_ENABLE_MALLOC
|
||||
# ifndef pb_realloc
|
||||
# define pb_realloc(ptr, size) realloc(ptr, size)
|
||||
# endif
|
||||
# ifndef pb_free
|
||||
# define pb_free(ptr) free(ptr)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* This is used to inform about need to regenerate .pb.h/.pb.c files. */
|
||||
#define PB_PROTO_HEADER_VERSION 40
|
||||
|
||||
/* These macros are used to declare pb_field_t's in the constant array. */
|
||||
/* Size of a structure member, in bytes. */
|
||||
#define pb_membersize(st, m) (sizeof ((st*)0)->m)
|
||||
/* Number of entries in an array. */
|
||||
#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0]))
|
||||
/* Delta from start of one member to the start of another member. */
|
||||
#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2))
|
||||
|
||||
/* Force expansion of macro value */
|
||||
#define PB_EXPAND(x) x
|
||||
|
||||
/* Binding of a message field set into a specific structure */
|
||||
#define PB_BIND(msgname, structname, width) \
|
||||
const uint32_t structname ## _field_info[] PB_PROGMEM = \
|
||||
{ \
|
||||
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ ## width, structname) \
|
||||
0 \
|
||||
}; \
|
||||
const pb_msgdesc_t* const structname ## _submsg_info[] = \
|
||||
{ \
|
||||
msgname ## _FIELDLIST(PB_GEN_SUBMSG_INFO, structname) \
|
||||
NULL \
|
||||
}; \
|
||||
const pb_msgdesc_t structname ## _msg = \
|
||||
{ \
|
||||
structname ## _field_info, \
|
||||
structname ## _submsg_info, \
|
||||
msgname ## _DEFAULT, \
|
||||
msgname ## _CALLBACK, \
|
||||
0 msgname ## _FIELDLIST(PB_GEN_FIELD_COUNT, structname), \
|
||||
0 msgname ## _FIELDLIST(PB_GEN_REQ_FIELD_COUNT, structname), \
|
||||
0 msgname ## _FIELDLIST(PB_GEN_LARGEST_TAG, structname), \
|
||||
}; \
|
||||
msgname ## _FIELDLIST(PB_GEN_FIELD_INFO_ASSERT_ ## width, structname)
|
||||
|
||||
#define PB_GEN_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) +1
|
||||
#define PB_GEN_REQ_FIELD_COUNT(structname, atype, htype, ltype, fieldname, tag) \
|
||||
+ (PB_HTYPE_ ## htype == PB_HTYPE_REQUIRED)
|
||||
#define PB_GEN_LARGEST_TAG(structname, atype, htype, ltype, fieldname, tag) \
|
||||
* 0 + tag
|
||||
|
||||
/* X-macro for generating the entries in struct_field_info[] array. */
|
||||
#define PB_GEN_FIELD_INFO_1(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_2(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_4(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_8(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_AUTO(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
|
||||
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_FIELDINFO_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
|
||||
|
||||
#define PB_FIELDINFO_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_FIELDINFO_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
|
||||
|
||||
/* X-macro for generating asserts that entries fit in struct_field_info[] array.
|
||||
* The structure of macros here must match the structure above in PB_GEN_FIELD_INFO_x(),
|
||||
* but it is not easily reused because of how macro substitutions work. */
|
||||
#define PB_GEN_FIELD_INFO_ASSERT_1(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_ASSERT_1(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_ASSERT_2(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_ASSERT_2(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_ASSERT_4(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_ASSERT_4(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_ASSERT_8(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_ASSERT_8(tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_GEN_FIELD_INFO_ASSERT_AUTO(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_FIELDINFO_ASSERT_AUTO2(PB_FIELDINFO_WIDTH_AUTO(_PB_ATYPE_ ## atype, _PB_HTYPE_ ## htype, _PB_LTYPE_ ## ltype), \
|
||||
tag, PB_ATYPE_ ## atype | PB_HTYPE_ ## htype | PB_LTYPE_MAP_ ## ltype, \
|
||||
PB_DATA_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_DATA_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_SIZE_OFFSET_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname), \
|
||||
PB_ARRAY_SIZE_ ## atype(_PB_HTYPE_ ## htype, structname, fieldname))
|
||||
|
||||
#define PB_FIELDINFO_ASSERT_AUTO2(width, tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size)
|
||||
|
||||
#define PB_FIELDINFO_ASSERT_AUTO3(width, tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_FIELDINFO_ASSERT_ ## width(tag, type, data_offset, data_size, size_offset, array_size)
|
||||
|
||||
#define PB_DATA_OFFSET_STATIC(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
|
||||
#define PB_DATA_OFFSET_POINTER(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
|
||||
#define PB_DATA_OFFSET_CALLBACK(htype, structname, fieldname) PB_DO ## htype(structname, fieldname)
|
||||
#define PB_DO_PB_HTYPE_REQUIRED(structname, fieldname) offsetof(structname, fieldname)
|
||||
#define PB_DO_PB_HTYPE_SINGULAR(structname, fieldname) offsetof(structname, fieldname)
|
||||
#define PB_DO_PB_HTYPE_ONEOF(structname, fieldname) offsetof(structname, PB_ONEOF_NAME(FULL, fieldname))
|
||||
#define PB_DO_PB_HTYPE_OPTIONAL(structname, fieldname) offsetof(structname, fieldname)
|
||||
#define PB_DO_PB_HTYPE_REPEATED(structname, fieldname) offsetof(structname, fieldname)
|
||||
#define PB_DO_PB_HTYPE_FIXARRAY(structname, fieldname) offsetof(structname, fieldname)
|
||||
|
||||
#define PB_SIZE_OFFSET_STATIC(htype, structname, fieldname) PB_SO ## htype(structname, fieldname)
|
||||
#define PB_SIZE_OFFSET_POINTER(htype, structname, fieldname) PB_SO_PTR ## htype(structname, fieldname)
|
||||
#define PB_SIZE_OFFSET_CALLBACK(htype, structname, fieldname) PB_SO_CB ## htype(structname, fieldname)
|
||||
#define PB_SO_PB_HTYPE_REQUIRED(structname, fieldname) 0
|
||||
#define PB_SO_PB_HTYPE_SINGULAR(structname, fieldname) 0
|
||||
#define PB_SO_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF2(structname, PB_ONEOF_NAME(FULL, fieldname), PB_ONEOF_NAME(UNION, fieldname))
|
||||
#define PB_SO_PB_HTYPE_ONEOF2(structname, fullname, unionname) PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname)
|
||||
#define PB_SO_PB_HTYPE_ONEOF3(structname, fullname, unionname) pb_delta(structname, fullname, which_ ## unionname)
|
||||
#define PB_SO_PB_HTYPE_OPTIONAL(structname, fieldname) pb_delta(structname, fieldname, has_ ## fieldname)
|
||||
#define PB_SO_PB_HTYPE_REPEATED(structname, fieldname) pb_delta(structname, fieldname, fieldname ## _count)
|
||||
#define PB_SO_PB_HTYPE_FIXARRAY(structname, fieldname) 0
|
||||
#define PB_SO_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 0
|
||||
#define PB_SO_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 0
|
||||
#define PB_SO_PTR_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
|
||||
#define PB_SO_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 0
|
||||
#define PB_SO_PTR_PB_HTYPE_REPEATED(structname, fieldname) PB_SO_PB_HTYPE_REPEATED(structname, fieldname)
|
||||
#define PB_SO_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) 0
|
||||
#define PB_SO_CB_PB_HTYPE_REQUIRED(structname, fieldname) 0
|
||||
#define PB_SO_CB_PB_HTYPE_SINGULAR(structname, fieldname) 0
|
||||
#define PB_SO_CB_PB_HTYPE_ONEOF(structname, fieldname) PB_SO_PB_HTYPE_ONEOF(structname, fieldname)
|
||||
#define PB_SO_CB_PB_HTYPE_OPTIONAL(structname, fieldname) 0
|
||||
#define PB_SO_CB_PB_HTYPE_REPEATED(structname, fieldname) 0
|
||||
#define PB_SO_CB_PB_HTYPE_FIXARRAY(structname, fieldname) 0
|
||||
|
||||
#define PB_ARRAY_SIZE_STATIC(htype, structname, fieldname) PB_AS ## htype(structname, fieldname)
|
||||
#define PB_ARRAY_SIZE_POINTER(htype, structname, fieldname) PB_AS_PTR ## htype(structname, fieldname)
|
||||
#define PB_ARRAY_SIZE_CALLBACK(htype, structname, fieldname) 1
|
||||
#define PB_AS_PB_HTYPE_REQUIRED(structname, fieldname) 1
|
||||
#define PB_AS_PB_HTYPE_SINGULAR(structname, fieldname) 1
|
||||
#define PB_AS_PB_HTYPE_OPTIONAL(structname, fieldname) 1
|
||||
#define PB_AS_PB_HTYPE_ONEOF(structname, fieldname) 1
|
||||
#define PB_AS_PB_HTYPE_REPEATED(structname, fieldname) pb_arraysize(structname, fieldname)
|
||||
#define PB_AS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname)
|
||||
#define PB_AS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) 1
|
||||
#define PB_AS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) 1
|
||||
#define PB_AS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) 1
|
||||
#define PB_AS_PTR_PB_HTYPE_ONEOF(structname, fieldname) 1
|
||||
#define PB_AS_PTR_PB_HTYPE_REPEATED(structname, fieldname) 1
|
||||
#define PB_AS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_arraysize(structname, fieldname[0])
|
||||
|
||||
#define PB_DATA_SIZE_STATIC(htype, structname, fieldname) PB_DS ## htype(structname, fieldname)
|
||||
#define PB_DATA_SIZE_POINTER(htype, structname, fieldname) PB_DS_PTR ## htype(structname, fieldname)
|
||||
#define PB_DATA_SIZE_CALLBACK(htype, structname, fieldname) PB_DS_CB ## htype(structname, fieldname)
|
||||
#define PB_DS_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
|
||||
#define PB_DS_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname)[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname[0])
|
||||
#define PB_DS_PTR_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname[0][0])
|
||||
#define PB_DS_CB_PB_HTYPE_REQUIRED(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_CB_PB_HTYPE_SINGULAR(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_CB_PB_HTYPE_OPTIONAL(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_CB_PB_HTYPE_ONEOF(structname, fieldname) pb_membersize(structname, PB_ONEOF_NAME(FULL, fieldname))
|
||||
#define PB_DS_CB_PB_HTYPE_REPEATED(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
#define PB_DS_CB_PB_HTYPE_FIXARRAY(structname, fieldname) pb_membersize(structname, fieldname)
|
||||
|
||||
#define PB_ONEOF_NAME(type, tuple) PB_EXPAND(PB_ONEOF_NAME_ ## type tuple)
|
||||
#define PB_ONEOF_NAME_UNION(unionname,membername,fullname) unionname
|
||||
#define PB_ONEOF_NAME_MEMBER(unionname,membername,fullname) membername
|
||||
#define PB_ONEOF_NAME_FULL(unionname,membername,fullname) fullname
|
||||
|
||||
#define PB_GEN_SUBMSG_INFO(structname, atype, htype, ltype, fieldname, tag) \
|
||||
PB_SUBMSG_INFO_ ## htype(_PB_LTYPE_ ## ltype, structname, fieldname)
|
||||
|
||||
#define PB_SUBMSG_INFO_REQUIRED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
|
||||
#define PB_SUBMSG_INFO_SINGULAR(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
|
||||
#define PB_SUBMSG_INFO_OPTIONAL(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
|
||||
#define PB_SUBMSG_INFO_ONEOF(ltype, structname, fieldname) PB_SUBMSG_INFO_ONEOF2(ltype, structname, PB_ONEOF_NAME(UNION, fieldname), PB_ONEOF_NAME(MEMBER, fieldname))
|
||||
#define PB_SUBMSG_INFO_ONEOF2(ltype, structname, unionname, membername) PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername)
|
||||
#define PB_SUBMSG_INFO_ONEOF3(ltype, structname, unionname, membername) PB_SI ## ltype(structname ## _ ## unionname ## _ ## membername ## _MSGTYPE)
|
||||
#define PB_SUBMSG_INFO_REPEATED(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
|
||||
#define PB_SUBMSG_INFO_FIXARRAY(ltype, structname, fieldname) PB_SI ## ltype(structname ## _ ## fieldname ## _MSGTYPE)
|
||||
#define PB_SI_PB_LTYPE_BOOL(t)
|
||||
#define PB_SI_PB_LTYPE_BYTES(t)
|
||||
#define PB_SI_PB_LTYPE_DOUBLE(t)
|
||||
#define PB_SI_PB_LTYPE_ENUM(t)
|
||||
#define PB_SI_PB_LTYPE_UENUM(t)
|
||||
#define PB_SI_PB_LTYPE_FIXED32(t)
|
||||
#define PB_SI_PB_LTYPE_FIXED64(t)
|
||||
#define PB_SI_PB_LTYPE_FLOAT(t)
|
||||
#define PB_SI_PB_LTYPE_INT32(t)
|
||||
#define PB_SI_PB_LTYPE_INT64(t)
|
||||
#define PB_SI_PB_LTYPE_MESSAGE(t) PB_SUBMSG_DESCRIPTOR(t)
|
||||
#define PB_SI_PB_LTYPE_MSG_W_CB(t) PB_SUBMSG_DESCRIPTOR(t)
|
||||
#define PB_SI_PB_LTYPE_SFIXED32(t)
|
||||
#define PB_SI_PB_LTYPE_SFIXED64(t)
|
||||
#define PB_SI_PB_LTYPE_SINT32(t)
|
||||
#define PB_SI_PB_LTYPE_SINT64(t)
|
||||
#define PB_SI_PB_LTYPE_STRING(t)
|
||||
#define PB_SI_PB_LTYPE_UINT32(t)
|
||||
#define PB_SI_PB_LTYPE_UINT64(t)
|
||||
#define PB_SI_PB_LTYPE_EXTENSION(t)
|
||||
#define PB_SI_PB_LTYPE_FIXED_LENGTH_BYTES(t)
|
||||
#define PB_SUBMSG_DESCRIPTOR(t) &(t ## _msg),
|
||||
|
||||
/* The field descriptors use a variable width format, with width of either
|
||||
* 1, 2, 4 or 8 of 32-bit words. The two lowest bytes of the first byte always
|
||||
* encode the descriptor size, 6 lowest bits of field tag number, and 8 bits
|
||||
* of the field type.
|
||||
*
|
||||
* Descriptor size is encoded as 0 = 1 word, 1 = 2 words, 2 = 4 words, 3 = 8 words.
|
||||
*
|
||||
* Formats, listed starting with the least significant bit of the first word.
|
||||
* 1 word: [2-bit len] [6-bit tag] [8-bit type] [8-bit data_offset] [4-bit size_offset] [4-bit data_size]
|
||||
*
|
||||
* 2 words: [2-bit len] [6-bit tag] [8-bit type] [12-bit array_size] [4-bit size_offset]
|
||||
* [16-bit data_offset] [12-bit data_size] [4-bit tag>>6]
|
||||
*
|
||||
* 4 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit array_size]
|
||||
* [8-bit size_offset] [24-bit tag>>6]
|
||||
* [32-bit data_offset]
|
||||
* [32-bit data_size]
|
||||
*
|
||||
* 8 words: [2-bit len] [6-bit tag] [8-bit type] [16-bit reserved]
|
||||
* [8-bit size_offset] [24-bit tag>>6]
|
||||
* [32-bit data_offset]
|
||||
* [32-bit data_size]
|
||||
* [32-bit array_size]
|
||||
* [32-bit reserved]
|
||||
* [32-bit reserved]
|
||||
* [32-bit reserved]
|
||||
*/
|
||||
|
||||
#define PB_FIELDINFO_1(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
(0 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(data_offset) & 0xFF) << 16) | \
|
||||
(((uint32_t)(size_offset) & 0x0F) << 24) | (((uint32_t)(data_size) & 0x0F) << 28)),
|
||||
|
||||
#define PB_FIELDINFO_2(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
(1 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFF) << 16) | (((uint32_t)(size_offset) & 0x0F) << 28)), \
|
||||
(((uint32_t)(data_offset) & 0xFFFF) | (((uint32_t)(data_size) & 0xFFF) << 16) | (((uint32_t)(tag) & 0x3c0) << 22)),
|
||||
|
||||
#define PB_FIELDINFO_4(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
(2 | (((tag) << 2) & 0xFF) | ((type) << 8) | (((uint32_t)(array_size) & 0xFFFF) << 16)), \
|
||||
((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
|
||||
(data_offset), (data_size),
|
||||
|
||||
#define PB_FIELDINFO_8(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
(3 | (((tag) << 2) & 0xFF) | ((type) << 8)), \
|
||||
((uint32_t)(int_least8_t)(size_offset) | (((uint32_t)(tag) << 2) & 0xFFFFFF00)), \
|
||||
(data_offset), (data_size), (array_size), 0, 0, 0,
|
||||
|
||||
/* These assertions verify that the field information fits in the allocated space.
|
||||
* The generator tries to automatically determine the correct width that can fit all
|
||||
* data associated with a message. These asserts will fail only if there has been a
|
||||
* problem in the automatic logic - this may be worth reporting as a bug. As a workaround,
|
||||
* you can increase the descriptor width by defining PB_FIELDINFO_WIDTH or by setting
|
||||
* descriptorsize option in .options file.
|
||||
*/
|
||||
#define PB_FITS(value,bits) ((uint32_t)(value) < ((uint32_t)1<<bits))
|
||||
#define PB_FIELDINFO_ASSERT_1(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,6) && PB_FITS(data_offset,8) && PB_FITS(size_offset,4) && PB_FITS(data_size,4) && PB_FITS(array_size,1), FIELDINFO_DOES_NOT_FIT_width1_field ## tag)
|
||||
|
||||
#define PB_FIELDINFO_ASSERT_2(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,10) && PB_FITS(data_offset,16) && PB_FITS(size_offset,4) && PB_FITS(data_size,12) && PB_FITS(array_size,12), FIELDINFO_DOES_NOT_FIT_width2_field ## tag)
|
||||
|
||||
#ifndef PB_FIELD_32BIT
|
||||
/* Maximum field sizes are still 16-bit if pb_size_t is 16-bit */
|
||||
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
|
||||
|
||||
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,16) && PB_FITS(data_offset,16) && PB_FITS((int_least8_t)size_offset,8) && PB_FITS(data_size,16) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
|
||||
#else
|
||||
/* Up to 32-bit fields supported.
|
||||
* Note that the checks are against 31 bits to avoid compiler warnings about shift wider than type in the test.
|
||||
* I expect that there is no reasonable use for >2GB messages with nanopb anyway.
|
||||
*/
|
||||
#define PB_FIELDINFO_ASSERT_4(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,16), FIELDINFO_DOES_NOT_FIT_width4_field ## tag)
|
||||
|
||||
#define PB_FIELDINFO_ASSERT_8(tag, type, data_offset, data_size, size_offset, array_size) \
|
||||
PB_STATIC_ASSERT(PB_FITS(tag,30) && PB_FITS(data_offset,31) && PB_FITS(size_offset,8) && PB_FITS(data_size,31) && PB_FITS(array_size,31), FIELDINFO_DOES_NOT_FIT_width8_field ## tag)
|
||||
#endif
|
||||
|
||||
|
||||
/* Automatic picking of FIELDINFO width:
|
||||
* Uses width 1 when possible, otherwise resorts to width 2.
|
||||
* This is used when PB_BIND() is called with "AUTO" as the argument.
|
||||
* The generator will give explicit size argument when it knows that a message
|
||||
* structure grows beyond 1-word format limits.
|
||||
*/
|
||||
#define PB_FIELDINFO_WIDTH_AUTO(atype, htype, ltype) PB_FI_WIDTH ## atype(htype, ltype)
|
||||
#define PB_FI_WIDTH_PB_ATYPE_STATIC(htype, ltype) PB_FI_WIDTH ## htype(ltype)
|
||||
#define PB_FI_WIDTH_PB_ATYPE_POINTER(htype, ltype) PB_FI_WIDTH ## htype(ltype)
|
||||
#define PB_FI_WIDTH_PB_ATYPE_CALLBACK(htype, ltype) 2
|
||||
#define PB_FI_WIDTH_PB_HTYPE_REQUIRED(ltype) PB_FI_WIDTH ## ltype
|
||||
#define PB_FI_WIDTH_PB_HTYPE_SINGULAR(ltype) PB_FI_WIDTH ## ltype
|
||||
#define PB_FI_WIDTH_PB_HTYPE_OPTIONAL(ltype) PB_FI_WIDTH ## ltype
|
||||
#define PB_FI_WIDTH_PB_HTYPE_ONEOF(ltype) PB_FI_WIDTH ## ltype
|
||||
#define PB_FI_WIDTH_PB_HTYPE_REPEATED(ltype) 2
|
||||
#define PB_FI_WIDTH_PB_HTYPE_FIXARRAY(ltype) 2
|
||||
#define PB_FI_WIDTH_PB_LTYPE_BOOL 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_BYTES 2
|
||||
#define PB_FI_WIDTH_PB_LTYPE_DOUBLE 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_ENUM 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_UENUM 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_FIXED32 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_FIXED64 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_FLOAT 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_INT32 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_INT64 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_MESSAGE 2
|
||||
#define PB_FI_WIDTH_PB_LTYPE_MSG_W_CB 2
|
||||
#define PB_FI_WIDTH_PB_LTYPE_SFIXED32 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_SFIXED64 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_SINT32 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_SINT64 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_STRING 2
|
||||
#define PB_FI_WIDTH_PB_LTYPE_UINT32 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_UINT64 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_EXTENSION 1
|
||||
#define PB_FI_WIDTH_PB_LTYPE_FIXED_LENGTH_BYTES 2
|
||||
|
||||
/* The mapping from protobuf types to LTYPEs is done using these macros. */
|
||||
#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL
|
||||
#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES
|
||||
#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64
|
||||
#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT
|
||||
#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT
|
||||
#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32
|
||||
#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64
|
||||
#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32
|
||||
#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT
|
||||
#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT
|
||||
#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE
|
||||
#define PB_LTYPE_MAP_MSG_W_CB PB_LTYPE_SUBMSG_W_CB
|
||||
#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32
|
||||
#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64
|
||||
#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT
|
||||
#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT
|
||||
#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING
|
||||
#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT
|
||||
#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT
|
||||
#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION
|
||||
#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES
|
||||
|
||||
/* These macros are used for giving out error messages.
|
||||
* They are mostly a debugging aid; the main error information
|
||||
* is the true/false return value from functions.
|
||||
* Some code space can be saved by disabling the error
|
||||
* messages if not used.
|
||||
*
|
||||
* PB_SET_ERROR() sets the error message if none has been set yet.
|
||||
* msg must be a constant string literal.
|
||||
* PB_GET_ERROR() always returns a pointer to a string.
|
||||
* PB_RETURN_ERROR() sets the error and returns false from current
|
||||
* function.
|
||||
*/
|
||||
#ifdef PB_NO_ERRMSG
|
||||
#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream)
|
||||
#define PB_GET_ERROR(stream) "(errmsg disabled)"
|
||||
#else
|
||||
#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg))
|
||||
#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)")
|
||||
#endif
|
||||
|
||||
#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
#if __cplusplus >= 201103L
|
||||
#define PB_CONSTEXPR constexpr
|
||||
#else // __cplusplus >= 201103L
|
||||
#define PB_CONSTEXPR
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
#if __cplusplus >= 201703L
|
||||
#define PB_INLINE_CONSTEXPR inline constexpr
|
||||
#else // __cplusplus >= 201703L
|
||||
#define PB_INLINE_CONSTEXPR PB_CONSTEXPR
|
||||
#endif // __cplusplus >= 201703L
|
||||
|
||||
namespace nanopb {
|
||||
// Each type will be partially specialized by the generator.
|
||||
template <typename GenMessageT> struct MessageDescriptor;
|
||||
} // namespace nanopb
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
|
||||
388
components/serial_sync/protobuf/nanopb/pb_common.c
Executable file
388
components/serial_sync/protobuf/nanopb/pb_common.c
Executable file
@@ -0,0 +1,388 @@
|
||||
/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c.
|
||||
*
|
||||
* 2014 Petteri Aimonen <jpa@kapsi.fi>
|
||||
*/
|
||||
|
||||
#include "pb_common.h"
|
||||
|
||||
static bool load_descriptor_values(pb_field_iter_t *iter)
|
||||
{
|
||||
uint32_t word0;
|
||||
uint32_t data_offset;
|
||||
int_least8_t size_offset;
|
||||
|
||||
if (iter->index >= iter->descriptor->field_count)
|
||||
return false;
|
||||
|
||||
word0 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
|
||||
iter->type = (pb_type_t)((word0 >> 8) & 0xFF);
|
||||
|
||||
switch(word0 & 3)
|
||||
{
|
||||
case 0: {
|
||||
/* 1-word format */
|
||||
iter->array_size = 1;
|
||||
iter->tag = (pb_size_t)((word0 >> 2) & 0x3F);
|
||||
size_offset = (int_least8_t)((word0 >> 24) & 0x0F);
|
||||
data_offset = (word0 >> 16) & 0xFF;
|
||||
iter->data_size = (pb_size_t)((word0 >> 28) & 0x0F);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: {
|
||||
/* 2-word format */
|
||||
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
|
||||
|
||||
iter->array_size = (pb_size_t)((word0 >> 16) & 0x0FFF);
|
||||
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 28) << 6));
|
||||
size_offset = (int_least8_t)((word0 >> 28) & 0x0F);
|
||||
data_offset = word1 & 0xFFFF;
|
||||
iter->data_size = (pb_size_t)((word1 >> 16) & 0x0FFF);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: {
|
||||
/* 4-word format */
|
||||
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
|
||||
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
|
||||
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
|
||||
|
||||
iter->array_size = (pb_size_t)(word0 >> 16);
|
||||
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
|
||||
size_offset = (int_least8_t)(word1 & 0xFF);
|
||||
data_offset = word2;
|
||||
iter->data_size = (pb_size_t)word3;
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
/* 8-word format */
|
||||
uint32_t word1 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 1]);
|
||||
uint32_t word2 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 2]);
|
||||
uint32_t word3 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 3]);
|
||||
uint32_t word4 = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index + 4]);
|
||||
|
||||
iter->array_size = (pb_size_t)word4;
|
||||
iter->tag = (pb_size_t)(((word0 >> 2) & 0x3F) | ((word1 >> 8) << 6));
|
||||
size_offset = (int_least8_t)(word1 & 0xFF);
|
||||
data_offset = word2;
|
||||
iter->data_size = (pb_size_t)word3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!iter->message)
|
||||
{
|
||||
/* Avoid doing arithmetic on null pointers, it is undefined */
|
||||
iter->pField = NULL;
|
||||
iter->pSize = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->pField = (char*)iter->message + data_offset;
|
||||
|
||||
if (size_offset)
|
||||
{
|
||||
iter->pSize = (char*)iter->pField - size_offset;
|
||||
}
|
||||
else if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED &&
|
||||
(PB_ATYPE(iter->type) == PB_ATYPE_STATIC ||
|
||||
PB_ATYPE(iter->type) == PB_ATYPE_POINTER))
|
||||
{
|
||||
/* Fixed count array */
|
||||
iter->pSize = &iter->array_size;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->pSize = NULL;
|
||||
}
|
||||
|
||||
if (PB_ATYPE(iter->type) == PB_ATYPE_POINTER && iter->pField != NULL)
|
||||
{
|
||||
iter->pData = *(void**)iter->pField;
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->pData = iter->pField;
|
||||
}
|
||||
}
|
||||
|
||||
if (PB_LTYPE_IS_SUBMSG(iter->type))
|
||||
{
|
||||
iter->submsg_desc = iter->descriptor->submsg_info[iter->submessage_index];
|
||||
}
|
||||
else
|
||||
{
|
||||
iter->submsg_desc = NULL;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void advance_iterator(pb_field_iter_t *iter)
|
||||
{
|
||||
iter->index++;
|
||||
|
||||
if (iter->index >= iter->descriptor->field_count)
|
||||
{
|
||||
/* Restart */
|
||||
iter->index = 0;
|
||||
iter->field_info_index = 0;
|
||||
iter->submessage_index = 0;
|
||||
iter->required_field_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Increment indexes based on previous field type.
|
||||
* All field info formats have the following fields:
|
||||
* - lowest 2 bits tell the amount of words in the descriptor (2^n words)
|
||||
* - bits 2..7 give the lowest bits of tag number.
|
||||
* - bits 8..15 give the field type.
|
||||
*/
|
||||
uint32_t prev_descriptor = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
|
||||
pb_type_t prev_type = (prev_descriptor >> 8) & 0xFF;
|
||||
pb_size_t descriptor_len = (pb_size_t)(1 << (prev_descriptor & 3));
|
||||
|
||||
/* Add to fields.
|
||||
* The cast to pb_size_t is needed to avoid -Wconversion warning.
|
||||
* Because the data is is constants from generator, there is no danger of overflow.
|
||||
*/
|
||||
iter->field_info_index = (pb_size_t)(iter->field_info_index + descriptor_len);
|
||||
iter->required_field_index = (pb_size_t)(iter->required_field_index + (PB_HTYPE(prev_type) == PB_HTYPE_REQUIRED));
|
||||
iter->submessage_index = (pb_size_t)(iter->submessage_index + PB_LTYPE_IS_SUBMSG(prev_type));
|
||||
}
|
||||
}
|
||||
|
||||
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message)
|
||||
{
|
||||
memset(iter, 0, sizeof(*iter));
|
||||
|
||||
iter->descriptor = desc;
|
||||
iter->message = message;
|
||||
|
||||
return load_descriptor_values(iter);
|
||||
}
|
||||
|
||||
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension)
|
||||
{
|
||||
const pb_msgdesc_t *msg = (const pb_msgdesc_t*)extension->type->arg;
|
||||
bool status;
|
||||
|
||||
uint32_t word0 = PB_PROGMEM_READU32(msg->field_info[0]);
|
||||
if (PB_ATYPE(word0 >> 8) == PB_ATYPE_POINTER)
|
||||
{
|
||||
/* For pointer extensions, the pointer is stored directly
|
||||
* in the extension structure. This avoids having an extra
|
||||
* indirection. */
|
||||
status = pb_field_iter_begin(iter, msg, &extension->dest);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = pb_field_iter_begin(iter, msg, extension->dest);
|
||||
}
|
||||
|
||||
iter->pSize = &extension->found;
|
||||
return status;
|
||||
}
|
||||
|
||||
bool pb_field_iter_next(pb_field_iter_t *iter)
|
||||
{
|
||||
advance_iterator(iter);
|
||||
(void)load_descriptor_values(iter);
|
||||
return iter->index != 0;
|
||||
}
|
||||
|
||||
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag)
|
||||
{
|
||||
if (iter->tag == tag)
|
||||
{
|
||||
return true; /* Nothing to do, correct field already. */
|
||||
}
|
||||
else if (tag > iter->descriptor->largest_tag)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
pb_size_t start = iter->index;
|
||||
uint32_t fieldinfo;
|
||||
|
||||
if (tag < iter->tag)
|
||||
{
|
||||
/* Fields are in tag number order, so we know that tag is between
|
||||
* 0 and our start position. Setting index to end forces
|
||||
* advance_iterator() call below to restart from beginning. */
|
||||
iter->index = iter->descriptor->field_count;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
/* Advance iterator but don't load values yet */
|
||||
advance_iterator(iter);
|
||||
|
||||
/* Do fast check for tag number match */
|
||||
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
|
||||
|
||||
if (((fieldinfo >> 2) & 0x3F) == (tag & 0x3F))
|
||||
{
|
||||
/* Good candidate, check further */
|
||||
(void)load_descriptor_values(iter);
|
||||
|
||||
if (iter->tag == tag &&
|
||||
PB_LTYPE(iter->type) != PB_LTYPE_EXTENSION)
|
||||
{
|
||||
/* Found it */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} while (iter->index != start);
|
||||
|
||||
/* Searched all the way back to start, and found nothing. */
|
||||
(void)load_descriptor_values(iter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool pb_field_iter_find_extension(pb_field_iter_t *iter)
|
||||
{
|
||||
if (PB_LTYPE(iter->type) == PB_LTYPE_EXTENSION)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
pb_size_t start = iter->index;
|
||||
uint32_t fieldinfo;
|
||||
|
||||
do
|
||||
{
|
||||
/* Advance iterator but don't load values yet */
|
||||
advance_iterator(iter);
|
||||
|
||||
/* Do fast check for field type */
|
||||
fieldinfo = PB_PROGMEM_READU32(iter->descriptor->field_info[iter->field_info_index]);
|
||||
|
||||
if (PB_LTYPE((fieldinfo >> 8) & 0xFF) == PB_LTYPE_EXTENSION)
|
||||
{
|
||||
return load_descriptor_values(iter);
|
||||
}
|
||||
} while (iter->index != start);
|
||||
|
||||
/* Searched all the way back to start, and found nothing. */
|
||||
(void)load_descriptor_values(iter);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void *pb_const_cast(const void *p)
|
||||
{
|
||||
/* Note: this casts away const, in order to use the common field iterator
|
||||
* logic for both encoding and decoding. The cast is done using union
|
||||
* to avoid spurious compiler warnings. */
|
||||
union {
|
||||
void *p1;
|
||||
const void *p2;
|
||||
} t;
|
||||
t.p2 = p;
|
||||
return t.p1;
|
||||
}
|
||||
|
||||
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message)
|
||||
{
|
||||
return pb_field_iter_begin(iter, desc, pb_const_cast(message));
|
||||
}
|
||||
|
||||
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension)
|
||||
{
|
||||
return pb_field_iter_begin_extension(iter, (pb_extension_t*)pb_const_cast(extension));
|
||||
}
|
||||
|
||||
bool pb_default_field_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_t *field)
|
||||
{
|
||||
if (field->data_size == sizeof(pb_callback_t))
|
||||
{
|
||||
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
|
||||
|
||||
if (pCallback != NULL)
|
||||
{
|
||||
if (istream != NULL && pCallback->funcs.decode != NULL)
|
||||
{
|
||||
return pCallback->funcs.decode(istream, field, &pCallback->arg);
|
||||
}
|
||||
|
||||
if (ostream != NULL && pCallback->funcs.encode != NULL)
|
||||
{
|
||||
return pCallback->funcs.encode(ostream, field, &pCallback->arg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; /* Success, but didn't do anything */
|
||||
|
||||
}
|
||||
|
||||
#ifdef PB_VALIDATE_UTF8
|
||||
|
||||
/* This function checks whether a string is valid UTF-8 text.
|
||||
*
|
||||
* Algorithm is adapted from https://www.cl.cam.ac.uk/~mgk25/ucs/utf8_check.c
|
||||
* Original copyright: Markus Kuhn <http://www.cl.cam.ac.uk/~mgk25/> 2005-03-30
|
||||
* Licensed under "Short code license", which allows use under MIT license or
|
||||
* any compatible with it.
|
||||
*/
|
||||
|
||||
bool pb_validate_utf8(const char *str)
|
||||
{
|
||||
const pb_byte_t *s = (const pb_byte_t*)str;
|
||||
while (*s)
|
||||
{
|
||||
if (*s < 0x80)
|
||||
{
|
||||
/* 0xxxxxxx */
|
||||
s++;
|
||||
}
|
||||
else if ((s[0] & 0xe0) == 0xc0)
|
||||
{
|
||||
/* 110XXXXx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[0] & 0xfe) == 0xc0) /* overlong? */
|
||||
return false;
|
||||
else
|
||||
s += 2;
|
||||
}
|
||||
else if ((s[0] & 0xf0) == 0xe0)
|
||||
{
|
||||
/* 1110XXXX 10Xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xe0 && (s[1] & 0xe0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xed && (s[1] & 0xe0) == 0xa0) || /* surrogate? */
|
||||
(s[0] == 0xef && s[1] == 0xbf &&
|
||||
(s[2] & 0xfe) == 0xbe)) /* U+FFFE or U+FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 3;
|
||||
}
|
||||
else if ((s[0] & 0xf8) == 0xf0)
|
||||
{
|
||||
/* 11110XXX 10XXxxxx 10xxxxxx 10xxxxxx */
|
||||
if ((s[1] & 0xc0) != 0x80 ||
|
||||
(s[2] & 0xc0) != 0x80 ||
|
||||
(s[3] & 0xc0) != 0x80 ||
|
||||
(s[0] == 0xf0 && (s[1] & 0xf0) == 0x80) || /* overlong? */
|
||||
(s[0] == 0xf4 && s[1] > 0x8f) || s[0] > 0xf4) /* > U+10FFFF? */
|
||||
return false;
|
||||
else
|
||||
s += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
49
components/serial_sync/protobuf/nanopb/pb_common.h
Executable file
49
components/serial_sync/protobuf/nanopb/pb_common.h
Executable file
@@ -0,0 +1,49 @@
|
||||
/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c.
|
||||
* These functions are rarely needed by applications directly.
|
||||
*/
|
||||
|
||||
#ifndef PB_COMMON_H_INCLUDED
|
||||
#define PB_COMMON_H_INCLUDED
|
||||
|
||||
#include "pb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Initialize the field iterator structure to beginning.
|
||||
* Returns false if the message type is empty. */
|
||||
bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_msgdesc_t *desc, void *message);
|
||||
|
||||
/* Get a field iterator for extension field. */
|
||||
bool pb_field_iter_begin_extension(pb_field_iter_t *iter, pb_extension_t *extension);
|
||||
|
||||
/* Same as pb_field_iter_begin(), but for const message pointer.
|
||||
* Note that the pointers in pb_field_iter_t will be non-const but shouldn't
|
||||
* be written to when using these functions. */
|
||||
bool pb_field_iter_begin_const(pb_field_iter_t *iter, const pb_msgdesc_t *desc, const void *message);
|
||||
bool pb_field_iter_begin_extension_const(pb_field_iter_t *iter, const pb_extension_t *extension);
|
||||
|
||||
/* Advance the iterator to the next field.
|
||||
* Returns false when the iterator wraps back to the first field. */
|
||||
bool pb_field_iter_next(pb_field_iter_t *iter);
|
||||
|
||||
/* Advance the iterator until it points at a field with the given tag.
|
||||
* Returns false if no such field exists. */
|
||||
bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag);
|
||||
|
||||
/* Find a field with type PB_LTYPE_EXTENSION, or return false if not found.
|
||||
* There can be only one extension range field per message. */
|
||||
bool pb_field_iter_find_extension(pb_field_iter_t *iter);
|
||||
|
||||
#ifdef PB_VALIDATE_UTF8
|
||||
/* Validate UTF-8 text string */
|
||||
bool pb_validate_utf8(const char *s);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
1709
components/serial_sync/protobuf/nanopb/pb_decode.c
Executable file
1709
components/serial_sync/protobuf/nanopb/pb_decode.c
Executable file
File diff suppressed because it is too large
Load Diff
199
components/serial_sync/protobuf/nanopb/pb_decode.h
Executable file
199
components/serial_sync/protobuf/nanopb/pb_decode.h
Executable file
@@ -0,0 +1,199 @@
|
||||
/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c.
|
||||
* The main function is pb_decode. You also need an input stream, and the
|
||||
* field descriptions created by nanopb_generator.py.
|
||||
*/
|
||||
|
||||
#ifndef PB_DECODE_H_INCLUDED
|
||||
#define PB_DECODE_H_INCLUDED
|
||||
|
||||
#include "pb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structure for defining custom input streams. You will need to provide
|
||||
* a callback function to read the bytes from your storage, which can be
|
||||
* for example a file or a network socket.
|
||||
*
|
||||
* The callback must conform to these rules:
|
||||
*
|
||||
* 1) Return false on IO errors. This will cause decoding to abort.
|
||||
* 2) You can use state to store your own data (e.g. buffer pointer),
|
||||
* and rely on pb_read to verify that no-body reads past bytes_left.
|
||||
* 3) Your callback may be used with substreams, in which case bytes_left
|
||||
* is different than from the main stream. Don't use bytes_left to compute
|
||||
* any pointers.
|
||||
*/
|
||||
struct pb_istream_s
|
||||
{
|
||||
#ifdef PB_BUFFER_ONLY
|
||||
/* Callback pointer is not used in buffer-only configuration.
|
||||
* Having an int pointer here allows binary compatibility but
|
||||
* gives an error if someone tries to assign callback function.
|
||||
*/
|
||||
int *callback;
|
||||
#else
|
||||
bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count);
|
||||
#endif
|
||||
|
||||
void *state; /* Free field for use by callback implementation */
|
||||
size_t bytes_left;
|
||||
|
||||
#ifndef PB_NO_ERRMSG
|
||||
const char *errmsg;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef PB_NO_ERRMSG
|
||||
#define PB_ISTREAM_EMPTY {0,0,0,0}
|
||||
#else
|
||||
#define PB_ISTREAM_EMPTY {0,0,0}
|
||||
#endif
|
||||
|
||||
/***************************
|
||||
* Main decoding functions *
|
||||
***************************/
|
||||
|
||||
/* Decode a single protocol buffers message from input stream into a C structure.
|
||||
* Returns true on success, false on any failure.
|
||||
* The actual struct pointed to by dest must match the description in fields.
|
||||
* Callback fields of the destination structure must be initialized by caller.
|
||||
* All other fields will be initialized by this function.
|
||||
*
|
||||
* Example usage:
|
||||
* MyMessage msg = {};
|
||||
* uint8_t buffer[64];
|
||||
* pb_istream_t stream;
|
||||
*
|
||||
* // ... read some data into buffer ...
|
||||
*
|
||||
* stream = pb_istream_from_buffer(buffer, count);
|
||||
* pb_decode(&stream, MyMessage_fields, &msg);
|
||||
*/
|
||||
bool pb_decode(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct);
|
||||
|
||||
/* Extended version of pb_decode, with several options to control
|
||||
* the decoding process:
|
||||
*
|
||||
* PB_DECODE_NOINIT: Do not initialize the fields to default values.
|
||||
* This is slightly faster if you do not need the default
|
||||
* values and instead initialize the structure to 0 using
|
||||
* e.g. memset(). This can also be used for merging two
|
||||
* messages, i.e. combine already existing data with new
|
||||
* values.
|
||||
*
|
||||
* PB_DECODE_DELIMITED: Input message starts with the message size as varint.
|
||||
* Corresponds to parseDelimitedFrom() in Google's
|
||||
* protobuf API.
|
||||
*
|
||||
* PB_DECODE_NULLTERMINATED: Stop reading when field tag is read as 0. This allows
|
||||
* reading null terminated messages.
|
||||
* NOTE: Until nanopb-0.4.0, pb_decode() also allows
|
||||
* null-termination. This behaviour is not supported in
|
||||
* most other protobuf implementations, so PB_DECODE_DELIMITED
|
||||
* is a better option for compatibility.
|
||||
*
|
||||
* Multiple flags can be combined with bitwise or (| operator)
|
||||
*/
|
||||
#define PB_DECODE_NOINIT 0x01U
|
||||
#define PB_DECODE_DELIMITED 0x02U
|
||||
#define PB_DECODE_NULLTERMINATED 0x04U
|
||||
bool pb_decode_ex(pb_istream_t *stream, const pb_msgdesc_t *fields, void *dest_struct, unsigned int flags);
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define pb_decode_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NOINIT)
|
||||
#define pb_decode_delimited(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED)
|
||||
#define pb_decode_delimited_noinit(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_DELIMITED | PB_DECODE_NOINIT)
|
||||
#define pb_decode_nullterminated(s,f,d) pb_decode_ex(s,f,d, PB_DECODE_NULLTERMINATED)
|
||||
|
||||
#ifdef PB_ENABLE_MALLOC
|
||||
/* Release any allocated pointer fields. If you use dynamic allocation, you should
|
||||
* call this for any successfully decoded message when you are done with it. If
|
||||
* pb_decode() returns with an error, the message is already released.
|
||||
*/
|
||||
void pb_release(const pb_msgdesc_t *fields, void *dest_struct);
|
||||
#else
|
||||
/* Allocation is not supported, so release is no-op */
|
||||
#define pb_release(fields, dest_struct) PB_UNUSED(fields); PB_UNUSED(dest_struct);
|
||||
#endif
|
||||
|
||||
|
||||
/**************************************
|
||||
* Functions for manipulating streams *
|
||||
**************************************/
|
||||
|
||||
/* Create an input stream for reading from a memory buffer.
|
||||
*
|
||||
* msglen should be the actual length of the message, not the full size of
|
||||
* allocated buffer.
|
||||
*
|
||||
* Alternatively, you can use a custom stream that reads directly from e.g.
|
||||
* a file or a network socket.
|
||||
*/
|
||||
pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t msglen);
|
||||
|
||||
/* Function to read from a pb_istream_t. You can use this if you need to
|
||||
* read some custom header data, or to read data in field callbacks.
|
||||
*/
|
||||
bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count);
|
||||
|
||||
|
||||
/************************************************
|
||||
* Helper functions for writing field callbacks *
|
||||
************************************************/
|
||||
|
||||
/* Decode the tag for the next field in the stream. Gives the wire type and
|
||||
* field tag. At end of the message, returns false and sets eof to true. */
|
||||
bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof);
|
||||
|
||||
/* Skip the field payload data, given the wire type. */
|
||||
bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type);
|
||||
|
||||
/* Decode an integer in the varint format. This works for enum, int32,
|
||||
* int64, uint32 and uint64 field types. */
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest);
|
||||
#else
|
||||
#define pb_decode_varint pb_decode_varint32
|
||||
#endif
|
||||
|
||||
/* Decode an integer in the varint format. This works for enum, int32,
|
||||
* and uint32 field types. */
|
||||
bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest);
|
||||
|
||||
/* Decode a bool value in varint format. */
|
||||
bool pb_decode_bool(pb_istream_t *stream, bool *dest);
|
||||
|
||||
/* Decode an integer in the zig-zagged svarint format. This works for sint32
|
||||
* and sint64. */
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest);
|
||||
#else
|
||||
bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest);
|
||||
#endif
|
||||
|
||||
/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to
|
||||
* a 4-byte wide C variable. */
|
||||
bool pb_decode_fixed32(pb_istream_t *stream, void *dest);
|
||||
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to
|
||||
* a 8-byte wide C variable. */
|
||||
bool pb_decode_fixed64(pb_istream_t *stream, void *dest);
|
||||
#endif
|
||||
|
||||
#ifdef PB_CONVERT_DOUBLE_FLOAT
|
||||
/* Decode a double value into float variable. */
|
||||
bool pb_decode_double_as_float(pb_istream_t *stream, float *dest);
|
||||
#endif
|
||||
|
||||
/* Make a limited-length substream for reading a PB_WT_STRING field. */
|
||||
bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream);
|
||||
bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
987
components/serial_sync/protobuf/nanopb/pb_encode.c
Executable file
987
components/serial_sync/protobuf/nanopb/pb_encode.c
Executable file
@@ -0,0 +1,987 @@
|
||||
/* pb_encode.c -- encode a protobuf using minimal resources
|
||||
*
|
||||
* 2011 Petteri Aimonen <jpa@kapsi.fi>
|
||||
*/
|
||||
|
||||
#include "pb.h"
|
||||
#include "pb_encode.h"
|
||||
#include "pb_common.h"
|
||||
|
||||
/* Use the GCC warn_unused_result attribute to check that all return values
|
||||
* are propagated correctly. On other compilers and gcc before 3.4.0 just
|
||||
* ignore the annotation.
|
||||
*/
|
||||
#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
|
||||
#define checkreturn
|
||||
#else
|
||||
#define checkreturn __attribute__((warn_unused_result))
|
||||
#endif
|
||||
|
||||
/**************************************
|
||||
* Declarations internal to this file *
|
||||
**************************************/
|
||||
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
|
||||
static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field);
|
||||
static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field);
|
||||
static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field);
|
||||
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension);
|
||||
static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high);
|
||||
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
|
||||
#ifdef PB_WITHOUT_64BIT
|
||||
#define pb_int64_t int32_t
|
||||
#define pb_uint64_t uint32_t
|
||||
#else
|
||||
#define pb_int64_t int64_t
|
||||
#define pb_uint64_t uint64_t
|
||||
#endif
|
||||
|
||||
/*******************************
|
||||
* pb_ostream_t implementation *
|
||||
*******************************/
|
||||
|
||||
static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
|
||||
{
|
||||
size_t i;
|
||||
pb_byte_t *dest = (pb_byte_t*)stream->state;
|
||||
stream->state = dest + count;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
dest[i] = buf[i];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize)
|
||||
{
|
||||
pb_ostream_t stream;
|
||||
#ifdef PB_BUFFER_ONLY
|
||||
stream.callback = (void*)1; /* Just a marker value */
|
||||
#else
|
||||
stream.callback = &buf_write;
|
||||
#endif
|
||||
stream.state = buf;
|
||||
stream.max_size = bufsize;
|
||||
stream.bytes_written = 0;
|
||||
#ifndef PB_NO_ERRMSG
|
||||
stream.errmsg = NULL;
|
||||
#endif
|
||||
return stream;
|
||||
}
|
||||
|
||||
bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count)
|
||||
{
|
||||
if (count > 0 && stream->callback != NULL)
|
||||
{
|
||||
if (stream->bytes_written + count < stream->bytes_written ||
|
||||
stream->bytes_written + count > stream->max_size)
|
||||
{
|
||||
PB_RETURN_ERROR(stream, "stream full");
|
||||
}
|
||||
|
||||
#ifdef PB_BUFFER_ONLY
|
||||
if (!buf_write(stream, buf, count))
|
||||
PB_RETURN_ERROR(stream, "io error");
|
||||
#else
|
||||
if (!stream->callback(stream, buf, count))
|
||||
PB_RETURN_ERROR(stream, "io error");
|
||||
#endif
|
||||
}
|
||||
|
||||
stream->bytes_written += count;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Encode a single field *
|
||||
*************************/
|
||||
|
||||
/* Read a bool value without causing undefined behavior even if the value
|
||||
* is invalid. See issue #434 and
|
||||
* https://stackoverflow.com/questions/27661768/weird-results-for-conditional
|
||||
*/
|
||||
static bool safe_read_bool(const void *pSize)
|
||||
{
|
||||
const char *p = (const char *)pSize;
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(bool); i++)
|
||||
{
|
||||
if (p[i] != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Encode a static array. Handles the size calculations and possible packing. */
|
||||
static bool checkreturn encode_array(pb_ostream_t *stream, pb_field_iter_t *field)
|
||||
{
|
||||
pb_size_t i;
|
||||
pb_size_t count;
|
||||
#ifndef PB_ENCODE_ARRAYS_UNPACKED
|
||||
size_t size;
|
||||
#endif
|
||||
|
||||
count = *(pb_size_t*)field->pSize;
|
||||
|
||||
if (count == 0)
|
||||
return true;
|
||||
|
||||
if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size)
|
||||
PB_RETURN_ERROR(stream, "array max size exceeded");
|
||||
|
||||
#ifndef PB_ENCODE_ARRAYS_UNPACKED
|
||||
/* We always pack arrays if the datatype allows it. */
|
||||
if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE)
|
||||
{
|
||||
if (!pb_encode_tag(stream, PB_WT_STRING, field->tag))
|
||||
return false;
|
||||
|
||||
/* Determine the total size of packed array. */
|
||||
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32)
|
||||
{
|
||||
size = 4 * (size_t)count;
|
||||
}
|
||||
else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
|
||||
{
|
||||
size = 8 * (size_t)count;
|
||||
}
|
||||
else
|
||||
{
|
||||
pb_ostream_t sizestream = PB_OSTREAM_SIZING;
|
||||
void *pData_orig = field->pData;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (!pb_enc_varint(&sizestream, field))
|
||||
PB_RETURN_ERROR(stream, PB_GET_ERROR(&sizestream));
|
||||
field->pData = (char*)field->pData + field->data_size;
|
||||
}
|
||||
field->pData = pData_orig;
|
||||
size = sizestream.bytes_written;
|
||||
}
|
||||
|
||||
if (!pb_encode_varint(stream, (pb_uint64_t)size))
|
||||
return false;
|
||||
|
||||
if (stream->callback == NULL)
|
||||
return pb_write(stream, NULL, size); /* Just sizing.. */
|
||||
|
||||
/* Write the data */
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32 || PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
|
||||
{
|
||||
if (!pb_enc_fixed(stream, field))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!pb_enc_varint(stream, field))
|
||||
return false;
|
||||
}
|
||||
|
||||
field->pData = (char*)field->pData + field->data_size;
|
||||
}
|
||||
}
|
||||
else /* Unpacked fields */
|
||||
#endif
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
/* Normally the data is stored directly in the array entries, but
|
||||
* for pointer-type string and bytes fields, the array entries are
|
||||
* actually pointers themselves also. So we have to dereference once
|
||||
* more to get to the actual data. */
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER &&
|
||||
(PB_LTYPE(field->type) == PB_LTYPE_STRING ||
|
||||
PB_LTYPE(field->type) == PB_LTYPE_BYTES))
|
||||
{
|
||||
bool status;
|
||||
void *pData_orig = field->pData;
|
||||
field->pData = *(void* const*)field->pData;
|
||||
|
||||
if (!field->pData)
|
||||
{
|
||||
/* Null pointer in array is treated as empty string / bytes */
|
||||
status = pb_encode_tag_for_field(stream, field) &&
|
||||
pb_encode_varint(stream, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = encode_basic_field(stream, field);
|
||||
}
|
||||
|
||||
field->pData = pData_orig;
|
||||
|
||||
if (!status)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!encode_basic_field(stream, field))
|
||||
return false;
|
||||
}
|
||||
field->pData = (char*)field->pData + field->data_size;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* In proto3, all fields are optional and are only encoded if their value is "non-zero".
|
||||
* This function implements the check for the zero value. */
|
||||
static bool checkreturn pb_check_proto3_default_value(const pb_field_iter_t *field)
|
||||
{
|
||||
pb_type_t type = field->type;
|
||||
|
||||
if (PB_ATYPE(type) == PB_ATYPE_STATIC)
|
||||
{
|
||||
if (PB_HTYPE(type) == PB_HTYPE_REQUIRED)
|
||||
{
|
||||
/* Required proto2 fields inside proto3 submessage, pretty rare case */
|
||||
return false;
|
||||
}
|
||||
else if (PB_HTYPE(type) == PB_HTYPE_REPEATED)
|
||||
{
|
||||
/* Repeated fields inside proto3 submessage: present if count != 0 */
|
||||
return *(const pb_size_t*)field->pSize == 0;
|
||||
}
|
||||
else if (PB_HTYPE(type) == PB_HTYPE_ONEOF)
|
||||
{
|
||||
/* Oneof fields */
|
||||
return *(const pb_size_t*)field->pSize == 0;
|
||||
}
|
||||
else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->pSize != NULL)
|
||||
{
|
||||
/* Proto2 optional fields inside proto3 message, or proto3
|
||||
* submessage fields. */
|
||||
return safe_read_bool(field->pSize) == false;
|
||||
}
|
||||
else if (field->descriptor->default_value)
|
||||
{
|
||||
/* Proto3 messages do not have default values, but proto2 messages
|
||||
* can contain optional fields without has_fields (generator option 'proto3').
|
||||
* In this case they must always be encoded, to make sure that the
|
||||
* non-zero default value is overwritten.
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Rest is proto3 singular fields */
|
||||
if (PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE)
|
||||
{
|
||||
/* Simple integer / float fields */
|
||||
pb_size_t i;
|
||||
const char *p = (const char*)field->pData;
|
||||
for (i = 0; i < field->data_size; i++)
|
||||
{
|
||||
if (p[i] != 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (PB_LTYPE(type) == PB_LTYPE_BYTES)
|
||||
{
|
||||
const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)field->pData;
|
||||
return bytes->size == 0;
|
||||
}
|
||||
else if (PB_LTYPE(type) == PB_LTYPE_STRING)
|
||||
{
|
||||
return *(const char*)field->pData == '\0';
|
||||
}
|
||||
else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES)
|
||||
{
|
||||
/* Fixed length bytes is only empty if its length is fixed
|
||||
* as 0. Which would be pretty strange, but we can check
|
||||
* it anyway. */
|
||||
return field->data_size == 0;
|
||||
}
|
||||
else if (PB_LTYPE_IS_SUBMSG(type))
|
||||
{
|
||||
/* Check all fields in the submessage to find if any of them
|
||||
* are non-zero. The comparison cannot be done byte-per-byte
|
||||
* because the C struct may contain padding bytes that must
|
||||
* be skipped. Note that usually proto3 submessages have
|
||||
* a separate has_field that is checked earlier in this if.
|
||||
*/
|
||||
pb_field_iter_t iter;
|
||||
if (pb_field_iter_begin(&iter, field->submsg_desc, field->pData))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (!pb_check_proto3_default_value(&iter))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (pb_field_iter_next(&iter));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (PB_ATYPE(type) == PB_ATYPE_POINTER)
|
||||
{
|
||||
return field->pData == NULL;
|
||||
}
|
||||
else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK)
|
||||
{
|
||||
if (PB_LTYPE(type) == PB_LTYPE_EXTENSION)
|
||||
{
|
||||
const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
|
||||
return extension == NULL;
|
||||
}
|
||||
else if (field->descriptor->field_callback == pb_default_field_callback)
|
||||
{
|
||||
pb_callback_t *pCallback = (pb_callback_t*)field->pData;
|
||||
return pCallback->funcs.encode == NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return field->descriptor->field_callback == NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return false; /* Not typically reached, safe default for weird special cases. */
|
||||
}
|
||||
|
||||
/* Encode a field with static or pointer allocation, i.e. one whose data
|
||||
* is available to the encoder directly. */
|
||||
static bool checkreturn encode_basic_field(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (!field->pData)
|
||||
{
|
||||
/* Missing pointer field */
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!pb_encode_tag_for_field(stream, field))
|
||||
return false;
|
||||
|
||||
switch (PB_LTYPE(field->type))
|
||||
{
|
||||
case PB_LTYPE_BOOL:
|
||||
return pb_enc_bool(stream, field);
|
||||
|
||||
case PB_LTYPE_VARINT:
|
||||
case PB_LTYPE_UVARINT:
|
||||
case PB_LTYPE_SVARINT:
|
||||
return pb_enc_varint(stream, field);
|
||||
|
||||
case PB_LTYPE_FIXED32:
|
||||
case PB_LTYPE_FIXED64:
|
||||
return pb_enc_fixed(stream, field);
|
||||
|
||||
case PB_LTYPE_BYTES:
|
||||
return pb_enc_bytes(stream, field);
|
||||
|
||||
case PB_LTYPE_STRING:
|
||||
return pb_enc_string(stream, field);
|
||||
|
||||
case PB_LTYPE_SUBMESSAGE:
|
||||
case PB_LTYPE_SUBMSG_W_CB:
|
||||
return pb_enc_submessage(stream, field);
|
||||
|
||||
case PB_LTYPE_FIXED_LENGTH_BYTES:
|
||||
return pb_enc_fixed_length_bytes(stream, field);
|
||||
|
||||
default:
|
||||
PB_RETURN_ERROR(stream, "invalid field type");
|
||||
}
|
||||
}
|
||||
|
||||
/* Encode a field with callback semantics. This means that a user function is
|
||||
* called to provide and encode the actual data. */
|
||||
static bool checkreturn encode_callback_field(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (field->descriptor->field_callback != NULL)
|
||||
{
|
||||
if (!field->descriptor->field_callback(NULL, stream, field))
|
||||
PB_RETURN_ERROR(stream, "callback error");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Encode a single field of any callback, pointer or static type. */
|
||||
static bool checkreturn encode_field(pb_ostream_t *stream, pb_field_iter_t *field)
|
||||
{
|
||||
/* Check field presence */
|
||||
if (PB_HTYPE(field->type) == PB_HTYPE_ONEOF)
|
||||
{
|
||||
if (*(const pb_size_t*)field->pSize != field->tag)
|
||||
{
|
||||
/* Different type oneof field */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL)
|
||||
{
|
||||
if (field->pSize)
|
||||
{
|
||||
if (safe_read_bool(field->pSize) == false)
|
||||
{
|
||||
/* Missing optional field */
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (PB_ATYPE(field->type) == PB_ATYPE_STATIC)
|
||||
{
|
||||
/* Proto3 singular field */
|
||||
if (pb_check_proto3_default_value(field))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!field->pData)
|
||||
{
|
||||
if (PB_HTYPE(field->type) == PB_HTYPE_REQUIRED)
|
||||
PB_RETURN_ERROR(stream, "missing required field");
|
||||
|
||||
/* Pointer field set to NULL */
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Then encode field contents */
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_CALLBACK)
|
||||
{
|
||||
return encode_callback_field(stream, field);
|
||||
}
|
||||
else if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED)
|
||||
{
|
||||
return encode_array(stream, field);
|
||||
}
|
||||
else
|
||||
{
|
||||
return encode_basic_field(stream, field);
|
||||
}
|
||||
}
|
||||
|
||||
/* Default handler for extension fields. Expects to have a pb_msgdesc_t
|
||||
* pointer in the extension->type->arg field, pointing to a message with
|
||||
* only one field in it. */
|
||||
static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension)
|
||||
{
|
||||
pb_field_iter_t iter;
|
||||
|
||||
if (!pb_field_iter_begin_extension_const(&iter, extension))
|
||||
PB_RETURN_ERROR(stream, "invalid extension");
|
||||
|
||||
return encode_field(stream, &iter);
|
||||
}
|
||||
|
||||
|
||||
/* Walk through all the registered extensions and give them a chance
|
||||
* to encode themselves. */
|
||||
static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
const pb_extension_t *extension = *(const pb_extension_t* const *)field->pData;
|
||||
|
||||
while (extension)
|
||||
{
|
||||
bool status;
|
||||
if (extension->type->encode)
|
||||
status = extension->type->encode(stream, extension);
|
||||
else
|
||||
status = default_extension_encoder(stream, extension);
|
||||
|
||||
if (!status)
|
||||
return false;
|
||||
|
||||
extension = extension->next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*********************
|
||||
* Encode all fields *
|
||||
*********************/
|
||||
|
||||
bool checkreturn pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
|
||||
{
|
||||
pb_field_iter_t iter;
|
||||
if (!pb_field_iter_begin_const(&iter, fields, src_struct))
|
||||
return true; /* Empty message type */
|
||||
|
||||
do {
|
||||
if (PB_LTYPE(iter.type) == PB_LTYPE_EXTENSION)
|
||||
{
|
||||
/* Special case for the extension field placeholder */
|
||||
if (!encode_extension_field(stream, &iter))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Regular field */
|
||||
if (!encode_field(stream, &iter))
|
||||
return false;
|
||||
}
|
||||
} while (pb_field_iter_next(&iter));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags)
|
||||
{
|
||||
if ((flags & PB_ENCODE_DELIMITED) != 0)
|
||||
{
|
||||
return pb_encode_submessage(stream, fields, src_struct);
|
||||
}
|
||||
else if ((flags & PB_ENCODE_NULLTERMINATED) != 0)
|
||||
{
|
||||
const pb_byte_t zero = 0;
|
||||
|
||||
if (!pb_encode(stream, fields, src_struct))
|
||||
return false;
|
||||
|
||||
return pb_write(stream, &zero, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return pb_encode(stream, fields, src_struct);
|
||||
}
|
||||
}
|
||||
|
||||
bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct)
|
||||
{
|
||||
pb_ostream_t stream = PB_OSTREAM_SIZING;
|
||||
|
||||
if (!pb_encode(&stream, fields, src_struct))
|
||||
return false;
|
||||
|
||||
*size = stream.bytes_written;
|
||||
return true;
|
||||
}
|
||||
|
||||
/********************
|
||||
* Helper functions *
|
||||
********************/
|
||||
|
||||
/* This function avoids 64-bit shifts as they are quite slow on many platforms. */
|
||||
static bool checkreturn pb_encode_varint_32(pb_ostream_t *stream, uint32_t low, uint32_t high)
|
||||
{
|
||||
size_t i = 0;
|
||||
pb_byte_t buffer[10];
|
||||
pb_byte_t byte = (pb_byte_t)(low & 0x7F);
|
||||
low >>= 7;
|
||||
|
||||
while (i < 4 && (low != 0 || high != 0))
|
||||
{
|
||||
byte |= 0x80;
|
||||
buffer[i++] = byte;
|
||||
byte = (pb_byte_t)(low & 0x7F);
|
||||
low >>= 7;
|
||||
}
|
||||
|
||||
if (high)
|
||||
{
|
||||
byte = (pb_byte_t)(byte | ((high & 0x07) << 4));
|
||||
high >>= 3;
|
||||
|
||||
while (high)
|
||||
{
|
||||
byte |= 0x80;
|
||||
buffer[i++] = byte;
|
||||
byte = (pb_byte_t)(high & 0x7F);
|
||||
high >>= 7;
|
||||
}
|
||||
}
|
||||
|
||||
buffer[i++] = byte;
|
||||
|
||||
return pb_write(stream, buffer, i);
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value)
|
||||
{
|
||||
if (value <= 0x7F)
|
||||
{
|
||||
/* Fast path: single byte */
|
||||
pb_byte_t byte = (pb_byte_t)value;
|
||||
return pb_write(stream, &byte, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef PB_WITHOUT_64BIT
|
||||
return pb_encode_varint_32(stream, value, 0);
|
||||
#else
|
||||
return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)(value >> 32));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value)
|
||||
{
|
||||
pb_uint64_t zigzagged;
|
||||
if (value < 0)
|
||||
zigzagged = ~((pb_uint64_t)value << 1);
|
||||
else
|
||||
zigzagged = (pb_uint64_t)value << 1;
|
||||
|
||||
return pb_encode_varint(stream, zigzagged);
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value)
|
||||
{
|
||||
uint32_t val = *(const uint32_t*)value;
|
||||
pb_byte_t bytes[4];
|
||||
bytes[0] = (pb_byte_t)(val & 0xFF);
|
||||
bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
|
||||
bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
|
||||
bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
|
||||
return pb_write(stream, bytes, 4);
|
||||
}
|
||||
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value)
|
||||
{
|
||||
uint64_t val = *(const uint64_t*)value;
|
||||
pb_byte_t bytes[8];
|
||||
bytes[0] = (pb_byte_t)(val & 0xFF);
|
||||
bytes[1] = (pb_byte_t)((val >> 8) & 0xFF);
|
||||
bytes[2] = (pb_byte_t)((val >> 16) & 0xFF);
|
||||
bytes[3] = (pb_byte_t)((val >> 24) & 0xFF);
|
||||
bytes[4] = (pb_byte_t)((val >> 32) & 0xFF);
|
||||
bytes[5] = (pb_byte_t)((val >> 40) & 0xFF);
|
||||
bytes[6] = (pb_byte_t)((val >> 48) & 0xFF);
|
||||
bytes[7] = (pb_byte_t)((val >> 56) & 0xFF);
|
||||
return pb_write(stream, bytes, 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number)
|
||||
{
|
||||
pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype;
|
||||
return pb_encode_varint(stream, tag);
|
||||
}
|
||||
|
||||
bool pb_encode_tag_for_field ( pb_ostream_t* stream, const pb_field_iter_t* field )
|
||||
{
|
||||
pb_wire_type_t wiretype;
|
||||
switch (PB_LTYPE(field->type))
|
||||
{
|
||||
case PB_LTYPE_BOOL:
|
||||
case PB_LTYPE_VARINT:
|
||||
case PB_LTYPE_UVARINT:
|
||||
case PB_LTYPE_SVARINT:
|
||||
wiretype = PB_WT_VARINT;
|
||||
break;
|
||||
|
||||
case PB_LTYPE_FIXED32:
|
||||
wiretype = PB_WT_32BIT;
|
||||
break;
|
||||
|
||||
case PB_LTYPE_FIXED64:
|
||||
wiretype = PB_WT_64BIT;
|
||||
break;
|
||||
|
||||
case PB_LTYPE_BYTES:
|
||||
case PB_LTYPE_STRING:
|
||||
case PB_LTYPE_SUBMESSAGE:
|
||||
case PB_LTYPE_SUBMSG_W_CB:
|
||||
case PB_LTYPE_FIXED_LENGTH_BYTES:
|
||||
wiretype = PB_WT_STRING;
|
||||
break;
|
||||
|
||||
default:
|
||||
PB_RETURN_ERROR(stream, "invalid field type");
|
||||
}
|
||||
|
||||
return pb_encode_tag(stream, wiretype, field->tag);
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size)
|
||||
{
|
||||
if (!pb_encode_varint(stream, (pb_uint64_t)size))
|
||||
return false;
|
||||
|
||||
return pb_write(stream, buffer, size);
|
||||
}
|
||||
|
||||
bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct)
|
||||
{
|
||||
/* First calculate the message size using a non-writing substream. */
|
||||
pb_ostream_t substream = PB_OSTREAM_SIZING;
|
||||
size_t size;
|
||||
bool status;
|
||||
|
||||
if (!pb_encode(&substream, fields, src_struct))
|
||||
{
|
||||
#ifndef PB_NO_ERRMSG
|
||||
stream->errmsg = substream.errmsg;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
size = substream.bytes_written;
|
||||
|
||||
if (!pb_encode_varint(stream, (pb_uint64_t)size))
|
||||
return false;
|
||||
|
||||
if (stream->callback == NULL)
|
||||
return pb_write(stream, NULL, size); /* Just sizing */
|
||||
|
||||
if (stream->bytes_written + size > stream->max_size)
|
||||
PB_RETURN_ERROR(stream, "stream full");
|
||||
|
||||
/* Use a substream to verify that a callback doesn't write more than
|
||||
* what it did the first time. */
|
||||
substream.callback = stream->callback;
|
||||
substream.state = stream->state;
|
||||
substream.max_size = size;
|
||||
substream.bytes_written = 0;
|
||||
#ifndef PB_NO_ERRMSG
|
||||
substream.errmsg = NULL;
|
||||
#endif
|
||||
|
||||
status = pb_encode(&substream, fields, src_struct);
|
||||
|
||||
stream->bytes_written += substream.bytes_written;
|
||||
stream->state = substream.state;
|
||||
#ifndef PB_NO_ERRMSG
|
||||
stream->errmsg = substream.errmsg;
|
||||
#endif
|
||||
|
||||
if (substream.bytes_written != size)
|
||||
PB_RETURN_ERROR(stream, "submsg size changed");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Field encoders */
|
||||
|
||||
static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
uint32_t value = safe_read_bool(field->pData) ? 1 : 0;
|
||||
PB_UNUSED(field);
|
||||
return pb_encode_varint(stream, value);
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (PB_LTYPE(field->type) == PB_LTYPE_UVARINT)
|
||||
{
|
||||
/* Perform unsigned integer extension */
|
||||
pb_uint64_t value = 0;
|
||||
|
||||
if (field->data_size == sizeof(uint_least8_t))
|
||||
value = *(const uint_least8_t*)field->pData;
|
||||
else if (field->data_size == sizeof(uint_least16_t))
|
||||
value = *(const uint_least16_t*)field->pData;
|
||||
else if (field->data_size == sizeof(uint32_t))
|
||||
value = *(const uint32_t*)field->pData;
|
||||
else if (field->data_size == sizeof(pb_uint64_t))
|
||||
value = *(const pb_uint64_t*)field->pData;
|
||||
else
|
||||
PB_RETURN_ERROR(stream, "invalid data_size");
|
||||
|
||||
return pb_encode_varint(stream, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Perform signed integer extension */
|
||||
pb_int64_t value = 0;
|
||||
|
||||
if (field->data_size == sizeof(int_least8_t))
|
||||
value = *(const int_least8_t*)field->pData;
|
||||
else if (field->data_size == sizeof(int_least16_t))
|
||||
value = *(const int_least16_t*)field->pData;
|
||||
else if (field->data_size == sizeof(int32_t))
|
||||
value = *(const int32_t*)field->pData;
|
||||
else if (field->data_size == sizeof(pb_int64_t))
|
||||
value = *(const pb_int64_t*)field->pData;
|
||||
else
|
||||
PB_RETURN_ERROR(stream, "invalid data_size");
|
||||
|
||||
if (PB_LTYPE(field->type) == PB_LTYPE_SVARINT)
|
||||
return pb_encode_svarint(stream, value);
|
||||
#ifdef PB_WITHOUT_64BIT
|
||||
else if (value < 0)
|
||||
return pb_encode_varint_32(stream, (uint32_t)value, (uint32_t)-1);
|
||||
#endif
|
||||
else
|
||||
return pb_encode_varint(stream, (pb_uint64_t)value);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_fixed(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
#ifdef PB_CONVERT_DOUBLE_FLOAT
|
||||
if (field->data_size == sizeof(float) && PB_LTYPE(field->type) == PB_LTYPE_FIXED64)
|
||||
{
|
||||
return pb_encode_float_as_double(stream, *(float*)field->pData);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (field->data_size == sizeof(uint32_t))
|
||||
{
|
||||
return pb_encode_fixed32(stream, field->pData);
|
||||
}
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
else if (field->data_size == sizeof(uint64_t))
|
||||
{
|
||||
return pb_encode_fixed64(stream, field->pData);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
PB_RETURN_ERROR(stream, "invalid data_size");
|
||||
}
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
const pb_bytes_array_t *bytes = NULL;
|
||||
|
||||
bytes = (const pb_bytes_array_t*)field->pData;
|
||||
|
||||
if (bytes == NULL)
|
||||
{
|
||||
/* Treat null pointer as an empty bytes field */
|
||||
return pb_encode_string(stream, NULL, 0);
|
||||
}
|
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_STATIC &&
|
||||
bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes))
|
||||
{
|
||||
PB_RETURN_ERROR(stream, "bytes size exceeded");
|
||||
}
|
||||
|
||||
return pb_encode_string(stream, bytes->bytes, (size_t)bytes->size);
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
size_t size = 0;
|
||||
size_t max_size = (size_t)field->data_size;
|
||||
const char *str = (const char*)field->pData;
|
||||
|
||||
if (PB_ATYPE(field->type) == PB_ATYPE_POINTER)
|
||||
{
|
||||
max_size = (size_t)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pb_dec_string() assumes string fields end with a null
|
||||
* terminator when the type isn't PB_ATYPE_POINTER, so we
|
||||
* shouldn't allow more than max-1 bytes to be written to
|
||||
* allow space for the null terminator.
|
||||
*/
|
||||
if (max_size == 0)
|
||||
PB_RETURN_ERROR(stream, "zero-length string");
|
||||
|
||||
max_size -= 1;
|
||||
}
|
||||
|
||||
|
||||
if (str == NULL)
|
||||
{
|
||||
size = 0; /* Treat null pointer as an empty string */
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *p = str;
|
||||
|
||||
/* strnlen() is not always available, so just use a loop */
|
||||
while (size < max_size && *p != '\0')
|
||||
{
|
||||
size++;
|
||||
p++;
|
||||
}
|
||||
|
||||
if (*p != '\0')
|
||||
{
|
||||
PB_RETURN_ERROR(stream, "unterminated string");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PB_VALIDATE_UTF8
|
||||
if (!pb_validate_utf8(str))
|
||||
PB_RETURN_ERROR(stream, "invalid utf8");
|
||||
#endif
|
||||
|
||||
return pb_encode_string(stream, (const pb_byte_t*)str, size);
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
if (field->submsg_desc == NULL)
|
||||
PB_RETURN_ERROR(stream, "invalid field descriptor");
|
||||
|
||||
if (PB_LTYPE(field->type) == PB_LTYPE_SUBMSG_W_CB && field->pSize != NULL)
|
||||
{
|
||||
/* Message callback is stored right before pSize. */
|
||||
pb_callback_t *callback = (pb_callback_t*)field->pSize - 1;
|
||||
if (callback->funcs.encode)
|
||||
{
|
||||
if (!callback->funcs.encode(stream, field, &callback->arg))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return pb_encode_submessage(stream, field->submsg_desc, field->pData);
|
||||
}
|
||||
|
||||
static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_iter_t *field)
|
||||
{
|
||||
return pb_encode_string(stream, (const pb_byte_t*)field->pData, (size_t)field->data_size);
|
||||
}
|
||||
|
||||
#ifdef PB_CONVERT_DOUBLE_FLOAT
|
||||
bool pb_encode_float_as_double(pb_ostream_t *stream, float value)
|
||||
{
|
||||
union { float f; uint32_t i; } in;
|
||||
uint_least8_t sign;
|
||||
int exponent;
|
||||
uint64_t mantissa;
|
||||
|
||||
in.f = value;
|
||||
|
||||
/* Decompose input value */
|
||||
sign = (uint_least8_t)((in.i >> 31) & 1);
|
||||
exponent = (int)((in.i >> 23) & 0xFF) - 127;
|
||||
mantissa = in.i & 0x7FFFFF;
|
||||
|
||||
if (exponent == 128)
|
||||
{
|
||||
/* Special value (NaN etc.) */
|
||||
exponent = 1024;
|
||||
}
|
||||
else if (exponent == -127)
|
||||
{
|
||||
if (!mantissa)
|
||||
{
|
||||
/* Zero */
|
||||
exponent = -1023;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Denormalized */
|
||||
mantissa <<= 1;
|
||||
while (!(mantissa & 0x800000))
|
||||
{
|
||||
mantissa <<= 1;
|
||||
exponent--;
|
||||
}
|
||||
mantissa &= 0x7FFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* Combine fields */
|
||||
mantissa <<= 29;
|
||||
mantissa |= (uint64_t)(exponent + 1023) << 52;
|
||||
mantissa |= (uint64_t)sign << 63;
|
||||
|
||||
return pb_encode_fixed64(stream, &mantissa);
|
||||
}
|
||||
#endif
|
||||
185
components/serial_sync/protobuf/nanopb/pb_encode.h
Executable file
185
components/serial_sync/protobuf/nanopb/pb_encode.h
Executable file
@@ -0,0 +1,185 @@
|
||||
/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c.
|
||||
* The main function is pb_encode. You also need an output stream, and the
|
||||
* field descriptions created by nanopb_generator.py.
|
||||
*/
|
||||
|
||||
#ifndef PB_ENCODE_H_INCLUDED
|
||||
#define PB_ENCODE_H_INCLUDED
|
||||
|
||||
#include "pb.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Structure for defining custom output streams. You will need to provide
|
||||
* a callback function to write the bytes to your storage, which can be
|
||||
* for example a file or a network socket.
|
||||
*
|
||||
* The callback must conform to these rules:
|
||||
*
|
||||
* 1) Return false on IO errors. This will cause encoding to abort.
|
||||
* 2) You can use state to store your own data (e.g. buffer pointer).
|
||||
* 3) pb_write will update bytes_written after your callback runs.
|
||||
* 4) Substreams will modify max_size and bytes_written. Don't use them
|
||||
* to calculate any pointers.
|
||||
*/
|
||||
struct pb_ostream_s
|
||||
{
|
||||
#ifdef PB_BUFFER_ONLY
|
||||
/* Callback pointer is not used in buffer-only configuration.
|
||||
* Having an int pointer here allows binary compatibility but
|
||||
* gives an error if someone tries to assign callback function.
|
||||
* Also, NULL pointer marks a 'sizing stream' that does not
|
||||
* write anything.
|
||||
*/
|
||||
int *callback;
|
||||
#else
|
||||
bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
|
||||
#endif
|
||||
void *state; /* Free field for use by callback implementation. */
|
||||
size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */
|
||||
size_t bytes_written; /* Number of bytes written so far. */
|
||||
|
||||
#ifndef PB_NO_ERRMSG
|
||||
const char *errmsg;
|
||||
#endif
|
||||
};
|
||||
|
||||
/***************************
|
||||
* Main encoding functions *
|
||||
***************************/
|
||||
|
||||
/* Encode a single protocol buffers message from C structure into a stream.
|
||||
* Returns true on success, false on any failure.
|
||||
* The actual struct pointed to by src_struct must match the description in fields.
|
||||
* All required fields in the struct are assumed to have been filled in.
|
||||
*
|
||||
* Example usage:
|
||||
* MyMessage msg = {};
|
||||
* uint8_t buffer[64];
|
||||
* pb_ostream_t stream;
|
||||
*
|
||||
* msg.field1 = 42;
|
||||
* stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
|
||||
* pb_encode(&stream, MyMessage_fields, &msg);
|
||||
*/
|
||||
bool pb_encode(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
|
||||
|
||||
/* Extended version of pb_encode, with several options to control the
|
||||
* encoding process:
|
||||
*
|
||||
* PB_ENCODE_DELIMITED: Prepend the length of message as a varint.
|
||||
* Corresponds to writeDelimitedTo() in Google's
|
||||
* protobuf API.
|
||||
*
|
||||
* PB_ENCODE_NULLTERMINATED: Append a null byte to the message for termination.
|
||||
* NOTE: This behaviour is not supported in most other
|
||||
* protobuf implementations, so PB_ENCODE_DELIMITED
|
||||
* is a better option for compatibility.
|
||||
*/
|
||||
#define PB_ENCODE_DELIMITED 0x02U
|
||||
#define PB_ENCODE_NULLTERMINATED 0x04U
|
||||
bool pb_encode_ex(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct, unsigned int flags);
|
||||
|
||||
/* Defines for backwards compatibility with code written before nanopb-0.4.0 */
|
||||
#define pb_encode_delimited(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_DELIMITED)
|
||||
#define pb_encode_nullterminated(s,f,d) pb_encode_ex(s,f,d, PB_ENCODE_NULLTERMINATED)
|
||||
|
||||
/* Encode the message to get the size of the encoded data, but do not store
|
||||
* the data. */
|
||||
bool pb_get_encoded_size(size_t *size, const pb_msgdesc_t *fields, const void *src_struct);
|
||||
|
||||
/**************************************
|
||||
* Functions for manipulating streams *
|
||||
**************************************/
|
||||
|
||||
/* Create an output stream for writing into a memory buffer.
|
||||
* The number of bytes written can be found in stream.bytes_written after
|
||||
* encoding the message.
|
||||
*
|
||||
* Alternatively, you can use a custom stream that writes directly to e.g.
|
||||
* a file or a network socket.
|
||||
*/
|
||||
pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize);
|
||||
|
||||
/* Pseudo-stream for measuring the size of a message without actually storing
|
||||
* the encoded data.
|
||||
*
|
||||
* Example usage:
|
||||
* MyMessage msg = {};
|
||||
* pb_ostream_t stream = PB_OSTREAM_SIZING;
|
||||
* pb_encode(&stream, MyMessage_fields, &msg);
|
||||
* printf("Message size is %d\n", stream.bytes_written);
|
||||
*/
|
||||
#ifndef PB_NO_ERRMSG
|
||||
#define PB_OSTREAM_SIZING {0,0,0,0,0}
|
||||
#else
|
||||
#define PB_OSTREAM_SIZING {0,0,0,0}
|
||||
#endif
|
||||
|
||||
/* Function to write into a pb_ostream_t stream. You can use this if you need
|
||||
* to append or prepend some custom headers to the message.
|
||||
*/
|
||||
bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count);
|
||||
|
||||
|
||||
/************************************************
|
||||
* Helper functions for writing field callbacks *
|
||||
************************************************/
|
||||
|
||||
/* Encode field header based on type and field number defined in the field
|
||||
* structure. Call this from the callback before writing out field contents. */
|
||||
bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_iter_t *field);
|
||||
|
||||
/* Encode field header by manually specifying wire type. You need to use this
|
||||
* if you want to write out packed arrays from a callback field. */
|
||||
bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number);
|
||||
|
||||
/* Encode an integer in the varint format.
|
||||
* This works for bool, enum, int32, int64, uint32 and uint64 field types. */
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
bool pb_encode_varint(pb_ostream_t *stream, uint64_t value);
|
||||
#else
|
||||
bool pb_encode_varint(pb_ostream_t *stream, uint32_t value);
|
||||
#endif
|
||||
|
||||
/* Encode an integer in the zig-zagged svarint format.
|
||||
* This works for sint32 and sint64. */
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
bool pb_encode_svarint(pb_ostream_t *stream, int64_t value);
|
||||
#else
|
||||
bool pb_encode_svarint(pb_ostream_t *stream, int32_t value);
|
||||
#endif
|
||||
|
||||
/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */
|
||||
bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size);
|
||||
|
||||
/* Encode a fixed32, sfixed32 or float value.
|
||||
* You need to pass a pointer to a 4-byte wide C variable. */
|
||||
bool pb_encode_fixed32(pb_ostream_t *stream, const void *value);
|
||||
|
||||
#ifndef PB_WITHOUT_64BIT
|
||||
/* Encode a fixed64, sfixed64 or double value.
|
||||
* You need to pass a pointer to a 8-byte wide C variable. */
|
||||
bool pb_encode_fixed64(pb_ostream_t *stream, const void *value);
|
||||
#endif
|
||||
|
||||
#ifdef PB_CONVERT_DOUBLE_FLOAT
|
||||
/* Encode a float value so that it appears like a double in the encoded
|
||||
* message. */
|
||||
bool pb_encode_float_as_double(pb_ostream_t *stream, float value);
|
||||
#endif
|
||||
|
||||
/* Encode a submessage field.
|
||||
* You need to pass the pb_field_t array and pointer to struct, just like
|
||||
* with pb_encode(). This internally encodes the submessage twice, first to
|
||||
* calculate message size and then to actually write it out.
|
||||
*/
|
||||
bool pb_encode_submessage(pb_ostream_t *stream, const pb_msgdesc_t *fields, const void *src_struct);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
443
components/serial_sync/src/sync_master.c
Executable file
443
components/serial_sync/src/sync_master.c
Executable file
@@ -0,0 +1,443 @@
|
||||
|
||||
/* UART asynchronous example, that uses separate RX and TX tasks
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "driver/uart.h"
|
||||
#include "string.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "nanopb/pb_decode.h"
|
||||
#include "nanopb/pb_encode.h"
|
||||
#include "nanopb/pb_common.h"
|
||||
|
||||
#include "LoToHi.pb.h"
|
||||
#include "HiToLo.pb.h"
|
||||
// #include "inc/version_autogen.h"
|
||||
#include "sync_master.h"
|
||||
#include "evse_api.h"
|
||||
|
||||
#define VERSION_STRING "2.2"
|
||||
|
||||
static const int RX_BUF_SIZE = 1024;
|
||||
|
||||
#define TXD_PIN (GPIO_NUM_27)
|
||||
#define RXD_PIN (GPIO_NUM_26)
|
||||
|
||||
static uint8_t msg[2048];
|
||||
static uint8_t code;
|
||||
static uint8_t block;
|
||||
static uint8_t *decode;
|
||||
|
||||
static const char *TAG = "MASTER_TASK";
|
||||
|
||||
void cobsDecodeReset()
|
||||
{
|
||||
code = 0xff;
|
||||
block = 0;
|
||||
decode = msg;
|
||||
}
|
||||
|
||||
void handlePacket(uint8_t *buf, int len);
|
||||
|
||||
void init(void)
|
||||
{
|
||||
const uart_config_t uart_config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
// We won't use a buffer for sending data.
|
||||
uart_driver_install(UART_NUM_2, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
|
||||
uart_param_config(UART_NUM_2, &uart_config);
|
||||
uart_set_pin(UART_NUM_2, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
uint32_t crc32(uint8_t *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t b, crc, msk;
|
||||
|
||||
i = 0;
|
||||
crc = 0xFFFFFFFF;
|
||||
while (i < len)
|
||||
{
|
||||
b = buf[i];
|
||||
crc = crc ^ b;
|
||||
for (j = 7; j >= 0; j--)
|
||||
{
|
||||
msk = -(crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & msk);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// printf("%X",crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void cobsDecodeByte(uint8_t byte)
|
||||
{
|
||||
|
||||
// ESP_LOGI("RX_TASK", "init cobsDecodeByte");
|
||||
// ESP_LOGI("RX_TASK", "Read bytes: '%02X'", byte);
|
||||
|
||||
// check max length
|
||||
if ((decode - msg == 2048 - 1) && byte != 0x00)
|
||||
{
|
||||
ESP_LOGI(TAG, "cobsDecode: Buffer overflow");
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
if (block)
|
||||
{
|
||||
// ESP_LOGI("RX_TASK", "block");
|
||||
// we're currently decoding and should not get a 0
|
||||
if (byte == 0x00)
|
||||
{
|
||||
// probably found some garbage -> reset
|
||||
ESP_LOGI("RX_TASK", "cobsDecode: Garbage detected");
|
||||
cobsDecodeReset();
|
||||
return;
|
||||
}
|
||||
*decode++ = byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESP_LOGI("RX_TASK", "not block");
|
||||
if (code != 0xff)
|
||||
{
|
||||
*decode++ = 0;
|
||||
}
|
||||
block = code = byte;
|
||||
if (code == 0x00)
|
||||
{
|
||||
// we're finished, reset everything and commit
|
||||
if (decode == msg)
|
||||
{
|
||||
// we received nothing, just a 0x00
|
||||
ESP_LOGI("RX_TASK", "cobsDecode: Received nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
// set back decode with one, as it gets post-incremented
|
||||
handlePacket(msg, decode - 1 - msg);
|
||||
}
|
||||
cobsDecodeReset();
|
||||
return; // need to return here, because of block--
|
||||
}
|
||||
}
|
||||
block--;
|
||||
}
|
||||
|
||||
void cobsDecode(uint8_t *buf, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
cobsDecodeByte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t cobsEncode(const void *data, size_t length, uint8_t *buffer)
|
||||
{
|
||||
uint8_t *encode = buffer; // Encoded byte pointer
|
||||
uint8_t *codep = encode++; // Output code pointer
|
||||
uint8_t code = 1; // Code value
|
||||
|
||||
for (const uint8_t *byte = (const uint8_t *)data; length--; ++byte)
|
||||
{
|
||||
if (*byte) // Byte not zero, write it
|
||||
*encode++ = *byte, ++code;
|
||||
|
||||
if (!*byte || code == 0xff) // Input is zero or block completed, restart
|
||||
{
|
||||
*codep = code, code = 1, codep = encode;
|
||||
if (!*byte || length)
|
||||
++encode;
|
||||
}
|
||||
}
|
||||
*codep = code; // Write final code value
|
||||
|
||||
// add final 0
|
||||
*encode++ = 0x00;
|
||||
|
||||
return encode - buffer;
|
||||
}
|
||||
|
||||
int linkWrite(HiToLo *m)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "linkWrite");
|
||||
uint8_t tx_packet_buf[200];
|
||||
uint8_t encode_buf[208];
|
||||
pb_ostream_t ostream = pb_ostream_from_buffer(tx_packet_buf, sizeof(tx_packet_buf) - 4);
|
||||
bool status = pb_encode(&ostream, HiToLo_fields, m);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
// couldn't encode
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t tx_payload_len = ostream.bytes_written;
|
||||
|
||||
// add crc32 (CRC-32/JAMCRC)
|
||||
uint32_t crc = crc32(tx_packet_buf, tx_payload_len);
|
||||
|
||||
for (int byte_pos = 0; byte_pos < 4; ++byte_pos)
|
||||
{
|
||||
tx_packet_buf[tx_payload_len] = (uint8_t)crc & 0xFF;
|
||||
crc = crc >> 8;
|
||||
tx_payload_len++;
|
||||
}
|
||||
size_t tx_encode_len = cobsEncode(tx_packet_buf, tx_payload_len, encode_buf);
|
||||
const int txBytes = uart_write_bytes(UART_NUM_2, encode_buf, tx_encode_len);
|
||||
return txBytes;
|
||||
}
|
||||
|
||||
void send_time_stamp()
|
||||
{
|
||||
ESP_LOGI(TAG, "send_time_stamp");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_time_stamp_tag;
|
||||
msg_out.payload.time_stamp = esp_timer_get_time() / 1000;
|
||||
linkWrite(&msg_out);
|
||||
printf("time stamp sent %i.\n", (int)msg_out.payload.time_stamp);
|
||||
}
|
||||
|
||||
void send_connector_lock(bool on)
|
||||
{
|
||||
ESP_LOGI(TAG, "connector_lock");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_connector_lock_tag;
|
||||
msg_out.payload.connector_lock = on;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_max_charging_current(uint32_t max_charging_current)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_max_charging_current");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_max_charging_current_tag;
|
||||
msg_out.payload.max_charging_current = max_charging_current;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_allow_power_on(bool allow_power_on)
|
||||
{
|
||||
ESP_LOGI(TAG, "allow_power_on");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_allow_power_on_tag;
|
||||
msg_out.payload.allow_power_on = allow_power_on;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_reset(bool reset)
|
||||
{
|
||||
ESP_LOGI(TAG, "reset");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_reset_tag;
|
||||
msg_out.payload.reset = reset;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_grid_current(uint32_t grid_current)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_grid_current");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_grid_current_tag;
|
||||
msg_out.payload.grid_current = grid_current;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_max_grid_current(uint32_t max_grid_current)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_max_grid_current");
|
||||
HiToLo msg_out = HiToLo_init_default;
|
||||
msg_out.which_payload = HiToLo_max_grid_current_tag;
|
||||
msg_out.payload.max_grid_current = max_grid_current;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
/*
|
||||
const evse_state_t cp_state_to_evse_state(CpState cp_state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CpState_EVSE_STATE_A:
|
||||
return EVSE_STATE_A;
|
||||
case CpState_EVSE_STATE_B1:
|
||||
return EVSE_STATE_B1;
|
||||
case CpState_EVSE_STATE_B2:
|
||||
return EVSE_STATE_B2;
|
||||
case CpState_EVSE_STATE_C1:
|
||||
return EVSE_STATE_C1;
|
||||
case CpState_EVSE_STATE_C2:
|
||||
return EVSE_STATE_C2;
|
||||
case CpState_EVSE_STATE_D1:
|
||||
return EVSE_STATE_D1;
|
||||
case CpState_EVSE_STATE_D2:
|
||||
return EVSE_STATE_D2;
|
||||
case CpState_EVSE_STATE_E:
|
||||
return EVSE_STATE_E;
|
||||
case CpState_EVSE_STATE_F:
|
||||
return EVSE_STATE_F;
|
||||
default:
|
||||
return EVSE_STATE_F;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void handlePacket(uint8_t *buf, int len)
|
||||
{
|
||||
// printf ("packet received len %u\n", len);
|
||||
|
||||
// Check CRC32 (last 4 bytes)
|
||||
// uint32_t crc = calculateCrc(rx_packet_buf, rx_packet_len);
|
||||
if (crc32(buf, len))
|
||||
{
|
||||
printf("CRC mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
|
||||
LoToHi msg_in;
|
||||
|
||||
pb_istream_t istream = pb_istream_from_buffer(buf, len);
|
||||
|
||||
if (pb_decode(&istream, LoToHi_fields, &msg_in))
|
||||
{
|
||||
//printf("LoToHi recvd %i \n", msg_in.which_payload);
|
||||
|
||||
switch (msg_in.which_payload)
|
||||
{
|
||||
case LoToHi_time_stamp_tag:
|
||||
printf("Received time stamp %i\n", (int)msg_in.payload.time_stamp);
|
||||
break;
|
||||
case LoToHi_relais_state_tag:
|
||||
printf("Received relais_state %i\n", (int)msg_in.payload.relais_state);
|
||||
break;
|
||||
case LoToHi_error_flags_tag:
|
||||
// printf("Received error_flags %i\n", (int)msg_in.payload.error_flags);
|
||||
break;
|
||||
case LoToHi_cp_state_tag:
|
||||
printf("Received cp_state %i\n", (int)msg_in.payload.cp_state);
|
||||
// state = cp_state_to_evse_state(msg_in.payload.cp_state);
|
||||
break;
|
||||
case LoToHi_pp_state_tag:
|
||||
printf("Received cp_state %i\n", (int)msg_in.payload.pp_state);
|
||||
break;
|
||||
case LoToHi_max_charging_current_tag:
|
||||
printf("Received max_charging_current %i\n", (int)msg_in.payload.max_charging_current);
|
||||
|
||||
int max_charging_current = (int)msg_in.payload.max_charging_current;
|
||||
|
||||
if (max_charging_current != evse_get_max_charging_current())
|
||||
{
|
||||
send_max_charging_current(evse_get_max_charging_current());
|
||||
}
|
||||
break;
|
||||
|
||||
case LoToHi_max_grid_current_tag:
|
||||
printf("Received max_grid_current %i\n", (int)msg_in.payload.max_grid_current);
|
||||
|
||||
int max_grid_current = (int)msg_in.payload.max_grid_current;
|
||||
|
||||
if (max_grid_current != grid_get_max_current())
|
||||
{
|
||||
send_max_grid_current(grid_get_max_current());
|
||||
}
|
||||
break;
|
||||
|
||||
case LoToHi_lock_state_tag:
|
||||
printf("Received lock_state %i\n", (int)msg_in.payload.lock_state);
|
||||
break;
|
||||
case LoToHi_power_meter_tag:
|
||||
printf("Received power_meter %i\n", (int)msg_in.payload.power_meter.time_stamp);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Not Found Sync Master recvd %i \n", msg_in.which_payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_task(void *arg)
|
||||
{
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
// send_time_stamp();
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// send_connector_lock(true);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
send_max_charging_current(32);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
// send_allow_power_on(true);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// send_reset(true);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
static void rx_task(void *arg)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)malloc(RX_BUF_SIZE + 1);
|
||||
while (1)
|
||||
{
|
||||
|
||||
const int rxBytes = uart_read_bytes(UART_NUM_2, data, RX_BUF_SIZE, 1000 / portTICK_PERIOD_MS);
|
||||
if (rxBytes > 0)
|
||||
{
|
||||
data[rxBytes] = 0;
|
||||
// ESP_LOGI(TAG, "Read %d bytes: '%s'", rxBytes, data);
|
||||
// ESP_LOG_BUFFER_HEXDUMP(TAG, data, rxBytes, ESP_LOG_INFO);
|
||||
cobsDecode(data, rxBytes);
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
void master_sync_start()
|
||||
{
|
||||
ESP_LOGI(TAG, "Master SYNC Serial");
|
||||
|
||||
init();
|
||||
xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 5, NULL);
|
||||
//xTaskCreate(tx_task, "uart_tx_task", 1024 * 5, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
void master_sync_stop(void)
|
||||
{
|
||||
/*
|
||||
ESP_LOGI(TAG, "Stopping");
|
||||
|
||||
if (rx_task)
|
||||
{
|
||||
vTaskDelete(rx_task);
|
||||
rx_task = NULL;
|
||||
}
|
||||
|
||||
if (tx_task)
|
||||
{
|
||||
vTaskDelete(tx_task);
|
||||
tx_task = NULL;
|
||||
}
|
||||
|
||||
if (port != -1)
|
||||
{
|
||||
uart_driver_delete(port);
|
||||
port = -1;
|
||||
}*/
|
||||
}
|
||||
530
components/serial_sync/src/sync_slave.c
Executable file
530
components/serial_sync/src/sync_slave.c
Executable file
@@ -0,0 +1,530 @@
|
||||
/* UART asynchronous example, that uses separate RX and TX tasks sync_slave
|
||||
*/
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_timer.h"
|
||||
#include "driver/uart.h"
|
||||
#include "string.h"
|
||||
#include "driver/gpio.h"
|
||||
|
||||
#include "nanopb/pb_decode.h"
|
||||
#include "nanopb/pb_encode.h"
|
||||
#include "nanopb/pb_common.h"
|
||||
|
||||
#include "LoToHi.pb.h"
|
||||
#include "HiToLo.pb.h"
|
||||
// #include "inc/version_autogen.h"
|
||||
|
||||
#include "sync_slave.h"
|
||||
#include "currentshaper.h"
|
||||
#include "evse_api.h"
|
||||
|
||||
#define VERSION_STRING "2.2"
|
||||
|
||||
static const int RX_BUF_SIZE = 1024;
|
||||
|
||||
#define TXD_PIN (GPIO_NUM_27)
|
||||
#define RXD_PIN (GPIO_NUM_26)
|
||||
|
||||
static uint8_t msg[2048];
|
||||
static uint8_t code;
|
||||
static uint8_t block;
|
||||
static uint8_t *decode;
|
||||
// static ErrorFlags error_flags;
|
||||
|
||||
static const char *TAG = "SLAVE";
|
||||
|
||||
void cobsDecodeReset()
|
||||
{
|
||||
code = 0xff;
|
||||
block = 0;
|
||||
decode = msg;
|
||||
}
|
||||
|
||||
void handlePacket(uint8_t *buf, int len);
|
||||
|
||||
void init(void)
|
||||
{
|
||||
const uart_config_t uart_config = {
|
||||
.baud_rate = 115200,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
// We won't use a buffer for sending data.
|
||||
uart_driver_install(UART_NUM_2, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
|
||||
uart_param_config(UART_NUM_2, &uart_config);
|
||||
uart_set_pin(UART_NUM_2, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
|
||||
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
uint32_t crc32(uint8_t *buf, int len)
|
||||
{
|
||||
int i, j;
|
||||
uint32_t b, crc, msk;
|
||||
|
||||
i = 0;
|
||||
crc = 0xFFFFFFFF;
|
||||
while (i < len)
|
||||
{
|
||||
b = buf[i];
|
||||
crc = crc ^ b;
|
||||
for (j = 7; j >= 0; j--)
|
||||
{
|
||||
msk = -(crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & msk);
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
// printf("%X",crc);
|
||||
return crc;
|
||||
}
|
||||
|
||||
void cobsDecodeByte(uint8_t byte)
|
||||
{
|
||||
|
||||
// ESP_LOGI("RX_TASK", "init cobsDecodeByte");
|
||||
// ESP_LOGI("RX_TASK", "Read bytes: '%02X'", byte);
|
||||
|
||||
// check max length
|
||||
if ((decode - msg == 2048 - 1) && byte != 0x00)
|
||||
{
|
||||
ESP_LOGI(TAG, "cobsDecode: Buffer overflow");
|
||||
cobsDecodeReset();
|
||||
}
|
||||
|
||||
if (block)
|
||||
{
|
||||
// ESP_LOGI("RX_TASK", "block");
|
||||
// we're currently decoding and should not get a 0
|
||||
if (byte == 0x00)
|
||||
{
|
||||
// probably found some garbage -> reset
|
||||
ESP_LOGI(TAG, "cobsDecode: Garbage detected");
|
||||
cobsDecodeReset();
|
||||
return;
|
||||
}
|
||||
*decode++ = byte;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ESP_LOGI("RX_TASK", "not block");
|
||||
if (code != 0xff)
|
||||
{
|
||||
*decode++ = 0;
|
||||
}
|
||||
block = code = byte;
|
||||
if (code == 0x00)
|
||||
{
|
||||
// we're finished, reset everything and commit
|
||||
if (decode == msg)
|
||||
{
|
||||
// we received nothing, just a 0x00
|
||||
ESP_LOGI(TAG, "cobsDecode: Received nothing");
|
||||
}
|
||||
else
|
||||
{
|
||||
// set back decode with one, as it gets post-incremented
|
||||
handlePacket(msg, decode - 1 - msg);
|
||||
}
|
||||
cobsDecodeReset();
|
||||
return; // need to return here, because of block--
|
||||
}
|
||||
}
|
||||
block--;
|
||||
}
|
||||
|
||||
void cobsDecode(uint8_t *buf, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
cobsDecodeByte(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t cobsEncode(const void *data, size_t length, uint8_t *buffer)
|
||||
{
|
||||
uint8_t *encode = buffer; // Encoded byte pointer
|
||||
uint8_t *codep = encode++; // Output code pointer
|
||||
uint8_t code = 1; // Code value
|
||||
|
||||
for (const uint8_t *byte = (const uint8_t *)data; length--; ++byte)
|
||||
{
|
||||
if (*byte) // Byte not zero, write it
|
||||
*encode++ = *byte, ++code;
|
||||
|
||||
if (!*byte || code == 0xff) // Input is zero or block completed, restart
|
||||
{
|
||||
*codep = code, code = 1, codep = encode;
|
||||
if (!*byte || length)
|
||||
++encode;
|
||||
}
|
||||
}
|
||||
*codep = code; // Write final code value
|
||||
|
||||
// add final 0
|
||||
*encode++ = 0x00;
|
||||
|
||||
return encode - buffer;
|
||||
}
|
||||
|
||||
int linkWrite(LoToHi *m)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "linkWrite");
|
||||
uint8_t tx_packet_buf[200];
|
||||
uint8_t encode_buf[208];
|
||||
pb_ostream_t ostream = pb_ostream_from_buffer(tx_packet_buf, sizeof(tx_packet_buf) - 4);
|
||||
bool status = pb_encode(&ostream, LoToHi_fields, m);
|
||||
|
||||
if (!status)
|
||||
{
|
||||
// couldn't encode
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t tx_payload_len = ostream.bytes_written;
|
||||
|
||||
// add crc32 (CRC-32/JAMCRC)
|
||||
uint32_t crc = crc32(tx_packet_buf, tx_payload_len);
|
||||
|
||||
for (int byte_pos = 0; byte_pos < 4; ++byte_pos)
|
||||
{
|
||||
tx_packet_buf[tx_payload_len] = (uint8_t)crc & 0xFF;
|
||||
crc = crc >> 8;
|
||||
tx_payload_len++;
|
||||
}
|
||||
size_t tx_encode_len = cobsEncode(tx_packet_buf, tx_payload_len, encode_buf);
|
||||
const int txBytes = uart_write_bytes(UART_NUM_2, encode_buf, tx_encode_len);
|
||||
return txBytes;
|
||||
}
|
||||
|
||||
void send_time_stamp()
|
||||
{
|
||||
ESP_LOGI(TAG, "send_time_stamp");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_time_stamp_tag;
|
||||
msg_out.payload.time_stamp = esp_timer_get_time() / 1000;
|
||||
linkWrite(&msg_out);
|
||||
printf("time stamp sent %i.\n", (int)msg_out.payload.time_stamp);
|
||||
}
|
||||
|
||||
void send_relais_state(bool on)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_relais_state");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_relais_state_tag;
|
||||
msg_out.payload.relais_state = on;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_error_flags(ErrorFlags e)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_error_flags");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_error_flags_tag;
|
||||
msg_out.payload.error_flags = e;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_cp_state(CpState cp_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_cp_state");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_cp_state_tag;
|
||||
msg_out.payload.cp_state = cp_state;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_pp_state(PpState pp_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_pp_state");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_pp_state_tag;
|
||||
msg_out.payload.pp_state = pp_state;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_max_charging_current(uint32_t max_charging_current)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_max_charging_current");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_max_charging_current_tag;
|
||||
msg_out.payload.max_charging_current = max_charging_current;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_max_grid_current(uint32_t max_grid_current)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_max_grid_current");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_max_grid_current_tag;
|
||||
msg_out.payload.max_grid_current = max_grid_current;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_lock_state(LockState lock_state)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_lock_state");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_lock_state_tag;
|
||||
msg_out.payload.lock_state = lock_state;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void send_power_meter(PowerMeter p)
|
||||
{
|
||||
ESP_LOGI(TAG, "send_power_meter");
|
||||
LoToHi msg_out = LoToHi_init_default;
|
||||
msg_out.which_payload = LoToHi_power_meter_tag;
|
||||
msg_out.payload.power_meter = p;
|
||||
linkWrite(&msg_out);
|
||||
}
|
||||
|
||||
void handlePacket(uint8_t *buf, int len)
|
||||
{
|
||||
// Check CRC32 (last 4 bytes)
|
||||
// uint32_t crc = calculateCrc(rx_packet_buf, rx_packet_len);
|
||||
if (crc32(buf, len))
|
||||
{
|
||||
printf("CRC mismatch\n");
|
||||
return;
|
||||
}
|
||||
|
||||
len -= 4;
|
||||
|
||||
HiToLo msg_in;
|
||||
|
||||
pb_istream_t istream = pb_istream_from_buffer(buf, len);
|
||||
|
||||
if (pb_decode(&istream, HiToLo_fields, &msg_in))
|
||||
{
|
||||
// printf("RemoteControl recvd %i \n", msg_in.which_payload);
|
||||
|
||||
switch (msg_in.which_payload)
|
||||
{
|
||||
case HiToLo_time_stamp_tag:
|
||||
printf("Received time stamp tag \n");
|
||||
break;
|
||||
case HiToLo_connector_lock_tag:
|
||||
printf("Received connector_lock %i\n", (int)msg_in.payload.connector_lock);
|
||||
break;
|
||||
case HiToLo_max_charging_current_tag:
|
||||
printf("Received max_charging_current %i\n",
|
||||
(int)msg_in.payload.max_charging_current);
|
||||
evse_set_max_charging_current((int)msg_in.payload.max_charging_current);
|
||||
break;
|
||||
case HiToLo_max_grid_current_tag:
|
||||
printf("Received max_grid_current %i\n",
|
||||
(int)msg_in.payload.max_grid_current);
|
||||
grid_set_max_current((int)msg_in.payload.max_grid_current);
|
||||
break;
|
||||
case HiToLo_allow_power_on_tag:
|
||||
printf("Received allow_poweron %i\n",
|
||||
(int)msg_in.payload.allow_power_on);
|
||||
break;
|
||||
case HiToLo_reset_tag:
|
||||
printf("Received reset\n");
|
||||
break;
|
||||
case HiToLo_grid_current_tag:
|
||||
printf("Received grid_current %i\n",
|
||||
(int)msg_in.payload.grid_current);
|
||||
|
||||
setMaxGridCurrent(grid_get_max_current() * 10);
|
||||
setLiveGridCurrent((int)msg_in.payload.grid_current);
|
||||
|
||||
break;
|
||||
default:
|
||||
// printf("not found");
|
||||
printf("Not Found RemoteControl recvd %i \n", msg_in.which_payload);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const int evse_state_to_int(evse_state_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case EVSE_STATE_A:
|
||||
return 1;
|
||||
case EVSE_STATE_B1:
|
||||
return 2;
|
||||
case EVSE_STATE_B2:
|
||||
return 3;
|
||||
case EVSE_STATE_C1:
|
||||
return 4;
|
||||
case EVSE_STATE_C2:
|
||||
return 5;
|
||||
case EVSE_STATE_D1:
|
||||
return 6;
|
||||
case EVSE_STATE_D2:
|
||||
return 7;
|
||||
case EVSE_STATE_E:
|
||||
return 8;
|
||||
case EVSE_STATE_F:
|
||||
return 9;
|
||||
default:
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
CpState evse_state_to_cpState(evse_state_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case EVSE_STATE_A:
|
||||
return CpState_EVSE_STATE_A;
|
||||
case EVSE_STATE_B1:
|
||||
return CpState_EVSE_STATE_B1;
|
||||
case EVSE_STATE_B2:
|
||||
return CpState_EVSE_STATE_B2;
|
||||
case EVSE_STATE_C1:
|
||||
return CpState_EVSE_STATE_C1;
|
||||
case EVSE_STATE_C2:
|
||||
return CpState_EVSE_STATE_C2;
|
||||
case EVSE_STATE_D1:
|
||||
return CpState_EVSE_STATE_D1;
|
||||
case EVSE_STATE_D2:
|
||||
return CpState_EVSE_STATE_D2;
|
||||
case EVSE_STATE_E:
|
||||
return CpState_EVSE_STATE_E;
|
||||
case EVSE_STATE_F:
|
||||
return CpState_EVSE_STATE_F;
|
||||
default:
|
||||
return CpState_EVSE_STATE_F;
|
||||
}
|
||||
}
|
||||
|
||||
static void tx_task(void *arg)
|
||||
{
|
||||
|
||||
/*
|
||||
error_flags.connector_lock_failed = false;
|
||||
error_flags.cp_signal_fault = false;
|
||||
error_flags.diode_fault = false;
|
||||
error_flags.rcd_selftest_failed = false;
|
||||
error_flags.rcd_triggered = false;
|
||||
error_flags.ventilation_not_available = false;
|
||||
*/
|
||||
|
||||
while (1)
|
||||
{
|
||||
// send_time_stamp();
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
// send_relais_state(false);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
// send_error_flags(error_flags);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
send_cp_state(evse_state_to_cpState(evse_get_state()));
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
// send_pp_state(PpState_STATE_32A);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
send_max_charging_current(evse_get_max_charging_current());
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
|
||||
send_max_grid_current(grid_get_max_current());
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
// send_lock_state(false);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
|
||||
/*
|
||||
PowerMeter p;
|
||||
p.vrmsL1 = 230;
|
||||
p.vrmsL2 = 230;
|
||||
p.vrmsL3 = 230;
|
||||
p.irmsL1 = 0;
|
||||
p.irmsL2 = 0;
|
||||
p.irmsL3 = 0;
|
||||
p.irmsN = 0;
|
||||
p.wattHrL1 = 0;
|
||||
p.wattHrL2 = 0;
|
||||
p.wattHrL3 = 0;
|
||||
p.totalWattHr = 0;
|
||||
|
||||
p.tempL1 = 20;
|
||||
p.tempL2 = 20;
|
||||
p.tempL3 = 20;
|
||||
p.tempN = 20;
|
||||
|
||||
p.wattL1 = 0;
|
||||
p.wattL2 = 0;
|
||||
p.wattL3 = 0;
|
||||
|
||||
p.freqL1 = 50;
|
||||
p.freqL2 = 50;
|
||||
p.freqL3 = 50;
|
||||
|
||||
p.phaseSeqError = 0;
|
||||
|
||||
// send_power_meter(p);
|
||||
// vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
static void rx_task(void *arg)
|
||||
{
|
||||
uint8_t *data = (uint8_t *)malloc(RX_BUF_SIZE + 1);
|
||||
while (1)
|
||||
{
|
||||
const int rxBytes = uart_read_bytes(UART_NUM_2, data, RX_BUF_SIZE, 1000 / portTICK_PERIOD_MS);
|
||||
if (rxBytes > 0)
|
||||
{
|
||||
data[rxBytes] = 0;
|
||||
// ESP_LOGI(TAG, "Read %d bytes: '%s'", rxBytes, data);
|
||||
// ESP_LOG_BUFFER_HEXDUMP(TAG, data, rxBytes, ESP_LOG_INFO);
|
||||
cobsDecode(data, rxBytes);
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
}
|
||||
|
||||
void slave_sync_start()
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "Starting SYNC Serial");
|
||||
|
||||
init();
|
||||
xTaskCreate(rx_task, "uart_rx_task", 1024 * 5, NULL, 5, NULL);
|
||||
xTaskCreate(tx_task, "uart_tx_task", 1024 * 5, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
void slave_sync_stop(void)
|
||||
{
|
||||
|
||||
/*
|
||||
ESP_LOGI(TAG, "Stopping");
|
||||
|
||||
if (rx_task)
|
||||
{
|
||||
vTaskDelete(rx_task);
|
||||
rx_task = NULL;
|
||||
}
|
||||
|
||||
if (tx_task)
|
||||
{
|
||||
vTaskDelete(tx_task);
|
||||
tx_task = NULL;
|
||||
}
|
||||
|
||||
if (port != -1)
|
||||
{
|
||||
uart_driver_delete(port);
|
||||
port = -1;
|
||||
}*/
|
||||
}
|
||||
Reference in New Issue
Block a user