mirror of
https://github.com/cjfranko/NTP-Timeturner.git
synced 2025-11-08 10:22:02 +00:00
CD/CI git build workflow and unit testing + dependabot intergration for security updates
This commit is contained in:
parent
bd2111d77a
commit
a6523bf105
6 changed files with 182 additions and 15 deletions
6
.github/dependabot.yml
vendored
Normal file
6
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "cargo"
|
||||
directory: "/" # Location of Cargo.toml
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
70
.github/workflows/build.yml
vendored
Normal file
70
.github/workflows/build.yml
vendored
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
name: Build for Raspberry Pi
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
# Target for 64-bit Raspberry Pi (Raspberry Pi OS)
|
||||
RUST_TARGET: aarch64-unknown-linux-gnu
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build for aarch64
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ env.RUST_TARGET }}
|
||||
|
||||
|
||||
|
||||
- name: Install cross-compilation dependencies
|
||||
run: |
|
||||
sudo dpkg --add-architecture arm64
|
||||
# Configure sources for ARM64 packages - all ARM64 packages come from ports.ubuntu.com
|
||||
sudo tee /etc/apt/sources.list.d/arm64.list > /dev/null <<'EOF'
|
||||
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy main restricted universe multiverse
|
||||
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-updates main restricted universe multiverse
|
||||
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-backports main restricted universe multiverse
|
||||
deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports jammy-security main restricted universe multiverse
|
||||
EOF
|
||||
# Modify existing sources to exclude arm64 architecture
|
||||
sudo sed -i 's/^deb /deb [arch=amd64] /' /etc/apt/sources.list
|
||||
sudo apt-get update -y
|
||||
# Install build tools and cross-compilation libraries for Raspberry Pi 5
|
||||
sudo apt-get install -y gcc-aarch64-linux-gnu libudev-dev:arm64 pkg-config cmake libudev-dev
|
||||
# Ensure pkg-config can find ARM64 libraries
|
||||
sudo apt-get install -y libpkgconf3:arm64
|
||||
- name: Install Rust dependencies
|
||||
run: cargo fetch --target ${{ env.RUST_TARGET }}
|
||||
- name: Build release binary
|
||||
run: cargo build --release --target ${{ env.RUST_TARGET }}
|
||||
env:
|
||||
# Set linker for the target
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
|
||||
# Configure pkg-config for cross-compilation
|
||||
PKG_CONFIG_ALLOW_CROSS: 1
|
||||
PKG_CONFIG_PATH: /usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
PKG_CONFIG_LIBDIR: /usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
PKG_CONFIG_SYSROOT_DIR: /
|
||||
PKG_CONFIG_ALLOW_SYSTEM_LIBS: 1
|
||||
PKG_CONFIG_ALLOW_SYSTEM_CFLAGS: 1
|
||||
# Add library path for the cross-compiler's linker
|
||||
RUSTFLAGS: -L/usr/lib/aarch64-linux-gnu
|
||||
- name: Run tests on native platform
|
||||
run: cargo test --release --bin ntp_timeturner
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: timeturner-aarch64
|
||||
path: target/${{ env.RUST_TARGET }}/release/ntp_timeturner
|
||||
17
.gitignore
vendored
17
.gitignore
vendored
|
|
@ -361,3 +361,20 @@ MigrationBackup/
|
|||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
.aider*
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug
|
||||
target
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
# Generated by cargo mutants
|
||||
# Contains mutation testing data
|
||||
**/mutants.out*/
|
||||
# RustRover
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ edition = "2021"
|
|||
[dependencies]
|
||||
serialport = "4.2"
|
||||
chrono = "0.4"
|
||||
crossterm = "0.27"
|
||||
crossterm = "0.29"
|
||||
regex = "1.11"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
notify = "5.1.0"
|
||||
notify = "8.1.0"
|
||||
|
|
@ -28,8 +28,13 @@ Inspired by the TimeTurner in the Harry Potter series, this project synchronises
|
|||
|
||||
---
|
||||
|
||||
## 🚀 Installation
|
||||
## 🚀 Installation (to update)
|
||||
|
||||
|
||||
For Rust install you can do
|
||||
```bash
|
||||
cargo install --git https://github.com/cjfranko/NTP-Timeturner
|
||||
```
|
||||
Clone and run the installer:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -77,6 +77,17 @@ impl LtcState {
|
|||
match frame.status.as_str() {
|
||||
"LOCK" => {
|
||||
self.lock_count += 1;
|
||||
|
||||
// Every 5 seconds, recompute whether HH:MM:SS matches local time
|
||||
let now_secs = Utc::now().timestamp();
|
||||
if now_secs - self.last_match_check >= 5 {
|
||||
self.last_match_status = if frame.matches_system_time() {
|
||||
"IN SYNC".into()
|
||||
} else {
|
||||
"OUT OF SYNC".into()
|
||||
};
|
||||
self.last_match_check = now_secs;
|
||||
}
|
||||
}
|
||||
"FREE" => {
|
||||
self.free_count += 1;
|
||||
|
|
@ -86,17 +97,6 @@ impl LtcState {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
// Every 5 seconds, recompute whether HH:MM:SS matches local time
|
||||
let now_secs = Utc::now().timestamp();
|
||||
if now_secs - self.last_match_check >= 5 {
|
||||
self.last_match_status = if frame.matches_system_time() {
|
||||
"IN SYNC".into()
|
||||
} else {
|
||||
"OUT OF SYNC".into()
|
||||
};
|
||||
self.last_match_check = now_secs;
|
||||
}
|
||||
|
||||
self.latest = Some(frame);
|
||||
}
|
||||
|
||||
|
|
@ -135,3 +135,72 @@ impl LtcState {
|
|||
&self.last_match_status
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use chrono::{Local, Utc};
|
||||
|
||||
fn get_test_frame(status: &str, h: u32, m: u32, s: u32) -> LtcFrame {
|
||||
LtcFrame {
|
||||
status: status.to_string(),
|
||||
hours: h,
|
||||
minutes: m,
|
||||
seconds: s,
|
||||
frames: 0,
|
||||
frame_rate: 25.0,
|
||||
timestamp: Utc::now(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ltc_frame_matches_system_time() {
|
||||
let now = Local::now();
|
||||
let frame = get_test_frame("LOCK", now.hour(), now.minute(), now.second());
|
||||
assert!(frame.matches_system_time());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ltc_frame_does_not_match_system_time() {
|
||||
let now = Local::now();
|
||||
// Create a time that is one hour ahead, wrapping around 23:00
|
||||
let different_hour = (now.hour() + 1) % 24;
|
||||
let frame = get_test_frame("LOCK", different_hour, now.minute(), now.second());
|
||||
assert!(!frame.matches_system_time());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ltc_state_update_lock() {
|
||||
let mut state = LtcState::new();
|
||||
let frame = get_test_frame("LOCK", 10, 20, 30);
|
||||
state.update(frame);
|
||||
assert_eq!(state.lock_count, 1);
|
||||
assert_eq!(state.free_count, 0);
|
||||
assert!(state.latest.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ltc_state_update_free() {
|
||||
let mut state = LtcState::new();
|
||||
state.record_offset(100);
|
||||
assert!(!state.offset_history.is_empty());
|
||||
|
||||
let frame = get_test_frame("FREE", 10, 20, 30);
|
||||
state.update(frame);
|
||||
assert_eq!(state.lock_count, 0);
|
||||
assert_eq!(state.free_count, 1);
|
||||
assert!(state.offset_history.is_empty()); // Offsets should be cleared
|
||||
assert_eq!(state.last_match_status, "UNKNOWN");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_offset_history_management() {
|
||||
let mut state = LtcState::new();
|
||||
for i in 0..25 {
|
||||
state.record_offset(i);
|
||||
}
|
||||
assert_eq!(state.offset_history.len(), 20);
|
||||
assert_eq!(*state.offset_history.front().unwrap(), 5); // 0-4 are pushed out
|
||||
assert_eq!(*state.offset_history.back().unwrap(), 24);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue