Tool to manage openinverter via CAN

davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Tool to manage openinverter via CAN

Post by davefiddes »

I have written a new command line tool called openinverter_can_tool which may be of general use. It allows the configuration and control of an openinverter system entirely via a CAN bus adapter connected to a PC rather than the conventional web interface and serial connection. I need to build such a facility to allow my Tesla M3 inverter port to work but it may be of interest to others.

The tool should run on Windows, Linux and MacOS machines with almost any CAN adapter. I've only tested it myself on Linux with an Innomaker USB2CAN. It works with stm32-sine 5.24-R or newer only.

It's easy to install just run:

Code: Select all

pip install openinverter_can_tool
Linux users check the docs for additional packages it may be advisable to install directly.

Once installed you need to bring up the CAN bus (on Linux):

Code: Select all

sudo ip link set can0 up type can bitrate 500000
Then you can query parameters:

Code: Select all

$ oic -d parameter-databases/stm32-sine.5.24.R-foc.json read brakeregen
brakeregen: -13 [%]
or change them:

Code: Select all

oic -d parameter-databases/stm32-sine.5.24.R-foc.json write brakeregen -30.5
You can also dump out the current value of all parameters and values on the device. Finally you can list all parameters and values known to the tool.

The source is published on github: https://github.com/davefiddes/openinverter-can-tool

The tool requires a "parameter database" of all of the available parameters on the device. At the moment this has to be generated by the build process for the firmware. I have some example databases for the current stm32-sine release. The code that generated these runs as part of the firmware build process. I have published this on a branch here: https://github.com/davefiddes/stm32-sin ... ase-export. In the long run I hope to figure out a way of allowing the database to be generated on the fly on the device and sent over CAN. What I've done here is a temporary hack to get something running.

Going forwards I hope to get CAN parameter map reading and writing working next. After that any remaining capability needed to be able to control the inverter entirely via CAN. The eventual aim is to be able to run an openinverter system with this tool and SavvyCAN (for realtime data logging).

If anyone wants to help out with documentation on other platforms and CAN interface adapters that would be great. It should be very straightforward to get the tool running with the stm32-vcu, you just need to generate a parameter database file.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

Very nice. I think with the IPutChar interface it should be easy to redirect the output of the "json" command to a CAN message. See printf.h

All you need is implementing a function PutChar(char c) maybe even within the Can class. Then pass it to TerminalCommands::PrintParamsJson(IPutChar*, char*)

Maybe I get around to it. Could be triggered by some SDO, right?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

SDO has support for segmented downloads and dictionary downloads. Some of that protocol may be reusable or serve as a template. I've not really tried to figure that out yet. An approach using IPutChar should allow an incremental generation of the JSON to minimise memory requirements.

The "json" command needs some work to add in the unique ID on all parameters and values.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

Ok, that's any easy addition.

Trying to understand segmented downloads: https://docs.octave.dev/docs/canopen-reference-guide
Only the 4 last bytes can be used for payload.
The first byte is structured like ccs[7:5], toggle bit[4], n[3:2], e[1], s[0]
ccs should be 5 - we are block uploading (to client)
toggle bit - toggles on every frame?
n number of bytes that do NOT contain data
e expedited transfer - means more frames need to be downloaded
s size specified - check n for number of valid bytes

Makes me wonder, why are we setting the expedited and size specified bit on single frame uploads? Anyway.
So the way this goes round is every 4 bytes a new request is needed. So the 13k of json data would be about 3300 requests. Lets say we can complete 1000 per second this needs roughly 4s on an idle bus. Juicy! Only want to do that on firmware change.

So our new PutChar can collect 4 bytes and send them. Then it has to block-wait for the next request. Meaning PrintParamsJson can't be called from the RX ISR directly but should run in the idle function that also runs the regular terminal.

EDIT: I don't think just dumping out the data without request/reply is a good idea because messages with the same ID usually get overwritten by the next message in the buffers
EDIT2: how do we talk to GVRET with python?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Would recommend getting a hold of the CiA 301 from https://www.can-cia.org/. You need to register for a free account then search for "CiA 301 version 4.2.0" in the technical documents section (https://www.can-cia.org/groups/specifications/). I believe that the use of expedited is correct and is needed when getting all of the data in a single frame rather than a segmented download. The spec does explain all of the bits so much better than the various interpretations that exist on the web.

