Closed inonoob closed 3 years ago
Good day @inonoob Welcome to the FortiusANT community
I'm always curious to know who I communicate with, where FortiusANT is used and what configuration is used. Please tell me what bundle did you buy, and what brake and what head unit do you use? I would therefore appreciate that you introduce yourself; perhaps leave a comment under issue #14.
@inonoob "Or what did I miss ?" I am curious about your exact question, what do you think it should be?
I admit I'm pretty much struggling with the way byte 7 is described; but since the capabilities bit field is "the lower 4 bits of byte 7" I assume that bit0 is the least significant bit. Therefore HRM = 0x03 would be "The source of the heart rate is hand contact sensor". I do not know anymore why that option has been chosen.
Hey,
the reason why I ask is I have the same problem to know exactly which one is correct. I'm currently building a kind of FortiusANT for a rowing machine called Waterrower. Thing is I finished to implement BLE for things like Zwift or Kinomap or Werow. But now I also would like to have ANT in order to send the data to the Garmin watch.
I'm currently implementing the ANT+ with python-ant lib but those things, I try to understand more in depth because the FE and Rowing machine is not implemented. So I checked yours to see how you build the byte from the bits.
I though about little endian because I saw this kind of thing also in the FIT documents which is also Garmin. When they worked with bits that It would work that way. But I'm also confused. :(
@inonoob Your example looks correct. As far as I know, "bit 0" in ANT documents always refers to the least significant bit. I'm not sure if this is ever stated explicitly, but like @WouterJD said it is implied in various places (and very common outside of ANT). I would refer to this as "LSB 0" bit ordering rather than "little endian" though because the latter is usually used to refer to byte ordering and things are confusing enough without mixing that up.
I guess FortiusANT should technically set HR source to 0x2 (5kHz HRM) if the data is from the Tacx head unit. In theory, I think the idea is that the FE display device can prioritize based on source: if the data is from a HRM strap (more accurate/realiable than contact sensor), just use that, otherwise keep looking for a ANT+ HRM source. In practice, I would expect it is usually ignored nowadays. When the FE profile was originally specified for treadmills in 2009, an FE display device might have been a battery-powered head unit with a limited UI...
Improving/verifying compliance with the profile specs is on my todo-list (there are also some automated tests), but not very high because the current implementation seems to mostly work with relevant display devices/CTPs.
@inonoob If you haven't already, I strongly suggest you look at SimulANT+ from the ANT download page. I have found it very useful for testing and to clear up some ambiguities. There is also https://www.thisisant.com/forum/ which may or may not be helpful.
Hey that's great; I'm curious what that is going to be ... Waterrower!
First: big/litte endian does not apply here; that affects byte-sequence in an int (short, long), not the bit-sequence in a byte.
For our case the solution is given on page 31 8.5.2.6 "capabilities = the lower 4 bits of byte 7"; based upon that I have concluded that bit0 is the least significant bit of the "lower four bits" and also the whole byte.
Therefore the table as you have drawn matches what I read now (although some confusion remains) and how it is implemented today. And I did not ghet any complaints that it would not work.
Regarding "how you build the byte from the bits"; I remember I was struggling with this and it's the only place where bits in a byte are addressed.
What I should have done to properly document the code:
# bit 7... ...0
HRM = 0b0000 0011 # 0b____ __xx bits 0-1 3 = hand contact sensor (2020-12-28 Unclear why option chosen)
Distance = 0b0000 0000 # 0b____ _x__ bit 2 0 = No distance in byte 3 (2020-12-28 Unclear why option chosen)
VirtualSpeedFlag = 0b0000 0000 # 0b____ x___ bit 3 0 = Real speed in byte 4/5 (2020-12-28 Could be virtual speed)
FEstate = 0b0011 0000 # 0b_xxx ____ bits 4-6 3 = IN USE
LapToggleBit = 0b0000 0000 # 0bx___ ____ bit 7 0 = No lap toggle
Capacilities = HRM | Distance | VirtualSpeedFlag | FEstate | LapToggleBit
Looking at the options today, I might have chosen differently.
@inonoob is your project already published?
Hey,
Will Clean my code tonight and hopefully post the code on GitHub. I still have to test one thing this evening before publishing it.
Many thanks for the feedback.
Concerning th ant+ simulator. How can I have access to it. I'm not a company. And if I'm right you need to register. So I did look for the documents on the internet and study source code on GitHub to understand the ant protocol.
Also nice documentation. That helped a lot.
Hey that's great; I'm curious what that is going to be ... Waterrower!
First: big/litte endian does not apply here; that affects byte-sequence in an int (short, long), not the bit-sequence in a byte.
For our case the solution is given on page 31 8.5.2.6 "capabilities = the lower 4 bits of byte 7"; based upon that I have concluded that bit0 is the least significant bit of the "lower four bits" and also the whole byte.
Therefore the table as you have drawn matches what I read now (although some confusion remains) and how it is implemented today. And I did not ghet any complaints that it would not work.
Regarding "how you build the byte from the bits"; I remember I was struggling with this and it's the only place where bits in a byte are addressed.
What I should have done to properly document the code:
# bit 7... ...0 HRM = 0b0000 0011 # 0b____ __xx bits 0-1 3 = hand contact sensor (2020-12-28 Unclear why option chosen) Distance = 0b0000 0000 # 0b____ _x__ bit 2 0 = No distance in byte 3 (2020-12-28 Unclear why option chosen) VirtualSpeedFlag = 0b0000 0000 # 0b____ x___ bit 3 0 = Real speed in byte 4/5 (2020-12-28 Could be virtual speed) FEstate = 0b0011 0000 # 0b_xxx ____ bits 4-6 3 = IN USE LapToggleBit = 0b0000 0000 # 0bx___ ____ bit 7 0 = No lap toggle Capacilities = HRM | Distance | VirtualSpeedFlag | FEstate | LapToggleBit
Looking at the options today, I might have chosen differently.
@inonoob Just register as an "ANT+ adopter" on thisisant.com. It is free and you don't need a company (at least that was the case last I checked). It should give you access to all the documents and tools you need. Just a few things to be aware of:
But using the info and tools to make your own open source implementation should be completely fine.
Off-topic, let see how long ant+ will be a thing as more and more companies switch to the ble standard with the fitness machine profile and their services. Other thing I tried to get also connected to apple watches but they also have there own protocol called "gymkit" which is even more difficult to get information.
Many thanks to everyone for the help. I think to topic can be closed
Just register as an "ANT+ adopter" on thisisant.com
That's what I did and it works fine untill today.
What I should have done to properly document the code:
# bit 7... ...0 HRM = 0b0000 0011 # 0b____ __xx bits 0-1 3 = hand contact sensor (2020-12-28 Unclear why option chosen) Distance = 0b0000 0000 # 0b____ _x__ bit 2 0 = No distance in byte 3 (2020-12-28 Unclear why option chosen) VirtualSpeedFlag = 0b0000 0000 # 0b____ x___ bit 3 0 = Real speed in byte 4/5 (2020-12-28 Could be virtual speed) FEstate = 0b0011 0000 # 0b_xxx ____ bits 4-6 3 = IN USE LapToggleBit = 0b0000 0000 # 0bx___ ____ bit 7 0 = No lap toggle Capacilities = HRM | Distance | VirtualSpeedFlag | FEstate | LapToggleBit
Looking at the options today, I might have chosen differently.
@switchabl would you suggest to use other constants thsn the ones used now?
Maybe consider to have options. As mentioned, I would like to implement ant beside ble to be able to send the data from my rowing machine to Garmin watches. And the flag "laps" is a big part of the Garmin fit files if you wanna import it to Garmin connect or Strava. I have a repo where I go very deep in detail what a fit file is and how it can be implemented in python. My code is not as nice as yours
Export TCX; feel free to copy tcxExport.py
WouterJD at the end the FIT format gives you a lot more details for a training but beside that check this explanation why I took the hard way and went with fit files:
Quote from my repo:
But first let's talk background for garmin's file formats:
in the early days of data gathering for sport activities, Garmin developed the program Garmin Training Center link and along with the program the exchange file Training Center XML (TCX) has been developed. This file format has only 3 categories for sport : ( Running, Bike and Others). Garmin begun developing smartwatches and switched from being a gps for cars manufacture to a fitness gadget manufacture. In order to achiv to store a lot of data on small smartwatch, garmin decide to introduce a new format which is called the FIT format. Which has a lot more information and can be used for a lot of fitness IoT devices. Rowing machine, Smartscales and the list goes on. This new file is a binary file which has all the information needed. An example is each sport has an dedicated number. But also a lot of other things can be stored in that file. The Waterrower for example has the manufacture id 118 so it exist but not yet used. Garmin connect is complete centered and focused on the FIT file system. The TCX format is a legacy format which is still used as it is widely adopted for a lot of fitness tracking pages, apps and fitness machines.
But why have you made this script if the TCX file is working well... Well not quiet as you expect. The most annoying thing is that garmin doesn't respect their own tcx file format. The best example is the stroke amount. The coxswain implementation of the tcx file format respect to the letter the garmin nomenclature. But when this file is uploaded to Garmin connect as indoor-rowing. It just ignores the stroke amount. But isn't it possible to just edit this in Garmin connect ? Nop ... Garmin don't even let you edit because it completely missing.
Thanks for explaining
I implemented TCX because of the request to import manual rides into Strava; in fact FortiusANT is not the sports-application but a device driver.
Hey
You are welcome. May I ask if I could use your ant code for my waterrowerAntble project.
My repo is now online: https://github.com/inonoob/WaterrowerAntBle
I'm fine; please document that you have borrowed code from the FortiusANT project. I think we can close this issue; please keep me informed on your progress.
Just for my curiosity: where are you from?
Germany :)
Many thanks again @WouterJD. The Ant+ part is now working in my project. I can use Bluetooth LE via Bluez and Ant+ to send the rowing data.
Hey,
I just checked the antDongle code and saw that I'm not sure about the byte nr.7 for ANT+ page 16.
link to the code
This is how I read the document:
ANT+ Device Profil Fitness Equipment Page 31 8.5.2.6 + ANT+ Device Profil Fitness Equipment Page 31 8.5.2.7
Or what did I miss ?