diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 634540e77..51818a7f3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -11,7 +11,7 @@ on: env: # Set defines for builds/tests - DEFINES: "LOG_LEVEL_VERBOSITY=LOG_LEVEL_WARN" + DEFINES: "LOG_LEVEL=LOG_LEVEL_WARN" jobs: build: diff --git a/.gitignore b/.gitignore index dc677bc26..7264aa76b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,15 +23,6 @@ __pycache__ *.pyc # Autogenerated code -*_getters.h -*_pack_msg.h -*_rx_all.c -*_rx_structs.h -*_setters.h -*_tx_all.c -*_tx_structs.h -*_unpack_msg.h *can_board_ids.h -*can_codegen.h *system_can.dbc x86_flash diff --git a/SConstruct b/SConstruct index c719d135c..65b44a67c 100644 --- a/SConstruct +++ b/SConstruct @@ -1,148 +1,117 @@ -import os -import sys +from scons.common import flash_run import subprocess -from scons.common import parse_config + + +def set_target(option, opt, value, parser): + if opt == '--project': + target = f'projects/{value}' + if opt == '--smoke': + target = f'smoke/{value}' + if opt == '--library': + target = f'libraries/{value}' + if opt == '--python' or opt == '--py': + target = f'py/{value}' + setattr(parser.values, option.dest, target) + ########################################################### # Build arguments ########################################################### - AddOption( '--platform', dest='platform', - type='string', - action='store', - default='arm' + type='choice', + choices=("arm", "x86"), + default='arm', + help="Specifies target platform. One of 'arm' or 'x86'. Defaults to 'arm' if not provided." ) AddOption( - '--project', - dest='project', - type='string', - action='store', -) - -AddOption( - '--library', - dest='library', - type='string', - action='store', -) - -AddOption( - '--python', - dest='python', - type='string', - action='store' -) -AddOption( - '--py', - dest='python', - type='string', - action='store' + '--library', '--project', '--smoke', '--python', '--py', + type="string", dest="name", + action='callback', callback=set_target, + help="Specify the target. e.g. --library=ms-common, --project=leds, --smoke=adc, --python=example", ) AddOption( '--test', dest='testfile', type='string', - action='store' + action='store', + help="Additionally specify the name of test to run for 'test' command." ) AddOption( '--define', dest='define', type='string', - action='store' + action='store', + help="Add CPP defines to a build. e.g. --define='LOG_LEVEL=LOG_LEVEL_WARN'" ) AddOption( - '--name', - dest='name', + '--task', + dest='task', type='string', action='store' ) -# Adding Memory Report Argument to Environment Flags -# Note platform needs to be explicitly set to arm - AddOption( '--mem-report', dest='mem-report', - type='string', - action='store', + action='store_true', + help="(arm) Reports the memory space after a build." +) + +AddOption( + '--sanitizer', + dest='sanitizer', + type='choice', + choices=("asan", "tsan"), + default="none", + help="(x86) Specifies the sanitizer. One of 'asan' for Address sanitizer or 'tsan' for Thread sanitizer. Defaults to none." ) PLATFORM = GetOption('platform') -PROJECT = GetOption('project') -LIBRARY = GetOption('library') -PYTHON = GetOption('python') -MEM_REPORT = GetOption('mem-report') -NAME = GetOption('name') +TARGET = GetOption('name') ########################################################### # Environment setup ########################################################### # Retrieve the construction environment from the appropriate platform script -if PLATFORM == 'x86': - env = SConscript('platform/x86.py') -elif PLATFORM == 'arm': - env = SConscript('platform/arm.py') - - -# env.VariantDir('build', '.', duplicate=0) - -TYPE = None -if PROJECT: - TYPE = 'project' -elif LIBRARY: - TYPE = 'library' -elif PYTHON: - TYPE = 'python' -TARGET = PROJECT or LIBRARY or PYTHON +env = SConscript(f'platform/{PLATFORM}.py') VARS = { "PLATFORM": PLATFORM, - "TYPE": TYPE, "TARGET": TARGET, - "NAME": NAME, "env": env, } -env["VARS"] = VARS +COMMAND = COMMAND_LINE_TARGETS[0] if COMMAND_LINE_TARGETS else "" -# Add flags when compiling a test -TEST_CFLAGS = ['-DMS_TEST=1'] -if 'test' in COMMAND_LINE_TARGETS: # are we running "scons test"? - env['CCFLAGS'] += TEST_CFLAGS # Parse asan / tsan and Adding Sanitizer Argument to Environment Flags # Note platform needs to be explicitly set to x86 -AddOption( - '--sanitizer', - dest='sanitizer', - type='string', - action='store', - default="none" -) SANITIZER = GetOption('sanitizer') if SANITIZER == 'asan': - env['CCFLAGS'] += ["-fsanitize=address"] - env['CXXFLAGS'] += ["-fsanitize=address"] + env['CCFLAGS'] += ["-fsanitize=address"] + env['CXXFLAGS'] += ["-fsanitize=address"] env['LINKFLAGS'] += ["-fsanitize=address"] elif SANITIZER == 'tsan': - env['CCFLAGS'] += ["-fsanitize=thread"] - env['CXXFLAGS'] += ["-fsanitize=thread"] + env['CCFLAGS'] += ["-fsanitize=thread"] + env['CXXFLAGS'] += ["-fsanitize=thread"] env['LINKFLAGS'] += ["-fsanitize=thread"] -env['CCCOMSTR'] = "Compiling $TARGET" -env['LINKCOMSTR'] = "Linking $TARGET" -env['ARCOMSTR'] = "Archiving $TARGET" -env['ASCOMSTR'] = "Assembling $TARGET" +env['CCCOMSTR'] = "Compiling $TARGET" +env['ARCOMSTR'] = "Archiving $TARGET" +env['ASCOMSTR'] = "Assembling $TARGET" +env['LINKCOMSTR'] = "Linking $TARGET" env['RANLIBCOMSTR'] = "Indexing $TARGET" +env.Append(CPPDEFINES=[GetOption('define')]) + ########################################################### # Directory setup ########################################################### @@ -151,131 +120,77 @@ BUILD_DIR = Dir('#/build').Dir(PLATFORM) BIN_DIR = BUILD_DIR.Dir('bin') OBJ_DIR = BUILD_DIR.Dir('obj') -PROJ_DIR = Dir('#/projects') -SMOKE_DIR = Dir('#/smoke') - -PLATFORM_DIR = Dir('#/platform') - VariantDir(OBJ_DIR, '.', duplicate=0) -COMMAND = COMMAND_LINE_TARGETS[0] if COMMAND_LINE_TARGETS else None - -########################################################### -# Build -########################################################### -if COMMAND == None or COMMAND == "test": - SConscript('scons/build.scons', exports='VARS') - ########################################################### # Testing ########################################################### if COMMAND == "test": + # Add flags when compiling a test + TEST_CFLAGS = ['-DMS_TEST=1'] + env['CCFLAGS'] += TEST_CFLAGS SConscript('scons/test.scons', exports='VARS') + SConscript('scons/build.scons', exports='VARS') ########################################################### # Helper targets ########################################################### -if COMMAND == "new_task": +elif COMMAND == "new": SConscript('scons/new_target.scons', exports='VARS') ########################################################### # Clean ########################################################### -# 'clean' is a dummy file that doesn't get created -# This is required for phony targets for scons to be happy -Command('#/clean', [], 'rm -rf build/*') -# Alias('clean', clean) +elif COMMAND == "clean": + AlwaysBuild(Command('#/clean', [], 'rm -rf build/*')) ########################################################### # Linting and Formatting ########################################################### -if COMMAND == "lint" or COMMAND == "format": +elif COMMAND == "lint" or COMMAND == "format": SConscript('scons/lint_format.scons', exports='VARS') -# ELFs are used for gdb and x86 -def proj_elf(proj_name, is_smoke=False): - return BIN_DIR.Dir(SMOKE_DIR.name if is_smoke else PROJ_DIR.name).File(proj_name) - -# .bin is used for flashing to MCU -def proj_bin(proj_name, is_smoke=False): - return proj_elf(proj_name, is_smoke).File(proj_name + '.bin') +########################################################### +# Build +########################################################### +else: # command not recognised, default to build + SConscript('scons/build.scons', exports='VARS') ########################################################### # Helper targets for x86 ########################################################### -if PLATFORM == 'x86' and TYPE == 'project': +if PLATFORM == 'x86' and TARGET: + project_elf = BIN_DIR.File(TARGET) # os.exec the x86 project ELF file to simulate it - def sim_run(target, source, env): - path = proj_elf(TARGET, env.get("smoke")).path - print('Simulating', path) - os.execv(path, [path]) - sim = Command('sim.txt', [], sim_run) - Depends(sim, proj_elf(TARGET)) - Alias('sim', sim) + def sim_run(target, source, env): + print('Simulating', project_elf) + subprocess.run([project_elf.path]) - sim_smoke = Command('sim_smoke.txt', [], sim_run, smoke=True) - Depends(sim_smoke, proj_elf(TARGET, True)) - Alias('sim_smoke', sim_smoke) + AlwaysBuild(Command('#/sim', project_elf, sim_run)) # open gdb with the elf file def gdb_run(target, source, env): - path = proj_elf(TARGET, env.get("smoke")).path - os.execv('/usr/bin/gdb', ['/usr/bin/gdb', path]) - - gdb = Command('gdb.txt', [], gdb_run) - Depends(gdb, proj_elf(TARGET)) - Alias('gdb', gdb) + subprocess.run(['/usr/bin/gdb', project_elf.path]) - gdb_smoke = Command('gdb_smoke.txt', [], gdb_run, smoke=True) - Depends(gdb_smoke, proj_elf(TARGET, True)) - Alias('gdb_smoke', gdb_smoke) + AlwaysBuild(Command('#/gdb', project_elf, gdb_run)) ########################################################### # Helper targets for arm ########################################################### -if PLATFORM == 'arm' and TYPE == 'project': +if PLATFORM == 'arm' and TARGET: + project_bin = BIN_DIR.File(TARGET + '.bin') # display memory info for the project - if MEM_REPORT: - get_mem_report = Action("python3 scons/mem_report.py " + "build/arm/bin/projects/{}".format(TARGET)) - env.AddPostAction(proj_bin(TARGET, False), get_mem_report) - + if GetOption('mem-report'): + AlwaysBuild(Command("#/mem-report", project_bin, + f"python3 scons/mem_report.py build/arm/bin/{TARGET}")) + Default("#/mem-report") + # flash the MCU using openocd - def flash_run(target, source, env): - import serial - output = subprocess.check_output(["ls", "/dev/serial/by-id/"]) - device_path = f"/dev/serial/by-id/{str(output, 'ASCII').strip()}" - serialData = serial.Serial(device_path,115200) - - OPENOCD = 'openocd' - OPENOCD_SCRIPT_DIR = '/usr/share/openocd/scripts/' - PROBE = 'cmsis-dap' - OPENOCD_CFG = [ - OPENOCD, - '-s {}'.format(OPENOCD_SCRIPT_DIR), - '-f interface/{}.cfg'.format(PROBE), - '-f target/stm32f1x.cfg', - '-f {}/stm32f1-openocd.cfg'.format(PLATFORM_DIR), - '-c "stm32f1x.cpu configure -rtos FreeRTOS"', - '-c "stm_flash {}"'.format(proj_bin(TARGET, env.get("smoke"))), - '-c shutdown' - ] - cmd = 'sudo {}'.format(' '.join(OPENOCD_CFG)) - subprocess.run(cmd, shell=True) - + def flash_run_target(target, source, env): + serialData = flash_run(project_bin) while True: line: str = serialData.readline().decode("utf-8") print(line, end='') - if line.startswith('OK'): - break - if line.startswith('FAIL'): - fails += 1 - break - - flash = Command('flash.txt', [], flash_run) - Depends(flash, proj_bin(TARGET)) - Alias('flash', flash) - - flash_smoke = Command('flash_smoke.txt', [], flash_run, smoke=True) - Depends(flash_smoke, proj_bin(TARGET, True)) - Alias('flash_smoke', flash_smoke) + + AlwaysBuild(Command('#/flash', project_bin, flash_run_target)) \ No newline at end of file diff --git a/bps_indicator.c b/bps_indicator.c deleted file mode 100644 index 2d33570b6..000000000 --- a/bps_indicator.c +++ /dev/null @@ -1,31 +0,0 @@ -#include "bps_indicator.h" - -#define BPS_FAULT_INDICATOR_PERIOD_MS 375 - -static SoftTimer s_bps_indicator_timer; -static bool s_bps_fault_enabled; -static OutputState s_output_state; - -static void prv_callback() { - if (s_bps_fault_enabled) { - // ternary statement: sets s_output_state to opposite of current state - s_output_state = (s_output_state == OUPUT_STATE_OFF) ? OUTPUT_STATE_ON : OUTPUT_STATE_OFF; - // set OUTPUT_GROUP_BPS_FAULT to s_output_state - pd_set_output_group(OUTPUT_GROUP_BPS_FAULT, s_output_state); - // add s_bps_indicator_timer - 375 ms before running, run prv_callback after - soft_timer_start(BPS_FAULT_INDICATOR_PERIOD_MS, prv_callback, &s_bps_indicator_timer); - } else { - // set OUTPUT_GROUP_BPS_FAULT to OUPUT_STATE_OFF - // function terminates - pd_set_output_group(OUTPUT_GROUP_BPS_FAULT, OUPUT_STATE_OFF); - } -} - -void start_bps_fault_indicator() { - s_bps_fault_enabled = true; - soft_timer_start(BPS_FAULT_INDICATOR_PERIOD_MS, prv_callback, &s_bps_indicator_timer); -} - -void stop_bps_fault_indicator() { - s_bps_fault_enabled = false; -} \ No newline at end of file diff --git a/bps_indicator.h b/bps_indicator.h deleted file mode 100644 index 2ff824df4..000000000 --- a/bps_indicator.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include -#include "soft_timer.h" -#include "outputs.h" - -// functions to start/stop bps fault indicator -void start_bps_fault_indicator(void); -void stop_bps_fault_indicator(void); diff --git a/build_system.md b/build_system.md index 2c896e3a5..082e9525f 100644 --- a/build_system.md +++ b/build_system.md @@ -10,48 +10,109 @@ Each project and library may also contain a `config.json` file with certain fiel Unit tests are per-project/library and are built and run from scons. Functions may be mocked by specifying which test file mocks which functions. An example of a mocking configuration is in the `core` library, in `config.json` and in `test/test_mock.c`. ## Usage -### Build commands -- `no command`: Build all projects. - - e.g. `scons` -- `project / library`: Build the project or library - - e.g. `scons leds` -- `test`: Builds and runs the tests for the specified project or library. If no project or library is specified, runs all tests. Also allows specifying a test file to run. - - e.g. `scons test` - - e.g. `scons test --library=core` - - e.g. `scons test --project=leds --test=test_led_1` - -### Convenience commands: - -- `new [name]`: Creates a new project, smoke project, or library with the given name. - - e.g. `scons new --project=my_new_project` - - e.g. `scons new --library=my_new_library` - - e.g. `scons new_smoke --project=my_smoke_test` -- `new_task [name] [task name]`: Creates a new task within a project or library - - e.g. `scons new_task --project=my_project --name=task_name` - - e.g. `scons new_task --library=my_library --name=task_name` -- `clean`: Delete the `build` directory. - - e.g. `scons clean` -- `sim [project]`: (x86 specific) Run the project's binary. - - e.g. `scons sim --project=leds --platform=x86` - - e.g. `scons sim_smoke --project=smoke_leds --platform=x86` - - `sim_smoke` should be used for smoke tests. -- `gdb [project]`: (x86 specific) Run the project's binary with gdb. - - e.g. `scons gdb --project=leds --platform=x86` - - e.g. `scons gdb_smoke --project=smoke_leds --platform=x86` -- `flash [project]`: (arm specific) Flash the project's binary using openocd. A controller board must be connected an powered. - - e.g. `scons flash --project=leds` - - e.g. `scons flash_smoke --project=smoke_leds` -- `lint`: Lints all files. - - Can specify `--project` or `--library` argument to only lint specific project/library -- `format`: Formats all files. - - Can specify `--project` or `--library` argument to only format specific project/library - -### Arguments -- `--platform`: Specifies target platform. One of `arm` or `x86`. Defaults to `arm`. -- `--project`: Specifies target project. Only required when running convenience commands or tests. -- `--library`: Specifies target library. Only required when running convenience commands or tests. -- `--test`: Specify test file to run. -- `--sanitizer`: Specifies the sanitizer. One of `asan` for Address sanitizer or `tsan` for Thread sanitizer. Defaults to `none`. Note it only works on `x86` platform. +``` +scons [options]... + +Options: +options can occur anywhere in the command string + + --platform={x86|arm} + Specifies target platform. One of `arm` or `x86`. Defaults to `arm` if not provided. + + --define=... + Add CPP defines to a build. + - e.g.`--define="LOG_LEVEL=LOG_LEVEL_WARN"` + + --sanitizer={asan|tsan} + (x86) Specifies the sanitizer. One of `asan` for Address sanitizer or `tsan` for Thread sanitizer. Defaults to `none`. + + --test= + Additionally specify the name of test to run for `test` command. + + --task= + Specify a task to create for `new` command. + + --mem-report + (arm) Reports the memory space after a build + +Commands: + NONE + Build the specified target, or all target if not specified. + - e.g. `scons` + - e.g. `scons ` (`scons --project=leds`) + if the target is a python project, run the project. + + test + Test the specified target, or all target if not specified. + - e.g. `scons test` + - e.g. `scons test ` (`scons test --project=leds`) + + new + Creates a new project, smoke project, or library with the given name. + - e.g. `scons new ` (`scons new --project=new_led`) + if --task= option is specified, instead create a new task within the target + - e.g. `scons new --task=` (`scons new --project=leds --task=led_task`) + + sim + (x86) Run the project's binary. + - e.g. `scons sim --platform=x86 ` (`scons sim --platform=x86 --project=new_led`) + + gdb + (x86) Run the project's binary with gdb. + - e.g. `scons gdb ` (`scons gdb --project=new_led`) + + flash + (arm) Flash the project's binary using openocd. A controller board must be connected an powered. + - e.g. `scons flash ` (`scons flash --project=new_led`) + + format + Format a target, or all targets if not specified. uses autopep8 for python and clang-format for c. + - e.g. `scons format` + - e.g. `scons format ` (`scons format --project=new_led`) + + lint + Lint a target, or all targets if not specified. uses pylint for python and cpplint for c. + - e.g. `scons lint` + - e.g. `scons lint ` (`scons lint --project=new_led`) + + clean + Delete the `build` directory. + +Target: +targest can be specified with an option. + + --project= + specify the target as a project with `name` + - e.g. `--project=leds` + + --library= + specify the target as a library with `name` + - e.g. `--library=ms-common` + + --python=` or --py= + specify the target as a project with `name` (same as `--py=...`) + - e.g. `--python=example`, `--py=example` + + --smoke=` + specify the target as a project with `name`, + - e.g. `--smoke=adc` + +Convenience Commands: + + build the target with the name + - e.g. `scons leds` + - e.g. `scons ms-common` + + + build the target with the path. + - e.g. `scons projects/leds` + - e.g. `scons libraries/ms-common` + + test / + test the target with the name/path + - e.g. `scons test projects/leds` + (experimental, use at own risk) +``` # Future Improvements Features that would be nice to have in the future but haven't been done yet: diff --git a/can/tools/can.py b/can/tools/can.py new file mode 100644 index 000000000..9ccdf9877 --- /dev/null +++ b/can/tools/can.py @@ -0,0 +1,361 @@ +import struct +import subprocess +import time +import threading + +SYSTEM_CAN_MESSAGE_BABYDRIVER_BABYDRIVER = 2016 +SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_STATUS = 1 +SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_VT = 961 +SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_AGGREGATE_VC = 1057 +SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_FAN_STATE = 1825 +SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_RELAY_INFO = 1857 +SYSTEM_CAN_MESSAGE_CAN_COMMUNICATION_ONE_SHOT_MSG = 2 +SYSTEM_CAN_MESSAGE_CAN_DEBUG_TEST_DEBUG = 3 +SYSTEM_CAN_MESSAGE_CENTRE_CONSOLE_CC_POWER_CONTROL = 36 +SYSTEM_CAN_MESSAGE_CENTRE_CONSOLE_DRIVE_OUTPUT = 68 +SYSTEM_CAN_MESSAGE_CHARGER_REQUEST_TO_CHARGE = 1541 +SYSTEM_CAN_MESSAGE_CHARGER_CHARGER_CONNECTED_STATE = 1605 +SYSTEM_CAN_MESSAGE_CHARGER_CHARGER_FAULT = 1701 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_CONTROLLER_VC = 966 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_VELOCITY = 998 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_STATUS = 1030 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_SINK_TEMPS = 1222 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_DSP_BOARD_TEMPS = 1254 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MC_STATUS = 1286 +SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_PRECHARGE_COMPLETED = 454 +SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG1 = 7 +SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG2 = 39 +SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG3 = 71 +SYSTEM_CAN_MESSAGE_PEDAL_PEDAL_OUTPUT = 584 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_UV_CUTOFF_NOTIFICATION = 1449 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_CURRENT_MEASUREMENT = 1737 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_PD_FAULT = 1993 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_HORN_AND_LIGHTS = 1481 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_LIGHTS_SYNC = 745 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_POWER_INFO = 105 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_PD_STATUS = 41 +SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_BMS_RELAYS = 329 +SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_STATUS = 42 +SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_AUX_MEASUREMENTS = 74 +SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_DCDC_MEASUREMENTS = 106 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_1 = 683 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_2 = 715 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_3 = 747 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_4 = 779 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_5 = 811 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_6 = 651 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_CURRENT_SENSE = 843 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_THERMAL_STATUS = 875 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_THERMAL_TEMPS = 907 +SYSTEM_CAN_MESSAGE_SOLAR_SENSE_SOLAR_INFO = 939 +SYSTEM_CAN_MESSAGE_STEERING_STEERING_INFO = 684 +SYSTEM_CAN_MESSAGE_TELEMETRY_TEST_MSG = 13 +SYSTEM_CAN_MESSAGE_UV_CUTOFF_UV_CUTOFF_NOTIFICATION1 = 1454 +# Send single message +def send_message(id, data): + # id: int -> hex, data: str + cmd = f"cansend vcan0 {hex(id)[2:].zfill(3)}#{data}" + subprocess.run(cmd, shell=True) + +def pack(num, size): + if isinstance(num, float) and (size == 32): + return struct.pack("f", num).hex() + elif (size == 32): + return struct.pack("i", num).hex() + elif (size == 16): + return struct.pack("h", num).hex() + elif (size == 8): + return struct.pack("b", num).hex() +def send_babydriver_babydriver(id, data0, data1, data2, data3, data4, data5, data6): + send_message(SYSTEM_CAN_MESSAGE_BABYDRIVER_BABYDRIVER, + pack(id, 8) + + pack(data0, 8) + + pack(data1, 8) + + pack(data2, 8) + + pack(data3, 8) + + pack(data4, 8) + + pack(data5, 8) + + pack(data6, 8)) + +def send_bms_carrier_battery_status(batt_perc, status, fault): + send_message(SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_STATUS, + pack(batt_perc, 16) + + pack(status, 8) + + pack(fault, 8)) + +def send_bms_carrier_battery_vt(module_id, voltage, temperature): + send_message(SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_VT, + pack(module_id, 16) + + pack(voltage, 16) + + pack(temperature, 16)) + +def send_bms_carrier_battery_aggregate_vc(voltage, current): + send_message(SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_AGGREGATE_VC, + pack(voltage, 32) + + pack(current, 32)) + +def send_bms_carrier_battery_fan_state(fan_1, fan_2, fan_3, fan_4, fan_5, fan_6, fan_7, fan_8): + send_message(SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_FAN_STATE, + pack(fan_1, 8) + + pack(fan_2, 8) + + pack(fan_3, 8) + + pack(fan_4, 8) + + pack(fan_5, 8) + + pack(fan_6, 8) + + pack(fan_7, 8) + + pack(fan_8, 8)) + +def send_bms_carrier_battery_relay_info(state): + send_message(SYSTEM_CAN_MESSAGE_BMS_CARRIER_BATTERY_RELAY_INFO, + pack(state, 8)) + +def send_can_communication_one_shot_msg(sig1, sig2): + send_message(SYSTEM_CAN_MESSAGE_CAN_COMMUNICATION_ONE_SHOT_MSG, + pack(sig1, 16) + + pack(sig2, 16)) + +def send_can_debug_test_debug(operation, operandA, operandB, operandC): + send_message(SYSTEM_CAN_MESSAGE_CAN_DEBUG_TEST_DEBUG, + pack(operation, 8) + + pack(operandA, 8) + + pack(operandB, 8) + + pack(operandC, 8)) + +def send_centre_console_cc_power_control(power_event, hazard_enabled): + send_message(SYSTEM_CAN_MESSAGE_CENTRE_CONSOLE_CC_POWER_CONTROL, + pack(power_event, 8) + + pack(hazard_enabled, 8)) + +def send_centre_console_drive_output(target_velocity, drive_state, cruise_control, regen_braking, precharge): + send_message(SYSTEM_CAN_MESSAGE_CENTRE_CONSOLE_DRIVE_OUTPUT, + pack(target_velocity, 32) + + pack(drive_state, 8) + + pack(cruise_control, 8) + + pack(regen_braking, 8) + + pack(precharge, 8)) + +def send_charger_request_to_charge(signal1): + send_message(SYSTEM_CAN_MESSAGE_CHARGER_REQUEST_TO_CHARGE, + pack(signal1, 8)) + +def send_charger_charger_connected_state(is_connected): + send_message(SYSTEM_CAN_MESSAGE_CHARGER_CHARGER_CONNECTED_STATE, + pack(is_connected, 8)) + +def send_charger_charger_fault(fault): + send_message(SYSTEM_CAN_MESSAGE_CHARGER_CHARGER_FAULT, + pack(fault, 8)) + +def send_motor_controller_motor_controller_vc(mc_voltage_l, mc_current_l, mc_voltage_r, mc_current_r): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_CONTROLLER_VC, + pack(mc_voltage_l, 16) + + pack(mc_current_l, 16) + + pack(mc_voltage_r, 16) + + pack(mc_current_r, 16)) + +def send_motor_controller_motor_velocity(velocity_l, velocity_r): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_VELOCITY, + pack(velocity_l, 16) + + pack(velocity_r, 16)) + +def send_motor_controller_motor_status(motor_status_l, motor_status_r): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_STATUS, + pack(motor_status_l, 32) + + pack(motor_status_r, 32)) + +def send_motor_controller_motor_sink_temps(motor_temp_l, heatsink_temp_l, motor_temp_r, heatsink_temp_r): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MOTOR_SINK_TEMPS, + pack(motor_temp_l, 16) + + pack(heatsink_temp_l, 16) + + pack(motor_temp_r, 16) + + pack(heatsink_temp_r, 16)) + +def send_motor_controller_dsp_board_temps(dsp_temp_l, dsp_temp_r): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_DSP_BOARD_TEMPS, + pack(dsp_temp_l, 32) + + pack(dsp_temp_r, 32)) + +def send_motor_controller_mc_status(limit_bitset_l, error_bitset_l, limit_bitset_r, error_bitset_r, board_fault_bitset, overtemp_bitset, precharge_status): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_MC_STATUS, + pack(limit_bitset_l, 8) + + pack(error_bitset_l, 8) + + pack(limit_bitset_r, 8) + + pack(error_bitset_r, 8) + + pack(board_fault_bitset, 8) + + pack(overtemp_bitset, 8) + + pack(precharge_status, 8)) + +def send_motor_controller_precharge_completed(notification): + send_message(SYSTEM_CAN_MESSAGE_MOTOR_CONTROLLER_PRECHARGE_COMPLETED, + pack(notification, 8)) + +def send_new_can_transmit_msg1(status): + send_message(SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG1, + pack(status, 8)) + +def send_new_can_transmit_msg2(signal, signal2): + send_message(SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG2, + pack(signal, 8) + + pack(signal2, 8)) + +def send_new_can_transmit_msg3(help): + send_message(SYSTEM_CAN_MESSAGE_NEW_CAN_TRANSMIT_MSG3, + pack(help, 8)) + +def send_pedal_pedal_output(throttle_output, brake_output): + send_message(SYSTEM_CAN_MESSAGE_PEDAL_PEDAL_OUTPUT, + pack(throttle_output, 32) + + pack(brake_output, 32)) + +def send_power_distribution_uv_cutoff_notification(signal1): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_UV_CUTOFF_NOTIFICATION, + pack(signal1, 8)) + +def send_power_distribution_current_measurement(current_id, current): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_CURRENT_MEASUREMENT, + pack(current_id, 16) + + pack(current, 16)) + +def send_power_distribution_pd_fault(fault_data, faulting_output): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_PD_FAULT, + pack(fault_data, 16) + + pack(faulting_output, 16)) + +def send_power_distribution_horn_and_lights(horn_state, lights_state): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_HORN_AND_LIGHTS, + pack(horn_state, 8) + + pack(lights_state, 8)) + +def send_power_distribution_lights_sync(signal1): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_LIGHTS_SYNC, + pack(signal1, 8)) + +def send_power_distribution_power_info(power_state, pd_fault): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_POWER_INFO, + pack(power_state, 8) + + pack(pd_fault, 8)) + +def send_power_distribution_pd_status(fault_bitset): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_PD_STATUS, + pack(fault_bitset, 8)) + +def send_power_distribution_bms_relays(relays_state): + send_message(SYSTEM_CAN_MESSAGE_POWER_DISTRIBUTION_BMS_RELAYS, + pack(relays_state, 8)) + +def send_power_select_power_select_status(status, fault): + send_message(SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_STATUS, + pack(status, 8) + + pack(fault, 8)) + +def send_power_select_power_select_aux_measurements(aux_voltage, aux_current, aux_temp, power_supply_current): + send_message(SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_AUX_MEASUREMENTS, + pack(aux_voltage, 16) + + pack(aux_current, 16) + + pack(aux_temp, 16) + + pack(power_supply_current, 16)) + +def send_power_select_power_select_dcdc_measurements(dcdc_voltage, dcdc_current, dcdc_temp, power_supply_voltage): + send_message(SYSTEM_CAN_MESSAGE_POWER_SELECT_POWER_SELECT_DCDC_MEASUREMENTS, + pack(dcdc_voltage, 16) + + pack(dcdc_current, 16) + + pack(dcdc_temp, 16) + + pack(power_supply_voltage, 16)) + +def send_solar_sense_mppt_1(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_1, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_mppt_2(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_2, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_mppt_3(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_3, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_mppt_4(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_4, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_mppt_5(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_5, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_mppt_6(current, voltage, pwm, status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_MPPT_6, + pack(current, 16) + + pack(voltage, 16) + + pack(pwm, 16) + + pack(status, 16)) + +def send_solar_sense_current_sense(current, voltage, relay_status): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_CURRENT_SENSE, + pack(current, 16) + + pack(voltage, 16) + + pack(relay_status, 8)) + +def send_solar_sense_thermal_status(overtemp, fullspeed, fan_fail, temp_1, temp_2): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_THERMAL_STATUS, + pack(overtemp, 8) + + pack(fullspeed, 8) + + pack(fan_fail, 8) + + pack(temp_1, 16) + + pack(temp_2, 16)) + +def send_solar_sense_thermal_temps(temp_3, temp_4, temp_5, temp_6): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_THERMAL_TEMPS, + pack(temp_3, 16) + + pack(temp_4, 16) + + pack(temp_5, 16) + + pack(temp_6, 16)) + +def send_solar_sense_solar_info(solar_fault): + send_message(SYSTEM_CAN_MESSAGE_SOLAR_SENSE_SOLAR_INFO, + pack(solar_fault, 8)) + +def send_steering_steering_info(input_cc, input_lights): + send_message(SYSTEM_CAN_MESSAGE_STEERING_STEERING_INFO, + pack(input_cc, 8) + + pack(input_lights, 8)) + +def send_telemetry_test_msg(test): + send_message(SYSTEM_CAN_MESSAGE_TELEMETRY_TEST_MSG, + pack(test, 8)) + +def send_uv_cutoff_uv_cutoff_notification1(signal1): + send_message(SYSTEM_CAN_MESSAGE_UV_CUTOFF_UV_CUTOFF_NOTIFICATION1, + pack(signal1, 8)) + + +def repeat(repeat_period, send_device_message, *args): + def threading_repeat(kill_process): + while not kill_process.is_set(): + send_device_message(*args) + time.sleep(repeat_period) + + kill_process = threading.Event() + + process_name = threading.Thread(target=threading_repeat, args=(kill_process,)) + process_name.start() + + return process_name, kill_process + +def end_repeat(send_device_message_process, kill_process): + kill_process.set() + send_device_message_process.join() \ No newline at end of file diff --git a/libraries/codegen/boards/centre_console.yaml b/libraries/codegen/boards/centre_console.yaml index 07d624b34..300adaa62 100644 --- a/libraries/codegen/boards/centre_console.yaml +++ b/libraries/codegen/boards/centre_console.yaml @@ -11,7 +11,7 @@ --- Messages: cc_power_control: - id: 1 + id: 8 target: power_distribution: watchdog: 0 @@ -23,7 +23,7 @@ length: 8 drive_output: - id: 2 + id: 9 target: motor_controller: watchdog: 0 diff --git a/libraries/codegen/boards/motor_controller.yaml b/libraries/codegen/boards/motor_controller.yaml index 1a41d7d91..433b488fd 100644 --- a/libraries/codegen/boards/motor_controller.yaml +++ b/libraries/codegen/boards/motor_controller.yaml @@ -11,7 +11,7 @@ --- Messages: motor_controller_vc: - id: 30 + id: 35 target: centre_console: watchdog: 0 @@ -26,7 +26,7 @@ length: 16 motor_velocity: - id: 31 + id: 36 target: centre_console: watchdog: 0 @@ -37,7 +37,7 @@ length: 16 motor_status: - id: 32 + id: 37 target: centre_console: watchdog: 0 @@ -97,7 +97,7 @@ length: 8 precharge_completed: - id: 14 + id: 16 target: centre_console: watchdog: 0 diff --git a/libraries/codegen/boards/pedal.yaml b/libraries/codegen/boards/pedal.yaml index 40ccc94dc..c28d5e912 100644 --- a/libraries/codegen/boards/pedal.yaml +++ b/libraries/codegen/boards/pedal.yaml @@ -17,6 +17,8 @@ watchdog: 0 centre_console: watchdog: 0 + power_distribution: + watchdog: 0 signals: throttle_output: length: 32 diff --git a/libraries/codegen/generator.py b/libraries/codegen/generator.py index f01bf8e39..38172d1aa 100644 --- a/libraries/codegen/generator.py +++ b/libraries/codegen/generator.py @@ -76,6 +76,11 @@ def get_data(): "name": signal_name, "start_bit": start_bit, "length": signal["length"], + "scale": 1, + "offset": 0, + "min": 0, + "max": 100, + "receiver": message["target"], }) start_bit += signal["length"] @@ -112,8 +117,6 @@ def main(): output = env.get_template(template).render(data=data) Path(output_dir, get_file_name(template, args.board)).write_text(output) - print("Done autogenerating") - if __name__ == "__main__": main() diff --git a/libraries/codegen/templates/can.py.jinja b/libraries/codegen/templates/can.py.jinja new file mode 100644 index 000000000..d09b2b3eb --- /dev/null +++ b/libraries/codegen/templates/can.py.jinja @@ -0,0 +1,57 @@ +{% set boards = data["Boards"] -%} +{% set messages = data["Messages"] -%} + +import struct +import subprocess +import time +import threading + +{% for message in messages -%} +SYSTEM_CAN_MESSAGE_{{ message["sender"] | upper }}_{{ message.name | upper }} = {{ message.id * 0x20 + + boards.index(message.sender)}} +{% endfor -%} + +# Send single message +def send_message(id, data): + # id: int -> hex, data: str + cmd = f"cansend vcan0 {hex(id)[2:].zfill(3)}#{data}" + subprocess.run(cmd, shell=True) + +def pack(num, size): + if isinstance(num, float) and (size == 32): + return struct.pack("f", num).hex() + elif (size == 32): + return struct.pack("i", num).hex() + elif (size == 16): + return struct.pack("h", num).hex() + elif (size == 8): + return struct.pack("b", num).hex() + +{%- for message in messages %} +def send_{{ message["sender"] }}_{{ message.name }}( + {%- for signal in message.signals %} + {{- signal.name -}}{{- ", " if not loop.last -}} + {%- endfor -%} +): + send_message(SYSTEM_CAN_MESSAGE_{{ message["sender"] | upper }}_{{ message.name | upper }}, + {%- for signal in message.signals %} + pack({{ signal.name }}, {{ signal["length"] }}){{ ' + ' if not loop.last }} + {%- endfor -%} + ) +{% endfor %} + +def repeat(repeat_period, send_device_message, *args): + def threading_repeat(kill_process): + while not kill_process.is_set(): + send_device_message(*args) + time.sleep(repeat_period) + + kill_process = threading.Event() + + process_name = threading.Thread(target=threading_repeat, args=(kill_process,)) + process_name.start() + + return process_name, kill_process + +def end_repeat(send_device_message_process, kill_process): + kill_process.set() + send_device_message_process.join() diff --git a/libraries/codegen/templates/system_can.dbc.jinja b/libraries/codegen/templates/system_can.dbc.jinja index ee491e3e8..74a941a05 100644 --- a/libraries/codegen/templates/system_can.dbc.jinja +++ b/libraries/codegen/templates/system_can.dbc.jinja @@ -38,11 +38,10 @@ BU_: {% for message in messages -%} -BO_ {{message.id * 0x20 + boards.index(message.sender)}} {{message.name}} {{message.signals | sum("length")}} {{message.sender}} +BO_ {{message.id * 0x20 + boards.index(message.sender)}} {{message.name}}: {{message.signals | sum("length") // 8 }} {{message.sender}} {%- for signal in message.signals %} - SG_ {{signal.name}} : {{signal.start_bit}}|{{signal.length}}@1+ ({{signal["scale"]}},{{signal["offset"]}}) [{{signal["min"]}}|{{signal["max"]}}] "{{signal["unit"]}}" {{signal.receiver | join(" ")}} - {# SG_ {{signal["signal_name"]}} : {{signal["start_bit"]}}|{{signal["length"]}}@1+ ({{signal["scale"]}},{{signal["offset"]}}) [{{signal["min"]}}|{{signal["max"]}}] "{{signal["unit"]}}" {{signal["receiver"]}} #} + SG_ {{signal.name}} : {{signal.start_bit}}|{{signal.length}}@1+ ({{signal["scale"]}},{{signal["offset"]}}) [{{signal["min"]}}|{{signal["max"]}}] "{{signal["unit"]}}" {{signal.receiver | join(", ")}} {%- endfor %} {% endfor -%} diff --git a/libraries/core/config.json b/libraries/core/config.json index 2c45a4d4e..9158c91df 100644 --- a/libraries/core/config.json +++ b/libraries/core/config.json @@ -6,7 +6,7 @@ "stm32f10x" ], "mocks": { - "mock": [ + "test_mock": [ "status_impl_update" ] } diff --git a/libraries/ms-common/inc/fsm.h b/libraries/ms-common/inc/fsm.h index d361c5967..9c46d5e30 100644 --- a/libraries/ms-common/inc/fsm.h +++ b/libraries/ms-common/inc/fsm.h @@ -63,7 +63,7 @@ #include "status.h" #include "tasks.h" -#define FSM_PRIORITY 2 +#define FSM_PRIORITY 1 // TODO(mitchellostler): make user defined #define FSM_TASK_STACK TASK_STACK_1024 #define FSM_TIMEOUT_MS 1000 @@ -106,12 +106,12 @@ typedef struct Fsm { // Creates the FSM structure with the supplied number of states // and initializes its associated FSM task // num_states must be a defined constant -#define FSM(name, num_fsm_states) \ - Fsm *name##_fsm = &((Fsm){ \ - .num_states = num_fsm_states, \ - }); \ - TASK(name, TASK_STACK_512) { \ - _fsm_task(context); \ +#define FSM(name, num_fsm_states, stack_size) \ + Fsm *name##_fsm = &((Fsm){ \ + .num_states = num_fsm_states, \ + }); \ + TASK(name, stack_size) { \ + _fsm_task(context); \ } // Creates state with associated id in a state list diff --git a/libraries/ms-common/inc/hw_timer.h b/libraries/ms-common/inc/hw_timer.h new file mode 100644 index 000000000..55cc8f69a --- /dev/null +++ b/libraries/ms-common/inc/hw_timer.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "status.h" +#include "stm32f10x_rcc.h" +#include "stm32f10x_tim.h" + +typedef void (*TimerCallback)(void); + +void hw_timer_init(void); + +void hw_timer_delay_us(uint32_t us); + +void hw_timer_callback_us(uint32_t us, TimerCallback callback_function); diff --git a/libraries/ms-common/src/arm/hw_timer.c b/libraries/ms-common/src/arm/hw_timer.c new file mode 100644 index 000000000..8d0ad0ef7 --- /dev/null +++ b/libraries/ms-common/src/arm/hw_timer.c @@ -0,0 +1,45 @@ +#include "hw_timer.h" + +#include "log.h" +#include "stm32f10x.h" + +void hw_timer_init(void) { + RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); + + TIM_Cmd(TIM2, DISABLE); + TIM_ITConfig(TIM2, TIM_IT_CC1, DISABLE); + TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE); + + RCC_ClocksTypeDef clocks; + RCC_GetClocksFreq(&clocks); + + TIM_TimeBaseInitTypeDef timer_init = { + .TIM_Prescaler = (clocks.PCLK1_Frequency / 1000000) - 1, // 1 Mhz + .TIM_CounterMode = TIM_CounterMode_Up, + .TIM_Period = UINT16_MAX, + .TIM_ClockDivision = TIM_CKD_DIV1, + }; + TIM_TimeBaseInit(TIM2, &timer_init); + TIM_Cmd(TIM2, ENABLE); +} + +void hw_timer_delay_us(uint32_t us) { + TIM_SetCounter(TIM2, 0); + TIM_CCxCmd(TIM2, TIM_Channel_1, TIM_CCx_Enable); + TIM_SetCompare1(TIM2, us); + TIM_Cmd(TIM2, ENABLE); + + while (!TIM_GetFlagStatus(TIM2, TIM_FLAG_CC1)) { + LOG_DEBUG("DELAYING\n"); + } + + TIM_ClearFlag(TIM2, TIM_FLAG_CC1); + TIM_CCxCmd(TIM2, TIM_Channel_1, TIM_CCx_Disable); + TIM_Cmd(TIM2, DISABLE); +} + +void hw_timer_callback_us(uint32_t us, TimerCallback callback_function) { + hw_timer_delay_us(us); + + if (callback_function != NULL) callback_function(); +} diff --git a/libraries/ms-common/test/test_fsm.c b/libraries/ms-common/test/test_fsm.c index 55093bdaa..6145a9862 100644 --- a/libraries/ms-common/test/test_fsm.c +++ b/libraries/ms-common/test/test_fsm.c @@ -12,7 +12,7 @@ #define NUM_TEST1_EVENTS 3 #define NUM_TEST1_TRANSITIONS 7 -FSM(test1, NUM_TEST1_STATES); +FSM(test1, NUM_TEST1_STATES, TASK_STACK_512); // State Definitions for fsm "test1" typedef enum TestStateId { diff --git a/libraries/ms-drivers/inc/ltc6811.h b/libraries/ms-drivers/inc/ltc6811.h index 26ce022d2..8a4077fb6 100644 --- a/libraries/ms-drivers/inc/ltc6811.h +++ b/libraries/ms-drivers/inc/ltc6811.h @@ -74,17 +74,17 @@ static_assert(sizeof(LtcAfeConfigRegisterData) == 6, "LtcAfeConfigRegisterData m // COMM Register, refer to LTC6803 datasheet page 31, Table 15 typedef struct { - uint8_t icom0 : 4; - uint8_t d0 : 8; - uint8_t fcom0 : 4; + uint16_t icom0 : 4; + uint16_t d0 : 8; + uint16_t fcom0 : 4; - uint8_t icom1 : 4; - uint8_t d1 : 8; - uint8_t fcom1 : 4; + uint16_t icom1 : 4; + uint16_t d1 : 8; + uint16_t fcom1 : 4; - uint8_t icom2 : 4; - uint8_t d2 : 8; - uint8_t fcom2 : 4; + uint16_t icom2 : 4; + uint16_t d2 : 8; + uint16_t fcom2 : 4; } _PACKED LtcAfeCommRegisterData; static_assert(sizeof(LtcAfeCommRegisterData) == 6, "LtcAfeCommRegisterData must be 6 bytes"); diff --git a/libraries/ms-drivers/test/test_max11600.c b/libraries/ms-drivers/test/test_max11600.c index d47239eff..86ffb7fed 100644 --- a/libraries/ms-drivers/test/test_max11600.c +++ b/libraries/ms-drivers/test/test_max11600.c @@ -18,7 +18,7 @@ static I2CSettings i2c_settings = { void setup_test(void) { log_init(); - LOG_DEBUG("here"); + LOG_DEBUG("here\n"); i2c_init(TEST_MAX11600_I2C_PORT, &i2c_settings); TEST_ASSERT_OK(max11600_init(&max_storage, TEST_MAX11600_I2C_PORT)); } diff --git a/libraries/ms-drivers/test/test_pca9555_gpio_expander.c b/libraries/ms-drivers/test/test_pca9555_gpio_expander.c index f2cafc53b..8cf38a660 100644 --- a/libraries/ms-drivers/test/test_pca9555_gpio_expander.c +++ b/libraries/ms-drivers/test/test_pca9555_gpio_expander.c @@ -36,7 +36,6 @@ void setup_test(void) { void teardown_test(void) {} TEST_IN_TASK - void test_gpio_set_state(void) { StatusCode status; uint8_t data = MOCK_REG; diff --git a/libraries/unity/auto/test_runner.c.jinja b/libraries/unity/auto/test_runner.c.jinja index 0a48c5dda..07331c496 100644 --- a/libraries/unity/auto/test_runner.c.jinja +++ b/libraries/unity/auto/test_runner.c.jinja @@ -45,7 +45,6 @@ void test_pre_task(void) { {% if data.has_in_task_test -%} /*=======IN TASK TESTS=====*/ TASK(test_task, TASK_STACK_1024) { - UnityBegin("{{data.filename}}"); {% for test in data.tests | selectattr("type", "eq", "TEST_IN_TASK") %} run_test({{test.name}}, "{{test.name}}", {{test.line}}); @@ -58,11 +57,16 @@ TASK(test_task, TASK_STACK_1024) { /*=======MAIN=====*/ int main() { setup_test(); + + UnityBegin("{{data.filename}}"); test_pre_task(); {%- if data.has_in_task_test %} tasks_init(); tasks_init_task(test_task, configMAX_PRIORITIES - 1, NULL); tasks_start(); +{%- else %} + exit(UnityEnd()); {%- endif %} + return 0; } diff --git a/projects/can_communication/src/main.c b/projects/can_communication/src/main.c index 110e2b0c1..799c63d7d 100644 --- a/projects/can_communication/src/main.c +++ b/projects/can_communication/src/main.c @@ -8,7 +8,7 @@ static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_CAN_COMMUNICATION, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/can_debug/src/main.c b/projects/can_debug/src/main.c index d1e701e89..76bed8c63 100644 --- a/projects/can_debug/src/main.c +++ b/projects/can_debug/src/main.c @@ -1,4 +1,5 @@ #include "can.h" +#include "can_board_ids.h" #include "can_debug.h" #include "log.h" #include "tasks.h" @@ -9,7 +10,7 @@ static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_CAN_DEBUG, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/centre_console/src/drive_fsm.c b/projects/centre_console/src/drive_fsm.c index 7d98c3acb..68e061603 100644 --- a/projects/centre_console/src/drive_fsm.c +++ b/projects/centre_console/src/drive_fsm.c @@ -4,7 +4,7 @@ #include "centre_console_getters.h" #include "centre_console_setters.h" -FSM(drive, NUM_DRIVE_STATES); +FSM(drive, NUM_DRIVE_STATES, TASK_STACK_512); #define NUM_DRIVE_FSM_BUTTONS 3 diff --git a/projects/centre_console/src/main.c b/projects/centre_console/src/main.c index 19112fdc7..adf2486ef 100644 --- a/projects/centre_console/src/main.c +++ b/projects/centre_console/src/main.c @@ -24,7 +24,7 @@ static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_CENTRE_CONSOLE, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/fsm_demo/src/fsm1.c b/projects/fsm_demo/src/fsm1.c index 3b3745320..e0fbf86c9 100644 --- a/projects/fsm_demo/src/fsm1.c +++ b/projects/fsm_demo/src/fsm1.c @@ -6,7 +6,7 @@ #include "notify.h" #include "task.h" -FSM(fsm1, NUM_FSM1_STATES); +FSM(fsm1, NUM_FSM1_STATES, TASK_STACK_512); // Input functions are executed each iteration of run_cycle, and // Output functions are executed only when a state is transitioned to diff --git a/projects/fsm_demo/src/fsm2.c b/projects/fsm_demo/src/fsm2.c index 48addd5bb..280b08b03 100644 --- a/projects/fsm_demo/src/fsm2.c +++ b/projects/fsm_demo/src/fsm2.c @@ -8,7 +8,7 @@ // FSM2 Lags one cycle behind FSM1, so it will transition to state X // When FSM1 finishes state X -FSM(fsm2, NUM_FSM2_STATES); +FSM(fsm2, NUM_FSM2_STATES, TASK_STACK_512); static void prv_fsm2_state0_output(void *context) { LOG_DEBUG("Transitioned to FSM2 state0\n"); diff --git a/projects/fsm_demo/src/main.c b/projects/fsm_demo/src/main.c index cc52c1a36..a29e70358 100644 --- a/projects/fsm_demo/src/main.c +++ b/projects/fsm_demo/src/main.c @@ -25,7 +25,6 @@ void run_medium_cycle() { wait_tasks(1); fsm_run_cycle(fsm2); wait_tasks(1); - delay_ms(1000); } int main(void) { diff --git a/projects/motor_controller/src/main.c b/projects/motor_controller/src/main.c index efcb52e64..7586dcc7d 100644 --- a/projects/motor_controller/src/main.c +++ b/projects/motor_controller/src/main.c @@ -15,7 +15,7 @@ static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_MOTOR_CONTROLLER, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/new_can/src/main.c b/projects/new_can/src/main.c index 65e824f6d..101d034c5 100644 --- a/projects/new_can/src/main.c +++ b/projects/new_can/src/main.c @@ -13,7 +13,7 @@ static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_NEW_CAN, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/power_distribution/inc/outputs.h b/projects/power_distribution/inc/outputs.h index 61f4bfbf3..bd0870bd3 100644 --- a/projects/power_distribution/inc/outputs.h +++ b/projects/power_distribution/inc/outputs.h @@ -60,6 +60,7 @@ typedef enum { OUTPUT_GROUP_LIGHTS_LEFT_TURN, OUTPUT_GROUP_LIGHTS_RIGHT_TURN, OUTPUT_GROUP_LIGHTS_HAZARD, + OUTPUT_GROUP_BRAKE, // Power States OUTPUT_GROUP_POWER_OFF, OUTPUT_GROUP_POWER_ON, diff --git a/projects/power_distribution/inc/pin_defs.h b/projects/power_distribution/inc/pin_defs.h index 6f9449d3b..b035dda0d 100644 --- a/projects/power_distribution/inc/pin_defs.h +++ b/projects/power_distribution/inc/pin_defs.h @@ -3,31 +3,31 @@ // PCA9555 and I2C definitions #define PD_I2C_PORT I2C_PORT_1 -#define PD_PCA9555_I2C_ADDRESS_0 0x24 -#define PD_PCA9555_I2C_ADDRESS_1 0x26 +#define PD_PCA9555_I2C_ADDRESS_0 0x20 +#define PD_PCA9555_I2C_ADDRESS_1 0x21 #define PD_I2C_SDA \ { GPIO_PORT_B, 9 } #define PD_I2C_SCL \ { GPIO_PORT_B, 8 } #define PCA9555_IO_INT1 \ - { GPIO_PORT_B, 14 } + { GPIO_PORT_A, 9 } #define PCA9555_IO_INT2 \ - { GPIO_PORT_B, 13 } + { GPIO_PORT_A, 10 } // Power, fan, and mux pin definitions #define PD_5V_REG_MONITOR_PIN \ { GPIO_PORT_B, 1 } #define PD_MUX_OUTPUT_PIN \ - { GPIO_PORT_A, 7 } -#define PD_MUX_SEL1_PIN \ { GPIO_PORT_A, 6 } +#define PD_MUX_SEL1_PIN \ + { GPIO_PORT_B, 15 } #define PD_MUX_SEL2_PIN \ - { GPIO_PORT_A, 5 } + { GPIO_PORT_B, 14 } #define PD_MUX_SEL3_PIN \ - { GPIO_PORT_A, 4 } + { GPIO_PORT_B, 13 } #define PD_MUX_SEL4_PIN \ - { GPIO_PORT_A, 3 } + { GPIO_PORT_B, 12 } #define PD_SMBALERT_PIN \ { GPIO_PORT_B, 10 } @@ -41,94 +41,94 @@ { GPIO_PORT_A, 8 } #define SOLAR_SENSE_1_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_0 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_5 } #define SOLAR_SENSE_2_EN \ - { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_1 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_7 } #define SOLAR_SENSE_1_2_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_2 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_6 } #define PEDAL_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_3 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_2 } #define STEERING_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_4 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_4 } #define PEDAL_STEERING_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_5 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_3 } #define LEFT_TURN_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_6 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_0 } #define RIGHT_TURN_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_7 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_1 } #define LEFT_RIGHT_TURN_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_0 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO0_0 } #define DRL_LIGHT_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_1 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_4 } #define BRAKE_LIGHT_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_2 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_6 } #define DRL_BRAKE_LIGHT_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_3 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_5 } #define CENTER_CONSOLE_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_4 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_1 } #define BMS_DCDC_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_5 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_3 } #define CENTER_CONSOLE_BMS_DCDC_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_6 } + { PD_PCA9555_I2C_ADDRESS_1, PCA9555_PIN_IO1_2 } #define MCI_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_0 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_4 } #define BPS_LIGHT_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_1 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_6 } #define MCI_BPS_LIGHT_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_2 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_5 } #define SPARE_12V_1_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_3 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_3 } #define SPARE_12V_2_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_4 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_1 } #define SPARE_12V_1_2_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_5 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_2 } #define BMS_AUX_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_6 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_0 } #define DRIVER_FAN_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_7 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_2 } #define BMS_AUX_DRIVER_FAN_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_0 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_1 } #define REAR_CAM_LCD_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_1 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_6 } #define SPARE_5V_DCDC_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_2 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_0 } #define REAR_CAM_LCD_SPARE_5V_DCDC_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_3 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_7 } #define TELEMETRY_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_4 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_3 } #define SPARE_5V_AUX_EN \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_5 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_5 } #define TELEMETRY_SPARE_5V_AUX_DSEL \ - { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO1_6 } + { PD_PCA9555_I2C_ADDRESS_0, PCA9555_PIN_IO0_4 } // Select Pins @@ -154,13 +154,11 @@ // Fault pin addresses // GPIO -#define AUX_FAULT_GPIO_1 \ - { .port = GPIO_PORT_B, .pin = 3 } -#define AUX_FAULT_GPIO_2 \ - { .port = GPIO_PORT_B, .pin = 4 } -#define DCDC_FAULT_GPIO_1 \ - { .port = GPIO_PORT_A, .pin = 15 } -#define DCDC_FAULT_GPIO_2 \ - { .port = GPIO_PORT_B, .pin = 5 } -#define DCDC_FAULT_GPIO_3 \ - { .port = GPIO_PORT_A, .pin = 6 } +#define AUX_VALID1 \ + { .port = GPIO_PORT_B, .pin = 10 } +#define AUX_VALID2 \ + { .port = GPIO_PORT_B, .pin = 2 } +#define DCDC_VALID1 \ + { .port = GPIO_PORT_B, .pin = 1 } +#define DCDC_VALID2 \ + { .port = GPIO_PORT_B, .pin = 0 } diff --git a/projects/power_distribution/inc/power_seq_fsm.h b/projects/power_distribution/inc/power_seq_fsm.h index d15a8191a..c0c8034ca 100644 --- a/projects/power_distribution/inc/power_seq_fsm.h +++ b/projects/power_distribution/inc/power_seq_fsm.h @@ -7,8 +7,8 @@ #include "task.h" // TODO: figure out actual values for timeout -#define BMS_RESPONSE_TIMEOUT_MS 10000 -#define MCI_RESPONSE_TIMEOUT_MS 12000 +#define BMS_RESPONSE_TIMEOUT_MS 3000 +#define MCI_RESPONSE_TIMEOUT_MS 300 #define NUM_POWER_STATES 6 diff --git a/projects/power_distribution/src/lights_fsm.c b/projects/power_distribution/src/lights_fsm.c index 2465f7fac..f8c1911a7 100644 --- a/projects/power_distribution/src/lights_fsm.c +++ b/projects/power_distribution/src/lights_fsm.c @@ -4,6 +4,13 @@ #include "outputs.h" #include "power_distribution_getters.h" +static void prv_brake_lights() { + if (get_pedal_output_brake_output()) + pd_set_output_group(OUTPUT_GROUP_BRAKE, OUTPUT_STATE_ON); + else + pd_set_output_group(OUTPUT_GROUP_BRAKE, OUTPUT_STATE_OFF); +} + // Placeholder GPIO Address, will be updated GpioAddress RIGHT_LIGHT_ADDR = { .port = GPIO_PORT_B, .pin = 5 }; GpioAddress LEFT_LIGHT_ADDR = { .port = GPIO_PORT_A, .pin = 15 }; @@ -12,7 +19,7 @@ GpioAddress LEFT_LIGHT_ADDR = { .port = GPIO_PORT_A, .pin = 15 }; static SoftTimer s_timer_single; static EELightType light_id_callback; -FSM(lights, NUM_LIGHTS_STATES); +FSM(lights, NUM_LIGHTS_STATES, TASK_STACK_512); static OutputState left_signal_state = OUTPUT_STATE_OFF; static OutputState right_signal_state = OUTPUT_STATE_OFF; static LightsStateId fsm_prev_state = INIT_STATE; @@ -55,6 +62,7 @@ static void prv_lights_signal_blinker(SoftTimerId id) { } static void prv_init_state_input(Fsm *fsm, void *context) { + prv_brake_lights(); // can transition to LEFT, RIGHT, HAZARD EELightType light_event = get_steering_info_input_lights(); HazardStatus hazard_status = get_cc_power_control_hazard_enabled(); @@ -75,6 +83,7 @@ static void prv_init_state_output(void *context) { } static void prv_left_signal_input(Fsm *fsm, void *context) { + prv_brake_lights(); // can transition to INIT, RIGHT, HAZARD EELightType light_event = get_steering_info_input_lights(); HazardStatus hazard_status = get_cc_power_control_hazard_enabled(); @@ -99,6 +108,7 @@ static void prv_left_signal_output(void *context) { } static void prv_right_signal_input(Fsm *fsm, void *context) { + prv_brake_lights(); // can transition to INIT, LEFT, HAZARD EELightType light_event = get_steering_info_input_lights(); HazardStatus hazard_status = get_cc_power_control_hazard_enabled(); @@ -123,6 +133,7 @@ static void prv_right_signal_output(void *context) { } static void prv_hazard_input(Fsm *fsm, void *context) { + prv_brake_lights(); // can transition to INIT, BPS_FAULT EELightType light_event = get_steering_info_input_lights(); HazardStatus hazard_status = get_cc_power_control_hazard_enabled(); diff --git a/projects/power_distribution/src/main.c b/projects/power_distribution/src/main.c index 757cace7c..52869a792 100644 --- a/projects/power_distribution/src/main.c +++ b/projects/power_distribution/src/main.c @@ -2,6 +2,7 @@ #include "bts_load_switch.h" #include "can.h" +#include "can_board_ids.h" #include "gpio.h" #include "i2c.h" #include "interrupt.h" @@ -13,11 +14,9 @@ #include "power_seq_fsm.h" #include "tasks.h" -#define DEVICE_ID 0x06 - static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = DEVICE_ID, + .device_id = SYSTEM_CAN_DEVICE_POWER_DISTRIBUTION, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, @@ -31,6 +30,7 @@ I2CSettings i2c_settings = { }; void pre_loop_init() { + pca9555_gpio_init(I2C_PORT_1); pd_output_init(); pd_sense_init(); adc_init(); @@ -58,9 +58,8 @@ int main() { log_init(); interrupt_init(); gpio_init(); - i2c_init(I2C_PORT_1, &i2c_settings); - pca9555_gpio_init(I2C_PORT_1); can_init(&s_can_storage, &can_settings); + i2c_init(I2C_PORT_1, &i2c_settings); // set_master_cycle_time(250); // Give it enough time to run an entire medium cycle // set_medium_cycle_count(2); // adjust medium cycle count to run once per 500ms init_power_seq(); diff --git a/projects/power_distribution/src/output_config.c b/projects/power_distribution/src/output_config.c index 0c1729daa..e191dab5e 100644 --- a/projects/power_distribution/src/output_config.c +++ b/projects/power_distribution/src/output_config.c @@ -310,6 +310,8 @@ static OutputGroupDef s_output_group_hazards = { .outputs = { LEFT_TURN, RIGHT_TURN }, }; +static OutputGroupDef s_output_group_brake = { .num_outputs = 1, .outputs = { BRAKE_LIGHT } }; + static OutputGroupDef s_output_group_power_off = { .num_outputs = 2, .outputs = { CENTER_CONSOLE, BMS_DCDC } }; @@ -335,4 +337,9 @@ const OutputGroupDef *g_output_group_map[NUM_OUTPUT_GROUPS] = { [OUTPUT_GROUP_LIGHTS_LEFT_TURN] = &s_output_group_left_signal, [OUTPUT_GROUP_LIGHTS_RIGHT_TURN] = &s_output_group_right_signal, [OUTPUT_GROUP_LIGHTS_HAZARD] = &s_output_group_hazards, + [OUTPUT_GROUP_BRAKE] = &s_output_group_brake, + [OUTPUT_GROUP_POWER_OFF] = &s_output_group_power_off, + [OUTPUT_GROUP_POWER_ON] = &s_output_group_power_on, + [OUTPUT_GROUP_POWER_DRIVE] = &s_output_group_power_drive, + [OUTPUT_GROUP_POWER_FAULT] = &s_output_group_power_fault, }; diff --git a/projects/power_distribution/src/pd_fault.c b/projects/power_distribution/src/pd_fault.c index 01fa19211..80657e444 100644 --- a/projects/power_distribution/src/pd_fault.c +++ b/projects/power_distribution/src/pd_fault.c @@ -3,17 +3,17 @@ #include "adc.h" #include "exported_enums.h" #include "gpio.h" +#include "log.h" #include "pin_defs.h" #include "power_distribution_setters.h" static uint8_t s_fault_bitset = 0; // Fault pin address definitions -static const GpioAddress aux_fault_gpio_1 = AUX_FAULT_GPIO_1; -static const GpioAddress aux_fault_gpio_2 = AUX_FAULT_GPIO_2; -static const GpioAddress dcdc_fault_gpio_1 = DCDC_FAULT_GPIO_1; -static const GpioAddress dcdc_fault_gpio_2 = DCDC_FAULT_GPIO_2; -static const GpioAddress dcdc_fault_gpio_3 = DCDC_FAULT_GPIO_3; +static const GpioAddress aux_valid1 = AUX_VALID1; +static const GpioAddress aux_valid2 = AUX_VALID2; +static const GpioAddress dcdc_valid1 = DCDC_VALID1; +static const GpioAddress dcdc_valid2 = DCDC_VALID2; static void prv_set_fault_bit(uint8_t mask, bool condition) { if (condition) { @@ -24,27 +24,23 @@ static void prv_set_fault_bit(uint8_t mask, bool condition) { } static bool prv_check_aux_fault(void) { - GpioState aux_gpio_1_state; - GpioState aux_gpio_2_state; - if (!status_ok(gpio_get_state(&aux_fault_gpio_1, &aux_gpio_1_state)) || - !status_ok(gpio_get_state(&aux_fault_gpio_2, &aux_gpio_2_state))) { + GpioState aux_valid1_state; + GpioState aux_valid2_state; + if (!status_ok(gpio_get_state(&aux_valid1, &aux_valid1_state)) || + !status_ok(gpio_get_state(&aux_valid2, &aux_valid2_state))) { return true; } - return (aux_gpio_1_state == GPIO_STATE_LOW || aux_gpio_2_state == GPIO_STATE_LOW); + return (aux_valid1_state == GPIO_STATE_HIGH || aux_valid2_state == GPIO_STATE_HIGH); } static bool prv_check_dcdc_fault(void) { - GpioState dcdc_gpio_1_state; - GpioState dcdc_gpio_2_state; - GpioState dcdc_gpio_3_state; - if (!status_ok(gpio_get_state(&dcdc_fault_gpio_1, &dcdc_gpio_1_state)) || - !status_ok(gpio_get_state(&dcdc_fault_gpio_2, &dcdc_gpio_2_state)) || - !status_ok(gpio_get_state(&dcdc_fault_gpio_3, &dcdc_gpio_3_state))) { + GpioState dcdc_valid1_state; + GpioState dcdc_valid2_state; + if (!status_ok(gpio_get_state(&dcdc_valid1, &dcdc_valid1_state)) || + !status_ok(gpio_get_state(&dcdc_valid2, &dcdc_valid2_state))) { return true; } - - return (dcdc_gpio_1_state == GPIO_STATE_LOW || dcdc_gpio_2_state == GPIO_STATE_LOW || - dcdc_gpio_3_state == GPIO_STATE_HIGH); + return (dcdc_valid1_state == GPIO_STATE_HIGH || dcdc_valid2_state == GPIO_STATE_HIGH); } uint8_t check_pd_fault(void) { diff --git a/projects/power_distribution/src/power_seq_fsm.c b/projects/power_distribution/src/power_seq_fsm.c index b03112a55..0e2423b2c 100644 --- a/projects/power_distribution/src/power_seq_fsm.c +++ b/projects/power_distribution/src/power_seq_fsm.c @@ -12,7 +12,7 @@ return; \ } -FSM(power_seq, NUM_POWER_STATES); +FSM(power_seq, NUM_POWER_STATES, TASK_STACK_256); static PowerFsmContext power_context = { 0 }; @@ -32,7 +32,7 @@ static void prv_off_state_input(Fsm *fsm, void *context) { } CentreConsoleCCPwrEvent cc_power_event = get_cc_power_control_power_event(); if (cc_power_event == EE_CC_PWR_CTL_EVENT_BTN_AND_BRAKE) { - power_context.target_state = POWER_STATE_DRIVE; + power_context.target_state = POWER_STATE_ON; fsm_transition(fsm, TRANSMIT_BMS_CLOSE_RELAYS); } else if (cc_power_event == EE_CC_PWR_CTL_EVENT_BTN) { power_context.target_state = POWER_STATE_ON; @@ -72,14 +72,6 @@ static void prv_on_state_output(void *context) { static void prv_on_state_input(Fsm *fsm, void *context) { pd_fault_ok_or_transition(fsm); - if (power_context.target_state == POWER_STATE_OFF) { - fsm_transition(fsm, POWER_STATE_OFF); - return; - } - if (power_context.target_state == POWER_STATE_DRIVE) { - fsm_transition(fsm, TURN_ON_DRIVE_OUTPUTS); - return; - } if (!get_received_cc_power_control()) { return; diff --git a/projects/power_distribution/test/test_lights_fsm.c b/projects/power_distribution/test/test_lights_fsm.c index 05832e171..5ce98066b 100644 --- a/projects/power_distribution/test/test_lights_fsm.c +++ b/projects/power_distribution/test/test_lights_fsm.c @@ -3,7 +3,7 @@ #include "task_test_helpers.h" #include "unity.h" -#define HAZARD_SIGNAL_MSG g_rx_struct.power_info_hazard_state +#define HAZARD_SIGNAL_MSG g_rx_struct.cc_power_control_hazard_enabled #define STEERING_ANALOG_SIGNAL_MSG g_rx_struct.steering_info_input_lights void setup_test(void) { diff --git a/projects/power_select/src/power_select_aux_bat_task.c b/projects/power_select/src/power_select_aux_bat_task.c index 2054d7124..c83b18be0 100644 --- a/projects/power_select/src/power_select_aux_bat_task.c +++ b/projects/power_select/src/power_select_aux_bat_task.c @@ -13,7 +13,7 @@ static uint16_t adc_reading_voltage; static uint16_t adc_reading_current; static uint16_t adc_reading_temp; -FSM(aux_bat, NUM_POWER_SELECT_STATES); +FSM(aux_bat, NUM_POWER_SELECT_STATES, TASK_STACK_512); static void prv_aux_bat_inactive_input(Fsm *fsm, void *context) { GpioState state = GPIO_STATE_LOW; diff --git a/projects/power_select/src/power_select_dcdc_task.c b/projects/power_select/src/power_select_dcdc_task.c index 6348cd728..22b2b814d 100644 --- a/projects/power_select/src/power_select_dcdc_task.c +++ b/projects/power_select/src/power_select_dcdc_task.c @@ -13,7 +13,7 @@ static uint16_t adc_reading_voltage; static uint16_t adc_reading_current; static uint16_t adc_reading_temp; -FSM(dcdc, NUM_POWER_SELECT_STATES); +FSM(dcdc, NUM_POWER_SELECT_STATES, TASK_STACK_512); static void prv_dcdc_inactive_input(Fsm *fsm, void *context) { GpioState state = GPIO_STATE_LOW; diff --git a/projects/power_select/src/power_select_power_supply_task.c b/projects/power_select/src/power_select_power_supply_task.c index 9b3b19d10..51541f841 100644 --- a/projects/power_select/src/power_select_power_supply_task.c +++ b/projects/power_select/src/power_select_power_supply_task.c @@ -11,7 +11,7 @@ const GpioAddress g_power_supply_current_pin = POWER_SELECT_PWR_SUP_ISENSE_ADDR; static uint16_t adc_reading_voltage; static uint16_t adc_reading_current; -FSM(power_supply, NUM_POWER_SELECT_STATES); +FSM(power_supply, NUM_POWER_SELECT_STATES, TASK_STACK_512); static void prv_power_supply_inactive_input(Fsm *fsm, void *context) { GpioState state = GPIO_STATE_LOW; diff --git a/projects/solar_sense/src/main.c b/projects/solar_sense/src/main.c index afc0fadd2..642bc9a04 100644 --- a/projects/solar_sense/src/main.c +++ b/projects/solar_sense/src/main.c @@ -1,5 +1,6 @@ #include +#include "can_board_ids.h" #include "log.h" #include "master_task.h" #include "mppt.h" @@ -18,7 +19,7 @@ void run_slow_cycle() {} static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_SOLAR_SENSE, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/steering/src/main.c b/projects/steering/src/main.c index eddbbdeb5..e32122164 100644 --- a/projects/steering/src/main.c +++ b/projects/steering/src/main.c @@ -3,6 +3,7 @@ #include "adc.h" #include "can.h" +#include "can_board_ids.h" #include "gpio.h" #include "gpio_it.h" #include "gpio_mcu.h" @@ -11,11 +12,9 @@ #include "steering_task.h" #include "tasks.h" -#define DEVICE_ID 0x02 - static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = DEVICE_ID, + .device_id = SYSTEM_CAN_DEVICE_STEERING, .bitrate = CAN_HW_BITRATE_125KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/telemetry/src/main.c b/projects/telemetry/src/main.c index cd6d7a765..bc6f6eb55 100644 --- a/projects/telemetry/src/main.c +++ b/projects/telemetry/src/main.c @@ -14,7 +14,7 @@ static const CanMessageId telemetry_ids[] = { static CanStorage s_can_storage = { 0 }; const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_TELEMETRY, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/projects/uv_cutoff/src/main.c b/projects/uv_cutoff/src/main.c index bc9e46de4..ee82337a9 100644 --- a/projects/uv_cutoff/src/main.c +++ b/projects/uv_cutoff/src/main.c @@ -36,7 +36,7 @@ static const GpioAddress lights = { .port = LIGHTS_PORT, .pin = LIGHTS_PIN }; static CanStorage s_can_storage = { 0 }; static const CanSettings can_settings = { - .device_id = 0x1, + .device_id = SYSTEM_CAN_DEVICE_UV_CUTOFF, .bitrate = CAN_HW_BITRATE_500KBPS, .tx = { GPIO_PORT_A, 12 }, .rx = { GPIO_PORT_A, 11 }, diff --git a/py/example/main.py b/py/example/main.py index 547f1eaff..cb082ae7a 100644 --- a/py/example/main.py +++ b/py/example/main.py @@ -1,3 +1,6 @@ +''' +Example script +''' from example_module.add import add print("1 + 1 =", add(1, 1)) diff --git a/py/example_module/add.py b/py/example_module/add.py index 19cf2a0e4..e60341a9e 100644 --- a/py/example_module/add.py +++ b/py/example_module/add.py @@ -1,2 +1,8 @@ -def add(a, b): - return a + b \ No newline at end of file +''' +Example module add +''' + + +def add(lhs, rhs): + '''add two numbers''' + return lhs + rhs diff --git a/py/motor_controller/config.json b/py/motor_controller/config.json new file mode 100644 index 000000000..68c4a6bcc --- /dev/null +++ b/py/motor_controller/config.json @@ -0,0 +1,3 @@ +{ + "no_lint": true +} \ No newline at end of file diff --git a/py/motor_controller/main.py b/py/motor_controller/main.py index a6206bb27..728c54261 100644 --- a/py/motor_controller/main.py +++ b/py/motor_controller/main.py @@ -105,15 +105,15 @@ def main(): "brake": 0, } - rx = defaultdict(int) + rx_data = defaultdict(int) while True: # std input state |= handle_stdin() # Can RX - rx |= rx_all(proc) + rx_data |= rx_all(proc) - update_display(state, rx) + update_display(state, rx_data) # every 200 ms can.send_centre_console_drive_output( diff --git a/scons/build.scons b/scons/build.scons index 6cbffb1b5..4eedf836d 100644 --- a/scons/build.scons +++ b/scons/build.scons @@ -1,10 +1,8 @@ from scons.common import parse_config -import subprocess -import os +from pathlib import Path Import("VARS") -TYPE = VARS.get("TYPE") TARGET = VARS.get("TARGET") PLATFORM = VARS.get("PLATFORM") env = VARS.get("env") @@ -20,16 +18,9 @@ PY_DIR = ROOT.Dir('py') PROJ_DIR = ROOT.Dir('projects') LIB_DIR = ROOT.Dir('libraries') SMOKE_DIR = ROOT.Dir('smoke') -CAN_DIR = ROOT.Dir('can') - -PROJ_DIRS = [entry for entry in PROJ_DIR.glob('*')] -LIB_DIRS = [entry for entry in LIB_DIR.glob('*')] -SMOKE_DIRS = [entry for entry in SMOKE_DIR.glob('*')] LIB_BIN_DIR = BIN_DIR.Dir('libraries') -PLATFORM_DIR = ROOT.Dir('platform') - CODEGEN_DIR = LIB_DIR.Dir("codegen") BOARDS_DIR = CODEGEN_DIR.Dir("boards") GENERATOR = CODEGEN_DIR.File("generator.py") @@ -37,180 +28,147 @@ TEMPLATES_DIR = CODEGEN_DIR.Dir("templates") LIBRARIES_INC_DIR = LIB_DIR.Dir("ms-common").Dir("inc") -# Recursively get library dependencies for entry + +def src(path): + # return all source files within a path + srcs = [] + for file in path.glob("src/*.[cs]") + path.glob(f"src/{PLATFORM}/*.[cs]"): + if file.abspath.startswith(OBJ_DIR.abspath): + srcs.append(file) + else: + srcs.append(OBJ_DIR.File(file.path)) + return srcs + + +def inc(path): + # return all include directories within a path + return [path.Dir("inc"), path.Dir("inc").Dir(PLATFORM)] + + def get_lib_deps(entry): + # Recursively get library dependencies for entry config = parse_config(entry) deps = config['libs'] + config['{}_libs'.format(PLATFORM)] for dep in deps: deps += get_lib_deps(LIB_DIR.Dir(dep)) return deps -def lib_bin(lib_name): - return BIN_DIR.Dir(LIB_DIR.name).File('lib{}.a'.format(lib_name)) - -# ELFs are used for gdb and x86 -def proj_elf(proj_name, is_smoke=False): - return BIN_DIR.Dir(SMOKE_DIR.name if is_smoke else PROJ_DIR.name).File(proj_name) - -# .bin is used for flashing to MCU -def proj_bin(proj_name, is_smoke=False): - return proj_elf(proj_name, is_smoke).File(proj_name + '.bin') ########################################################### # Header file generation from jinja templates ########################################################### -def generate_can_files(env, target=[], source=[], project=TARGET, is_smoke=False): - source_yaml = BOARDS_DIR.File(project + ".yaml") - if is_smoke: - project_can_dir = OBJ_DIR.Dir("smoke").Dir(project).Dir("can") - else: - project_can_dir = OBJ_DIR.Dir("projects").Dir(project).Dir("can") +autogen_sources = [BOARDS_DIR.glob("*"), TEMPLATES_DIR.glob("*"), GENERATOR] + +env.Command( + LIBRARIES_INC_DIR.File("can_board_ids.h"), + autogen_sources, + env.Action(f"python3 {GENERATOR} -f {LIBRARIES_INC_DIR} -t can_board_ids.h.jinja", + f"Autogen {LIBRARIES_INC_DIR}/can_board_ids.h") +) + + +def generate_can_files(env, project): + project_can_dir = OBJ_DIR.Dir(project).Dir("can") source_dir = project_can_dir.Dir("src") header_dir = project_can_dir.Dir("inc") - source += [BOARDS_DIR, TEMPLATES_DIR, GENERATOR] - header_files = [] source_files = [] source_command = f"-f {source_dir} -t" header_command = f"-f {header_dir} -t" # TODO: Fix up system_can.dbc output directory - for template in TEMPLATES_DIR.glob('*.jinja'): + # project specific files + header_command += " can_codegen.h.jinja" + header_files.append(header_dir.File("can_codegen.h")) + for template in TEMPLATES_DIR.glob('_*.jinja'): # name of output file - file_name = os.path.splitext(template.name)[0] - if file_name.startswith("_"): - file_name = project + file_name - if file_name == "can.py": - env.Command( - PY_DIR.File(file_name), - [BOARDS_DIR, TEMPLATES_DIR, GENERATOR], - f"python3 {GENERATOR} -f {PY_DIR} -t {template.name}" - ) - elif file_name == "can_board_ids.h": - env.Command( - LIBRARIES_INC_DIR.File(file_name), - [BOARDS_DIR, TEMPLATES_DIR, GENERATOR], - f"python3 {GENERATOR} -f {LIBRARIES_INC_DIR} -t {template.name}" - ) - target.append(LIBRARIES_INC_DIR.File(file_name)) - elif ".c" in file_name: + file_name = Path(project).stem + Path(template.name).stem + if ".c" in file_name: source_command += " " + template.name source_files.append(source_dir.File(file_name)) else: header_command += " " + template.name header_files.append(header_dir.File(file_name)) - source.append(source_yaml) - # env.Command(header_files, source, f"python3 {GENERATOR} -b {project} {header_command}") - # env.Command(source_files, source, f"python3 {GENERATOR} -b {project} {source_command}") - command = f"python3 {GENERATOR} -b {project} {source_command} {header_command}" - env.Command(header_files + source_files, source, command) + command = env.Action(f"python3 {GENERATOR} -b {Path(project).stem} {source_command} {header_command}", + f"Autogen {project} can files") + # print([f.path for f in header_files + source_files]) + env.Command(header_files + source_files, autogen_sources, command) # Add a VariantDir that point to can folder. Create the can target specific for the project - VariantDir(project_can_dir, CAN_DIR, duplicate=0) - source_files = [] - source_files += project_can_dir.Dir('src').glob('*.[cs]') - source_files += project_can_dir.Dir('src').Dir(PLATFORM).glob('*.[cs]') + VariantDir(project_can_dir, ROOT.Dir('can'), duplicate=0) + return src(project_can_dir), [header_dir] + inc(ROOT.Dir("can")) - target += source_files + header_files - return source_files, header_dir -def addBuildPath(string: str): - if (not string.startswith('build')): - return f"#/{OBJ_DIR.path}/{string}" - else: - return f"#/{string}" +########################################################### +# Create appropriate targets for all libraries +########################################################### +# Just include all library headers +# This resolves dependency issues like ms-freertos including FreeRTOS headers +# even though FreeRTOS depends on ms-freertos, not the other way around +lib_incs = [inc(lib_dir) for lib_dir in LIB_DIR.glob('*')] +for entry in LIB_DIR.glob('*'): + config = parse_config(entry) + lib_deps = get_lib_deps(entry) + target = env.Library( + target=LIB_BIN_DIR.File(f'lib{entry.name}.a'), + source=src(entry), + LIBS=env['LIBS'] + lib_deps * 2, + LIBPATH=[LIB_BIN_DIR], + CPPPATH=env['CPPPATH'] + lib_incs, + CCFLAGS=env['CCFLAGS'] + config['cflags'], + ) + Alias(entry.path, target) + Alias(entry.name, target) -# Create appropriate targets for all projects and libraries -for entry in PROJ_DIRS + LIB_DIRS + SMOKE_DIRS: - srcs = [] - inc_dirs = [] - lib_incs = [] - +########################################################### +# Create appropriate targets for all projects and smoke projects +########################################################### +for entry in PROJ_DIR.glob('*') + SMOKE_DIR.glob('*'): config = parse_config(entry) - - if config["can"]: - is_smoke = entry in SMOKE_DIRS - can_location_name = entry.name + incs = inc(entry) + srcs = src(entry) + + if config["can"]: # Add Autogenerated files - can_sources, can_header_dir = generate_can_files(env, project=can_location_name, is_smoke=is_smoke) + can_sources, can_headers = generate_can_files(env, entry.path) srcs += can_sources - inc_dirs.append(can_header_dir) - - if "include" in config: - for i in config["include"]: - inc_dirs.append(Dir(i)) - - if "sources" in config: - for i in config["sources"]: - srcs.append(File(i)) - - # Glob the source files from OBJ_DIR because it's a variant dir - # See: https://scons.org/doc/1.2.0/HTML/scons-user/x3346.html - # str(entry) is e.g. 'projects/example', so this is like build/obj/projects/example/src - srcs += entry.Dir('src').glob('*.[cs]') - srcs += entry.Dir('src').Dir(PLATFORM).glob('*.[cs]') - - inc_dirs.append(entry.Dir('inc')) - inc_dirs.append(entry.Dir('inc').Dir(PLATFORM)) - - # Just include all library headers - # This resolves dependency issues like ms-freertos including FreeRTOS headers - # even though FreeRTOS depends on ms-freertos, not the other way around - lib_incs += [lib_dir.Dir('inc') for lib_dir in LIB_DIRS] - lib_incs += [lib_dir.Dir('inc').Dir(PLATFORM) for lib_dir in LIB_DIRS] - - # Add #/build/{PLATFORM} to srcs path so that .o files stays in build - srcs = [addBuildPath(x.path) for x in srcs] - inc_dirs = [addBuildPath(x.path) for x in inc_dirs] - - env.Append(CPPDEFINES=[GetOption('define')]) - if entry in PROJ_DIRS or entry in SMOKE_DIRS: - # print(entry, srcs) - is_smoke = entry in SMOKE_DIRS - lib_deps = get_lib_deps(entry) - output = proj_elf(entry.name, is_smoke) - # SCons automagically handles object creation and linking - - target = env.Program( - target=output, - source=srcs, - CPPPATH=env['CPPPATH'] + [inc_dirs, lib_incs], - # link each library twice so that dependency cycles are resolved - # See: https://stackoverflow.com/questions/45135 - LIBS=env['LIBS'] + lib_deps * 2, - LIBPATH=[LIB_BIN_DIR], - CCFLAGS=env['CCFLAGS'] + config['cflags'], - ) - - # .bin file only required for arm, not x86 - if PLATFORM == 'arm': - target = env.Bin(target=proj_bin(entry.name, is_smoke), source=target) - elif entry in LIB_DIRS: - output = lib_bin(entry.name) - target = env.Library( - target=output, - source=srcs, - CPPPATH=env['CPPPATH'] + [inc_dirs, lib_incs], - CCFLAGS=env['CCFLAGS'] + config['cflags'], - ) - + incs += can_headers + + incs += map(ROOT.Dir, config.get("include", [])) + srcs += map(OBJ_DIR.File, config.get("sources", [])) + + lib_deps = get_lib_deps(entry) + # SCons automagically handles object creation and linking + target = env.Program( + target=BIN_DIR.File(entry.path), + source=srcs, + CPPPATH=env['CPPPATH'] + incs + lib_incs, + # link each library twice so that dependency cycles are resolved + # See: https://stackoverflow.com/questions/45135 + LIBS=env['LIBS'] + lib_deps * 2, + LIBPATH=[LIB_BIN_DIR], + CCFLAGS=env['CCFLAGS'] + config['cflags'], + ) + + # .bin file only required for arm, not x86 + if PLATFORM == 'arm': + target = env.Bin(target=BIN_DIR.File(entry.path + '.bin'), + source=target) + # Create an alias for the entry so we can do `scons leds` and it Just Works + Alias(entry.path, target) Alias(entry.name, target) ########################################################### # Python ########################################################### -def run_python(target, source, env): - py_env = os.environ.copy() - py_env["PYTHONPATH"] = os.path.abspath("py/") - subprocess.run(["python3", f"py/{TARGET}/main.py"], env=py_env).check_returncode() +for entry in PY_DIR.glob("*", exclude=["*.*", "__pycache__"]): + target = env.Command(entry.path, [], + f"PYTHONPATH={PY_DIR.path} python3 {entry.path}/main.py") + Alias(entry.path, target) + Alias(entry.name, target) # Build all projects when you just run `scons` -if (TYPE != 'python'): - Default(TARGET or [proj.name for proj in PROJ_DIRS]) -else: - py = Command('py.txt', [], run_python) - Default(py) - Depends(py, PY_DIR.File("can.py")) +Default(TARGET or [e.path for e in PROJ_DIR.glob('*')]) diff --git a/scons/common.py b/scons/common.py index 0d7223ba9..f429f0f20 100644 --- a/scons/common.py +++ b/scons/common.py @@ -1,4 +1,7 @@ import json +import subprocess +import serial # pip install pyserial + def parse_config(entry): # Default config to empty for fields that don't exist @@ -19,3 +22,35 @@ def parse_config(entry): for key, value in config.items(): ret[key] = value return ret + + +def flash_run(entry): + '''flash and run file, return a pyserial object which monitors the device serial output''' + try: + output = subprocess.check_output(["ls", "/dev/serial/by-id/"]) + device_path = f"/dev/serial/by-id/{str(output, 'ASCII').strip()}" + serialData = serial.Serial(device_path, 115200) + except: + print() + print("Flashing requires a controller board to be connected, use --platform=x86 for x86 targets") + + OPENOCD = 'openocd' + OPENOCD_SCRIPT_DIR = '/usr/share/openocd/scripts/' + PROBE = 'cmsis-dap' + PLATFORM_DIR = 'platform' + OPENOCD_CFG = [ + OPENOCD, + '-s {}'.format(OPENOCD_SCRIPT_DIR), + '-f interface/{}.cfg'.format(PROBE), + '-f target/stm32f1x.cfg', + '-f {}/stm32f1-openocd.cfg'.format(PLATFORM_DIR), + '-c "stm32f1x.cpu configure -rtos FreeRTOS"', + '-c "stm_flash {}"'.format(entry), + '-c shutdown' + ] + cmd = 'sudo {}'.format(' '.join(OPENOCD_CFG)) + + subprocess.run(cmd, shell=True).check_returncode() + + print("Flash complete") + return serialData diff --git a/scons/lint_format.scons b/scons/lint_format.scons index ad4c6e794..b7a3890eb 100644 --- a/scons/lint_format.scons +++ b/scons/lint_format.scons @@ -1,7 +1,6 @@ from scons.common import parse_config import glob import subprocess -import scons ########################################################### # Variables setup @@ -9,80 +8,41 @@ import scons Import('VARS') -TYPE = VARS.get("TYPE") TARGET = VARS.get("TARGET") ROOT = Dir('#') -PROJ_DIR = ROOT.Dir('projects') -LIB_DIR = ROOT.Dir('libraries') -SMOKE_DIR = ROOT.Dir("SMOKE_DIR") +PROJ_DIRS = ROOT.glob('projects/*') +LIB_DIRS = ROOT.glob('libraries/*') +SMOKE_DIRS = ROOT.glob('smoke/*') +PY_DIRS = ROOT.glob('py/*') -PROJ_DIRS = [entry for entry in PROJ_DIR.glob('*')] -LIB_DIRS = [entry for entry in LIB_DIR.glob('*')] ########################################################### # Linting and Formatting ########################################################### - -# Convert a list of paths/Dirs to space-separated paths. -def dirs_to_str(dir_list): - # Use str(file) to ensure Dir objects are converted to paths. - return ' '.join([str(file) for file in dir_list]) - -# Glob files by extension in a particular directory. Defaults to root directory. -def glob_by_extension(extension, dir='.'): - return glob.glob('{}/**/*.{}'.format(str(dir), extension), recursive=True) - -# Retrieve files to lint - returns a tuple (c_lint_files, py_lint_files) -def get_lint_files(): - c_lint_files = [] - py_lint_files = [] - - lint_dirs = [] - - # Get directories to lint based on PROJECT/LIBRARY args. - # If no PROJECT/LIBRARY argument,lint all directories. - if TYPE == 'project': - lint_dirs.append(PROJ_DIR.Dir(TARGET)) - lint_dirs.append(SMOKE_DIR.Dir(TARGET)) - elif TYPE == 'library': - lint_dirs.append(LIB_DIR.Dir(TARGET)) - else: - lint_dirs += PROJ_DIRS + LIB_DIRS - - # Get all src and header files (*.c, *.h) to lint/format - for dir in lint_dirs: - config = parse_config(dir) - - # Avoid linting/formatting external libraries - if not config.get('no_lint'): - c_lint_files += glob_by_extension('[ch]', dir) - py_lint_files += glob_by_extension('py', dir) - - return (c_lint_files, py_lint_files) - def run_lint(target, source, env): C_LINT_CMD = 'cpplint --quiet' PY_LINT_CMD = 'pylint --rcfile={}/.pylintrc'.format(ROOT.abspath) - c_lint_files, py_lint_files = get_lint_files() - errors = 0 # Lint C source files - if len(c_lint_files) > 0: - print('\nLinting *.[ch] in {}, {} ...'.format(PROJ_DIR, LIB_DIR)) - errors += subprocess.run('{} {}'.format(C_LINT_CMD, dirs_to_str(c_lint_files)), shell=True).returncode + if len(c_files) > 0: + print(f'\nLinting *.[ch] files ...') + errors += subprocess.run(f'{C_LINT_CMD} {c_files_str}', + shell=True).returncode # Lint Python files - if len(py_lint_files) > 0: + if len(py_files) > 0: print('\nLinting *.py files ...') - errors += subprocess.run('{} {}'.format(PY_LINT_CMD, dirs_to_str(py_lint_files)), shell=True).returncode + errors += subprocess.run(f'{PY_LINT_CMD} {py_files_str}', + shell=True).returncode print('Done Linting.') if (errors > 0): Exit("Lint errors") + def run_format(target, source, env): # Formatter configs AUTOPEP8_CONFIG = '-a --max-line-length 100 -r' @@ -91,19 +51,40 @@ def run_format(target, source, env): C_FORMAT_CMD = 'clang-format {}'.format(CLANG_FORMAT_CONFIG) PY_FORMAT_CMD = 'autopep8 {} -i'.format(AUTOPEP8_CONFIG) - c_format_files, py_format_files = get_lint_files() - # Format C source files - if len(c_format_files) > 0: - print('\nFormatting *.[ch] in {}, {} ...'.format(str(PROJ_DIR), str(LIB_DIR))) - subprocess.run('{} {}'.format(C_FORMAT_CMD, dirs_to_str(c_format_files)), shell=True) + if len(c_files) > 0: + print(f'\nFormatting *.[ch] files ...') + subprocess.run(f'{C_FORMAT_CMD} {c_files_str}', shell=True) # Format Python source files - if len(py_format_files) > 0: + if len(py_files) > 0: print('\nFormatting *.py files ...') - subprocess.run('{} {}'.format(PY_FORMAT_CMD, dirs_to_str(py_format_files)), shell=True) + subprocess.run(f'{PY_FORMAT_CMD} {py_files_str}', shell=True) print('Done Formatting.') + +# Retrieve files to lint - returns a tuple (c_lint_files, py_lint_files) +c_files = [] +py_files = [] +# Get directories to lint based on PROJECT/LIBRARY args. +# If no PROJECT/LIBRARY argument,lint all directories. +# Get all src and header files (*.c, *.h) to lint/format +if TARGET: + target_dirs = [ROOT.Dir(TARGET)] +else: + target_dirs = PROJ_DIRS + LIB_DIRS + SMOKE_DIRS + PY_DIRS + +for dir in target_dirs: + config = parse_config(dir) + if config.get('no_lint'): # Avoid linting/formatting external libraries + continue + + c_files += glob.glob(f'{dir.abspath}/**/*.[ch]', recursive=True) + py_files += glob.glob(f'{dir.abspath}/**/*.py', recursive=True) + +c_files_str = ' '.join(c_files) +py_files_str = ' '.join(py_files) + Command('#/lint', [], run_lint) Command('#/format', [], run_format) diff --git a/scons/new_target.scons b/scons/new_target.scons index fdfc3dbea..368aca487 100644 --- a/scons/new_target.scons +++ b/scons/new_target.scons @@ -1,15 +1,6 @@ -#!/usr/bin/env python3 -"""New target script. - -This module sets up the folder structure and config.json for a new project or library. - -Usage: python3 new_target.py project|library name -""" -import os -import textwrap import json -import sys -from string import Template +import jinja2 +from pathlib import Path ########################################################### # Variables setup @@ -17,111 +8,86 @@ from string import Template Import('VARS') -TYPE = VARS.get("TYPE") TARGET = VARS.get("TARGET") -README_TEMPLATE = Template("""\ - - # $name - - """) - -DEFAULT_DEPS = ["FreeRTOS", "ms-common"] - -main_template_file = open(os.path.join('template', 'main_template.txt'), 'r') - -def generate_config(target_type): - """Generates a new config.json file for a project/library. - - Args: - target_type: Either 'project' or 'library' - - Returns: - dict: dictionary representation of the initial config.json file. - """ - deps = DEFAULT_DEPS if target_type == 'project' or target_type == 'smoke' else [] +# default configuration for projects +DEFAULT_CONFIG = {"libs": ["FreeRTOS", "ms-common"]} + + +def new_task(target, task_name): + '''Create a new task within target''' + DATA = {"task_name": task_name} + target_path = Path(target) + target_path.joinpath("inc").mkdir() + target_path.joinpath("src").mkdir() + + templateLoader = jinja2.FileSystemLoader(searchpath="scons/template") + env = jinja2.Environment(loader=templateLoader) + + template = env.get_template("_task.h.jinja") + output = template.render(data=DATA) + target_path.joinpath(f'inc/{task_name}_task.h').write_text(output) - return {"libs": deps} + template = env.get_template("_task.c.jinja") + output = template.render(data=DATA) + target_path.joinpath(f'src/{task_name}_task.c').write_text(output) -def new_target(target_type, name): + +def new_target(target, source, env): """Creates a new project or library. Creates a subfolder in the appropriate folder with the specified name with the following structure: - projects/libraries + project/library/smoke - name - inc - README.md - config.json - src - test - - where config.json is required for the project or library to be valid. - - Args: - target_type: Either 'project' or 'library' or 'python'. - name: The new project or library's name. - - Returns: - None + py + - name + - __init__.py + - main.py """ - if (target_type == 'python'): - return new_py_project(name) + if not TARGET: + print("Missing target. Expected --project=..., or --library=..., or --python=..., or --smoke=...") + return + + task_name = GetOption("task") + if task_name: + new_task(TARGET, task_name) + return - type_folders = { - 'project': 'projects', - 'library': 'libraries', - 'smoke': 'smoke' - } + target_dir = Path(TARGET) + target_dir.mkdir(parents=True) - proj_path = os.path.join(type_folders[target_type], name) - folders = ['src', 'inc', 'test'] + if TARGET.startswith('py'): + target_dir.joinpath('__init__.py').touch() + target_dir.joinpath('main.py').touch() + print(f'Created new {TARGET}') + return - for folder in folders: - os.makedirs(os.path.join(proj_path, folder), exist_ok=True) + for folder in ['src', 'inc', 'test']: + target_dir.joinpath(folder).mkdir(parents=True, exist_ok=True) - with open(os.path.join(proj_path, 'config.json'), 'w') as config_file: - json.dump(generate_config(target_type), config_file, indent=4) + config = [] + if TARGET.startswith("project") or TARGET.startswith("smoke"): + config = DEFAULT_CONFIG - with open(os.path.join(proj_path, 'README.md'), 'w') as readme_file: - readme_file.write(textwrap.dedent(README_TEMPLATE.substitute({'name': name}))) + target_dir.joinpath("config.json").write_text(json.dumps(config, indent=4)) - with open(os.path.join(proj_path, 'src', 'main.c'), 'w') as main_file: - main_file.write(textwrap.dedent(main_template_file.read())) + readme_template = Path("scons/template/README.md") + readme_file = target_dir.joinpath("README.md") + readme_file.write_text(readme_template.read_text() + target_dir.name) - print('Created new {0} {1}'.format(target_type, name)) + main_c_template = Path("scons/template/main.c") + main_c_file = target_dir.joinpath("src/main.c") + main_c_file.write_text(main_c_template.read_text()) -def new_py_project(name): - os.makedirs(os.path.join('py', name), exist_ok=True) - open(os.path.join('py', name, '__init__.py'), 'a').close() - open(os.path.join('py', name, 'main.py'), 'a').close() + print(f'Created new {TARGET}') -def make_new_target(target, source, env): - # No project or library option provided - if not TYPE: - print("Missing project or library name. Expected --project=..., or --library=..., or --python") - sys.exit(1) - - if env.get("smoke") and TYPE == 'project': - new_target('smoke', TARGET) - else: - new_target(TYPE, TARGET) -new = Command('new_proj.txt', [], make_new_target) +new = Command('new_proj.txt', [], new_target) Alias('new', new) -new = Command('new_smoke.txt', [], make_new_target, smoke=True) -Alias('new_smoke', new) diff --git a/scons/new_task.py b/scons/new_task.py deleted file mode 100644 index 3b7e8579f..000000000 --- a/scons/new_task.py +++ /dev/null @@ -1,120 +0,0 @@ -import os -import sys -import jinja2 -import yaml -import argparse -import re - -def read_yaml(yaml_file): - """reads yaml file and returns information in data""" - with open(yaml_file, "r", encoding="utf-8") as f: - data = yaml.load(f, Loader=yaml.FullLoader) - return data - -def get_function_line_spacing(function_words): - """Returns an integer that indicates the amount of - spaces needed leading up to the first open bracket - Loop through the line array until the first open bracket to find where - the parameter declaration starts to determine correct spacing""" - spacing = 0 - bracket_location = -1 - for i, n_m in enumerate(function_words): - if '(' in n_m: - bracket_location = i - break - - spacing += len(n_m) - if '\n' in n_m: - spacing -= 1 - - if bracket_location == -1: - raise Exception("No bracket in provided line!") - - # Count the number of letters leading up to the bracket - for i in range(len(function_words[bracket_location])): - spacing += 1 - if function_words[bracket_location][i] == '(': - break - return spacing - - -def format_function_length(function_line, spacing=0): - """Custom jinja filter that takes in the function string - and format it to indent to a new line whenever string length - reaches 100 characters.""" - - # Splits by whitespace - function_line = re.split(r'(\s+)', function_line) - letter_count = 0 - - spacing += get_function_line_spacing(function_line) - for a_b in enumerate(function_line): - letter_count += len(a_b) - if letter_count >= 100: - a_b = "\n" + (" " * spacing) + a_b - letter_count = len(a_b) - function_line = "".join(function_line) - return function_line - - -def write_template(env, template_name, file_path, data): - """writes and creates a file from jinja template and yaml data""" - template = env.get_template(template_name) - output = template.render(data=data) - with open(file_path, "a", encoding="utf-8") as f: - f.write(output) - -def new_task(type, name, task_name): - folder_choice = { - 'project' : 'projects', - 'library' : 'libraries' - } - subfolders = ['src', 'inc'] - - folder_path = os.path.join(folder_choice[type], name) - - for folder in subfolders: - os.makedirs(os.path.join(folder_path, folder), exist_ok=True) - - DATA = { - "task_name" : task_name, - "proj_name" : name - } - src_path = os.path.join(folder_path, subfolders[0]) - inc_path = os.path.join(folder_path, subfolders[1]) - - for template_iterable in ["_task.c.jinja", "_task.h.jinja"]: - template_name = template_iterable - templateLoader = jinja2.FileSystemLoader(searchpath="scons/template") - env = jinja2.Environment(loader=templateLoader) - env.filters["format_function_length"] = format_function_length - - if ".h.jinja" in template_name: - file_path = inc_path + "/" + name + "_" + task_name + template_name[:-6] - else: - file_path = src_path + "/" + name + "_" + task_name + template_name[:-6] - - write_template(env, template_name, file_path, DATA) - -def make_new_task(target, source, env): - TYPE = env["VARS"]["TYPE"] - TARGET = env["VARS"]["TARGET"] - NAME = env["VARS"]["NAME"] - # No project or library option provided - if TYPE not in ['project', 'libray']: - print("Missing project or library name. Expected --project=..., or --library=...") - sys.exit(1) - - # Chain or's to select the first non-None value - new_task(TYPE, TARGET, NAME) - -def main(): - PARSER = argparse.ArgumentParser() - PARSER.add_argument("-c",'--type', choices=['project', 'library'], dest="type") - PARSER.add_argument("--task_name", dest="task_name") - PARSER.add_argument("-n",'--name', dest="name") - ARGPARSER = PARSER.parse_args() - new_task(ARGPARSER.type, ARGPARSER.name, ARGPARSER.task_name) - -if __name__ == '__main__': - main() diff --git a/scons/template/README.md b/scons/template/README.md new file mode 100644 index 000000000..d54852911 --- /dev/null +++ b/scons/template/README.md @@ -0,0 +1,15 @@ + +# \ No newline at end of file diff --git a/scons/template/_task.c.jinja b/scons/template/_task.c.jinja index f7ed56756..2e8050e36 100644 --- a/scons/template/_task.c.jinja +++ b/scons/template/_task.c.jinja @@ -1,13 +1,12 @@ #include "log.h" #include "tasks.h" -#include "{{data['proj_name']}}_{{data['task_name']}}_task.h" +#include "{{data.task_name}}_task.h" -static SemaphoreHandle_t s_{{data['proj_name']}}_{{data['task_name']}}_sem_handle; -static StaticSemaphore_t s_{{data['proj_name']}}_{{data['task_name']}}_sem; +static SemaphoreHandle_t s_{{data.task_name}}_sem_handle; +static StaticSemaphore_t s_{{data.task_name}}_sem; -void run_{{data['proj_name']}}_{{data['task_name']}}_cycle() -{ - BaseType_t ret = xSemaphoreGive(s_{{data['proj_name']}}_{{data['task_name']}}_sem_handle); +void run_{{data.task_name}}_cycle() { + BaseType_t ret = xSemaphoreGive(s_{{data.task_name}}_sem_handle); if (ret == pdFALSE) { return STATUS_CODE_INTERNAL_ERROR; @@ -16,36 +15,27 @@ void run_{{data['proj_name']}}_{{data['task_name']}}_cycle() return STATUS_CODE_OK; } -TASK({{data['task_name']}}, TASK_MIN_STACK_SIZE) -{ +TASK({{data.task_name}}, TASK_MIN_STACK_SIZE) { int counter = 0; - while (true) - { - xSemaphoreTake(s_{{data['proj_name']}}_{{data['task_name']}}_sem_handle, portMAX_DELAY); + while (true) { + xSemaphoreTake(s_{{data.task_name}}_sem_handle, portMAX_DELAY); counter++; - run_{{data['proj_name']}}_{{data['task_name']}}_fast_cycle(); + run_{{data.task_name}}_fast_cycle(); if ((counter % 10) == 0) - run_{{data['proj_name']}}_{{data['task_name']}}_medium_cycle(); + run_{{data.task_name}}_medium_cycle(); if ((counter % 100) == 0) - run_{{data['proj_name']}}_{{data['task_name']}}_slow_cycle(); + run_{{data.task_name}}_slow_cycle(); xSemaphoreGive(s_end_task_sem); } } -void run_{{data['proj_name']}}_{{data['task_name']}}_fast_cycle() -{ -} +void run_{{data.task_name}}_fast_cycle() {} -void run_{{data['proj_name']}}_{{data['task_name']}}_medium_cycle() -{ -} +void run_{{data.task_name}}_medium_cycle() {} -void run_{{data['proj_name']}}_{{data['task_name']}}_slow_cycle() -{ -} +void run_{{data.task_name}}_slow_cycle() {} -StatusCode init_{{data['proj_name']}}_{{data['task_name']}}() -{ - status_ok_or_return(tasks_init_task({{data['task_name']}}, TASK_PRIORITY(2), NULL)); +StatusCode init_{{data.task_name}}() { + status_ok_or_return(tasks_init_task({{data.task_name}}, TASK_PRIORITY(2), NULL)); return STATUS_CODE_OK; } \ No newline at end of file diff --git a/scons/template/_task.h.jinja b/scons/template/_task.h.jinja index 0502e22a9..238f4cd17 100644 --- a/scons/template/_task.h.jinja +++ b/scons/template/_task.h.jinja @@ -1,14 +1,14 @@ #include "status.h" /* - * Name: {{data['proj_name']}}_{{data['task_name']}} + * Name: {{data.task_name}} * Description: What this task does and to use it * Author: * Date: */ -void run_{{data['proj_name']}}_{{data['task_name']}}_cycle(); -void run_{{data['proj_name']}}_{{data['task_name']}}_fast_cycle(); -void run_{{data['proj_name']}}_{{data['task_name']}}_medium_cycle(); -void run_{{data['proj_name']}}_{{data['task_name']}}_slow_cycle(); -StatusCode init_{{data['proj_name']}}_{{data['task_name']}}(); \ No newline at end of file +void run_{{data.task_name}}_cycle(); +void run_{{data.task_name}}_fast_cycle(); +void run_{{data.task_name}}_medium_cycle(); +void run_{{data.task_name}}_slow_cycle(); +StatusCode init_{{data.task_name}}(); \ No newline at end of file diff --git a/scons/template/main.c b/scons/template/main.c new file mode 100644 index 000000000..edca49486 --- /dev/null +++ b/scons/template/main.c @@ -0,0 +1,26 @@ +#include + +#include "log.h" +#include "master_task.h" +#include "tasks.h" + +void pre_loop_init() {} + +void run_fast_cycle() {} + +void run_medium_cycle() {} + +void run_slow_cycle() {} + +int main() { + tasks_init(); + log_init(); + LOG_DEBUG("Welcome to TEST!"); + + init_master_task(); + + tasks_start(); + + LOG_DEBUG("exiting main?"); + return 0; +} diff --git a/scons/template/main_template.txt b/scons/template/main_template.txt deleted file mode 100644 index 2627f420f..000000000 --- a/scons/template/main_template.txt +++ /dev/null @@ -1,39 +0,0 @@ -#include - -#include "log.h" -#include "tasks.h" -#include "master_task.h" - -void pre_loop_init() -{ - -} - -void run_fast_cycle() -{ - -} - -void run_medium_cycle() -{ - -} - -void run_slow_cycle() -{ - -} - -int main() { - tasks_init(); - log_init(); - LOG_DEBUG("Welcome to TEST!"); - - init_master_task(); - - tasks_start(); - - LOG_DEBUG("exiting main?"); - return 0; -} - diff --git a/scons/test.scons b/scons/test.scons index fe4d8ddfe..317d95ff1 100644 --- a/scons/test.scons +++ b/scons/test.scons @@ -1,33 +1,13 @@ -from scons.common import parse_config +from scons.common import parse_config, flash_run import subprocess -import serial # pip install pyserial +from pathlib import Path Import('VARS') -TYPE = VARS.get("TYPE") TARGET = VARS.get("TARGET") PLATFORM = VARS.get("PLATFORM") env = VARS.get("env") -# Recursively get library dependencies for entry -def get_lib_deps(entry): - config = parse_config(entry) - deps = config['libs'] + config['{}_libs'.format(PLATFORM)] - for dep in deps: - deps += get_lib_deps(LIB_DIR.Dir(dep)) - return deps - -def lib_bin(lib_name): - return BIN_DIR.Dir(LIB_DIR.name).File('lib{}.a'.format(lib_name)) - -# ELFs are used for gdb and x86 -def proj_elf(proj_name, is_smoke=False): - return BIN_DIR.Dir(SMOKE_DIR.name if is_smoke else PROJ_DIR.name).File(proj_name) - -# .bin is used for flashing to MCU -def proj_bin(proj_name, is_smoke=False): - return proj_elf(proj_name, is_smoke).File(proj_name + '.bin') - ROOT = Dir('#') BUILD_DIR = ROOT.Dir('build').Dir(PLATFORM) @@ -38,156 +18,77 @@ TEST_DIR = BUILD_DIR.Dir('test') PROJ_DIR = ROOT.Dir('projects') LIB_DIR = ROOT.Dir('libraries') SMOKE_DIR = ROOT.Dir('smoke') -CAN_DIR = ROOT.Dir('can') -PROJ_DIRS = [entry for entry in PROJ_DIR.glob('*')] -LIB_DIRS = [entry for entry in LIB_DIR.glob('*')] -SMOKE_DIRS = [entry for entry in SMOKE_DIR.glob('*')] +GEN_RUNNER = 'libraries/unity/auto/generate_test_runner.py' +GEN_RUNNER_CONFIG = 'libraries/unity/unity_config.yml' -LIB_BIN_DIR = BIN_DIR.Dir('libraries') +########################################################### +# Create appropriate test targets, (when lib/proj target is defined) +########################################################### +run_list = [] -PLATFORM_DIR = ROOT.Dir('platform') -CODEGEN_DIR = LIB_DIR.Dir("codegen") -BOARDS_DIR = CODEGEN_DIR.Dir("boards") -GENERATOR = CODEGEN_DIR.File("generator.py") -TEMPLATES_DIR = CODEGEN_DIR.Dir("templates") +def add_to_run_list(target, source, env): + run_list.extend(source) -LIBRARIES_INC_DIR = LIB_DIR.Dir("ms-common").Dir("inc") -GEN_RUNNER = 'libraries/unity/auto/generate_test_runner.py' -GEN_RUNNER_CONFIG = 'libraries/unity/unity_config.yml' +def add_test_targets(target, source, env): + entry = ROOT.Dir(Path(target[0].path).relative_to(BIN_DIR.path)) + config = parse_config(entry) -# tests dict maps proj/lib -> list of their test executables -tests = {} - -def addBuildPath(string: str): - if (not string.startswith('build')): - return f"#/{OBJ_DIR.path}/{string}" - else: - return f"#/{string}" - -# Create the test executable targets -for entry in PROJ_DIRS + LIB_DIRS + SMOKE_DIRS: - tests[entry.name] = [] - for test_file in OBJ_DIR.Dir(str(entry)).Dir('test').glob('*.c'): - # Link runner object, test file object, and proj/lib objects - # into executable - config = parse_config(entry) - test_module_name = test_file.name.replace('test_', '').replace('.c', '') - mock_link_flags = [] - if test_module_name in config['mocks']: - mocks = config['mocks'][test_module_name] - mock_link_flags = ['-Wl,-wrap,' + mock for mock in mocks] - - objs = OBJ_DIR.Dir(str(entry.path)).Dir('src').glob('*.o') - objs += OBJ_DIR.Dir(str(entry.path)).Dir('src').Dir(PLATFORM).glob('*.o') - - if config["can"]: - objs += OBJ_DIR.Dir(entry.path).Dir('can').Dir("src").glob('*.o') - objs += OBJ_DIR.Dir(entry.path).Dir('can').Dir("src").Dir(PLATFORM).glob('*.o') - - entry_objects = [] - for obj in objs: - if 'main.o' not in obj.name: - entry_objects.append(obj) - - inc_dirs = [entry.Dir('inc')] - inc_dirs += [entry.Dir('inc').Dir(PLATFORM)] - if config["can"]: - inc_dirs.append(OBJ_DIR.Dir(entry.path).Dir('can').Dir("inc")) - inc_dirs.append(CAN_DIR.Dir("inc")) - lib_incs = [lib_dir.Dir('inc') for lib_dir in LIB_DIRS] - lib_incs += [lib_dir.Dir('inc').Dir(PLATFORM) for lib_dir in LIB_DIRS] - lib_deps = get_lib_deps(entry) - - # Flags used for both preprocessing and compiling - cpppath = env['CPPPATH'] + [inc_dirs, lib_incs] - ccflags = env['CCFLAGS'] + config['cflags'] - - # Create the test_*_runner.c file - runner_file = TEST_DIR.Dir(entry.name).File(test_file.name.replace('.c', '_runner.c')) - test_runner = env.Command(runner_file, test_file, - Action( - 'python3 {} {} $SOURCE $TARGET'.format(GEN_RUNNER, GEN_RUNNER_CONFIG), - cmdstr='Generating test runner $TARGET')) - - output = TEST_DIR.Dir(entry.name).Dir('test').File(test_file.name.replace('.c', '')) - - srcs = [test_file] + test_runner + entry_objects - srcs = [addBuildPath(x.path) for x in srcs] - - target = env.Program( - target=output, - source=srcs, - # We do env['variable'] + [entry-specific variables] to avoid - # mutating the environment for other entries - CPPPATH=cpppath, - LIBS=env['LIBS'] + lib_deps * 2 + ['unity'], - LIBPATH=[LIB_BIN_DIR], - CCFLAGS=ccflags, + if entry.path.startswith("libraries"): + # libraries target will look like libraries/lib[name].a + # extract the name and convert to the directory of the actual library + entry = ROOT.Dir(f"libraries/{entry.name[3:-2]}") + # non-libraries has a main.o that needs to be removed from the source for tests + sources_no_main = list(filter(lambda f: f.name != "main.o", source)) + + # create target for every test + for test_file in entry.glob('test/*.c'): + test_module_name = Path(test_file.path).stem + + mocks = config.get("mocks", {}).get(test_module_name, []) + mock_link_flags = [f'-Wl,-wrap,{mock}' for mock in mocks] + + runner_exec = TEST_DIR.File(f"{entry.path}/bin/{test_module_name}") + + runner_file = TEST_DIR.File(test_file.path) + autogen = env.Action(f'python3 {GEN_RUNNER} {GEN_RUNNER_CONFIG} {test_file.path} {runner_file.path}', + f'Autogen {test_file.path} test_runner') + runner_file = env.Command( + runner_file, + [test_file, ROOT.Dir("libraries/unity/auto").glob("*")], + autogen) + test_sources = [runner_file, OBJ_DIR.File(test_file.path)] + + test_target = env.Program( + target=runner_exec, + source=sources_no_main + test_sources, + LIBS=env['LIBS'] + ['unity'], LINKFLAGS=env['LINKFLAGS'] + mock_link_flags, + PROGEMITTER=None, # don't trigger emitter recursively ) + if PLATFORM == 'arm': - target = env.Bin(target=output.File(test_file.name + '.bin'), source=target) - - # Make test executable depend on the project / library final target - if entry in PROJ_DIRS: - Depends(target, proj_elf(entry.name, entry in SMOKE_DIRS)) - elif entry in LIB_DIRS: - Depends(target, lib_bin(entry.name)) - - # Add to tests dict - tests[entry.name] += [node for node in target] - -def get_test_list(): - # Based on the project/library and test in options, - # create a list of tests to run - # Assume only one of project or library is set - entry = TARGET - if entry and tests.get(entry): - if GetOption('testfile'): - return [test for test in tests[entry] if (test.name + '.').startswith(f"test_{GetOption('testfile')}.")] - else: - return [test for test in tests[entry]] - else: - ret = [] - for test_list in tests.values(): - ret += test_list - return ret - -def test_runner(target, source, env): - test_list = get_test_list() - - if PLATFORM == "arm": - output = subprocess.check_output(["ls", "/dev/serial/by-id/"]) - device_path = f"/dev/serial/by-id/{str(output, 'ASCII').strip()}" - serialData = serial.Serial(device_path,115200) - - fails = 0 - for test in test_list: + test_target = env.Bin(target=ROOT.File(runner_exec.path+'.bin'), + source=test_target) + env.Command(f"test/{entry.path}/{test_module_name}", + test_target, env.Action(add_to_run_list, None)) + # target and source are not modified + # this emitter only adds the test targets based on the project/library's inc + src + return target, source + + +def run_test(target, source, env): + fails = [] + for test_name, test_file in zip(source, run_list): if PLATFORM == "x86": - test_process = subprocess.run(test.get_path()) - fails += (test_process.returncode != 0) + test_process = subprocess.run(test_file.path) + if test_process.returncode != 0: + fails.append(test_name) elif PLATFORM == "arm": - OPENOCD = 'openocd' - OPENOCD_SCRIPT_DIR = '/usr/share/openocd/scripts/' - PROBE = 'cmsis-dap' - OPENOCD_CFG = [ - OPENOCD, - '-s {}'.format(OPENOCD_SCRIPT_DIR), - '-f interface/{}.cfg'.format(PROBE), - '-f target/stm32f1x.cfg', - '-f {}/stm32f1-openocd.cfg'.format(PLATFORM_DIR), - '-c "stm32f1x.cpu configure -rtos FreeRTOS"', - '-c "stm_flash {}"'.format(test), - '-c shutdown' - ] - cmd = 'sudo {}'.format(' '.join(OPENOCD_CFG)) - print(f"Flashing {test}") - subprocess.run(cmd, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - print(f"Starting {test}") + serialData = flash_run(test_file) # wait until test ok or fail while True: @@ -196,10 +97,24 @@ def test_runner(target, source, env): if line.startswith('OK'): break if line.startswith('FAIL'): - fails += 1 + fails.append(test_name) break - print(f"{len(test_list)} Files tested {fails} Failures") + print(f"{len(run_list)} Files tested {len(fails)} Failures") + for fail in fails: + print(f" {fail}") + return "" + + +env.Append(PROGEMITTER=add_test_targets) +env.Append(LIBEMITTER=add_test_targets) +# generate all test target names +all_tests = [] +for entry in PROJ_DIR.glob('*') + LIB_DIR.glob('*') + SMOKE_DIR.glob('*'): + for test_file in entry.glob('test/*.c'): + test_module_name = Path(test_file.path).stem + all_tests.append(f"test/{entry.path}/{test_module_name}") -test = Command('#/test', [], test_runner) -Depends(test, get_test_list()) +TARGET = str(Path("test", TARGET or '', GetOption("testfile") or '')) +selected_tests = [t for t in all_tests if t.startswith(TARGET)] +env.Command("#/test", selected_tests, env.Action(run_test, "Running tests:")) diff --git a/smoke/adc/src/main.c b/smoke/adc/src/main.c index e3a5cec08..38dc52373 100644 --- a/smoke/adc/src/main.c +++ b/smoke/adc/src/main.c @@ -1,7 +1,8 @@ #include + +#include "adc.h" #include "delay.h" #include "gpio.h" -#include "adc.h" #include "interrupt.h" #include "log.h" #include "tasks.h" @@ -9,47 +10,41 @@ #define ADC_TIMEOUT_MS 100 static const GpioAddress adc_addy[] = { - { .port = GPIO_PORT_A, .pin = 0 }, - { .port = GPIO_PORT_A, .pin = 1 }, - { .port = GPIO_PORT_A, .pin = 2 }, - { .port = GPIO_PORT_A, .pin = 3 }, - { .port = GPIO_PORT_A, .pin = 4 }, - { .port = GPIO_PORT_A, .pin = 5 }, - { .port = GPIO_PORT_A, .pin = 6 }, - { .port = GPIO_PORT_A, .pin = 7 }, - { .port = GPIO_PORT_B, .pin = 0 }, - { .port = GPIO_PORT_B, .pin = 1 }, + { .port = GPIO_PORT_A, .pin = 0 }, { .port = GPIO_PORT_A, .pin = 1 }, + { .port = GPIO_PORT_A, .pin = 2 }, { .port = GPIO_PORT_A, .pin = 3 }, + { .port = GPIO_PORT_A, .pin = 4 }, { .port = GPIO_PORT_A, .pin = 5 }, + { .port = GPIO_PORT_A, .pin = 6 }, { .port = GPIO_PORT_A, .pin = 7 }, + { .port = GPIO_PORT_B, .pin = 0 }, { .port = GPIO_PORT_B, .pin = 1 }, }; TASK(smoke_adc_task, TASK_STACK_512) { - for (uint8_t i = 0; i < SIZEOF_ARRAY(adc_addy); i++) { - gpio_init_pin(&adc_addy[i], GPIO_ANALOG, GPIO_STATE_LOW); - adc_add_channel(adc_addy[i]); - } - - adc_init(); - - while(true) { - uint16_t data = 0; - adc_run(); - for (uint8_t i = 0; i < SIZEOF_ARRAY(adc_addy); i++) { - adc_read_converted(adc_addy[i], &data); - printf("%d%d: %d\n\r", adc_addy[i].port, adc_addy[i].pin, data); - } - delay_ms(1000); - } + for (uint8_t i = 0; i < SIZEOF_ARRAY(adc_addy); i++) { + gpio_init_pin(&adc_addy[i], GPIO_ANALOG, GPIO_STATE_LOW); + adc_add_channel(adc_addy[i]); + } + + adc_init(); + + while (true) { + uint16_t data = 0; + adc_run(); + for (uint8_t i = 0; i < SIZEOF_ARRAY(adc_addy); i++) { + adc_read_converted(adc_addy[i], &data); + printf("%d%d: %d\n\r", adc_addy[i].port, adc_addy[i].pin, data); + } + delay_ms(1000); + } } int main() { - tasks_init(); - interrupt_init(); - gpio_init(); - log_init(); + tasks_init(); + interrupt_init(); + gpio_init(); + log_init(); - tasks_init_task(smoke_adc_task, TASK_PRIORITY(2), NULL); + tasks_init_task(smoke_adc_task, TASK_PRIORITY(2), NULL); - tasks_start(); + tasks_start(); - return 0; + return 0; } - diff --git a/smoke/gpio/src/main.c b/smoke/gpio/src/main.c index c314d1c75..86477b0d0 100644 --- a/smoke/gpio/src/main.c +++ b/smoke/gpio/src/main.c @@ -156,4 +156,4 @@ int main(void) { LOG_DEBUG("Tasks Ended\n"); return 0; -} \ No newline at end of file +} diff --git a/smoke/hw_timer/README.md b/smoke/hw_timer/README.md new file mode 100644 index 000000000..5395454a2 --- /dev/null +++ b/smoke/hw_timer/README.md @@ -0,0 +1,16 @@ + +# adc + diff --git a/smoke/hw_timer/config.json b/smoke/hw_timer/config.json new file mode 100644 index 000000000..4019f4748 --- /dev/null +++ b/smoke/hw_timer/config.json @@ -0,0 +1,6 @@ +{ + "libs": [ + "FreeRTOS", + "ms-common" + ] +} \ No newline at end of file diff --git a/smoke/hw_timer/src/main.c b/smoke/hw_timer/src/main.c new file mode 100644 index 000000000..0a406235d --- /dev/null +++ b/smoke/hw_timer/src/main.c @@ -0,0 +1,45 @@ +#include + +#include "adc.h" +#include "delay.h" +#include "gpio.h" +#include "hw_timer.h" +#include "interrupt.h" +#include "log.h" +#include "tasks.h" + +static const GpioAddress leds[] = { + { .port = GPIO_PORT_B, .pin = 5 }, // + { .port = GPIO_PORT_B, .pin = 4 }, // + { .port = GPIO_PORT_B, .pin = 3 }, // + { .port = GPIO_PORT_A, .pin = 15 }, // +}; + +void pre_loop_init() {} + +TASK(hw_timer_task, TASK_STACK_512) { + for (uint8_t i = 0; i < SIZEOF_ARRAY(leds); i++) { + gpio_init_pin(&leds[i], GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_LOW); + } + + while (true) { + gpio_toggle_state(&leds[0]); + gpio_toggle_state(&leds[3]); + LOG_DEBUG("HW Delay"); + hw_timer_delay_us(1000); + } +} + +int main() { + tasks_init(); + interrupt_init(); + gpio_init(); + hw_timer_init(); + log_init(); + + tasks_init_task(hw_timer_task, TASK_PRIORITY(2), NULL); + + tasks_start(); + + return 0; +} diff --git a/smoke/i2c/src/main.c b/smoke/i2c/src/main.c index 856cfdd77..726a266c2 100644 --- a/smoke/i2c/src/main.c +++ b/smoke/i2c/src/main.c @@ -1,14 +1,15 @@ #include + +#include "delay.h" #include "gpio.h" #include "i2c.h" -#include "tasks.h" #include "log.h" -#include "delay.h" +#include "tasks.h" // ==== WRITE PARAMETERS ==== // Fill in these variables with the port and address to write to. -#define WRITE_I2C_PORT I2C_PORT_1 // I2C_Port_2 is also available +#define WRITE_I2C_PORT I2C_PORT_1 // I2C_Port_2 is also available #define WRITE_I2C_ADDRESS 0x24 // Fill in this array with the bytes to write. @@ -17,7 +18,7 @@ static const uint8_t bytes_to_write[] = { 0x10, 0x2F }; // ==== READ PARAMETERS ==== // Fill in these variables with the port and address to read from. -#define READ_I2C_PORT I2C_PORT_1 +#define READ_I2C_PORT I2C_PORT_1 #define READ_I2C_ADDRESS 0x08 // Fill in this variable with the number of bytes to read. @@ -36,28 +37,25 @@ static const uint8_t bytes_to_write[] = { 0x10, 0x2F }; { .port = GPIO_PORT_B, .pin = 10 } static I2CSettings i2c_settings = { - .speed = I2C_SPEED_STANDARD, - .sda = I2C1_SDA, - .scl = I2C1_SCL, + .speed = I2C_SPEED_STANDARD, + .sda = I2C1_SDA, + .scl = I2C1_SCL, }; -static const GpioAddress test_pin = { - .pin = 3, - .port = GPIO_PORT_B -}; +static const GpioAddress test_pin = { .pin = 3, .port = GPIO_PORT_B }; -TASK(smoke_i2c_task, TASK_STACK_512){ +TASK(smoke_i2c_task, TASK_STACK_512) { uint16_t tx_len = SIZEOF_ARRAY(bytes_to_write); - uint8_t rx_buf[SIZEOF_ARRAY(bytes_to_write)] = {0}; - gpio_init_pin(&test_pin ,GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_HIGH); - uint8_t dat[2] = {0xff, 0xff}; + uint8_t rx_buf[SIZEOF_ARRAY(bytes_to_write)] = { 0 }; + gpio_init_pin(&test_pin, GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_HIGH); + uint8_t dat[2] = { 0xff, 0xff }; StatusCode ret = i2c_write_reg(WRITE_I2C_PORT, WRITE_I2C_ADDRESS, 0x02, dat, 2); while (true) { // I2C write uint8_t rx_data[2] = { 0 }; // StatusCode ret = i2c_write(WRITE_I2C_PORT, WRITE_I2C_ADDRESS, dat, 2); StatusCode ret1 = i2c_read_reg(WRITE_I2C_PORT, WRITE_I2C_ADDRESS, 0x02, rx_data, 2); - LOG_DEBUG("ret: %d %d, DATA : %d %d\n\r",ret , ret1, rx_data[0], rx_data[1]); + LOG_DEBUG("ret: %d %d, DATA : %d %d\n\r", ret, ret1, rx_data[0], rx_data[1]); // I2C read (uncomment to test) // i2c_read(READ_I2C_PORT, READ_I2C_ADDRESS, rx_buf, 6); delay_ms(1000); diff --git a/smoke/pd_load_switch_validate/src/main.c b/smoke/pd_load_switch_validate/src/main.c index 8bdb2ee48..30265a988 100644 --- a/smoke/pd_load_switch_validate/src/main.c +++ b/smoke/pd_load_switch_validate/src/main.c @@ -1,11 +1,11 @@ #include #include "delay.h" +#include "i2c.h" #include "log.h" #include "master_task.h" #include "pca_config.h" #include "tasks.h" -#include "i2c.h" Pca9555GpioAddress addy[] = { { .i2c_address = I2C_ADDRESS_1, .pin = PCA9555_PIN_IO1_0 }, diff --git a/smoke/pedal_calib/src/main.c b/smoke/pedal_calib/src/main.c index 74881888c..fb8eb08d2 100644 --- a/smoke/pedal_calib/src/main.c +++ b/smoke/pedal_calib/src/main.c @@ -25,7 +25,6 @@ I2CSettings i2c_settings = { .sda = { .port = GPIO_PORT_B, .pin = 11 }, }; - /* TODO - ads1015 storage needs to be changed to MAX11600 (pending driver completion) */ void test_throttle_calibration_run(void) { LOG_DEBUG("Please ensure the throttle is not being pressed.\n"); @@ -74,9 +73,9 @@ int main(void) { StatusCode ret = calib_init(&global_calib_blob, sizeof(global_calib_blob), true); if (ret == STATUS_CODE_OK) { - LOG_DEBUG("calib_init test: OK\n"); + LOG_DEBUG("calib_init test: OK\n"); } else { - LOG_DEBUG("calib_init test: FAILED (Error code: %d)\n", (int)ret); + LOG_DEBUG("calib_init test: FAILED (Error code: %d)\n", (int)ret); } pedal_calib_init(&s_throttle_calibration_storage); @@ -85,5 +84,6 @@ int main(void) { test_throttle_calibration_run(); test_brake_calibration_run(); - while(1); -} \ No newline at end of file + while (1) { + } +} diff --git a/smoke/power_distribution/config.json b/smoke/power_distribution/config.json index b2f5f4d97..726bef5e0 100644 --- a/smoke/power_distribution/config.json +++ b/smoke/power_distribution/config.json @@ -6,11 +6,11 @@ "master" ], "include": [ - "#/projects/power_distribution/inc" + "projects/power_distribution/inc" ], "sources": [ - "#/projects/power_distribution/src/outputs.c", - "#/projects/power_distribution/src/output_config.c", - "#/projects/power_distribution/src/output_current_sense.c" + "projects/power_distribution/src/outputs.o", + "projects/power_distribution/src/output_config.o", + "projects/power_distribution/src/output_current_sense.o" ] } \ No newline at end of file diff --git a/smoke/power_distribution/inc/power_distribution.h b/smoke/power_distribution/inc/power_distribution.h index d32a5df65..1b82b0573 100644 --- a/smoke/power_distribution/inc/power_distribution.h +++ b/smoke/power_distribution/inc/power_distribution.h @@ -1,21 +1,21 @@ #pragma once #include "bts_load_switch.h" -#include "pca9555_gpio_expander.h" #include "gpio.h" #include "i2c.h" +#include "pca9555_gpio_expander.h" #include "pin_defs.h" -#define CHECK_EQUAL(actual, expected) \ - ({ \ - __typeof__(actual) a = (actual); \ - __typeof__(actual) e = (__typeof__(actual)) (expected); \ - if (a != e) { \ - LOG_DEBUG("Equal check failed!\n"); \ - } \ +#define CHECK_EQUAL(actual, expected) \ + ({ \ + __typeof__(actual) a = (actual); \ + __typeof__(actual) e = (__typeof__(actual))(expected); \ + if (a != e) { \ + LOG_DEBUG("Equal check failed!\n"); \ + } \ }) I2CSettings i2c_settings = { - .speed = I2C_SPEED_STANDARD, + .speed = I2C_SPEED_STANDARD, .sda = PD_I2C_SDA, .scl = PD_I2C_SCL, }; diff --git a/smoke/power_distribution/src/main.c b/smoke/power_distribution/src/main.c index 07832d49b..ffdd60f97 100644 --- a/smoke/power_distribution/src/main.c +++ b/smoke/power_distribution/src/main.c @@ -1,20 +1,18 @@ #include +#include "adc.h" +#include "delay.h" +#include "interrupt.h" #include "log.h" -#include "tasks.h" #include "master_task.h" -#include "delay.h" -#include "adc.h" -#include "power_distribution.h" -#include "outputs.h" #include "output_current_sense.h" -#include "interrupt.h" +#include "outputs.h" +#include "power_distribution.h" +#include "tasks.h" -static const OutputGroup output_groups_to_test[] = { - OUTPUT_GROUP_LIGHTS_LEFT_TURN -}; +static const OutputGroup output_groups_to_test[] = { OUTPUT_GROUP_LIGHTS_LEFT_TURN }; -static const GpioAddress test_gpio = { .port = GPIO_PORT_B, .pin = 5 }; +static const GpioAddress test_gpio = { .port = GPIO_PORT_B, .pin = 5 }; void pd_print_adc_readings(OutputGroup group) { if (group == OUTPUT_GROUP_ALL) { @@ -31,18 +29,18 @@ void pd_print_adc_readings(OutputGroup group) { } } -TASK(smoke_pd, TASK_STACK_512){ +TASK(smoke_pd, TASK_STACK_512) { gpio_init_pin(&test_gpio, GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_LOW); - + pd_output_init(); pd_sense_init(); adc_init(); uint16_t num_test_grps = SIZEOF_ARRAY(output_groups_to_test); - while(true) { - for(uint8_t i = 0; i < num_test_grps; i++) { + while (true) { + for (uint8_t i = 0; i < num_test_grps; i++) { uint16_t sense = 0; - + gpio_toggle_state(&test_gpio); pd_set_output_group(output_groups_to_test[i], OUTPUT_STATE_ON); delay_ms(2000); @@ -73,4 +71,3 @@ int main() { LOG_DEBUG("exiting main?"); return 0; } - diff --git a/smoke/spi/src/main.c b/smoke/spi/src/main.c index c74f16e37..706a9947f 100644 --- a/smoke/spi/src/main.c +++ b/smoke/spi/src/main.c @@ -1,7 +1,7 @@ #include -#include "gpio.h" #include "delay.h" +#include "gpio.h" #include "log.h" #include "spi.h" #include "tasks.h" @@ -41,7 +41,7 @@ static SpiSettings spi_settings = { TASK(smoke_spi_task, TASK_STACK_512) { spi_init(SPI_PORT_2, &spi_settings); - uint8_t spi_tx_data[5] = { 0x02, 0x28, 0x7, 0x8, 0x9 }; + uint8_t spi_tx_data[5] = { 0x02, 0x28, 0x7, 0x8, 0x9 }; while (true) { spi_cs_set_state(SPI_PORT_2, GPIO_STATE_LOW); uint8_t read_bytes[3] = { 0 }; diff --git a/smoke/uart/src/main.c b/smoke/uart/src/main.c index 07d90a7b5..7c43800af 100644 --- a/smoke/uart/src/main.c +++ b/smoke/uart/src/main.c @@ -8,7 +8,8 @@ static const char test[] = "test uart\n"; -// This might cause issues because logs are initialized on the same port at a different baudrate, check this if there are issues +// This might cause issues because logs are initialized on the same port at a different baudrate, +// check this if there are issues static UartSettings uart_settings = { .tx = { .port = GPIO_PORT_A, .pin = 10 }, .rx = { .port = GPIO_PORT_A, .pin = 11 }, .baudrate = 9600 }; diff --git a/smoke/uv_cutoff/src/main.c b/smoke/uv_cutoff/src/main.c index 86d5ae4f5..db8e05e34 100644 --- a/smoke/uv_cutoff/src/main.c +++ b/smoke/uv_cutoff/src/main.c @@ -1,10 +1,10 @@ #include -#include "can.h" #include "assert.h" -#include "gpio.h" +#include "can.h" #include "can_board_ids.h" #include "delay.h" +#include "gpio.h" #include "interrupt.h" #include "log.h" #include "misc.h" @@ -30,9 +30,9 @@ static const GpioAddress horn = { .port = HORN_PORT, .pin = HORN_PIN }; static const GpioAddress lights = { .port = LIGHTS_PORT, .pin = LIGHTS_PIN }; - StatusCode status; - GpioState state_val; - int lights_check = 0; +StatusCode status; +GpioState state_val; +int lights_check = 0; static UVCutoffState state = UV_CUTOFF_ACTIVE; @@ -45,7 +45,7 @@ void uv_smoke_logic() { } if (uv_value == GPIO_STATE_LOW) { state = UV_CUTOFF_DISCONNECTED; - } else { + } else { state = UV_CUTOFF_ACTIVE; } @@ -54,7 +54,7 @@ void uv_smoke_logic() { if (state == UV_CUTOFF_DISCONNECTED) { return; } - + if (get_horn_and_lights_horn_state()) { status = gpio_set_state(&horn, GPIO_STATE_LOW); if (status == STATUS_CODE_OK) { @@ -65,16 +65,15 @@ void uv_smoke_logic() { if (status == STATUS_CODE_OK) { gpio_get_state(&horn, &state_val); } - } - if(lights_check) { + if (lights_check) { if (get_horn_and_lights_lights_state()) { status = gpio_set_state(&lights, GPIO_STATE_LOW); if (status == STATUS_CODE_OK) { gpio_get_state(&lights, &state_val); } - + } else { status = gpio_set_state(&lights, GPIO_STATE_HIGH); if (status == STATUS_CODE_OK) { @@ -82,29 +81,28 @@ void uv_smoke_logic() { } } } - } TASK(smoke_task, TASK_MIN_STACK_SIZE) { // - //TEST 1 - Disconnected UV status + // TEST 1 - Disconnected UV status LOG_DEBUG("Running test for UV Disconnected state\n"); - gpio_set_state(&uv_status,GPIO_STATE_LOW); + gpio_set_state(&uv_status, GPIO_STATE_LOW); uv_smoke_logic(); - assert( g_tx_struct.uv_cutoff_notification1_signal1 == UV_CUTOFF_DISCONNECTED ); + assert(g_tx_struct.uv_cutoff_notification1_signal1 == UV_CUTOFF_DISCONNECTED); LOG_DEBUG("uv_cutoff notification signal set to 'UV_CUTOFF_DISCONNECTED'\n"); delay_ms(1000); - //TEST 2 - Active UV status + // TEST 2 - Active UV status LOG_DEBUG("Running test for UV Active state\n"); - gpio_set_state(&uv_status,GPIO_STATE_HIGH); + gpio_set_state(&uv_status, GPIO_STATE_HIGH); uv_smoke_logic(); - assert( g_tx_struct.uv_cutoff_notification1_signal1 == UV_CUTOFF_ACTIVE ); + assert(g_tx_struct.uv_cutoff_notification1_signal1 == UV_CUTOFF_ACTIVE); LOG_DEBUG("uv_cutoff notification signal set to 'UV_CUTOFF_ACTIVE'\n"); delay_ms(1000); - //TEST 3 - Horn state HIGH + // TEST 3 - Horn state HIGH LOG_DEBUG("Running test for Horn in state HIGH\n"); - gpio_set_state(&uv_status,GPIO_STATE_HIGH); - gpio_set_state(&horn,GPIO_STATE_HIGH); + gpio_set_state(&uv_status, GPIO_STATE_HIGH); + gpio_set_state(&horn, GPIO_STATE_HIGH); g_rx_struct.horn_and_lights_horn_state = GPIO_STATE_HIGH; lights_check = 0; uv_smoke_logic(); @@ -112,10 +110,10 @@ TASK(smoke_task, TASK_MIN_STACK_SIZE) { assert(state_val == GPIO_STATE_LOW); LOG_DEBUG("horn state set to LOW\n"); delay_ms(1000); - //TEST 4 - Lights state HIGH + // TEST 4 - Lights state HIGH LOG_DEBUG("Running test for Lights in state HIGH\n"); - gpio_set_state(&uv_status,GPIO_STATE_HIGH); - gpio_set_state(&lights,GPIO_STATE_HIGH); + gpio_set_state(&uv_status, GPIO_STATE_HIGH); + gpio_set_state(&lights, GPIO_STATE_HIGH); g_rx_struct.horn_and_lights_lights_state = GPIO_STATE_HIGH; lights_check = 1; uv_smoke_logic(); @@ -123,10 +121,10 @@ TASK(smoke_task, TASK_MIN_STACK_SIZE) { assert(state_val == GPIO_STATE_LOW); LOG_DEBUG("lights state set to LOW\n"); delay_ms(1000); - //TEST 5 - Horn state LOW + // TEST 5 - Horn state LOW LOG_DEBUG("Running test for Horn in state LOW\n"); - gpio_set_state(&uv_status,GPIO_STATE_HIGH); - gpio_set_state(&horn,GPIO_STATE_LOW); + gpio_set_state(&uv_status, GPIO_STATE_HIGH); + gpio_set_state(&horn, GPIO_STATE_LOW); g_rx_struct.horn_and_lights_horn_state = GPIO_STATE_LOW; lights_check = 0; uv_smoke_logic(); @@ -134,10 +132,10 @@ TASK(smoke_task, TASK_MIN_STACK_SIZE) { assert(state_val == GPIO_STATE_HIGH); LOG_DEBUG("horn state set to HIGH\n"); delay_ms(1000); - //TEST 6 - Lights state LOW + // TEST 6 - Lights state LOW LOG_DEBUG("Running test for Lights in state LOW\n"); - gpio_set_state(&uv_status,GPIO_STATE_HIGH); - gpio_set_state(&lights,GPIO_STATE_LOW); + gpio_set_state(&uv_status, GPIO_STATE_HIGH); + gpio_set_state(&lights, GPIO_STATE_LOW); g_rx_struct.horn_and_lights_lights_state = GPIO_STATE_LOW; lights_check = 1; uv_smoke_logic(); @@ -151,10 +149,10 @@ TASK(smoke_task, TASK_MIN_STACK_SIZE) { int main() { tasks_init(); log_init(); - + gpio_init(); - //IT SHOULD BE GPIO_INPUT_PULL_UP BUT CHANGED FOR TESTING PURPOSES ONLY + // IT SHOULD BE GPIO_INPUT_PULL_UP BUT CHANGED FOR TESTING PURPOSES ONLY gpio_init_pin(&uv_status, GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_HIGH); gpio_init_pin(&horn, GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_LOW); gpio_init_pin(&lights, GPIO_OUTPUT_PUSH_PULL, GPIO_STATE_LOW);