openc3-cosmos-cfdp 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +18 -0
  3. data/README.md +181 -0
  4. data/Rakefile +40 -0
  5. data/lib/cfdp.rb +283 -0
  6. data/lib/cfdp_api.rb +204 -0
  7. data/microservices/CFDP/Gemfile +37 -0
  8. data/microservices/CFDP/Rakefile +6 -0
  9. data/microservices/CFDP/app/controllers/application_controller.rb +46 -0
  10. data/microservices/CFDP/app/controllers/cfdp_controller.rb +222 -0
  11. data/microservices/CFDP/app/models/cfdp_checksum.rb +52 -0
  12. data/microservices/CFDP/app/models/cfdp_crc_checksum.rb +41 -0
  13. data/microservices/CFDP/app/models/cfdp_mib.rb +613 -0
  14. data/microservices/CFDP/app/models/cfdp_model.rb +25 -0
  15. data/microservices/CFDP/app/models/cfdp_null_checksum.rb +29 -0
  16. data/microservices/CFDP/app/models/cfdp_pdu.rb +202 -0
  17. data/microservices/CFDP/app/models/cfdp_receive_transaction.rb +590 -0
  18. data/microservices/CFDP/app/models/cfdp_source_transaction.rb +449 -0
  19. data/microservices/CFDP/app/models/cfdp_topic.rb +58 -0
  20. data/microservices/CFDP/app/models/cfdp_transaction.rb +188 -0
  21. data/microservices/CFDP/app/models/cfdp_user.rb +601 -0
  22. data/microservices/CFDP/bin/rails +4 -0
  23. data/microservices/CFDP/bin/rake +4 -0
  24. data/microservices/CFDP/bin/setup +25 -0
  25. data/microservices/CFDP/config/application.rb +55 -0
  26. data/microservices/CFDP/config/boot.rb +4 -0
  27. data/microservices/CFDP/config/credentials.yml.enc +1 -0
  28. data/microservices/CFDP/config/environment.rb +5 -0
  29. data/microservices/CFDP/config/environments/development.rb +53 -0
  30. data/microservices/CFDP/config/environments/production.rb +75 -0
  31. data/microservices/CFDP/config/environments/test.rb +50 -0
  32. data/microservices/CFDP/config/initializers/application_controller_renderer.rb +8 -0
  33. data/microservices/CFDP/config/initializers/backtrace_silencers.rb +7 -0
  34. data/microservices/CFDP/config/initializers/cfdp_initializer.rb +26 -0
  35. data/microservices/CFDP/config/initializers/cors.rb +16 -0
  36. data/microservices/CFDP/config/initializers/filter_parameter_logging.rb +8 -0
  37. data/microservices/CFDP/config/initializers/inflections.rb +16 -0
  38. data/microservices/CFDP/config/initializers/mime_types.rb +4 -0
  39. data/microservices/CFDP/config/initializers/wrap_parameters.rb +9 -0
  40. data/microservices/CFDP/config/locales/en.yml +29 -0
  41. data/microservices/CFDP/config/puma.rb +38 -0
  42. data/microservices/CFDP/config/routes.rb +16 -0
  43. data/microservices/CFDP/config.ru +5 -0
  44. data/microservices/CFDP/init.sh +9 -0
  45. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_ack.rb +82 -0
  46. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_enum.rb +237 -0
  47. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_eof.rb +87 -0
  48. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_file_data.rb +98 -0
  49. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_finished.rb +114 -0
  50. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_keep_alive.rb +65 -0
  51. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_metadata.rb +116 -0
  52. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_nak.rb +91 -0
  53. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_prompt.rb +60 -0
  54. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_tlv.rb +291 -0
  55. data/microservices/CFDP/lib/cfdp_pdu/cfdp_pdu_user_ops.rb +749 -0
  56. data/microservices/CFDP/public/robots.txt +1 -0
  57. data/microservices/CFDP/spec/models/cfdp_pdu_ack_spec.rb +114 -0
  58. data/microservices/CFDP/spec/models/cfdp_pdu_eof_spec.rb +159 -0
  59. data/microservices/CFDP/spec/models/cfdp_pdu_file_data_spec.rb +76 -0
  60. data/microservices/CFDP/spec/models/cfdp_pdu_finished_spec.rb +192 -0
  61. data/microservices/CFDP/spec/models/cfdp_pdu_keep_alive_spec.rb +69 -0
  62. data/microservices/CFDP/spec/models/cfdp_pdu_metadata_spec.rb +346 -0
  63. data/microservices/CFDP/spec/models/cfdp_pdu_nak_spec.rb +126 -0
  64. data/microservices/CFDP/spec/models/cfdp_pdu_prompt_spec.rb +94 -0
  65. data/microservices/CFDP/spec/models/cfdp_pdu_spec.rb +111 -0
  66. data/microservices/CFDP/spec/rails_helper.rb +71 -0
  67. data/microservices/CFDP/spec/requests/cfdp_spec.rb +1965 -0
  68. data/microservices/CFDP/spec/spec_helper.rb +200 -0
  69. data/plugin.txt +67 -0
  70. data/targets/CFDPTEST/cmd_tlm/cmd.txt +5 -0
  71. data/targets/CFDPTEST/cmd_tlm/tlm.txt +4 -0
  72. data/targets/CFDPTEST/procedures/cfdp_test_suite.rb +130 -0
  73. data/targets/CFDPTEST/target.txt +4 -0
  74. metadata +118 -0