I don't know how to talk to a GVRET with python. The python-can documentation lists all of the different interfaces it supports here: https://python-can.readthedocs.io/en/st ... faces.html. It looks like GVRET might work with the "CAN over Serial / SLCAN" interface. The capabilities of GVRET don't seem to be very well documented so it's difficult to say. I would imagine that my command line argument processing would need to be updated to work with different python-can interface types. Happy to do what's necessary if you can get a simple python-can sample program talking to the device.
Pete9008
Posts: 1801
Joined: Sun Apr 03, 2022 1:57 pm
Has thanked: 102 times
Been thanked: 347 times

Re: Tool to manage openinverter via CAN

Post by Pete9008 »

Looks good!

Would it be possible to use this to upload firmware if CAN support was added to the bootloader?
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Should be fairly straight forward. The canopen library gives access to sending/receiving raw CAN frames in addition to the higher level CANopen protocol. It's cross-platform and has good hardware interface support so it would seem to be a good place to put that functionality.
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

johu wrote: Mon Dec 26, 2022 5:00 am Makes me wonder, why are we setting the expedited and size specified bit on single frame uploads? Anyway.
These bits both need to be set to indicate that the response is complete and that no further frames are expected to be sent. From section "7.2.4.3.6
Protocol SDO upload initiate":

Code: Select all

d: data
e = 0, s = 0: d is reserved for further use.
e = 0, s = 1: d contains the number of bytes to be uploaded.
Byte 4 contains the lsb and byte 7 contains the msb.
e = 1, s = 1: d contains the data of length 4-n to be uploaded,
the encoding depends on the type of the data referenced by index and sub-
index
e = 1, s = 0: d contains unspecified number of bytes to be uploaded.
We set the data length to 0 because we always use the full length of the data packets (4-bytes).

As you can see any other combination of the expedited and size bits would mean that the client would expect a very different response from the inverter.

Sorry for the slow reply but I had the spec open for other purposes and my head around this stuff again...
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

I found out how to use GVRET as a SocketCAN device: http://pascal-walter.blogspot.com/2015/ ... linux.html

Will try running https://github.com/CANopenNode/CANopenLinux on it and see if I can dump the json out
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Ah, so GVRET supports slcan. Not a single bit of documentation that says that. Sigh.

Using slcand on Linux is a good way to get it up and running quickly with my tool. openinverter_can_tool will default to using the "can0" on Linux. Also using socketcan means you can use Wireshark and its CANOPEN dissector to see what's going on at the same time as running the tool. Ditto SavvyCAN.

I'll look at updating the tool and docs so it's clear on how to use directly with slcan (esp on Windows and MacOS).

I'm not sure I understand how CANopenNode is going to help.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

it's a bit like openinverter, you've gotta search for it ;) searching gvret socketcan brings up https://github.com/collin80/GVRET/issues/9

I thought with CANopenNode I could test the download, no? Any suggestion for a slim canopen client?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Can't get a much slimmer CANopen client than the python canopen library. That's why I based my tool around it...

This should do what you want:

Code: Select all

from canopen import objectdictionary, Network
from canopen.sdo import SdoClient

network = Network()

# Connect to the CAN bus
network.connect(
    bustype="socketcan",
    channel="can0",
    bitrate=500000)

network.check()

# Set the Node ID we're trying to communicate with
node_id = 1

# Create temporary SDO client
sdo_client = SdoClient(0x600 + node_id, 0x580 + node_id, objectdictionary.ObjectDictionary())
sdo_client.network = network

# Subscribe to SDO responses
network.subscribe(0x580 + node_id, sdo_client.on_response)

# Open the remote SDO node Index 0x1021 (CANopen uses this as the EDS dictionary text)
try:
    with sdo_client.open(0x1021, 0, "rt", encoding="ascii") as remote:
        print(remote.read())
finally:
    network.unsubscribe(0x580 + node_id)
I've checked it in Wireshark and it seems to make the correct initial request at least before stm32-sine kicks back with an unknown index error.

