timex_datalink_client 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10adb86fd981a90fa2e764e3dd63bbaf0b1ffa1c37b5210d510ea6aa29b76edb
4
- data.tar.gz: 2d2b67b5b10a8a6bd7bbefd4423e9e7b661a4824649e241df0e4e3ca45e17290
3
+ metadata.gz: 6b3a3f3ffde31a9f937f60f6ebba23851aeacc62d49b5677f7769f7392a9a1ea
4
+ data.tar.gz: 5a9f3acd574998d9bf430225459bb7f98f2954b5e1f6fff038a240145c5ffef5
5
5
  SHA512:
6
- metadata.gz: 3a2fca239d0220cc056a7577ec7b17d1e4e9cf9f2c706af832b38ec0d0eb5522ae4df970369fa7be882eea686fa0da0bb0f063d86f8ce3736ba24c9c0f1acca2
7
- data.tar.gz: 4c8296686c59d03b8da2970cda23c8c525f2376a1d8bca2094c3b44955c37d59625d9cf8e9a8c9545a600421514e584a32e53d52fa537f40af0a035041f140b6
6
+ metadata.gz: 93da0a4e3153cbeb4feaae86574a25034e315d82182833f5b7822796d00cc6d4dbc8f57830bde9e906b6e21471a6829808f0e621b432937314cfefb2090d52f7
7
+ data.tar.gz: b4c516c8b2db51e393b60324ed0d723f00562f34823a6e43c62b07c276b6bfae7edaa9c4f8ab338af6b2fe395afed38729f4e072381d977baef6371c08370802
@@ -4,6 +4,7 @@ class TimexDatalinkClient
4
4
  class Helpers
5
5
  module CharEncoders
6
6
  CHARS = "0123456789abcdefghijklmnopqrstuvwxyz !\"#$%&'()*+,-./:\\;=@?_|<>[]"
7
+ CHARS_PROTOCOL_6 = "0123456789 abcdefghijklmnopqrstuvwxyz!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
7
8
  EEPROM_CHARS = "0123456789abcdefghijklmnopqrstuvwxyz !\"#$%&'()*+,-./:\\;=@?_|<>["
8
9
  PHONE_CHARS = "0123456789cfhpw "
9
10
  INVALID_CHAR = " "
@@ -19,6 +20,10 @@ class TimexDatalinkClient
19
20
  end
20
21
  end
21
22
 
23
+ def protocol_6_chars_for(string_chars, length: nil, pad: false)
24
+ chars_for(string_chars, char_map: CHARS_PROTOCOL_6, length:, pad:)
25
+ end
26
+
22
27
  def eeprom_chars_for(string_chars, length: 31)
23
28
  chars = chars_for(string_chars, char_map: EEPROM_CHARS, length:).append(EEPROM_TERMINATOR)
24
29
 
@@ -24,7 +24,7 @@ class TimexDatalinkClient
24
24
  # Create a TimeName instance.
25
25
  #
26
26
  # @param zone [Integer] Time zone number (1 or 2).
27
- # @param name [String] Name of time zone (3 chars max)
27
+ # @param name [String] Name of time zone (3 chars max).
28
28
  # @return [TimeName] TimeName instance.
29
29
  def initialize(zone:, name:)
30
30
  @zone = zone
@@ -49,8 +49,12 @@ class TimexDatalinkClient
49
49
 
50
50
  private
51
51
 
52
+ def name_formatted
53
+ name || "tz#{zone}"
54
+ end
55
+
52
56
  def name_characters
53
- chars_for(name, length: 3, pad: true)
57
+ chars_for(name_formatted, length: 3, pad: true)
54
58
  end
55
59
  end
56
60
  end
@@ -33,7 +33,7 @@ class TimexDatalinkClient
33
33
  message: "%{value} is invalid! Valid date formats are #{DATE_FORMAT_MAP.keys}."
34
34
  }
35
35
 
36
- attr_accessor :zone, :is_24h, :date_format, :time
36
+ attr_accessor :zone, :is_24h, :date_format, :time, :name
37
37
 
38
38
  # Create a Time instance.
39
39
  #
@@ -42,7 +42,7 @@ class TimexDatalinkClient
42
42
  # @param date_format ["%_m-%d-%y", "%_d-%m-%y", "%y-%m-%d", "%_m.%d.%y", "%_d.%m.%y", "%y.%m.%d"] Date format
43
43
  # (represented by Time#strftime format).
44
44
  # @param time [::Time] Time to set (including time zone).
45
- # @param name [String, nil] Name of time zone (defaults to zone from time; 3 chars max)
45
+ # @param name [String, nil] Name of time zone (defaults to zone from time; 3 chars max).
46
46
  # @return [Time] Time instance.
