Skip to content

Commit

Permalink
update readme, add scripts to package, fix cob-id for OD.[c/h] files
Browse files Browse the repository at this point in the history
  • Loading branch information
ryanpdx committed Sep 4, 2023
1 parent b0c76b9 commit e391070
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 13 deletions.
78 changes: 76 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,77 @@
# oresat-od-database
# OreSat Object Dictionary Database

All CANopen node and beacon configs for each OreSat.
A centeralize "database" for all OreSat card object dictionaries and beacon
definition for each OreSat mission.

Having all the OD defined in one place makes it much easier to update
OD definitions without having to go to each repo to update each cards OD.
Also, the C3 can easily import all the OD definitions to be used for SDO
transfers.

## How This Works

- All object dictionaries (OD) for a specific OreSat mission are defined
by JSONs.
- A `standard_object.json` contains some CANopen standard objects that any
`*_core.json` file can flag to include.
- The `sw_core.json` defines all CANopen standard objects, core object,
and core PDOs for all Octavo A8-based cards for a OreSat mission.
- The `fw_core.json` defines all CANopen standard objects, core object,
and core PDOs for all STM32-based cards for a OreSat mission.
- All card specific configs are are named `<card_name>.json` format.
They contian all card specific objects and PDOs.
- **NOTE:** The cards JSON are simular to CANopen's `.eds` files; they are for
a device type, not a unique device on a CAN network.
- The `beacon.json` file defines the beacon definition as all the data is pull
strait out the the C3 OD, which is mostly build from all other ODs.
- All the configs are passed to `gen_od_db()` that reads in all configs
cross reference so all OD definition of PDOs match.
- All python-based projects can just import their OreSat OD like:
```python
from oresat_od_db.oresat0_5 import GPS_OD
```
- All ChibiOS-based generate their `OD.[c/h]` files by:
```bash
$ oresat-gen-canopennode-od oresat0.5 imu -d path/to/output/dir
```

## Updating a Config

After updating configs for card(s), run the unit tests to validate all the configs.

```bash
$ python3 -m unittest
```

If there are no errors, the configs are valid.

Build and install the new version of oresat-od-database to build/test/import with.

Once the change have been tested with firmware/software, open a Pull
Request to this repo to get all changes into the next release.

## Build and Install Local Package

If it is already installed, uninstall the package.

```bash
$ python3 -m pip uninstall oresat-od-database
```

Clear any previous builds.

```bash
$ rm -rf dist/ *.egg-info/
```

Build the package.

```bash
$ python3 -m build
```

Install the package.

```bash
$ python3 -m pip install dist/*.whl
```
9 changes: 7 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
name = "oresat-od-database"
description = "OreSat object dictionary database"
readme = "README.md"
requires-python = ">=3.7"
requires-python = ">=3.9"
license = {text = "GPL-3.0"}
classifiers = [
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
Expand All @@ -22,11 +22,16 @@ dependencies = [
]
dynamic = ["version"]

[project.scripts]
oresat-gen-canopennode-od = "scripts.gen_canopennode_od:main"
oresat-gen-dcf = "scripts.gen_dcf:main"
oresat-print-od = "scripts.print_od:main"

[tool.setuptools.dynamic]
version = {attr = "oresat_od_db.__version__"}

[tool.setuptools.packages.find]
exclude = ["docs*"]
exclude = ["docs*", "tests*"]

[tool.setuptools.package-data]
"*" = ["*.json"]
Expand Down
4 changes: 3 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
black
build
canopen
dataclasses_json
pylama[toml]
pylama[all]
pylama[toml]
26 changes: 18 additions & 8 deletions scripts/gen_canopennode_od.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def format_name(string: str) -> str:
return name


def write_canopennode(od: canopen.ObjectDictionary, dir_path=""):
def write_canopennode(od: canopen.ObjectDictionary, dir_path: str = "."):
"""Save an od/dcf as CANopenNode OD.[c/h] files
Parameters
Expand All @@ -103,13 +103,19 @@ def write_canopennode(od: canopen.ObjectDictionary, dir_path=""):
be used.
"""

if dir_path[-1] == "/":
dir_path = dir_path[:-1]

write_canopennode_c(od, dir_path)
write_canopennode_h(od, dir_path)


def remove_node_id(default: str) -> str:
"""Remove "+$NODEID" or "$NODEID+" from the default value"""

if not isinstance(default, str):
return default

temp = default.split("+")

if default == "":
Expand All @@ -134,9 +140,7 @@ def attr_lines(od: canopen.ObjectDictionary, index: int) -> list:
default = remove_node_id(obj.default)
line = f"{INDENT4}.x{index:X}_{format_name(obj.name)} = "

if obj.name == "COB-ID":
line += f"0x{default - od.node_id}, "
elif obj.data_type == canopen.objectdictionary.datatypes.VISIBLE_STRING:
if obj.data_type == canopen.objectdictionary.datatypes.VISIBLE_STRING:
line += "{"
for i in obj.default:
line += f'"{i}", '
Expand Down Expand Up @@ -213,7 +217,12 @@ def attr_lines(od: canopen.ObjectDictionary, index: int) -> list:
if obj[i].data_type == canopen.objectdictionary.datatypes.DOMAIN:
continue # skip domains

if obj[i].data_type == canopen.objectdictionary.datatypes.VISIBLE_STRING:
if obj[i].name == "COB-ID":
# oresat firmware only wants 0x180, 0x280, 0x380, 0x480
# no +node_id or +1, +2, +3 for TPDO nums > 4
cob_id = (default - od.node_id) & 0xFFC
lines.append(f"{INDENT8}.{name} = 0x{cob_id:X},")
elif obj[i].data_type == canopen.objectdictionary.datatypes.VISIBLE_STRING:
line = f"{INDENT8}.{name} = " + "{"
for i in obj[i].default:
line += f'"{i}", '
Expand Down Expand Up @@ -364,7 +373,7 @@ def obj_lines(od: canopen.ObjectDictionary, index) -> list:
return lines


def write_canopennode_c(od: canopen.ObjectDictionary, dir_path=""):
def write_canopennode_c(od: canopen.ObjectDictionary, dir_path: str = "."):
"""Save an od/dcf as a CANopenNode OD.c file
Parameters
Expand Down Expand Up @@ -511,7 +520,7 @@ def _canopennode_h_lines(od: canopen.ObjectDictionary, index: int) -> list:
return lines


def write_canopennode_h(od: canopen.ObjectDictionary, dir_path=""):
def write_canopennode_h(od: canopen.ObjectDictionary, dir_path: str = "."):
"""Save an od/dcf as a CANopenNode OD.h file
Parameters
Expand Down Expand Up @@ -624,7 +633,7 @@ def main():
parser.add_argument("oresat", help="oresat mission; oresat0 or oresat0.5")
parser.add_argument("card", help="card name; c3, battery, solar, imu, or reaction_wheel")
parser.add_argument(
"-d", "--dir_path", default=".", help='output directory path, default: "."'
"-d", "--dir-path", default=".", help='output directory path, default: "."'
)
args = parser.parse_args()

Expand All @@ -633,6 +642,7 @@ def main():
sys.exit()

od = OD_LIST[(args.oresat.lower(), args.card)]

write_canopennode(od, args.dir_path)


Expand Down

0 comments on commit e391070

Please sign in to comment.