some refactoring. Also compute crc over payload AND header
This commit is contained in:
parent
588ea34510
commit
f3336e911d
5 changed files with 111 additions and 25 deletions
|
|
@ -62,11 +62,11 @@ typedef struct {msg_struct} {{
|
||||||
{struct_fields_str}
|
{struct_fields_str}
|
||||||
}} {msg_type};
|
}} {msg_type};
|
||||||
|
|
||||||
void {NS_PREFIX_LOWER}{m.name_lower}_msg_encode(uint8_t src_id, uint8_t dst_id, const {msg_type} *msg, {GENERIC_MSG_TYPE} *packet) {{
|
static inline void {NS_PREFIX_LOWER}msg_{m.name_lower}_encode(uint8_t src_id, uint8_t dst_id, const {msg_type} *msg, {GENERIC_MSG_TYPE} *packet) {{
|
||||||
packet->id = {MSG_ID_PREFIX}{m.name};
|
packet->id = {MSG_ID_PREFIX}{m.name};
|
||||||
packet->src_id = src_id;
|
packet->src_id = src_id;
|
||||||
packet->dst_id = dst_id;
|
packet->dst_id = dst_id;
|
||||||
packet->length = {MSG_ID_PREFIX}{m.id}_LEN + HYDROLINK_NON_PAYLOAD_LEN;
|
packet->payload_length = {MSG_ID_PREFIX}{m.id}_LEN + HYDROLINK_NON_PAYLOAD_LEN;
|
||||||
{encode_payload_str}
|
{encode_payload_str}
|
||||||
}}
|
}}
|
||||||
""")
|
""")
|
||||||
|
|
@ -77,6 +77,6 @@ static inline {field.type} {msg_name}_get_{field.name}(const {GENERIC_MSG_TYPE}
|
||||||
return HYDROLINK_RETURN_{field.type}(packet, {field.wire_offset});
|
return HYDROLINK_RETURN_{field.type}(packet, {field.wire_offset});
|
||||||
}}""")
|
}}""")
|
||||||
f.write(f"""
|
f.write(f"""
|
||||||
static inline void {NS_PREFIX_LOWER}msg{m.name_lower}_decode(const {GENERIC_MSG_TYPE} *packet, {msg_type} *{m.name_lower}) {{
|
static inline void {NS_PREFIX_LOWER}msg_{m.name_lower}_decode(const {GENERIC_MSG_TYPE} *packet, {msg_type} *{m.name_lower}) {{
|
||||||
{decode_payload_str(m)}
|
{decode_payload_str(m)}
|
||||||
}}""")
|
}}""")
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,11 @@ def generate_main_header(msgs, dir):
|
||||||
with open(os.path.join(dir, "hydrolink.h"), "w") as f:
|
with open(os.path.join(dir, "hydrolink.h"), "w") as f:
|
||||||
f.write(f"""#pragma once
|
f.write(f"""#pragma once
|
||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
|
#include "hydrolink_enums.h"
|
||||||
{"\n".join(f"#include \"{GENERIC_MSG_NAME}_{msg.name_lower}.h\"" for msg in msgs)}
|
{"\n".join(f"#include \"{GENERIC_MSG_NAME}_{msg.name_lower}.h\"" for msg in msgs)}
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def generate_protocol(xml, dir):
|
def generate_protocol(xml, msgs, dir):
|
||||||
put_defines = []
|
put_defines = []
|
||||||
for typename in TYPE_LENGTHS:
|
for typename in TYPE_LENGTHS:
|
||||||
length = TYPE_LENGTHS[typename]
|
length = TYPE_LENGTHS[typename]
|
||||||
|
|
@ -41,6 +42,44 @@ def generate_protocol(xml, dir):
|
||||||
#define HYDROLINK_MAX_PAYLOAD_LEN {xml.largest_payload}
|
#define HYDROLINK_MAX_PAYLOAD_LEN {xml.largest_payload}
|
||||||
#define HYDROLINK_MAX_MSG_LEN (HYDROLINK_MAX_PAYLOAD_LEN + HYDROLINK_NON_PAYLOAD_LEN)
|
#define HYDROLINK_MAX_MSG_LEN (HYDROLINK_MAX_PAYLOAD_LEN + HYDROLINK_NON_PAYLOAD_LEN)
|
||||||
|
|
||||||
|
typedef struct {{
|
||||||
|
uint8_t msg_id;
|
||||||
|
uint8_t crc_extra;
|
||||||
|
}} hydrolink_crc_extra_t;
|
||||||
|
|
||||||
|
#define HYDROLINK_MSG_CRCS {{{", ".join(f"{{{msg.id}, {msg.crc_extra}}}" for msg in msgs)}}}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the crc_extra byte corresponding to msg_id
|
||||||
|
*
|
||||||
|
* @param msg_id the message's id
|
||||||
|
* @param crc[out] the crc_extra byte as output of this function
|
||||||
|
* @return Return 1 if successfull, 0 otherwise.
|
||||||
|
**/
|
||||||
|
static inline uint8_t hydrolink_get_crc_extra(uint8_t msg_id, uint8_t *crc) {{
|
||||||
|
static const hydrolink_crc_extra_t crcs[] = HYDROLINK_MSG_CRCS;
|
||||||
|
uint8_t left = 0;
|
||||||
|
uint8_t right = sizeof(crcs) / sizeof(crcs[0]) - 1;
|
||||||
|
while (left < right) {{
|
||||||
|
uint8_t center = (left+right+1) / 2;
|
||||||
|
if (msg_id < crcs[center].msg_id) {{
|
||||||
|
right = center - 1;
|
||||||
|
continue;
|
||||||
|
}}
|
||||||
|
if (msg_id > crcs[center].msg_id) {{
|
||||||
|
left = center;
|
||||||
|
continue;
|
||||||
|
}}
|
||||||
|
left = center;
|
||||||
|
break;
|
||||||
|
}}
|
||||||
|
if (crcs[left].msg_id != msg_id) {{
|
||||||
|
return 0;
|
||||||
|
}}
|
||||||
|
*crc = crcs[left].crc_extra;
|
||||||
|
return 1;
|
||||||
|
}}
|
||||||
|
|
||||||
struct {GENERIC_MSG_STRUCT};
|
struct {GENERIC_MSG_STRUCT};
|
||||||
|
|
||||||
typedef struct {GENERIC_MSG_STRUCT} {GENERIC_MSG_TYPE};
|
typedef struct {GENERIC_MSG_STRUCT} {GENERIC_MSG_TYPE};
|
||||||
|
|
@ -59,19 +98,19 @@ struct {GENERIC_MSG_STRUCT} {{
|
||||||
|
|
||||||
{put_defines_str}
|
{put_defines_str}
|
||||||
|
|
||||||
inline void byte_swap_2(char *dst, const char *src) {{
|
static inline void byte_swap_2(char *dst, const char *src) {{
|
||||||
dst[0] = src[1];
|
dst[0] = src[1];
|
||||||
dst[1] = src[0];
|
dst[1] = src[0];
|
||||||
}}
|
}}
|
||||||
|
|
||||||
inline void byte_swap_4(char *dst, const char *src) {{
|
static inline void byte_swap_4(char *dst, const char *src) {{
|
||||||
dst[0] = src[3];
|
dst[0] = src[3];
|
||||||
dst[1] = src[2];
|
dst[1] = src[2];
|
||||||
dst[2] = src[1];
|
dst[2] = src[1];
|
||||||
dst[3] = src[0];
|
dst[3] = src[0];
|
||||||
}}
|
}}
|
||||||
|
|
||||||
inline void byte_swap_8(char *dst, const char *src) {{
|
static inline void byte_swap_8(char *dst, const char *src) {{
|
||||||
dst[0] = src[7];
|
dst[0] = src[7];
|
||||||
dst[1] = src[6];
|
dst[1] = src[6];
|
||||||
dst[2] = src[5];
|
dst[2] = src[5];
|
||||||
|
|
@ -100,9 +139,9 @@ static inline TYPE HYDROLINK_RETURN_## TYPE(const {GENERIC_MSG_TYPE} *msg, uint8
|
||||||
HYDROLINK_MSG_RETURN_TYPE({typename}, {length})
|
HYDROLINK_MSG_RETURN_TYPE({typename}, {length})
|
||||||
""")
|
""")
|
||||||
f.write("""
|
f.write("""
|
||||||
inline void crc_xmodem_init(uint16_t *crc) { *crc = 0; }
|
static inline void crc_xmodem_init(uint16_t *crc) { *crc = 0; }
|
||||||
|
|
||||||
inline void crc_xmodem_accumulate(uint8_t data, uint16_t *crc) {
|
static inline void crc_xmodem_accumulate(uint8_t data, uint16_t *crc) {
|
||||||
*crc = *crc ^ ((uint16_t)data << 8);
|
*crc = *crc ^ ((uint16_t)data << 8);
|
||||||
for (uint8_t j = 0; j < 8; j++) {
|
for (uint8_t j = 0; j < 8; j++) {
|
||||||
if (*crc & 0x8000) {
|
if (*crc & 0x8000) {
|
||||||
|
|
@ -113,7 +152,7 @@ inline void crc_xmodem_accumulate(uint8_t data, uint16_t *crc) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint16_t crc_xmodem_calculate(const uint8_t *data, uint8_t length) {
|
static inline uint16_t crc_xmodem_calculate(const uint8_t *data, uint8_t length) {
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
crc_xmodem_init(&crc);
|
crc_xmodem_init(&crc);
|
||||||
for (uint8_t i = 0; i < length; i++) {
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
|
@ -121,15 +160,29 @@ inline uint16_t crc_xmodem_calculate(const uint8_t *data, uint8_t length) {
|
||||||
}
|
}
|
||||||
return crc;
|
return crc;
|
||||||
}
|
}
|
||||||
""")
|
|
||||||
f.write(f"""
|
static inline uint16_t hydrolink_calculate_crc(const uint8_t *payload, uint8_t length, uint8_t crc_extra) {
|
||||||
void hydrolink_fill_header_and_crc({GENERIC_MSG_TYPE} *msg, uint8_t msg_id, uint8_t payload_length, uint8_t dst_id, uint8_t src_id, uint8_t crc_extra) {{
|
|
||||||
msg->id = msg_id;
|
|
||||||
msg->payload_length = payload_length;
|
|
||||||
msg->dst_id = dst_id;
|
|
||||||
msg->src_id = src_id;
|
|
||||||
uint16_t crc;
|
uint16_t crc;
|
||||||
crc_xmodem_init(&crc);
|
crc_xmodem_init(&crc);
|
||||||
|
for(int i = 0; i < length; ++i) {
|
||||||
|
crc_xmodem_accumulate(payload[i], &crc);
|
||||||
|
}
|
||||||
|
crc_xmodem_accumulate(crc_extra, &crc);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
f.write(f"""
|
||||||
|
static inline void hydrolink_fill_header_and_crc({GENERIC_MSG_TYPE} *msg, uint8_t msg_id, uint8_t payload_length, uint8_t dst_id, uint8_t src_id, uint8_t crc_extra) {{
|
||||||
|
uint16_t crc;
|
||||||
|
crc_xmodem_init(&crc);
|
||||||
|
msg->id = msg_id;
|
||||||
|
crc_xmodem_accumulate(msg->id, &crc);
|
||||||
|
msg->payload_length = payload_length;
|
||||||
|
crc_xmodem_accumulate(msg->payload_length, &crc);
|
||||||
|
msg->dst_id = dst_id;
|
||||||
|
crc_xmodem_accumulate(msg->dst_id, &crc);
|
||||||
|
msg->src_id = src_id;
|
||||||
|
crc_xmodem_accumulate(msg->src_id, &crc);
|
||||||
for(int i = 0; i < msg->payload_length; ++i) {{
|
for(int i = 0; i < msg->payload_length; ++i) {{
|
||||||
crc_xmodem_accumulate(msg->payload[i], &crc);
|
crc_xmodem_accumulate(msg->payload[i], &crc);
|
||||||
}}
|
}}
|
||||||
|
|
@ -137,7 +190,7 @@ void hydrolink_fill_header_and_crc({GENERIC_MSG_TYPE} *msg, uint8_t msg_id, uint
|
||||||
msg->crc = crc;
|
msg->crc = crc;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
uint8_t hydrolink_serialize_message({GENERIC_MSG_TYPE} *msg, uint8_t *buffer) {{
|
static inline uint8_t hydrolink_serialize_message({GENERIC_MSG_TYPE} *msg, uint8_t *buffer) {{
|
||||||
buffer[0] = msg->id;
|
buffer[0] = msg->id;
|
||||||
buffer[1] = msg->payload_length;
|
buffer[1] = msg->payload_length;
|
||||||
buffer[2] = msg->dst_id;
|
buffer[2] = msg->dst_id;
|
||||||
|
|
@ -151,7 +204,7 @@ uint8_t hydrolink_serialize_message({GENERIC_MSG_TYPE} *msg, uint8_t *buffer) {{
|
||||||
return HYDROLINK_NON_PAYLOAD_LEN + msg->payload_length;
|
return HYDROLINK_NON_PAYLOAD_LEN + msg->payload_length;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
uint8_t hydrolink_deserialize_header({GENERIC_MSG_TYPE} *msg, uint8_t *buffer, uint8_t buffer_length) {{
|
static inline uint8_t hydrolink_deserialize_header({GENERIC_MSG_TYPE} *msg, uint8_t *buffer, uint8_t buffer_length) {{
|
||||||
if (buffer_length < HYDROLINK_NON_PAYLOAD_LEN) {{
|
if (buffer_length < HYDROLINK_NON_PAYLOAD_LEN) {{
|
||||||
return 0;
|
return 0;
|
||||||
}}
|
}}
|
||||||
|
|
@ -176,8 +229,9 @@ def generate(xmls, out_dir):
|
||||||
msgs = []
|
msgs = []
|
||||||
for x in xmls:
|
for x in xmls:
|
||||||
msgs.extend(x.messages)
|
msgs.extend(x.messages)
|
||||||
|
sorted(msgs, key=lambda msg: msg.id)
|
||||||
for msg in msgs:
|
for msg in msgs:
|
||||||
generate_message_h(os.path.join(out_dir), msg)
|
generate_message_h(os.path.join(out_dir), msg)
|
||||||
generate_main_header(msgs, out_dir)
|
generate_main_header(msgs, out_dir)
|
||||||
generate_protocol(xmls[0], out_dir)
|
generate_protocol(xmls[0], msgs, out_dir)
|
||||||
generate_enums_h(out_dir, xmls[0].enums)
|
generate_enums_h(out_dir, xmls[0].enums)
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,41 @@ def generate_hydrolink(out_dir, msgs):
|
||||||
from .hydrolink_msg import HydrolinkHeader, HydrolinkMessage, CrcXmodem
|
from .hydrolink_msg import HydrolinkHeader, HydrolinkMessage, CrcXmodem
|
||||||
from .hydrolink_msg_ids import {", ".join(f"HYDROLINK_MSG_ID_{msg.name}" for msg in msgs)}
|
from .hydrolink_msg_ids import {", ".join(f"HYDROLINK_MSG_ID_{msg.name}" for msg in msgs)}
|
||||||
{"\n".join(f"from .hydrolink_{msg.name_lower}_message import Hydrolink{to_camel_case(msg.name)}Message" for msg in msgs)}
|
{"\n".join(f"from .hydrolink_{msg.name_lower}_message import Hydrolink{to_camel_case(msg.name)}Message" for msg in msgs)}
|
||||||
import hydrolink_enums as ENUMS
|
from . import hydrolink_enums as ENUMS
|
||||||
|
|
||||||
|
|
||||||
|
def cobs_decode(data):
|
||||||
|
output = []
|
||||||
|
index = 1
|
||||||
|
offset = data[0] - 1
|
||||||
|
while index < len(data):
|
||||||
|
if offset == 0:
|
||||||
|
output.append(0)
|
||||||
|
offset = data[index]
|
||||||
|
else:
|
||||||
|
output.append(data[index])
|
||||||
|
index = index + 1
|
||||||
|
offset = offset - 1
|
||||||
|
return bytearray(output)
|
||||||
|
|
||||||
|
|
||||||
|
def cobs_encode(data):
|
||||||
|
output = [0 for i in range(len(data) + 2)]
|
||||||
|
dst_index = 1
|
||||||
|
zero_offset = 1
|
||||||
|
for src_byte in data:
|
||||||
|
if src_byte == 0:
|
||||||
|
output[dst_index - zero_offset] = zero_offset
|
||||||
|
zero_offset = 1
|
||||||
|
else:
|
||||||
|
output[dst_index] = src_byte
|
||||||
|
zero_offset += 1
|
||||||
|
dst_index += 1
|
||||||
|
|
||||||
|
output[dst_index - zero_offset] = zero_offset
|
||||||
|
output[dst_index] = 0
|
||||||
|
|
||||||
|
return output
|
||||||
|
|
||||||
|
|
||||||
MSG_ID_TO_CLASS_MAP = {{
|
MSG_ID_TO_CLASS_MAP = {{
|
||||||
|
|
|
||||||
|
|
@ -161,11 +161,9 @@ class HydrolinkMessage:
|
||||||
self._header.payload_length = len(self._payload)
|
self._header.payload_length = len(self._payload)
|
||||||
self._msg_buffer = self._header.pack() + self._payload
|
self._msg_buffer = self._header.pack() + self._payload
|
||||||
crc = CrcXmodem()
|
crc = CrcXmodem()
|
||||||
print(f"Computing crc over {[int(x) for x in self._msg_buffer]}")
|
|
||||||
crc.accumulate(self._msg_buffer)
|
crc.accumulate(self._msg_buffer)
|
||||||
crc.accumulate(struct.pack("B", crc_extra))
|
crc.accumulate(struct.pack("B", crc_extra))
|
||||||
self._crc = crc.crc
|
self._crc = crc.crc
|
||||||
print(f"Computed crc: {self._crc}")
|
|
||||||
self._msg_buffer += struct.pack("!H", self._crc)
|
self._msg_buffer += struct.pack("!H", self._crc)
|
||||||
return self._msg_buffer
|
return self._msg_buffer
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
<entry name="SWITCH">
|
<entry name="SWITCH">
|
||||||
<description>Command for getting/setting the state of a switch</description>
|
<description>Command for getting/setting the state of a switch</description>
|
||||||
</entry>
|
</entry>
|
||||||
<entry name="CMD_ID_PWM">
|
<entry name="PWM">
|
||||||
<description>Command for getting/setting the value of a PWM channel</description>
|
<description>Command for getting/setting the value of a PWM channel</description>
|
||||||
</entry>
|
</entry>
|
||||||
</enum>
|
</enum>
|
||||||
|
|
@ -37,7 +37,7 @@
|
||||||
<field type="uint8" name="cmd_id" enum="CMD_ID"></field>
|
<field type="uint8" name="cmd_id" enum="CMD_ID"></field>
|
||||||
<field type="uint8" name="index"></field>
|
<field type="uint8" name="index"></field>
|
||||||
</message>
|
</message>
|
||||||
<message id="3" name="GET_RESPONSE">
|
<message id="5" name="GET_RESPONSE">
|
||||||
<field type="uint8" name="cmd_id" enum="CMD_ID"></field>
|
<field type="uint8" name="cmd_id" enum="CMD_ID"></field>
|
||||||
<field type="uint8" name="result" enum="CMD_RESULT"></field>
|
<field type="uint8" name="result" enum="CMD_RESULT"></field>
|
||||||
<field type="int32" name="value"></field>
|
<field type="int32" name="value"></field>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue