Skip to content

Commit b6ba592

Browse files
committed
Scoped state to track whether to update component state
1 parent 5d4bff5 commit b6ba592

File tree

24 files changed

+296
-43
lines changed

24 files changed

+296
-43
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
mm/
2+
cosmos/
3+
output/
14
*.o
25
*.def
36
*.so

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
source ENV['RUBYGEMS_URL']
1+
source ENV['RUBYGEMS_URL'] || "https://rubygems.org"
22
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
33

44
gem 'dotenv'

compose.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,9 @@ services:
185185
user: "${OPENC3_USER_ID:-1001}:${OPENC3_GROUP_ID:-1001}"
186186
image: "${OPENC3_REGISTRY}/${OPENC3_NAMESPACE}/openc3-operator${OPENC3_IMAGE_SUFFIX}:${OPENC3_TAG}"
187187
restart: "unless-stopped"
188-
# ports:
188+
ports:
189+
- "127.0.0.1:8080:8080"
190+
- "127.0.0.1:8081:8081"
189191
# - "127.0.0.1:7779:7779" # Open port for the demo router
190192
# - "127.0.0.1:8081:8081/udp" # Open a udp port
191193
depends_on:

docs.openc3.com/docs/configuration/interfaces.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,18 @@ For a full example, please see the [openc3-cosmos-proto-target](https://github.c
666666

667667
## Custom Interfaces
668668

669-
Interfaces have the following methods that must be implemented:
669+
Custom interfaces should be created in the `lib/` folder of your plugin and then referenced in `plugin.txt` simply by the file name, no pathing necessary.
670+
```ruby
671+
# my_custom_interface.py
672+
from openc3.interfaces.interface import Interface
673+
class MyCustomInterface(Interface):
674+
... your code here ...
675+
676+
# plugin.txt
677+
INTERFACE MY_INTEFACE_NAME my_custom_interface.py arg1 arg2 arg3
678+
```
679+
680+
All interfaces must be subclasses of the `Cosmos::Interface` class or one of its subclasses. Interfaces have the following methods that must be implemented:
670681

671682
1. **connect** - Open the socket or port or somehow establish the connection to the target. Note: This method may not block indefinitely. Be sure to call super() in your implementation.
672683
1. **connected?** - Return true or false depending on the connection state. Note: This method should return immediately.
@@ -683,5 +694,5 @@ Interfaces also have the following methods that exist and have default implement
683694
1. **write_raw** - Send a raw binary string of data to the target. COSMOS implements this method by basically calling write_interface with the raw data.
684695

685696
:::warning Naming Conventions
686-
When creating your own interfaces, in most cases they will be subclasses of one of the built-in interfaces described below. It is important to know that both the filename and class name of the interface files must match with correct capitalization or you will receive "class not found" errors when trying to load your new interface. For example, an interface file called labview_interface.rb must contain the class LabviewInterface. If the class was named, LabVIEWInterface, for example, COSMOS would not be able to find the class because of the unexpected capitalization.
697+
When creating your own interfaces, in most cases they will be subclasses of one of the built-in interfaces described above. It is important to know that both the filename and class name of the interface files must match with correct capitalization or you will receive "class not found" errors when trying to load your new interface. For example, an interface file called labview_interface.rb must contain the class LabviewInterface. If the class was named, LabVIEWInterface, for example, COSMOS would not be able to find the class because of the unexpected capitalization.
687698
:::

docs.openc3.com/docs/getting-started/generators.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ The plugin generator creates the scaffolding for a new COSMOS Plugin. It require
2626

2727
```bash
2828
% openc3.sh cli generate plugin
29-
Usage: cli generate plugin <NAME>
29+
Usage: cli generate plugin <NAME> (--ruby or --python)
3030

31-
% openc3.sh cli generate plugin GSE
31+
% openc3.sh cli generate plugin GSE --python
3232
Plugin openc3-cosmos-gse successfully generated!
3333
```
3434

openc3-cosmos-init/plugins/packages/openc3-cosmos-tool-packetviewer/src/tools/PacketViewer/PacketViewer.vue

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
:items="rows"
7171
:custom-filter="filter"
7272
:sort-by="sortBy"
73-
:loading="loading"
73+
:loading="loading > 0"
7474
multi-sort
7575
fixed-header
7676
density="compact"
@@ -240,8 +240,7 @@ export default {
240240
data() {
241241
return {
242242
panel: 0,
243-
loadingPacketItems: false,
244-
loadingTlmData: false,
243+
loading: 0,
245244
title: 'Packet Viewer',
246245
configKey: 'packet_viewer',
247246
showOpenConfig: false,
@@ -419,9 +418,6 @@ export default {
419418
}
420419
return options
421420
},
422-
loading: function () {
423-
return this.loadingPacketItems || this.loadingTlmData
424-
},
425421
},
426422
watch: {
427423
showIgnored: function () {
@@ -542,7 +538,7 @@ export default {
542538
return // No change
543539
}
544540
try {
545-
this.loadingPacketItems = true
541+
this.loading++
546542
const target = await this.api.get_target(event.targetName)
547543
if (target) {
548544
this.ignoredItems = target.ignored_items
@@ -588,7 +584,7 @@ export default {
588584
})
589585
}
590586
} finally {
591-
this.loadingPacketItems = false
587+
this.loading--
592588
}
593589
},
594590
latestGetTlmValues(values) {
@@ -640,12 +636,17 @@ export default {
640636
this.latestAvailable = null
641637
this.latestItems = null
642638
}
639+
let loadingFirstTlm = false
643640
if (!this.rows.length) {
644-
this.loadingTlmData = true
641+
this.loading++
642+
loadingFirstTlm = true
645643
}
646644
this.updater = setInterval(() => {
647645
if (!this.targetName || !this.packetName) {
648-
this.loadingTlmData = false
646+
if (loadingFirstTlm) {
647+
loadingFirstTlm = false
648+
this.loading--
649+
}
649650
return // noop if target/packet aren't set
650651
}
651652
@@ -742,7 +743,10 @@ export default {
742743
console.log(error)
743744
})
744745
}
745-
this.loadingTlmData = false
746+
if (loadingFirstTlm) {
747+
loadingFirstTlm = false
748+
this.loading--
749+
}
746750
}, this.refreshInterval)
747751
},
748752
resetConfig: function () {

openc3-cosmos-init/plugins/packages/openc3-vue-common/src/components/TargetPacketItemChooser.vue

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,10 @@ export default {
209209
type: String,
210210
default: '',
211211
},
212+
initialValueType: {
213+
type: String,
214+
default: 'CONVERTED',
215+
},
212216
selectTypes: {
213217
type: Boolean,
214218
default: false,
@@ -264,7 +268,7 @@ export default {
264268
itemNames: [],
265269
selectedItemName: this.initialItemName?.toUpperCase(),
266270
valueTypes: ['CONVERTED', 'RAW'],
267-
selectedValueType: 'CONVERTED',
271+
selectedValueType: this.initialValueType.toUpperCase(),
268272
reductionModes: [
269273
// Map NONE to DECOM for clarity
270274
{ title: 'NONE', value: 'DECOM' },
@@ -378,6 +382,11 @@ export default {
378382
this.selectedItemName = val.toUpperCase()
379383
}
380384
},
385+
initialValueType: function (val) {
386+
if (val) {
387+
this.selectedValueType = val.toUpperCase()
388+
}
389+
},
381390
mode: function (newVal, oldVal) {
382391
this.selectedPacketName = null
383392
this.selectedItemName = null
@@ -405,17 +414,19 @@ export default {
405414
406415
// Fetch queues if in command mode
407416
if (this.mode === 'cmd') {
408-
Api.get('/openc3-api/queues').then((response) => {
409-
this.queueNames = [{ label: 'None', value: null }]
410-
if (response.data && Array.isArray(response.data)) {
411-
response.data.forEach((queue) => {
412-
this.queueNames.push({ label: queue.name, value: queue.name })
413-
})
414-
}
415-
}).catch((error) => {
416-
console.error('Error fetching queues:', error)
417-
// Keep default "None" option even if fetch fails
418-
})
417+
Api.get('/openc3-api/queues')
418+
.then((response) => {
419+
this.queueNames = [{ label: 'None', value: null }]
420+
if (response.data && Array.isArray(response.data)) {
421+
response.data.forEach((queue) => {
422+
this.queueNames.push({ label: queue.name, value: queue.name })
423+
})
424+
}
425+
})
426+
.catch((error) => {
427+
console.error('Error fetching queues:', error)
428+
// Keep default "None" option even if fetch fails
429+
})
419430
}
420431
421432
this.api.get_target_names().then((result) => {

openc3/openc3.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ spec = Gem::Specification.new do |s|
9595
s.add_runtime_dependency 'rubyzip', '~> 3.0'
9696
s.add_runtime_dependency 'uuidtools', '~> 2.2'
9797
s.add_runtime_dependency 'yard', '~> 0.9'
98-
# faraday includes faraday-net_http as the default adapter
9998
s.add_runtime_dependency 'aws-sdk-s3', '< 2'
10099
s.add_runtime_dependency 'cbor', '~> 0.5.10'
101100
s.add_runtime_dependency 'childprocess', '~> 5.0'
102101
s.add_runtime_dependency 'connection_pool', '~> 2.4'
102+
# faraday includes faraday-net_http as the default adapter
103103
s.add_runtime_dependency 'faraday', '~> 2.7'
104104
s.add_runtime_dependency 'faraday-follow_redirects', '~> 0.3'
105105
s.add_runtime_dependency 'faraday-multipart', '~> 1.0'

openc3/spec/api/cmd_api_spec.rb

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -355,16 +355,33 @@ def test_cmd_unknown(method)
355355
end
356356

357357
it "returns a command packet buffer" do
358+
time = Time.now
358359
@api.cmd("INST ABORT")
359-
output = @api.get_cmd_buffer("inst", "Abort")
360-
expect(output["buffer"][6..7].unpack("n")[0]).to eq 2
361-
output = @api.get_cmd_buffer("inst Abort")
362-
expect(output["buffer"][6..7].unpack("n")[0]).to eq 2
360+
[
361+
@api.get_cmd_buffer("inst", "Abort"),
362+
@api.get_cmd_buffer("inst Abort")
363+
].each do |output|
364+
expect(output["buffer"][6..7].unpack("n")[0]).to eq 2
365+
expect(output["target_name"]).to eq "INST"
366+
expect(output["packet_name"]).to eq "ABORT"
367+
expect(output["time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
368+
expect(output["received_time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
369+
expect(output["received_count"].to_i).to eq 1
370+
expect(output["stored"]).to eq "false"
371+
end
363372
@api.cmd("INST COLLECT with TYPE NORMAL, DURATION 5")
364-
output = @api.get_cmd_buffer("INST", "COLLECT")
365-
expect(output["buffer"][6..7].unpack("n")[0]).to eq 1
366-
output = @api.get_cmd_buffer("INST COLLECT")
367-
expect(output["buffer"][6..7].unpack("n")[0]).to eq 1
373+
[
374+
@api.get_cmd_buffer("INST", "COLLECT"),
375+
@api.get_cmd_buffer("INST COLLECT")
376+
].each do |output|
377+
expect(output["buffer"][6..7].unpack("n")[0]).to eq 1
378+
expect(output["target_name"]).to eq "INST"
379+
expect(output["packet_name"]).to eq "COLLECT"
380+
expect(output["time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
381+
expect(output["received_time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
382+
expect(output["received_count"].to_i).to eq 1
383+
expect(output["stored"]).to eq "false"
384+
end
368385
end
369386
end
370387

openc3/spec/api/tlm_api_spec.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -469,14 +469,22 @@ def test_tlm_unknown(method)
469469

470470
describe "get_tlm_buffer" do
471471
it "returns a telemetry packet buffer" do
472+
time = Time.now
472473
buffer = "\x01\x02\x03\x04"
473474
packet = System.telemetry.packet('INST', 'HEALTH_STATUS')
474475
packet.buffer = buffer
475476
TelemetryTopic.write_packet(packet, scope: 'DEFAULT')
476-
output = @api.get_tlm_buffer("INST", "Health_Status")
477-
expect(output["buffer"][0..3]).to eq buffer
478-
output = @api.get_tlm_buffer("INST Health_Status")
479-
expect(output["buffer"][0..3]).to eq buffer
477+
[
478+
@api.get_tlm_buffer("INST", "Health_Status"),
479+
@api.get_tlm_buffer("INST Health_Status")
480+
].each do |output|
481+
expect(output["buffer"][0..3]).to eq buffer
482+
expect(output["target_name"]).to eq "INST"
483+
expect(output["packet_name"]).to eq "HEALTH_STATUS"
484+
expect(output["time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
485+
expect(output["received_time"].to_i / 1_000_000_000).to be_within(1).of(time.to_i)
486+
expect(output["stored"]).to eq "false"
487+
end
480488
end
481489
end
482490

0 commit comments

Comments
 (0)