diff --git a/README.md b/README.md index b407078..cfff283 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # arrowdrone-docs + Documentation (Design, Certification), Requirements, Dictionary + +## Requirements + +See the [requirements README.md](reqs/README.md) for how to understand, view, and modify requirements. \ No newline at end of file diff --git a/reqs/.doorstop.yml b/reqs/.doorstop.yml new file mode 100644 index 0000000..13192f8 --- /dev/null +++ b/reqs/.doorstop.yml @@ -0,0 +1,17 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + prefix: REQ + sep: '-' diff --git a/reqs/.gitignore b/reqs/.gitignore new file mode 100644 index 0000000..5293c75 --- /dev/null +++ b/reqs/.gitignore @@ -0,0 +1,3 @@ +*.xlsx +*.csv +public/ \ No newline at end of file diff --git a/reqs/HW/FLIGHT/.doorstop.yml b/reqs/HW/FLIGHT/.doorstop.yml new file mode 100644 index 0000000..4fea2c6 --- /dev/null +++ b/reqs/HW/FLIGHT/.doorstop.yml @@ -0,0 +1,18 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: FLIGHT + sep: '-' diff --git a/reqs/HW/FLIGHT/FLIGHT-0001.yml b/reqs/HW/FLIGHT/FLIGHT-0001.yml new file mode 100644 index 0000000..63a8097 --- /dev/null +++ b/reqs/HW/FLIGHT/FLIGHT-0001.yml @@ -0,0 +1,20 @@ +active: false +derived: false +header: '' +level: 1.0 +links: +- REQ-0004: KJbcY6mEnaQiumBuEOTotUFkhGpCxG_g3fCK0ThW95M= +normative: true +rationale: 'FIXME: Decide on this value. Need to decide lift goals (movie camera? + packages?) + + ' +ref: '' +reviewed: n3JctxP-exqx5GI4L_7_Hf9ywg_JSU_PoSTUiakaUzQ= +text: 'The platform shall have a lift capacity of X kilograms. + + ' +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/PROJ/.doorstop.yml b/reqs/PROJ/.doorstop.yml new file mode 100644 index 0000000..9fa8642 --- /dev/null +++ b/reqs/PROJ/.doorstop.yml @@ -0,0 +1,18 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: PROJ + sep: '-' diff --git a/reqs/PROJ/PROJ-0001.yml b/reqs/PROJ/PROJ-0001.yml new file mode 100644 index 0000000..5986d4e --- /dev/null +++ b/reqs/PROJ/PROJ-0001.yml @@ -0,0 +1,17 @@ +active: true +derived: false +header: '' +level: 1.0 +links: +- REQ-0008: YW22H8xaKJL8USRbxri4QPw7iLx5fpo4xbsMcDgwc8Q= +normative: true +rationale: | + See [Mars Climate Orbiter](https://en.wikipedia.org/wiki/Mars_Climate_Orbiter) +ref: '' +reviewed: Cfq47pZ7chTEp0Nuc8AXHcEZS81KdBn3oXdcfe1uqr0= +text: | + The project shall enforce explicitly stating the SI Unit beside any numerical value of measurement. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/README.md b/reqs/README.md new file mode 100644 index 0000000..e6b863f --- /dev/null +++ b/reqs/README.md @@ -0,0 +1,199 @@ +# Requirements + +## Table of Contents + +- [Dependencies](#dependencies) +- [Layout](#layout) +- [Requirement Files](#requirement-files) +- [How to Validate the Requirements](#how-to-validate-the-requirements) +- [How to Export Requirements](#how-to-export-requirements) +- [How to Add a Requirement Category](#how-to-add-a-requirement-category) +- [How to Add a Requirement](#how-to-add-a-requirement) +- [How to View Requirements](#how-to-view-requirements) + +## Dependencies + +```python3 +pip3 install doorstop pyyaml +``` + +Requirements are managed with [doorstop](https://doorstop.readthedocs.io/en/latest/). + +The `doorstop` command can be run in any directory, but this README assumes the current directory is `reqs/`. + +## Layout + +The top level requirement directory is `reqs`. The requirements in this repository are the highest level platform requirements. They have the prefix `REQ`. + +Lower level requirement locations: +- Software-related: `SW/` +- Electronics-related: `HW/` +- Project directives: `PROJ/` + +An example layout of requirements is below. +```tree +. +├── build +├── REQ-0001.yml +├── PROJ +│ └── PROJ-0001.yml +├── HW +│ └── FLIGHT +│ └── FLIGHT-0001.yml +└── SW + ├── CMD_SVC + │ ├── CMD_SVC-0001.yml + ├── HEALTH_SVC + │ ├── HEALTH_SVC-0001.yml + └── TLM_SVC + ├── TLM_SVC-0001.yml +``` + +## Requirement Files + +The requirements are individual `.yml` files. Each contains the requirement's primary text as well as metadata. + +```yml +# reqs/SW/HEALTH/HEALTH_SVC-0001.yml +active: true +derived: false +header: '' +level: 1.0 +links: +- REQ-0001: bBkf6YMFHFULHe5eLcjSBipaMvJL7t5BdNTRJdS-4Ug= +normative: true +rationale: | + If a device is acting offnominally, the software manager in charge of that device may elect to mark it as SICK or DEAD + to prevent accidental further usage. +ref: '' +reviewed: 7Pi6ZnjoRSEqcevT_DevP6N0liXRQPDnPh1W4QYxSz4= +text: | + HEALTH_SVC shall provide an interface to mark a device as HEALTHY, SICK, or DEAD. +``` + +Important Field | Description +---- | --- +`text` | The primary text of the requirement +`rationale` | Why the requirement exists, explanation of values in requirement, etc. This is a required field and is enforced with the `build` script. +`links` | Links to parent requirements. In this case REQ-0001 (*The platform shall maintain the health status of each device*) is the parent requirement. **All lower level requirements must have a parent.** This is enforced with the `build` script. +`active` | If the requirement is in draft and you don't want to cause build errors, set this to `false`. + + +## How to Validate the Requirements + +Use the `reqs/build` script. + +`reqs/build` will call: +- `doorstop_yml_formatter.yml` (enforces fields in `.doorstop.yml`) +- `doorstop_hooks.py` (a wrapper around `doorstop` with extra rules) +- `doorstop publish all public/` +- `doorstop export all ./csv_files/` + +An ideal build will look like so: + +```zsh +➜ reqs git:(main) ✗ ./build +building tree... +loading documents... +publishing tree to '/home/ams/gitprojects/arrowdrone-docs/reqs/REQ'... +published: /home/ams/gitprojects/arrowdrone-docs/reqs/REQ +building tree... +loading documents... +exporting tree to './csv_files'... +exported: ./csv_files +``` + +Common errors and their fixes: + +Common Error | Fix +--- | --- +`EXAMPLE-0001: Rationale is required!` | Populate a `rationale` field in the requirement file. +`EXAMPLE-0001: A parent is required for a lower level requirement!` | `doorstop link EXAMPLE-0001 REQ-####`
Or manually update the `links` field in the requirement's `.yml`. +`EXAMPLE-0001: suspect link` | `doorstop clear EXAMPLE-0001`.
Use `all` resolving all suspect links. This occurs sometimes when the parent requirement changes. +`EXAMPLE-0001: unreviewed changes` | `doorstop review EXAMPLE-0001`.
Use `all` for resolving all reviews. +`WARNING: no item with UID: EXAMPLE-0001` | This can happen if `active:false` in `EXAMPLE-0001.yml`. + +## How to Export Requirements + +You may be more comfortable with viewing requirements in an Excel spreadsheet. + +The `build` script should produce a `reqs/csv_files` directory. + +You can also run `doorstop export REQ path/to/tst.xlsx` (also supports tsv, csv, or yml), or similarly call it for any other requirement category. + +## How to Add a Requirement Category + +A requirement category can be added with `doorstop create`: + +```bash +# doorstop create --parent REQ +$ doorstop create PWR ./HW/PWR --parent REQ +building tree... +created document: PWR (@/reqs/HW/PWR) +``` + +You will see that a new directory was created and populated with a `.doorstop.yml` file: +```yaml +settings: + digits: 3 + parent: REQ + prefix: PWR + sep: '' +``` + +We have specific fields for this project. All `.doorstop.yml` files not following the project standard will be rectified when the `build` script is called. + +Output after `./build`: + +```yaml +attributes: + publish: + - verified-by + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: PWR + sep: '-' +``` + +If we build now, we will get a warning: `PWR: no items`. + +## How to Add a Requirement + +Requirements can be added with `doorstop add`: + +```bash +# doorstop add +$ doorstop add PWR +building tree... +added item: PWR-0001 (@/reqs/HW/PWR/PWR-0001.yml) +``` +The new file can be manually populated with the required fields. + +You must then link the requirement to a parent requirement before the build can succeed: + +`doorstop link PWR-0001 REQ-####` + +You can add multiple requirements add the same time with the `-c` option: + +```bash +$ doorstop add PWR -c 3 +building tree... +added item: PWR-0002 (@/reqs/HW/PWR/PWR-0002.yml) +added item: PWR-0003 (@/reqs/HW/PWR/PWR-0003.yml) +added item: PWR-0004 (@/reqs/HW/PWR/PWR-0004.yml) +``` + +## How to View Requirements + +To view the requirements outside of source code, do one of the following: +1) `doorstop-server` + - Visit `localhost:7867` in your browser +2) `cd public/; python -m http.server PORT` + - Visit `localhost:PORT` in your browser +3) `doorstop-gui` + - tkinter application +4) TODO: Visit arrowair.com arrowdrone subdir +5) Open the csv file(s) in Excel. \ No newline at end of file diff --git a/reqs/REQ-0001.yml b/reqs/REQ-0001.yml new file mode 100644 index 0000000..12b2f88 --- /dev/null +++ b/reqs/REQ-0001.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.0 +links: [] +normative: true +rationale: | + Each device (thruster, instrument, battery, etc.) should have a controller that reports the health condition of the device. We can use the health condition to trigger fault protection scenarios, and report to ground. +ref: '' +reviewed: MATot0753ONzuVAaPgmlKD3O0dKpM-25Bmgk0jf31E0= +text: | + The platform shall maintain the health status of each device. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0002.yml b/reqs/REQ-0002.yml new file mode 100644 index 0000000..dcb7551 --- /dev/null +++ b/reqs/REQ-0002.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.1 +links: [] +normative: true +rationale: | + Telemetry that will be *expected* at some known frequency. Loss of this telemetry can be indicative of loss of signal. +ref: '' +reviewed: LbETQ9JP--LIZ5Zrfy54ZdOCGqzId_d0HOQZDO28d7Y= +text: | + The platform shall downlink periodic telemetry. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0003.yml b/reqs/REQ-0003.yml new file mode 100644 index 0000000..9886b59 --- /dev/null +++ b/reqs/REQ-0003.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.5 +links: [] +normative: true +rationale: | + Some telemetry (warnings, errors, events) will occur outside of regularly scheduled telemetry. +ref: '' +reviewed: MM0cI5pdfHZp9_6Ew305M5pmhHu0MaZnsQQ1r2BlkTU= +text: | + The platform shall downlink aperiodic event reports. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0004.yml b/reqs/REQ-0004.yml new file mode 100644 index 0000000..127de15 --- /dev/null +++ b/reqs/REQ-0004.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.3 +links: [] +normative: true +rationale: | + The drone will have a flight duration, must be safely controlled (manual or autonomous), and will carry payloads. +ref: '' +reviewed: KJbcY6mEnaQiumBuEOTotUFkhGpCxG_g3fCK0ThW95M= +text: | + The platform shall be capable of sustained and controlled flight under load. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0005.yml b/reqs/REQ-0005.yml new file mode 100644 index 0000000..c74b678 --- /dev/null +++ b/reqs/REQ-0005.yml @@ -0,0 +1,19 @@ +active: false +derived: false +header: '' +level: 1.4 +links: [] +normative: true +rationale: 'The battery itself may remain in the platform or be hot swappable, either + way the batteries should support recharge. + + ' +ref: '' +reviewed: wm9YicP0l8riWhP2Cb6oKOv7PzYC16VzTelaoqdUvfU= +text: 'The platform shall have a rechargeable battery system. + + ' +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0006.yml b/reqs/REQ-0006.yml new file mode 100644 index 0000000..1882f00 --- /dev/null +++ b/reqs/REQ-0006.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.2 +links: [] +normative: true +rationale: | + Desire is for the platform to be networked but only under control of approved users. +ref: '' +reviewed: vciObFMLpnSwMND9dFxQjwHHfANnD-BBroJHyryfl-c= +text: | + The platform shall support bidirectional wireless communication with approved devices. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0007.yml b/reqs/REQ-0007.yml new file mode 100644 index 0000000..af64045 --- /dev/null +++ b/reqs/REQ-0007.yml @@ -0,0 +1,17 @@ +active: true +derived: false +header: '' +level: 1.6 +links: [] +normative: true +rationale: | + Command packets will be continuous (remote control transmitter) or aperiodic (command to change configuration). + Rate (Hz) to process command packets TBD depending on hardware selected. +ref: '' +reviewed: Kqsc6a-OEYsUHSXCo0h_xmwXz7oQswxBCA2LMgQLCLI= +text: | + The platform shall receive and process commands. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0008.yml b/reqs/REQ-0008.yml new file mode 100644 index 0000000..8bc3871 --- /dev/null +++ b/reqs/REQ-0008.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.7 +links: [] +normative: true +rationale: | + The project will enforce standards for development to ensure a safe product. +ref: '' +reviewed: YW22H8xaKJL8USRbxri4QPw7iLx5fpo4xbsMcDgwc8Q= +text: | + The platform's development shall adhere to project directives. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/REQ-0009.yml b/reqs/REQ-0009.yml new file mode 100644 index 0000000..18841c4 --- /dev/null +++ b/reqs/REQ-0009.yml @@ -0,0 +1,19 @@ +active: false +derived: false +header: '' +level: 1.8 +links: [] +normative: true +rationale: 'Demonstration of: following an airline, safely descending and landing, + hovering in space. + + ' +ref: '' +reviewed: Gg1CiTPYNKMuV3PONpKyxy09f0FaE2XS9twvgUhHGUM= +text: 'The platform shall have defined autonomous behaviors. + + ' +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/CMD_SVC/.doorstop.yml b/reqs/SW/CMD_SVC/.doorstop.yml new file mode 100644 index 0000000..e3704f3 --- /dev/null +++ b/reqs/SW/CMD_SVC/.doorstop.yml @@ -0,0 +1,18 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: CMD_SVC + sep: '-' diff --git a/reqs/SW/CMD_SVC/CMD_SVC-0001.yml b/reqs/SW/CMD_SVC/CMD_SVC-0001.yml new file mode 100644 index 0000000..5b60afe --- /dev/null +++ b/reqs/SW/CMD_SVC/CMD_SVC-0001.yml @@ -0,0 +1,17 @@ +active: true +derived: false +header: '' +level: 1.0 +links: +- REQ-0007: Kqsc6a-OEYsUHSXCo0h_xmwXz7oQswxBCA2LMgQLCLI= +normative: true +rationale: | + Command packets will be continuous (remote control transmitter) or aperiodic (command to change configuration). Won't want to drop the aperiodic command packets on accident, as they can be safety critical commands like immediately powering off. +ref: '' +reviewed: ZmtBVGv4gYXgP1D6OIBFMaXvaHxZMDOk1cjg0O2egSI= +text: | + CMD_SVC shall queue command packets. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/CMD_SVC/CMD_SVC-0002.yml b/reqs/SW/CMD_SVC/CMD_SVC-0002.yml new file mode 100644 index 0000000..663cbca --- /dev/null +++ b/reqs/SW/CMD_SVC/CMD_SVC-0002.yml @@ -0,0 +1,24 @@ +active: false +derived: false +header: '' +level: 1.1 +links: [] +normative: true +rationale: 'FIXME: Need hardware team to decide on flight computer hardware. + + + Command packets will be continuous (remote control transmitter) or aperiodic (command + to change configuration). + + Rate (Hz) to process command packets TBD depending on hardware selected. + + ' +ref: '' +reviewed: L8OWpS5A219vyMeiNOJKoU9NHXT3K-10pa2IQmogrws= +text: 'CMD_SVC shall process a command packet once every FIXME Hz RTI. + + ' +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/HEALTH_SVC/.doorstop.yml b/reqs/SW/HEALTH_SVC/.doorstop.yml new file mode 100644 index 0000000..f9cce8e --- /dev/null +++ b/reqs/SW/HEALTH_SVC/.doorstop.yml @@ -0,0 +1,18 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: HEALTH_SVC + sep: '-' diff --git a/reqs/SW/HEALTH_SVC/HEALTH_SVC-0001.yml b/reqs/SW/HEALTH_SVC/HEALTH_SVC-0001.yml new file mode 100644 index 0000000..011f865 --- /dev/null +++ b/reqs/SW/HEALTH_SVC/HEALTH_SVC-0001.yml @@ -0,0 +1,17 @@ +active: true +derived: false +header: '' +level: 1.0 +links: +- REQ-0001: MATot0753ONzuVAaPgmlKD3O0dKpM-25Bmgk0jf31E0= +normative: true +rationale: | + If a device is acting offnominally, the software manager in charge of that device may elect to mark it as SICK or DEAD to prevent accidental further usage. +ref: '' +reviewed: 1JPo7ocuX84muGiAoVOmRQumMCqI4OgtN3dB3opU9-Q= +text: | + HEALTH_SVC shall provide an interface to mark a device as HEALTHY, SICK, or DEAD. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/HEALTH_SVC/HEALTH_SVC-0002.yml b/reqs/SW/HEALTH_SVC/HEALTH_SVC-0002.yml new file mode 100644 index 0000000..96a9eaa --- /dev/null +++ b/reqs/SW/HEALTH_SVC/HEALTH_SVC-0002.yml @@ -0,0 +1,17 @@ +active: true +derived: false +header: '' +level: 1.1 +links: +- REQ-0001: MATot0753ONzuVAaPgmlKD3O0dKpM-25Bmgk0jf31E0= +normative: true +rationale: | + A module may need to check if a device is healthy prior to requesting some action. +ref: '' +reviewed: XA6UqhbwpPcOiHis7QdSimOnXzHx3RSGdt5-coJkdNg= +text: | + HEALTH_SVC shall provide an interface to get the health status (HEALTHY, SICK, or DEAD) of a device. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/TLM_SVC/.doorstop.yml b/reqs/SW/TLM_SVC/.doorstop.yml new file mode 100644 index 0000000..107d62f --- /dev/null +++ b/reqs/SW/TLM_SVC/.doorstop.yml @@ -0,0 +1,18 @@ +attributes: + defaults: + rationale: null + type: Requirement + verified-by: unverified + verified-comment: unverified + verified-date: unverified + publish: + - verified-by + - verified-date + - verified-comment + - type + - rationale +settings: + digits: 4 + parent: REQ + prefix: TLM_SVC + sep: '-' diff --git a/reqs/SW/TLM_SVC/TLM_SVC-0001.yml b/reqs/SW/TLM_SVC/TLM_SVC-0001.yml new file mode 100644 index 0000000..580d38e --- /dev/null +++ b/reqs/SW/TLM_SVC/TLM_SVC-0001.yml @@ -0,0 +1,18 @@ +active: true +derived: false +header: '' +level: 1.0 +links: +- REQ-0002: LbETQ9JP--LIZ5Zrfy54ZdOCGqzId_d0HOQZDO28d7Y= +- REQ-0003: MM0cI5pdfHZp9_6Ew305M5pmhHu0MaZnsQQ1r2BlkTU= +normative: true +rationale: | + "Parameterized" means we can change this value with a ground command while the vehicle is in flight. +ref: '' +reviewed: eaAFSvBx--BqcxUl0bfgJOTdlLa92YA9724nhEB6LIc= +text: | + TLM_SVC shall downlink telemetry at a parameterized frequency. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/TLM_SVC/TLM_SVC-0002.yml b/reqs/SW/TLM_SVC/TLM_SVC-0002.yml new file mode 100644 index 0000000..34d3801 --- /dev/null +++ b/reqs/SW/TLM_SVC/TLM_SVC-0002.yml @@ -0,0 +1,16 @@ +active: true +derived: false +header: '' +level: 1.1 +links: +- REQ-0006: vciObFMLpnSwMND9dFxQjwHHfANnD-BBroJHyryfl-c= +normative: true +rationale: Don't want to drop potentially critical event reports. +ref: '' +reviewed: k0J2zZJVlwBW4rJQK4Y5XZxMLikBh4tvkEOIxMH1ysY= +text: | + TLM_SVC shall queue event reports. +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/SW/TLM_SVC/TLM_SVC-0003.yml b/reqs/SW/TLM_SVC/TLM_SVC-0003.yml new file mode 100644 index 0000000..edabbf0 --- /dev/null +++ b/reqs/SW/TLM_SVC/TLM_SVC-0003.yml @@ -0,0 +1,20 @@ +active: false +derived: false +header: '' +level: 1.2 +links: +- REQ-0003: MM0cI5pdfHZp9_6Ew305M5pmhHu0MaZnsQQ1r2BlkTU= +- REQ-0006: vciObFMLpnSwMND9dFxQjwHHfANnD-BBroJHyryfl-c= +normative: true +rationale: 'FIXME: Decide on this value. Likely to slide depeneding on EVR volume. + + ' +ref: '' +reviewed: C4mC5AuGQrVLCoqcD1iF7SXnUl92Vy4jUYmEGSK90Cc= +text: 'TLM_SVC shall downlink event report packets once per FIXME Hz RTI. + + ' +type: Requirement +verified-by: unverified +verified-comment: unverified +verified-date: unverified diff --git a/reqs/build b/reqs/build new file mode 100755 index 0000000..e757cef --- /dev/null +++ b/reqs/build @@ -0,0 +1,22 @@ +#!/bin/bash + +CSV=csv_files + +python3 doorstop_yml_formatter.py +if [ $? -ne 0 ]; then + echo "FAILURE, exiting build." + exit 1 +fi + +python3 doorstop_hooks.py +if [ $? -eq 0 ]; then + rm -rf public + doorstop publish all public/ # This may not scale + rm -rf ./$CSV + doorstop export all ./$CSV # This may not scale +else + echo "FAILURE, exiting build." + exit 1 +fi + +exit 0 \ No newline at end of file diff --git a/reqs/doorstop_hooks.py b/reqs/doorstop_hooks.py new file mode 100755 index 0000000..2231fba --- /dev/null +++ b/reqs/doorstop_hooks.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + + +import sys +from doorstop import build, DoorstopInfo, DoorstopWarning, DoorstopError + + +def main(): + tree = build() + success = tree.validate(document_hook=check_document, item_hook=check_item) + sys.exit(0 if success else 1) + + +def check_document(document, tree): + if sum(1 for i in document if i.normative) < 10: + yield DoorstopInfo("fewer than 10 normative items") + + +def check_item(item, tree, document): + if not item.get('rationale'): + yield DoorstopError("Rationale is required!") + + uid = item.get('path').split('/')[-1] + if len(item.get('links')) == 0 and not uid.startswith('REQ'): + yield DoorstopError("A parent is required for a lower level requirement!") + + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/reqs/doorstop_yml_formatter.py b/reqs/doorstop_yml_formatter.py new file mode 100755 index 0000000..15b83d0 --- /dev/null +++ b/reqs/doorstop_yml_formatter.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python + +import os +import sys +import re +import yaml + +# Constants +# To appear in every .doorstop.yml +DIGITS = 4 +SEPARATOR = '-' +TYPE = 'Requirement' + +## +## Helper +## +def failure(msg): + print("ERROR: %s. Failing %s." % ( + msg, __file__ + )) + sys.exit(1) + +def req_yaml_format(filename): + with open(filename, 'r') as f: + contents = yaml.safe_load(f) + if not contents: + failure("Unable to parse %s." % filename) + + contents['type'] = TYPE + if not contents.get('rationale'): + contents['rationale'] = None + + x = contents.get('verified-by') + if not x or x is None: + contents['verified-by'] = 'unverified' + + x = contents.get('verified-date') + if not x or x is None: + contents['verified-date'] = 'unverified' + + x = contents.get('verified-comment') + if not x or x is None: + contents['verified-comment'] = 'unverified' + + with open(filename, 'w') as yml_file: + yaml.dump(contents, yml_file) + +def doorstop_yaml_format(filename): + with open(filename, 'r') as f: + contents = yaml.safe_load(f) + if not contents: + failure("Unable to parse %s." % filename) + + if not contents.get('settings'): + contents['settings'] = {} + + contents['settings']['sep'] = SEPARATOR + contents['settings']['digits'] = DIGITS + + if not contents.get('attributes'): + contents['attributes'] = {} + + contents['attributes']['publish'] = [ + 'verified-by', + 'verified-date', + 'verified-comment', + 'type', + 'rationale' + ] + + if not contents['attributes'].get('defaults'): + contents['attributes']['defaults'] = {} + + # Needs to be specific value + contents['attributes']['defaults']['type'] = TYPE + + # Default is None + if not contents['attributes']['defaults'].get('rationale'): + contents['attributes']['defaults']['rationale'] = None + + # Default is "unverified" + l = [ + 'verified-by', + 'verified-date', + 'verified-comment', + ] + for item in l: + x = contents['attributes']['defaults'].get(item) + if not x or x is None: + contents['attributes']['defaults'][item] = 'unverified' + + + with open(filename, 'w') as yml_file: + yaml.dump(contents, yml_file) + + +if __name__ == '__main__': + for root, subdirs, files in os.walk('.'): + for f in files: + if f == '.doorstop.yml': + doorstop_yaml_format(os.path.join(root, f)) + elif re.search('[A-Z]+-[0-9]+.yml', f): + req_yaml_format(os.path.join(root, f)) + + sys.exit(0) \ No newline at end of file