47
47
  def initialize(zone:, is_24h:, date_format:, time:, name: nil)
48
48
  @zone = zone
@@ -79,12 +79,12 @@ class TimexDatalinkClient
79
79
 
80
80
  private
81
81
 
82
- def name
83
- @name || time.zone.downcase
82
+ def name_formatted
83
+ name || time.zone || "tz#{zone}"
84
84
  end
85
85
 
86
86
  def name_characters
87
- chars_for(name, length: 3, pad: true)
87
+ chars_for(name_formatted, length: 3, pad: true)
88
88
  end
89
89
 
90
90
  def year_mod_1900
@@ -33,7 +33,7 @@ class TimexDatalinkClient
33
33
  message: "%{value} is invalid! Valid date formats are #{DATE_FORMAT_MAP.keys}."
34
34
  }
35
35
 
36
- attr_accessor :zone, :is_24h, :date_format, :time
36
+ attr_accessor :zone, :is_24h, :date_format, :time, :name
37
37
 
38
38
  # Create a Time instance.
39
39
  #
@@ -42,7 +42,7 @@ class TimexDatalinkClient
42
42
  # @param date_format ["%_m-%d-%y", "%_d-%m-%y", "%y-%m-%d", "%_m.%d.%y", "%_d.%m.%y", "%y.%m.%d"] Date format
43
43
  # (represented by Time#strftime format).
44
44
  # @param time [::Time] Time to set (including time zone).
45
- # @param name [String, nil] Name of time zone (defaults to zone from time; 3 chars max)
45
+ # @param name [String, nil] Name of time zone (defaults to zone from time; 3 chars max).
46
46
  # @return [Time] Time instance.
47
47
  def initialize(zone:, is_24h:, date_format:, time:, name: nil)
48
48
  @zone = zone
@@ -79,12 +79,12 @@ class TimexDatalinkClient
79
79
 
80
80
  private
81
81
 
82
- def name
83
- @name || time.zone.downcase
82
+ def name_formatted
83
+ name || time.zone || "tz#{zone}"
84
84
  end
85
85
 
86
86
  def name_characters
87
- chars_for(name, length: 3, pad: true)
87
+ chars_for(name_formatted, length: 3, pad: true)
88
88
  end
89
89
 
