Ant

module
Extended With
Loggability

This is an extension for using the ANT ultra-low power wireless protocol via the Garmin USB ANT Stick. ANT can be used to send information wirelessly from one device to another device, in a robust and flexible manner.

Constants

EXT_PARAM_ASYNC_TRANSMIT
EXT_PARAM_BACKGROUND_SCANNING
EXT_PARAM_FAST_CHANNEL_INIT
REVISION

Version control revision

VALID_CHANNEL_PERIODS

The default range of frequencies for the channel period

VALID_DEVICE_NUMBERS

A Range for matching valid ANT device numbers

VALID_DEVICE_TYPES

A Range for matching valid ANT device types (6 least signficant bits)

VALID_RF_FREQUENCIES

The valid offsets for the “RF Frequency” setting; this is an offset from 2400Hz.

VERSION

Package version

Public Class Methods

anchor
assign_channel( channel, channel_type, network_number=0, extended_options=0x0, timeout=0 ) → channel

Assign a channel and return an Ant::Channel object for it. Channel assignment reserves a channel number and assigns the type and network number to the channel. The optional extended assignment byte allows for the following features to be enabled:

EXT_PARAM_FREQUENCY_AGILITY

enable frequency agility

EXT_PARAM_BACKGROUND_SCANNING

enable background scanning

EXT_PARAM_FAST_CHANNEL_INIT

enable fast channel initiation

EXT_PARAM_ASYNC_TRANSMIT

enable asynchronous transmission

static VALUE
rant_s_assign_channel( int argc, VALUE *argv, VALUE _module )
{
    unsigned char ucChannel,
        ucChannelType,
        ucNetworkNumber = 0,
        ucExtend = 0,
        ulResponseTime = 0;
    VALUE channel,
        channel_type,
        network_number,
        extended_options,
        timeout;
    VALUE args[4];

    rb_scan_args( argc, argv, "23", &channel, &channel_type, &network_number, &extended_options, &timeout );

    ucChannel = NUM2CHR( channel );
    ucChannelType = NUM2CHR( channel_type );

    if ( RTEST(network_number) ) {
        ucNetworkNumber = NUM2CHR( network_number );
    }
    if ( RTEST(extended_options) ) {
        ucExtend = NUM2CHR( extended_options );
    }
    if ( RTEST(timeout) ) {
        ulResponseTime = NUM2CHR( timeout );
    }

    if ( !ANT_AssignChannelExt_RTO(ucChannel, ucChannelType, ucNetworkNumber, ucExtend, ulResponseTime) ) {
        rb_raise( rb_eRuntimeError, "Couldn't assign channel %d", ucChannel );
    }

    rant_log( "info", "Assigned channel %d (0x%02x) to network %d {0x%02x}.",
        ucChannel, ucChannelType, ucNetworkNumber, ucExtend );

    args[0] = channel;
    args[1] = channel_type;
    args[2] = network_number;
    args[3] = extended_options;

    return rb_class_new_instance( 4, args, rant_cAntChannel );
}
anchor
close

Close the USB connection to the ANT module.

static VALUE
rant_s_close( VALUE _module )
{
    ANT_Close();

    rant_channel_clear_registry();

    return Qtrue;
}
anchor
device_serial_number → integer

Returns the serial number of the ANT device; not implemented on all devices.

static VALUE
rant_s_device_serial_number( VALUE _module )
{
#ifdef HAVE_ANT_GETDEVICESERIALNUMBER
    const unsigned long serial = ANT_GetDeviceSerialNumber();
    return LONG2FIX( serial );
#else
    rb_notimplement();
#endif
}
anchor
device_usb_info( device_num ) → [ product_string, serial_string ]

Get the product and serial info of the USB device device_num.

static VALUE
rant_s_device_usb_info( VALUE _module, VALUE device_num )
{
    const unsigned short deviceNum = NUM2SHORT( device_num );
    unsigned char product_string[256];
    unsigned char serial_string[256];
    VALUE rval = rb_ary_new2( 2 );

    if ( !ANT_GetDeviceUSBInfo( (unsigned char)deviceNum, product_string, serial_string ) ) {
        return Qnil;
    }

    rant_log_obj( _module, "debug", "Got product string = %s, serial string = %s", product_string, serial_string );
    rb_ary_push( rval, rb_str_new_cstr((const char *)product_string) );
    rb_ary_push( rval, rb_str_new_cstr((const char *)serial_string) );

    return rval;
}
anchor
device_usb_pid → integer

