nstrct 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +26 -0
- data/LICENSE.txt +21 -0
- data/README.md +40 -0
- data/cross_platform_test +83 -0
- data/lib/nstrct.rb +3 -0
- data/lib/nstrct/argument.rb +149 -0
- data/lib/nstrct/frame.rb +62 -0
- data/lib/nstrct/instruction.rb +68 -0
- data/lib/nstrct/version.rb +3 -0
- data/nstrct.gemspec +21 -0
- data/spec/protocol_spec.rb +27 -0
- data/spec/spec_helper.rb +1 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e2087a496c196012c63735b96ff04f1ab6d51c79
|
4
|
+
data.tar.gz: 669624331f0b1a78b122e926ddc1d703ddaa614f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff6574cb663aca80b4bee655b3e7a93a9a60be152b8213636402c39b33ccbcc3e14c8116a5dab061f820167f6a450d28c40ed4c683ff5a8ecf4096ecef57fd1f
|
7
|
+
data.tar.gz: 1929493e6b70b29c39d86bdc1e75e91758f123d445e634f462f7ab7c9b44ab5ae1cdc93b811e569a073cd6ee47a1910af4e093d45a72586fd9c070c0f6da99b3
|
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
.DS_Store
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
nstrct (0.0.3)
|
5
|
+
digest-crc
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: http://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.2.5)
|
11
|
+
digest-crc (0.4.0)
|
12
|
+
rspec (2.14.1)
|
13
|
+
rspec-core (~> 2.14.0)
|
14
|
+
rspec-expectations (~> 2.14.0)
|
15
|
+
rspec-mocks (~> 2.14.0)
|
16
|
+
rspec-core (2.14.7)
|
17
|
+
rspec-expectations (2.14.4)
|
18
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
19
|
+
rspec-mocks (2.14.4)
|
20
|
+
|
21
|
+
PLATFORMS
|
22
|
+
ruby
|
23
|
+
|
24
|
+
DEPENDENCIES
|
25
|
+
nstrct!
|
26
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 ElectricFeel Mobility Systems GmbH, Joël Gähwiler
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# nstrct-ruby
|
2
|
+
|
3
|
+
**a multi-purpose binary protocol for instruction interchange**
|
4
|
+
|
5
|
+
Interchange formats like json or xml are great to keep data visible, but due to their parse and pack complexity they aren't used in embedded applications. There are alternatives like msgpack or Google's protocol buffer, which allow a more binary representation of data, but these protcols are still heavy and developers tend to rather implement their own 'simple' binary protocols instead of porting or using the big ones.
|
6
|
+
|
7
|
+
The protcol **nstrct** is designed to be an alternative in those situations where a tiny and versatile protocol is needed. The main transportable unit in nstrct are **instructions** which carry a dynamic amount of data in the form of **arguments**. Each instruction is identified by a code between 0-65535 which can be used by two communicating applications to identify the blueprint of the message. Arguments support all standard types of integers(boolean, int8-64, uint8-64, float32/64), strings, and arrays of integers or strings. There is no support for hashes by design to keep the pack and unpacking functions as small as possible. [Check the main repository for the binary layout of the instructions](http://github.com/nstrct/nstrct).
|
8
|
+
|
9
|
+
**Start using nstrct by getting the library for your favorite programming language:**
|
10
|
+
|
11
|
+
* [C/C++ (nstrct-c)](http://github.com/nstrct/nstrct-c)
|
12
|
+
* [Ruby (nstrct-ruby)](http://github.com/nstrct/nstrct-ruby)
|
13
|
+
* [Obj-C (nstrct-objc)](http://github.com/nstrct/nstrct-objc)
|
14
|
+
* [Java (nstrct-c)](http://github.com/nstrct/nstrct-java)
|
15
|
+
|
16
|
+
_This software has been open sourced by [ElectricFeel Mobility Systems Gmbh](http://electricfeel.com) and is further maintained by [Joël Gähwiler](http://github.com/256dpi)._
|
17
|
+
|
18
|
+
## Instruction Composing
|
19
|
+
|
20
|
+
A simple example:
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
instruction = Nstrct::Instruction.new(382)
|
24
|
+
bytes = instruction.pack
|
25
|
+
```
|
26
|
+
|
27
|
+
A more complex example:
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
instruction = Nstrct::Instruction.build_instruction(232, [:boolean, true], [:int8, 2], [:float32, 1.0], [[:uint16], [54, 23, 1973]])
|
31
|
+
instruction.pack
|
32
|
+
```
|
33
|
+
|
34
|
+
## Instruction Processing
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
instruction = Nstrct::Instruction.parse(bytes)
|
38
|
+
instruction.code
|
39
|
+
instruction.arguments[0].datatype
|
40
|
+
```
|
data/cross_platform_test
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
6
|
+
require 'nstrct'
|
7
|
+
|
8
|
+
mode = nil
|
9
|
+
|
10
|
+
MIN = {
|
11
|
+
int8: (2**7)*-1,
|
12
|
+
int16: (2**15)*-1,
|
13
|
+
int32: (2**31)*-1,
|
14
|
+
int64: (2**63)*-1
|
15
|
+
}
|
16
|
+
|
17
|
+
MAX = {
|
18
|
+
uint8: (2**8)-1,
|
19
|
+
uint16: (2**16)-1,
|
20
|
+
uint32: (2**32)-1,
|
21
|
+
uint64: (2**64)-1,
|
22
|
+
float32: 3.4028234663852886*(10**38),
|
23
|
+
float64: 1.7976931348623157*(10**308)
|
24
|
+
}
|
25
|
+
|
26
|
+
def assert test, exp
|
27
|
+
unless exp
|
28
|
+
puts test
|
29
|
+
exit!
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
OptionParser.new do |opts|
|
34
|
+
opts.banner = 'Usage: cross_platform_test [options]'
|
35
|
+
opts.on('-p', '--process', 'process bytes at STDIN and return result') do |p|
|
36
|
+
mode = :process
|
37
|
+
end
|
38
|
+
opts.on('-g', '--generate', 'generate bytes and write to STDOUT') do |g|
|
39
|
+
mode = :generate
|
40
|
+
end
|
41
|
+
end.parse!
|
42
|
+
|
43
|
+
if mode == :generate
|
44
|
+
i = Nstrct::Instruction.build MAX[:uint16],
|
45
|
+
[:boolean, false],
|
46
|
+
[:int8, MIN[:int8]],
|
47
|
+
[:int16, MIN[:int16]],
|
48
|
+
[:int32, MIN[:int32]],
|
49
|
+
[:int64, MIN[:int64]],
|
50
|
+
[:uint8, MAX[:uint8]],
|
51
|
+
[:uint16, MAX[:uint16]],
|
52
|
+
[:uint32, MAX[:uint32]],
|
53
|
+
[:uint64, MAX[:uint64]],
|
54
|
+
[:float32, MAX[:float32]],
|
55
|
+
[:float64, MAX[:float64]],
|
56
|
+
[:string, 'hello world'],
|
57
|
+
[:string, ''],
|
58
|
+
[[:uint16], [2443, 3443]]
|
59
|
+
buf = Nstrct::Frame.new(i).pack
|
60
|
+
STDOUT.write [buf.size].pack('L>')
|
61
|
+
STDOUT.write buf
|
62
|
+
elsif mode == :process
|
63
|
+
length = STDIN.read(4).unpack('L>')[0]
|
64
|
+
i = Nstrct::Frame.parse(STDIN.read(length)).instruction
|
65
|
+
assert ' boolean value error', !i.arguments[0].value
|
66
|
+
assert ' int8 value error', i.arguments[1].value == MIN[:int8]
|
67
|
+
assert ' int16 value error', i.arguments[2].value == MIN[:int16]
|
68
|
+
assert ' int32 value error', i.arguments[3].value == MIN[:int32]
|
69
|
+
assert ' int64 value error', i.arguments[4].value == MIN[:int64]
|
70
|
+
assert ' uint8 value error', i.arguments[5].value == MAX[:uint8]
|
71
|
+
assert ' uint16 value error', i.arguments[6].value == MAX[:uint16]
|
72
|
+
assert ' uint32 value error', i.arguments[7].value == MAX[:uint32]
|
73
|
+
assert ' uint64 value error', i.arguments[8].value == MAX[:uint64]
|
74
|
+
assert ' float32 value error', i.arguments[9].value == MAX[:float32]
|
75
|
+
assert ' float64 value error', i.arguments[10].value == MAX[:float64]
|
76
|
+
assert ' string value error', i.arguments[11].value.eql?('hello world')
|
77
|
+
assert ' empty string value error', i.arguments[12].value.eql?('')
|
78
|
+
assert ' array uint16 value 1 error', i.arguments[13].value[0] == 2443
|
79
|
+
assert ' array uint16 value 2 error', i.arguments[13].value[1] == 3443
|
80
|
+
puts ' tests passed'
|
81
|
+
else
|
82
|
+
puts 'please specify a run mode'
|
83
|
+
end
|
data/lib/nstrct.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
module Nstrct
|
2
|
+
|
3
|
+
class Argument
|
4
|
+
|
5
|
+
# Available datatypes and their argument code
|
6
|
+
DATATYPES = {
|
7
|
+
boolean: 1,
|
8
|
+
int8: 10,
|
9
|
+
int16: 11,
|
10
|
+
int32: 12,
|
11
|
+
int64: 13,
|
12
|
+
uint8: 14,
|
13
|
+
uint16: 15,
|
14
|
+
uint32: 16,
|
15
|
+
uint64: 17,
|
16
|
+
float32: 21,
|
17
|
+
float64: 22,
|
18
|
+
string: 31,
|
19
|
+
array: 32
|
20
|
+
}
|
21
|
+
|
22
|
+
# Get the datatype of a argument code
|
23
|
+
def self.datatype_by_for_argument_code code
|
24
|
+
DATATYPES.detect{ |k,v| v == code }[0]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Parse a single value of a buffer
|
28
|
+
def self.parse_value datatype, data
|
29
|
+
case datatype
|
30
|
+
when :boolean
|
31
|
+
return data.slice!(0).unpack('C')[0] == 1
|
32
|
+
when :int8
|
33
|
+
return data.slice!(0).unpack('c')[0]
|
34
|
+
when :int16
|
35
|
+
return data.slice!(0..1).unpack('s>')[0]
|
36
|
+
when :int32
|
37
|
+
return data.slice!(0..3).unpack('l>')[0]
|
38
|
+
when :int64
|
39
|
+
return data.slice!(0..7).unpack('q>')[0]
|
40
|
+
when :uint8
|
41
|
+
return data.slice!(0).unpack('C')[0]
|
42
|
+
when :uint16
|
43
|
+
return data.slice!(0..1).unpack('S>')[0]
|
44
|
+
when :uint32
|
45
|
+
return data.slice!(0..3).unpack('L>')[0]
|
46
|
+
when :uint64
|
47
|
+
return data.slice!(0..7).unpack('Q>')[0]
|
48
|
+
when :float32
|
49
|
+
return data.slice!(0..3).unpack('g')[0]
|
50
|
+
when :float64
|
51
|
+
return data.slice!(0..7).unpack('G')[0]
|
52
|
+
when :string
|
53
|
+
length = data.slice!(0).unpack('C')[0]
|
54
|
+
return length > 0 ? data.slice!(0..length-1) : ''
|
55
|
+
when :array
|
56
|
+
raise 'cannot parse array value directly'
|
57
|
+
else
|
58
|
+
raise "datatype '#{datatype}' not recognized"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Parse a single argument from a buffer
|
63
|
+
def self.parse data
|
64
|
+
datatype = self.datatype_by_for_argument_code(data.slice!(0).unpack('C')[0])
|
65
|
+
if datatype == :array
|
66
|
+
array_datatype = self.datatype_by_for_argument_code(data.slice!(0).unpack('C')[0])
|
67
|
+
array_num_elements = data.slice!(0).unpack('C')[0]
|
68
|
+
values = []
|
69
|
+
array_num_elements.times do
|
70
|
+
values << self.parse_value(array_datatype, data)
|
71
|
+
end
|
72
|
+
return self.new(array_datatype, values, true)
|
73
|
+
else
|
74
|
+
return self.new(datatype, self.parse_value(datatype, data), false)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
attr_reader :datatype, :value, :array
|
79
|
+
|
80
|
+
# Instantiate a new Argument providing its datatype, value and arrayness
|
81
|
+
def initialize datatype, value, array
|
82
|
+
@datatype, @value, @array = datatype, value, array
|
83
|
+
end
|
84
|
+
|
85
|
+
# Pack a single value in a buffer
|
86
|
+
def pack_value datatype, value, data
|
87
|
+
case datatype
|
88
|
+
when :boolean
|
89
|
+
data += [value ? 1 : 0].pack('C')
|
90
|
+
when :int8
|
91
|
+
data += [value].pack('c')
|
92
|
+
when :int16
|
93
|
+
data += [value].pack('s>')
|
94
|
+
when :int32
|
95
|
+
data += [value].pack('l>')
|
96
|
+
when :int64
|
97
|
+
data += [value].pack('q>')
|
98
|
+
when :uint8
|
99
|
+
data += [value].pack('C')
|
100
|
+
when :uint16
|
101
|
+
data += [value].pack('S>')
|
102
|
+
when :uint32
|
103
|
+
data += [value].pack('L>')
|
104
|
+
when :uint64
|
105
|
+
data += [value].pack('Q>')
|
106
|
+
when :float32
|
107
|
+
data += [value].pack('g')
|
108
|
+
when :float64
|
109
|
+
data += [value].pack('G')
|
110
|
+
when :string
|
111
|
+
data += [value.size].pack('C')
|
112
|
+
data += value
|
113
|
+
when :array
|
114
|
+
raise 'cannot pack array value directly'
|
115
|
+
else
|
116
|
+
raise "datatype '#{datatype}' not recognized"
|
117
|
+
end
|
118
|
+
data
|
119
|
+
end
|
120
|
+
|
121
|
+
# Pack a single argument in a buffer
|
122
|
+
def pack
|
123
|
+
data = ''
|
124
|
+
if @array
|
125
|
+
data += [DATATYPES[:array]].pack('C')
|
126
|
+
data += [DATATYPES[@datatype]].pack('C')
|
127
|
+
data += [@value.size].pack('C')
|
128
|
+
@value.each do |val|
|
129
|
+
data = pack_value(@datatype, val, data)
|
130
|
+
end
|
131
|
+
else
|
132
|
+
data += [DATATYPES[datatype]].pack('C')
|
133
|
+
data = pack_value(@datatype, @value, data)
|
134
|
+
end
|
135
|
+
data
|
136
|
+
end
|
137
|
+
|
138
|
+
# Return comparable inspection
|
139
|
+
def inspect
|
140
|
+
if @array
|
141
|
+
"[#{@datatype.inspect}]=#{@value}"
|
142
|
+
else
|
143
|
+
"#{@datatype.inspect}=#{@value}"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
data/lib/nstrct/frame.rb
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'digest/crc32'
|
2
|
+
|
3
|
+
module Nstrct
|
4
|
+
|
5
|
+
class Frame
|
6
|
+
|
7
|
+
FRAME_OVERHEAD = 8
|
8
|
+
FRAME_START = 0x55
|
9
|
+
FRAME_END = 0xAA
|
10
|
+
|
11
|
+
def self.crc32 buffer
|
12
|
+
Digest::CRC32.checksum buffer
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.available? buffer
|
16
|
+
if buffer.size >= 1
|
17
|
+
raise 'start of frame invalid' unless buffer.slice(0).unpack('C')[0] == FRAME_START
|
18
|
+
if buffer.size >= 3
|
19
|
+
payload_length = buffer.slice(1..2).unpack('S>')[0]
|
20
|
+
if buffer.size >= (payload_length+FRAME_OVERHEAD)
|
21
|
+
raise 'end of frame invalid' unless buffer.slice(payload_length+FRAME_OVERHEAD-1).unpack('C')[0] == FRAME_END
|
22
|
+
return true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
false
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.parse buffer
|
30
|
+
raise 'no frame available' unless self.available?(buffer)
|
31
|
+
buffer.slice!(0) # remove start of frame
|
32
|
+
length = buffer.slice!(0..1).unpack('S>')[0]
|
33
|
+
payload = buffer.slice!(0..length-1)
|
34
|
+
checksum = buffer.slice!(0..3).unpack('L>')[0]
|
35
|
+
buffer.slice!(0) # remove end of frame
|
36
|
+
raise 'checksum invalid' unless checksum == crc32(payload)
|
37
|
+
self.new(Instruction.parse(payload))
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_accessor :instruction
|
41
|
+
|
42
|
+
def initialize instruction
|
43
|
+
@instruction = instruction
|
44
|
+
end
|
45
|
+
|
46
|
+
def pack
|
47
|
+
payload = @instruction.pack
|
48
|
+
frame = [FRAME_START].pack('C')
|
49
|
+
frame += [payload.size].pack('S>')
|
50
|
+
frame += payload
|
51
|
+
frame += [Frame.crc32(payload)].pack('L>')
|
52
|
+
frame + [FRAME_END].pack('C')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return a comparable inspection
|
56
|
+
def inspect
|
57
|
+
"#<Nstrct::Frame instruction=#{@instruction.inspect}>"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Nstrct
|
2
|
+
|
3
|
+
class Instruction
|
4
|
+
|
5
|
+
attr_accessor :code, :arguments
|
6
|
+
|
7
|
+
# Parse one message from the data stream.
|
8
|
+
def self.parse data
|
9
|
+
code = data.slice!(0..1).unpack('s>')[0]
|
10
|
+
num_arguments = data.slice!(0).unpack('C')[0]
|
11
|
+
data.slice!(0..1) # num_array_elements
|
12
|
+
arguments = []
|
13
|
+
num_arguments.times do
|
14
|
+
arguments << Nstrct::Argument.parse(data)
|
15
|
+
end
|
16
|
+
self.new(code, arguments)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Build an instruction for a code and some arguments.
|
20
|
+
#
|
21
|
+
# Message.build_instruction 54, [ :boolean, true], [[:int8], [7, 8, 9]] ]
|
22
|
+
#
|
23
|
+
def self.build code, *args
|
24
|
+
arguments = []
|
25
|
+
args.each do |arg|
|
26
|
+
if arg[0].is_a?(Array)
|
27
|
+
arguments << Nstrct::Argument.new(arg[0][0], arg[1], true)
|
28
|
+
else
|
29
|
+
arguments << Nstrct::Argument.new(arg[0], arg[1], false)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
self.new(code, arguments)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Instantiate a new instruction by its code and alist of arguments
|
36
|
+
def initialize code, arguments=[]
|
37
|
+
@code, @arguments = code, arguments
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get all the arguments values
|
41
|
+
def argument_values
|
42
|
+
@arguments.map{ |arg| arg.value }
|
43
|
+
end
|
44
|
+
|
45
|
+
# get all elements in arrays
|
46
|
+
def array_elements
|
47
|
+
@arguments.inject(0){ |sum, a| sum + (a.array ? a.value.size : 0) }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Pack a single instruction in a buffer
|
51
|
+
def pack
|
52
|
+
message = [@code].pack('s>')
|
53
|
+
message += [@arguments.size].pack('C')
|
54
|
+
message += [array_elements].pack('s>')
|
55
|
+
@arguments.each do |arg|
|
56
|
+
message += arg.pack
|
57
|
+
end
|
58
|
+
message
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return a comparable inspection
|
62
|
+
def inspect
|
63
|
+
"#<Nstrct::Instructon code=#{@code.inspect}, arguments=#{@arguments.inspect}>"
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/nstrct.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
$:.push File.expand_path('../lib', __FILE__)
|
2
|
+
require 'nstrct/version'
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'nstrct'
|
6
|
+
s.version = Nstrct::VERSION
|
7
|
+
|
8
|
+
s.summary = 'a multi-purpose binary protocol for instruction interchange'
|
9
|
+
s.authors = 'Joël Gähwiler'
|
10
|
+
s.email = 'nstrct@256dpi.ch'
|
11
|
+
s.homepage = 'http://github.com/nstrct'
|
12
|
+
|
13
|
+
s.description = "Interchange formats like json or xml are great to keep data visible, but due to their parse and pack complexity they aren't used in embedded applications. There are alternatives like msgpack or Google's protocol buffer, which allow a more binary representation of data, but these protcols are still heavy and developers tend to rather implement their own 'simple' binary protocols instead of porting or using the big ones."
|
14
|
+
|
15
|
+
s.license = 'MIT'
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
|
20
|
+
s.add_runtime_dependency 'digest-crc'
|
21
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Nstrct::Instruction do
|
4
|
+
|
5
|
+
it 'should pack and unpack an empty instruction' do
|
6
|
+
instruction1 = Nstrct::Instruction.new(382, [])
|
7
|
+
instruction2 = Nstrct::Instruction.parse(instruction1.pack)
|
8
|
+
instruction1.inspect.should == instruction2.inspect
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'should pack and unpack an instructionw with arguments' do
|
12
|
+
instruction1 = Nstrct::Instruction.build(232, [:float32, 1.0 ], [:boolean, true], [:int8, 2], [:float32, 1.0], [[:uint16], [54, 23, 1973]])
|
13
|
+
instruction2 = Nstrct::Instruction.parse(instruction1.pack)
|
14
|
+
instruction1.inspect.should == instruction2.inspect
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Nstrct::Frame do
|
20
|
+
|
21
|
+
it 'should pack and unpack a frame' do
|
22
|
+
frame1 = Nstrct::Frame.new(Nstrct::Instruction.new(132, []))
|
23
|
+
frame2 = Nstrct::Frame.parse(frame1.pack)
|
24
|
+
frame1.inspect.should == frame2.inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'nstrct'
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nstrct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joël Gähwiler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: digest-crc
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Interchange formats like json or xml are great to keep data visible,
|
28
|
+
but due to their parse and pack complexity they aren't used in embedded applications.
|
29
|
+
There are alternatives like msgpack or Google's protocol buffer, which allow a more
|
30
|
+
binary representation of data, but these protcols are still heavy and developers
|
31
|
+
tend to rather implement their own 'simple' binary protocols instead of porting
|
32
|
+
or using the big ones.
|
33
|
+
email: nstrct@256dpi.ch
|
34
|
+
executables: []
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- .gitignore
|
39
|
+
- Gemfile
|
40
|
+
- Gemfile.lock
|
41
|
+
- LICENSE.txt
|
42
|
+
- README.md
|
43
|
+
- cross_platform_test
|
44
|
+
- lib/nstrct.rb
|
45
|
+
- lib/nstrct/argument.rb
|
46
|
+
- lib/nstrct/frame.rb
|
47
|
+
- lib/nstrct/instruction.rb
|
48
|
+
- lib/nstrct/version.rb
|
49
|
+
- nstrct.gemspec
|
50
|
+
- spec/protocol_spec.rb
|
51
|
+
- spec/spec_helper.rb
|
52
|
+
homepage: http://github.com/nstrct
|
53
|
+
licenses:
|
54
|
+
- MIT
|
55
|
+
metadata: {}
|
56
|
+
post_install_message:
|
57
|
+
rdoc_options: []
|
58
|
+
require_paths:
|
59
|
+
- lib
|
60
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
requirements: []
|
71
|
+
rubyforge_project:
|
72
|
+
rubygems_version: 2.0.3
|
73
|
+
signing_key:
|
74
|
+
specification_version: 4
|
75
|
+
summary: a multi-purpose binary protocol for instruction interchange
|
76
|
+
test_files:
|
77
|
+
- spec/protocol_spec.rb
|
78
|
+
- spec/spec_helper.rb
|