Edit: In case you're not familiar with Wireshark on Linux:
  • start a socketcan interface
  • Open Wireshark
  • Start a capture on "can0" by double-clicking "can0"
  • When a CAN frame appears in the capture, right-click and pick "Decode As..."
  • Pick "CANOPEN" in the drop-down in the "Current" column and press OK
  • All CAN frames will now be interpreted as CANopen frames and allow detailed analysis in the bottom-left pane
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

thanks, good to know.

Right now is looks like slcan isn't sending frames, just receiving. Gotta find out how to upgrade firmware on that DUE board
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

I found the GVRET firmware in slcan/lawicel mode only sends on CAN0 but I'm using CAN1. Simply changed that and now I can read/write with CANopenNode. Will also try python now.
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

I've put together a new v0.0.3 release. This adds:
  • Save and load all parameters to a JSON file on the PC. Uses the same format as the web interface.
  • Change the way CAN interfaces are configured to use the python-can configuration file. This is more flexible and once set up should be the same from one run to another.
  • Added the details of how to configure to use the SLCAN interfaces like GVRET.
Obtain the release here: https://pypi.org/project/openinverter-can-tool/

Or run

Code: Select all

pip install openinverter_can_tool
Would be great if someone else wanted to give this a go. It would be useful to know it worked for more than just me... Feedback and github issues greatly received.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

Gave it a whirl on the stm32-template project. Downloaded /cmd?cmd=json and manually added ids.

Doesn't install on my beaglebone but installs fine on my laptop.

When I do

Code: Select all

oic -d ~/cmd.json dumpall
I get

Code: Select all

canspeed            :          2 [0=125k, 1=250k, 2=500k, 3=800k, 4=1M]
canperiod           :          0 [0=100ms, 1=10ms]
testparam           :          0 [Hz]
opmode              :          0 [0=Off, 1=Run]
version             :          4 [4=1.00.R-name]
Traceback (most recent call last):
... long traceback ...
canopen.sdo.exceptions.SdoAbortedError: Code 0x06020000, Object does not exist
When I check the camdump it looks strange:

Code: Select all

  
  can0       601   [8]  40 07 21 D2 20 00 00 00
  can0       581   [8]  80 07 21 D2 00 00 02 06
  can0       601   [8]  40 00 21 01 00 00 00 00
  can0       581   [8]  43 00 21 01 40 00 00 00
  can0       601   [8]  40 00 21 02 00 00 00 00
  can0       581   [8]  43 00 21 02 00 00 00 00
  can0       601   [8]  40 00 21 00 00 00 00 00
  can0       581   [8]  43 00 21 00 00 00 00 00
  can0       601   [8]  40 07 21 D0 00 00 00 00
  can0       581   [8]  43 07 21 D0 00 00 00 00
  can0       601   [8]  40 07 21 D1 00 00 00 00
  can0       581   [8]  43 07 21 D1 80 00 00 00
  can0       601   [8]  40 07 21 D2 00 00 00 00
  can0       581   [8]  80 07 21 D2 00 00 02 06

For some reason it sends out 0x60 and all zeros instead of 0x40 and correct indexes
Gotta be something with the firmware

edit: Yes, works now! Directly with the slcan driver.

Code: Select all

canspeed            :          2 [0=125k, 1=250k, 2=500k, 3=800k, 4=1M]
canperiod           :          0 [0=100ms, 1=10ms]
testparam           :          0 [Hz]
opmode              :          0 [0=Off, 1=Run]
version             :          4 [4=1.00.R-name]
lasterr             :          0 [0=NONE, 1=TESTERROR,]
testain             :        158 [dig]
cpuload             :          0 [%]
Attachments
cmd.json
(960 Bytes) Downloaded 65 times
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

I'm wondering, since you have the json info anyway, do you see any disadvantage in accessing the objects via their index rather than id?

I'm trying to hide the id as long as possible so people don't depend on it.

Can you briefly sketch how segmented upload works? Then I could stream out the json info via some object id.
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

johu wrote: Mon Feb 06, 2023 7:08 pm Gave it a whirl on the stm32-template project. Downloaded /cmd?cmd=json and manually added ids.
This patch should apply without much effort to most of your stm32-template based projects and generate the parameter database automatically.

