Compare commits

..

8 Commits

Author SHA1 Message Date
Joris van Rantwijk f7dcab08b2 Update user manual 2026-03-03 21:03:35 +01:00
Joris van Rantwijk 66444a3067 Bump software version to 1.2 2026-03-01 15:17:59 +01:00
Joris van Rantwijk 4eb6ada765 Add command REALTIME? 2026-03-01 15:17:59 +01:00
Joris van Rantwijk 9687b65b6f Add password management script 2026-03-01 15:17:59 +01:00
Joris van Rantwijk d38617c98f Run init scripts in subshells
Rename custom init scripts so they will run in separate shell processes
rather than being sourced into rcS/rcK.
2026-03-01 15:17:59 +01:00
Joris van Rantwijk 051f24dc2d Add script to configure NTP 2026-03-01 15:17:55 +01:00
Joris van Rantwijk 7fcf233489 Fix typo in IP configuration script 2026-03-01 15:17:39 +01:00
Joris van Rantwijk 2a1cf374b3 Use static NTP server configuration
Ignore NTP servers provided via DHCP.
Enable real-time scheduling for Chrony.
2026-02-08 15:57:58 +01:00
19 changed files with 350 additions and 42 deletions

View File

@ -211,7 +211,20 @@ to open the USB serial port of the Red Pitaya.
Set the baud rate to 115200 bps, character format to `8N1`.
Press Enter to get a login prompt on the console.
Use login `root` with password `root`.
Login as user `root`.
The default password is `root`.
### Changing the password
The default login password is `root`, but this can be changed.
To change the password, login on the console and run the command `puzzle-passwd`.
The tool will prompt to type a new root password.
The changed password will be persistently stored on the SD card.
Do not use the normal Unix command `passwd`.
This tool does not write the new password to the SD card; therefore the changes will be forgotten after reboot.
## Network access
@ -241,16 +254,47 @@ This is the same host name as used by the official Red Pitaya software.
It is possible to run an SSH server on the Red Pitaya.
This can be used to remotely log in on the Linux system.
To login via SSH, use username `root` with password `root`.
To login via SSH, use username `root` and the same password used for logging in via the USB console.
For security reasons, the SSH server is disabled by default.
The default password is `root`.
It is recommended to change the password before enabling SSH access.
An SSH server with an easy-to-guess password should never be connected to an untrusted network.
If you want to use the SSH server, you have to enable it explicitly.
To enable the SSH server, login on the USB console as described above.
Then run the following command: `puzzle-sshcfg enable` .
Finally, run `reboot` to reboot the Red Pitaya.
For security reasons, the SSH server is disabled by default.
If you want to login via SSH, it must be enabled explicitly.
Use the following steps to enable the SSH server:
- Login on the USB console as described above.
- Set a safe password by running command: `puzzle-passwd`
- Enable the SSH server by running command: `puzzle-sshcfg enable`
- Reboot the Red Pitaya by running command: `reboot`
From this point onward, the SSH server will be started automatically during boot.
You can again use the command `puzzle-sshcfg` to disable SSH access.
### NTP configuration
Optionally, an NTP server may be configured to synchronize the system clock via the network.
Without an NTP server, the system clock of the Red Pitaya is initialized to the year 1970 on power-on.
The only feature that uses the system clock is the remote control command `REALTIME?` .
If this command is used, configuring an NTP server is necessary to get correct results.
If this command is not used, synchronizing the system clock is not important.
To configure an NTP server, use the following steps:
- Login on the Red Pitaya via USB console or SSH as described above.
- Run the command `puzzle-ntpcfg server <IP-address>` .
This command configures Chrony to synchronize to the specified NTP server.
The configuration is also written to the SD card and used during boot.
Optionally, a poll interval can be specified as a power of 2 in seconds.
For example: `puzzle-ntpcfg server <IP-address> poll 5` specifies a poll interval of 32 seconds.
Sub-millisecond accuracy can be achieved with an NTP server in the local network and `poll 0` (poll each second).
Poll intervals shorter than 64 seconds must only be used with a dedicated NTP server in the local network.
Using such short poll intervals with a public NTP server is considered abuse.
## Data stream protocol
@ -330,6 +374,7 @@ In the response string, such data elements are separated by space characters.
| `*IDN?` | Instrument identification. |
| `RESET` | Restore default settings. |
| `TIMESTAMP?` | Timestamp counter. |
| `REALTIME?` | System time and timestamp counter. |
| `AIN:CHANNELS:COUNT?` | Number of input channels. |
| `AIN:CHANNELS:ACTIVE` | Number of active input channels. |
| `AIN:CHn:RANGE` | Analog input range. |
@ -391,6 +436,23 @@ Any ongoing analog acquisition is stopped.
Query: `TIMESTAMP?` <br>
Response: decimal integer, representing the current timestamp in units of 8 ns.
### `REALTIME?`
Query: `REALTIME?` <br>
Response: system time and firmware timestamp, separated by a space character.
The system time is represented as a floating point number denoting the number of seconds since 1970-01-01 00:00 UTC (ignoring leap seconds).
The firmware timestamp is represented as a decimal integer denoting the current timestamp in units of 8 ns.
This command is only useful if the Red Pitaya is configured to synchronize its system clock via NTP.
Without NTP, the system time of the Red Pitaya will be incorrect and essentially meaningless.
The system time and firmware timestamp are captured nearly simultaneous, but not exactly simultaneous.
The mismatch between these two time values is almost always less than 10 microseconds.
The overall accuracy of the system time is limited by the synchronization via NTP.
In practice, sub-millisecond accuracy is possible with an NTP server in the local network.
### `AIN:CHANNELS:COUNT?`
Query: `AIN:CHANNELS:COUNT?` <br>

