ant-wireless 0.1.0.pre.20210715102740 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 60051597c316ed311fb5c3203f5903e62f46e107c2094ae379db5dbf07c8232e
4
- data.tar.gz: 41a4cc508416234557867b3fd0ac8c27c5d856cea90c7531fb99f29106028ec8
3
+ metadata.gz: abd16b62c0eb3b3e7e683fd46cca0382fa6b0400f23d8ae8a12de4455e66599a
4
+ data.tar.gz: c0e7b0571d2cb8285f072b23027b226ac4c472e0b2147faa34c1bd13d4c78aef
5
5
  SHA512:
6
- metadata.gz: 22d0cf3c237e478f41ed217a67ce07a13e1dea8584142bee797fa7085cbf5e24445758cba5b2d29f7ca2ea50f973e20bb231e6579c50647bf286bb94e935f144
7
- data.tar.gz: 3ce7d04e91583044385715746750f9bfd83dcbd06831a0e38f8c123f57e05fd778c6eaf13e5f9a6d770e85156c8406f7c195eab637a620dc6b5fa99f66ff829f
6
+ metadata.gz: 994058a2faa922f5d5469b9ab04aa5eecefaa6fdac4921a035a9bfe4f0ca58bea90a32f225c54d695f93b5cc27bcaf87ce2442b80160984944e7a04234eb0036
7
+ data.tar.gz: 11f91861b51651d3cfba2309334ac4e9253a4ea9bc313bd0434f42eaa4a86e05d3659b11cfed13a85b162761b1913afb2da13d99faf58f1b14cf53b52fb03da3
checksums.yaml.gz.sig ADDED
Binary file
data/History.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Release History for ruby-ant
2
2
 
3
3
  ---
4
+ ## v0.2.1 [2021-09-30] Michael Granger <ged@FaerieMUD.org>
4
5
 
6
+ Bugfixes:
7
+
8
+ - Add missing files to the manifest
9
+
10
+
11
+
12
+ ## v0.2.0 [2021-09-22] Michael Granger <ged@FaerieMUD.org>
13
+
14
+ Enhancements:
15
+
16
+ - Add channel period, search timeout, and introspection methods
17
+ - Add Ant.initialized? predicate
18
+ - Make the default response and event callback modules more useful.
19
+
20
+
21
+ ## v0.1.0 [2021-08-26] Michael Granger <ged@FaerieMUD.org>
22
+
23
+ First release.
5
24
 
data/README.md CHANGED
@@ -20,8 +20,13 @@ manner.
20
20
 
21
21
  ## Prerequisites
22
22
 
23
- * Ruby
24
- * Garmin USB ANT Stick (https://buy.garmin.com/en-US/US/p/10997/pn/010-01058-00)
23
+ * Ruby 2.7.x or later
24
+ * [Garmin USB ANT Stick][antstick]
25
+ * [ANT SDK][antsdk]
26
+
27
+ Note that we had trouble compiling the latest ANT SDK on some platforms, so we are currently using a modified version of it with a reworked build system for MacOS and FreeBSD. That is available under the same licensing terms at:
28
+
29
+ https://github.com/RavnGroup/Garmin-ANT-SDK
25
30
 
26
31
 
27
32
  ## Installation
@@ -52,6 +57,12 @@ This task will install dependencies, and do any other necessary setup for develo
52
57
 
53
58
  ## License
54
59
 
60
+ Portions of this code are from StaticCling, and are used under the
61
+ terms of the 3-Clause BSD License. Specifics can be found in the
62
+ appropriate files.
63
+
64
+ This software is:
65
+
55
66
  Copyright (c) 2021, Ravn Group
56
67
 
57
68
  Permission is hereby granted, free of charge, to any person obtaining
@@ -76,4 +87,5 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
76
87
 
77
88
  [ant]: https://www.thisisant.com/
78
89
  [antstick]: https://buy.garmin.com/en-US/US/p/10997/pn/010-01058-00
90
+ [antsdk]: https://www.thisisant.com/developer/resources/downloads/#software_tab
79
91
 
@@ -225,6 +225,17 @@ rant_s_init( int argc, VALUE *argv, VALUE _module )
225
225
  }