This tool gives the CAN interface a good workout. I found it useful to hammer my C2000 CAN driver and find bugs. My error messages aren't the cleanest as I'm being lazy about exception handling for now. Will clean up eventually.
johu wrote: Mon Feb 06, 2023 7:34 pm I'm wondering, since you have the json info anyway, do you see any disadvantage in accessing the objects via their index rather than id?
Using the unique id seems the right solution where there exists the possibility of a difference of opinion between the firmware and any client. Same reasoning as using it for the params at rest in Flash. Should result in robust system behaviour provided the uniqueness is maintained.

The index seems to be very ephemeral and highly likely to change from one firmware build to the next. Seems a good way to do things where the database was delivered over the wire. We're limited to 255 parameters/spot values in a single project but that doesn't seem to be an issue so far. Would get quite noisy on the bus when reading a single value having to download the entire parameter database first. OK for bigger transactions though.
johu wrote: Mon Feb 06, 2023 7:08 pm Can you briefly sketch how segmented upload works? Then I could stream out the json info via some object id.
Easiest way to see how this works is to grab the two python test programs attached. Set up a virtual CAN interface on Linux with:

Code: Select all

sudo ip link add dev vcan0 type vcan
sudo ip link set vcan0 up
One program acts as a little SDO server and the other a client. The client will download a long(ish) string from the server. You can follow along with SavvyCAN/candump or Wireshark hooked up to vcan0. I'd recommend Wireshark as it'll decode the bits for you.
Attachments
candownload.txt
This is python3
(777 Bytes) Downloaded 69 times
canopen-testserver.txt
This is python3
(1.25 KiB) Downloaded 61 times
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

johu wrote: Mon Feb 06, 2023 7:34 pm I'm trying to hide the id as long as possible so people don't depend on it.
Been thinking about this all morning. I don't understand. Can you explain your thought process?

The pattern of using unique IDs is very common across network protocols (SNMP oids for instance)(shudder). In my 30-odd years of doing embedded comms I've come across it frequently. If you don't want people to depend on it I would suggest removing it from the public interface of your firmware! Also, it's a recent feature of the firmware which between us we've fixed and improved over the past year it seems odd to want to turn it off now.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

Yes I see how I am contradicting myself here. Will give it a try anyway. People seem weirdly attracted to cryptic numbers. In the company I worked for last I also introduced uids for the exact same purpose, saving parameters to flash.
When I returned as a contractor years later I found that uids had made it deeply into the user space and people's heads. They were talking gibberish like "can you set parameter 773 to 10". Imagine this on a public forum. SNMP oids are indeed a very good example of pure unreadableness!
Also sometimes I give parameters a fresh uid when I don't want their saved value restored from flash but rather load a default. I think I recently did that with something FOC related. I want to retain the freedom to do that without anyone screaming.
That's the "why not"

On the other hand I saw Jon Volk struggling with the exact issue you're describing: index shifts. That's why included it with the SDO. Didn't weigh it carefully back then as hardly anyone used SDO.
Also with a numeric protocol like that, what's the alternative...
That would be the "why"

So in case of your tool I see the chance of forgoing uids, that's why I brought it up
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
User avatar
catphish
Posts: 954
Joined: Fri Oct 08, 2021 11:02 pm
Location: Dorset, UK
Has thanked: 93 times
Been thanked: 179 times

Re: Tool to manage openinverter via CAN

Post by catphish »

I'm keen to use this, but for reasons I don't entirely understand, your parameter export won't compile for me:

Edit: shouldn't it be using /usr/bin/arm-none-eabi-ld rather than /usr/bin/ld?
Edit2: maybe not, I guess params are generated on the host machine, not the MCU.
Edit3: changed gcc to g++ in the Makefile and it's fixed the problem. Not sure why I thought that would work, or why it did work, but it did. gcc is supposed to detect C++ based on file extension, not sure why that isn't happening here.

Code: Select all

genparamdb: utils/genparamdb/genparamdb.cpp include/param_prj.h
        $(Q)g++ $(CFLAGS_COMMON) -lstdc++ -DNDEBUG \
        utils/genparamdb/genparamdb.cpp -o genparamdb

Code: Select all