View File

@ -1,3 +1,4 @@
include /etc/chrony_dhcp.conf
pool pool.ntp.org iburst
sourcedir /etc/chrony/sources.d
makestep 0.1 3
sched_priority 1
cmdport 0

View File

@ -1,3 +1,7 @@
# Disable chrony (NTP client)
# Only start Chrony if an NTP server is configured.
if [ ! -f /etc/chrony/sources.d/ntp.sources ]; then
echo "NTP server not configured, not starting chrony."
exit 1
fi
exit

View File

@ -5,6 +5,21 @@
. /opt/puzzlefw/lib/functions.sh
# Copy root password from configuration partition.
copy_passwd() {
# Do nothing if there is no password on the configuration partition.
[ -f ${CONFIG_DIR}/passwd.conf ] || return
# Do nothing if there is no root password entry in the config file.
grep "^root:" ${CONFIG_DIR}/passwd.conf > /etc/shadow.new || return
grep -v "^root:" /etc/shadow >> /etc/shadow.new
chmod 0600 /etc/shadow.new
mv /etc/shadow.new /etc/shadow
}
# Copy SSH host key from configuration partition.
copy_ssh_host_key() {
@ -25,12 +40,24 @@ copy_ssh_host_key() {
chmod 0600 /etc/dropbear/dropbear_ed25519_host_key || true
}
# Take NTP server from configuration partition.
copy_ntp_server() {
# If an NTP server is configured, copy it to Chrony configuration.
if [ -s ${CONFIG_DIR}/ntp.sources ]; then
mkdir -p /etc/chrony/sources.d
cp -p ${CONFIG_DIR}/ntp.sources /etc/chrony/sources.d
fi
}
case "$1" in
start)
echo "Reading configuration files from SD card ..."
lock_config || exit 1
read_config || exit 1
copy_passwd
copy_ssh_host_key
copy_ntp_server
;;
stop|restart|reload)
true

View File

@ -276,7 +276,7 @@ case "$1" in
*)
script="${0##*/}"
cat <<EOF
Usage: $script {init|show|config|save|restart}
Usage: $script {init|show|config|save}
Manage IP address configuration.

View File