226
226
 
227
227
 
228
+ static VALUE
229
+ rant_s_initialized_p( VALUE _module )
230
+ {
231
+ #ifdef HAVE_ANT_ISINITIALIZED
232
+ const bool initialized = ANT_IsInitialized();
233
+ return initialized ? Qtrue : Qfalse;
234
+ #else
235
+ rb_notimplement();
236
+ #endif
237
+ }
238
+
228
239
 
229
240
  /*
230
241
  * call-seq:
@@ -291,7 +302,7 @@ rant_s_set_network_key( VALUE _module, VALUE network_number, VALUE key )
291
302
  }
292
303
 
293
304
  if ( !ANT_SetNetworkKey(ucNetNumber, (unsigned char *)pucKey) ) {
294
- rb_raise( rb_eRuntimeError, "could not set the network key." );
305
+ rant_log( "error", "could not set the network key." );
295
306
  }
296
307
 
297
308
  return Qtrue;
@@ -463,6 +474,56 @@ rant_s_on_response( int argc, VALUE *argv, VALUE module )
463
474
  }
464
475
 
465
476
 
477
+ /*
478
+ * call-seq:
479
+ * Ant.request_capabilities
480
+ *
481
+ * Request the current ANT device's capabilities. These will be delivered
482
+ * via a callback to the #on_capabilities response callback, which by default
483
+ * extracts them into a Hash which is stored at Ant.capabilities.
484
+ *
485
+ */
486
+ static VALUE
487
+ rant_s_request_capabilities( VALUE module )
488
+ {
489
+ bool rval = ANT_RequestMessage( 0, MESG_CAPABILITIES_ID );
490
+ return rval ? Qtrue : Qfalse;
491
+ }
492
+
493
+
494
+ /*
495
+ * call-seq:
496
+ * Ant.request_serial_num
497
+ *
498
+ * Request the current ANT device's serial number. The result will be delivered
499
+ * via a callback to the #on_get_serial_num response callback, which by default
500
+ * extracts it and stores it at Ant.serial_number.
501
+ *
502
+ */
503
+ static VALUE
504
+ rant_s_request_serial_num( VALUE module )
505
+ {
506
+ bool rval = ANT_RequestMessage( 0, MESG_GET_SERIAL_NUM_ID );
507
+ return rval ? Qtrue : Qfalse;
508
+ }
509
+
510
+
511
+ /*
512
+ * call-seq:
513
+ * Ant.request_version
514
+ *
515
+ * Request the current device's ANT version. The result will be delivered
516
+ * via a callback to the #on_version response callback, which by default
517
+ * extracts it and stores it at Ant.hardware_version.
518
+ *
519
+ */
520
+ static VALUE
521
+ rant_s_request_version( VALUE module )
522
+ {
523
+ bool rval = ANT_RequestMessage( 0, MESG_VERSION_ID );
524
+ return rval ? Qtrue : Qfalse;
525
+ }
526
+
466
527
 
