diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
new file mode 100644
index 0000000..2648c1f
--- /dev/null
+++ b/.github/workflows/main.yml
@@ -0,0 +1,28 @@
+name: CI
+
+on:
+ push:
+ pull_request:
+ schedule:
+ - cron: '0 0 * * 0' # Runs every Sunday at midnight
+
+jobs:
+ build:
+ name: Build and Test
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Install dependencies
+ run: sudo apt-get update && sudo apt-get install -y build-essential
+
+ - name: Run make all and wait for Sent
+ run: make wait-for-sent
+ working-directory: ./docker
+
+ - name: Archive all.txt logs
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ path: /quickstart/docker/all.txt
diff --git a/.gitignore b/.gitignore
index 9ed18f9..4456b6b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,4 +8,9 @@
# VSCode
.vscode/settings.json
-/.history/
\ No newline at end of file
+
+# Docker logs for CI
+docker/all.log
+
+# Local un-stage files
+/.history/
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 07f47b4..dcc5643 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -1,3 +1,3 @@
-FROM maven:3.8.5-openjdk-17
+FROM maven:3.9.9-eclipse-temurin-17
WORKDIR /yamcs
diff --git a/docker/Makefile b/docker/Makefile
index 8645a3d..7effc2b 100644
--- a/docker/Makefile
+++ b/docker/Makefile
@@ -1,33 +1,89 @@
-ifeq ($(shell which python3),)
- PYTHON = python
-else
- PYTHON = python3
-endif
+SHELL := /bin/bash
+.ONESHELL:
+.SHELLFLAGS := -eu -o pipefail -c
+.DELETE_ON_ERROR:
+MAKEFLAGS += --warn-undefined-variables
+MAKEFLAGS += --no-builtin-rules
+
+PYTHON := $(shell command -v python3 2>/dev/null || echo python)
.DEFAULT_GOAL := help
-all: ## run all, yamcs-up (yamcs-down) and yamcs-simulator
- $(MAKE) yamcs-simulator
-
+# Define function to print messages in different colors
+# Usage: $(call print_message,ANSI_COLOR_CODE,Your message here)
+define print_message
+ @printf "\033[$(1)m$(2)\033[0m\n"
+endef
+
+.PHONY: all all-10hz clean yamcs-up yamcs-down yamcs-simulator yamcs-simulator-10hz yamcs-shell help
+
+all: clean yamcs-up yamcs-simulator ## run all: clean, yamcs-up (yamcs-down) and yamcs-simulator
+
+all-10hz: clean yamcs-up yamcs-simulator-10hz ## run all: clean, yamcs-up (yamcs-down) and yamcs-simulator
+
yamcs-up: | yamcs-down ## bring up yamcs system
docker compose up -d
yamcs-down: ## bring down yamcs system
+ $(call print_message,33,Stopping any running docker-yamcs containers...)
docker compose down -v --remove-orphans
-yamcs-simulator: yamcs-up ## run yamcs simulator
- @echo "connect via http://localhost:8090/ system make take about 50 seconds to startup" && \
+yamcs-simulator: ## run yamcs simulator
+ $(call print_message,36,Connect via http://localhost:8090/ system may take about 50 seconds to startup)
cd .. && $(PYTHON) ./simulator.py
+yamcs-simulator-10hz: ## run yamcs simulator at 10hz
+ $(call print_message,36,Connect via http://localhost:8090/ system may take about 50 seconds to startup)
+ cd .. && $(PYTHON) ./simulator.py --rate=10
+
+yamcs-simulator-down: ## stop the yamcs simulator
+ $(call print_message,33,Stopping the yamcs simulator...)
+ pkill -f simulator.py
+ $(call print_message,32,Simulator stopped successfully)
+
+yamcs-simulator-restart: yamcs-simulator-down yamcs-simulator ## stop the yamcs simulator and start it again
+
yamcs-shell: ## shell into yamcs container
docker compose up -d && docker compose exec yamcs bash
-help:
- @printf "\033[37m%-30s\033[0m %s\n" "#----------------------------------------------------------------------------------"
- @printf "\033[37m%-30s\033[0m %s\n" "# Makefile "
- @printf "\033[37m%-30s\033[0m %s\n" "#----------------------------------------------------------------------------------"
- @printf "\033[37m%-30s\033[0m %s\n" "#-targets----------------------description-----------------------------------------"
- @grep -E '^[a-zA-Z_-].+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
+clean: | yamcs-down ## remove yamcs build artifacts and docker resources created by this Makefile
+ $(call print_message,33,Cleaning up docker-yamcs resources (containers, volumes, networks)...)
+ docker compose rm -f -s -v
+ $(call print_message,33,Removing docker-yamcs image...)
+ docker image rm -f docker-yamcs 2>/dev/null || true
+ $(call print_message,33,Cleaning up yamcs build artifacts...)
+ rm -rf ../target
+ $(call print_message,32,Done!)
+
+wait-for-sent: | yamcs-up ## run make all and wait up to 10 minutes for "Sent:" in the output
+ @echo "Running make all and waiting for 'Sent:' in the output..." && \
+ nohup $(MAKE) all > all.log 2>&1 & \
+ pid=$$!; \
+ timeout=600; \
+ while ! grep -q "Sent:" all.log; do \
+ sleep 1; \
+ timeout=$$((timeout - 1)); \
+ if [ $$timeout -le 0 ]; then \
+ echo "Timeout waiting for 'Sent:' in the output"; \
+ kill $$pid; \
+ exit 1; \
+ fi; \
+ done; \
+ echo "Found 'Sent:' in the output"; \
+ kill $$pid
+
+TERM_WIDTH := $(shell tput cols 2>/dev/null || echo 80)
+
+define print_header
+ @printf '%*s\n' "$(TERM_WIDTH)" '' | tr ' ' '-'
+ @printf '%-*s\n' "$(TERM_WIDTH)" "$(1)"
+ @printf '%*s\n' "$(TERM_WIDTH)" '' | tr ' ' '-'
+endef
+
+
+help: ## display this help message
+ $(call print_header,"Makefile")
+ @awk 'BEGIN {FS = ":.*##"; printf "\033[36m%-30s\033[0m %s\n", "Target", "Description"} /^[a-zA-Z_-]+:.*?##/ {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) | sort
-print-%:
+print-%: ## Print any variable (e.g., make print-PYTHON)
@echo $* = $($*)
diff --git a/pom.xml b/pom.xml
index 084b400..e39df3b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
Update this to the latest Yamcs release.
Check https://mvnrepository.com/artifact/org.yamcs/yamcs-core
-->
- 5.9.8
+ 5.10.1
@@ -52,7 +52,7 @@
org.yamcs
yamcs-maven-plugin
- 1.3.1
+ 1.3.2
diff --git a/simulator.py b/simulator.py
index 3d30440..7c9de19 100755
--- a/simulator.py
+++ b/simulator.py
@@ -4,15 +4,42 @@
import io
import socket
import sys
+import argparse
+
from struct import unpack_from
from threading import Thread
from time import sleep
+parser = argparse.ArgumentParser(description='Yamcs Simulator')
+parser.add_argument('--testdata', type=str, default='testdata.ccsds', help='simulated testdata.ccsds data')
+
+# telemetry
+parser.add_argument('--tm_host', type=str, default='127.0.0.1', help='TM host')
+parser.add_argument('--tm_port', type=int, default=10015, help='TM port')
+parser.add_argument('-r', '--rate', type=int, default=1, help='TM playback rate. 1 = 1Hz, 10 = 10Hz, etc.')
+
+# telecommand
+parser.add_argument('--tc_host', type=str, default='127.0.0.1', help='TC host')
+parser.add_argument('--tc_port', type=int, default=10025 , help='TC port')
+
+args = vars(parser.parse_args())
+
+# test data
+TEST_DATA = args['testdata']
+
+# telemetry
+TM_SEND_ADDRESS = args['tm_host']
+TM_SEND_PORT = args['tm_port']
+RATE = args['rate']
+
+# telecommand
+TC_RECEIVE_ADDRESS = args['tc_host']
+TC_RECEIVE_PORT = args['tc_port']
def send_tm(simulator):
tm_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- with io.open('testdata.ccsds', 'rb') as f:
+ with io.open(TEST_DATA, 'rb') as f:
simulator.tm_counter = 1
header = bytearray(6)
while f.readinto(header) == 6:
@@ -22,15 +49,15 @@ def send_tm(simulator):
f.seek(-6, io.SEEK_CUR)
f.readinto(packet)
- tm_socket.sendto(packet, ('127.0.0.1', 10015))
+ tm_socket.sendto(packet, (TM_SEND_ADDRESS, TM_SEND_PORT))
simulator.tm_counter += 1
- sleep(1)
+ sleep(1 / simulator.rate)
def receive_tc(simulator):
tc_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- tc_socket.bind(('127.0.0.1', 10025))
+ tc_socket.bind((TC_RECEIVE_ADDRESS, TC_RECEIVE_PORT ))
while True:
data, _ = tc_socket.recvfrom(4096)
simulator.last_tc = data
@@ -39,12 +66,13 @@ def receive_tc(simulator):
class Simulator():
- def __init__(self):
+ def __init__(self, rate):
self.tm_counter = 0
self.tc_counter = 0
self.tm_thread = None
self.tc_thread = None
self.last_tc = None
+ self.rate = rate
def start(self):
self.tm_thread = Thread(target=send_tm, args=(self,))
@@ -63,9 +91,11 @@ def print_status(self):
if __name__ == '__main__':
- simulator = Simulator()
+ simulator = Simulator(RATE)
simulator.start()
-
+ sys.stdout.write('Using playback rate of ' + str(RATE) + 'Hz, ');
+ sys.stdout.write('TM host=' + str(TM_SEND_ADDRESS) + ', TM port=' + str(TM_SEND_PORT) + ', ');
+ sys.stdout.write('TC host=' + str(TC_RECEIVE_ADDRESS) + ', TC port=' + str(TC_RECEIVE_PORT) + '\r\n');
try:
prev_status = None
while True:
diff --git a/src/main/yamcs/mdb/xtce.xml b/src/main/yamcs/mdb/xtce.xml
index 7825200..ba8fa4c 100644
--- a/src/main/yamcs/mdb/xtce.xml
+++ b/src/main/yamcs/mdb/xtce.xml
@@ -141,6 +141,9 @@
+
+
+
@@ -262,6 +265,20 @@
+
+
+ out0.setFloatValue(in.getEngValue().getFloatValue());
+
+
+
+
+
+
+
+
+
+
+