@ -0,0 +1,171 @@
#!/bin/sh
#
# Manage NTP configuration.
#
. /opt/puzzlefw/lib/functions.sh
# Show current configuration.
ntpcfg_show() {
echo "Active NTP configuration:"
if [ -s /etc/chrony/sources.d/ntp.sources ]; then
cat /etc/chrony/sources.d/ntp.sources
else
echo "disabled"
fi
echo
echo "Saved NTP configuration:"
if [ -s ${CONFIG_DIR}/ntp.sources ]; then
cat ${CONFIG_DIR}/ntp.sources
else
echo "disabled"
fi
echo
}
# Check that parameter is a well-formed IPv4 address.
check_ipaddr() {
IFS="." read a b c d <<EOF
$1
EOF
for i in "$a" "$b" "$c" "$d" ; do
if ! [ "$i" -ge 0 -a "$i" -le 255 ]; then
echo "ERROR: Invalid IP address '$1'" >&2
exit 1
fi
done
}
# Configure and enable Chrony.
ntpcfg_server() {
if [ "$1" != "server" ]; then
echo "ERROR: Invalid command '$1'" >&2
exit 1
fi
NTPSERVER="$2"
if [ -z "$NTPSERVER" ]; then
echo "ERROR: Server IP address not specified" >&2
exit 1
fi
check_ipaddr "$NTPSERVER"
POLLOPTS=""
if [ "$#" -gt 2 ]; then
if [ "$3" != "poll" ]; then
echo "ERROR: Unknown option '$3'" >&2
exit 1
fi
POLLINT="$4"
if [ -z "$POLLINT" ]; then
echo "ERROR: Poll interval not specified" >&2
exit 1
fi
if ! [ "$POLLINT" -ge "-1" -a "$POLLINT" -le "10" ]; then
echo "ERROR: Invalid poll interval '$POLLINT', must be between -1 and 10" >&2
exit 1
fi
POLLOPTS="minpoll $POLLINT maxpoll $POLLINT"
if [ "$#" -gt 4 ]; then
echo "ERROR: Unexpected option '$5'" >&2
exit 1
fi
fi
# Lock to avoid conflicting changes.
lock_config || exit 1
echo "Configuring Chrony to start on boot with server $NTPSERVER ..."
SERVERLINE="server $NTPSERVER $POLLOPTS iburst prefer"
echo "$SERVERLINE" > ${CONFIG_DIR}/ntp.sources.new
sync_config ntp.sources || exit 1
mkdir -p /etc/chrony/sources.d
cp -p ${CONFIG_DIR}/ntp.sources /etc/chrony/sources.d
echo
echo "New NTP configuration:"
cat /etc/chrony/sources.d/ntp.sources
echo
echo "Restarting Chrony ..."
/etc/init.d/S49chrony restart
}
# Disable starting Chrony during boot.
ntpcfg_disable() {
# Lock to avoid conflicting changes.
lock_config || exit 1
echo "Disabling Chrony startup on boot ..."
echo -n "" > ${CONFIG_DIR}/ntp.sources.new
sync_config ntp.sources || exit 1
echo "Stopping Chrony ..."
/etc/init.d/S49chrony stop
rm -f /etc/chrony/sources.d/ntp.sources
}
case "$1" in
show)
ntpcfg_show
;;
server)
ntpcfg_server "$@"
;;
disable)
ntpcfg_disable
;;
*)
script="${0##*/}"
cat <<EOF
Usage: $script {server|disable|show}
Manage NTP server configuration.
$script server {IP-address} [poll N]
Enable starting Chrony during boot and specify NTP server to use.
Optionally, the poll interval can be specified as a power of 2 in seconds,
for example "poll 5" means a polling interval of 32 seconds. By default,
the poll interval starts at 6 (64 seconds) and slowly steps up to
10 (1024 seconds).
Sub-millisecond accuracy can be achieved with an NTP server in the local
network and "poll 0" (poll each second).
Do not use a poll interval shorter than 64 seconds unless the NTP server
is in the local network. Doing this with a public NTP server is
considered abuse.
$script disable
Disable starting Chrony during boot and stop Chrony if it was running.
$script show
Display NTP configuration.
EOF
exit 1
;;
esac
exit $?

View File