@@ -0,0 +1,116 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # Licensed for Evaluation and Educational Use
7
+ #
8
+ # This file may only be used commercially under the terms of a commercial license
9
+ # purchased from OpenC3, Inc.
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.
14
+ #
15
+ # The development of this software was funded in-whole or in-part by MethaneSAT LLC.
16
+
17
+ class CfdpPdu < OpenC3::Packet
18
+ def self.decom_metadata_pdu_contents(pdu, pdu_hash, variable_data)
19
+ s, s2 = pdu.define_metadata_pdu_contents
20
+ s.buffer = variable_data
21
+ pdu_hash["CLOSURE_REQUESTED"] = s.read("CLOSURE_REQUESTED")
22
+ pdu_hash["CHECKSUM_TYPE"] = s.read("CHECKSUM_TYPE")
23
+ pdu_hash["FILE_SIZE"] = s.read("FILE_SIZE")
24
+ source_file_name_length = s.read("SOURCE_FILE_NAME_LENGTH")
25
+ s.buffer = variable_data[0..(s.defined_length + source_file_name_length - 1)]
26
+ pdu_hash["SOURCE_FILE_NAME"] = s.read("SOURCE_FILE_NAME")
27
+ variable_data = variable_data[(s.defined_length + source_file_name_length)..-1]
28
+ if variable_data and variable_data.length > 0
29
+ s2.buffer = variable_data
30
+ destination_file_name_length = s2.read("DESTINATION_FILE_NAME_LENGTH")
31
+ s2.buffer = variable_data[0..(s2.defined_length + destination_file_name_length - 1)]
32
+ pdu_hash["DESTINATION_FILE_NAME"] = s2.read("DESTINATION_FILE_NAME")
33
+ variable_data = variable_data[(s2.defined_length + destination_file_name_length)..-1]
34
+ end
35
+ while variable_data and variable_data.length > 0
36
+ variable_data = decom_tlv(pdu, pdu_hash, variable_data)
37
+ end
38
+ end
39
+
40
+ def self.build_metadata_pdu(
41
+ source_entity:,
42
+ transaction_seq_num:,
43
+ destination_entity:,
44
+ file_size:,
45
+ segmentation_control: "NOT_PRESERVED",
46
+ transmission_mode: nil,
47
+ source_file_name: nil,
48
+ destination_file_name: nil,
49
+ closure_requested:,
50
+ options: [])
51
+
52
+ pdu = build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, transmission_mode: transmission_mode, file_size: file_size, segmentation_control: segmentation_control)
53
+ pdu_header_part_1_length = pdu.length # Measured here before writing variable data
54
+ pdu_header = pdu.build_variable_header(source_entity_id: source_entity['id'], transaction_seq_num: transaction_seq_num, destination_entity_id: destination_entity['id'], directive_code: "METADATA")
55
+ pdu_header_part_2_length = pdu_header.length
56
+ if checksum_type_implemented(destination_entity['default_checksum_type'])
57
+ checksum_type = destination_entity['default_checksum_type']
58
+ else
59
+ checksum_type = 0
60
+ end
61
+ pdu_contents = pdu.build_metadata_pdu_contents(source_entity: source_entity, closure_requested: closure_requested, checksum_type: checksum_type, file_size: file_size, source_file_name: source_file_name, destination_file_name: destination_file_name, options: options)
62
+ pdu.write("VARIABLE_DATA", pdu_header + pdu_contents)
63
+ pdu.write("PDU_DATA_LENGTH", pdu.length - pdu_header_part_1_length - pdu_header_part_2_length)
64
+ if destination_entity['crcs_required']
65
+ crc16 = OpenC3::Crc16.new
66
+ pdu.write("CRC", crc16.calc(pdu.buffer(false)[0..-3]))
67
+ end
68
+ return pdu.buffer(false)
69
+ end
70
+
71
+ def define_metadata_pdu_contents
72
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
73
+ s.append_item("RESERVED", 1, :UINT)
74
+ item = s.append_item("CLOSURE_REQUESTED", 1, :UINT)
75
+ item.states = CLOSURE_MODES
76
+ s.append_item("RESERVED2", 2, :UINT)
77
+ s.append_item("CHECKSUM_TYPE", 4, :UINT)
78
+ large_file = read("LARGE_FILE_FLAG")
79
+ if large_file == "SMALL_FILE"
80
+ s.append_item("FILE_SIZE", 32, :UINT)
81
+ else
82
+ s.append_item("FILE_SIZE", 64, :UINT)
83
+ end
84
+ s.append_item("SOURCE_FILE_NAME_LENGTH", 8, :UINT)
85
+ s.append_item("SOURCE_FILE_NAME", 0, :BLOCK)
86
+
87
+ s2 = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
88
+ s2.append_item("DESTINATION_FILE_NAME_LENGTH", 8, :UINT)
89
+ s2.append_item("DESTINATION_FILE_NAME", 0, :BLOCK)
90
+
91
+ return s, s2
92
+ end
93
+
94
+ def build_metadata_pdu_contents(source_entity:, closure_requested:, checksum_type:, file_size:, source_file_name: nil, destination_file_name: nil, options: [])
95
+ s, s2 = define_metadata_pdu_contents()
96
+ s.write("RESERVED", 0)
97
+ if closure_requested
98
+ s.write("CLOSURE_REQUESTED", closure_requested)
99
+ else
100
+ s.write("CLOSURE_REQUESTED", source_entity['transaction_closure_requested'])
101
+ end
102
+ s.write("RESERVED2", 0)
103
+ s.write("CHECKSUM_TYPE", checksum_type)
104
+ s.write("FILE_SIZE", file_size)
105
+ s.write("SOURCE_FILE_NAME_LENGTH", source_file_name.to_s.length)
106
+ s.write("SOURCE_FILE_NAME", source_file_name.to_s) if source_file_name.to_s.length > 0
107
+ s2.write("DESTINATION_FILE_NAME_LENGTH", destination_file_name.to_s.length)
108
+ s2.write("DESTINATION_FILE_NAME", destination_file_name.to_s) if destination_file_name.to_s.length > 0
109
+
110
+ result = s.buffer(false) + s2.buffer(false)
111
+ options.each do |option|
112
+ result << self.class.build_tlv(option)
113
+ end
114
+ return result
115
+ end
116
+ end
@@ -0,0 +1,91 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # Licensed for Evaluation and Educational Use
7
+ #
8
+ # This file may only be used commercially under the terms of a commercial license
9
+ # purchased from OpenC3, Inc.
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.
14
+ #
15
+ # The development of this software was funded in-whole or in-part by MethaneSAT LLC.
16
+
17
+ class CfdpPdu < OpenC3::Packet
18
+ def self.decom_nak_pdu_contents(pdu, pdu_hash, variable_data)
19
+ s, s2 = pdu.define_nak_pdu_contents()
20
+ s.buffer = variable_data[0..(s.defined_length - 1)]
21
+ pdu_hash["START_OF_SCOPE"] = s.read("START_OF_SCOPE")
22
+ pdu_hash["END_OF_SCOPE"] = s.read("END_OF_SCOPE")
23
+ pdu_hash["SEGMENT_REQUESTS"] = []
24
+ variable_data = variable_data[s.defined_length..-1]
25
+ while variable_data and variable_data.length > 0
26
+ s2.buffer = variable_data[0..(s2.defined_length - 1)]
27
+ pdu_hash["SEGMENT_REQUESTS"] << {}
28
+ pdu_hash["SEGMENT_REQUESTS"][-1]["START_OFFSET"] = s2.read("START_OFFSET")
29
+ pdu_hash["SEGMENT_REQUESTS"][-1]["END_OFFSET"] = s2.read("END_OFFSET")
30
+ variable_data = variable_data[s2.defined_length..-1]
31
+ end
32
+ end
33
+
34
+ def self.build_nak_pdu(
35
+ source_entity:,
36
+ transaction_seq_num:,
37
+ destination_entity:,
38
+ file_size:,
39
+ segmentation_control: "NOT_PRESERVED",
40
+ transmission_mode: nil,
41
+ start_of_scope:,
42
+ end_of_scope:,
43
+ segment_requests: [])
44
+
45
+ pdu = build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, transmission_mode: transmission_mode, file_size: file_size, segmentation_control: segmentation_control)
46
+ pdu.write("DIRECTION", "TOWARD_FILE_SENDER")
47
+ pdu_header_part_1_length = pdu.length # Measured here before writing variable data
48
+ pdu_header = pdu.build_variable_header(source_entity_id: source_entity['id'], transaction_seq_num: transaction_seq_num, destination_entity_id: destination_entity['id'], directive_code: "NAK")
49
+ pdu_header_part_2_length = pdu_header.length
50
+ pdu_contents = pdu.build_nak_pdu_contents(start_of_scope: start_of_scope, end_of_scope: end_of_scope, segment_requests: segment_requests)
51
+ pdu.write("VARIABLE_DATA", pdu_header + pdu_contents)
52
+ pdu.write("PDU_DATA_LENGTH", pdu.length - pdu_header_part_1_length - pdu_header_part_2_length)
53
+ if destination_entity['crcs_required']
54
+ crc16 = OpenC3::Crc16.new
55
+ pdu.write("CRC", crc16.calc(pdu.buffer(false)[0..-3]))
56
+ end
57
+ return pdu.buffer(false)
58
+ end
59
+
60
+ def define_nak_pdu_contents
61
+ s = OpenC3::Structure.new(:BIG_ENDIAN)
62
+ large_file = read("LARGE_FILE_FLAG")
63
+ if large_file == "SMALL_FILE"
64
+ item_size = 32
65
+ else
66
+ item_size = 64
67
+ end
68
+
69
+ s.append_item("START_OF_SCOPE", item_size, :UINT)
70
+ s.append_item("END_OF_SCOPE", item_size, :UINT)
71
+
72
+ s2 = OpenC3::Structure.new(:BIG_ENDIAN)
73
+ s2.append_item("START_OFFSET", item_size, :UINT)
74
+ s2.append_item("END_OFFSET", item_size, :UINT)
75
+ return s, s2
76
+ end
77
+
78
+ def build_nak_pdu_contents(start_of_scope:, end_of_scope:, segment_requests: [])
79
+ s, s2 = define_nak_pdu_contents()
80
+ result = ''
81
+ s.write("START_OF_SCOPE", start_of_scope)
82
+ s.write("END_OF_SCOPE", end_of_scope)
83
+ result << s.buffer(false)
84
+ segment_requests.each do |segment_request|
85
+ s2.write("START_OFFSET", segment_request[0])
86
+ s2.write("END_OFFSET", segment_request[1])
87
+ result << s2.buffer(false)
88
+ end
89
+ return result
90
+ end
91
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # Licensed for Evaluation and Educational Use
7
+ #
8
+ # This file may only be used commercially under the terms of a commercial license
9
+ # purchased from OpenC3, Inc.
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.
14
+ #
15
+ # The development of this software was funded in-whole or in-part by MethaneSAT LLC.
16
+
17
+ class CfdpPdu < OpenC3::Packet
18
+ def self.decom_prompt_pdu_contents(pdu, pdu_hash, variable_data)
19
+ s = pdu.define_prompt_pdu_contents
20
+ s.buffer = variable_data
21
+ pdu_hash["RESPONSE_REQUIRED"] = s.read("RESPONSE_REQUIRED")
22
+ end
23
+
24
+ def self.build_prompt_pdu(
25
+ source_entity:,
26
+ transaction_seq_num:,
27
+ destination_entity:,
28
+ segmentation_control: "NOT_PRESERVED",
29
+ transmission_mode: nil,
30
+ response_required:)
31
+
32
+ pdu = build_initial_pdu(type: "FILE_DIRECTIVE", destination_entity: destination_entity, transmission_mode: transmission_mode, file_size: 0, segmentation_control: segmentation_control)
33
+ pdu_header_part_1_length = pdu.length # Measured here before writing variable data
34
+ pdu_header = pdu.build_variable_header(source_entity_id: source_entity['id'], transaction_seq_num: transaction_seq_num, destination_entity_id: destination_entity['id'], directive_code: "PROMPT")
35
+ pdu_header_part_2_length = pdu_header.length
36
+ pdu_contents = pdu.build_prompt_pdu_contents(response_required: response_required)
37
+ pdu.write("VARIABLE_DATA", pdu_header + pdu_contents)
38
+ pdu.write("PDU_DATA_LENGTH", pdu.length - pdu_header_part_1_length - pdu_header_part_2_length)
39
+ if destination_entity['crcs_required']
40
+ crc16 = OpenC3::Crc16.new
41
+ pdu.write("CRC", crc16.calc(pdu.buffer(false)[0..-3]))
42
+ end
43
+ return pdu.buffer(false)
44
+ end
45
+
46
+ def define_prompt_pdu_contents
47
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
48
+ item = s.append_item("RESPONSE_REQUIRED", 1, :UINT)
49
+ item.states = {"NAK" => 0, "KEEP_ALIVE" => 1}
50
+ s.append_item("SPARE", 7, :UINT)
51
+ return s
52
+ end
53
+
54
+ def build_prompt_pdu_contents(response_required:)
55
+ s = define_prompt_pdu_contents()
56
+ s.write("RESPONSE_REQUIRED", response_required)
57
+ s.write("SPARE", 0)
58
+ return s.buffer(false)
59
+ end
60
+ end
@@ -0,0 +1,291 @@
1
+ # encoding: ascii-8bit
2
+
3
+ # Copyright 2023 OpenC3, Inc.
4
+ # All Rights Reserved.
5
+ #
6
+ # Licensed for Evaluation and Educational Use
7
+ #
8
+ # This file may only be used commercially under the terms of a commercial license
9
+ # purchased from OpenC3, Inc.
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.
14
+ #
15
+ # The development of this software was funded in-whole or in-part by MethaneSAT LLC.
16
+
17
+ class CfdpPdu < OpenC3::Packet
18
+ def self.decom_tlv(pdu, pdu_hash, variable_data)
19
+ if variable_data.length >= 2 # Need at least 2 bytes
20
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
21
+ item = s.append_item("TLV_TYPE", 8, :UINT)
22
+ item.states = TLV_TYPES
23
+ s.append_item("TLV_LENGTH", 8, :UINT)
24
+ s.buffer = variable_data[0..(s.defined_length - 1)]
25
+ type = s.read("TLV_TYPE")
26
+ length = s.read("TLV_LENGTH")
27
+ if length > 0
28
+ tlv_data = variable_data[0..(length + 1)]
29
+ variable_data = variable_data[(length + 2)..-1]
30
+ tlv = {}
31
+ tlv["TYPE"] = type
32
+ pdu_hash["TLVS"] ||= []
33
+ pdu_hash["TLVS"] << tlv
34
+
35
+ case type
36
+ when "FILESTORE_REQUEST"
37
+ s, s2 = define_filestore_request_tlv()
38
+ s.buffer = tlv_data
39
+ first_file_name_length = s.read("FIRST_FILE_NAME_LENGTH")
40
+ s.buffer = tlv_data[0..(4 + first_file_name_length - 1)]
41
+ tlv_data = tlv_data[(4 + first_file_name_length)..-1]
42
+ tlv["ACTION_CODE"] = s.read("ACTION_CODE")
43
+ tlv["FIRST_FILE_NAME"] = s.read("FIRST_FILE_NAME")
44
+ if tlv_data.length > 0
45
+ s2.buffer = tlv_data
46
+ second_file_name_length = s2.read("SECOND_FILE_NAME_LENGTH")
47
+ s2.buffer = tlv_data[0..(1 + second_file_name_length - 1)]
48
+ tlv["SECOND_FILE_NAME"] = s2.read("SECOND_FILE_NAME")
49
+ end
50
+
51
+ when "FILESTORE_RESPONSE"
52
+ s, s2, s3, status_code_item = define_filestore_response_tlv()
53
+ s.buffer = tlv_data
54
+ first_file_name_length = s.read("FIRST_FILE_NAME_LENGTH")
55
+ s.buffer = tlv_data[0..(4 + first_file_name_length - 1)]
56
+ tlv_data = tlv_data[(4 + first_file_name_length)..-1]
57
+ tlv["ACTION_CODE"] = s.read("ACTION_CODE")
58
+ add_status_code_states(action_code: tlv["ACTION_CODE"], status_code_item: status_code_item)
59
+ tlv["STATUS_CODE"] = s.read("STATUS_CODE")
60
+ tlv["FIRST_FILE_NAME"] = s.read("FIRST_FILE_NAME")
61
+ if tlv_data.length > 0
62
+ s2.buffer = tlv_data
63
+ second_file_name_length = s2.read("SECOND_FILE_NAME_LENGTH")
64
+ s2.buffer = tlv_data[0..(1 + second_file_name_length - 1)]
65
+ tlv_data = tlv_data[(1 + second_file_name_length)..-1]
66
+ tlv["SECOND_FILE_NAME"] = s2.read("SECOND_FILE_NAME")
67
+ if tlv_data.length > 0
68
+ s3.buffer = tlv_data
69
+ filestore_message_length = s3.read("FILESTORE_MESSAGE_LENGTH")
70
+ s3.buffer = tlv_data[0..(1 + filestore_message_length - 1)]
71
+ tlv_data = tlv_data[(1 + filestore_message_length)..-1]
72
+ tlv["FILESTORE_MESSAGE"] = s3.read("FILESTORE_MESSAGE")
73
+ end
74
+ end
75
+
76
+ when "MESSAGE_TO_USER"
77
+ s = define_message_to_user_tlv()
78
+ s.buffer = tlv_data
79
+ tlv["MESSAGE_TO_USER"] = s.read("MESSAGE_TO_USER")
80
+ tlv.merge!(pdu.decom_message_to_user(tlv["MESSAGE_TO_USER"]))
81
+
82
+ when "FAULT_HANDLER_OVERRIDE"
83
+ s = define_fault_handler_override_tlv()
84
+ s.buffer = tlv_data
85
+ tlv["CONDITION_CODE"] = s.read("CONDITION_CODE")
86
+ tlv["HANDLER_CODE"] = s.read("HANDLER_CODE")
87
+
88
+ when "FLOW_LABEL"
89
+ s = define_flow_label_tlv()
90
+ s.buffer = tlv_data
91
+ tlv["FLOW_LABEL"] = s.read("FLOW_LABEL")
92
+
93
+ when "ENTITY_ID"
94
+ s = define_entity_id_tlv()
95
+ s.buffer = tlv_data
96
+ entity_id_string = s.read("ENTITY_ID")
97
+ s2 = OpenC3::Structure.new(:BIG_ENDIAN)
98
+ s2.append_item("ENTITY_ID", entity_id_string.length * 8, :UINT)
99
+ s2.buffer = entity_id_string
100
+ tlv["ENTITY_ID"] = s2.read("ENTITY_ID")
101
+
102
+ end
103
+ else
104
+ variable_data = variable_data[2..-1]
105
+ end
106
+ return variable_data
107
+ else
108
+ return ""
109
+ end
110
+ end
111
+
112
+ def self.build_tlv(tlv, entity_id_length: nil)
113
+ type = tlv["TYPE"]
114
+ case type
115
+ when "FILESTORE_REQUEST"
116
+ first_file_name = tlv["FIRST_FILE_NAME"].to_s
117
+ second_file_name = nil
118
+ length = 2 + first_file_name.length # type + length field + length
119
+ if tlv.key?("SECOND_FILE_NAME")
120
+ second_file_name = tlv["SECOND_FILE_NAME"].to_s
121
+ length += 1 + second_file_name.length # length field + length
122
+ end
123
+
124
+ s, s2 = define_filestore_request_tlv()
125
+ s.write("TLV_TYPE", "FILESTORE_REQUEST")
126
+ s.write("TLV_LENGTH", length)
127
+ s.write("ACTION_CODE", tlv['ACTION_CODE'])
128
+ s.write("SPARE", 0)
129
+ s.write("FIRST_FILE_NAME_LENGTH", first_file_name.length)
130
+ s.write("FIRST_FILE_NAME", first_file_name)
131
+ if second_file_name
132
+ s2.write("SECOND_FILE_NAME_LENGTH", second_file_name.length)
133
+ s2.write("SECOND_FILE_NAME", second_file_name)
134
+ return s.buffer(false) + s2.buffer(false)
135
+ else
136
+ return s.buffer(false)
137
+ end
138
+
139
+ # TODO: Handled by cfdp_receive_transaction.rb, search 'Handle Filestore Requests'
140
+ # when "FILESTORE_RESPONSE"
141
+ # first_file_name = tlv["FIRST_FILE_NAME"].to_s
142
+ # second_file_name = tlv["SECOND_FILE_NAME"].to_s
143
+ # filestore_message = tlv["FILESTORE_MESSAGE"].to_s
144
+
145
+ # s, s2, s3, status_code_item = define_filestore_response_tlv()
146
+ # add_status_code_states(action_code: tlv["ACTION_CODE"], status_code_item: status_code_item)
147
+ # s.write("TLV_TYPE", "FILESTORE_REQUEST")
148
+ # s.write("TLV_LENGTH", 4 + first_file_name.length + second_file_name.length + filestore_message.length)
149
+ # s.write("ACTION_CODE", tlv['ACTION_CODE'])
150
+ # s.write("STATUS_CODE", tlv['STATUS_CODE'])
151
+ # s.write("FIRST_FILE_NAME_LENGTH", first_file_name.length)
152
+ # s.write("FIRST_FILE_NAME", first_file_name)
153
+ # s2.write("SECOND_FILE_NAME_LENGTH", second_file_name.length)
154
+ # s2.write("SECOND_FILE_NAME", second_file_name)
155
+ # s3.write("FILESTORE_MESSAGE_LENGTH", filestore_message.length)
156
+ # s3.write("FILESTORE_MESSAGE", filestore_message)
157
+ # return s.buffer(false) + s2.buffer(false) + s3.buffer(false)
158
+
159
+ when "MESSAGE_TO_USER"
160
+ s = define_message_to_user_tlv()
161
+ s.write("TLV_TYPE", "MESSAGE_TO_USER")
162
+ s.write("TLV_LENGTH", tlv["MESSAGE_TO_USER"].length)
163
+ s.write("MESSAGE_TO_USER", tlv["MESSAGE_TO_USER"])
164
+ return s.buffer(false)
165
+
166
+ when "FAULT_HANDLER_OVERRIDE"
167
+ s = define_fault_handler_override_tlv()
168
+ s.write("TLV_TYPE", "FAULT_HANDLER_OVERRIDE")
169
+ s.write("TLV_LENGTH", 1)
170
+ s.write("CONDITION_CODE", tlv["CONDITION_CODE"])
171
+ s.write("HANDLER_CODE", tlv["HANDLER_CODE"])
172
+ return s.buffer(false)
173
+
174
+ when "FLOW_LABEL"
175
+ s = define_flow_label_tlv()
176
+ s.write("TLV_TYPE", "FLOW_LABEL")
177
+ s.write("TLV_LENGTH", tlv["FLOW_LABEL"].length)
178
+ s.write("FLOW_LABEL", tlv["FLOW_LABEL"])
179
+ return s.buffer(false)
180
+
181
+ when "ENTITY_ID"
182
+ s = define_entity_id_tlv(entity_id_length: entity_id_length)
183
+ s.write("TLV_TYPE", "ENTITY_ID")
184
+ s.write("TLV_LENGTH", entity_id_length)
185
+ s.write("ENTITY_ID", tlv["ENTITY_ID"])
186
+ return s.buffer(false)
187
+
188
+ end
189
+ end
190
+
191
+ # Table 5-15
192
+ def self.define_filestore_request_tlv
193
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
194
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x01
195
+ item.states = TLV_TYPES
196
+ s.append_item("TLV_LENGTH", 8, :UINT)
197
+ item = s.append_item("ACTION_CODE", 4, :UINT)
198
+ item.states = ACTION_CODES
199
+ s.append_item("SPARE", 4, :UINT)
200
+ s.append_item("FIRST_FILE_NAME_LENGTH", 8, :UINT)
201
+ s.append_item("FIRST_FILE_NAME", 0, :BLOCK)
202
+
203
+ s2 = OpenC3::Structure.new(:BIG_ENDIAN)
204
+ s2.append_item("SECOND_FILE_NAME_LENGTH", 8, :UINT)
205
+ s2.append_item("SECOND_FILE_NAME", 0, :BLOCK)
206
+
207
+ return s, s2
208
+ end
209
+
210
+ # Table 5-17
211
+ def self.define_filestore_response_tlv
212
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
213
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x01
214
+ item.states = TLV_TYPES
215
+ s.append_item("TLV_LENGTH", 8, :UINT)
216
+ item = s.append_item("ACTION_CODE", 4, :UINT)
217
+ item.states = ACTION_CODES
218
+ status_code_item = s.append_item("STATUS_CODE", 4, :UINT)
219
+ s.append_item("FIRST_FILE_NAME_LENGTH", 8, :UINT)
220
+ s.append_item("FIRST_FILE_NAME", 0, :BLOCK)
221
+
222
+ s2 = OpenC3::Structure.new(:BIG_ENDIAN)
223
+ s2.append_item("SECOND_FILE_NAME_LENGTH", 8, :UINT)
224
+ s2.append_item("SECOND_FILE_NAME", 0, :BLOCK)
225
+
226
+ s3 = OpenC3::Structure.new(:BIG_ENDIAN)
227
+ s3.append_item("FILESTORE_MESSAGE_LENGTH", 8, :UINT)
228
+ s3.append_item("FILESTORE_MESSAGE", 0, :BLOCK)
229
+
230
+ return s, s2, s3, status_code_item
231
+ end
232
+
233
+ # Table 5-18
234
+ def self.add_status_code_states(action_code:, status_code_item:)
235
+ if String === action_code
236
+ states = FILESTORE_RESPONSE_STATUS_CODES[action_code]
237
+ else
238
+ states = FILESTORE_RESPONSE_STATUS_CODES[ACTION_CODES.key(action_code)]
239
+ end
240
+ states = UNKNOWN_STATUS_CODES unless states
241
+ status_code_item.states = states
242
+ end
243
+
244
+ # Section 5.4.3
245
+ def self.define_message_to_user_tlv
246
+ # Todo: Improve for Proxy support
247
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
248
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x02
249
+ item.states = TLV_TYPES
250
+ s.append_item("TLV_LENGTH", 8, :UINT)
251
+ s.append_item("MESSAGE_TO_USER", 0, :BLOCK)
252
+ return s
253
+ end
254
+
255
+ # Table 5-19
256
+ def self.define_fault_handler_override_tlv
257
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
258
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x04
259
+ item.states = TLV_TYPES
260
+ s.append_item("TLV_LENGTH", 8, :UINT)
261
+ item = s.append_item("CONDITION_CODE", 4, :UINT)
262
+ item.states = CONDITION_CODES
263
+ item = s.append_item("HANDLER_CODE", 4, :UINT)
264
+ item.states = HANDLER_CODES
265
+ return s
266
+ end
267
+
268
+ # Section 5.4.5
269
+ def self.define_flow_label_tlv
270
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
271
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x05
272
+ item.states = TLV_TYPES
273
+ s.append_item("TLV_LENGTH", 8, :UINT)
274
+ s.append_item("FLOW_LABEL", 0, :BLOCK)
275
+ return s
276
+ end
277
+
278
+ # See Section 5.4.6
279
+ def self.define_entity_id_tlv(entity_id_length: nil)
280
+ s = OpenC3::Packet.new(nil, nil, :BIG_ENDIAN)
281
+ item = s.append_item("TLV_TYPE", 8, :UINT) # 0x06
282
+ item.states = TLV_TYPES
283
+ s.append_item("TLV_LENGTH", 8, :UINT)
284
+ if entity_id_length
285
+ s.append_item("ENTITY_ID", entity_id_length * 8, :UINT)
286
+ else
287
+ s.append_item("ENTITY_ID", 0, :BLOCK)
288
+ end
289
+ return s
290
+ end
291
+ end