90
90
  def year_mod_1900
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ require "timex_datalink_client/helpers/char_encoders"
6
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
7
+
8
+ class TimexDatalinkClient
9
+ class Protocol6
10
+ class Alarm
11
+ include ActiveModel::Validations
12
+ include Helpers::CharEncoders
13
+ prepend Helpers::CrcPacketsWrapper
14
+
15
+ CPACKET_ALARM = 0x51
16
+
17
+ VALID_DAYS_IN_MONTH = {
18
+ 1 => 1..31,
19
+ 2 => 1..29,
20
+ 3 => 1..31,
21
+ 4 => 1..30,
22
+ 5 => 1..31,
23
+ 6 => 1..30,
24
+ 7 => 1..31,
25
+ 8 => 1..31,
26
+ 9 => 1..30,
27
+ 10 => 1..31,
28
+ 11 => 1..30,
29
+ 12 => 1..31
30
+ }.freeze
31
+
32
+ ALARM_STATUS_MAP = {
33
+ disarmed: 0,
34
+ armed: 1,
35
+ unused: 2
36
+ }.freeze
37
+
38
+ DEFAULT_TIME = Time.new(0, 1, 1, 6, 0)
39
+
40
+ attr_accessor :number, :status, :time, :message, :month, :day
41
+
42
+ validates :number, inclusion: {
43
+ in: 1..8,
44
+ message: "value %{value} is invalid! Valid number values are 1..8."
45
+ }
46
+
47
+ validates :status, inclusion: {
48
+ in: ALARM_STATUS_MAP.keys,
49
+ message: "%{value} is invalid! Valid date formats are #{ALARM_STATUS_MAP.keys}."
50
+ }
51
+
52
+ validates :month, inclusion: {
53
+ in: 1..12,
54
+ allow_nil: true,
55
+ message: "%{value} is invalid! Valid months are 1..12 and nil."
56
+ }
57
+
58
+ validates :day, inclusion: {
59
+ if: ->(alarm) { alarm.month.nil? },
60
+ in: 1..31,
61
+ allow_nil: true,
62
+ message: "%{value} is invalid! Valid days are 1..31 and nil."
63
+ }
64
+
65
+ validates :day, inclusion: {
66
+ if: ->(alarm) { alarm.day && alarm.month },
67
+ in: ->(alarm) { VALID_DAYS_IN_MONTH[alarm.month] },
68
+ message: ->(alarm, _attributes) do
69
+ "#{alarm.day} is invalid for month #{alarm.month}! " \
70
+ "Valid days are #{VALID_DAYS_IN_MONTH[alarm.month]} and nil when month is #{alarm.month}."
71
+ end
72
+ }
73
+
74
+ # Create an Alarm instance.
75
+ #
76
+ # @param number [Integer] Alarm number (from 1 to 8).
77
+ # @param status [Symbol] Alarm status (:armed, :disarmed, or :unused).
78
+ # @param time [::Time] Time of alarm.
79
+ # @param message [String] Alarm message text.
80
+ # @param month [Integer, nil] Month of alarm.
81
+ # @param day [Integer, nil] Day of alarm.
82
+ # @return [Alarm] Alarm instance.
83
+ def initialize(number:, status:, time: DEFAULT_TIME, message: "", month: nil, day: nil)
84
+ @number = number
85
+ @status = status
86
+ @time = time
87
+ @message = message
88
+ @month = month
89
+ @day = day
90
+ end
91
+
92
+ # Compile packets for an alarm.
93
+ #
94
+ # @raise [ActiveModel::ValidationError] One or more model values are invalid.
95
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
96
+ def packets
97
+ validate!
98
+
99
+ [
100
+ [
101
+ CPACKET_ALARM,
102
+ number,
103
+ time.hour,
104
+ time.min,
105
+ month.to_i,
106
+ day.to_i,
107
+ status_formatted,
108
+ message_characters,
109
+ ].flatten
110
+ ]
111
+ end
112
+
113
+ private
114
+
115
+ def message_characters
116
+ protocol_6_chars_for(message, length: 16, pad: true)
117
+ end
118
+
119
+ def status_formatted
120
+ ALARM_STATUS_MAP[status]
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/char_encoders"
4
+ require "timex_datalink_client/helpers/length_packet_wrapper"
5
+
6
+ class TimexDatalinkClient
7
+ class Protocol6
8
+ class Eeprom
9
+ class PhoneNumber
10
+ include Helpers::CharEncoders
11
+ prepend Helpers::LengthPacketWrapper
12
+
13
+ PHONE_DIGITS = 12
14
+ NAME_MAX_LENGTH = 31
15
+
16
+ NUMBER_NAME_DELIMITER = "-"
17
+ NUMBER_NAME_MAX_NUMBER_LENGTH = 30
18
+
19
+ TERMINATOR = 0x5c
20
+
21
+ attr_accessor :name, :number, :type
22
+
23
+ # Create a PhoneNumber instance.
24
+ #
25
+ # @param name [String] Name associated to phone number.
26
+ # @param number [String] Phone number text.
27
+ # @param type [String] Phone number type.
28
+ # @return [PhoneNumber] PhoneNumber instance.
29
+ def initialize(name:, number:, type: " ")
30
+ @name = name
31
+ @number = number
32
+ @type = type
33
+ end
34
+
35
+ # Compile a packet for a phone number.
36
+ #
37
+ # @return [Array<Integer>] Array of integers that represent bytes.
38
+ def packet
39
+ [
40
+ number_with_type_characters,
41
+ name_characters,
42
+ TERMINATOR
43
+ ].flatten
44
+ end
45
+
46
+ private
47
+
48
+ def number_with_type_characters
49
+ phone_chars_for(number_with_type_padded)
50
+ end
51
+
52
+ def name_characters
53
+ return protocol_6_chars_for(name_with_number) if number.length > PHONE_DIGITS
54
+
55
+ protocol_6_chars_for(name, length: NAME_MAX_LENGTH)
56
+ end
57
+
58
+ def number_with_type_padded
59
+ number_with_type = "#{number} #{type}"
60
+ number_with_type.rjust(PHONE_DIGITS)
61
+ end
62
+
63
+ def name_with_number
64
+ number_name = NUMBER_NAME_DELIMITER
65
+ number_name += number[PHONE_DIGITS..NUMBER_NAME_MAX_NUMBER_LENGTH - 1]
66
+
67
+ name_length = NUMBER_NAME_MAX_NUMBER_LENGTH - number_name.length
68
+ truncated_name = name[..name_length - 1]
69
+
70
+ "#{truncated_name}#{number_name}"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/cpacket_paginator"
4
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
5
+ require "timex_datalink_client/helpers/lsb_msb_formatter"
6
+
7
+ class TimexDatalinkClient
8
+ class Protocol6
9
+ class Eeprom
10
+ include Helpers::CpacketPaginator
11
+ include Helpers::LsbMsbFormatter
12
+ prepend Helpers::CrcPacketsWrapper
13
+
14
+ CPACKET_CLEAR = [0x93, 0x01]
15
+ CPACKET_SECT = [0x90, 0x01]
16
+ CPACKET_DATA = [0x91, 0x01]
17
+ CPACKET_END = [0x92, 0x01]
18
+
19
+ CPACKET_DATA_LENGTH = 32
20
+
21
+ attr_accessor :phone_numbers
22
+
23
+ # Create an Eeprom instance.
24
+ #
25
+ # @param phone_numbers [Array<PhoneNumber>] Phone numbers to be added to EEPROM data.
26
+ # @return [Eeprom] Eeprom instance.
27
+ def initialize(phone_numbers: [])
28
+ @phone_numbers = phone_numbers
29
+ end
30
+
31
+ # Compile packets for EEPROM data.
32
+ #
33
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
34
+ def packets
35
+ [CPACKET_CLEAR, header] + payloads + [CPACKET_END]
36
+ end
37
+
38
+ private
39
+
40
+ def header
41
+ [
42
+ CPACKET_SECT,
43
+ payloads_length,
44
+ 0x04,
45
+ phone_numbers_length,
46
+ ].flatten
47
+ end
48
+
49
+ def payloads
50
+ paginate_cpackets(header: CPACKET_DATA, length: CPACKET_DATA_LENGTH, cpackets: all_packets)
51
+ end
52
+
53
+ def all_packets
54
+ phone_numbers.map(&:packet).flatten
55
+ end
56
+
57
+ def payloads_length
58
+ lsb_msb_format_for(payloads.length)
59
+ end
60
+
61
+ def phone_numbers_length
62
+ length_lsb = lsb_msb_format_for(phone_numbers.length).first
63
+
64
+ [length_lsb, 0]
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
4
+
5
+ class TimexDatalinkClient
6
+ class Protocol6
7
+ class End
8
+ prepend Helpers::CrcPacketsWrapper
9
+
10
+ CPACKET_SKIP = [0x21]
11
+
12
+ # Compile packets for data end command.
13
+ #
14
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
15
+ def packets
16
+ [CPACKET_SKIP]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
4
+
5
+ class TimexDatalinkClient
6
+ class Protocol6
7
+ class NightModeOptions
8
+ include ActiveModel::Validations
9
+ prepend Helpers::CrcPacketsWrapper
10
+
11
+ CPACKET_NIGHT_MODE = 0x72
12
+
13
+ validates :night_mode_deactivate_hours, inclusion: {
14
+ in: 3..12,
15
+ message: "%{value} is invalid! Valid night mode deactivate hour values are 3..12."
16
+ }
17
+
18
+ validates :indiglo_timeout_seconds, inclusion: {
19
+ in: 3..10,
20
+ message: "%{value} is invalid! Valid Indiglo timeout second values are 3..10."
21
+ }
22
+
23
+ attr_accessor :night_mode_deactivate_hours, :indiglo_timeout_seconds, :night_mode_on_notification
24
+
25
+ # Create a NightModeOptions instance.
26
+ #
27
+ # @param night_mode_deactivate_hours [Integer] Automatically deactivate night mode after specified hours.
28
+ # @param indiglo_timeout_seconds [Integer] Turn Indiglo light off after specified seconds after each button push.
29
+ # @param night_mode_on_notification [Boolean] Toggle activating night mode on any pager or alarm event.
30
+ # @return [NightModeOptions] NightModeOptions instance.
31
+ def initialize(night_mode_deactivate_hours: 8, indiglo_timeout_seconds: 4, night_mode_on_notification: false)
32
+ @night_mode_deactivate_hours = night_mode_deactivate_hours
33
+ @indiglo_timeout_seconds = indiglo_timeout_seconds
34
+ @night_mode_on_notification = night_mode_on_notification
35
+ end
36
+
37
+ # Compile packets for night mode options.
38
+ #
39
+ # @raise [ActiveModel::ValidationError] One or more model values are invalid.
40
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
41
+ def packets
42
+ validate!
43
+
44
+ [
45
+ [
46
+ CPACKET_NIGHT_MODE,
47
+ night_mode_on_notification_formatted,
48
+ night_mode_deactivate_hours,
49
+ indiglo_timeout_seconds
50
+ ]
51
+ ]
52
+ end
53
+
54
+ def night_mode_on_notification_formatted
55
+ night_mode_on_notification ? 1 : 0
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,89 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
4
+
5
+ class TimexDatalinkClient
6
+ class Protocol6
7
+ class PagerOptions
8
+ include ActiveModel::Validations
9
+ prepend Helpers::CrcPacketsWrapper
10
+
11
+ CPACKET_PAGER = 0x73
12
+ ALERT_SOUND_SILENT = 6
13
+
14
+ validates :on_hour, inclusion: {
15
+ in: 0..23,
16
+ message: "%{value} is invalid! Valid on hour values are 0..23."
17
+ }
18
+
19
+ validates :on_minute, inclusion: {
20
+ in: 0..59,
21
+ message: "%{value} is invalid! Valid on minute values are 0..59."
22
+ }
23
+
24
+ validates :off_hour, inclusion: {
25
+ in: 0..23,
26
+ message: "%{value} is invalid! Valid off hour values are 0..23."
27
+ }
28
+
29
+ validates :off_minute, inclusion: {
30
+ in: 0..59,
31
+ message: "%{value} is invalid! Valid off minute values are 0..59."
32
+ }
33
+
34
+ validates :alert_sound, inclusion: {
35
+ in: 0..5,
36
+ allow_nil: true,
37
+ message: "%{value} is invalid! Valid alert sound values are 0..5 and nil."
38
+ }
39
+
40
+ attr_accessor :auto_on_off, :on_hour, :on_minute, :off_hour, :off_minute, :alert_sound
41
+
42
+ # Create a PagerOptions instance.
43
+ #
44
+ # @param auto_on_off [Boolean] Toggle turning pager on and off every day.
45
+ # @param on_hour [Integer] Hour to turn pager on at.
46
+ # @param on_minute [Integer] Minute to turn pager on at.
47
+ # @param off_hour [Integer] Hour to turn pager off at.
48
+ # @param off_minute [Integer] Minute to turn pager off at.
49
+ # @param alert_sound [Integer, nil] Pager alert sound (0 to 5 or nil for silent).
50
+ # @return [PagerOptions] PagerOptions instance.
51
+ def initialize(auto_on_off: false, on_hour: 0, on_minute: 0, off_hour: 0, off_minute: 0, alert_sound: 0)
52
+ @auto_on_off = auto_on_off
53
+ @on_hour = on_hour
54
+ @on_minute = on_minute
55
+ @off_hour = off_hour
56
+ @off_minute = off_minute
57
+ @alert_sound = alert_sound
58
+ end
59
+
60
+ # Compile packets for pager options.
61
+ #
62
+ # @raise [ActiveModel::ValidationError] One or more model values are invalid.
63
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
64
+ def packets
65
+ validate!
66
+
67
+ [
68
+ [
69
+ CPACKET_PAGER,
70
+ auto_on_off_formatted,
71
+ on_hour,
72
+ on_minute,
73
+ off_hour,
74
+ off_minute,
75
+ alert_sound_formatted
76
+ ]
77
+ ]
78
+ end
79
+
80
+ def auto_on_off_formatted
81
+ auto_on_off ? 1 : 0
82
+ end
83
+
84
+ def alert_sound_formatted
85
+ alert_sound || ALERT_SOUND_SILENT
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
4
+
5
+ class TimexDatalinkClient
6
+ class Protocol6
7
+ class SoundScrollOptions
8
+ include ActiveModel::Validations
9
+ prepend Helpers::CrcPacketsWrapper
10
+
11
+ CPACKET_SOUND_SCROLL = 0x71
12
+
13
+ validates :scroll_speed, inclusion: {
14
+ in: 0..2,
15
+ message: "%{value} is invalid! Valid scroll speed values are 0..2."
16
+ }
17
+
18
+ attr_accessor :hourly_chime, :button_beep, :scroll_speed
19
+
20
+ # Create a SoundScrollOptions instance.
21
+ #
22
+ # @param hourly_chime [Boolean] Toggle hourly chime.
23
+ # @param button_beep [Boolean] Toggle button beep.
24
+ # @param scroll_speed [Integer] Message scroll speed (0 to 2).
25
+ # @return [SoundScrollOptions] SoundScrollOptions instance.
26
+ def initialize(hourly_chime: false, button_beep: false, scroll_speed: 1)
27
+ @hourly_chime = hourly_chime
28
+ @button_beep = button_beep
29
+ @scroll_speed = scroll_speed
30
+ end
31
+
32
+ # Compile packets for sound and scroll options.
33
+ #
34
+ # @raise [ActiveModel::ValidationError] One or more model values are invalid.
35
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
36
+ def packets
37
+ validate!
38
+
39
+ [
40
+ [
41
+ CPACKET_SOUND_SCROLL,
42
+ hourly_chime_formatted,
43
+ button_beep_formatted,
44
+ scroll_speed
45
+ ]
46
+ ]
47
+ end
48
+
49
+ def hourly_chime_formatted
50
+ hourly_chime ? 1 : 0
51
+ end
52
+
53
+ def button_beep_formatted
54
+ button_beep ? 1 : 0
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
4
+
5
+ class TimexDatalinkClient
6
+ class Protocol6
7
+ class Start
8
+ prepend Helpers::CrcPacketsWrapper
9
+
10
+ CPACKET_START = [0x20, 0x00, 0x00, 0x06]
11
+
12
+ # Compile packets for data start command.
13
+ #
14
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
15
+ def packets
16
+ [CPACKET_START]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class TimexDatalinkClient
4
+ class Protocol6
5
+ class Sync
6
+ PING_BYTE = [0x78]
7
+ FAST_MODE_BYTE = [0x56]
8
+ SYNC_1_BYTE = [0x55]
9
+ SYNC_2_BYTE = [0xaa]
10
+
11
+ SYNC_2_LENGTH = 40
12
+
13
+ attr_accessor :length
14
+
15
+ # Create a Sync instance.
16
+ #
17
+ # @param length [Integer] Number of 0x55 sync bytes to use.
18
+ # @return [Sync] Sync instance.
19
+ def initialize(length: 300)
20
+ @length = length
21
+ end
22
+
23
+ # Compile packets for syncronization data.
24
+ #
25
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
26
+ def packets
27
+ [PING_BYTE + FAST_MODE_BYTE + render_sync_1 + render_sync_2]
28
+ end
29
+
30
+ private
31
+
32
+ def render_sync_1
33
+ SYNC_1_BYTE * length
34
+ end
35
+
36
+ def render_sync_2
37
+ SYNC_2_BYTE * SYNC_2_LENGTH
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model"
4
+
5
+ require "timex_datalink_client/helpers/char_encoders"
6
+ require "timex_datalink_client/helpers/crc_packets_wrapper"
7
+
8
+ class TimexDatalinkClient
9
+ class Protocol6
10
+ class Time
11
+ include ActiveModel::Validations
12
+ include Helpers::CharEncoders
13
+ prepend Helpers::CrcPacketsWrapper
14
+
15
+ CPACKET_TIME = [0x32].freeze
16
+ CPACKET_FLEX_TIME = [0x33].freeze
17
+
18
+ ZONE_OFFSET_MAP = {
19
+ -39600 => 0x15,
20
+ -36000 => 0x16,
21
+ -32400 => 0x17,
22
+ -28800 => 0x18,
23
+ -25200 => 0x19,
24
+ -21600 => 0x1a,
25
+ -18000 => 0x1b,
26
+ -14400 => 0x1c,
27
+ -12600 => 0x14,
28
+ -10800 => 0x1d,
29
+ -7200 => 0x1e,
30
+ -3600 => 0x1f,
31
+ 0 => 0x00,
32
+ 3600 => 0x01,
33
+ 7200 => 0x02,
34
+ 10800 => 0x03,
35
+ 12600 => 0x0d,
36
+ 14400 => 0x04,
37
+ 16200 => 0x0e,
38
+ 18000 => 0x05,
39
+ 19800 => 0x0f,
40
+ 20700 => 0x11,
41
+ 21600 => 0x06,
42
+ 23400 => 0x12,
43
+ 25200 => 0x07,
44
+ 28800 => 0x08,
45
+ 32400 => 0x09,
46
+ 34200 => 0x13,
47
+ 36000 => 0x0a,
48
+ 39600 => 0x0b,
49
+ 43200 => 0x0c
50
+ }.freeze
51
+
52
+ FLEX_TIME_ZONE = 0x10
53
+ FLEX_DST_VALUE = 0x08
54
+
55
+ DATE_FORMAT_MAP = {
56
+ "%_m-%d-%y" => 0x00,
57
+ "%_d-%m-%y" => 0x01,
58
+ "%y-%m-%d" => 0x02,
59
+ "%_m.%d.%y" => 0x04,
60
+ "%_d.%m.%y" => 0x05,
61
+ "%y.%m.%d" => 0x06
62
+ }.freeze
63
+
64
+ validates :zone, inclusion: {
65
+ in: 1..2,
66
+ message: "%{value} is invalid! Valid zones are 1..2."
67
+ }
68
+
69
+ validates :date_format, inclusion: {
70
+ in: DATE_FORMAT_MAP.keys,
71
+ message: "%{value} is invalid! Valid date formats are #{DATE_FORMAT_MAP.keys}."
72
+ }
73
+
74
+ validates :flex_time_zone, unless: :flex_time, inclusion: {
75
+ in: [false],
76
+ message: "cannot be enabled unless FLEXtime is also enabled."
77
+ }
78
+
79
+ validates :flex_dst, unless: :flex_time, inclusion: {
80
+ in: [false],
81
+ message: "cannot be enabled unless FLEXtime is also enabled."
82
+ }
83
+
84
+ attr_accessor :zone, :is_24h, :date_format, :time, :name, :flex_time, :flex_time_zone, :flex_dst
85
+
86
+ # Create a Time instance.
87
+ #
88
+ # @param zone [Integer] Time zone number (1 or 2).
89
+ # @param is_24h [Boolean] Toggle 24 hour time.
90
+ # @param date_format ["%_m-%d-%y", "%_d-%m-%y", "%y-%m-%d", "%_m.%d.%y", "%_d.%m.%y", "%y.%m.%d"] Date format
91
+ # (represented by Time#strftime format).
92
+ # @param time [::Time] Time to set (including time zone).
93
+ # @param name [String, nil] Name of time zone (defaults to zone from time; 3 chars max).
94
+ # @param flex_time [Boolean] Toggle using FLEXtime to set time and date.
95
+ # @param flex_time_zone [Boolean] Toggle using FLEXtime to set time zone.
96
+ # @param flex_dst [Boolean] Toggle using FLEXtime to apply daylight savings time offset.
97
+ # @return [Time] Time instance.
98
+ def initialize(
99
+ zone:, is_24h:, date_format:, time:, name: nil, flex_time: false, flex_time_zone: false, flex_dst: false
100
+ )
101
+ @zone = zone
102
+ @is_24h = is_24h
103
+ @date_format = date_format
104
+ @time = time
105
+ @name = name
106
+ @flex_time = flex_time
107
+ @flex_time_zone = flex_time_zone
108
+ @flex_dst = flex_dst
109
+ end
110
+
111
+ # Compile packets for a time.
112
+ #
113
+ # @raise [ActiveModel::ValidationError] One or more model values are invalid.
114
+ # @return [Array<Array<Integer>>] Two-dimensional array of integers that represent bytes.
115
+ def packets
116
+ validate!
117
+
118
+ [
119
+ [
120
+ cpacket,
121
+ zone,
122
+ second,
123
+ hour,
124
+ minute,
125
+ month,
126
+ day,
127
+ year_mod_1900,
128
+ name_characters,
129
+ wday_from_monday,
130
+ formatted_time_zone,
131
+ is_24h_value,
132
+ date_format_value
133
+ ].flatten
134
+ ]
135
+ end
136
+
137
+ private
138
+
139
+ def cpacket
140
+ flex_time ? CPACKET_FLEX_TIME : CPACKET_TIME
141
+ end
142
+
143
+ def second
144
+ flex_time ? 0 : formatted_time.sec
145
+ end
146
+
147
+ def hour
148
+ flex_time ? 0 : formatted_time.hour
149
+ end
150
+
151
+ def minute
152
+ flex_time ? 0 : formatted_time.min
153
+ end
154
+
155
+ def month
156
+ flex_time ? 0 : formatted_time.month
157
+ end
158
+
159
+ def day
160
+ flex_time ? 0 : formatted_time.day
161
+ end
162
+
163
+ def formatted_name
164
+ name || time.zone || "tz#{zone}"
165
+ end
166
+
167
+ def name_characters
168
+ protocol_6_chars_for(formatted_name, length: 3, pad: true)
169
+ end
170
+
171
+ def year_mod_1900
172
+ flex_time ? 0 : formatted_time.year % 100
173
+ end
174
+
175
+ def wday_from_monday
176
+ flex_time ? 0 : (formatted_time.wday + 6) % 7
177
+ end
178
+
179
+ def formatted_time
180
+ time.dst? ? time + 3600 : time
181
+ end
182
+
183
+ def formatted_utc_offset
184
+ time.dst? ? time.utc_offset - 3600 : time.utc_offset
185
+ end
186
+
187
+ def formatted_time_zone
188
+ flex_time_zone ? FLEX_TIME_ZONE : ZONE_OFFSET_MAP[formatted_utc_offset]
189
+ end
190
+
191
+ def is_24h_value
192
+ is_24h ? 2 : 1
193
+ end
194
+
195
+ def date_format_value
196
+ format = DATE_FORMAT_MAP.fetch(date_format)
197
+ format += FLEX_DST_VALUE if flex_dst
198
+
199
+ format
200
+ end
201
+ end
202
+ end
203
+ end
@@ -24,7 +24,7 @@ class TimexDatalinkClient
24
24
  # Create a TimeName instance.
