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

Better better autogen #260

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 16 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
11 changes: 6 additions & 5 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -164,14 +164,14 @@ if PLATFORM == 'x86' and TARGET:
# os.exec the x86 project ELF file to simulate it

def sim_run(target, source, env):
print('Simulating', project_elf)
subprocess.run([project_elf.path])
print('Simulating', source)
subprocess.run([source.path])

AlwaysBuild(Command('#/sim', project_elf, sim_run))

# open gdb with the elf file
def gdb_run(target, source, env):
subprocess.run(['/usr/bin/gdb', project_elf.path])
subprocess.run(['/usr/bin/gdb', source.path])

AlwaysBuild(Command('#/gdb', project_elf, gdb_run))

Expand All @@ -188,9 +188,10 @@ if PLATFORM == 'arm' and TARGET:

# flash the MCU using openocd
def flash_run_target(target, source, env):
serialData = flash_run(project_bin)
serialData = flash_run(source)
print("\nSerial output:")
while True:
line: str = serialData.readline().decode("utf-8")
print(line, end='')

AlwaysBuild(Command('#/flash', project_bin, flash_run_target))
AlwaysBuild(Command('#/flash', project_bin, flash_run_target))
52 changes: 52 additions & 0 deletions autogen/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import argparse
import jinja2
from pathlib import Path


def get_file_name(template_name, board):
# get the name of the jinja file from the filepath
jinja_prefix = Path(template_name).stem
# files that start with _ are generic and we want to prepend the board name
if jinja_prefix.startswith('_') and board != None:
return board + jinja_prefix
else:
return jinja_prefix


def main():
parser = argparse.ArgumentParser()
parser.add_argument("template_name")
parser.add_argument("-o", dest="output", required=True, metavar="DIR")

args = parser.parse_args()

if args.template_name in ["can", "can_board_ids", "python_can"]:
from .can import get_data
elif args.template_name in ["test"]:
from .test import get_data
elif args.template_name in ["new", "new_py"]:
from .new import get_data
elif args.template_name in ["new_task"]:
from .new_task import get_data

data = get_data(args)

template_dir = Path("autogen/templates", args.template_name)
template_loader = jinja2.FileSystemLoader(searchpath=template_dir)
env = jinja2.Environment(loader=template_loader)
env.tests["contains"] = (lambda list, var: (var in list))

for template in template_dir.glob("**/*.jinja"):
template_path = str(template.relative_to(template_dir))

output = env.get_template(template_path).render(**data)
output_file_name = env.from_string(template_path).render(**data)
output_file = Path(args.output, output_file_name).with_suffix("")
output_file.parent.mkdir(parents=True, exist_ok=True)
output_file.write_text(output)

print("Done autogenerating")


if __name__ == "__main__":
main()
52 changes: 10 additions & 42 deletions libraries/codegen/generator.py → autogen/can.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,8 @@
import argparse
import jinja2
import yaml
import re
import yaml
from pathlib import Path


def get_file_name(template_name, board):
# get the name of the jinja file from the filepath
jinja_prefix = Path(template_name).stem
# files that start with _ are generic and we want to prepend the board name
if jinja_prefix.startswith('_') and board != None:
return board + jinja_prefix
else:
return jinja_prefix


def check_yaml_file(data):
illegal_chars_regex = re.compile('[@!#$%^&*()<>?/\|}{~:]')
message_ids = set()
Expand Down Expand Up @@ -55,11 +43,16 @@ def check_yaml_file(data):
raise Exception("Message must be 64 bits or less")


def get_data():
def get_data(args):
'''
get data to generate the can files for a board
expect args.output to be .../<target-type>/<target-name>/can
where <target-type> is one of libraries/projects/smoke
'''
boards = []
messages = []

for yaml_path in Path(__file__).parent.glob("boards/*.yaml"):
for yaml_path in Path("can/boards").glob("*.yaml"):
# read yaml
with open(yaml_path, "r") as f:
data = yaml.load(f, Loader=yaml.FullLoader)
Expand Down Expand Up @@ -92,31 +85,6 @@ def get_data():
"receiver": message["target"],
})

return {"Boards": boards, "Messages": messages}


def main():
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--template", nargs='+', default=[], dest="templates",
action="append", help="template file to populate", metavar="FILE")
parser.add_argument("-f", "--file_path", default=[], dest="outputs",
action="append", help="output directory path", metavar="DIR")
parser.add_argument("-b", dest="board", default=None)

args = parser.parse_args()
data = get_data()
data.update({"Board": args.board})

template_loader = jinja2.FileSystemLoader(
searchpath=Path(__file__).parent.joinpath("templates").as_posix())
env = jinja2.Environment(loader=template_loader)
env.tests["contains"] = (lambda list, var: (var in list))

for output_dir, templates in zip(args.outputs, args.templates):
for template in templates:
output = env.get_template(template).render(data=data)
Path(output_dir, get_file_name(template, args.board)).write_text(output)

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

if __name__ == "__main__":
main()
return {"boards": boards, "messages": messages, "board": board}
20 changes: 20 additions & 0 deletions autogen/new.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from pathlib import Path


def get_data(args):
project_name = Path(args.output).stem
project_type = Path(args.output).parent.stem

libs = []
if project_type in ["projects", "smoke"]:
# default libs
libs = ["FreeRTOS", "ms-common"]

if project_type == "py":
args.template_name = "new_py"

if Path(args.output).exists():
raise (f"{project_type}/{project_name} already exists")

return {"proj_name": project_name, "libs": libs }

