Skip to content

Commit 23dcaa8

Browse files
committed
Restructure COSMO plugin files
This merges COSMOS plugin generation for the pico example using serial connection (from Jbsco#1, commented out in plugin.txt), adds serial-specific COSMOS plugin protocols, updates plugin.txt template to include comments and examples for the user, changes plugin.txt generated location to build/cosmos/template.
1 parent 0381b15 commit 23dcaa8

File tree

4 files changed

+245
-5
lines changed

4 files changed

+245
-5
lines changed

gen/generators/assembly.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ def __init__(self):
128128
this_file_dir = os.path.dirname(os.path.realpath(__file__))
129129
template_dir = os.path.join(this_file_dir, ".." + os.sep + "templates")
130130
assembly_cosmos_plugin_generator_base.__init__(
131-
self, "name_ccsds_cosmos_plugin.txt", template_dir=template_dir, subdir="plugin"
131+
self, "name_ccsds_cosmos_plugin.txt", template_dir=template_dir, subdir="template"
132132
)
133133

134134
def generate(self, input_filename):
Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
1-
# Set Variables here to allow variation in your plugin
1+
# COSMOS interface documentation is available at: https://docs.openc3.com/docs/configuration/interfaces
2+
# Set variables here to allow variation in your plugin.
3+
# Variables are able to be modified at time of install in COSMOS.
24
Variable {{ name|lower }}_target_name {{ name }}
3-
Variable port_w 2003
4-
Variable port_r 2003
55
Variable crc_parameter_name CRC
66
Variable checksum_parameter_name Checksum
7+
# If TCP:
8+
Variable port_w 2003
9+
Variable port_r 2003
10+
# If serial:
11+
# Variable port_w /dev/ttyACM0
12+
# Variable port_r /dev/ttyACM0
713

814
Target {{ name }} <%= {{ name|lower }}_target_name %>
15+
# TCP example interface:
916
Interface <%= {{ name|lower }}_target_name %>_INT tcpip_server_interface.rb <%= port_w %> <%= port_r %> 10.0 nil Length 32 16 7
1017
Map_Target <%= {{ name|lower }}_target_name %>
1118
Protocol Read crc_protocol.rb <%= crc_parameter_name %> false "ERROR" -16 16
1219
Protocol Write cmd_checksum.rb <%= checksum_parameter_name %>
13-
20+
# Serial example interface:
21+
# Interface <%= {{ name|lower }}_target_name %>_INT serial_interface.rb <%= port_w %> <%= port_r %> 10.0 nil Length 64 16 11 1 Big_Endian 0 FED4AFEE
22+
# Map_Target <%= {{ name|lower }}_target_name %>
23+
# Protocol Read crc_sync_protocol.rb <%= crc_parameter_name %> false "ERROR" -16 16
24+
# Protocol Write cmd_sync_checksum.rb <%= checksum_parameter_name %>

gnd/cosmos/cmd_sync_checksum.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
require 'openc3/config/config_parser'
2+
require 'openc3/interfaces/protocols/protocol'
3+
require 'openc3/utilities/crc'
4+
require 'thread'
5+
6+
module OpenC3
7+
# Creates a checksum on write and inserts into packet
8+
class CmdChecksum < Protocol
9+
10+
# @param write_item_name [String/nil] Item to fill with calculated CRC value for outgoing packets (nil = don't fill)
11+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
12+
def initialize(
13+
write_item_name = nil,
14+
allow_empty_data = nil
15+
)
16+
super(allow_empty_data)
17+
@write_item_name = ConfigParser.handle_nil(write_item_name)
18+
@allow_empty_data = ConfigParser.handle_true_false(allow_empty_data)
19+
20+
end
21+
22+
# @write_packet generates packet checksum: XOR of packet bytes with 0xFF seed
23+
def write_packet(packet, seed = 0xFF)
24+
if @write_item_name
25+
checksum = packet.buffer.bytes.reduce(seed, :^)
26+
packet.write(@write_item_name, checksum)
27+
end
28+
packet.buffer = ["FED4AFEE"].pack('H*') + packet.buffer # only for serial
29+
# this resolves outgoing serial for the pico example, but need to correct for expected length in COSMOS on outgoing packets.
30+
packet
31+
end
32+
end
33+
end

gnd/cosmos/crc_sync_protocol.rb

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# encoding: ascii-8bit
2+
3+
# Copyright 2022 Ball Aerospace & Technologies Corp.
4+
# All Rights Reserved.
5+
#
6+
# This program is free software; you can modify and/or redistribute it
7+
# under the terms of the GNU Affero General Public License
8+
# as published by the Free Software Foundation; version 3 with
9+
# attribution addendums as found in the LICENSE.txt
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 Affero General Public License for more details.
15+
16+
# Modified by OpenC3, Inc.
17+
# All changes Copyright 2022, OpenC3, Inc.
18+
# All Rights Reserved
19+
#
20+
# This file may also be used under the terms of a commercial license
21+
# if purchased from OpenC3, Inc.
22+
23+
require 'openc3/config/config_parser'
24+
require 'openc3/interfaces/protocols/protocol'
25+
require 'openc3/utilities/crc'
26+
require 'thread'
27+
28+
module OpenC3
29+
# Creates a CRC on write and verifies a CRC on read
30+
class CrcModProtocol < Protocol
31+
ERROR = "ERROR" # on CRC mismatch
32+
DISCONNECT = "DISCONNECT" # on CRC mismatch
33+
34+
# @param write_item_name [String/nil] Item to fill with calculated CRC value for outgoing packets (nil = don't fill)
35+
# @param strip_crc [Boolean] Whether or not to remove the CRC from incoming packets
36+
# @param bad_strategy [ERROR/DISCONNECT] How to handle CRC errors on incoming packets. ERROR = Just log the error, DISCONNECT = Disconnect interface
37+
# @param bit_offset [Integer] Bit offset of the CRC in the data. Can be negative to indicate distance from end of packet
38+
# @param bit_size [Integer] Bit size of the CRC - Must be 16, 32, or 64
39+
# @param endianness [BIG_ENDIAN/LITTLE_ENDIAN] Endianness of the CRC
40+
# @param poly [Integer] Polynomial to use when calculating the CRC
41+
# @param seed [Integer] Seed value to start the calculation
42+
# @param xor [Boolean] Whether to XOR the CRC result with 0xFFFF
43+
# @param reflect [Boolean] Whether to bit reverse each byte of data before calculating the CRC
44+
# @param allow_empty_data [true/false/nil] See Protocol#initialize
45+
def initialize(
46+
write_item_name = nil,
47+
strip_crc = false,
48+
bad_strategy = "ERROR",
49+
bit_offset = -32,
50+
bit_size = 32,
51+
endianness = 'BIG_ENDIAN',
52+
poly = nil,
53+
seed = nil,
54+
xor = nil,
55+
reflect = nil,
56+
allow_empty_data = nil
57+
)
58+
super(allow_empty_data)
59+
@write_item_name = ConfigParser.handle_nil(write_item_name)
60+
@strip_crc = ConfigParser.handle_true_false(strip_crc)
61+
raise "Invalid strip CRC of '#{strip_crc}'. Must be TRUE or FALSE." unless !!@strip_crc == @strip_crc
62+
63+
case bad_strategy
64+
when ERROR, DISCONNECT
65+
@bad_strategy = bad_strategy
66+
else
67+
raise "Invalid bad CRC strategy of #{bad_strategy}. Must be ERROR or DISCONNECT."
68+
end
69+
70+
case endianness.to_s.upcase
71+
when 'BIG_ENDIAN'
72+
@endianness = :BIG_ENDIAN # Convert to symbol for use in BinaryAccessor.write
73+
when 'LITTLE_ENDIAN'
74+
@endianness = :LITTLE_ENDIAN # Convert to symbol for use in BinaryAccessor.write
75+
else
76+
raise "Invalid endianness '#{endianness}'. Must be BIG_ENDIAN or LITTLE_ENDIAN."
77+
end
78+
79+
begin
80+
@bit_offset = Integer(bit_offset)
81+
rescue
82+
raise "Invalid bit offset of #{bit_offset}. Must be a number."
83+
end
84+
raise "Invalid bit offset of #{bit_offset}. Must be divisible by 8." if @bit_offset % 8 != 0
85+
86+
poly = ConfigParser.handle_nil(poly)
87+
begin
88+
poly = Integer(poly) if poly
89+
rescue
90+
raise "Invalid polynomial of #{poly}. Must be a number."
91+
end
92+
93+
seed = ConfigParser.handle_nil(seed)
94+
begin
95+
seed = Integer(seed) if seed
96+
rescue
97+
raise "Invalid seed of #{seed}. Must be a number."
98+
end
99+
100+
xor = ConfigParser.handle_true_false_nil(xor)
101+
raise "Invalid XOR value of '#{xor}'. Must be TRUE or FALSE." if xor && !!xor != xor
102+
103+
reflect = ConfigParser.handle_true_false_nil(reflect) if reflect
104+
raise "Invalid reflect value of '#{reflect}'. Must be TRUE or FALSE." if reflect && !!reflect != reflect
105+
106+
# Built the CRC arguments array. All subsequent arguments are dependent
107+
# on the previous ones so we build it up incrementally.
108+
args = []
109+
if poly
110+
args << poly
111+
if seed
112+
args << seed
113+
unless xor.nil? # Can't check raw variable because it could be false
114+
args << xor
115+
unless reflect.nil? # Can't check raw variable because it could be false
116+
args << reflect
117+
end
118+
end
119+
end
120+
end
121+
122+
@bit_size = bit_size.to_i
123+
case @bit_size
124+
when 16
125+
@pack = (@endianness == :BIG_ENDIAN) ? 'n' : 'v'
126+
if args.empty?
127+
@crc = Crc16.new
128+
else
129+
@crc = Crc16.new(*args)
130+
end
131+
when 32
132+
@pack = (@endianness == :BIG_ENDIAN) ? 'N' : 'V'
133+
if args.empty?
134+
@crc = Crc32.new
135+
else
136+
@crc = Crc32.new(*args)
137+
end
138+
when 64
139+
@pack = (@endianness == :BIG_ENDIAN) ? 'N' : 'V'
140+
if args.empty?
141+
@crc = Crc64.new
142+
else
143+
@crc = Crc64.new(*args)
144+
end
145+
else
146+
raise "Invalid bit size of #{bit_size}. Must be 16, 32, or 64."
147+
end
148+
end
149+
150+
def read_data(data, extra = nil)
151+
return super(data, extra) if data.length <= 0
152+
data.slice!(0, 4) # only for serial, remove sync word
153+
crc = BinaryAccessor.read(@bit_offset, @bit_size, :UINT, data, @endianness)
154+
calculated_crc = @crc.calc(data[0...(@bit_offset / 8)])
155+
if calculated_crc != crc
156+
Logger.error "#{@interface ? @interface.name : ""}: Invalid CRC detected! Calculated 0x#{calculated_crc.to_s(16).upcase} vs found 0x#{crc.to_s(16).upcase}."
157+
if @bad_strategy == DISCONNECT
158+
return :DISCONNECT
159+
end
160+
end
161+
if @strip_crc
162+
new_data = data.dup
163+
new_data = new_data[0...(@bit_offset / 8)]
164+
end_range = (@bit_offset + @bit_size) / 8
165+
new_data << data[end_range..-1] if end_range != 0
166+
return new_data, extra
167+
end
168+
return data, extra
169+
end
170+
171+
def write_packet(packet)
172+
if @write_item_name
173+
end_range = packet.get_item(@write_item_name).bit_offset / 8
174+
crc = @crc.calc(packet.buffer(false)[0...end_range])
175+
packet.write(@write_item_name, crc)
176+
end
177+
packet
178+
end
179+
180+
def write_data(data, extra = nil)
181+
unless @write_item_name
182+
if @bit_size == 64
183+
crc = @crc.calc(data)
184+
data << ("\x00" * 8)
185+
BinaryAccessor.write((crc >> 32), -64, 32, :UINT, data, @endianness, :ERROR)
186+
BinaryAccessor.write((crc & 0xFFFFFFFF), -32, 32, :UINT, data, @endianness, :ERROR)
187+
else
188+
crc = @crc.calc(data)
189+
data << ("\x00" * (@bit_size / 8))
190+
BinaryAccessor.write(crc, -@bit_size, @bit_size, :UINT, data, @endianness, :ERROR)
191+
end
192+
end
193+
return data, extra
194+
end
195+
end
196+
end

0 commit comments

Comments
 (0)