467
528
  /*
468
529
  * call-seq:
@@ -490,7 +551,7 @@ Init_ant_ext()
490
551
  /*
491
552
  * Document-module: Ant
492
553
  *
493
- * This is an extension for using the ANT ultra-low power wireless protocol via
554
+ * This is an extension for using the ANT ultra-low power wireless protocol via
494
555
  * the Garmin USB ANT Stick. ANT can be used to send information
495
556
  * wirelessly from one device to another device, in a robust and flexible
496
557
  * manner.
@@ -508,6 +569,7 @@ Init_ant_ext()
508
569
  rb_define_singleton_method( rant_mAnt, "device_serial_number", rant_s_device_serial_number, 0 );
509
570
 
510
571
  rb_define_singleton_method( rant_mAnt, "init", rant_s_init, -1 );
572
+ rb_define_singleton_method( rant_mAnt, "initialized?", rant_s_initialized_p, 0 );
511
573
  // rb_define_singleton_method( rant_mAnt, "init_ext", rant_s_init_ext, 4 );
512
574
  rb_define_singleton_method( rant_mAnt, "close", rant_s_close, 0 );
513
575
  rb_define_singleton_method( rant_mAnt, "reset", rant_s_reset, 0 );
@@ -521,6 +583,9 @@ Init_ant_ext()
521
583
  rb_define_singleton_method( rant_mAnt, "on_response", rant_s_on_response, -1 );
522
584
  // EXPORT void ANT_UnassignAllResponseFunctions(); //Unassigns all response functions
523
585
 
586
+ rb_define_singleton_method( rant_mAnt, "request_capabilities", rant_s_request_capabilities, 0 );
587
+ rb_define_singleton_method( rant_mAnt, "request_serial_num", rant_s_request_serial_num, 0 );
588
+ rb_define_singleton_method( rant_mAnt, "request_version", rant_s_request_version, 0 );
524
589
 
525
590
  rb_define_singleton_method( rant_mAnt, "log_directory=", rant_s_log_directory_eq, 1 );
526
591
 
@@ -537,6 +602,7 @@ Init_ant_ext()
537
602
  EXPOSE_CONST( ANT_EXT_STRING_SIZE );
538
603
  EXPOSE_CONST( ANT_EXT_MESG_BITFIELD_DEVICE_ID );
539
604
  EXPOSE_CONST( ANT_EXT_MESG_BIFIELD_EXTENSION );
605
+ rb_define_const( rant_mAnt, "ANT_EXT_MESG_BITFIELD_EXTENSION", INT2FIX(ANT_EXT_MESG_BIFIELD_EXTENSION) );
540
606
  EXPOSE_CONST( ANT_EXT_MESG_BITFIELD_OVERWRITE_SHARED_ADR );
541
607
  EXPOSE_CONST( ANT_EXT_MESG_BITFIELD_TRANSMISSION_TYPE );
542
608
 
@@ -618,6 +684,9 @@ Init_ant_ext()
618
684
  EXPOSE_CONST( CAPABILITIES_SELECTIVE_DATA_UPDATE_ENABLED );
619
685
  EXPOSE_CONST( CAPABILITIES_ENCRYPTED_CHANNEL_ENABLED );
620
686
 
687
+ // Not in the header; this is taken from 9.5.7.4, ANT Message Protocol and Usage v5.1
688
+ rb_define_const( rant_mAnt, "CAPABILITIES_RFACTIVE_NOTIFICATION_ENABLED", INT2FIX(0) );
689
+
621
690
  EXPOSE_CONST( CHANNEL_NUMBER_MASK );
622
691
  EXPOSE_CONST( SEQUENCE_NUMBER_MASK );
623
692
  EXPOSE_CONST( SEQUENCE_NUMBER_ROLLOVER );
@@ -128,6 +128,11 @@ rant_channel_init( VALUE self, VALUE channel_number, VALUE channel_type, VALUE n
128
128
  rb_iv_set( self, "@network_number", network_number );
129
129
  rb_iv_set( self, "@extended_options", extended_options );
130
130
 
131
+ rb_iv_set( self, "@device_type", Qnil );
132
+ rb_iv_set( self, "@device_number", Qnil );
133
+ rb_iv_set( self, "@transmission_type", Qnil );
134
+ rb_iv_set( self, "@rf_frequency", Qnil );
135
+
131
136
  rb_hash_aset( registry, channel_number, self );
132
137
 
133
138
  return self;
@@ -173,8 +178,8 @@ rant_channel_set_channel_id( int argc, VALUE *argv, VALUE self )
173
178
  rb_scan_args( argc, argv, "31", &device_number, &device_type, &transmission_type, &timeout );
174
179
 
175
180
  usDeviceNumber = NUM2USHORT( device_number );
176
- ucDeviceType = NUM2USHORT( device_type );
177
- ucTransmissionType = NUM2USHORT( transmission_type );
181
+ ucDeviceType = NUM2CHR( device_type );
182
+ ucTransmissionType = NUM2CHR( transmission_type );
178
183
 
179
184
  if ( RTEST(timeout) )
180
185
  ulResponseTime = NUM2UINT( timeout );
@@ -186,13 +191,114 @@ rant_channel_set_channel_id( int argc, VALUE *argv, VALUE self )
186
191
  rb_raise( rb_eRuntimeError, "Failed to set the channel id." );
187
192
  }
188
193
 
194
+ rb_iv_set( self, "@device_type", device_type );
195
+ rb_iv_set( self, "@device_number", device_number );
196
+ rb_iv_set( self, "@transmission_type", transmission_type );
197
+
198
+ return Qtrue;
199
+ }
200
+
201
+
202
+ /*
203
+ * call-seq:
204
+ * channel.set_channel_period( period, timeout=0 )
205
+ *
206
+ * This message configures the messaging +period+ of a specific channel where:
207
+ * Messaging period = channel period time +period+ * 32768.
208
+ *
209
+ * E.g.: To send or receive a message at 4Hz, set the channel period to 8192 (32768/4).
210
+ *
211
+ * Note: The minimum acceptable channel period is difficult to specify as it is
212
+ * system dependent and depends on the number of configured channels and their use.
213
+ * Caution should be used to appropriately test the system when high data rates are
214
+ * used, especially in combination with multiple channels.
215
+ *
216
+ */
217
+ static VALUE
218
+ rant_channel_set_channel_period( int argc, VALUE *argv, VALUE self )
219
+ {
220
+ rant_channel_t *ptr = rant_get_channel( self );
221
+ VALUE period, timeout;
222
+ unsigned int ulResponseTime = 0;
223
+ unsigned short usMesgPeriod;
224
+ bool result;
225
+
226
+ rb_scan_args( argc, argv, "11", &period, &timeout );
227
+
228
+ usMesgPeriod = NUM2USHORT( period );
229
+ if ( RTEST(timeout) )
230
+ ulResponseTime = NUM2UINT( timeout );
231
+
232
+ result = ANT_SetChannelPeriod_RTO( ptr->channel_num, usMesgPeriod, ulResponseTime );
233
+
234
+ if ( !result )
235
+ rb_raise( rb_eRuntimeError, "Failed to set the channel period." );
236
+
237
+ return Qtrue;
238
+ }
239
+
240
+
241
+ /*
242
+ * call-seq:
243
+ * channel.set_channel_search_timeout( search_timeout, timeout=0 )
244
+ *
245
+ * Configure the length of time that the receiver will search for a channel
246
+ * before timing out. Note that a value of zero will disable high priority
247
+ * search mode, and a value of 255 sets an infinite search time-out. The
248
+ * exception to this is the AP1 module, which has only a high priority search
249
+ * mode. For AP1 only, a value of 0 is an immediate search timeout, and a value
250
+ * of 255 corresponds to approximately 10.5 minutes.
251
+ *
252
+ */
253
+ static VALUE
254
+ rant_channel_set_channel_search_timeout( int argc, VALUE *argv, VALUE self )
255
+ {
256
+ rant_channel_t *ptr = rant_get_channel( self );
257
+ VALUE search_timeout, timeout;
258
+ unsigned int ulResponseTime = 0;
259
+ unsigned char ucSearchTimeout;
260
+ bool result;
261
+
262
+ rb_scan_args( argc, argv, "11", &search_timeout, &timeout );
263
+
264
+ ucSearchTimeout = NUM2CHR( search_timeout );
265
+ if ( RTEST(timeout) )
266
+ ulResponseTime = NUM2UINT( timeout );
267
+
268
+ result = ANT_SetChannelSearchTimeout_RTO( ptr->channel_num, ucSearchTimeout, ulResponseTime );
269
+
270
+ if ( !result )
271
+ rb_raise( rb_eRuntimeError, "Failed to set the channel search timeout." );
272
+
273
+ return Qtrue;
274
+ }
275
+
276
+
277
+ /*
278
+ * call-seq:
279
+ * channel.set_channel_rf_freq( frequency )
280
+ *
281
+ * Set the ANT RF +frequency+.
282
+ *
283
+ */
284
+ static VALUE
285
+ rant_channel_set_channel_rf_freq( VALUE self, VALUE frequency )
286
+ {
287
+ rant_channel_t *ptr = rant_get_channel( self );
288
+ unsigned short ucRFFreq = NUM2USHORT( frequency );
289
+
290
+ if ( ucRFFreq > 124 ) {
291
+ rb_raise( rb_eArgError, "frequency must be between 0 and 124." );
292
+ }
293
+
294
+ ANT_SetChannelRFFreq( ptr->channel_num, ucRFFreq );
295
+
296
+ rb_iv_set( self, "@rf_frequency", frequency );
297
+
189
298
  return Qtrue;
190
299
  }