charlie@charlie-ThinkPad-T14:~/stm32-sine$ make
  CPP     obj/stm32_sine.o
  CPP     obj/hwinit.o
  CPP     obj/stm32scheduler.o
  CPP     obj/params.o
  CPP     obj/terminal.o
  CPP     obj/terminal_prj.o
  CC      obj/my_string.o
  CPP     obj/digio.o
  CPP     obj/sine_core.o
  CC      obj/my_fp.o
  CPP     obj/fu.o
  CPP     obj/inc_encoder.o
  CPP     obj/printf.o
  CPP     obj/anain.o
  CPP     obj/temp_meas.o
  CPP     obj/param_save.o
  CPP     obj/throttle.o
  CPP     obj/errormessage.o
  CPP     obj/stm32_can.o
  CPP     obj/pwmgeneration.o
  CPP     obj/picontroller.o
  CPP     obj/terminalcommands.o
  CPP     obj/vehiclecontrol.o
  CPP     obj/pwmgeneration-sine.o
  LD      stm32_sine
  OBJCOPY stm32_sine.bin
  OBJCOPY stm32_sine.hex
   text	   data	    bss	    dec	    hex	filename
  45792	   4108	    992	  50892	   c6cc	stm32_sine
/usr/bin/ld: /tmp/ccHOg4xs.o: warning: relocation against `_ZSt4cout' in read-only section `.text.startup'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintValue(char const*, char const*, unsigned int)':
genparamdb.cpp:(.text+0x9): undefined reference to `std::cout'
/usr/bin/ld: genparamdb.cpp:(.text+0x37): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x46): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x51): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x60): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x6f): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: /tmp/ccHOg4xs.o:genparamdb.cpp:(.text+0x7a): more undefined references to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' follow
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintValue(char const*, char const*, unsigned int)':
genparamdb.cpp:(.text+0xb1): undefined reference to `std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long)'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintParam(char const*, char const*, float, float, float, char const*, unsigned int)':
genparamdb.cpp:(.text+0xdb): undefined reference to `std::cout'
/usr/bin/ld: genparamdb.cpp:(.text+0x11d): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x12c): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x137): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x146): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x155): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: /tmp/ccHOg4xs.o:genparamdb.cpp:(.text+0x167): more undefined references to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' follow
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintParam(char const*, char const*, float, float, float, char const*, unsigned int)':
genparamdb.cpp:(.text+0x192): undefined reference to `std::ostream& std::ostream::_M_insert<double>(double)'
/usr/bin/ld: genparamdb.cpp:(.text+0x19d): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1ac): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1ba): undefined reference to `std::ostream& std::ostream::_M_insert<double>(double)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1c5): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1d4): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1e2): undefined reference to `std::ostream& std::ostream::_M_insert<double>(double)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1ed): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x1fc): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x20b): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x216): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text+0x221): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: /tmp/ccHOg4xs.o:genparamdb.cpp:(.text+0x230): more undefined references to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)' follow
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintParam(char const*, char const*, float, float, float, char const*, unsigned int)':
genparamdb.cpp:(.text+0x23a): undefined reference to `std::ostream& std::ostream::_M_insert<unsigned long>(unsigned long)'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintValue(char const*, char const*, unsigned int)':
genparamdb.cpp:(.text+0xc7): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `PrintParam(char const*, char const*, float, float, float, char const*, unsigned int)':
genparamdb.cpp:(.text+0x257): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `main':
genparamdb.cpp:(.text.startup+0x10): undefined reference to `std::cout'
/usr/bin/ld: genparamdb.cpp:(.text.startup+0x48): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text.startup+0x123b): undefined reference to `std::cout'
/usr/bin/ld: genparamdb.cpp:(.text.startup+0x1240): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
/usr/bin/ld: genparamdb.cpp:(.text.startup+0x1248): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
/usr/bin/ld: /tmp/ccHOg4xs.o: in function `_GLOBAL__sub_I__Z10PrintValuePKcS0_j':
genparamdb.cpp:(.text.startup+0x126a): undefined reference to `std::ios_base::Init::Init()'
/usr/bin/ld: genparamdb.cpp:(.text.startup+0x1271): undefined reference to `std::ios_base::Init::~Init()'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:100: genparamdb] Error 1
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Hmm. I can replicate on an Ubuntu CI build. Will investigate... It is the world's simplest C++ program (almost).
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