25
25
  #
26
26
  # @param zone [Integer] Time zone number (1 or 2).
27
- # @param name [String] Name of time zone (3 chars max)
27
+ # @param name [String] Name of time zone (3 chars max).
28
28
  # @return [TimeName] TimeName instance.
29
29
  def initialize(zone:, name:)
30
30
  @zone = zone
@@ -49,8 +49,12 @@ class TimexDatalinkClient
49
49
 
50
50
  private
51
51
 
52
+ def name_formatted
53
+ name || "tz#{zone}"
54
+ end
55
+
52
56
  def name_characters
53
- chars_for(name, length: 3, pad: true)
57
+ chars_for(name_formatted, length: 3, pad: true)
54
58
  end
55
59
  end
56
60
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class TimexDatalinkClient
4
- VERSION = "0.11.0"
4
+ VERSION = "0.12.0"
5
5
  end
@@ -43,6 +43,17 @@ require "timex_datalink_client/protocol_4/sync"
43
43
  require "timex_datalink_client/protocol_4/time"
44
44
  require "timex_datalink_client/protocol_4/wrist_app"
45
45
 
46
+ require "timex_datalink_client/protocol_6/alarm"
47
+ require "timex_datalink_client/protocol_6/eeprom"
48
+ require "timex_datalink_client/protocol_6/eeprom/phone_number"
49
+ require "timex_datalink_client/protocol_6/end"
50
+ require "timex_datalink_client/protocol_6/night_mode_options"
51
+ require "timex_datalink_client/protocol_6/pager_options"
52
+ require "timex_datalink_client/protocol_6/sound_scroll_options"
53
+ require "timex_datalink_client/protocol_6/start"
54
+ require "timex_datalink_client/protocol_6/sync"
55
+ require "timex_datalink_client/protocol_6/time"
56
+
46
57
  require "timex_datalink_client/protocol_7/eeprom"
