nRF24AP1 - ANT Code - Garmin Heart-Rate Monitor

smohit@hotmail.com:
i see, basically i wanted to have a heartrate strap that transmits data to 2 devices

  1. something thats always on the person to store the data for the last 24 hours…

  2. a pc connection to keep a monitor of the data aswell…

any ideas or if i could use any products i.e. sunito belt with our own ANT modules? or are we restricted to use their own ANT reciever and software?

The Suunto ANT receiver (PC Pod) only receives from Suunto devices. It has a fixed network key. The garmin ANT stick can receive from any ANT device including the Suunto. Presumably you've looked at the Suunto memory belt? I'm not sure if it can store 24 hours of data or not though.

I was looking at the data sheet and noticed that to get a baud rate of 9600 one would three BR pins (BR1, BR2, and BR3). This board only has BR1 and BR2, can it not be configured to a 9600 baud rate?

Hi

I wrote a basic code to interface with ANT board. I am using Suunto HRM strap.

I took Suunto settings from other code availalbe on this forum. here is what i did in initialization

ANT_ResetSystem();

delay(20);

ANT_RequestMessage(MESG_CAPABILITIES_ID);

delay(100);

ANT_AssignChannel();

delay(20);

ANT_SetChannelId();

delay(20);

ANT_SetNetworkKey();

delay(20);

ANT_SetChannelSearchTimeout();

delay(20);

ANT_SetChannelPeriod();

delay(20);

ANT_SetChannelRFFreq();

delay(20);

ANT_OpenChannel();

delay(20);

