ruby-sml 0.2
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.
- data/LICENSE +24 -0
- data/README.md +0 -0
- data/lib/ruby-sml.rb +30 -0
- data/lib/ruby-sml/crc16.rb +47 -0
- data/lib/ruby-sml/encoding-binary.rb +262 -0
- data/lib/ruby-sml/helpers.rb +58 -0
- data/lib/ruby-sml/nilclass-mixin.rb +5 -0
- data/lib/ruby-sml/obis.rb +139 -0
- data/lib/ruby-sml/sml-attention.rb +60 -0
- data/lib/ruby-sml/sml-file.rb +37 -0
- data/lib/ruby-sml/sml-getlist.rb +88 -0
- data/lib/ruby-sml/sml-getprocparameter.rb +61 -0
- data/lib/ruby-sml/sml-getprofilelist.rb +103 -0
- data/lib/ruby-sml/sml-getprofilepack.rb +107 -0
- data/lib/ruby-sml/sml-listentry.rb +98 -0
- data/lib/ruby-sml/sml-message.rb +87 -0
- data/lib/ruby-sml/sml-messagebody.rb +95 -0
- data/lib/ruby-sml/sml-periodentry.rb +38 -0
- data/lib/ruby-sml/sml-procparametervalue.rb +46 -0
- data/lib/ruby-sml/sml-profileobjectheaderentry.rb +31 -0
- data/lib/ruby-sml/sml-profileobjectperiodentry.rb +46 -0
- data/lib/ruby-sml/sml-publicclose.rb +51 -0
- data/lib/ruby-sml/sml-publicopen.rb +84 -0
- data/lib/ruby-sml/sml-setprocparameter.rb +37 -0
- data/lib/ruby-sml/sml-time.rb +46 -0
- data/lib/ruby-sml/sml-tree.rb +42 -0
- data/lib/ruby-sml/sml-treepath.rb +24 -0
- data/lib/ruby-sml/sml-tupelentry.rb +105 -0
- data/lib/ruby-sml/sml-valueentry.rb +29 -0
- data/lib/ruby-sml/transport-binary.rb +158 -0
- data/lib/ruby-sml/units.rb +84 -0
- data/sample.rb +66 -0
- metadata +85 -0
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
|
3
|
+
module SML
|
4
|
+
module PublicClose
|
5
|
+
|
6
|
+
class Request
|
7
|
+
attr_accessor :global_signature
|
8
|
+
|
9
|
+
def initialize(global_signature)
|
10
|
+
@global_signature = global_signature
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.construct(array_rep)
|
14
|
+
return nil if array_rep.nil?
|
15
|
+
return SML::PublicClose::Request.new(array_rep.shift)
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.pconstruct(o={})
|
19
|
+
return SML::PublicClose::Request.new(o[:global_signature])
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_a
|
23
|
+
return [] << global_signature
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
class Response
|
29
|
+
attr_accessor :global_signature
|
30
|
+
|
31
|
+
def initialize(global_signature)
|
32
|
+
@global_signature = global_signature
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.construct(array_rep)
|
36
|
+
return nil if array_rep.nil?
|
37
|
+
return SML::PublicClose::Response.new(array_rep.shift)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.pconstruct(o={})
|
41
|
+
return SML::PublicClose::Response.new(o[:global_signature])
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_a
|
45
|
+
return [] << global_signature
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
require 'ruby-sml/sml-time'
|
3
|
+
|
4
|
+
module SML
|
5
|
+
module PublicOpen
|
6
|
+
|
7
|
+
class Request
|
8
|
+
attr_accessor :codepage, :client_id, :request_file_id, :server_id, :username, :password, :sml_version
|
9
|
+
|
10
|
+
def initialize(codepage, client_id, request_file_id, server_id, username, password, sml_version)
|
11
|
+
@codepage = codepage
|
12
|
+
@client_id = client_id
|
13
|
+
@request_file_id = request_file_id
|
14
|
+
@server_id = server_id
|
15
|
+
@username = username
|
16
|
+
@password = password
|
17
|
+
@sml_version = sml_version
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.construct(array_rep)
|
21
|
+
return nil if array_rep.nil?
|
22
|
+
codepage = array_rep.shift
|
23
|
+
client_id = array_rep.shift
|
24
|
+
request_file_id = array_rep.shift
|
25
|
+
server_id = array_rep.shift
|
26
|
+
username = array_rep.shift
|
27
|
+
password = array_rep.shift
|
28
|
+
sml_version = array_rep.shift
|
29
|
+
array_rep.shift unless sml_version.nil?
|
30
|
+
|
31
|
+
return SML::PublicOpen::Request.new(codepage, client_id, request_file_id, server_id, username, password, sml_version)
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.pconstruct(o={})
|
35
|
+
return SML::PublicOpen::Request.new(o[:codepage], o[:client_id], o[:request_file_id], o[:server_id], o[:username], o[:password], o[:sml_version])
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_a
|
39
|
+
result = [] << codepage << client_id << request_file_id << server_id << username << password << sml_version
|
40
|
+
result << :uint8 unless sml_version.nil?
|
41
|
+
return result
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class Response
|
47
|
+
attr_accessor :codepage, :client_id, :request_file_id, :server_id, :reference_time, :sml_version
|
48
|
+
|
49
|
+
def initialize(codepage, client_id, request_file_id, server_id, reference_time, sml_version)
|
50
|
+
@codepage = codepage
|
51
|
+
@client_id = client_id
|
52
|
+
@request_file_id = request_file_id
|
53
|
+
@server_id = server_id
|
54
|
+
@reference_time = reference_time
|
55
|
+
@sml_version = sml_version
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.construct(array_rep)
|
59
|
+
return nil if array_rep.nil?
|
60
|
+
codepage = array_rep.shift
|
61
|
+
client_id = array_rep.shift
|
62
|
+
request_file_id = array_rep.shift
|
63
|
+
server_id = array_rep.shift
|
64
|
+
reference_time = SML::Time.construct(array_rep.shift)
|
65
|
+
sml_version = array_rep.shift
|
66
|
+
array_rep.shift unless sml_version.nil?
|
67
|
+
|
68
|
+
return SML::PublicOpen::Response.new(codepage, client_id, request_file_id, server_id, reference_time, sml_version)
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.pconstruct(o={})
|
72
|
+
return SML::PublicOpen::Response.new(o[:codepage], o[:client_id], o[:request_file_id], o[:server_id], o[:reference_time], o[:sml_version])
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_a
|
76
|
+
result = [] << codepage << client_id << request_file_id << server_id << reference_time.to_a << sml_version
|
77
|
+
result << :uint8 unless sml_version.nil?
|
78
|
+
return result
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
require 'ruby-sml/sml-treepath'
|
3
|
+
require 'ruby-sml/sml-tree'
|
4
|
+
|
5
|
+
module SML
|
6
|
+
module SetProcParameter
|
7
|
+
|
8
|
+
class Request
|
9
|
+
attr_accessor :server_id, :username, :password, :parameter_treepath, :parameter_tree
|
10
|
+
|
11
|
+
def initialize(server_id, username, password, parameter_treepath, parameter_tree)
|
12
|
+
@server_id = server_id
|
13
|
+
@username = username
|
14
|
+
@password = password
|
15
|
+
@parameter_treepath = parameter_treepath
|
16
|
+
@parameter_tree = parameter_tree
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.construct(array_rep)
|
20
|
+
return nil if array_rep.nil?
|
21
|
+
server_id = array_rep.shift
|
22
|
+
username = array_rep.shift
|
23
|
+
password = array_rep.shift
|
24
|
+
parameter_treepath = SML::Treepath.construct(array_rep.shift)
|
25
|
+
parameter_tree = SML::Tree.construct(array_rep.shift)
|
26
|
+
|
27
|
+
return nil if (parameter_treepath.nil? or parameter_tree.nil?)
|
28
|
+
return SML::SetProcParameter::Request.new(server_id, username, password, parameter_treepath, parameter_tree)
|
29
|
+
end
|
30
|
+
def to_a
|
31
|
+
return [] << server_id << username << password << parameter_treepath.to_a << parameter_tree.to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
|
3
|
+
module SML
|
4
|
+
|
5
|
+
class Time
|
6
|
+
attr_accessor :type, :value
|
7
|
+
|
8
|
+
def initialize(type, value)
|
9
|
+
@type = type
|
10
|
+
@value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.construct(array_rep)
|
14
|
+
return nil if array_rep.nil?
|
15
|
+
choice = array_rep.shift
|
16
|
+
array_rep.shift unless choice.nil?
|
17
|
+
type = case choice
|
18
|
+
when 0x01
|
19
|
+
:seconds_index
|
20
|
+
when 0x02
|
21
|
+
:timestamp
|
22
|
+
end
|
23
|
+
value = array_rep.shift
|
24
|
+
array_rep.shift unless value.nil?
|
25
|
+
|
26
|
+
return SML::Time.new(type, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.pconstruct(o={})
|
30
|
+
return SML::Time.new(o[:type], o[:value])
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_a
|
34
|
+
choice = case type
|
35
|
+
when :seconds_index
|
36
|
+
0x01
|
37
|
+
when :timestamp
|
38
|
+
0x02
|
39
|
+
end
|
40
|
+
|
41
|
+
return [] << choice << :uint8 << value << :uint32
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
require 'ruby-sml/sml-procparametervalue'
|
3
|
+
|
4
|
+
module SML
|
5
|
+
|
6
|
+
class Tree
|
7
|
+
attr_accessor :parameter_name, :parameter_value, :child_list
|
8
|
+
|
9
|
+
def initialize(parameter_name, parameter_value, child_list)
|
10
|
+
@parameter_name = parameter_name
|
11
|
+
@parameter_value = parameter_value
|
12
|
+
@child_list = child_list
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.construct(array_rep)
|
16
|
+
return nil if array_rep.nil?
|
17
|
+
parameter_name = array_rep.shift
|
18
|
+
parameter_value = SML::ProcParameterValue.construct(array_rep.shift)
|
19
|
+
child_list = []
|
20
|
+
child_list_array_rep = array_rep.shift
|
21
|
+
unless child_list_array_rep.nil?
|
22
|
+
child_list_array_rep.each do |entry_array_rep|
|
23
|
+
entry = SML::Tree.construct(entry_array_rep)
|
24
|
+
return nil if entry.nil?
|
25
|
+
child_list << entry
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
return SML::Tree.new(parameter_name, parameter_value, child_list)
|
30
|
+
end
|
31
|
+
def to_a
|
32
|
+
child_list_array = []
|
33
|
+
child_list.each do |entry|
|
34
|
+
child_list_array << entry.to_a
|
35
|
+
end
|
36
|
+
|
37
|
+
return [] << parameter_name << SML::ProcParameterValue.to_a(parameter_value) << child_list_array
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
|
3
|
+
module SML
|
4
|
+
|
5
|
+
class Treepath
|
6
|
+
attr_accessor :path_entry
|
7
|
+
|
8
|
+
def initialize(path_entry)
|
9
|
+
@path_entry = path_entry
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.construct(array_rep)
|
13
|
+
return nil if array_rep.nil?
|
14
|
+
path_entry = array_rep.shift
|
15
|
+
|
16
|
+
return SML::Treepath.new(path_entry)
|
17
|
+
end
|
18
|
+
def to_a
|
19
|
+
return [] << path_entry
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
require 'ruby-sml/sml-time'
|
3
|
+
|
4
|
+
module SML
|
5
|
+
|
6
|
+
class TupelEntry
|
7
|
+
attr_accessor :server_id, :seconds_index, :status, :unit_pa, :scaler_pa, :value_pa, :unit_r1, :scaler_r1, :value_r1, :unit_r4, :scaler_r4, :value_r4, :signature_pa_r1_r4, :unit_ma, :scaler_ma, :value_ma, :unit_r2, :scaler_r2, :value_r2, :unit_r3, :scaler_r3, :value_r3, :signature_ma_r2_r3
|
8
|
+
|
9
|
+
def initialize(server_id, seconds_index, status, unit_pa, scaler_pa, value_pa, unit_r1, scaler_r1, value_r1, unit_r4, scaler_r4, value_r4, signature_pa_r1_r4, unit_ma, scaler_ma, value_ma, unit_r2, scaler_r2, value_r2, unit_r3, scaler_r3, value_r3, signature_ma_r2_r3)
|
10
|
+
@server_id = server_id
|
11
|
+
@seconds_index = seconds_index
|
12
|
+
@status = status
|
13
|
+
|
14
|
+
@unit_pa = unit_pa
|
15
|
+
@scaler_pa = scaler_pa
|
16
|
+
@value_pa = value_pa
|
17
|
+
|
18
|
+
@unit_r1 = unit_r1
|
19
|
+
@scaler_r1 = scaler_r1
|
20
|
+
@value_r1 = value_r1
|
21
|
+
|
22
|
+
@unit_r4 = unit_r4
|
23
|
+
@scaler_r4 = scaler_r4
|
24
|
+
@value_r4 = value_r4
|
25
|
+
|
26
|
+
@signature_pa_r1_r4 = signature_pa_r1_r4
|
27
|
+
|
28
|
+
@unit_ma = unit_ma
|
29
|
+
@scaler_ma = scaler_ma
|
30
|
+
@value_ma = value_ma
|
31
|
+
|
32
|
+
@unit_r2 = unit_r2
|
33
|
+
@scaler_r2 = scaler_r2
|
34
|
+
@value_r2 = value_r2
|
35
|
+
|
36
|
+
@unit_r3 = unit_r3
|
37
|
+
@scaler_r3 = scaler_r3
|
38
|
+
@value_r3 = value_r3
|
39
|
+
|
40
|
+
@signature_ma_r2_r3 = signature_ma_r2_r3
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.construct(array_rep)
|
44
|
+
return nil if array_rep.nil?
|
45
|
+
server_id = array_rep.shift
|
46
|
+
seconds_index = SML::Time.construct(array_rep.shift)
|
47
|
+
status = array_rep.shift
|
48
|
+
array_rep.shift
|
49
|
+
|
50
|
+
unit_pa = array_rep.shift
|
51
|
+
array_rep.shift
|
52
|
+
scaler_pa = array_rep.shift
|
53
|
+
array_rep.shift
|
54
|
+
value_pa = array_rep.shift
|
55
|
+
array_rep.shift
|
56
|
+
|
57
|
+
unit_r1 = array_rep.shift
|
58
|
+
array_rep.shift
|
59
|
+
scaler_r1 = array_rep.shift
|
60
|
+
array_rep.shift
|
61
|
+
value_r1 = array_rep.shift
|
62
|
+
array_rep.shift
|
63
|
+
|
64
|
+
unit_r4 = array_rep.shift
|
65
|
+
array_rep.shift
|
66
|
+
scaler_r4 = array_rep.shift
|
67
|
+
array_rep.shift
|
68
|
+
value_r4 = array_rep.shift
|
69
|
+
array_rep.shift
|
70
|
+
|
71
|
+
signature_pa_r1_r4 = array_rep.shift
|
72
|
+
|
73
|
+
unit_ma = array_rep.shift
|
74
|
+
array_rep.shift
|
75
|
+
scaler_ma = array_rep.shift
|
76
|
+
array_rep.shift
|
77
|
+
value_ma = array_rep.shift
|
78
|
+
array_rep.shift
|
79
|
+
|
80
|
+
unit_r2 = array_rep.shift
|
81
|
+
array_rep.shift
|
82
|
+
scaler_r2 = array_rep.shift
|
83
|
+
array_rep.shift
|
84
|
+
value_r2 = array_rep.shift
|
85
|
+
array_rep.shift
|
86
|
+
|
87
|
+
unit_r3 = array_rep.shift
|
88
|
+
array_rep.shift
|
89
|
+
scaler_r3 = array_rep.shift
|
90
|
+
array_rep.shift
|
91
|
+
value_r3 = array_rep.shift
|
92
|
+
array_rep.shift
|
93
|
+
|
94
|
+
signature_ma_r2_r3 = array_rep.shift
|
95
|
+
|
96
|
+
return nil if seconds_index.nil?
|
97
|
+
return SML::TupelEntry.new(server_id, seconds_index, status, unit_pa, scaler_pa, value_pa, unit_r1, scaler_r1, value_r1, unit_r4, scaler_r4, value_r4, signature_pa_r1_r4, unit_ma, scaler_ma, value_ma, unit_r2, scaler_r2, value_r2, unit_r3, scaler_r3, value_r3, signature_ma_r2_r3)
|
98
|
+
end
|
99
|
+
def to_a
|
100
|
+
return [] << server_id << seconds_index.to_a << status << :uint64 << unit_pa << :uint8 << scaler_pa << :int8 << value_pa << :int64 << unit_r1 << :uint8 << scaler_r1 << :int8 << value_r1 << :int64 << unit_r4 << :uint8 << scaler_r4 << :int8 << value_r4 << :int64 << signature_pa_r1_r4 << unit_ma << :uint8 << scaler_ma << :int8 << value_ma << :int64 << unit_r2 << :uint8 << scaler_r2 << :int8 << value_r2 << :int64 << unit_r3 << :uint8 << scaler_r3 << :int8 << value_r3 << :int64 << signature_ma_r2_r3
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'ruby-sml/nilclass-mixin'
|
2
|
+
|
3
|
+
module SML
|
4
|
+
|
5
|
+
class ValueEntry
|
6
|
+
attr_accessor :value, :value_type, :signature
|
7
|
+
|
8
|
+
def initialize(value, value_type, signature)
|
9
|
+
@value = value
|
10
|
+
@value_type = value_type
|
11
|
+
@signature = signature
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.construct(array_rep)
|
15
|
+
return nil if array_rep.nil?
|
16
|
+
value = array_rep.shift
|
17
|
+
value_type = array_rep.shift
|
18
|
+
signature = array_rep.shift
|
19
|
+
|
20
|
+
return nil if value.nil?
|
21
|
+
return SML::ValueEntry.new(value, value_type, signature)
|
22
|
+
end
|
23
|
+
def to_a
|
24
|
+
return [] << value << value_type << signature
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
require 'ruby-sml/crc16'
|
2
|
+
|
3
|
+
require 'stringio'
|
4
|
+
|
5
|
+
module SML
|
6
|
+
|
7
|
+
class BinaryTransport
|
8
|
+
|
9
|
+
def self.readfile(io)
|
10
|
+
file = String.new
|
11
|
+
received_checksum_bytes = String.new
|
12
|
+
raw = String.new
|
13
|
+
|
14
|
+
while not io.eof?
|
15
|
+
bytes_raw = io.read(4)
|
16
|
+
raw << bytes_raw
|
17
|
+
bytes = bytes_raw.unpack('N')[0]
|
18
|
+
if bytes == 0x1b1b1b1b
|
19
|
+
escape = []
|
20
|
+
4.times do
|
21
|
+
byte = io.read(1)
|
22
|
+
raw << byte
|
23
|
+
escape.push(byte.unpack('C')[0])
|
24
|
+
end
|
25
|
+
escape_return, padding_length = handle_escape(escape)
|
26
|
+
case escape_return
|
27
|
+
when 1
|
28
|
+
4.times do
|
29
|
+
file << [0x1b].pack('C')
|
30
|
+
end
|
31
|
+
when String
|
32
|
+
received_checksum_bytes = escape_return
|
33
|
+
break
|
34
|
+
end
|
35
|
+
else
|
36
|
+
file << [bytes].pack('N')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# calculate CRC16 over all received bytes (except last 2 - they contain the checksum itself)
|
41
|
+
raw.chop!.chop!
|
42
|
+
calculated_checksum = CRC16.crc16(raw)
|
43
|
+
calculated_checksum = (calculated_checksum ^ 0xffff)
|
44
|
+
calculated_checksum = ((calculated_checksum & 0xff00) >> 8) | ((calculated_checksum & 0x00ff) << 8)
|
45
|
+
# unpack the checksum we received
|
46
|
+
received_checksum = received_checksum_bytes.unpack('n')[0]
|
47
|
+
|
48
|
+
return nil unless calculated_checksum == received_checksum
|
49
|
+
return file[0..-(padding_length+1)]
|
50
|
+
end
|
51
|
+
def self.readstring(data)
|
52
|
+
io = StringIO.new(data)
|
53
|
+
end_of_transmission_found = false
|
54
|
+
file = String.new
|
55
|
+
received_checksum_bytes = String.new
|
56
|
+
raw = String.new
|
57
|
+
|
58
|
+
while not io.eof?
|
59
|
+
bytes_raw = io.read(4)
|
60
|
+
raw << bytes_raw
|
61
|
+
bytes = bytes_raw.unpack('N')[0]
|
62
|
+
if bytes == 0x1b1b1b1b
|
63
|
+
escape = []
|
64
|
+
4.times do
|
65
|
+
byte = io.read(1)
|
66
|
+
raw << byte
|
67
|
+
escape.push(byte.unpack('C')[0])
|
68
|
+
end
|
69
|
+
escape_return, padding_length = handle_escape(escape)
|
70
|
+
case escape_return
|
71
|
+
when 1
|
72
|
+
4.times do
|
73
|
+
file << [0x1b].pack('C')
|
74
|
+
end
|
75
|
+
when String
|
76
|
+
received_checksum_bytes = escape_return
|
77
|
+
end_of_transmission_found = true
|
78
|
+
break
|
79
|
+
end
|
80
|
+
else
|
81
|
+
file << [bytes].pack('N')
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
return [nil, nil, data] unless end_of_transmission_found
|
86
|
+
|
87
|
+
# calculate CRC16 over all received bytes (except last 2 - they contain the checksum itself)
|
88
|
+
raw.chop!.chop!
|
89
|
+
calculated_checksum = CRC16.crc16(raw)
|
90
|
+
calculated_checksum = (calculated_checksum ^ 0xffff)
|
91
|
+
calculated_checksum = ((calculated_checksum & 0xff00) >> 8) | ((calculated_checksum & 0x00ff) << 8)
|
92
|
+
# unpack the checksum we received
|
93
|
+
received_checksum = received_checksum_bytes.unpack('n')[0]
|
94
|
+
|
95
|
+
return [nil, false, data[io.pos..-1]] unless calculated_checksum == received_checksum
|
96
|
+
return [file[0..-(padding_length+1)], true, data[io.pos..-1]]
|
97
|
+
end
|
98
|
+
def self.writefile(io, file)
|
99
|
+
source = String.new(file)
|
100
|
+
result = String.new
|
101
|
+
|
102
|
+
# add transport begin header
|
103
|
+
result << [0x1b1b1b1b, 0x01010101].pack('NN')
|
104
|
+
|
105
|
+
while not source.empty?
|
106
|
+
value = source.unpack('N')[0]
|
107
|
+
if value == 0x1b1b1b1b
|
108
|
+
result << [0x1b1b1b1b].pack('N')
|
109
|
+
result << source.slice!(0,4)
|
110
|
+
else
|
111
|
+
result << source.slice!(0,1)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# calculate padding length
|
116
|
+
padding_length = (4-(file.length % 4)) % 4
|
117
|
+
|
118
|
+
# add padding
|
119
|
+
padding_length.times do
|
120
|
+
result << 0x00
|
121
|
+
end
|
122
|
+
# add transmission end header
|
123
|
+
result << [0x1b1b1b1b, 0x1a, padding_length].pack('NCC')
|
124
|
+
|
125
|
+
# calculate checksum
|
126
|
+
checksum = CRC16.crc16(result)
|
127
|
+
checksum = (checksum ^ 0xffff)
|
128
|
+
result << [(checksum & 0x00ff), ((checksum >> 8) & 0x00ff)].pack('CC')
|
129
|
+
|
130
|
+
io << result
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.handle_escape(bytes)
|
134
|
+
# print "escape sequence: "
|
135
|
+
if bytes[0] == 0x01 and bytes[1] == 0x01 and bytes[2] == 0x01 and bytes[3] == 0x01
|
136
|
+
# puts "data transmission v1"
|
137
|
+
elsif bytes[0] == 0x1a
|
138
|
+
# puts "end of data transmission (padding: #{bytes[1]}, checksum: 0x#{bytes[2].to_s(16)}#{bytes[3].to_s(16)})"
|
139
|
+
return "" << bytes[2] << bytes[3], bytes[1]
|
140
|
+
elsif bytes[0] == 0x02
|
141
|
+
# puts "data transmission v2"
|
142
|
+
elsif bytes[0] == 0x03
|
143
|
+
# puts "v2 set timeout"
|
144
|
+
elsif bytes[0] == 0x04
|
145
|
+
# puts "v2 set block size"
|
146
|
+
elsif bytes[0] == 0x1b and bytes[1] == 0x1b and bytes[2] == 0x1b and bytes[3] == 0x1b
|
147
|
+
# puts "literal escape :("
|
148
|
+
return 1, 0
|
149
|
+
else
|
150
|
+
# print "unknown ["
|
151
|
+
# print "0x%08x" % escape
|
152
|
+
# puts "]"
|
153
|
+
end
|
154
|
+
return 0, 0
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|