Skip to content

CodileAB/meddela

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 

Meddela

Meddela is a command line tool for generating code for CAN node configuration, message routing, serializing and more.

As inputs it takes message and signal definitions in JSON format along with a Jinja2 template.

The 29-bit CAN message identifier is divided into four parts:

  28       20       12       4    0
+-+--------+--------+--------+----+
|-| MSG ID | TO     | FROM   | PR |
+-+--------+--------+--------+----+

MSG ID: Message ID (8 bits)
TO:     ID of recipient node (8 bits)
FROM:   ID of sender node (8 bits)
PR:     Priority (4 bits)

The most significant bit is unused.

Installation

Clone this repository:

git clone https://github.com/CodileAB/meddela

Then use pip to install it:

pip install -e meddela

Getting Started

Start by creating some files for the definitions for the messages, signals, nodes, and network:

messages.json:

[
    {
        "id": "0x01",
        "name": "WheelControl",
        "priority": "0xA",
        "signals":  [
            {
                "name": "Speed",
                "size": "0x10",
                "offset": "0x0"
            },
            {
                "name": "Direction",
                "size": "0x2",
                "offset": "0x10",
                "displayType": "Direction"
            }
        ]
    },
    {
        "id": "0x02",
        "name": "WheelStatus",
        "priority": "0x9",
        "signals":  [
            {
                "name": "RevolutionsPerMinute",
                "size": "0x10",
                "offset": "0x0"
            },
            {
                "name": "OvertemperatureShutdown",
                "size": "0x01",
                "offset": "0x10"
            },
            {
                "name": "CurrentLimitation",
                "size": "0x01",
                "offset": "0x11",
                "displayType": "YesNo"
            },
            {
                "name": "Direction",
                "size": "0x02",
                "offset": "0x12",
                "displayType": "Direction"
            }
        ]
    }
]

nodes.json:

[
    {
        "name": "Wheel",
        "rx": [
            "WheelControl"
        ],
        "tx":  [
            "WheelStatus"
        ]
    }
]

robot.json:

{
    "configurator": "Jack",
    "description": "My Robot",
    "nodes": [
        ["Wheel", "0x11", "Right wheel"],
        ["Wheel", "0x12", "Left wheel"]
    ]
}

Now Meddela knows about all the messages, their signals and nodes in the network. This information can now be used when generating the desired code but first a template must first be created so add the following content to a new file called structs.c.txt:

/* Message struct typedefs */
{% for message in node.all_messages -%}
typedef struct {{ message.name }}_s {
{%- for signal in message.signals %}
    uint{{ signal.get_word_size(8) * 8 }}_t {{ signal.name }};
{%- endfor %}
} {{ message.name }}_t;

{% endfor -%}

Run Meddela and provide the file paths and node ID to generate the code:

python -m meddela --messages=messages.json --nodes=nodes.json --config=robot.json --id=0x11 --template=structs.c.txt

The output can be piped to a file like this:

python -m meddela --messages=messages.json --nodes=nodes.json --config=robot.json --id=0x11 --template=structs.c.txt > structs.c

Template Context

The template context has the following values:

node_id             Node ID (int)
node                Node object
MSG_ID_OFFSET       Position of the 8-bit message ID in the 29-bit CAN message ID
FROM_NODE_ID_OFFSET Position of the 8-bit sender node ID in the 29-bit CAN message ID
TO_NODE_ID_OFFSET   Position of the 8-bit recipient node ID in the 29-bit CAN message ID

Node

Attributes:

rx_messages         List of Message objects being received by the node
tx_messages         List of Message objects being transmitted by the node
all_messages        List of Message objects being received or transmitted by the node

Message

Attributes:

id                  Node ID
name                Node name
priority            Priority (0 - 15, lower has higher priority)
signals             List of Signal objects that the message contains

Methods:

get_mask()
    Returns the bit mask for CAN message ID filtering.

get_id(from_node_id=0, to_node_id=0)
    Returns the full CAN message ID with priority, to, from and message ID.

get_broadcast_id(from_node_id)
    Short for get_id(from_node_id=from_node_id).

get_listen_id()
    Short for get_id().

Signal

Attributes:

name                Signal name
offset              The bit offset in the CAN frame
size                The bit size of the signal
endianness          'little' or 'big'
display_type        Data type, used for display purposes

Methods:

get_word_offset(width)
    Returns the index of the word (of the provided width) the signal's first bit is located in.

get_word_size(width)
    Returns the number of words (of the provided width) the signal will have bits in.

get_word_mask(word_offset, width)
    Returns the signal's bit mask for the provided word index and width.

get_words(width)
    Returns a list of dicts with the folliwing structure:
    {
        'offset': 0,       # The word index
        'bit_offset': 1,   # The bit offset in the word
        'mask': 255        # The signal's bit mask in the word
    }

Examples:

Get the number of messages the node receives and transmitts:

{{ node.all_messages|count }}

Get the node ID in hexadecimal:

{{ node_id|hex }}

Loop through all messages and their signals:

{% for message in node.all_messages %}
    typedef struct {{ message.name }}_s {
    {%- for signal in message.signals %}
        {{ signal.get_word_size(8) * 8 }}_t {{ signal.name }};
    {%- endfor %}
    } {{ message.name }}_t;
{% endfor -%}

Message File Structure

The message file should contain a JSON list of message definitions where each message has an ID, name, priority, and a list of signals. Each signal should have a name, size and offset in message data (in bits), and an optional display type that tells the tools how it should be displayed:

{
    "id": "0x01",
    "name": "WheelControl",
    "priority": "0xA",
    "signals":  [
        {
            "name": "Speed",
            "size": "0x10",
            "offset": "0x0"
        },
        {
            "name": "Direction",
            "size": "0x2",
            "offset": "0x10",
            "displayType": "Direction"
        }
    ]
}

Or it could include a file with the same structure (a list of messages):

{ "file": "path/to/messages.json" }

Node File Structure

The node file should contain a JSON list of node definitions where each node has a name, a list of messages it receives, and a list of messages it sends::

{
    "name": "Wheel",
    "rx": [
        "WheelControl"
    ],
    "tx":  [
        "WheelStatus"
    ]
}

Or it could include a file with the same structure (a list of nodes):

{ "file": "path/to/nodes.json" }

Config File Structure

The config file should contain a JSON object that has metadata about the CAN network, the actual nodes and their IDs and names. It should have the following structure:

{ "configurator": "Jack", "description": "My Robot", "nodes": [ ["Wheel", "0x11", "Right wheel"], ["Wheel", "0x12", "Left wheel"] ] }

About

Generate configuration and marshalling code for CAN nodes in a network

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages