Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

CANlib

Installation

If you're cloning this for the first time, use git clone --recursive to pull all submodules. However, if you already have this repository cloned non-recursively, make sure to run git submodule init and git submodule update.

To generate this library, run main.py in the generator directory with the path to your CAN spec as an argument (e.g. python main.py ../../../can_spec_my18.yml if you're running this from the lib directory in MY18). Make sure to use Python 3. This generates all of the necessary source files that are listed in .gitignore. These files are dependent on the CAN spec. If you want to change one of these files, don't edit them directly, but instead figure out what needs to change in the CAN spec. (If that still doesn't work, edit the generator scripts in generator rather than the generated files.) Source files that aren't ignored aren't generated from the CAN spec, so they can be edited directly.

When compiling, you need to compile with the appropriate CANLIB_ARCH_ defined in order to use the appropriate driver. Included drivers are listed in driver.h.

Writing a CAN spec

The CAN spec should be a YAML file with the following structure:

name: MYwhatever # Name of your CAN specunits: # Any custom units you need to define
- newtonmeter = N * m = J = Nmarchitecture:
arch1:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2
- hardwareBus3arch2:
family: archxparticipation:
can:
buses:
- hardwareBus1
- hardwareBus2computer: # All boards on the car, along with CAN messages they publish and subscribe toboard1:
architecture: arch1participation:
can:
mapping:
symbolicBus0: hardwareBus2symbolicBus1: hardwareBus3publish:
symbolicBus0:
- Msg0symbolicBus1:
- Msg0subscribe:
symbolicBus0:
- Msg2protocol:
can:
bus: # List of CAN buses on the carsymbolicBus0: # All messages on can0baudrate: 500000extended: falseframe:
key: 0x001# Lower CAN IDs have higher priorityperiod: 50ms # optional, only add it if you will use itatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: V # optionalatom1:
slice: 32 + 32type: int32 bigunit: VMsg2:
key: 0x002atom:
atom0:
slice: 0 + 2type:
type: int8endianness: bigenum:
ENUM_A: 0x0ENUM_B: 0x1ENUM_C: 0x2ENUM_D: 0x3symbolicBus1:
baudrate: 1000000extended: trueframe:
Msg0:
key: 0x001# Note that lower CAN IDs have higher priorityatom:
atom0:
slice: 0 + 32 # [start index] + [length]type: int32 big # type and endiannessunit: Vatom1:
slice: 32 + 32type: int32 bigunit: V

Once this spec is set up, to add a new message you need to do each of the following:

  • Add the message to the list of messages. Using the format like the messages above, specify key, period, (if necessary), and atom. For each atom, add slice, (of the form starting_position + length), type (of the form c_type endianness, or the more expanded version in the enum)
  • Update the publish and subscribe fields for the relevant boards. Add the name of your message to the publish list of your board and whichever boards subscribes to it.

Using the library

To use the can library, include the file canlib_<computer.name>.h for whatever computer it will be running on. (Make sure you have initialized CAN at the baudrate specified in your spec.) The follow names will then be exposed:

CANlib_<bus.name>_<frame.name>_T

This is a struct which has fields corresponding to the atoms in the corresponding frame. For example, for Msg0 on symbolic_can_1 above, it would be defined like this:

typedefstruct {
int32_tatom0;
int32_tatom1;
} CANlib_symbolicBus1_Msg0_T;

It will be available for every frame which the board publishes or subscribes to.

void CANlib_send_<bus.name>_<frame.name>_msg(CANlib_<bus.name>_<frame.name>_T *inp)

This function takes a pointer to a struct of the type described in the previous bullet and sends in on the correct CAN bus. It is only available for messages which the board publishes.

CANlib_update_can()

This function polls for any can messages and updates the relevant structs (see the next bullet). Call this periodically to update your inputs. It will only update structs corresponding to messages which a board subscribes to.

extern CANlib_<bus.name>_<frame.name>_T <bus.name>_<frame.name>_inp;

This statement extern declares the struct which will be updated when a frame.name message is received over can. Declare it in your own file and it will be updated whenever you call CANlib_update_can.

CANlib_<bus.name>_<message.name>_<atom.name>_T

This is an enum that includes values of the form <bus.name>_<message.name>_<atom.name>_<value.name> forall value in atom.value. Use this to refer to the type of enums created for enum segments (e.g., Msg2atom1 above).

Other library names

Do not use these structs in code outside of CANlib. This section is internal documentation.

CANlib_<bus.name>_T

This is an enum that includes values of the form <bus.name>_<message.name> forall message in bus.messages.

CANlib_<bus.name>_T CANlib_Identify_<bus.name>(Frame* frame)

Given a pointer to a Frame, returns the appropriate value from <bus.name>_T. It currently identifies messages based on their id. If a message is unknown w.r.t. the spec, it returns CANlib_UNKNOWN_MSG.

void CANlib_Pack_<bus.name>_<message.name>(CANlib_<bus.name>_<message.name>_T* type_in, Frame* can_out)

Given pointers to a message struct and a Frame respectively, unpacks the message contents into the Frame.

void CANlib_Unpack_<bus.name>_<message.name>(Frame *can_in, CANlib_<bus.name>_<message.name>_T *type_out)

Given pointers to a Frame and message struct respectively, unpacks the Frame contents into the message object.

CANlib_<bus.name>_<message.name>_<property> forall property in ["id", "period"]

The CANlib exposes certain properties for each message defined in the spec. Use them in your code with the above expression. There is no guarantee as to whether you learn about it as part of an enum or though a #define.

About

An automatically generated C library for packing and unpacking based on ParseCAN specifications.

Resources

Stars

6 stars

Watchers

14 watching

Forks

Releases

Packages

Used by

Contributors

Languages