Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Steven telemetry CAN autogen #343

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions libraries/codegen/bms_carrier_tx_all.c
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, saw you working on this yesterday! Gonna close this out but it looks like you're missing the 103 files, 101 and 102 are here. Let me know if you need help with anything!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this file is autogenerated when im playing around with the generator.py to see how it generates files. If I accidentally deleted something it might unintentional.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#include <stdint.h>

#include "can_board_ids.h"
#include "can_codegen.h"

static CanMessage s_msg = {
.type = CAN_MSG_TYPE_DATA,
};
static void prv_tx_can_message(CanMessageId id, uint8_t num_bytes, uint64_t data) {
s_msg.id.raw = id,
s_msg.dlc = num_bytes;
s_msg.data = data;
s_msg.extended = (s_msg.id.msg_id >= CAN_MSG_MAX_STD_IDS);
can_transmit(&s_msg);
}

void can_tx_all() {
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_STATUS,7,
(uint64_t) g_tx_struct.battery_status_fault << 0 |
(uint64_t) g_tx_struct.battery_status_fault_val << 16 |
(uint64_t) g_tx_struct.battery_status_aux_batt_v << 32 |
(uint64_t) g_tx_struct.battery_status_afe_status << 48);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_INFO,6,
(uint64_t) g_tx_struct.battery_info_fan1 << 0 |
(uint64_t) g_tx_struct.battery_info_fan2 << 8 |
(uint64_t) g_tx_struct.battery_info_max_cell_v << 16 |
(uint64_t) g_tx_struct.battery_info_min_cell_v << 32);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_VT,8,
(uint64_t) g_tx_struct.battery_vt_voltage << 0 |
(uint64_t) g_tx_struct.battery_vt_current << 16 |
(uint64_t) g_tx_struct.battery_vt_temperature << 32 |
(uint64_t) g_tx_struct.battery_vt_batt_perc << 48);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_RELAY_INFO,1,
(uint64_t) g_tx_struct.battery_relay_info_state << 0);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_AFE1_STATUS,8,
(uint64_t) g_tx_struct.AFE1_status_id << 0 |
(uint64_t) g_tx_struct.AFE1_status_temp << 8 |
(uint64_t) g_tx_struct.AFE1_status_v1 << 16 |
(uint64_t) g_tx_struct.AFE1_status_v2 << 32 |
(uint64_t) g_tx_struct.AFE1_status_v3 << 48);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_AFE2_STATUS,8,
(uint64_t) g_tx_struct.AFE2_status_id << 0 |
(uint64_t) g_tx_struct.AFE2_status_temp << 8 |
(uint64_t) g_tx_struct.AFE2_status_v1 << 16 |
(uint64_t) g_tx_struct.AFE2_status_v2 << 32 |
(uint64_t) g_tx_struct.AFE2_status_v3 << 48);
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_BMS_CARRIER_AFE3_STATUS,8,
(uint64_t) g_tx_struct.AFE3_status_id << 0 |
(uint64_t) g_tx_struct.AFE3_status_temp << 8 |
(uint64_t) g_tx_struct.AFE3_status_v1 << 16 |
(uint64_t) g_tx_struct.AFE3_status_v2 << 32 |
(uint64_t) g_tx_struct.AFE3_status_v3 << 48);
}
29 changes: 26 additions & 3 deletions libraries/codegen/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def check_yaml_file(data):
def get_data():
boards = []
messages = []

messages_dict = {}
for yaml_path in Path(__file__).parent.glob("boards/*.yaml"):
# read yaml
with open(yaml_path, "r") as f:
Expand Down Expand Up @@ -94,8 +94,31 @@ def get_data():
"receiver": message["target"],
})

return {"Boards": boards, "Messages": messages}
messages_dict[message["id"]] = {
"id": message["id"],
"critical": message["critical"],
"name": message_name,
"signals": signals,
"sender": sender,
"receiver": message["target"],
}

print("Boards:")
for board in boards:
print(f" - {board}")