191
300
 
192
301
 
193
- // ANT_SetChannelPeriod_RTO(UCHAR ucANTChannel_, USHORT usMesgPeriod_, ULONG ulResponseTime_);
194
- // ANT_SetChannelSearchTimeout_RTO(UCHAR ucANTChannel_, UCHAR ucSearchTimeout_, ULONG ulResponseTime_);
195
- // ANT_SetChannelRFFreq_RTO(UCHAR ucANTChannel_, UCHAR ucRFFreq_, ULONG ulResponseTime_);
196
302
 
197
303
 
198
304
  /*
@@ -450,29 +556,6 @@ rant_channel_send_broadcast_data( VALUE self, VALUE data )
450
556
  }
451
557
 
452
558
 
453
- /*
454
- * call-seq:
455
- * channel.set_channel_rf_freq( frequency )
456
- *
457
- * Set the ANT RF +frequency+.
458
- *
459
- */
460
- static VALUE
461
- rant_channel_set_channel_rf_freq( VALUE self, VALUE frequency )
462
- {
463
- rant_channel_t *ptr = rant_get_channel( self );
464
- unsigned short ucRFFreq = NUM2USHORT( frequency );
465
-
466
- if ( ucRFFreq > 124 ) {
467
- rb_raise( rb_eArgError, "frequency must be between 0 and 124." );
468
- }
469
-
470
- ANT_SetChannelRFFreq( ptr->channel_num, ucRFFreq );
471
-
472
- return Qtrue;
473
- }
474
-
475
-
476
559
  void