47
58
  require "timex_datalink_client/protocol_7/eeprom/activity"
48
59
  require "timex_datalink_client/protocol_7/eeprom/calendar"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timex_datalink_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maxwell Pray
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-27 00:00:00.000000000 Z
11
+ date: 2023-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -66,90 +66,6 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.6.0
69
- - !ruby/object:Gem::Dependency
70
- name: mdl
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 0.12.0
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 0.12.0
83
- - !ruby/object:Gem::Dependency
84
- name: rspec
85
- requirement: !ruby/object:Gem::Requirement
86
- requirements:
87
- - - "~>"
88
- - !ruby/object:Gem::Version
89
- version: 3.11.0
90
- type: :development
91
- prerelease: false
92
- version_requirements: !ruby/object:Gem::Requirement
93
- requirements:
94
- - - "~>"
95
- - !ruby/object:Gem::Version
96
- version: 3.11.0
97
- - !ruby/object:Gem::Dependency
98
- name: rubocop
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 1.41.1
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 1.41.1
111
- - !ruby/object:Gem::Dependency
112
- name: rubocop-github
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.20.0
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.20.0
125
- - !ruby/object:Gem::Dependency
126
- name: tzinfo
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 2.0.5
132
- type: :development
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 2.0.5
139
- - !ruby/object:Gem::Dependency
140
- name: yard-junk
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: 0.0.9
146
- type: :development
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: 0.0.9
153
69
  description:
