WouterJD / FortiusANT

FortiusANT enables a pre-smart Tacx trainer (usb- or ANT-connected) to communicate with TrainerRoad, Rouvy or Zwift through ANT or Bluetooth LE.
GNU General Public License v3.0
146 stars 78 forks source link

CYPLUS ANT+ Dongle - "Device does not work correctly" error #65

Closed ElDonad closed 4 years ago

ElDonad commented 4 years ago

Hello ! I have in mind since a few days to connect my old i-magic trainer to Zwyft, and I have bought two ant+ dongle (from Amazon, labelled CYCPLUS, id 0fcf:1008, Dynastream Innovation Inc.) and tried to run FortiusANT as well as antifier both on my linux and windows machine.

So far I haven't been able to run it successfully as I encountered several problems. Maybe would you have a clue about what it is ?

So, on linux the ANT didn't allow connection (errno 16: Busy) and I managed to overcome that by disabling the kernel drivers on code (basically copy-paste of https://stackoverflow.com/a/36505328). Now the ANT device is recognized as well as the trainer, but as soon as I click "Start" the console get flooded with read/write error (errno 30), happening directly after the dongle reset, from what I have been able to debug.

On windows the situation is the same, the ANT device is recognized as well as the trainer, but on clicking start I get this :

19:03:21,672: ------------------
19:03:21,672: Version info for the components
19:03:21,673:         FortiusAnt = 2020-04-07
19:03:21,673:          antDongle = 2020-03-31
19:03:21,674:             antHRM = 2020-02-18
19:03:21,675:              antFE = 2020-02-18
19:03:21,675:              debug = 2020-03-04
19:03:21,676:  FortiusAntCommand = 2020-03-25
19:03:21,676:      FortiusAntGui = 2020-04-07
19:03:21,677:            logfile = 2020-03-24
19:03:21,677:    structConstants = 2020-01-25
19:03:21,677:         usbTrainer = 2020-03-29
19:03:21,678:           argparse = 1.1
19:03:21,678:              numpy = 1.17.4
19:03:21,679:             pickle = 4.0
19:03:21,684:           platform = 1.0.8
19:03:21,685:       sys (python) = 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:21:23) [MSC v.1916 32 bit (Intel)]
19:03:21,685:                usb = 1.0.2
19:03:21,686:                 wx = 4.0.7.post2
19:03:22,210: Dongle    receive: synch=0xa4, len= 1, id=0x6f Start up             , check=0xea, info="20"
19:03:22,233: Dongle    timeout
19:03:22,234: Dongle - Using CYCPLUS dongle
19:03:22,234: Tacx   - Simulated Trainer
19:03:22,235: ResetDongle()
19:03:22,236: Dongle    send   : synch=0xa4, len= 1, id=0x4a Reset System         , check=0xef, info="00"
19:03:22,737: Calibrate()
19:03:22,737: ResetDongle()
19:03:22,738: Dongle    send   : synch=0xa4, len= 1, id=0x4a Reset System         , check=0xef, info="00"
19:03:23,239: Dongle    send   : synch=0xa4, len= 2, id=0x4d Request Message      , check=0xbf, info="00 54" msg=0x54
19:03:23,239: Dongle    drop   : synch=0xa4, len= 1, id=0x6f Start up             , check=0xea, info="20"
19:03:23,263: Dongle    timeout