477
560
  init_ant_channel()
478
561
  {
@@ -501,11 +584,15 @@ init_ant_channel()
501
584
  rb_attr( rant_cAntChannel, rb_intern("network_number"), 1, 0, 0 );
502
585
  rb_attr( rant_cAntChannel, rb_intern("extended_options"), 1, 0, 0 );
503
586
 
587
+ rb_attr( rant_cAntChannel, rb_intern("device_number"), 1, 0, 0 );
588
+ rb_attr( rant_cAntChannel, rb_intern("device_type"), 1, 0, 0 );
589
+ rb_attr( rant_cAntChannel, rb_intern("transmission_type"), 1, 0, 0 );
590
+ rb_attr( rant_cAntChannel, rb_intern("rf_frequency"), 1, 0, 0 );
591
+
504
592
  rb_define_method( rant_cAntChannel, "set_channel_id", rant_channel_set_channel_id, -1 );
505
- // rb_define_method( rant_cAntChannel, "set_channel_period",
506
- // rant_channel_set_channel_period, -1 );
507
- // rb_define_method( rant_cAntChannel, "set_channel_search_timeout",
508
- // rant_channel_set_channel_search_timeout, -1 );
593
+ rb_define_method( rant_cAntChannel, "set_channel_period", rant_channel_set_channel_period, -1 );
594
+ rb_define_method( rant_cAntChannel, "set_channel_search_timeout",
595
+ rant_channel_set_channel_search_timeout, -1 );
509
596
  rb_define_method( rant_cAntChannel, "set_channel_rf_freq", rant_channel_set_channel_rf_freq, 1 );
510
597
 
511
598
  rb_define_method( rant_cAntChannel, "open", rant_channel_open, -1 );
@@ -14,6 +14,7 @@ have_header( 'ruby/thread.h' ) or
14
14
  abort "Your Ruby is too old!"
15
15
 
16
16
  have_func( 'ANT_Init', 'libant.h' )
17
+ have_func( 'ANT_IsInitialized', 'libant.h' )
17
18
  have_func( 'ANT_LibVersion', 'libant.h' )
18
19
  have_func( 'ANT_GetDeviceSerialNumber', 'libant.h' )
19
20
 
@@ -0,0 +1,197 @@
1
+ # -*- ruby -*-
2
+ # frozen_string_literal: true
3
+ # vim: set nosta noet ts=4 sw=4:
4
+
5
+ require 'ant' unless defined?( Ant )
6
+
7
+ # Ant::BitVector -- a convenience class for manipulating and
8
+ # comparing bit vectors.
9
+ #
10
+ # This is a slightly-modified version of the same utility in StaticCling.
11
+ #
12
+ # == Synopsis
13
+ #
14
+ # require 'ant/bitvector'
15
+ #
16
+ # vector = Ant::BitVector.new
17
+ #
18
+ # vector.on( 4 ) # => 16
19
+ # vector.on( 12 ) # => 4112
20
+ # vector.toggle( 4 ) # => 4096
21
+ # vector.on?( 4 ) # => false
22
+ # vector.size # => 13
23
+ # vector.to_hex # => 0x1000
24
+ #
25
+ # vector2 = Ant::BitVector.new( 5 )
26
+ # vector > vector2 # => true
27
+ #
28
+ # vector2.each_with_index do |bit, i|
29
+ # puts "Bit %d is %s" % [ i + 1, bit.zero? ? 'off' : 'on' ]
30
+ # end
31
+ #
32
+ # Bit 1 is on
33
+ # Bit 2 is off
34
+ # Bit 3 is on
35
+ #
36
+ # == Version
37
+ #
38
+ # $Id$
39
+ #
40
+ # == Author
41
+ #
42
+ # * Mahlon E. Smith <mahlon@martini.nu>
43
+ #
44
+ # == License
45
+ #
46
+ # Copyright (c) 2000-2013, Mahlon E. Smith <mahlon@martini.nu>
47
+ #
48
+ # All rights reserved.
49
+ #
50
+ # Redistribution and use in source and binary forms, with or without
51
+ # modification, are permitted provided that the following conditions are met:
52
+ #
53
+ # * Redistributions of source code must retain the above copyright notice,
54
+ # this list of conditions and the following disclaimer.
55
+ #
56
+ # * Redistributions in binary form must reproduce the above copyright
57
+ # notice, this list of conditions and the following disclaimer in the
58
+ # documentation and/or other materials provided with the distribution.
59
+ #
60
+ # * Neither the name of the author, nor the names of contributors may be
61
+ # used to endorse or promote products derived from this software without
62
+ # specific prior written permission.
63
+ #
64
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
68
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69
+ # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70
+ # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75
+ #
76
+ class Ant::BitVector
77
+ include Enumerable,
78
+ Comparable
79
+
80
+ ### Create a new bit vector object, optionally from a pre-existing
81
+ ### +init+ number (Any number that ruby supports natively should be
82
+ ### fine -- 0b, 0x, or decimal.)
83
+ def initialize( init=0 )
84
+ unless init.respond_to?( :to_i )
85
+ raise ArgumentError, "I don't know what to do with a %s object." % [ init.class.name ]
86
+ end
87
+
88
+ @bv = init.to_i
89
+ end
90
+
91
+
92
+ ######
93
+ public
94
+ ######
95
+
96
+ # let any additional methods fall through to Fixnum/Bignum objs,
97
+ # and return new vector objects. This allows for doing bitwise math
98
+ # or simple addition/subtraction on two BitVector objects.
99
+ %w{ % & * ** + - / << >> ^ | ~ }.each do |op|
100
+ define_method( op.to_sym ) do |arg|
101
+ res = @bv.send( op.to_sym, arg.bv )
102
+ return self.class.new( res )
103
+ end
104
+ end
105
+
106
+
107
+ ##
108
+ # Allow external access to the underlying Fixnum/Bignum
109
+ attr_reader :bv
110
+
111
+
112
+ ### Return the bit vector as a decimal.
113
+ def to_i
114
+ return @bv
115
+ end
116
+ alias_method :to_int, :to_i
117
+ alias_method :to_dec, :to_i
118
+
119
+
120
+ ### Return the bit vector as a binary string.
121
+ def to_bin
122
+ return "0b%s" % @bv.to_s(2)
123
+ end
124
+
125
+
126
+ ### Return the bit vector as a hexidecimal string.
127
+ def to_hex
128
+ return "0x%04x" % @bv
129
+ end
130
+
131
+
132
+ ### Return the length of the vector in bytes.
133
+ def size
134
+ return @bv.to_s(2).length
135
+ end
136
+
137
+
138
+ ### Switch a +bit+ on.
139
+ def on( bit )
140
+ @bv = @bv | ( 1 << bit )
141
+ end
142
+
143
+
144
+ ### Return boolean true if given +bit+ is currently on.
145
+ def on?( bit )
146
+ return @bv[ bit ].zero? ? false : true
147
+ end
148
+ alias_method :[], :on?
149
+
150
+
151
+ ### Switch a +bit+ off.
152
+ def off( bit )
153
+ @bv = @bv & ~( 1 << bit )
154
+ end
155
+
156
+
157
+ ### Return boolean true if given +bit+ is currently +off+.
158
+ def off?( bit )
159
+ return ! self.on?( bit )
160
+ end
161
+
162
+
163
+ ### Swap the current state of the given +bit+.
164
+ def toggle( bit )
165
+ @bv = @bv ^ ( 1 << bit )
166
+ end
167
+ alias_method :flip, :toggle
168
+
169
+
170
+ ### Set a +bit+ to +bool+ -- either true (on) or false (off).
171
+ ### Any value other than nil or false is treated as true.
172
+ ### This form also accepts ranges of bits, a la: vector[ 1..4 ] = true
173
+ def []=( bit, bool )
174
+ if bit.respond_to?( :each )
175
+ bit.each { |b| bool ? self.on( b ) : self.off( b ) }
176
+ else
177
+ bool ? self.on( bit ) : self.off( bit )
178
+ end
179
+ end
180
+
181
+
182
+ ### Yield each binary position, least significant +bit+ first.
183
+ def each
184
+ @bv.to_s(2).reverse.each_byte do |bit|
185
+ yield bit.chr.to_i
186
+ end
187
+ end
188
+
189
+
190
+ ### Comparision operator for Comparable mixin, fallthrough to
191
+ ### Fixnum/Bignum. Compares current state against +cmp+.
192
+ def <=>( cmp )
193
+ @bv <=> cmp.bv
194
+ end
195
+
196
+ end # class Ant::BitVector
197
+