Here is the ONLY response I am getting back in terminal window…

  • RX: [sync]..0x3..0x40..0x0..0x54..0x28..0x9B

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler SConfig Done

    RX: [sync]…0x3…0x40…0x0…0x54…0x28…0x9B

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:54

    [unknown]

    Message Code:28

    RX: [sync]…0x3…0x40…0x0…0x42…0x0…0xA5

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:42

    [MESG_ASSIGN_CHANNEL_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0x0…0x51…0x0…0xB6

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:51

    [MESG_CHANNEL_ID_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0xD…0xB9…0x28…0x7B

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:D

    Message ID:B9

    [unknown]

    Message Code:28

    RX: [sync]…0x3…0x40…0x0…0x44…0x0…0xA3

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:44

    [MESG_CHANNEL_SEARCH_TIMEOUT_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0x0…0x43…0x0…0xA4

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:43

    [MESG_CHANNEL_MESG_PERIOD_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0x0…0x45…0x0…0xA2

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:45

    [MESG_CHANNEL_RADIO_FREQ_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0x0…0x4B…0x0…0xAC

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:4B

    [MESG_OPEN_CHANNEL_ID]

    Message Code:0

    RX: [sync]…0x3…0x40…0x0…0x1…0x1…0xE7

    RX: msg received

    ID: MESG_RESPONSE_EVENT_ID

    Response Handler Size:

    Channel Num:0

    Message ID:1

    [unknown]

    Message Code:1

  • I am not receiving any other message other than above! No burst mode data which has HR info.

    Any comments/suggestions on how to proceed.

    Thanks[/code][/list]

    Aspire:

  • RX: [sync]..0x3..0x40..0xD..0xB9..0x28..0x7B
    
  • RX: msg received
    ID: MESG_RESPONSE_EVENT_ID
    Response Handler Size:
    Channel Num:D
    Message ID:B9
    [unknown]
    Message Code:28

    
    </LI></LIST>
    

    It looks like your SetNetworkKey message was incorrectly formatted.

    Orin.

    Has anyone run this on a Mac? It compiles fine, but doesn’t show any output. I have the nordic’s vcc & ground connected to 3 volts that I’m getting from a L317 (because I read that 5v was too much), and the TX, RX, and RTS connected to 3 of the pins from my USB-FTDI cable. However, the program just seems to hang.

    Ultimately, I’d love to get this talking to an Arduino, but one step at a time, right?

    Any suggestions? Is it the cable, the OS, the board, the software, or the user? :wink:

    Hi!

    I’m new to this forum and to ANT and I’m trying to establish a connection between the Nordic USB Stick and the Garmin HRM, but I just can’t manage to do that. Can I actually use the ANT commands like ANT_OpenChannel() from the ANT.dll or do I have write an own routine to realize the ANT message protocol? I already opened up a new topic on that with a detailed explanation of my problem: viewtopic.php?f=13&t=21214.

    Can someone please help me and tell me to how to do it or maybe send me a program which is really working. I found a lot of stuff on the internet which is not really helpful.

    Thanks.

    I am also a newbie here trying to develop a Windows app to read real-time data from a Garmin HR monitor. I have a Garmin ANT USB stick and a Garmin HRM. I have found some code that uses functions in ANT_DLL.dll to communicate with the USB stick. (It only works if I first run, then kill Garmin’s “ANT Agent.exe”.) So far, I have been able to initialize, set the event callback function, and call ANT_RequestMessage to generate a few callbacks. I think I need to create a broadcast channel in which the HRM is the master and the USB stick is the slave. I assume that, if I can do that, I would get event callbacks from the USB stick with the HR data.

    Am I on the right track here? Can anyone point me to a decent source for documentation on how to do this? )So far, I have not even found anything on how to interpret the data that is set by the event callback.)

    I just got this working. It took me a while to figure out that I need to actually be wearing the HRM for it to connect and send data.

    Now I need to figure out how to interpret the data. Can anyone help me out here?

    Thanks.

    I only use the last two bytes.

    Byte 6 is a sequence number, if it’s changed you have a new reading.

    byte 7 is heart rate. I am not sure what filtering has already been aplied but I just take this as is.

    I think bytes 4-5 are some sort of timestamp for the actual beat time so you can compare them from different records to get a time between beats.

    Ifor

    I just bought this HR strap:

    http://www.amazon.com/gp/product/B00…_ya_os_product

    and this USB stick:

    http://www.amazon.com/Garmin-010-109…7&sr=8-1-spell

    Do you guys mind posting a windows version that works?

    I have been trying different stuff… including something I found on the ANT+ website, some demo called ANTFS… that at least detects the USB Drive (or claims to do so) but it never seems to “connect” to the HR strap

    I guess I can return the stuff I already bought and buy something else?.. just need a basic HRM and a USB stick to read the values “live/in real time” to my computer. I tried the code posted here on OSX but it seems that to access USB directly is a pain :(…

    Ideally I would like to get this working on OSX and Windows but windows is the main priority.

    I found this other good thread here but it is now “locked”… Garmin needs to get their stuff together.

    This is a slightly “Arduino-ified” version of the previous code, which allows the nrf24ap1 to get the information from a Garmin HR strap, and process the data with an 3.3v Arduino. Note that it uses the SoftwareSerial library to talk to the ANT receiver, so that the standard serial ports are free to communicate with a computer. This allows me to use the heartrate info to control things on my computer, like the volume of VLC player. :slight_smile: I do that with another python script that reads the other end of the serial connection.

    #include <SoftwareSerial.h>
    
    #define UCHAR unsigned char
    
    #define rxPin 2
    #define txPin 3
    #define ledPin 13
    
    // set up a new serial port
    SoftwareSerial mySerial =  SoftwareSerial(rxPin, txPin);
    byte pinState = 0;
    
    #define RETURN_ERROR   -1
    #define RETURN_SUCCESS    0 
    #define DEBUG       1 
    
    
    #define MESG_TX_SYNC                      ((UCHAR)0xA4)
    #define MESG_RX_SYNC                      ((UCHAR)0xA5)
    #define MESG_SIZE_OFFSET                  ((UCHAR)1)    
    #define MESG_ID_OFFSET                    ((UCHAR)2)     
    #define MESG_SYNC_SIZE                    ((UCHAR)1)
    #define MESG_SIZE_SIZE                    ((UCHAR)1)
    #define MESG_ID_SIZE                      ((UCHAR)1)
    #define MESG_CHECKSUM_SIZE                ((UCHAR)1)
    #define MESG_MAX_DATA_SIZE                ((UCHAR)17)
    #define MESG_HEADER_SIZE                  (MESG_SYNC_SIZE + MESG_SIZE_SIZE + MESG_ID_SIZE)
    #define MESG_DATA_OFFSET                  MESG_HEADER_SIZE  
    #define MESG_FRAME_SIZE                   (MESG_HEADER_SIZE + MESG_CHECKSUM_SIZE)
    #define MESG_MAX_SIZE                     (MESG_MAX_DATA_SIZE + MESG_FRAME_SIZE)
    
    //////////////////////////////////////////////
    
    // Message ID's
    
    //////////////////////////////////////////////
    #define MESG_INVALID_ID                   ((UCHAR)0x00)
    #define MESG_EVENT_ID                     ((UCHAR)0x01)
    #define MESG_VERSION_ID                   ((UCHAR)0x3E)  // protocol library version
    #define MESG_RESPONSE_EVENT_ID            ((UCHAR)0x40)
    #define MESG_UNASSIGN_CHANNEL_ID          ((UCHAR)0x41)
    #define MESG_ASSIGN_CHANNEL_ID            ((UCHAR)0x42)
    #define MESG_CHANNEL_MESG_PERIOD_ID       ((UCHAR)0x43)
    #define MESG_CHANNEL_SEARCH_TIMEOUT_ID    ((UCHAR)0x44)
    #define MESG_CHANNEL_RADIO_FREQ_ID        ((UCHAR)0x45)
    #define MESG_NETWORK_KEY_ID               ((UCHAR)0x46)
    #define MESG_RADIO_TX_POWER_ID            ((UCHAR)0x47)
    #define MESG_RADIO_CW_MODE_ID             ((UCHAR)0x48)
    #define MESG_SEARCH_WAVEFORM_ID           ((UCHAR)0x49)
    #define MESG_SYSTEM_RESET_ID              ((UCHAR)0x4A)
    #define MESG_OPEN_CHANNEL_ID              ((UCHAR)0x4B)
    #define MESG_CLOSE_CHANNEL_ID             ((UCHAR)0x4C)
    #define MESG_REQUEST_ID                   ((UCHAR)0x4D)
    #define MESG_BROADCAST_DATA_ID            ((UCHAR)0x4E)
    #define MESG_ACKNOWLEDGED_DATA_ID         ((UCHAR)0x4F)
    #define MESG_BURST_DATA_ID                ((UCHAR)0x50)
    #define MESG_CHANNEL_ID_ID                ((UCHAR)0x51)
    #define MESG_CHANNEL_STATUS_ID            ((UCHAR)0x52)
    #define MESG_RADIO_CW_INIT_ID             ((UCHAR)0x53)
    #define MESG_CAPABILITIES_ID              ((UCHAR)0x54)
    #define MESG_NVM_DATA_ID                  ((UCHAR)0x56)
    #define MESG_NVM_CMD_ID                   ((UCHAR)0x57)
    #define MESG_NVM_STRING_ID                ((UCHAR)0x58)
    #define MESG_ID_LIST_ADD_ID               ((UCHAR)0x59)
    #define MESG_ID_LIST_CONFIG_ID            ((UCHAR)0x5A)
    #define MESG_OPEN_RX_SCAN_ID              ((UCHAR)0x5B)
    #define MESG_EXT_CHANNEL_RADIO_FREQ_ID    ((UCHAR)0x5C)
    #define MESG_EXT_BROADCAST_DATA_ID        ((UCHAR)0x5D)
    #define MESG_EXT_ACKNOWLEDGED_DATA_ID     ((UCHAR)0x5E)
    #define MESG_EXT_BURST_DATA_ID            ((UCHAR)0x5F)
    #define MESG_CHANNEL_RADIO_TX_POWER_ID    ((UCHAR)0x60)
    #define MESG_GET_SERIAL_NUM_ID            ((UCHAR)0x61)
    #define MESG_GET_TEMP_CAL_ID              ((UCHAR)0x62)
    #define MESG_SET_LP_SEARCH_TIMEOUT_ID     ((UCHAR)0x63)
    #define MESG_SET_TX_SEARCH_ON_NEXT_ID     ((UCHAR)0x64)
    #define MESG_SERIAL_NUM_SET_CHANNEL_ID_ID ((UCHAR)0x65)
    #define MESG_RX_EXT_MESGS_ENABLE_ID       ((UCHAR)0x66)
    #define MESG_RADIO_CONFIG_ALWAYS_ID       ((UCHAR)0x67)
    #define MESG_ENABLE_LED_FLASH_ID          ((UCHAR)0x68)
    #define MESG_AGC_CONFIG_ID                ((UCHAR)0x6A)
    #define MESG_READ_SEGA_ID                 ((UCHAR)0xA0)
    #define MESG_SEGA_CMD_ID                  ((UCHAR)0xA1)
    #define MESG_SEGA_DATA_ID                 ((UCHAR)0xA2)
    #define MESG_SEGA_ERASE_ID                ((UCHAR)0XA3)   
    #define MESG_SEGA_WRITE_ID                ((UCHAR)0XA4)
    
    //                                        ((UCHAR)0xA5) //FREE
    
    #define MESG_SEGA_LOCK_ID                 ((UCHAR)0xA6)
    #define MESG_FUSECHECK_ID                 ((UCHAR)0xA7)
    #define MESG_UARTREG_ID                   ((UCHAR)0XA8)
    #define MESG_MAN_TEMP_ID                  ((UCHAR)0xA9)
    #define MESG_BIST_ID                      ((UCHAR)0XAA)
    #define MESG_SELFERASE_ID                 ((UCHAR)0XAB)
    #define MESG_SET_MFG_BITS_ID              ((UCHAR)0xAC)
    #define MESG_UNLOCK_INTERFACE_ID          ((UCHAR)0xAD)
    #define MESG_IO_STATE_ID                  ((UCHAR)0xB0)
    #define MESG_CFG_STATE_ID                 ((UCHAR)0xB1)
    #define MESG_RSSI_ID                      ((UCHAR)0xC0)
    #define MESG_RSSI_BROADCAST_DATA_ID       ((UCHAR)0xC1)
    #define MESG_RSSI_ACKNOWLEDGED_DATA_ID    ((UCHAR)0xC2)
    #define MESG_RSSI_BURST_DATA_ID           ((UCHAR)0xC3)
    #define MESG_RSSI_SEARCH_THRESHOLD_ID     ((UCHAR)0xC4)
    #define MESG_BTH_BROADCAST_DATA_ID        ((UCHAR)0xD0)
    #define MESG_BTH_ACKNOWLEDGED_DATA_ID     ((UCHAR)0xD1)
    #define MESG_BTH_BURST_DATA_ID            ((UCHAR)0xD2)
    #define MESG_BTH_EXT_BROADCAST_DATA_ID    ((UCHAR)0xD3)
    #define MESG_BTH_EXT_ACKNOWLEDGED_DATA_ID ((UCHAR)0xD4)
    #define MESG_BTH_EXT_BURST_DATA_ID        ((UCHAR)0xD5)
    
    //////////////////////////////////////////////
    
    // Message Sizes
    
    //////////////////////////////////////////////
    
    #define MESG_INVALID_SIZE                 ((UCHAR)0)
    #define MESG_RESPONSE_EVENT_SIZE          ((UCHAR)3)
    #define MESG_CHANNEL_STATUS_SIZE          ((UCHAR)2)
    #define MESG_VERSION_SIZE                 ((UCHAR)9)
    #define MESG_UNASSIGN_CHANNEL_SIZE        ((UCHAR)1)
    #define MESG_ASSIGN_CHANNEL_SIZE          ((UCHAR)3)
    #define MESG_CHANNEL_ID_SIZE              ((UCHAR)5)
    #define MESG_CHANNEL_MESG_PERIOD_SIZE     ((UCHAR)3)
    #define MESG_CHANNEL_SEARCH_TIMEOUT_SIZE  ((UCHAR)2)
    #define MESG_CHANNEL_RADIO_FREQ_SIZE      ((UCHAR)2)
    #define MESG_NETWORK_KEY_SIZE             ((UCHAR)9)
    #define MESG_RADIO_TX_POWER_SIZE          ((UCHAR)2)
    #define MESG_RADIO_CW_MODE_SIZE           ((UCHAR)3)
    #define MESG_RADIO_CW_INIT_SIZE           ((UCHAR)1)
    #define MESG_SEARCH_WAVEFORM_SIZE         ((UCHAR)3)
    #define MESG_SYSTEM_RESET_SIZE            ((UCHAR)1)
    #define MESG_OPEN_CHANNEL_SIZE            ((UCHAR)1)
    #define MESG_CLOSE_CHANNEL_SIZE           ((UCHAR)1)
    #define MESG_REQUEST_SIZE                 ((UCHAR)2)
    #define MESG_CAPABILITIES_SIZE            ((UCHAR)6)
    #define MESG_DATA_SIZE                    ((UCHAR)9)
    #define MESG_NVM_DATA_SIZE                ((UCHAR)10)
    #define MESG_NVM_CMD_SIZE                 ((UCHAR)3)
    #define MESG_NVM_STRING_SIZE              ((UCHAR)9)
    #define MESG_ID_LIST_ADD_SIZE             ((UCHAR)6)
    #define MESG_ID_LIST_CONFIG_SIZE          ((UCHAR)3)
    #define MESG_OPEN_RX_SCAN_SIZE            ((UCHAR)1)
    #define MESG_EXT_CHANNEL_RADIO_FREQ_SIZE  ((UCHAR)3)
    #define MESG_EXT_DATA_SIZE                ((UCHAR)13)
    #define MESG_RADIO_CONFIG_ALWAYS_SIZE     ((UCHAR)2)
    #define MESG_RX_EXT_MESGS_ENABLE_SIZE     ((UCHAR)2)
    #define MESG_SET_TX_SEARCH_ON_NEXT_SIZE   ((UCHAR)2)
    #define MESG_SET_LP_SEARCH_TIMEOUT_SIZE   ((UCHAR)2)
    #define MESG_SERIAL_NUM_SET_CHANNEL_ID_SIZE ((UCHAR)3)
    #define MESG_ENABLE_LED_FLASH_SIZE        ((UCHAR)2)
    #define MESG_GET_SERIAL_NUM_SIZE          ((UCHAR)4)
    #define MESG_GET_TEMP_CAL_SIZE            ((UCHAR)4)
    #define MESG_AGC_CONFIG_SIZE              ((UCHAR)2)
    #define MESG_READ_SEGA_SIZE               ((UCHAR)2)
    #define MESG_SEGA_CMD_SIZE                ((UCHAR)3)
    #define MESG_SEGA_DATA_SIZE               ((UCHAR)10)
    #define MESG_SEGA_ERASE_SIZE              ((UCHAR)0)
    #define MESG_SEGA_WRITE_SIZE              ((UCHAR)3)
    #define MESG_SEGA_LOCKED_SIZE             ((UCHAR)1)
    #define MESG_SEGA_LOCK_SIZE               ((UCHAR)0)
    #define MESG_FUSECHECK_SIZE               ((UCHAR)1)
    #define MESG_UARTREG_SIZE                 ((UCHAR)2)
    #define MESG_MAN_TEMP_SIZE                ((UCHAR)2)
    #define MESG_BIST_SIZE                    ((UCHAR)6)
    #define MESG_SELFERASE_SIZE               ((UCHAR)2)
    #define MESG_SET_MFG_BITS_SIZE            ((UCHAR)2)
    #define MESG_UNLOCK_INTERFACE_SIZE        ((UCHAR)1)
    #define MESG_IO_STATE_SIZE                ((UCHAR)2)
    #define MESG_CFG_STATE_SIZE               ((UCHAR)2)
    #define MESG_RSSI_SIZE                    ((UCHAR)3)
    #define MESG_RSSI_DATA_SIZE               ((UCHAR)17)
    #define MESG_RSSI_SEARCH_THRESHOLD_SIZE   ((UCHAR)2)
    
    #define RETURN_ERROR   -1
    #define RETURN_SUCCESS    0 
    #define DEBUG       1 
    // Ant Stuff
    #define MAXMSG       14 // SYNC,LEN,MSG,data[8],CHKSUM
    #define CHAN0      0
    #define CHAN1      1
    #define NET0      0
    #define NET1      1
    #define TIMEOUT   10 //mikec  30
    
    #define BAUD   4800   // Sparkfun ANT Default Baud
    
    //#define FREQ      0x41;   // Suunto radio frequency
    #define FREQ 0x39; //  garmin radio frequency
    //#define PERIOD      0x199a; // Suunto search period
    #define PERIOD      0x1f86; // Garmin search period
    //#define NETWORK_KEY      "B9AD3228757EC74D" // Suunto HRM
    #define NETWORK_KEY      "B9A521FBBD72C345" // Garmin HRM
    
    // Macros
    #define hexval(c) ((c >= '0' && c <= '9') ? (c-'0') : ((c&0xdf)-'A'+10))
    
    #define TRUE                           1
    #define FALSE                          0
    
    #if !defined(NULL)
       #define NULL                        ((void *) 0)
    #endif
    
    #define MAX_UCHAR                      0xFF
    #define MAX_SCHAR                      0x7F
    #define MIN_SCHAR                      0x80
    
    #define MAX_SHORT                      0x7FFF
    #define MIN_SHORT                      0x8000
    #define MAX_USHORT                     0xFFFF
    #define MAX_SSHORT                     0x7FFF
    #define MIN_SSHORT                     0x8000
    
    #define MAX_LONG                       0x7FFFFFFF
    #define MIN_LONG                       0x80000000
    #define MAX_ULONG                      0xFFFFFFFF
    #define MAX_SLONG                      0x7FFFFFFF
    #define MIN_SLONG                      0x80000000
    
    // GLOBAL VARIABLES
    ///////////////////
    UCHAR rxBuf[MAXMSG];
    
    
    UCHAR checkSum(UCHAR *data, int length)
    {
       int i;
       UCHAR chksum = data[0]; 
       
       for (i = 1; i < length; i++)
          chksum ^= data[i];  // +1 since skip prefix sync code, we already counted it
       
       return chksum;
    }
    
     
    int hstr2hex(UCHAR *hex, char *hexstr, int size)
    {
       int i;
       
       if ((size % 2) != 0)
       {
          Serial.println("hstr2hex error: input hex string has to be divisible by 2");
          exit(RETURN_ERROR);
       }
    
       for (i=0; i < (size/2); i++)
       {
          hex[i] = hexval(hexstr[i*2])*16 + hexval(hexstr[i*2 + 1]);
       }
       
       return RETURN_SUCCESS;
    }
    
    
    //ANT_send(1+1, MESG_SYSTEM_RESET_ID, 0x00)   
    // Resets module
    void reset (void) 
    {
       uint8_t i;
       uint8_t buf[4];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x01; // LENGTH Byte
       buf[2] = MESG_SYSTEM_RESET_ID; // ID Byte
       buf[3] = 0x00; // Data Byte N (N=LENGTH)
            buf[4] = checkSum(buf,4);
       Serial.print("TX: ");
       for(i = 0 ; i < 5 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
         mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    //ANT_send(1+2, MESG_REQUEST_ID, CHAN0, MESG_CAPABILITIES_ID)
    void assignch(void) 
    {
       uint8_t i;
       uint8_t buf[5];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x02; // LENGTH Byte
       buf[2] = MESG_REQUEST_ID; // ID Byte
       buf[3] = CHAN0; // 
       buf[4] = MESG_CAPABILITIES_ID; // 
            buf[5] = checkSum(buf,5);
       Serial.print("TX: ");
       for(i = 0 ; i < 6 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
         mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    //   ANT_send(1+2, MESG_REQUEST_ID, CHAN0, 0x3D)
    void assignch1(void) 
    {
       uint8_t i;
       uint8_t buf[5];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x02; // LENGTH Byte
       buf[2] = MESG_REQUEST_ID; // ID Byte
       buf[3] = CHAN0; // 
       buf[4] = ((UCHAR)0x3D); // 
            buf[5] = checkSum(buf,5);
       Serial.print("TX: ");
       for(i = 0 ; i < 6 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    //   ANT_send(1+3, MESG_ASSIGN_CHANNEL_ID, CHAN0, 0x00, NET0); // chan, chtype (0=wildcard?), network
    void assignch2(void) 
    {
       uint8_t i;
       uint8_t buf[6];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x03; // LENGTH Byte
       buf[2] = MESG_ASSIGN_CHANNEL_ID; // ID Byte
       buf[3] = CHAN0; 
       buf[4] = ((UCHAR)0x00);  
       buf[5] = NET0;  
            buf[6] = checkSum(buf,6);
       Serial.print("TX: ");
       for(i = 0 ; i < 7 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    //   ANT_send(1+5, MESG_CHANNEL_ID_ID, CHAN0, 0x00, 0x00, 0x00, 0x00); // chan, devno (2byte) (0=wildcard) (little-endian), devtype (0=wildcard), manid (0=wildcard));
    void assignch3(void) 
    {
       uint8_t i;
       uint8_t buf[8];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x05; // LENGTH Byte
       buf[2] = MESG_CHANNEL_ID_ID; // ID Byte
       buf[3] = CHAN0; 
       buf[4] = ((UCHAR)0x00);  
       buf[5] = ((UCHAR)0x00);  
       buf[6] = ((UCHAR)0x00);  
       buf[7] = ((UCHAR)0x00);  
            buf[8] = checkSum(buf,8);
       Serial.print("TX: ");
       for(i = 0 ; i < 9 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    // MESG_NETWORK_KEY_ID, net1, GARMIN_KEY 
    //   buf[0] = MESG_NETWORK_KEY_ID;   
    //   buf[1] = NET0;
    //   hstr2hex(&buf[2], NETWORK_KEY, 16);  // dest, orig, size            
    //   ANT_sendStr(1+9, buf);
    void assignch4(void) 
    {
       uint8_t i;
       uint8_t buf[12];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x09; // LENGTH Byte
       buf[2] = MESG_NETWORK_KEY_ID; // ID Byte
       buf[3] = NET0; 
            hstr2hex(&buf[4], NETWORK_KEY, 16);  // dest, orig, size
    //mikec        hstr2hex(&buf[2], NETWORK_KEY, 16);  // dest, orig, size
       buf[12] = checkSum(buf,12);
       Serial.print("TX: ");
       for(i = 0 ; i < 13 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    //ANT_send(1+2, MESG_CHANNEL_SEARCH_TIMEOUT_ID, CHAN0, TIMEOUT);    //   MESG_CHANNEL_SEARCH_TIMEOUT_ID, chan, timeout);   
    void timeout(void) 
    {
       uint8_t i;
       uint8_t buf[5];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x02; // LENGTH Byte
       buf[2] = MESG_CHANNEL_SEARCH_TIMEOUT_ID; // ID Byte
       buf[3] = CHAN0; 
       buf[4] = TIMEOUT;  
            buf[5] = checkSum(buf,5);
       Serial.print("TX: ");
       for(i = 0 ; i < 6 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    //ANT_send(1+2, MESG_CHANNEL_RADIO_FREQ_ID, CHAN0, FREQ);    
    void frequency(void) 
    {
       uint8_t i;
       uint8_t buf[5];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x02; // LENGTH Byte
       buf[2] = MESG_CHANNEL_RADIO_FREQ_ID; // ID Byte
       buf[3] = CHAN0; 
       buf[4] = FREQ;  
            buf[5] = checkSum(buf,5);
       Serial.print("TX: ");
       for(i = 0 ; i < 6 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    //ANT_send(1+3, MESG_CHANNEL_MESG_PERIOD_ID, CHAN0, PERIOD%256, PERIOD/256); // NOTE: Period = Little-endian
    void channel_period(void) 
    {
       uint8_t i;
       uint8_t buf[6];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x03; // LENGTH Byte
       buf[2] = MESG_CHANNEL_MESG_PERIOD_ID; // ID Byte
       buf[3] = CHAN0; 
       buf[4] = 0x1f; //mikec   buf[4] = 0x9A;  
       buf[5] = 0x86; //mikec   buf[5] = 0x19;  //   6554 = 25*256 + 154; 25=0x19; 154 = 0x9A
            buf[6] = checkSum(buf,6);
       Serial.print("TX: ");
       for(i = 0 ; i < 7 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
       mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    //ANT_send(1+1, MESG_OPEN_CHANNEL_ID, CHAN0);   // MESG_OPEN_CHANNEL_ID, chan 
    void open_channel(void) 
    {
       uint8_t i;
       uint8_t buf[4];
       
       buf[0] = MESG_TX_SYNC; // SYNC Byte
       buf[1] = 0x01; // LENGTH Byte
       buf[2] = MESG_OPEN_CHANNEL_ID; // ID Byte
       buf[3] = CHAN0; 
            buf[4] = checkSum(buf,4);
       Serial.print("TX: ");
       for(i = 0 ; i < 5 ; i++)
       {
         Serial.print(buf[i], HEX);
         Serial.print(" ");
         mySerial.print(buf[i]);
       }
       Serial.println("");
    }
    
    
    void config (void)
    {
       Serial.println("Config Starting");
    
            reset(); 
       delay(100);
             assignch(); 
       delay(1000);
             assignch1(); 
       delay(100);
             assignch2(); 
       delay(100);
             assignch3();
       delay(100);
             assignch4(); 
       delay(20);
             timeout(); 
       delay(20);
             frequency(); 
       delay(20);
             channel_period(); 
       delay(20);
             open_channel(); 
       delay(20);
            Serial.println("Config Done");
    }
    
    
    
    int ANT_rxHandler()
    {
       int n, fd, rc, inmsg = FALSE;
       UCHAR chr, msgN;
       
       while (mySerial.available()>0) 
       {
          chr = mySerial.read();
          
          if (chr == -1)
          {
             Serial.println("Unknown error has occured");
          }
          else
          {
             if ((chr == MESG_TX_SYNC) && (inmsg == FALSE))
             {
                msgN = 0; // Always reset msg count if we get a sync
                inmsg = TRUE;
             
                rxBuf[msgN] = chr; // second byte will be msg size
                msgN++;            
                Serial.println("RX: [sync]");           
             }
             else if (msgN == 1)
             {
                rxBuf[msgN] = chr; // second byte will be msg siz
                msgN++;
    //            Serial.print("..0x");
    //            Serial.print(chr,HEX);
             }
             else if (msgN == 2)
             {
                rxBuf[msgN] = chr;
                msgN++;
    //            Serial.print("..0x");
    //            Serial.print(chr,HEX);
             }
             else if (msgN < rxBuf[1]+3) // sync, size, checksum x 1 byte
             {            
                rxBuf[msgN] = chr;
                msgN++;            
    //            Serial.print("..0x");
    //            Serial.print(chr,HEX);
             }
             else
             {
                inmsg = FALSE;
                rxBuf[msgN] = chr;
    //            Serial.print("..0x");
    //            Serial.println(chr,HEX);
                
                if (checkSum(rxBuf, msgN) == rxBuf[msgN]) // Check if chksum = msg chksu
                {            
    //               Serial.print("RX: msg received-");
    //                         Serial.println(msgN);   
                                            ANT_rxMsg();
                }
                else
                {
                   Serial.println("RX: chksum mismatch");
                }
             }
          }
             
          
       }
       
    }
    
    
    int ANT_rxMsg()
    {
       //int i;
       UCHAR msgID, msgSize;
       UCHAR *msgData;
       
       // copy args
    //   memcpy(rxBuf, args, sizeof(UCHAR) * MAXMSG);
    
       msgID = rxBuf[2];
       msgSize = rxBuf[1];
       msgData = &rxBuf[3];
    
       switch (msgID)
       {
          case MESG_RESPONSE_EVENT_ID :    
             break;
          case MESG_CAPABILITIES_ID   :    
             break;
    
          case MESG_BROADCAST_DATA_ID :   
             Serial.print("Heartrate is ");
             Serial.println(msgData[msgSize-1], DEC);
             break;
                                  
          default                  :   Serial.println("ID: Unknown msgID");
          
       }
    }
    
    
    
    void setup()  {
      // define pin modes for tx, rx, led pins:
    //  pinMode(rxPin, INPUT);
    //  pinMode(txPin, OUTPUT);
      pinMode(ledPin, OUTPUT);
      // set the data rate for the SoftwareSerial port
      mySerial.begin(BAUD);
      Serial.begin(9600);
      config();
    }
    
    void loop()
    {
    ANT_rxHandler();
    }
    

    Hi

    Great work!! Will be very valuable!

    Do you by any chance know if the Suunto ant+ equiped belt would work in a similar way? To me it seems that it should be basically be “the same” code but i have heard something about coded signals etc. that would differ between garmin and sunto heart belts…

    Thanks in adance

    It’s my impression that you would comment out the 3 Garmin lines of code, and uncomment the 3 Suunto lines. But I haven’t tried it…

    Ok thanks, yes seems plausible. The reason asking is because it is not totally clear ifsuunto uses ant or ant+, ant is code locked and not ant+ if I understood it correctly . which specific heart belt modell of garmin did you use?

    I have a HRM1G chest strap which came with my forerunner.

    Someone earlier in this thread said that it should work fine with the Suunto. I also think that there was another thread in these forums by a Suunto user – it might be the one that I pulled most of this code from. I forget exactly.

    Good luck.

    Ok thanks again! Just here trying it out right now with my new suunto watch/belt. Was some months since i used my arduino last time here so will take some hours to get upp to date again with it :slight_smile: I assume you made rc pin 2, tx pin 3 and that rts is led pin 13… I do get some messages from the ant chip actually but I want to ask how you managed to run the command avaviable in the software serial? According to the compiler and the arduino reference code you should not be able to do a availiable call with software serial?! How did you managed this?

    int ANT_rxHandler()

    {

    int n, fd, rc, inmsg = FALSE;

    UCHAR chr, msgN;

    while (mySerial.available()>0)

    Thanks in advance…

    mikecapito:
    I have a HRM1G chest strap which came with my forerunner.

    Someone earlier in this thread said that it should work fine with the Suunto. I also think that there was another thread in these forums by a Suunto user – it might be the one that I pulled most of this code from. I forget exactly.

    Good luck.

    Hmm. I suppose I left out a key part. I used the “NewSoftSerial” libraries from http://arduiniana.org/libraries/newsoftserial/

    Also, for the record, I didn’t use the RTS pin on the antenna board. Things worked without it.

    Aha ok ok, then i get it :slight_smile: The program is compiling with out any errors but i get no contact after the config with the ant reciver when running it or any error messages from it so i guess it will need some reverse enginnering. Find that strange however as there should be no difference from a arduini mini to the big uno one and I should see some rx or tx error messages in the serial monitor i fellt when running your code out from the box with switch frequencecies and wearing the hr belt…

    I will need to put in some more work, for sure some super small problem :slight_smile:

    Some ideas:

  • Make sure it’s a 3.3V Arduino. The standard ones are most likely too high voltage for the antenna, and definitely won’t recognize the 3v responses from the antenna.

    Make sure that TX from the antenna goes to RX on the Arduino, and vice versa.

    Make sure you’re wearing the heartrate monitor. I checked on the watch to make sure it was sending stuff.

  • Many thanks Mike!

    Yes, it turned out I had connected it just wrong :slight_smile: I do use an arduino pro mini 3v now but I found out it worked pretty ok even with a uno 5v if you put a voltage divider on the IO lines, ofcourse 5 v on the vcd to the chip would fry it :slight_smile:

    I had some time to crack what really was saying in the main code given by dev here. I did not get straight away what was said in the message id in hex. I figured out from older code given here and some spreadsheet thinking that suunto belt is acutally sending mainly the beat times RR, atleast i did not see where the watch was seending the average hear rate in the ant message id (but yet again, I am a nowieb on this :slight_smile: ). So the message id of the suunto actually contains beat times, each beat time is send three times, I guess this is as I read elsewere a way to make sure that the beat reach the reciver even if there is some “traffic” lost so you will find the same beat time in three message id after eachother rolling so to say. So to calculate the beat time you use the two first message bytes in the message id after all the first id etc bytes, byte1byte2256=milliseconds, then you just wait for the next message id and calulate the time again (the time is given continous, and max out at about 64000ms and the restarts from zero again) and the just substract the previous beat time and you get a RR time, then just divide 60/RR and you are given the hear rate. My code is really basically the same as given by mikecapito above, just make sure to change to the suunto period, freq and key and also change in the void channel period the values of buf 4 and 5 to buf[4] = 0x9A; buf[5] = 0x19, this is calcualted according to the manual and also stated in the code above given for suunto ant.

    Many thanks to all!

    Message id example

    //in sync =first byte /////MsgNr = 6 byte /////Byte1= 7 byte //////Byte2 =8 byte

    0xA4 0x9 0x4E 0x0 0x1F 0x93 0x67 0x24 0x23 0x1F 0xF0 0x1B 0xFB //hex

    164 9 78 0 31 147 103 36 35 31 240 27 251 //DEC

    0xA4 0x9 0x4E 0x0 0x1F 0x94 0x39 0x28 0x67 0x24 0x23 0x1F 0x6

    164 9 78 0 31 148 57 40 103 36 35 31 6