1#!/usr/bin/env python3
2# Copyright 2022 The Pigweed Authors
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may not
5# use this file except in compliance with the License. You may obtain a copy of
6# the License at
7#
8#     https://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations under
14# the License.
15"""Generates freertos_tsktcb.h from FreeRTOS source.
16
17Extracts the tskTCB struct from FreeRTOS sources and writes it as a header to
18the specified output path.
19"""
20import argparse
21import re
22import sys
23from typing import TextIO
24from pathlib import Path
25
26_GENERATED_HEADER = """\
27// This header is generated by generate_freertos_tsktcb.py, DO NOT EDIT!
28#pragma once
29
30#include "FreeRTOS.h"
31#include "task.h"
32
33"""
34
35
36def _parse_args() -> argparse.Namespace:
37    """Parses arguments for this script, splitting out the command to run."""
38
39    parser = argparse.ArgumentParser(description=__doc__)
40    parser.add_argument(
41        '--freertos-src-dir',
42        type=Path,
43        help=(
44            'Path to the FreeRTOS source directory. Required unless'
45            ' --freertos-tasks-c is provided.'
46        ),
47    )
48    parser.add_argument(
49        '--freertos-tasks-c',
50        type=Path,
51        help=(
52            'Path to the tasks.c file in the FreeRTOS source directory. '
53            'Required unless --freertos-src-dir is provided.'
54        ),
55    )
56    parser.add_argument(
57        '--output',
58        '-o',
59        type=argparse.FileType('w'),
60        help=('Path to write generated tskTCB.h file to'),
61    )
62    return parser.parse_args()
63
64
65def _extract_struct(tasks_src: str):
66    tsk_tcb_struct = re.search(
67        r'(typedef struct tskTaskControlBlock.*tskTCB;\n)',
68        tasks_src,
69        flags=re.DOTALL,
70    )
71    if tsk_tcb_struct:
72        return tsk_tcb_struct.group(1)
73    raise ValueError('Could not find tskTCB struct in tasks.c')
74
75
76def _main(
77    freertos_src_dir: Path | None,
78    freertos_tasks_c: Path | None,
79    output: TextIO,
80):
81    if freertos_tasks_c is None or not freertos_tasks_c.is_file():
82        assert freertos_src_dir is not None
83        freertos_tasks_c = freertos_src_dir / 'tasks.c'
84    with open(freertos_tasks_c, 'r') as tasks_c:
85        output.write(_GENERATED_HEADER)
86        output.write(_extract_struct(tasks_c.read()))
87
88
89if __name__ == '__main__':
90    sys.exit(_main(**vars(_parse_args())))
91