print("\nMessages:")
for message in messages:
print(f"Message Name: {message['name']}")
print(f" ID: {message['id']}")
print(f" Critical: {message['critical']}")
print(f" Sender: {message['sender']}")
print(f" Receiver: {message['receiver']}")
print(" Signals:")
for signal in message['signals']:
print(f" - Name: {signal['name']}, Start Bit: {signal['start_bit']}, Length: {signal['length']}")

return {"Boards": boards, "Messages": messages, "Messages_dict": messages_dict}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice you're right this should speed things up, not a big deal for our regular autogen but definitely useful for telemetry.


def main():
parser = argparse.ArgumentParser()
Expand All @@ -119,6 +142,6 @@ def main():
output = env.get_template(template).render(data=data)
Path(output_dir, get_file_name(template, args.board)).write_text(output)


if __name__ == "__main__":
main()
3 changes: 1 addition & 2 deletions libraries/codegen/templates/_tx_all.c.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,4 @@ void can_tx_all() {
(uint64_t) g_tx_struct.{{message.name}}_{{signal.name}} << {{signal.start_bit}}{{ " |" if not loop.last }}
{%- endfor -%}
);
{%- endfor %}
}
{% }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the edit in the .c file?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Think when looking into the CAN message in C side and accidently changed something. Sorry about that.

50 changes: 50 additions & 0 deletions libraries/codegen/templates/python_autogen.py.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{% set bitstream = data["bitstream"] -%}
{% set messages_dict = data["Messages_dict"] -%}

def decode_packet(messages_dict, bitstream):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here does the user pass in the messages dict themselves?

You're right that maybe a quick sample app/unit test would be good and answer this question implicitly.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was also having a bit confusion in relation to this one. The jinja defines a python function that passes these two in as parameter, but currently they are located in generator.py. (data from get_data() that gets all the yaml files)

I am planning on after generating the python script, I just run python3 libraries/codegen/python_autogen.py with some arbitrary defined CAN messages in the main function. Something similar to this:

Define message values

# source_id = 1                 # source_id (3 + 4 bits)
# type_field = 0                # type (1 bit)
# msg_id = 3                    # msg_id (24 bits)
# dlc = 5 Bytes                 # (40 bits)
# throttle_output_value = 30    # throttle_value (32 bits)
# brake_output_value = 31       # brake_value (8 bits)
# print(decode_packet(data["Messages_dict"], "0000 0001 0000 0000 0000 0000 0000 0011 0000 0000 0000 0000 0000 0101 0000 0000 0000 0000 0000 0000 0001 1110 0001 1111"))

If eventually this python_autogen.py file will be in libraries/codegen, I'm thinking about just doing import data from generator.py to get the data array. Maybe I will look into this solution on Saturday in the bay.

# Clean the bitstream by removing spaces
clean_bitstream = bitstream.replace(" ", "")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, your function received a CAN frame right? Why are there spaces in the bitstream?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case something like 0000 0001 occurs, just removing the blank space in between.


# Extract the source_id (first 8 bits)
source_id_binary = clean_bitstream[0:8]
source_id = int(source_id_binary, 2) # Assuming it's a binary string
print(source_id)

# Extract the msg_id (next 24 bits)
msg_id_binary = clean_bitstream[8:32]
msg_id = int(msg_id_binary, 2) # Assuming it's a binary string
print(msg_id)

# Message definition
if 0 < msg_id <= 63:
message = messages_dict[msg_id]
else:
print(f"Message ID {msg_id} not found in messages dictionary.")
return

parsed_signals = []
data_start_bit = 56

# Iterate through each signal in the message dictionary
for signal in message['signals']:
name = signal['name']
start_bit = signal['start_bit'] + data_start_bit
length = signal['length']

# Extract the relevant bits for the signal
signal_bits = clean_bitstream[start_bit:start_bit + length]

# Convert the bits to a decimal value
signal_value = int(signal_bits, 2) # Assuming it's a binary string

# Store the parsed signal value
parsed_signals.append({
"name": name,
"value": signal_value
})

return {
"message ID": msg_id,
"message name": message["name"],
"signals": parsed_signals
}
Loading