10 changes: 10 additions & 0 deletions autogen/new_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pathlib import Path


def get_data(args):
task_name = Path(args.output).stem
proj_name = Path(args.output).parent.stem

args.output = str(Path(args.output).parent)

return {"proj_name": proj_name, "task_name": task_name}
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
{% set board = data["Board"] -%}

#pragma once

#include "{{board}}_rx_structs.h"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("receiver", "contains", board) | list -%}
{% set messages = messages | selectattr("receiver", "contains", board) | list -%}

#pragma once

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("receiver", "contains", board) | list -%}
{% set messages = messages | selectattr("receiver", "contains", board) | list -%}

#pragma once

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("receiver", "contains", board) | list -%}
{% set messages = messages | selectattr("receiver", "contains", board) | list -%}

#pragma once

#include <stdint.h>
#include <stdbool.h>
#include "can_watchdog.h"

{% for message in messages %}
{%- if message.receiver[board].watchdog != 0 %}
#define check_{{message.name}}_msg_watchdog() \
s_{{message.name}}_msg_watchdog.missed
{%- endif %}
{%- endfor %}
#include "can_watchdog.h"

typedef struct
{
Expand All @@ -28,6 +21,9 @@ typedef struct

{% for message in messages %}
{%- if message.receiver[board].watchdog != 0 %}
#define check_{{message.name}}_msg_watchdog() \
s_{{message.name}}_msg_watchdog.missed

extern CanWatchDog s_{{message.name}}_msg_watchdog;
{%- endif %}
{%- endfor %}
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("sender", "eq", board) | list -%}
{% set messages = messages | selectattr("sender", "eq", board) | list -%}

#pragma once

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("sender", "eq", board) | list -%}
{% set messages = messages | selectattr("sender", "eq", board) | list -%}

#pragma once

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("receiver", "contains", board) | list -%}
{% set messages = messages | selectattr("receiver", "contains", board) | list -%}

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

{% for message in messages %}
{%- for message in messages %}
{%- if message.receiver[board].watchdog != 0 %}
CanWatchDog s_{{message.name}}_msg_watchdog = {0, {{message.receiver[board].watchdog | lower}}, 0};
{%- endif %}
Expand Down Expand Up @@ -43,7 +42,6 @@ void clear_rx_received() {
}

StatusCode check_can_watchdogs() {
StatusCode status = STATUS_CODE_OK;
{%- for message in messages %}
{%- if message.receiver[board].watchdog != 0 %}
if (!g_rx_struct.received_{{message.name}}) {
Expand All @@ -52,14 +50,11 @@ StatusCode check_can_watchdogs() {
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;
status = STATUS_CODE_TIMEOUT;
} else {
s_{{message.name}}_msg_watchdog.missed = 0;
}
} else {
s_{{message.name}}_msg_watchdog.cycles_over = 0;
s_{{message.name}}_msg_watchdog.missed = 0;
}
{%- endif %}
{%- endfor %}
return status;
return STATUS_CODE_OK;
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{% set board = data["Board"] -%}
{% set messages = data["Messages"] | selectattr("sender", "eq", board) | list -%}
{% set messages = messages | selectattr("sender", "eq", board) | list -%}

#include <stdint.h>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{% set boards = data["Boards"] -%}
{% set messages = data["Messages"] -%}

#pragma once
#include <stdbool.h>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
{% set boards = data["Boards"] -%}
{% set messages = data["Messages"] -%}

NS_ :
NS_DESC_
CM_
Expand Down Expand Up @@ -34,7 +31,7 @@ NS_ :
BS_:

BU_:
{%- for board in boards %} {{board|upper}} {%- endfor %}
{%- for board in boards %} {{ board | upper }} {%- endfor %}

{% for message in messages -%}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ A README for a board project (powering a hardware board, e.g. power distribution
- How does it fit into the overall system?
- How does it work? (architectural overview, e.g. what each module's purpose is or how data flows through the firmware)
-->
#
# {{ proj_name }}
8 changes: 8 additions & 0 deletions autogen/templates/new/config.json.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"libs": [
{%- for lib in libs %}
"{{ lib }}"{{ "," if not loop.last }}
{%- endfor %}
],
"can": false
}
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ void run_slow_cycle() {}
int main() {
tasks_init();
log_init();
LOG_DEBUG("Welcome to TEST!");
LOG_DEBUG("Welcome to {{ proj_name }}!");

init_master_task();

tasks_start();

LOG_DEBUG("exiting main?");
return 0;
}
}
11 changes: 11 additions & 0 deletions autogen/templates/new/test/test.c.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdio.h>

#include "unity.h"

void setup_test(void) {}

void teardown_test(void) {}

void test_example(void) {
TEST_ASSERT_TRUE(true);
}
Empty file.
3 changes: 3 additions & 0 deletions autogen/templates/new_py/config.json.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"can": false
}
6 changes: 6 additions & 0 deletions autogen/templates/new_py/main.py.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

def main():
print("Welcome to {{ proj_name }}")

if __name__ == "__main__":
main()
14 changes: 14 additions & 0 deletions autogen/templates/new_task/inc/{{task_name}}.h.jinja
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "status.h"

/*
* Name: {{ task_name }}
* Description: What this task does and to use it
* Author: <who ever wrote this>
* Date: <date last editted>
*/

void run_{{ task_name }}_cycle();
void run_{{ task_name }}_fast_cycle();
void run_{{ task_name }}_medium_cycle();
void run_{{ task_name }}_slow_cycle();
StatusCode init_{{ task_name }}();
Loading
Loading