diff --git a/README.md b/README.md index 1999b5d..ae42f1c 100644 --- a/README.md +++ b/README.md @@ -119,13 +119,13 @@ The binary is built to `bin/bridge`. ## Usage ```bash -# Use defaults (device 3001) +# Listen to all trainers (default) sudo ./bin/bridge -# Custom trainer device +# Filter for a specific trainer sudo ./bin/bridge --device 0xbb9 -# Custom vendor/product IDs +# Custom vendor/product IDs with specific device sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001 ``` @@ -135,14 +135,14 @@ sudo ./bin/bridge --vendor 0x0fcf --product 0x1008 --device 3001 |------|---------|-------------| | `--vendor` | `0x0fcf` | USB vendor ID (hex or decimal, e.g. `0x0fcf` or `4047`) | | `--product` | `0x1008` | USB product ID (hex or decimal) | -| `--device` | `3001` | ANT+ device number (hex or decimal, e.g. `3001` or `0xbb9`) | +| `--device` | `0 (any)` | ANT+ device number (hex or decimal). Use 0 or omit to listen to all devices | | `--help` | | Show help | | `--version` | | Show version info | ## Finding your trainer's ANT+ device number -Most ANT+ cycling power trainers use device number `3001` (decimal) or `0xbb9` (hex). If that works, you can use the -bridge with default settings. +The bridge listens to all broadcasting devices by default. When multiple ANT+ trainers are nearby, each will appear in the +log output as `ant: : power: ...`. Use `--device ` to filter for a specific trainer. If you're unsure of your trainer's device number, you can discover it using another ANT+ device (e.g., a Garmin Edge head unit). Connect the Garmin to your trainer and look for the device number in the ANT+ sensor list. @@ -179,11 +179,14 @@ Your trainer's power and cadence data should now be available in the app. ``` 2026-05-26 11:00:34 ANT Bridge abc1234 built 2026-05-26T11:00:00 -2026-05-26 11:00:34 vendor: 0x0fcf/4047 -2026-05-26 11:00:34 product: 0x1008/4104 -2026-05-26 11:00:34 device: 0xbb9/3001 -2026-05-26 11:00:34 BLE advertising... -2026-05-26 11:00:34 bt: watts: 150 rpm: 80 completedRevs: 1234 lastRevTime: 4890 +2026-05-26 11:00:34 usb: vendor: 0x0fcf/4047 +2026-05-26 11:00:34 usb: product: 0x1008/4104 +2026-05-26 11:00:34 ant: device: any +2026-05-26 11:00:34 ant: device opened +2026-05-26 11:00:34 bt: BLE advertising... +2026-05-26 11:00:34 ant: scan mode started +2026-05-26 11:00:34 ant: listening... +2026-05-26 11:00:35 ant: 3001: power: 150W cadence: 80 rpm ``` The bridge logs a lot of output during normal operation — this is expected and helpful for debugging during this early @@ -191,9 +194,14 @@ stage of development. Key log lines: - `ANT Bridge ...` — Startup message with version and build time -- `vendor: ...` / `product: ...` / `device: ...` — Configuration being used -- `BLE advertising...` — BLE service is ready and visible to other devices -- `bt: watts: ...` — Power and cadence data being broadcast +- `usb: vendor: ...` / `usb: product: ...` — USB dongle configuration +- `ant: device: ...` — ANT+ device filter (or `any` if listening to all devices) +- `ant: device opened` — USB dongle opened successfully +- `bt: BLE advertising...` — BLE service is ready and visible to other devices +- `ant: scan mode started` / `ant: listening...` — ANT+ receiver is active +- `ant: : power: ...` — Power/cadence data with transmitting device ID +- `bt: watts: ...` — Power/cadence data being broadcast over BLE +- `ant: received msg from ignored device ...` — Message from non-matching device (when `--device` is specified) - `hciconfig ... failed` — Bluetooth adapter reset warnings (usually harmless) ## Development @@ -228,12 +236,12 @@ make clean # Remove build artifacts ### No data from trainer - Make sure the trainer is turned on and broadcasting -- Use another device (e.g. Garmin Edge) to verify it is broadcasting. This also provides a way - to get the device id. +- Use another device (e.g. Garmin Edge) to verify it is broadcasting. This also provides a way + to get the device id. +- The bridge listens to all devices by default. If multiple trainers are broadcasting, use + `--device ` to filter for a specific one - Make sure the dongle is close enough to the trainer (within 1-2 meters) -- Verify the device number is correct (try `--device 3001`) - Check the log output for the `listening...` message -- Try a different device number if available ### BLE connection drops diff --git a/bridge b/bridge index cd569c5..3c89a16 100755 Binary files a/bridge and b/bridge differ diff --git a/cmd/bridge/ant.go b/cmd/bridge/ant.go index b1b5065..e3157da 100644 --- a/cmd/bridge/ant.go +++ b/cmd/bridge/ant.go @@ -56,8 +56,8 @@ func ListenForTrainer(vendorId uint16, productId uint16, deviceNumber uint32, logMsg("ant: listening...") for msg := range msgs { - if msg.DeviceNumber() != deviceNumber { - logPrintf("Received msg from ignored ant+ device %v\n", msg.DeviceNumber()) + if deviceNumber != 0 && msg.DeviceNumber() != deviceNumber { + logPrintf("ant: received msg from ignored device %v\n", msg.DeviceNumber()) continue } //fmt.Printf("raw msg: device type=0x%02x device number=%d content=%x\n", diff --git a/cmd/bridge/cli.go b/cmd/bridge/cli.go index e544106..8dc3bd8 100644 --- a/cmd/bridge/cli.go +++ b/cmd/bridge/cli.go @@ -52,19 +52,26 @@ This allows these trainers to be used with modern devices that don't support ANT if err != nil { return fmt.Errorf("invalid --product %q: %w", c.product, err) } - deviceNumber, err := parseHex(c.device, 32) - if err != nil { - return fmt.Errorf("invalid --device %q: %w", c.device, err) + c.vendorID = uint64(vendorID) + c.productID = uint64(productID) + if c.device != "" { + deviceNumber, err := parseHex(c.device, 32) + if err != nil { + return fmt.Errorf("invalid --device %q: %w", c.device, err) + } + c.deviceNumber = uint32(deviceNumber) } - c.vendorID = vendorID - c.productID = productID - c.deviceNumber = uint32(deviceNumber) + deviceNumber := c.deviceNumber logMsgf("ANT Bridge %s built %s", Version, BuildTime) logMsgf("usb: vendor: 0x%04x/%d", vendorID, vendorID) logMsgf("usb: product: 0x%04x/%d", productID, productID) - logMsgf("ant: device: 0x%03x/%d", deviceNumber, deviceNumber) + if deviceNumber == 0 { + logMsgf("ant: device: any") + } else { + logMsgf("ant: device: 0x%03x/%d", deviceNumber, deviceNumber) + } if err := exec.Command("hciconfig", "hci0", "down").Run(); err != nil { logPrintf("bt: hciconfig down failed: %v\n", err) @@ -83,7 +90,7 @@ This allows these trainers to be used with modern devices that don't support ANT rootCmd.Flags().String("vendor", "0x0fcf", "USB vendor ID (hex, e.g. 0x0fcf)") rootCmd.Flags().String("product", "0x1008", "USB product ID (hex, e.g. 0x1008)") - rootCmd.Flags().String("device", "3001", "ANT+ device number (hex or decimal, e.g. 3001 or 0xbb9)") + rootCmd.Flags().String("device", "", "ANT+ device number (hex or decimal). Use 0 or omit to listen to all devices") if err := rootCmd.Execute(); err != nil { os.Exit(1) }