Returns the pid of the USB device.

static VALUE
rant_s_device_usb_pid( VALUE _module )
{
    unsigned short pid;

    if ( !ANT_GetDeviceUSBPID(&pid) ) {
        rb_sys_fail( "Fetching the USB PID." );
    }

    return INT2FIX( pid );
}
anchor
device_usb_vid → integer

Returns the vid of the USB device.

static VALUE
rant_s_device_usb_vid( VALUE _module )
{
    unsigned short vid;

    if ( !ANT_GetDeviceUSBVID(&vid) ) {
        rb_sys_fail( "Fetching the USB VID." );
    }

    return INT2FIX( vid );
}
anchor
init( device_num=0, baud_rate=57600 ) → true

Initialize the ANT library and connect to the ANT module. The device_num is the USB device number of the module to connect to, defaulting to 0. Modules connected to a PC will be assigned USB device numbers starting from 0. N is the number of USB ANT devices that are connected. The baud_rate is the asynchronous baud rate used to connect to the ANT controller. See specific ANT controllers for allowable baud rates.

static VALUE
rant_s_init( int argc, VALUE *argv, VALUE _module )
{
    VALUE device_num = Qnil, baud_rate = Qnil;
    unsigned char ucUSBDeviceNum;
    unsigned int ulBaudrate;

    rb_scan_args( argc, argv, "02", &device_num, &baud_rate );

    if ( RTEST(device_num) ) {
        ucUSBDeviceNum = NUM2CHR( device_num );
    } else {
        ucUSBDeviceNum = 0;
    }

    if ( RTEST(baud_rate) ) {
        ulBaudrate = NUM2UINT( baud_rate );
    } else {
        ulBaudrate = DEFAULT_BAUDRATE;
    }

    rant_log_obj( rant_mAnt, "info", "Initializing ANT device %d at %d baud", ucUSBDeviceNum, ulBaudrate );
    if ( !ANT_Init(ucUSBDeviceNum, ulBaudrate) ) {
        rb_raise( rb_eRuntimeError, "Initializing the ANT library (no ANT device present?)." );
    }

    return Qtrue;
}
anchor
lib_version → int

Return the version of the underlying libant.

static VALUE
rant_s_lib_version( VALUE _module )
{
    const char *version = ANT_LibVersion();

    return rb_str_new_cstr( version );
}
anchor
log_directory = "path/to/log/dir"

Write debugging logs to the specified directory, which should already exist.

static VALUE
rant_s_log_directory_eq( VALUE _module, VALUE directory )
{
    const char *directory_s = StringValueCStr( directory );
    bool rval = ANT_SetDebugLogDirectory( (char *)directory_s );

    return rval ? Qtrue : Qfalse;
}
anchor
on_response {|channel, response_msg_id| ... }

Sets the response callback. The callback is called whenever a response message is received from ANT. See set_response_handlers for a set of default handlers.

static VALUE
rant_s_on_response( int argc, VALUE *argv, VALUE module )
{
    VALUE callback = Qnil;

    rb_scan_args( argc, argv, "0&", &callback );

    if ( !RTEST(callback) ) {
        rb_raise( rb_eLocalJumpError, "block required, but not given" );
    }

    rant_log( "debug", "Callback is: %s", RSTRING_PTR(rb_inspect(callback)) );
    rb_ivar_set( module, response_callback_ivar, callback );

    ANT_AssignResponseFunction( rant_on_response_callback, pucResponseBuffer );

    return Qtrue;
}
anchor
reset

Reset the system and put it in a known, low-power state. Execution of this command terminates all channels. All information previously configured in the system can no longer be considered valid.

static VALUE
rant_s_reset( VALUE _module )
{
    const struct timeval wait_time = {
        .tv_sec = 0,
        .tv_usec = 500,
    };
    ANT_ResetSystem();

    rant_channel_clear_registry();

    // After a Reset System command has been issued, the application should wait
    // 500ms to ensure that ANT is in the proper, “after-reset” state before any
    // further commands are issued from the host.
    rb_thread_wait_for( wait_time );

    return Qtrue;
}
anchor
set_network_key( network_num, network_key )

Configures a network address for use by one of the available network numbers.

