Skip to content

Commit

Permalink
Simulation infra (#15)
Browse files Browse the repository at this point in the history
* Simulation infra and can stuff

* bootloader and simulation
  • Loading branch information
Akashem06 authored Jan 8, 2025
1 parent e52976f commit da9cc47
Show file tree
Hide file tree
Showing 115 changed files with 8,983 additions and 132 deletions.
6 changes: 1 addition & 5 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,13 @@ elif COMMAND == "new":
SConscript('scons/new_target.scons', exports='VARS')

###########################################################
# hil command
# HIL command
###########################################################
elif COMMAND == "hil":
print(TEST_FILE)
if not TEST_FILE:
#Error handling
pass

SConscript('scons/pytest.scons', exports='VARS')


###########################################################
# Clean
###########################################################
Expand Down
21 changes: 18 additions & 3 deletions autogen/can_autogen.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## @file can_autogen.py
# @date 2024-12-21
# @author Midnight Sun Team #24 - MSXVI
# @author Aryan Kashem
# @brief YAML parsing and validation module for CAN message configurations
#
# @details This module provides functionality to parse and validate CAN message
Expand Down Expand Up @@ -94,6 +94,12 @@ def get_data(args):
"""
boards = []
messages = []
message_count = {
"fast_cycle" : 0,
"medium_cycle" : 0,
"slow_cycle" : 0,
"total" : 0,
}

for yaml_path in Path("can/boards").glob("*.yaml"):
# read yaml
Expand Down Expand Up @@ -134,9 +140,18 @@ def get_data(args):
"receiver": message["target"],
})

# Update message counter
if message["cycle"] == "fast":
message_count["fast_cycle"] += 1
elif message["cycle"] == "medium":
message_count["medium_cycle"] += 1
elif message["cycle"] == "slow":
message_count["slow_cycle"] += 1

message_count["total"] +=1

project_name = Path(args.output).parent.stem

current_date = datetime.now()
current_date = current_date.strftime("%Y-%m-%d")

return {"boards": boards, "messages": messages, "project_name": project_name, "current_date": current_date}
return {"boards": boards, "messages": messages, "message_count": message_count, "project_name": project_name, "current_date": current_date}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ extern rx_struct g_rx_struct;
extern tx_struct g_tx_struct;

void can_tx_all();
void can_tx_fast_cycle();
void can_tx_medium_cycle();
void can_tx_slow_cycle();

void can_rx_all();

/** @} */
95 changes: 90 additions & 5 deletions autogen/templates/project_can/src/{{project_name}}_rx_all.c.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -53,26 +53,111 @@ void can_rx_all() {
}
}

void clear_rx_received() {
void clear_all_rx_received() {
{%- for message in messages %}
g_rx_struct.received_{{message.name}} = false;
{%- endfor %}
}

StatusCode check_can_watchdogs() {
void clear_fast_rx_received() {
{%- for message in messages %}
{%- if message.cycle == "fast" %}
g_rx_struct.received_{{message.name}} = false;
{%- endif %}
{%- endfor %}
}

void clear_medium_rx_received() {
{%- for message in messages %}
{%- if message.cycle == "medium" %}
g_rx_struct.received_{{message.name}} = false;
{%- endif %}
{%- endfor %}
}

void clear_slow_rx_received() {
{%- for message in messages %}
{%- if message.cycle == "slow" %}
g_rx_struct.received_{{message.name}} = false;
{%- endif %}
{%- endfor %}
}

StatusCode check_all_can_watchdogs() {
{%- for message in messages %}
{%- if message.receiver[project_name].watchdog != 0 %}
if (!g_rx_struct.received_{{message.name}}) {
++s_{{message.name}}_msg_watchdog.cycles_over;
if (s_{{message.name}}_msg_watchdog.cycles_over >= s_{{message.name}}_msg_watchdog.max_cycles) {
LOG_CRITICAL("DID NOT RECEIVE CAN MESSAGE: %u IN MAX CYCLES : %u\n", SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
s_{{message.name}}_msg_watchdog.max_cycles);
s_{{message.name}}_msg_watchdog.missed = 1;
s_{{message.name}}_msg_watchdog.missed = true;
} else {
s_{{message.name}}_msg_watchdog.missed = 0;
s_{{message.name}}_msg_watchdog.missed = false;
}
}
{%- endif %}
{%- endfor %}
return STATUS_CODE_OK;
}
}

StatusCode check_fast_can_watchdogs() {
{%- for message in messages %}
{%- if message.cycle == "fast" %}
{%- if message.receiver[project_name].watchdog != 0 %}
if (!g_rx_struct.received_{{message.name}}) {
++s_{{message.name}}_msg_watchdog.cycles_over;
if (s_{{message.name}}_msg_watchdog.cycles_over >= s_{{message.name}}_msg_watchdog.max_cycles) {
LOG_CRITICAL("DID NOT RECEIVE FAST CYCLE CAN MESSAGE: %u IN MAX CYCLES : %u\n", SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
s_{{message.name}}_msg_watchdog.max_cycles);
s_{{message.name}}_msg_watchdog.missed = true;
} else {
s_{{message.name}}_msg_watchdog.missed = false;
}
}
{%- endif %}
{%- endif %}
{%- endfor %}
return STATUS_CODE_OK;
}

StatusCode check_medium_can_watchdogs() {
{%- for message in messages %}
{%- if message.cycle == "medium" %}
{%- if message.receiver[project_name].watchdog != 0 %}
if (!g_rx_struct.received_{{message.name}}) {
++s_{{message.name}}_msg_watchdog.cycles_over;
if (s_{{message.name}}_msg_watchdog.cycles_over >= s_{{message.name}}_msg_watchdog.max_cycles) {
LOG_CRITICAL("DID NOT RECEIVE MEDIUM CYCLE CAN MESSAGE: %u IN MAX CYCLES : %u\n", SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
s_{{message.name}}_msg_watchdog.max_cycles);
s_{{message.name}}_msg_watchdog.missed = true;
} else {
s_{{message.name}}_msg_watchdog.missed = false;
}
}
{%- endif %}
{%- endif %}
{%- endfor %}
return STATUS_CODE_OK;
}

StatusCode check_slow_can_watchdogs() {
{%- for message in messages %}
{%- if message.cycle == "slow" %}
{%- if message.receiver[project_name].watchdog != 0 %}
if (!g_rx_struct.received_{{message.name}}) {
++s_{{message.name}}_msg_watchdog.cycles_over;
if (s_{{message.name}}_msg_watchdog.cycles_over >= s_{{message.name}}_msg_watchdog.max_cycles) {
LOG_CRITICAL("DID NOT RECEIVE SLOW CAN MESSAGE: %u IN MAX CYCLES : %u\n", SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
s_{{message.name}}_msg_watchdog.max_cycles);
s_{{message.name}}_msg_watchdog.missed = true;
} else {
s_{{message.name}}_msg_watchdog.missed = false;
}
}
{%- endif %}
{%- endif %}
{%- endfor %}
return STATUS_CODE_OK;
}

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
/* Intra-component Headers */
#include "can_codegen.h"
{% set messages = messages | selectattr("sender", "eq", project_name) | list -%}

static CanMessage s_msg = { 0U };

static void prv_tx_can_message(CanMessageId id, uint8_t num_bytes, uint64_t data) {
Expand All @@ -37,4 +38,46 @@ void can_tx_all() {
{%- endfor -%}
);
{%- endfor %}
}
}

void can_tx_fast_cycle() {
{%- for message in messages %}
{%- if message.cycle == "fast" %}
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
{{- (message.signals | sum(attribute='length') / 8) | int }},
{%- for signal in message.signals %}
(uint64_t) g_tx_struct.{{message.name}}_{{signal.name}} << {{signal.start_bit}}{{ " |" if not loop.last }}
{%- endfor -%}
);
{%- endif %}
{%- endfor %}
}

void can_tx_medium_cycle() {
{%- for message in messages %}
{%- if message.cycle == "medium" %}
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
{{- (message.signals | sum(attribute='length') / 8) | int }},
{%- for signal in message.signals %}
(uint64_t) g_tx_struct.{{message.name}}_{{signal.name}} << {{signal.start_bit}}{{ " |" if not loop.last }}
{%- endfor -%}
);
{%- endif %}
{%- endfor %}
}

void can_tx_slow_cycle() {
{%- for message in messages %}
{%- if message.cycle == "slow" %}
prv_tx_can_message(
SYSTEM_CAN_MESSAGE_{{message.sender | upper}}_{{message.name | upper}},
{{- (message.signals | sum(attribute='length') / 8) | int }},
{%- for signal in message.signals %}
(uint64_t) g_tx_struct.{{message.name}}_{{signal.name}} << {{signal.start_bit}}{{ " |" if not loop.last }}
{%- endfor -%}
);
{%- endif %}
{%- endfor %}
}
Empty file.
145 changes: 145 additions & 0 deletions autogen/templates/simulation_app/inc/can_scheduler.h.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#pragma once

/************************************************************************************************
* @file can_scheduler.h
*
* @brief Header file defining the CanScheduler class
*
* @date 2025-01-04
* @author Aryan Kashem
************************************************************************************************/

/** @warning This file is autogenerated */

/* Standard library Headers */
#include <atomic>
#include <string>

/* Inter-component Headers */
#include <arpa/inet.h>
#include <fcntl.h>
#include <linux/can.h>
#include <linux/can/bcm.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>

/* Intra-component Headers */

/**
* @defgroup CanScheduler
* @brief SocketCAN Broadcast Manager abstraction class
* @{
*/
{% set messages = messages | list %}
/**
* @class CanScheduler
* @brief Class that handles message scheduling over a SocketCAN interface
* @details This class is responsible scheduling CAN messages based on their cycle speed
* Only 3 cycle speeds are supported, Fast (1kHz), medium (10Hz) and slow (1Hz)
* The class shall support message updating during run-time for further bus simulation
*/
class CanScheduler {
private:
const std::string CAN_INTERFACE_NAME = "vcan0"; /**< SocketCAN interface name */

static const constexpr unsigned int FAST_CYCLE_SPEED_MS = 1U; /**< CAN fast cycle period in milliseconds */
static const constexpr unsigned int MEDIUM_CYCLE_SPEED_MS = 100U; /**< CAN medium cycle period in milliseconds */
static const constexpr unsigned int SLOW_CYCLE_SPEED_MS = 1000U; /**< CAN slow cycle period in milliseconds */

static const constexpr unsigned int SLOW_CYCLE_BCM_ID = 0U; /**< Linux Broadcast Manager Id for tracking fast cycle messages */
static const constexpr unsigned int MEDIUM_CYCLE_BCM_ID = 1U; /**< Linux Broadcast Manager Id for tracking medium cycle messages */
static const constexpr unsigned int FAST_CYCLE_BCM_ID = 2U; /**< Linux Broadcast Manager Id for tracking slow cycle messages */

static const constexpr unsigned int NUM_FAST_CYCLE_MESSAGES = {{ message_count.fast_cycle }}U; /**< Number of fast cycle messages */
static const constexpr unsigned int NUM_MEDIUM_CYCLE_MESSAGES = {{ message_count.medium_cycle }}U; /**< Number of medium cycle messages */
static const constexpr unsigned int NUM_SLOW_CYCLE_MESSAGES = {{ message_count.slow_cycle }}U; /**< Number of slow cycle messages */
static const constexpr unsigned int NUM_TOTAL_MESSAGES = {{ message_count.total }}U; /**< Total number of messages */
static const constexpr unsigned int MAX_MESSAGE_LENGTH = 8U; /**< Max message length in bytes */

{% set fast_message = namespace(count = 0) %}
{%- for message in messages %}
{%- if message.cycle == "fast" %}
static const constexpr unsigned int FAST_{{ message.sender | upper }}_{{ message.name | upper }}_FRAME_INDEX = {{ fast_message.count }}U; /**< Broadcast Manager {{ message.name | lower }} to Frame index mapping */
{%- set fast_message.count = fast_message.count + 1 %}
{%- endif %}
{%- endfor %}

{% set medium_message = namespace(count = 0) %}
{%- for message in messages %}
{%- if message.cycle == "medium" %}
static const constexpr unsigned int MEDIUM_{{ message.sender | upper }}_{{ message.name | upper }}_FRAME_INDEX = {{ medium_message.count }}U; /**< Broadcast Manager {{ message.name | lower }} to Frame index mapping */
{%- set medium_message.count = medium_message.count + 1 %}
{%- endif %}
{%- endfor %}

{% set slow_message = namespace(count = 0) %}
{%- for message in messages %}
{%- if message.cycle == "slow" %}
static const constexpr unsigned int SLOW_{{ message.sender | upper }}_{{ message.name | upper }}_FRAME_INDEX = {{ slow_message.count }}U; /**< Broadcast Manager {{ message.name | lower }} to Frame index mapping */
{%- set slow_message.count = slow_message.count + 1 %}
{%- endif %}
{%- endfor %}

/**
* @brief Fast cycle Broadcast Manager message for the Linux Kernel
*/
struct {
struct bcm_msg_head msg_head; /**< Broadcast Manager message head containing metadata */
struct can_frame frame[NUM_FAST_CYCLE_MESSAGES]; /**< CAN message frames that shall be scheduled for fast cycle */
} canFastCycleBCM;

/**
* @brief Medium cycle Broadcast Manager message for the Linux Kernel
*/
struct {
struct bcm_msg_head msg_head; /**< Broadcast Manager message head containing metadata */
struct can_frame frame[NUM_MEDIUM_CYCLE_MESSAGES]; /**< CAN message frames that shall be scheduled for medium cycle */
} canMediumCycleBCM;

/**
* @brief Slow cycle Broadcast Manager message for the Linux Kernel
*/
struct {
struct bcm_msg_head msg_head; /**< Broadcast Manager message head containing metadata */
struct can_frame frame[NUM_SLOW_CYCLE_MESSAGES]; /**< CAN message frames that shall be scheduled for slow cycle */
} canSlowCycleBCM;

int m_bcmCanSocket; /**< The CAN schedulers Broadcast Manager socket FD */
std::atomic<bool> m_isConnected; /**< Boolean flag to track the CAN schedulers connection status */

/**
* @brief Schedules all CAN data by updating the Broacast Manager socket
* @details This function is called by startCanScheduler
* This function shall initialize all CAN message values to 0
*/
void scheduleCanMessages();

public:
/**
* @brief Constructs a CanScheduler object
* @details Initializes the CanScheduler. The constructor sets up internal variables
*/
CanScheduler();

/**
* @brief Starts the CAN scheduler and sets all messages to 0. Must only be called once
* @details This function will connect to the Linux Broadcast Manager
* This function must only be called once, and it will set all messages to 0
*/
void startCanScheduler();

{%- for message in messages %}
{%- for signal in message.signals %}
/**
* @brief Update the CAN value for {{ message.name | lower }} {{ signal.name | lower }}
* @param {{ signal.name | lower }}_value New value for the signal
*/
void update_{{ message.name | lower }}_{{ signal.name | lower }}(uint{{ signal.length }}_t {{ signal.name | lower }}_value);
{%- endfor %}
{%- endfor %}
};

/** @} */
Loading

0 comments on commit da9cc47

Please sign in to comment.