cosmos-ccsds_transfer_frames 0.1.1
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +674 -0
- data/README.md +81 -0
- data/Rakefile +6 -0
- data/bin/setup +8 -0
- data/cosmos-ccsds_transfer_frames.gemspec +35 -0
- data/lib/cosmos/ccsds_transfer_frames.rb +2 -0
- data/lib/cosmos/ccsds_transfer_frames/ccsds_transfer_frame_protocol.rb +316 -0
- data/lib/cosmos/ccsds_transfer_frames/version.rb +5 -0
- metadata +131 -0
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Cosmos::CcsdsTransferFrames
|
2
|
+
|
3
|
+
This gem contains a CCSDS transfer frame protocol for use with the Ball Aerospace COSMOS application.
|
4
|
+
|
5
|
+
The protocol extracts CCSDS space packets from CCSDS transfer frames, optionally prefixing each packet with the transfer frame headers of the frame where it started.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
This gem is intended to be installed as a 'gem based target/tool' (see http://cosmosrb.com/docs/gemtargets/) in COSMOS and made available for use as a normal protocol in a target command and telemetry server configuration. Note that the protocol provided in this gem is neither a target nor a tool in the COSMOS sense.
|
10
|
+
|
11
|
+
In order to make this protocol available for use in your COSMOS targets, add this line to the Gemfile of your COSMOS project:
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
gem 'cosmos-ccsds_transfer_frames'
|
15
|
+
```
|
16
|
+
|
17
|
+
and then execute
|
18
|
+
|
19
|
+
```sh
|
20
|
+
$ bundle
|
21
|
+
```
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
In order to use this protocol in your COSMOS target first make sure to add the following to the `target.txt` file for your target:
|
26
|
+
|
27
|
+
```
|
28
|
+
REQUIRE cosmos/ccsds_transfer_frames
|
29
|
+
```
|
30
|
+
|
31
|
+
Then add the protocol in the command and telemetry server configuration in an interface definition as usual. The full explicit module namespace is necessary, for example:
|
32
|
+
|
33
|
+
```
|
34
|
+
INTERFACE INTERFACE_NAME tcpip_client_interface.rb localhost 12345 12345 10.0 nil
|
35
|
+
PROTOCOL Cosmos::CcsdsTransferFrames::CcsdsTranferFrameProtocol 1115 0 true true
|
36
|
+
TARGET TARGET_NAME
|
37
|
+
```
|
38
|
+
|
39
|
+
This would set up the protocol to expect transfer frames with:
|
40
|
+
|
41
|
+
* A total size of 1115 bytes.
|
42
|
+
* No secondary header.
|
43
|
+
* Operational control field.
|
44
|
+
* Frame error control field.
|
45
|
+
* No prefixing of packets (default).
|
46
|
+
* Discarding of idle packets (default).
|
47
|
+
|
48
|
+
For detailed information about the available configuration parameters for the protocol, please consult the yard inline source code documentation in `lib/cosmos/ccsds_transfer_frames/ccsds_transfer_frame_protocol.rb`
|
49
|
+
|
50
|
+
## Development
|
51
|
+
|
52
|
+
[](https://travis-ci.org/ienorand/cosmos-ccsds_transfer_frames)
|
53
|
+
|
54
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests.
|
55
|
+
|
56
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in the gemspec file, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
57
|
+
|
58
|
+
## Contributing
|
59
|
+
|
60
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/ienorand/cosmos-ccsds_transfer_frames. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
61
|
+
|
62
|
+
## License
|
63
|
+
|
64
|
+
This program is free software: you can redistribute it and/or modify
|
65
|
+
it under the terms of the GNU General Public License as published by
|
66
|
+
the Free Software Foundation, either version 3 of the License, or
|
67
|
+
(at your option) any later version.
|
68
|
+
|
69
|
+
This program is distributed in the hope that it will be useful,
|
70
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
71
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
72
|
+
GNU General Public License for more details.
|
73
|
+
|
74
|
+
You should have received a copy of the GNU General Public License
|
75
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
76
|
+
|
77
|
+
A copy of the GPLv3.0 is provided in [LICENSE.txt](LICENSE.txt).
|
78
|
+
|
79
|
+
## Code of Conduct
|
80
|
+
|
81
|
+
Everyone interacting in the Cosmos::CcsdsTransferFrames project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/ienorand/cosmos-ccsds_transfer_frames/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "cosmos/ccsds_transfer_frames/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cosmos-ccsds_transfer_frames"
|
8
|
+
spec.version = Cosmos::CcsdsTransferFrames::VERSION
|
9
|
+
spec.authors = ["Martin Erik Werner"]
|
10
|
+
spec.email = ["martinerikwerner@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = "CCSDS transfer frame protocol for use in COSMOS"
|
13
|
+
spec.description = <<-EOF
|
14
|
+
A Ball Aerospace COSMOS 'tool' gem which provides a read-only protocol
|
15
|
+
for extracting CCSDS space packets from CCSDS transfer frames, optionally
|
16
|
+
prefixing each packet, with the transfer frame headers of the frame where
|
17
|
+
it started.
|
18
|
+
EOF
|
19
|
+
spec.homepage = "https://github.com/ienorand/cosmos-ccsds_transfer_frames"
|
20
|
+
spec.license = "GPL-3.0"
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
23
|
+
f.match(%r{^(test|spec|features)/})
|
24
|
+
end
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_dependency "cosmos", "~> 4"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
spec.add_development_dependency "ruby-termios", "~> 0.9"
|
35
|
+
end
|
@@ -0,0 +1,316 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
|
3
|
+
# Copyright 2018 Fredrik Persson <u.fredrik.persson@gmail.com>
|
4
|
+
# Martin Erik Werner <martinerikwerner@gmail.com>
|
5
|
+
#
|
6
|
+
# This program is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# This program is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require 'cosmos/config/config_parser'
|
20
|
+
require 'cosmos/packets/binary_accessor'
|
21
|
+
require 'cosmos/interfaces/protocols/protocol'
|
22
|
+
require 'thread'
|
23
|
+
|
24
|
+
module Cosmos
|
25
|
+
module CcsdsTransferFrames
|
26
|
+
# Given a stream of ccsds transfer frames, extract ccsds space packets based
|
27
|
+
# on the first header pointer and packet lengths.
|
28
|
+
#
|
29
|
+
# Only read is supported.
|
30
|
+
class CcsdsTransferFrameProtocol < Protocol
|
31
|
+
FRAME_PRIMARY_HEADER_LENGTH = 6
|
32
|
+
FIRST_HEADER_POINTER_OFFSET = 4
|
33
|
+
# last 11 bits
|
34
|
+
FIRST_HEADER_POINTER_MASK = [0b00000111, 0b11111111]
|
35
|
+
IDLE_FRAME_FIRST_HEADER_POINTER = 0b11111111110
|
36
|
+
NO_PACKET_START_FIRST_HEADER_POINTER = 0b11111111111
|
37
|
+
FRAME_VIRTUAL_CHANNEL_BIT_OFFSET = 12
|
38
|
+
FRAME_VIRTUAL_CHANNEL_BITS = 3
|
39
|
+
VIRTUAL_CHANNEL_COUNT = 8
|
40
|
+
FRAME_OPERATIONAL_CONTROL_FIELD_LENGTH = 4
|
41
|
+
FRAME_ERROR_CONTROL_FIELD_LENGTH = 2
|
42
|
+
SPACE_PACKET_HEADER_LENGTH = 6
|
43
|
+
SPACE_PACKET_LENGTH_BIT_OFFSET = 4 * 8
|
44
|
+
SPACE_PACKET_LENGTH_BITS = 2 * 8
|
45
|
+
SPACE_PACKET_APID_BITS = 14
|
46
|
+
SPACE_PACKET_APID_BIT_OFFSET = 2 * 8 - SPACE_PACKET_APID_BITS
|
47
|
+
IDLE_PACKET_APID = 0b11111111111111
|
48
|
+
|
49
|
+
# @param transfer_frame_length [Integer] Length of transfer frame in bytes
|
50
|
+
# @param transfer_frame_secondary_header_length [Integer] Length of
|
51
|
+
# transfer frame secondary header in bytes
|
52
|
+
# @param transfer_frame_has_operational_control_field [Boolean] Flag
|
53
|
+
# indicating if the transfer frame operational control field is
|
54
|
+
# present or not
|
55
|
+
# @param transfer_frame_has_frame_error_control_field [Boolean] Flag
|
56
|
+
# indicating if the transfer frame error control field is present or
|
57
|
+
# not
|
58
|
+
# @param prefix_packets [Boolean] Flag indicating if each space packet should
|
59
|
+
# be prefixed with the transfer frame headers from the frame where
|
60
|
+
# it started.
|
61
|
+
# @param include_idle_packets [Boolean] Flag indicating if idle packets
|
62
|
+
# should be included or discarded.
|
63
|
+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
|
64
|
+
def initialize(
|
65
|
+
transfer_frame_length,
|
66
|
+
transfer_frame_secondary_header_length,
|
67
|
+
transfer_frame_has_operational_control_field,
|
68
|
+
transfer_frame_has_frame_error_control_field,
|
69
|
+
prefix_packets = false,
|
70
|
+
include_idle_packets = false,
|
71
|
+
allow_empty_data = nil)
|
72
|
+
super(allow_empty_data)
|
73
|
+
|
74
|
+
@frame_length = Integer(transfer_frame_length)
|
75
|
+
|
76
|
+
@frame_headers_length = FRAME_PRIMARY_HEADER_LENGTH + Integer(transfer_frame_secondary_header_length)
|
77
|
+
|
78
|
+
@frame_trailer_length = 0
|
79
|
+
has_ocf = ConfigParser.handle_true_false(transfer_frame_has_operational_control_field)
|
80
|
+
@frame_trailer_length += FRAME_OPERATIONAL_CONTROL_FIELD_LENGTH if has_ocf
|
81
|
+
has_fecf = ConfigParser.handle_true_false(transfer_frame_has_frame_error_control_field)
|
82
|
+
@frame_trailer_length += FRAME_ERROR_CONTROL_FIELD_LENGTH if has_fecf
|
83
|
+
|
84
|
+
@frame_data_field_length = @frame_length - @frame_headers_length - @frame_trailer_length
|
85
|
+
|
86
|
+
@packet_prefix_length = 0
|
87
|
+
@prefix_packets = ConfigParser.handle_true_false(prefix_packets)
|
88
|
+
@packet_prefix_length += @frame_headers_length if @prefix_packets
|
89
|
+
|
90
|
+
@include_idle_packets = ConfigParser.handle_true_false(include_idle_packets)
|
91
|
+
end
|
92
|
+
|
93
|
+
def reset
|
94
|
+
super()
|
95
|
+
@data = ''
|
96
|
+
@virtual_channels = Array.new(VIRTUAL_CHANNEL_COUNT) { VirtualChannel.new }
|
97
|
+
end
|
98
|
+
|
99
|
+
def read_data(data)
|
100
|
+
@data << data
|
101
|
+
|
102
|
+
if (@data.length >= @frame_length)
|
103
|
+
frame = @data.slice!(0, @frame_length)
|
104
|
+
process_frame(frame)
|
105
|
+
end
|
106
|
+
|
107
|
+
packet_data = get_packet()
|
108
|
+
|
109
|
+
# Potentially allow blank string to be sent to other protocols if no
|
110
|
+
# packet is ready in this one
|
111
|
+
if (Symbol === packet_data && packet_data == :STOP && data.length <= 0)
|
112
|
+
return super(data)
|
113
|
+
end
|
114
|
+
|
115
|
+
return packet_data
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
VirtualChannel = Struct.new(:packet_queue, :pending_incomplete_packet_bytes_left) do
|
121
|
+
def initialize(packet_queue: [], pending_incomplete_packet_bytes_left: 0)
|
122
|
+
super(packet_queue, pending_incomplete_packet_bytes_left)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# Get a packet from the virtual channel packet queues of stored packets
|
127
|
+
# from processed frames.
|
128
|
+
#
|
129
|
+
# If idle packets are not included, extracted idle packets are discarded
|
130
|
+
# and extraction is retried until a non-idle packet is found or no more
|
131
|
+
# complete packets are left in any of the virtual channel packet queues.
|
132
|
+
#
|
133
|
+
# @return [String] Packet data, if the queues contained at least one
|
134
|
+
# complete packet.
|
135
|
+
# @return [Symbol] :STOP, if the queues does not contain any complete
|
136
|
+
# packets.
|
137
|
+
def get_packet
|
138
|
+
@virtual_channels.each do |vc|
|
139
|
+
loop do
|
140
|
+
# Skip if there's only a single incomplete packet in the queue.
|
141
|
+
break if (vc.packet_queue.length == 1 &&
|
142
|
+
vc.pending_incomplete_packet_bytes_left > 0)
|
143
|
+
|
144
|
+
packet_data = vc.packet_queue.shift
|
145
|
+
|
146
|
+
break if packet_data.nil?
|
147
|
+
|
148
|
+
return packet_data if @include_idle_packets
|
149
|
+
|
150
|
+
apid = get_space_packet_apid(packet_data[@packet_prefix_length, SPACE_PACKET_HEADER_LENGTH])
|
151
|
+
return packet_data unless (apid == IDLE_PACKET_APID)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
# If the packet queues contains any more whole packets they will be
|
155
|
+
# handled in subsequent calls to this method. Cosmos will ensure that
|
156
|
+
# read_data() is called until it returns :STOP, which allows us to
|
157
|
+
# clear all whole packets.
|
158
|
+
|
159
|
+
# no complete packet for any virtual channel
|
160
|
+
return :STOP
|
161
|
+
end
|
162
|
+
|
163
|
+
# Extract packets from a transfer frame and store them in the packet queue.
|
164
|
+
#
|
165
|
+
# First handles packet continuation of any incomplete packet and then
|
166
|
+
# handles the rest of the packets in the frame.
|
167
|
+
#
|
168
|
+
# @param frame [String] Transfer frame data.
|
169
|
+
def process_frame(frame)
|
170
|
+
first_header_pointer =
|
171
|
+
((frame.bytes[FIRST_HEADER_POINTER_OFFSET] & FIRST_HEADER_POINTER_MASK[0]) << 8) |
|
172
|
+
(frame.bytes[FIRST_HEADER_POINTER_OFFSET + 1] & FIRST_HEADER_POINTER_MASK[1])
|
173
|
+
|
174
|
+
return if (first_header_pointer == IDLE_FRAME_FIRST_HEADER_POINTER)
|
175
|
+
|
176
|
+
virtual_channel = BinaryAccessor.read(
|
177
|
+
FRAME_VIRTUAL_CHANNEL_BIT_OFFSET,
|
178
|
+
FRAME_VIRTUAL_CHANNEL_BITS,
|
179
|
+
:UINT,
|
180
|
+
frame,
|
181
|
+
:BIG_ENDIAN)
|
182
|
+
|
183
|
+
frame_data_field = frame[@frame_headers_length, @frame_data_field_length]
|
184
|
+
|
185
|
+
status = handle_packet_continuation(virtual_channel, frame_data_field, first_header_pointer)
|
186
|
+
return if (Symbol === status && status == :STOP)
|
187
|
+
|
188
|
+
if (frame_data_field.length == @frame_data_field_length)
|
189
|
+
# No continuation packet was completed, and a packet starts in this
|
190
|
+
# frame. Utilise the first header pointer to re-sync to a packet start.
|
191
|
+
frame_data_field.replace(frame_data_field[first_header_pointer..-1])
|
192
|
+
end
|
193
|
+
|
194
|
+
frame_headers = frame[0, @frame_headers_length].clone
|
195
|
+
store_packets(virtual_channel, frame_headers, frame_data_field)
|
196
|
+
end
|
197
|
+
|
198
|
+
# Handle packet continuation when processing a transfer frame.
|
199
|
+
#
|
200
|
+
# Ensures that any incomplete packet first has enough data for the packet
|
201
|
+
# header to determine its length and then ensures that it has enough data
|
202
|
+
# to be complete based on its length.
|
203
|
+
#
|
204
|
+
# @param virtual_channel [Int] Transfer frame virtual channel.
|
205
|
+
# @param frame_data_field [String] Transfer frame data field.
|
206
|
+
# @param first_header_pointer [Int] First header pointer value.
|
207
|
+
def handle_packet_continuation(virtual_channel, frame_data_field, first_header_pointer)
|
208
|
+
vc = @virtual_channels[virtual_channel]
|
209
|
+
if (vc.packet_queue.length > 0 &&
|
210
|
+
vc.packet_queue[-1].length < @packet_prefix_length + SPACE_PACKET_HEADER_LENGTH)
|
211
|
+
# pending incomplete packet does not have header yet
|
212
|
+
rest_of_packet_header_length = @packet_prefix_length + SPACE_PACKET_HEADER_LENGTH - vc.packet_queue[-1].length
|
213
|
+
vc.packet_queue[-1] << frame_data_field.slice!(0, rest_of_packet_header_length)
|
214
|
+
|
215
|
+
space_packet_length = get_space_packet_length(vc.packet_queue[-1][@packet_prefix_length..-1])
|
216
|
+
throw "failed to get space packet length" if Symbol === space_packet_length && space_packet_length == :STOP
|
217
|
+
|
218
|
+
vc.pending_incomplete_packet_bytes_left = space_packet_length - SPACE_PACKET_HEADER_LENGTH
|
219
|
+
end
|
220
|
+
|
221
|
+
if (vc.pending_incomplete_packet_bytes_left >= frame_data_field.length)
|
222
|
+
# continuation of a packet
|
223
|
+
vc.packet_queue[-1] << frame_data_field
|
224
|
+
vc.pending_incomplete_packet_bytes_left -= frame_data_field.length
|
225
|
+
return :STOP
|
226
|
+
end
|
227
|
+
|
228
|
+
if (first_header_pointer == NO_PACKET_START_FIRST_HEADER_POINTER)
|
229
|
+
# This was not a continuation of a packet (or it was a continuation of
|
230
|
+
# an ignored idle packet), wait for another frame to find a packet
|
231
|
+
# start.
|
232
|
+
return :STOP
|
233
|
+
end
|
234
|
+
|
235
|
+
if (vc.pending_incomplete_packet_bytes_left > 0)
|
236
|
+
rest_of_packet = frame_data_field.slice!(0, vc.pending_incomplete_packet_bytes_left)
|
237
|
+
vc.packet_queue[-1] << rest_of_packet
|
238
|
+
vc.pending_incomplete_packet_bytes_left = 0
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# Extract all packets from the remaining frame data field, and store them
|
243
|
+
# in the packet queue.
|
244
|
+
#
|
245
|
+
# It is assumed that packet continuation data from any previously
|
246
|
+
# unfinished packets has been removed from the frame data field prior, and
|
247
|
+
# hence that the given remaining frame data field starts at a space packet
|
248
|
+
# header.
|
249
|
+
#
|
250
|
+
# Handles both complete packets and unfinished packets which will be
|
251
|
+
# finished in a later frame via handle_packet_continuation().
|
252
|
+
#
|
253
|
+
# @param virtual_channel [Int] Transfer frame virtual channel.
|
254
|
+
# @param frame_headers [String] Transfer frame headers, only used if prefixing packets.
|
255
|
+
# @param frame_data_field [String] (Remaining) transfer frame data field.
|
256
|
+
def store_packets(virtual_channel, frame_headers, frame_data_field)
|
257
|
+
vc = @virtual_channels[virtual_channel]
|
258
|
+
while (frame_data_field.length > 0) do
|
259
|
+
if (@prefix_packets)
|
260
|
+
vc.packet_queue << frame_headers.clone
|
261
|
+
else
|
262
|
+
vc.packet_queue << ""
|
263
|
+
end
|
264
|
+
|
265
|
+
if (frame_data_field.length < SPACE_PACKET_HEADER_LENGTH)
|
266
|
+
vc.packet_queue[-1] << frame_data_field
|
267
|
+
vc.pending_incomplete_packet_bytes_left = SPACE_PACKET_HEADER_LENGTH - frame_data_field.length
|
268
|
+
return
|
269
|
+
end
|
270
|
+
|
271
|
+
space_packet_length = get_space_packet_length(frame_data_field)
|
272
|
+
throw "failed to get space packet length" if Symbol === space_packet_length && space_packet_length == :STOP
|
273
|
+
|
274
|
+
if (space_packet_length > frame_data_field.length)
|
275
|
+
vc.packet_queue[-1] << frame_data_field
|
276
|
+
vc.pending_incomplete_packet_bytes_left = space_packet_length - frame_data_field.length
|
277
|
+
return
|
278
|
+
end
|
279
|
+
|
280
|
+
vc.packet_queue[-1] << frame_data_field.slice!(0, space_packet_length)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def get_space_packet_length(space_packet)
|
285
|
+
# signal more data needed if we do not have enough to determine the
|
286
|
+
# length of the space packet
|
287
|
+
return :STOP if (space_packet.length < SPACE_PACKET_HEADER_LENGTH)
|
288
|
+
|
289
|
+
# actual length in ccsds space packet is stored value plus one
|
290
|
+
space_packet_data_field_length = BinaryAccessor.read(
|
291
|
+
SPACE_PACKET_LENGTH_BIT_OFFSET,
|
292
|
+
SPACE_PACKET_LENGTH_BITS,
|
293
|
+
:UINT,
|
294
|
+
space_packet,
|
295
|
+
:BIG_ENDIAN) + 1
|
296
|
+
space_packet_length = SPACE_PACKET_HEADER_LENGTH + space_packet_data_field_length
|
297
|
+
return space_packet_length
|
298
|
+
end
|
299
|
+
|
300
|
+
def get_space_packet_apid(space_packet)
|
301
|
+
# signal more data needed if we do not have enough of the header to
|
302
|
+
# determine the apid of the space packet
|
303
|
+
return :STOP if (space_packet.length < (SPACE_PACKET_APID_BIT_OFFSET + SPACE_PACKET_APID_BITS) / 8)
|
304
|
+
|
305
|
+
# actual length in ccsds space packet is stored value plus one
|
306
|
+
space_packet_apid = BinaryAccessor.read(
|
307
|
+
SPACE_PACKET_APID_BIT_OFFSET,
|
308
|
+
SPACE_PACKET_APID_BITS,
|
309
|
+
:UINT,
|
310
|
+
space_packet,
|
311
|
+
:BIG_ENDIAN)
|
312
|
+
return space_packet_apid
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|