From e9866f8522f902c8bb1b0a6d9f29610ff1b299a7 Mon Sep 17 00:00:00 2001 From: mathalaxy Date: Sun, 9 Feb 2020 02:08:55 +0100 Subject: [PATCH] Added support for Linear Poti, Line, and Piezo Speaker 2.0 Bricklets --- .gitignore | 1 + shard.yml | 4 +- src/bindings/bricklets/line.cr | 58 +++++++ src/bindings/bricklets/linear_poti.cr | 43 ++++++ src/bindings/bricklets/piezo_speaker_v2.cr | 167 +++++++++++++++++++++ src/bindings/bricks/silent_stepper.cr | 31 +++- src/bricklets/line.cr | 115 ++++++++++++++ src/bricklets/linear_poti.cr | 70 +++++++++ src/bricklets/piezo_speaker_v2.cr | 85 +++++++++++ src/bricklets/rotary_poti.cr | 2 +- src/bricks/silent_stepper.cr | 135 ++++++++++++++++- src/staple.cr | 2 +- src/tinkerforge.cr | 6 + 13 files changed, 706 insertions(+), 13 deletions(-) create mode 100644 src/bindings/bricklets/line.cr create mode 100644 src/bindings/bricklets/linear_poti.cr create mode 100644 src/bindings/bricklets/piezo_speaker_v2.cr create mode 100644 src/bricklets/line.cr create mode 100644 src/bricklets/linear_poti.cr create mode 100644 src/bricklets/piezo_speaker_v2.cr diff --git a/.gitignore b/.gitignore index 73837c2..61fb312 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /test.cr +/dl/ /obj/ /docs/ /lib/ diff --git a/shard.yml b/shard.yml index 0a97d89..12158c0 100644 --- a/shard.yml +++ b/shard.yml @@ -10,5 +10,5 @@ license: MIT repository: https://github.com/mathalaxy/tinkerforge documentation: https://mathalaxy.github.io/tinkerforge/ -scripts: - postinstall: mkdir -p dl obj && cd dl && curl -o tf.zip "https://download.tinkerforge.com/bindings/c/tinkerforge_c_bindings_2_1_26.zip" && unzip -uq tf.zip source/* && cd source && make && cd ../.. && cp dl/source/*.o obj +# scripts: +# postinstall: mkdir -p dl/source obj && cd dl && curl -o tf.zip "https://download.tinkerforge.com/bindings/c/tinkerforge_c_bindings_2_1_27.zip" && unzip -uq tf.zip source/* && cd source && make && cd ../.. && cp dl/source/*.o obj diff --git a/src/bindings/bricklets/line.cr b/src/bindings/bricklets/line.cr new file mode 100644 index 0000000..98b6e2f --- /dev/null +++ b/src/bindings/bricklets/line.cr @@ -0,0 +1,58 @@ +@[Link( + ldflags: "#{__DIR__}/../../../obj/bricklet_line.o" + )] + +lib LibTF + alias Line = Entity + + # Creates the device object \c line with the unique device ID \c uid and adds + # it to the IPConnection \c ipcon. + fun line_create( + line : Line*, + uid : LibC::Char*, + ipcon : IPConnection* + ) : Void + + # Removes the device object \c line from its IPConnection and destroys it. + # The device object cannot be used anymore afterwards. + fun line_destroy( + line : Line* + ) : Void + + # Returns the currently measured reflectivity. The reflectivity is a value between 0 (not reflective) and 4095 (very reflective). + # + # Usually black has a low reflectivity while white has a high reflectivity. + # + # If you want to get the reflectivity periodically, it is recommended to use the LINE_CALLBACK_REFLECTIVITY callback and set the period with line_set_reflectivity_callback_period(). + fun line_get_reflectivity( + line : Line*, + ret_reflectivity : Int16* + ) : LibC::Int + + LINE_CALLBACK_REFLECTIVITY = 8 + LINE_CALLBACK_REFLECTIVITY_REACHED = 9 + + fun line_register_callback( + line : Line*, + callback_id : Int16, + function : Void*, + user_data : Void* + ) : Void + + fun line_set_reflectivity_callback_period( + line : Line*, + period : UInt32 + ) : LibC::Int + + fun line_set_reflectivity_callback_threshold( + line : Line*, + option : LibC::Char, + min : UInt16, + max : UInt16 + ) : LibC::Int + + fun line_set_debounce_period( + line : Line*, + debounce : UInt32 + ) : LibC::Int +end diff --git a/src/bindings/bricklets/linear_poti.cr b/src/bindings/bricklets/linear_poti.cr new file mode 100644 index 0000000..ef816f6 --- /dev/null +++ b/src/bindings/bricklets/linear_poti.cr @@ -0,0 +1,43 @@ +@[Link( + ldflags: "#{__DIR__}/../../../obj/bricklet_linear_poti.o" + )] + +lib LibTF + alias LinearPoti = Entity + + # Creates the device object \c linear_poti with the unique device ID \c uid and adds + # it to the IPConnection \c ipcon. + fun linear_poti_create( + linear_poti : LinearPoti*, + uid : LibC::Char*, + ipcon : IPConnection* + ) : Void + + # Removes the device object \c linear_poti from its IPConnection and destroys it. + # The device object cannot be used anymore afterwards. + fun linear_poti_destroy( + linear_poti : LinearPoti* + ) : Void + + # Returns the position of the linear potentiometer. The value is between 0 (slider down) and 100 (slider up). + # + # If you want to get the position periodically, it is recommended to use the {@link LINEAR_POTI_CALLBACK_POSITION} callback and set the period with {@link linear_poti_set_position_callback_period}. + fun linear_poti_get_position( + linear_poti : LinearPoti*, + ret_position : Int16* + ) : LibC::Int + + fun linear_poti_set_position_callback_period( + linear_poti : LinearPoti*, + period : UInt32 + ) : LibC::Int + + LINEAR_POTI_CALLBACK_POSITION = 13 + + fun linear_poti_register_callback( + linear_poti : LinearPoti*, + callback_id : Int16, + function : Void*, + user_data : Void* + ) : Void +end diff --git a/src/bindings/bricklets/piezo_speaker_v2.cr b/src/bindings/bricklets/piezo_speaker_v2.cr new file mode 100644 index 0000000..2ef58b0 --- /dev/null +++ b/src/bindings/bricklets/piezo_speaker_v2.cr @@ -0,0 +1,167 @@ +@[Link( + ldflags: "#{__DIR__}/../../../obj/bricklet_piezo_speaker_v2.o" + )] + +lib LibTF + alias PiezoSpeakerV2 = Entity + + # Creates the device object \c piezo_speaker_v2 with the unique device ID \c uid and adds + # it to the IPConnection \c ipcon. + fun piezo_speaker_v2_create( + piezo_speaker_v2 : PiezoSpeakerV2*, + uid : LibC::Char*, + ipcon : IPConnection* + ) : Void + + # Removes the device object \c piezo_speaker_v2 from its IPConnection and destroys it. + # The device object cannot be used anymore afterwards. + fun piezo_speaker_v2_destroy( + piezo_speaker_v2 : PiezoSpeakerV2* + ) : Void + + PIEZO_SPEAKER_V2_BEEP_DURATION_OFF = 0 + PIEZO_SPEAKER_V2_BEEP_DURATION_INFINITE = 4294967295 + + # Beeps with the given frequency and volume for the duration. + # + # A duration of 0 stops the current beep if any is ongoing. A duration of 4294967295 results in an infinite beep. + # + # The following constants are available for this function: + # + # For duration: + # + # PIEZO_SPEAKER_V2_BEEP_DURATION_OFF = 0 + # PIEZO_SPEAKER_V2_BEEP_DURATION_INFINITE = 4294967295 + fun piezo_speaker_v2_set_beep( + piezo_speaker_v2 : PiezoSpeakerV2*, + frequency : UInt16, + volume : UInt8, + duration : UInt32 + ) : LibC::Int + + # Returns the last beep settings as set by piezo_speaker_v2_set_beep(). If a beep is currently running it also returns the remaining duration of the beep. + # + # If the frequency or volume is updated during a beep (with piezo_speaker_v2_update_frequency() or piezo_speaker_v2_update_volume()) this function returns the updated value. + # + # The following constants are available for this function: + # + # For ret_duration: + # + # PIEZO_SPEAKER_V2_BEEP_DURATION_OFF = 0 + # PIEZO_SPEAKER_V2_BEEP_DURATION_INFINITE = 4294967295 + fun piezo_speaker_v2_get_beep( + piezo_speaker_v2 : PiezoSpeakerV2*, + ret_frequency : UInt16*, + ret_volume : UInt8*, + ret_duration : UInt32*, + ret_duration_remaining : UInt32* + ) : LibC::Int + + PIEZO_SPEAKER_V2_ALARM_DURATION_OFF = 0 + PIEZO_SPEAKER_V2_ALARM_DURATION_INFINITE = 4294967295 + + # Creates an alarm (a tone that goes back and force between two specified frequencies). + # + # The following parameters can be set: + # + # Start Frequency: Start frequency of the alarm. + # End Frequency: End frequency of the alarm. + # Step Size: Size of one step of the sweep between the start/end frequencies. + # Step Delay: Delay between two steps (duration of time that one tone is used in a sweep). + # Duration: Duration of the alarm. + # + # A duration of 0 stops the current alarm if any is ongoing. A duration of 4294967295 results in an infinite alarm. + # + # Below you can find two sets of example settings that you can try out. You can use these as a starting point to find an alarm signal that suits your application. + # + # Example 1: 10 seconds of loud annoying fast alarm + # + # Start Frequency = 800 + # End Frequency = 2000 + # Step Size = 10 + # Step Delay = 1 + # Volume = 10 + # Duration = 10000 + # + # Example 2: 10 seconds of soft siren sound with slow build-up + # + # Start Frequency = 250 + # End Frequency = 750 + # Step Size = 1 + # Step Delay = 5 + # Volume = 0 + # Duration = 10000 + # + # The following conditions must be met: + # + # Start Frequency: has to be smaller than end frequency + # End Frequency: has to be bigger than start frequency + # Step Size: has to be small enough to fit into the frequency range + # Step Delay: has to be small enough to fit into the duration + # + # The following constants are available for this function: + # + # For duration: + # + # PIEZO_SPEAKER_V2_ALARM_DURATION_OFF = 0 + # PIEZO_SPEAKER_V2_ALARM_DURATION_INFINITE = 4294967295 + fun piezo_speaker_v2_set_alarm( + piezo_speaker_v2 : PiezoSpeakerV2*, + start_frequency : UInt16, + end_frequency : UInt16, + step_size : UInt16, + step_delay : UInt16, + volume : UInt8, + duration : UInt32 + ) : LibC::Int + + # Returns the last alarm settings as set by piezo_speaker_v2_set_alarm(). If an alarm is currently running it also returns the remaining duration of the alarm as well as the current frequency of the alarm. + # + # If the volume is updated during an alarm (with piezo_speaker_v2_update_volume()) this function returns the updated value. + # + # The following constants are available for this function: + # + # For ret_duration: + # + # PIEZO_SPEAKER_V2_ALARM_DURATION_OFF = 0 + # PIEZO_SPEAKER_V2_ALARM_DURATION_INFINITE = 4294967295 + # + # For ret_duration_remaining: + # + # PIEZO_SPEAKER_V2_ALARM_DURATION_OFF = 0 + # PIEZO_SPEAKER_V2_ALARM_DURATION_INFINITE = 4294967295 + fun piezo_speaker_v2_get_alarm( + piezo_speaker_v2 : PiezoSpeakerV2*, + ret_start_frequency : UInt16*, + ret_end_frequency : UInt16*, + ret_step_size : UInt16*, + ret_step_delay : UInt16*, + ret_volume : UInt8*, + ret_duration : UInt32*, + ret_duration_remaining : UInt32*, + ret_current_frequency : UInt16* + ) : LibC::Int + + # Updates the volume of an ongoing beep or alarm. + fun piezo_speaker_v2_update_volume( + piezo_speaker_v2 : PiezoSpeakerV2*, + volume : UInt8 + ) : LibC::Int + + # Updates the frequency of an ongoing beep. + fun piezo_speaker_v2_update_frequency( + piezo_speaker_v2 : PiezoSpeakerV2*, + frequency : UInt16 + ) : LibC::Int + + + PIEZO_SPEAKER_V2_STATUS_LED_CONFIG_OFF = 0u8 + PIEZO_SPEAKER_V2_STATUS_LED_CONFIG_ON = 1u8 + PIEZO_SPEAKER_V2_STATUS_LED_CONFIG_SHOW_HEARTBEAT = 2u8 + PIEZO_SPEAKER_V2_STATUS_LED_CONFIG_SHOW_STATUS = 3u8 + + fun piezo_speaker_v2_set_status_led_config( + piezo_speaker_v2 : PiezoSpeakerV2*, + config : UInt8 + ) : LibC::Int +end diff --git a/src/bindings/bricks/silent_stepper.cr b/src/bindings/bricks/silent_stepper.cr index cd35e78..c279afd 100644 --- a/src/bindings/bricks/silent_stepper.cr +++ b/src/bindings/bricks/silent_stepper.cr @@ -4,7 +4,7 @@ lib LibTF alias SilentStepper = Entity - + # Creates the device object \c silent_stepper with the unique device ID \c uid and adds # it to the IPConnection \c ipcon. fun silent_stepper_create( @@ -116,6 +116,10 @@ lib LibTF silent_stepper : SilentStepper* ) : LibC::Int + fun silent_stepper_reset( + silent_stepper : SilentStepper* + ) : LibC::Int + SILENT_STEPPER_STEP_RESOLUTION_1 = 8 SILENT_STEPPER_STEP_RESOLUTION_2 = 7 SILENT_STEPPER_STEP_RESOLUTION_4 = 6 @@ -125,4 +129,29 @@ lib LibTF SILENT_STEPPER_STEP_RESOLUTION_64 = 2 SILENT_STEPPER_STEP_RESOLUTION_128 = 1 SILENT_STEPPER_STEP_RESOLUTION_256 = 0 + + SILENT_STEPPER_CALLBACK_UNDER_VOLTAGE = 40 + SILENT_STEPPER_CALLBACK_POSITION_REACHED = 41 + SILENT_STEPPER_CALLBACK_ALL_DATA = 47 + SILENT_STEPPER_CALLBACK_NEW_STATE = 48 + + fun silent_stepper_register_callback( + silent_stepper : SilentStepper*, + callback_id : Int16, + function : Void*, + user_data : Void* + ) : Void + + SILENT_STEPPER_STATE_STOP = 1 + SILENT_STEPPER_STATE_ACCELERATION = 2 + SILENT_STEPPER_STATE_RUN = 3 + SILENT_STEPPER_STATE_DEACCELERATION = 4 + SILENT_STEPPER_STATE_DIRECTION_CHANGE_TO_FORWARD = 5 + SILENT_STEPPER_STATE_DIRECTION_CHANGE_TO_BACKWARD = 6 + + fun silent_stepper_set_all_data_period( + silent_stepper : SilentStepper*, + period : UInt32 + ) : LibC::Int + end diff --git a/src/bricklets/line.cr b/src/bricklets/line.cr new file mode 100644 index 0000000..69d95f2 --- /dev/null +++ b/src/bricklets/line.cr @@ -0,0 +1,115 @@ +enum Is : UInt8 + Ignored = 120 + Within = 105 + Without = 111 + LowerThan = 60 + HigherThan = 62 +end + +module TF + + # A [Line Bricklet](https://www.tinkerforge.com/doc/Hardware/Bricklets/Line.html). + # + # ![Line Bricklet](https://www.tinkerforge.com/en/doc/_images/Bricklets/bricklet_line_tilted_800.jpg) + class LineBricklet < Bricklet + include RegularCallback + + DEVICE_ID = 241 + + # ======================================================================================= + # Class variables + # ======================================================================================= + + @@reached_callback_pointers = {} of UInt64 => Void* + + # ======================================================================================= + # Instance variables + # ======================================================================================= + + @reflectivity = 0u16 + + # ======================================================================================= + # Callbacks + # ======================================================================================= + + # :nodoc: + def cb_reflectivity(reflectivity) + @reflectivity = reflectivity + end + + # ======================================================================================= + # Data access mode + # ======================================================================================= + + getter regular_callback_interval = Time::Span.zero + + def regular_callback_interval=(value : Time::Span) + @regular_callback_interval = value + + if value.zero? + @@callback_pointers.delete object_id + LibTF.line_set_reflectivity_callback_period ptr, 0u32 + else + boxed = Box.box(->cb_reflectivity(UInt16)) + + LibTF.line_register_callback( + ptr, LibTF::LINE_CALLBACK_REFLECTIVITY, + Proc(UInt16, Void*, Void).new do |reflectivity, user_data| + unboxed = Box(Proc(UInt16, Void)).unbox(user_data) + unboxed.call(reflectivity) + end.pointer, + boxed \ + ) + + @@callback_pointers[object_id] = boxed + LibTF.line_set_reflectivity_callback_period ptr, value.total_milliseconds.to_u32 + end + end + + # ======================================================================================= + # Data access + # ======================================================================================= + + # Returns the currently measured reflectivity. The reflectivity is a value between 0 (not reflective) and 4095 (very reflective). + # + # Usually black has a low reflectivity while white has a high reflectivity. + def reflectivity + if @regular_callback_interval.zero? + LibTF.line_get_reflectivity ptr, out refl + refl + else + @reflectivity + end + end + + # ======================================================================================= + # Register an event callback + # ======================================================================================= + + def when_reflectivity(is : Is, reference : Int | Range, debounce = 100, &block : UInt16 ->) + if is.ignored? + @@reached_callback_pointers.delete object_id + LibTF.line_set_reflectivity_callback_threshold ptr, is.value, 0, 0 + else + boxed = Box.box(block) + LibTF.line_register_callback( + ptr, LibTF::LINE_CALLBACK_REFLECTIVITY_REACHED, + Proc(UInt16, Void*, Void).new do |reflectivity, user_data| + unboxed = Box(Proc(UInt16, Void)).unbox(user_data) + unboxed.call(reflectivity) + end.pointer, + boxed \ + ) + + @@reached_callback_pointers[object_id] = boxed + min, max = case reference + when Range then {reference.begin, reference.end} + else {reference, 0} + end + + LibTF.line_set_reflectivity_callback_threshold ptr, is.value, min, max + LibTF.line_set_debounce_period ptr, debounce + end + end + end +end diff --git a/src/bricklets/linear_poti.cr b/src/bricklets/linear_poti.cr new file mode 100644 index 0000000..d0387ad --- /dev/null +++ b/src/bricklets/linear_poti.cr @@ -0,0 +1,70 @@ +module TF + + # A [Linear Poti Bricklet](https://www.tinkerforge.com/doc/Hardware/Bricklets/Linear_Poti.html). + # + # ![Linear Poti Bricklet](https://www.tinkerforge.com/en/doc/_images/Bricklets/bricklet_linear_poti_tilted_800.jpg) + class LinearPotiBricklet < Bricklet + include RegularCallback + + DEVICE_ID = 213 + + # ======================================================================================= + # Instance variables + # ======================================================================================= + + @position = 0u16 + + # ======================================================================================= + # Callbacks + # ======================================================================================= + + # :nodoc: + def cb_position(position) + @position = position + end + + # ======================================================================================= + # Data access mode + # ======================================================================================= + + getter regular_callback_interval = Time::Span.zero + + def regular_callback_interval=(value : Time::Span) + @regular_callback_interval = value + + if value.zero? + @@callback_pointers.delete object_id + LibTF.linear_poti_set_position_callback_period ptr, 0u32 + else + boxed = Box.box(->cb_position(UInt16)) + + LibTF.linear_poti_register_callback( + ptr, LibTF::LINEAR_POTI_CALLBACK_POSITION, + Proc(UInt16, Void*, Void).new do |position, user_data| + instance = Box(Proc(UInt16, Void)).unbox(user_data) + instance.call(position) + end.pointer, + boxed \ + ) + + @@callback_pointers[object_id] = boxed + LibTF.linear_poti_set_position_callback_period ptr, value.total_milliseconds.to_u32 + end + end + + # ======================================================================================= + # Data access + # ======================================================================================= + + # Returns the currently selected position on the poti in percents. + # Positions are returned as integer values in the range `0..100`. + def position + if @regular_callback_interval.zero? + LibTF.linear_poti_get_position ptr, out pos + pos.to_i32 + else + @position.to_i32 + end + end + end +end diff --git a/src/bricklets/piezo_speaker_v2.cr b/src/bricklets/piezo_speaker_v2.cr new file mode 100644 index 0000000..043f39c --- /dev/null +++ b/src/bricklets/piezo_speaker_v2.cr @@ -0,0 +1,85 @@ +module TF + + # A [Piezo Speaker 2.0 Bricklet](https://www.tinkerforge.com/doc/Hardware/Bricklets/PiezoSpeakerV2.html). + # + # ![Piezo Speaker 2.0 Bricklet](https://www.tinkerforge.com/en/doc/_images/Bricklets/bricklet_piezo_speaker_v2_tilted_800.jpg) + class PiezoSpeakerV2Bricklet < Bricklet + DEVICE_ID = 2145 + + # ======================================================================================= + # Beeps + # ======================================================================================= + + # Stops the current beep if any is ongoing. + def stop_beep + LibTF.piezo_speaker_v2_set_beep ptr, 0, 0, LibTF::PIEZO_SPEAKER_V2_BEEP_DURATION_OFF + end + + # Beeps with the given *frequency* and *volume*, optionally only for some *duration*. + # The *volume* must be an integer between 0 (off) and 10 (very loud). + # The *frequency* must be an integer between 50 Hertz and 15_000 Hertz. + # If *duration* is left out, the beep will continue indefinitely until `#stop_beep` is called. + def beep(frequency, volume = 5, duration : Time::Span? = nil) + dur = if duration + duration.total_milliseconds.to_u32 + else + LibTF::PIEZO_SPEAKER_V2_BEEP_DURATION_INFINITE + end + LibTF.piezo_speaker_v2_set_beep ptr, frequency, volume, dur + end + + # ======================================================================================= + # Alarms + # ======================================================================================= + + # Stops the current alarm if any is ongoing. + def stop_alarm + LibTF.piezo_speaker_v2_set_alarm ptr, 50, 100, 10, 10, 0, LibTF::PIEZO_SPEAKER_V2_ALARM_DURATION_OFF + end + + # Sets an alarm that traverses a *frequency_range* with given *step_size*, *step_delay*, and *volume* – optionally only some *duration*. + # If *duration* is left out, the alarm will continue indefinitely until `#stop_alarm` is called. + def set_alarm(frequency_range : Range, step_size, step_delay, volume = 5, duration : Time::Span? = nil) + dur = if duration + duration.total_milliseconds.to_u32 + else + LibTF::PIEZO_SPEAKER_V2_ALARM_DURATION_INFINITE + end + LibTF.piezo_speaker_v2_set_alarm ptr, frequency_range.begin, frequency_range.end, step_size, step_delay, volume, dur + end + + # ======================================================================================= + # Update functions + # ======================================================================================= + + # Updates the volume of an ongoing beep or alarm. + # The value must be an integer between 0 (off) and 10 (very loud). + def volume=(value) + LibTF.piezo_speaker_v2_update_volume ptr, value + end + + # Updates the frequency of an ongoing beep. + # The value must be an integer between 50 Hertz and 15_000 Hertz. + def frequency=(value) + LibTF.piezo_speaker_v2_update_frequency ptr, value + end + + # ======================================================================================= + # Status LED + # ======================================================================================= + + enum LEDMode : UInt8 + Off = 0 + On = 1 + Heartbeat = 2 + Status = 3 + end + + getter led_mode = LEDMode::Status + def led_mode=(mode : LEDMode) + @led_mode = mode + LibTF.piezo_speaker_v2_set_status_led_config ptr, mode.value + end + + end +end diff --git a/src/bricklets/rotary_poti.cr b/src/bricklets/rotary_poti.cr index 095c4a5..ac0d429 100644 --- a/src/bricklets/rotary_poti.cr +++ b/src/bricklets/rotary_poti.cr @@ -11,7 +11,7 @@ module TF # ======================================================================================= # Returns the currently selected position on the poti in degrees. - # Positions are returned as integer values in the range `-150.. 150`. + # Positions are returned as integer values in the range `-150..150`. def position LibTF.rotary_poti_get_position ptr, out pos pos diff --git a/src/bricks/silent_stepper.cr b/src/bricks/silent_stepper.cr index 214fe54..3b85533 100644 --- a/src/bricks/silent_stepper.cr +++ b/src/bricks/silent_stepper.cr @@ -4,17 +4,97 @@ module TF # # ![Silent Stepper Brick](https://www.tinkerforge.com/doc/_images/Bricks/brick_silent_stepper_tilted_800.jpg) class SilentStepperBrick < Brick + include RegularCallback + DEVICE_ID = 19 + # ======================================================================================= + # Enums + # ======================================================================================= + + enum StepResolution : UInt8 + Full = 8 + Half = 7 + One4th = 6 + One8th = 5 + One16th = 4 + One32th = 3 + One64th = 2 + One128th = 1 + One256th = 0 + end + + # enum State : UInt8 + # Stop = 1 + # Acceleration = 2 + # Run = 3 + # Deacceleration = 4 + # DirectionChangeToForward = 5 + # DirectionChangeToBackward = 6 + # end + # + # @current_state : State? = nil + # + # def current_state : State + # if @current_state.nil? + # boxed_self = Box.box(self) + # + # LibTF.silent_stepper_register_callback( + # ptr, + # LibTF::SILENT_STEPPER_CALLBACK_NEW_STATE, + # Proc(UInt8, UInt8, Void*, Void).new do |state_new, state_previous, user_data| + # instance = Box(self).unbox(user_data).as(SilentStepperBrick) + # instance.new_state(state_new, state_previous) + # end.pointer, + # boxed_self \ + # ) + # + # @@boxed_self = boxed_self + # + # State::Stop + # else + # @current_state.not_nil! + # end + # end + # + # + # # :nodoc: + # def new_state(state_new, state_previous) + # @current_state = State.new(state_new) + # end + + # ======================================================================================= + # Properties + # ======================================================================================= + + def step_resolution=(step_res : StepResolution) + LibTF.silent_stepper_set_step_configuration ptr, step_res.value, 1 + end + + # ======================================================================================= + # Instance variables + # ======================================================================================= + + @current_velocity = 0 + + # ======================================================================================= + # Callbacks + # ======================================================================================= + + # :nodoc: + def all_data(current_velocity, current_position, remaining_steps, stack_voltage, external_voltage, current_consumption) + @current_velocity = current_velocity.to_i32 + end + # ======================================================================================= # Constructor / destructor # ======================================================================================= - # Constructor is automatically generated + # Constructor is auto-generated def finalize - # Make sure the stepper has been stopped before loosing contact - LibTF.silent_stepper_stop ptr + # Make sure the stepper has stopped/reset before loosing contact + LibTF.silent_stepper_reset ptr LibTF.silent_stepper_destroy ptr end @@ -36,13 +116,48 @@ module TF # Returns `true` if the driver is enabled, and `false` otherwise. def enabled? LibTF.silent_stepper_is_enabled ptr, out enabled - (enabled != 0) + (enabled == 0) + end + + # ======================================================================================= + # Data access mode + # ======================================================================================= + + getter regular_callback_interval = Time::Span.zero + + def regular_callback_interval=(value : Time::Span) + @regular_callback_interval = value + + if value.zero? + @@callback_pointers.delete object_id + LibTF.silent_stepper_set_all_data_period ptr, 0u32 + else + boxed = Box.box(->all_data(UInt16, Int32, Int32, UInt16, UInt16, UInt16)) + + LibTF.silent_stepper_register_callback( + ptr, LibTF::SILENT_STEPPER_CALLBACK_ALL_DATA, + Proc(UInt16, Int32, Int32, UInt16, UInt16, UInt16, Void*, Void).new \ + do |current_velocity, current_position, remaining_steps, stack_voltage, external_voltage, current_consumption, user_data| + unboxed = Box(Proc(UInt16, Int32, Int32, UInt16, UInt16, UInt16, Void)).unbox(user_data) + unboxed.call(current_velocity, current_position, remaining_steps, stack_voltage, external_voltage, current_consumption) + end.pointer, + boxed \ + ) + + @@callback_pointers[object_id] = boxed + LibTF.silent_stepper_set_all_data_period ptr, value.total_milliseconds.to_u32 + end end # ======================================================================================= # Basic configuration # ======================================================================================= + # Resets the stepper motor. + def reset + LibTF.silent_stepper_reset ptr + end + # Returns the acceleration of the stepper motor in steps per s². # The default value is 1000 steps/s². def acceleration @@ -77,20 +192,24 @@ module TF # Returns the current velocity of the stepper motor in steps per second. def current_velocity - LibTF.silent_stepper_get_current_velocity ptr, out value - value + if @regular_callback_interval.zero? + LibTF.silent_stepper_get_current_velocity ptr, out value + value.to_i32 + else + @current_velocity + end end # Sets the maximal velocity of the stepper motor in steps per second. def max_velocity=(value) - LibTF.silent_stepper_set_max_velocity ptr, value + LibTF.silent_stepper_set_max_velocity ptr, value.to_u16 value end # Returns the maximal velocity of the stepper motor in steps per second. def max_velocity LibTF.silent_stepper_get_max_velocity ptr, out value - value + value.to_i32 end # ======================================================================================= diff --git a/src/staple.cr b/src/staple.cr index dab4e71..4cd0ee6 100644 --- a/src/staple.cr +++ b/src/staple.cr @@ -20,7 +20,7 @@ module TF class Staple < Entity {% begin %} - {% supported = [:RotaryPotiBricklet, :SilentStepperBrick, :MasterBrick] %} + {% supported = [:MasterBrick, :SilentStepperBrick, :RotaryPotiBricklet, :LinearPotiBricklet, :LineBricklet, :PiezoSpeakerV2Bricklet ] %} # ======================================================================================= # Class variables diff --git a/src/tinkerforge.cr b/src/tinkerforge.cr index a10a000..4db5574 100644 --- a/src/tinkerforge.cr +++ b/src/tinkerforge.cr @@ -48,6 +48,12 @@ module TF # A TinkerForge [bricklet](https://www.tinkerforge.com/doc/Primer.html#primer-bricklets). class Bricklet < Device end + + module RegularCallback + macro included + @@callback_pointers = {} of UInt64 => Void* + end + end end require "./**"