static VALUE
rant_s_set_network_key( VALUE _module, VALUE network_number, VALUE key )
{
    const unsigned short ucNetNumber = NUM2USHORT( network_number );
    const char *pucKey = StringValuePtr( key );

    if ( RSTRING_LEN(key) != 8 ) {
        rb_raise( rb_eArgError, "expected an 8-byte key" );
    }

    if ( !ANT_SetNetworkKey(ucNetNumber, (unsigned char *)pucKey) ) {
        rb_raise( rb_eRuntimeError, "could not set the network key." );
    }

    return Qtrue;
}
anchor
set_response_handlers( mod=Ant::ResponseCallbacks )

Set up the given mod as the handler module for response callbacks. You can create your own handler module and extend with the default Ant::ResponseCallbacks.

# File lib/ant.rb, line 46
def self::set_response_handlers( mod=Ant::ResponseCallbacks )
    self.extend( mod )
    self.on_response( &self.method(:handle_response_callback) )
end
anchor
use_extended_messages = true or false

Enable or disable extended Rx messages. If the device supports it, when ANT will include the channel ID with the data message.

static VALUE
rant_s_use_extended_messages_eq( VALUE _module, VALUE true_false )
{
    // This is documented as an unsigned char and then explicitly cast
    // to a signed char. So this just uses their typedef.
    const BOOL ucEnable = RTEST( true_false ) ? TRUE : FALSE;

    rant_log( "info", "%s extended messages.", ucEnable ? "Enabling" : "Disabling" );
    ANT_RxExtMesgsEnable( ucEnable );

    return Qtrue;
}
anchor
validate_channel_period( frequency )

Check that specified frequency is a valid channel period and raise an appropriate exception if it isn't. Returns the frequency as an Integer if it is valid.

# File lib/ant.rb, line 83
def self::validate_channel_period( frequency )
    frequency = Integer( frequency )
    unless VALID_CHANNEL_PERIODS.include?( frequency )
        raise RangeError, "invalid channel period; expected a frequency between %d and %d, got %p" %
            [ VALID_CHANNEL_PERIODS.begin, VALID_CHANNEL_PERIODS.end, frequency ]
    end

    return frequency
end
anchor
validate_device_number( number )

Check that specified number is a valid device number and raise an appropriate exception if it isn't. Returns the number as an Integer if it is valid.

# File lib/ant.rb, line 55
def self::validate_device_number( number )
    number = Integer( number )
    unless VALID_DEVICE_NUMBERS.include?( number )
        raise RangeError, "invalid device number; expected a number between %d and %d, got %p" %
            [ VALID_DEVICE_NUMBERS.begin, VALID_DEVICE_NUMBERS.end, number ]
    end

    return number
end
anchor
validate_device_type( number )

Check that specified number is a valid device type and raise an appropriate exception if it isn't. Returns the number as an Integer if it is valid.

# File lib/ant.rb, line 69
def self::validate_device_type( number )
    number = Integer( number )
    unless VALID_DEVICE_TYPES.include?( number )
        raise RangeError, "invalid device type; expected a number between %d and %d, got %p" %
            [ VALID_DEVICE_TYPES.begin, VALID_DEVICE_TYPES.end, number ]
    end

    return number
end
anchor
validate_network_key( data )

Check that specified data is a valid ANT network key and raise an appropriate exception if it isn't. Returns the key itself if it is valid.

# File lib/ant.rb, line 111
def self::validate_network_key( data )
    data = data.to_s
    unless data.bytesize == 8
        raise RangeError, "invalid network key; expected exactly eight bytes, got %d" %
            [ data.bytesize ]
    end

    self.log.debug "Validated network key: %p" % [ data ]
    return data
end
anchor
validate_network_number( number )

Check that specified number is a valid ANT network number and raise an appropriate exception if it isn't. Note that this does not check the local device(s) to ensure they support the given network. Returns the key as an Integer if it is valid.

# File lib/ant.rb, line 98
def self::validate_network_number( number )
    number = Integer( number )
    unless number >= 0 && number <= 255
        raise RangeError, "invalid network number; expected an eight-bit number, got %p" %
            [ number ]
    end

    return number
end
anchor
validate_rf_frequency( offset )

Check that specified offset is a valid “rf frequency” and raise an appropriate exception if it isn't. Returns the offset as an Integer if it is valid.

# File lib/ant.rb, line 126
def self::validate_rf_frequency( offset )
    offset = Integer( offset )
    unless VALID_RF_FREQUENCIES.include?( offset )
        raise RangeError, "invalid RF Frequency; expected a offset between %d and %d, got %p" %
            [ VALID_RF_FREQUENCIES.begin, VALID_RF_FREQUENCIES.end, offset ]
    end

    return offset
end