@ -0,0 +1,32 @@
#!/bin/sh
#
# Password change tool.
#
. /opt/puzzlefw/lib/functions.sh
# Store changed password on the SD card.
store_password() {
# Lock to avoid conflicting changes.
lock_config || exit 1
echo "Writing new password to SD card ..."
grep "^root:" /etc/shadow > ${CONFIG_DIR}/passwd.conf.new
sync_config passwd.conf || exit 1
}
if [ $# -ne 0 ]; then
script="${0##*/}"
cat <<EOF
Usage: $script
Change root password and write the new password hash to the SD card
to make it persistent accross reboot.
EOF
exit 1
fi
passwd && store_password

View File

@ -62,6 +62,11 @@ enable() {
echo "start_ssh=1" > ${CONFIG_DIR}/start_ssh.conf.new
sync_config start_ssh.conf || exit 1
echo
echo "NOTE: Please remember to set a non-default root password."
echo " Use 'puzzle-passwd' to change the root password."
}
# Disable starting SSH server during boot.

View File

@ -33,6 +33,7 @@ read_config() {
# Copy config files to RAM filesystem.
cp -a ${CONFIG_MOUNTPOINT}/*.conf $CONFIG_DIR || true
cp -a ${CONFIG_MOUNTPOINT}/ntp.sources $CONFIG_DIR || true
cp -a ${CONFIG_MOUNTPOINT}/dropbear_* $CONFIG_DIR || true
umount $CONFIG_MOUNTPOINT

View File

@ -1,29 +0,0 @@
#!/bin/sh
#
# Configure chrony to use NTP server advertised by DHCP server.
#
configure_ntp() {
# Do nothing if the DHCP server does not advertise any NTP server.
[ -z "$ntpsrv" ] && return
# Write config snippet with NTP servers.
for srv in $ntpsrv ; do
echo "server $srv iburst"
done > /etc/chrony_dhcp.conf.new
# Compare to currently configured NTP servers.
if ! diff -q /etc/chrony_dhcp.conf /etc/chrony_dhcp.conf.new >/dev/null ; then
# Update configuration and restart Chrony.
mv /etc/chrony_dhcp.conf.new /etc/chrony_dhcp.conf
/etc/init.d/S49chrony reload
fi
}
case "$1" in
renew|bound)
configure_ntp
;;
esac

View File

@ -12,6 +12,7 @@
#include <math.h>
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#include <algorithm>
#include <chrono>
#include <fstream>
@ -776,6 +777,38 @@ private:
return std::to_string(timestamp);
}
/** Handle command REALTIME? */
std::string qry_realtime(CommandEnvironment env)
{
struct timespec tp1, tp2, tp3;
uint64_t ts1, ts2, ts3, ts4;
// Read approximately simultaneous real time and timestamp.
ts1 = m_device.get_timestamp();
clock_gettime(CLOCK_REALTIME, &tp1);
ts2 = m_device.get_timestamp();
clock_gettime(CLOCK_REALTIME, &tp2);
ts3 = m_device.get_timestamp();
clock_gettime(CLOCK_REALTIME, &tp3);
ts4 = m_device.get_timestamp();
// Choose shortest interval out of three.
const uint64_t timestamp_mask = 0xffffffffffff;
uint64_t d1 = (ts2 - ts1) & timestamp_mask;
uint64_t d2 = (ts3 - ts2) & timestamp_mask;
uint64_t d3 = (ts4 - ts3) & timestamp_mask;
if (d3 < d1 && d3 < d2) {
ts1 = ts3;
tp1 = tp3;
} else if (d2 < d1) {
ts1 = ts2;
tp1 = tp2;
}
return str_format("%lld.%09ld %llu",
(long long)tp1.tv_sec, (long)tp1.tv_nsec, ts1);
}
/** Handle command AIN:CHANNELS:COUNT? */
std::string qry_channels_count(CommandEnvironment env)
{
@ -1424,6 +1457,7 @@ private:
command_table_no_args = {
{ "*idn?", &CommandHandler::qry_idn },
{ "timestamp?", &CommandHandler::qry_timestamp },
{ "realtime?", &CommandHandler::qry_realtime },
{ "ain:channels:count?", &CommandHandler::qry_channels_count },
{ "ain:channels:active?", &CommandHandler::qry_channels_active },
{ "ain:chN:range?", &CommandHandler::qry_channel_range },

View File

@ -1,2 +1,2 @@
#define PUZZLEFW_SW_MAJOR 1
#define PUZZLEFW_SW_MINOR 1
#define PUZZLEFW_SW_MINOR 2