154
70
  email: synthead@gmail.com
155
71
  executables: []
@@ -201,6 +117,16 @@ files:
201
117
  - lib/timex_datalink_client/protocol_4/sync.rb
202
118
  - lib/timex_datalink_client/protocol_4/time.rb
203
119
  - lib/timex_datalink_client/protocol_4/wrist_app.rb
120
+ - lib/timex_datalink_client/protocol_6/alarm.rb
121
+ - lib/timex_datalink_client/protocol_6/eeprom.rb
122
+ - lib/timex_datalink_client/protocol_6/eeprom/phone_number.rb
123
+ - lib/timex_datalink_client/protocol_6/end.rb
124
+ - lib/timex_datalink_client/protocol_6/night_mode_options.rb
125
+ - lib/timex_datalink_client/protocol_6/pager_options.rb
126
+ - lib/timex_datalink_client/protocol_6/sound_scroll_options.rb
127
+ - lib/timex_datalink_client/protocol_6/start.rb
128
+ - lib/timex_datalink_client/protocol_6/sync.rb
129
+ - lib/timex_datalink_client/protocol_6/time.rb
204
130
  - lib/timex_datalink_client/protocol_7/eeprom.rb
205
131
  - lib/timex_datalink_client/protocol_7/eeprom/activity.rb
206
132
  - lib/timex_datalink_client/protocol_7/eeprom/calendar.rb
@@ -224,7 +150,7 @@ files:
224
150
  - lib/timex_datalink_client/protocol_9/time_name.rb
225
151
  - lib/timex_datalink_client/protocol_9/timer.rb
226
152
  - lib/timex_datalink_client/version.rb
227
- homepage: https://github.com/synthead/timex_datalink_client/tree/v0.11.0
153
+ homepage: https://github.com/synthead/timex_datalink_client/tree/v0.12.0
228
154
  licenses:
229
155
  - MIT
230
156
  metadata: {}
@@ -243,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
169
  - !ruby/object:Gem::Version
244
170
  version: '0'
245
171
  requirements: []
246
- rubygems_version: 3.3.7
172
+ rubygems_version: 3.4.10
247
173
  signing_key:
248
174
  specification_version: 4
249
175
  summary: Write data to Timex Datalink devices with an optical sensor