Fixed. It was using gcc rather than g++ as you point out. Seems to be an issue with older gcc versions..I was being lazy as I normally leave such choices to CMake. Merged with latest stm32-sine tip here: https://github.com/davefiddes/stm32-sin ... ase-export
davefiddes
Posts: 211
Joined: Mon Jan 18, 2021 12:39 pm
Location: Edinburgh, Scotland, UK
Has thanked: 14 times
Been thanked: 35 times

Re: Tool to manage openinverter via CAN

Post by davefiddes »

johu wrote: Tue Feb 07, 2023 8:09 pm People seem weirdly attracted to cryptic numbers.
Agreed. I have seen this as well. I am careful not to surface the parameter ID in the UI anywhere.

The nature of CANopen SDO is to use unique Index ids. It mitigates against confusion between the clients and servers.

The CAN bus interface to the inverter firmware is a public interface and different from the more tightly coupled higher bandwidth serial interface. The required tradeoffs are slightly different.

If you build parameter DB auto-generation and upload I'll make that the default in the tool. That way most casual users won't ever need to know it is possible to cache the parameter database.

Edit: Swapping unique IDs when the spec of a parameter changes but its name doesn't seems perfectly OK to me.
User avatar
johu
Site Admin
Posts: 5682
Joined: Thu Nov 08, 2018 10:52 pm
Location: Kassel/Germany
Has thanked: 153 times
Been thanked: 960 times
Contact:

Re: Tool to manage openinverter via CAN

Post by johu »

davefiddes wrote: Tue Feb 07, 2023 1:10 pmOne program acts as a little SDO server and the other a client. The client will download a long(ish) string from the server. You can follow along with SavvyCAN/candump or Wireshark hooked up to vcan0. I'd recommend Wireshark as it'll decode the bits for you.
Thanks for that one :) Executed and got:

Code: Select all

  vcan0  601   [8]  40 21 10 00 00 00 00 00   '@!......'
  vcan0  581   [8]  41 21 10 00 38 00 00 00   'A!..8...'
  vcan0  601   [8]  60 00 00 00 00 00 00 00   '`.......'
  vcan0  581   [8]  00 41 20 76 65 72 79 20   '.A very '
  vcan0  601   [8]  70 00 00 00 00 00 00 00   'p.......'
  vcan0  581   [8]  10 6C 61 72 67 65 20 61   '.large a'
  vcan0  601   [8]  60 00 00 00 00 00 00 00   '`.......'
  vcan0  581   [8]  00 6E 64 20 6C 6F 6E 67   '.nd long'
  vcan0  601   [8]  70 00 00 00 00 00 00 00   'p.......'
  vcan0  581   [8]  10 20 73 74 72 69 6E 67   '. string'
  vcan0  601   [8]  60 00 00 00 00 00 00 00   '`.......'
  vcan0  581   [8]  00 20 74 68 61 74 20 63   '. that c'
  vcan0  601   [8]  70 00 00 00 00 00 00 00   'p.......'
  vcan0  581   [8]  10 6F 75 6C 64 20 62 65   '.ould be'
  vcan0  601   [8]  60 00 00 00 00 00 00 00   '`.......'
  vcan0  581   [8]  00 20 61 20 6C 6F 74 20   '. a lot '
  vcan0  601   [8]  70 00 00 00 00 00 00 00   'p.......'
  vcan0  581   [8]  11 6F 66 20 4A 53 4F 4E   '.of JSON'
So first reply is the size in bytes and afterwards 7 bytes are used for payload and the first byte toggles between 0x10 and 0. On the request the first byte toggles between 0x60 and 0x70. So the reply seems to just retain bit 4 from the request. The final reply has bit 0 set.
davefiddes wrote: Wed Feb 08, 2023 12:39 pm If you build parameter DB auto-generation and upload I'll make that the default in the tool.
By that you mean SDO upload or including the output of genparamdb with every build?
Support R/D and forum on Patreon: https://patreon.com/openinverter - Subscribe on odysee: https://odysee.com/@openinverter:9
Post Reply