ruby-sml 0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|