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

Gabriel edits #23

Open
wants to merge 17 commits into
base: master
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
12 changes: 2 additions & 10 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,8 @@ compile_commands.json
*.pyc

# Files that should be written from CAN spec
src/constants.h
src/pack_unpack.c
src/pack_unpack.h
src/enum_atom.h
src/structs.h
src/computers/
src/send_receive.c
src/bus.h
src/drivers/inc/
src/test/
src/*
src/**
**/*.o
**/*.out

Expand Down
10 changes: 0 additions & 10 deletions generator/computers_c.py

This file was deleted.

10 changes: 10 additions & 0 deletions generator/computers_cpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import os


def write(env, computers, input_path, output_path, testing):
os.makedirs(output_path, exist_ok=True)
template = env.get_template(str(input_path))
for computer in computers:
f_path = os.path.join(output_path, 'canlib_{}.cpp'.format(computer.name))
with open(f_path, 'w') as f:
f.write(template.render(computer=computer, testing=testing))
reality95 marked this conversation as resolved.
Show resolved Hide resolved
11 changes: 0 additions & 11 deletions generator/computers_h.py

This file was deleted.

11 changes: 11 additions & 0 deletions generator/computers_hpp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import os


def write(env, computers, input_path, output_path, testing):
os.makedirs(output_path, exist_ok=True)
template = env.get_template(str(input_path))

for computer in computers:
f_path = os.path.join(output_path, 'canlib_{}.hpp'.format(computer.name))
with open(f_path, 'w') as f:
f.write(template.render(computer=computer, testing=testing))
9 changes: 5 additions & 4 deletions generator/drivers_inc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,17 @@ def find_architecture(system, template):
return None


def write(env, system, input_path, output_path):
def write(env, system, input_path, output_path, testing = False):
input_path = Path(input_path)
output_path = Path(output_path)
output_path.mkdir(parents=True, exist_ok=True)

for template_path in input_path.glob('*'):
architecture_name = template_path.stem.strip('.h')
architecture_name = template_path.stem.strip('.hpp')
architecture = find_architecture(system, architecture_name)
output_file = output_path.joinpath(template_path.stem)

template = env.get_template(str(template_path))
with open(output_file, 'w') as f:
f.write(template.render(architecture=architecture))
if (testing == (architecture_name == 'testfamily')):
with open(output_file, 'w') as f:
f.write(template.render(architecture=architecture))
reality95 marked this conversation as resolved.
Show resolved Hide resolved
111 changes: 75 additions & 36 deletions generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,38 @@
import ParseCAN.ParseCAN as ParseCAN

import constants
import computers_h
import computers_c
import computers_hpp
import computers_cpp
import drivers_inc


src_dir = Path('../src/')
constants_path = src_dir.joinpath('constants.h')
drivers_inc_dir_path = src_dir.joinpath('drivers/inc')
computer_h_dir_path = src_dir.joinpath('computers/inc')
computer_c_dir_path = src_dir.joinpath('computers/src')
src_dir = Path('../src/src/')
inc_dir = Path('../src/inc/')
drivers_inc_dir_path = inc_dir.joinpath('drivers/')
computer_hpp_dir_path = inc_dir.joinpath('computers/')
computer_cpp_dir_path = src_dir.joinpath('computers/')

template_dir = Path('./templates/')
computer_c_template_path = template_dir.joinpath('computer.c.j2')
computer_h_template_path = template_dir.joinpath('computer.h.j2')
constants_template_path = template_dir.joinpath('constants.h.j2')
computer_cpp_template_path = template_dir.joinpath('computer.cpp.j2')
computer_hpp_template_path = template_dir.joinpath('computer.hpp.j2')
drivers_inc_template_dir_path = template_dir.joinpath('drivers/inc')

from pint import UnitRegistry
def get_ms(period_str):
if type(period_str) is int:
# If it's set as an integer, assume ms
return period_str

ur = UnitRegistry()
return (int)(ur[period_str].to('ms').magnitude)

def get_num_msg_types(msg):
if hasattr(msg, "frame"):
return 1 + sum([get_num_msg_types(sub_frame) for sub_frame in msg.frame])
return 1
reality95 marked this conversation as resolved.
Show resolved Hide resolved

def get_len(can):
return len(can.bus)

# FROM: https://github.com/duelafn/python-jinja2-apci/blob/master/jinja2_apci/error.py
class RaiseExtension(Extension):
Expand All @@ -51,37 +66,61 @@ def parse(self, parser):
def _raise(self, msg, caller):
raise TemplateRuntimeError(msg)


def render_template_from_to(env, input_path, output_path):
template = env.get_template(str(input_path))
with open(output_path, 'w') as f:
f.write(template.render())

if output_path in [inc_dir.joinpath("structs.hpp"), src_dir.joinpath("structs.cpp")]:
f.write(template.render(get_len = get_len, get_ms = get_ms, get_num_msg_types = get_num_msg_types))
else:
f.write(template.render(get_len = get_len))

def render_template(env, relative_path):
render_template_from_to(env, template_dir.joinpath(f"{relative_path}.j2"), src_dir.joinpath(relative_path))
if relative_path.endswith('hpp') or relative_path.endswith('h'):
render_template_from_to(env, template_dir.joinpath(f"{relative_path}.j2"), inc_dir.joinpath(relative_path))
else:
render_template_from_to(env, template_dir.joinpath(f"{relative_path}.j2"), src_dir.joinpath(relative_path))


if __name__ == '__main__':
specpath = sys.argv[1]
specfile = open(specpath, 'r')
system = ParseCAN.spec.System.from_yaml(specfile)
can = system.protocol['name']['can']

script_dir = os.path.dirname(sys.argv[0])
if script_dir == '':
script_dir = '.'
os.chdir(script_dir)

template_loader = jinja2.FileSystemLoader(searchpath=".")
template_env = jinja2.Environment(loader=template_loader, keep_trailing_newline=True, extensions=[RaiseExtension])
template_env.globals["can"] = can
template_env.globals["system"] = system

for filename in ["pack_unpack.c", "pack_unpack.h", "enum_atom.h", "send_receive.c", "structs.h", "bus.h"]:
render_template(template_env, filename)

constants.write(template_env, constants_template_path, constants_path)
computers_h.write(template_env, system.computer, computer_h_template_path, computer_h_dir_path)
computers_c.write(template_env, system.computer, computer_c_template_path, computer_c_dir_path)
drivers_inc.write(template_env, system, drivers_inc_template_dir_path, drivers_inc_dir_path)
pth = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..')
spth = str(pth)
if '--clean' in sys.argv:
os.system("rm " + spth + "/src/inc/computers/*.hpp")
os.system("rm " + spth + "/src/inc/drivers/*.hpp")
os.system("rm " + spth + "/src/inc/bus.hpp " + spth + "/src/inc/pack_unpack.hpp " + spth + "/src/inc/structs.hpp")
os.system("rm " + spth + "/src/src/computers/*.cpp")
os.system("rm " + spth + "/src/src/bus.cpp " + spth + "/src/src/pack_unpack.cpp " + spth + "/src/src/structs.cpp")
else:
specpath = sys.argv[1]
specfile = open(specpath, 'r')
system = ParseCAN.spec.System.from_yaml(specfile)
can = system.protocol['name']['can']

script_dir = os.path.dirname(sys.argv[0])
if script_dir == '':
script_dir = '.'
os.chdir(script_dir)

template_loader = jinja2.FileSystemLoader(searchpath=".")
template_env = jinja2.Environment(loader=template_loader, keep_trailing_newline=True, extensions=[RaiseExtension])
template_env.globals["can"] = can
template_env.globals["system"] = system

for filename in ["pack_unpack.cpp", "pack_unpack.hpp", "structs.hpp", "bus.hpp", "bus.cpp", "structs.cpp"]:
render_template(template_env, filename)

testing = '--testing' in sys.argv
computers_hpp.write(template_env, system.computer, computer_hpp_template_path, computer_hpp_dir_path, testing)
computers_cpp.write(template_env, system.computer, computer_cpp_template_path, computer_cpp_dir_path, testing)
drivers_inc.write(template_env, system, drivers_inc_template_dir_path, drivers_inc_dir_path, testing)
clang_style = ""
styles = [arg for arg in sys.argv if arg.startswith('style=')]
if len(styles) > 0:
clang_style = styles[0]
try:
os.system('clang-format -i ' + clang_style + ' ' + spth + '/src/inc/drivers/*.hpp ' + spth + '/src/src/drivers/*.cpp')
os.system('clang-format -i ' + clang_style + ' ' + spth + '/src/inc/computers/*.hpp ' + spth + '/src/src/computers/*.cpp')
os.system('clang-format -i ' + clang_style + ' ' + spth + '/src/inc/*.hpp')
os.system('clang-format -i ' + clang_style + ' ' + spth + '/src/src/*.cpp')
except:
print('Error during clang-format, is it installed?')
68 changes: 68 additions & 0 deletions generator/templates/bus.cpp.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{%- macro key_type(num_bits) -%} uint{{ (((num_bits / 8) | round(method='ceil')) * 8) | int }}_t {%- endmacro -%}

{%- macro last_sent_def(bus, msg, msg_name) -%}
{%- if msg.frame is defined -%}
{% for sub_frame in msg.frame -%}
{{ last_sent_def(bus, sub_frame, msg_name + '::' + sub_frame.name) }}
reality95 marked this conversation as resolved.
Show resolved Hide resolved
{%- endfor %}
{%- else -%}
Clock::time_point {{msg_name}}::last_sent_;
{%- endif %}
{%- endmacro -%}

#include "static.hpp"
#include "bus.hpp"
#include "structs.hpp"
#include "pack_unpack.hpp"

namespace CANlib {

extern const std::pair<uint32_t, uint32_t>* frame_id_range[{{ get_len(can) }}];
extern const uint32_t* frame_len[{{ get_len(can) }}];
extern const uint32_t* keys[{{ get_len(can) }}];
extern const size_t can_size[{{ get_len(can) }}];
extern Message** messages[{{ get_len(can) }}];

{% for bus in can.bus %}
{{ last_sent_def(bus, bus, bus.name) }}
{% endfor %}

}

using namespace CANlib;

static uint32_t identify_internal(const uint32_t key, const Frame& frame, int l, int r, int bus_idx) {
for (int i = l;i <= r;++i) {
if (keys[bus_idx][i] == key) {
int left_bound = frame_id_range[bus_idx][i].first;
int right_bound = frame_id_range[bus_idx][i].second;
// If this is a frame search inside the frame, otherwise return the index of the message
if (left_bound <= right_bound) {
uint64_t bitstring;
to_bitstring((uint8_t*)frame.data, &bitstring);
return identify_internal(EXTRACT(bitstring, left_bound, right_bound), frame, i + 1, i + 1 + frame_len[bus_idx][i], bus_idx);
} else {
return i;
}
}
}
return 0;
}


uint32_t CANlib::identify(AbstractBus bus, const Frame& frame) {
const int bus_idx = static_cast<int>(bus);
return identify_internal(frame.id, frame, 1, can_size[bus_idx] - 1, bus_idx);
}

void CANlib::handle_frame(AbstractBus bus_name, const Frame& frame) {
if (bus_name == AbstractBus::INVALID_NAME) {
return;
reality95 marked this conversation as resolved.
Show resolved Hide resolved
}

uint32_t message_idx = identify(bus_name, frame);
uint32_t bus_idx = static_cast<int>(bus_name);
if (message_idx > 0) {
messages[bus_idx][message_idx]->pack(frame);
}
}
34 changes: 0 additions & 34 deletions generator/templates/bus.h.j2

This file was deleted.

40 changes: 40 additions & 0 deletions generator/templates/bus.hpp.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{%- set ns = namespace(first_frame=true) -%}

{%- macro enum_name(msg, msg_name=msg.name) -%}
{%- if msg.frame is defined -%}
{% for sub_frame in msg.frame -%}
{{ enum_name(sub_frame, msg_name + '_' + sub_frame.name) }}
{%- endfor -%}
{%- else %}
{{ msg_name }},
{%- endif -%}
{%- endmacro -%}
#pragma once

#include "static.hpp"

namespace CANlib {

enum class AbstractBus {
{%- for bus in can.bus %}
{{ bus.name }},
{%- endfor %}
INVALID_NAME,
};

uint32_t identify(AbstractBus, const Frame&);
void handle_frame(AbstractBus, const Frame&);

{% for bus in can.bus %}
namespace {{bus.name}} {
{%- set ns.first_frame = true %}
enum class MessageType {
UNKNOWN_MSG = 0,
{%- for msg in bus.frame -%}
{{- enum_name(msg) }}
{%- endfor %}
};
} // {{bus.name}}
{% endfor -%}

} // CANlib
Loading