and then `SendToDongle write error, reaping request failed, win error : a device attached to the system is not functionning, and multiple ReadFromDongle read error.

So the problem seems to come from the dongle, however running antifier from linux, which from what I understand uses instead the serial interface of the dongle, I was able to connect from Zwyft to antifier (even if the head unit wasn't supported).

So here I am. I don't know what I could try next or event where the problem come from. Has someone any clue ? Thanks a lot in advance...

WouterJD commented 4 years ago

Please verify whether you have most recent software downloaded, if so let's have a look. Quite some error handling has been improved lately.

ElDonad commented 4 years ago

Hello, thanks for your reply ! Yes, I git clone whenever I need a new copy of the software.

WouterJD commented 4 years ago

Do you use .exe (is older) or .py?

ElDonad commented 4 years ago

The .py one. python FortiusAnt.py -s -a.

WouterJD commented 4 years ago

Ok will check later. Please send logfile of the version you run -d127

ElDonad commented 4 years ago

Done, thank you much ! FortiusANT.2020-04-27 15-17-33.log

(sorry for the french Windows error messages)

WouterJD commented 4 years ago

Hi Elie, bon jour!

It's strange you have an error on Linux AND windows. I understand the logfile is from Windows

Detecting the ANT-dongle goes well; Tacx trainer is irrelevant (-s flag). I did not see a manufacturer=CYCPLUS ANT-dongle before, but that is not necessarily an issue.

The dongle responds normally untill 15:17:35,153 and then the message 15:17:35,627: devAntDongle.write exception: [Errno None] b'libusb0-dll:err [_usb_reap_async] reaping request failed, win error: Un périphérique attaché au système ne fonctionne pas correctement.' (Device does not work correctly)

Since some commands are received and responded correctly, basically your FortiusANT installation is OK and therefore it sounds like a driver issue. Cannot help you right now with this, perhaps somebody else following FortiusANT has a clue?

Just for my information; where are you located?

WouterJD commented 4 years ago

Hmmm... I read Iainhay's note on CYPLUS ANT-sticks: https://github.com/WouterJD/FortiusANT/issues/45#issuecomment-620065659 seems like bad news on this kind of dongles.

iainhay commented 4 years ago

Just to jump in, I had similar issues as referenced by @WouterJD - it was an issue with the CYCPLUS dongles, I ordered these to help confirm it was or wasnt the issue and these worked straight away.

Not sure why the CYCPLUS ones don't work, I'm going to try and find out why and what the difference is but changing the dongles should solve the issue.

ElDonad commented 4 years ago

Alright, merci de vos réponses !

So the ant dongle are causing the issue, weird... Something I noticed is that the driver of the linux version of antifier is working properly (that said, is able to communicate with the other dongle). I will check tomorrow if the windows version works as well, if so we might have the beginning of an answer, if not I will have either to implement the serial interface for FortiusANT, or the 1902 head unit support for antifier. Probably which one is the simplest, I don't have much knowledge about ant or serial drivers tough ...

Anyway, if you want to experiment with these devices, I could get you an ssh server running, tell me if you're intrested !

EDIT : an article I got from googling a bit, for what it's worth 😄 : https://tacxfaqx.com/knowledge-base/cycplus-ant-stick/

WouterJD commented 4 years ago

The antifier code contains solutions for a serial interface (see antifier.py and search for posix). Since FortiusANT works on windows, linux, macOS, etc I am not very inclined to restore the serial interface because some dongles do not work correctly...

Unless somebody has a clear reason to do that and a solid condition when that interface should be used...

ElDonad commented 4 years ago

Yes, I can understand that. But anyway, following what was being said by the article, the dongle "zwift-side" may cause the same kind of issue, even if they seem to connect. I will try to investigate a bit further, since these little pieces of scrap aren't cheap nor quick to deliver ^^ but I might eventually end up buying another model...

WouterJD commented 4 years ago

I understand Elie, and I understand that ANT+ dongles may be difficult to get. I leave you to it to resolve the issue, but will limit effort for this issue.

ElDonad commented 4 years ago

Alright, thank you again for your advice ! I will try to post here the eventual results of my investigations, but for now I think I can consider this thread closed.

totalreverse commented 4 years ago

Just a thought: several ANT+ implementations add two (or more) '0x00' bytes after the checksum. Maybe some dongles need these additional dummy bytes?

mattipee commented 4 years ago

I have just received two of these dongles.

The error I get is: 23:17:15,413: devAntDongle.read exception: [Errno None] b'libusb0-dll:err [submit_async] submitting request failed, win error: The device does not recognize the command.\r\n' 23:17:15,415: devAntDongle.write exception: [Errno None] b'libusb0-dll:err [submit_async] submitting request failed, win error: The device does not recognize the command.\r\n'

Adding the two null bytes after checksum (in ComposeMessage()) didn't help in my case.

WouterJD commented 4 years ago

Just a thought: several ANT+ implementations add two (or more) '0x00' bytes after the checksum. Maybe some dongles need these additional dummy bytes?

Antifier had two 0x00 bytes in every message and these did not make it to ComposeMessage() because there was no indication whatsoever why these 0x00's were there. Perhaps not smart after all; they will there for a reason. @totalreverse would you recommend to add these padding bytes? I have experience (and others) that ANT dongles "hang" and need full power-down-restart to get working properly again. Could that be related? Do 0x00 bytes give the dongles "space to breathe"?

Suggestions and hints welcome, and yes @mattipee I have read your test-result. Thanks guys!

mattipee commented 4 years ago

FortiusANT.2020-04-28 06-53-43.log @WouterJD for visibility, here's the log from the start.

mattipee commented 4 years ago

@WouterJD subject line to "CYCPLUS"

On Linux, I see "Pipe error" followed by many "No such device" errors. Note that in /var/log/messages, I see the ANT+ adapter reconnecting with a different numeric id. Also note that I appear to be able to restart FortiusANT repeatedly and it looks very much like every second attempt will succeed, and every other attempt will fail. I haven't checked that another device can read what the is being sent using the CYCPLUS, but FortiusANT doesn't always fail.

I wonder perhaps if it's worth implementing a three-retries approach to starting ANT+, certainly being defensive and failing and stopping automatically if there's nothing but exceptions.

WouterJD commented 4 years ago

Be my guest for a code-suggestion. It feels like programming around a faulty device, however, but I'm OK to adopt code when suggested.

WouterJD commented 4 years ago

PS. Perhaps an idea to log an issue in pyusb; I have the impression that they respond pretty fast. Perhaps they have a suggestion...

ElDonad commented 4 years ago

Hello again ! I have done some debugging on my side, and after having butchered your code to work with linux's serial interface, I was able to determine that the device return an error upon sending the event 4e (broadcast message). Here is the error message I got (deciphered with the ANT+ specification, not exactly sure of what I'm doing here...) a4 : start 03 : size 40 : message channel 01 : channel number 01 : message id 09 : message code : EVENT_CHANNEL_COLLISION ee : checksum

EDIT : it appears that the problem is found also with antifier, so I'm assuming that even if I was able to connect the two dongles using antifier, I wouldn't have been able to get them to run, since this message come after all the channel setup, and is used to broadcast data.... Again I'm not a specialist, this is only blind guesses and I might be wrong.

WouterJD commented 4 years ago

Please send the logfile as generated with -d127

WouterJD commented 4 years ago

PS, where are you from Elie? I like to know about the spread of FortiusANT and if you can, give me a ping on Strava: https://www.strava.com/athletes/2885978

@martingeraghty please join this issue (#67 closed)

martingeraghty commented 4 years ago

Thanks for adding me to this thread @WouterJD,

It certainly looks certain that the CYPLUS ANT+ dongle has issues but it would be good to confirm that there isn't anything else under the covers related to the i-magic. I have attached a log file where I ran FortiusANT.py -m -d 127, my ANT+ dongle was not connected to the computer. You'll note that no speed or cadence info is received from the trainer. Have you tried to run in manual mode without the dongle Elie? FortiusANT.2020-04-30 09-11-26.log

mattipee commented 4 years ago

Just to prove my point that the CYCPLUS dongle appears to be capable of working...

$ python3 pythoncode/FortiusAnt.py -s
14:23:51,803: Dongle - Using CYCPLUS dongle
14:23:51,803: Tacx   - Simulated Trainer
14:23:51,804: AntHRM - Heartrate expected from Tacx Trainer
14:23:52,308: devAntDongle.write exception: [Errno 32] Pipe error
14:23:52,308: Tacx2Dongle() raised an exception, retries remaining: 3
14:23:54,853: Dongle - Using CYCPLUS dongle
14:23:56,886: devAntDongle.write exception: [Errno 32] Pipe error
14:23:56,887: Tacx2Dongle() raised an exception, retries remaining: 2
14:23:59,434: Dongle - Using CYCPLUS dongle
14:24:00,919: Ctrl-C to exit
14:24:00,919: Tacx   - Simulated Trainer
14:24:00,966: Target=100W Speed=31.2kmh hr= 92 Current= 12W Cad= 89 r=   0  15
14:24:01,968: Target=100W Speed=32.9kmh hr= 88 Current= 48W Cad= 94 r=   0  15
14:24:02,970: Target=100W Speed=33.8kmh hr= 88 Current= 68W Cad= 96 r=   0  15
14:24:03,971: Target=100W Speed=34.1kmh hr= 92 Current= 75W Cad= 97 r=   0  15
14:24:04,972: Target=100W Speed=34.7kmh hr= 91 Current= 85W Cad= 99 r=   0  15
14:24:05,975: Target=100W Speed=34.2kmh hr= 88 Current= 87W Cad= 97 r=   0  15
14:24:06,977: Target=100W Speed=35.1kmh hr= 86 Current= 94W Cad=100 r=   0  15
14:24:07,977: Target=100W Speed=35.7kmh hr= 92 Current=103W Cad=102 r=   0  15
14:24:08,979: Target=100W Speed=35.0kmh hr= 85 Current= 98W Cad=100 r=   0  15

This retry-and-eventually-it-works approach works on my MX-19 Linux VM running on a server, but appears not to work on Raspberry PI 3 B+, or on Windows 7 Pro.

My CYCPLUS branch is here: https://github.com/mattipee/FortiusANT/tree/issue_65_cycplus

Edit: and it absolutely works, running GoldenCheetah on laptop with another dongle proves the CYCPLUS dongle on Linux server is connecting.

ElDonad commented 4 years ago

Wow, that is odd ! I never got it to work properly. Here is some more logging I have done, hope it helps...

As know next to nothing about ant, I wouldn't try make conclusions, but I would guess either there is something that has to be taken care of about this instruction, that this device is requiring, or this instruction on this specific device is faulty. Honestly no idea :sweat_smile:

Yes, I tried to run FortiusANT with a simulated dongle and my real trainer, everything works perfectly, which is to be expected : I already coded some small games to work with the bike ^^

I am from France @WouterJD (which explain my poor english ^^) , and never heard about Strava. I will definitively take a look at it !

@mattipee have you been able to connect to zwift or similar application ? I also got the two dongles to connect in zwift, but since all the channel and connection stuff is already configured when the first call to 4e is done in code, it might be that the device is able to connect, but not to send data. I will check that since now I am able to reach this point too ^^

And here I am, hope some of that will be useful to you !

EDIT : Actually there is two similar error messages being sent back : a4 03 40 01 01 09 ee and a4 03 40 00 01 09 ef. Apparently the only thing that differs is the fourth byte, which is the channel number, following the doc. So maybe these to channels are conflicting each other. Not sure why this would happen since I don't know why there would be two channels in the first place, maybe you will be able to tell...

WouterJD commented 4 years ago

Great guys! Thanks for working on the FortiusANT software to get your trainer and dongle working!

Matty I gave your code a quick check; as soon as tested an OK I will certainly adopt. Let's discuss then, I see your fork and https://github.com/mattipee/FortiusANT/tree/issue_65_cycplus/pythoncode we'll have to dicuss how to integrate lateron!

ElDonad commented 4 years ago

Also I can post here the small code snipped to detach the kernel drivers from the dongle :

for config in devAntDongle:
    for i in range(config.bNumInterfaces):
        if devAntDongle.is_kernel_driver_active(i):
            devAntDongle.detach_kernel_driver(i)
mattipee commented 4 years ago

@ElDonad I didn't know there was a way to detach the driver in code - I've been moving kernel module .ko files out of the way so that they don't load. I'll give that snippet a try.

Have you got your serial code committed onto a branch?

When I got the CYCPLUS dongle working, I managed to get it hooked up to both SimulANT+ and GoldenCheetah. So it would definitely have worked in Zwift. Unfortunately now, on my server, every time it fails and before my retry, the USB redirection into the VM is throwing an error. Frustrating, but glad I recorded my partial success earlier... it IS possible... we WILL crack it... :)

Would be good to see the changes you're trying and the code you're testing out, Elie.

mattipee commented 4 years ago

@ElDonad When I look in /var/log/messages (or similar), I see that the USB device disconnects and reconnects - and gets a different device ID each time. That used to happen inside my VM, it's now happening on my hosting server, which means the USB redirection fails because the device gets a new ID. I'm frustrated.

ElDonad commented 4 years ago

Oh ! Forget everything I said before, it totally works !

Seeing that you achieved to get it to work, I tried to connect it to zwift, and the usb version with the reset disabled totally works ! It eventually crashes at some point, not sure why, I will study the logs to try understanding more, but it totally works !

I would be glad to share with you my poorly written code of mine, give me some time to tidy it up a little bit and I publish my branch right away. Now I go back to log-studying, I get back to you when I have news.

mattipee commented 4 years ago

@ElDonad Splendid!!! I made ResetDongle() do nothing and results were much better! No failures on six starts, but an eventual crash on the last when I left it for a bit.

ElDonad commented 4 years ago

Okay, so here is the first log I've got : FortiusANT.2020-04-30 18-14-29.log We can see that everything is doing fine until line 4697, where an Errno 32 spawns from nowhere and hangs the device. Absolutely no idea why it does that, but I will try to find out.

mattipee commented 4 years ago

To cope with spurious errors, I guess my catch->raise->retry implementation on my branch could be used... the dongle will change device ID I think, and therefore you need to re-find it and re-initialise it... that should be able to be done during runtime, even if it requires some decoupling of stuff in Tacx2Dongle(). Good progress, though.

ElDonad commented 4 years ago

Ok, so as I suspected, the device eventually resets itself, we can see it through dmesg. Not sure if it is software induced or a behaviour of the device itself, but when it happens it don't reconnect on the same usb pipe it was previously, which causes the program to crash. My guess is that we could detect theses disconnections with libusb and reinitialize the device on the fly.

ElDonad commented 4 years ago

So, same conclusions ! Perfect, the solution is near :smile:

I will take a look at pyusb, to see if there isn't a way to detect these crashes. We can however only hope that the setup process will be quick enough for the user not to notice the discontinuity...

mattipee commented 4 years ago

Ok, so as I suspected, the device eventually resets itself, we can see it through dmesg. Not sure if it is software induced or a behaviour of the device itself, but when it happens it don't reconnect on the same usb pipe it was previously, which causes the program to crash. My guess is that we could detect theses disconnections with libusb and reinitialize the device on the fly.

Precisely what my retry loop does.

mattipee commented 4 years ago

Using command line parameter -s (and no -g) as a quick way to test on multiple systems where I don't have real Fortius connected, I get the following good results:

With the Fortius attached to the Raspberry PI:

PS. A fairly comprehensive page on USB resetting, though I appreciate it's NOT resetting that we care about. Useful link perhaps anyway... https://askubuntu.com/questions/645/how-do-you-reset-a-usb-device-from-the-command-line, particularly as, if there's a device that seems to be locked and unable to be picked up when starting FortiusANT, then the .c program near the top works well to free it up and carry on... particularly as I'm in the house and my trainer/FortiusANT are running in the garage, and I don't want to go out just to unplug and re-plug a dongle.

ElDonad commented 4 years ago

Back, after I got my ubuntu screen back in the right oritentation (didn't tough there was an accelerometer in laptops :sweat_smile: )

Calibration with reset ? I noticed that the reset in the calibration made the device to hang...

ElDonad commented 4 years ago

By the way, I just tried to run the program without any sort of endpoint for the dongle (so it is emitting in the void), and it never crashes ! I don't know exactly what causes that, but it is definitely something weird...

WouterJD commented 4 years ago

Guys, just a thought:

SendToDongle(messages, ...): sends/receives messages to the dongle in a loop. Could it be that a short sleep(0.1) or so would give the dongle time and that the error would not occur?

mattipee commented 4 years ago

I've just done a 40 minute test with CYCPLUS on a Raspberry PI 3 B+ probably crashed a dozen or more times - I was running my branch with a 3-retry loop, but if FortiusANT terminated completely, I could just run it again on the command line and keep riding. A little wobble as the 100W default kicks in and I guess it needs to wait for the next grade instruction from the controlling software.

But very happy that.

@WouterJD - I was wondering about whether a sleep would help - certainly the Reset() doesn't play nicely with the CYCPLUS - it may be that a strategic sleep might help but is it not on a 0.25 second period anyway?

WouterJD commented 4 years ago

Yes, there is a.25s cadence. But at times there are more messages to be sent and those are sent one-after-the-other. The messages are gathered in a list and the list is processed by SendToDongle() after every send a receive is done of which the answers are gathered in a list again. This is the original antifier setup and avoids that a series of 6 messages would cost seconds

In tehe CYCPLUS case it might be too fast

mattipee commented 4 years ago

@WouterJD Not sure about this... I modified SendToDongle() to write each message multiple times in a row and it didn't seem to mind.

I'll see about doing some USB or ANT+ capture and see if there's anything peculiar around the times it drops.

WouterJD commented 4 years ago

Was just a thought

WouterJD commented 4 years ago

Could you please summarize what has been changed, retyr + detach etc. I've been looking through the issue but don't find it; I see antDongle.py is changed in your fork, please help forward so we can merge these solutions.

Note that I cannot test, not having this dongle nor unix.

mattipee commented 4 years ago

The retry thing I'm not sure about yet.

The basic is to suppress ResetDongle() which I don't think I've committed yet.

Soon...

WouterJD commented 4 years ago

Wouldn't that be a simple solution!

WouterJD commented 4 years ago

After a solid afternoon of rounding up small issues, now going for some food :-)