Skip to content

Commit

Permalink
Merge pull request #23 from projecthorus/testing
Browse files Browse the repository at this point in the history
Merge in libcamera2 updates.
  • Loading branch information
darksidelemm authored Dec 23, 2024
2 parents 0da4d5a + 45e68e4 commit d491a3c
Show file tree
Hide file tree
Showing 35 changed files with 1,389 additions and 860 deletions.
9 changes: 6 additions & 3 deletions .github/workflows/container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- 'master'
- 'testing'
pull_request:
workflow_dispatch:
schedule:
Expand All @@ -18,11 +19,13 @@ jobs:

- name: Calculate Container Metadata
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v4
with:
images: ghcr.io/${{ github.repository }}
flavor: |
latest=true
tags: |
type=raw,value=latest,enable={{is_default_branch}}
type=ref,event=branch
type=ref,event=tag
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
Expand Down
35 changes: 23 additions & 12 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,11 @@ FROM debian:buster-slim AS build
# Install build dependencies.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
build-essential \
cmake \
git \
libusb-1.0-0-dev \
pkg-config \
libatlas-base-dev \
python3 \
python3-dev \
python3-pip \
python3-setuptools \
python3-numpy \
python3-wheel && \
build-essential cmake git libusb-1.0-0-dev pkg-config libatlas-base-dev \
python3 python3-dev python3-pip python3-setuptools python3-numpy python3-wheel \
libairspy-dev libairspyhf-dev libavahi-client-dev libbsd-dev libfftw3-dev \
libhackrf-dev libiniparser-dev libncurses5-dev libopus-dev librtlsdr-dev \
libusb-1.0-0-dev libusb-dev portaudio19-dev libasound2-dev uuid-dev rsync && \
rm -rf /var/lib/apt/lists/*

# Compile and install rtl-sdr.
Expand All @@ -36,6 +29,17 @@ RUN git clone https://github.com/fsphil/ssdv.git /root/ssdv && \
DESTDIR=/root/target make install && \
rm -rf /root/ssdv

# Compile and install pcmcat and tune from KA9Q-Radio
RUN git clone https://github.com/ka9q/ka9q-radio.git /root/ka9q-radio && \
#RUN git clone https://github.com/fventuri/ka9q-radio.git /root/ka9q-radio && \
cd /root/ka9q-radio && \
git checkout aa7791f && \
# git checkout sdrplay && \
make -f Makefile.linux pcmcat tune && \
mkdir -p /root/target/usr/local/bin/ && \
cp pcmcat /root/target/usr/local/bin/ && \
rm -rf /root/ka9q-radio

# Install Python packages.
# Removed numpy from this list, using system packages.
# --no-binary numpy
Expand All @@ -48,6 +52,7 @@ RUN --mount=type=cache,target=/root/.cache/pip pip3 install \
requests \
sondehub


# Copy in wenet.
COPY . /root/wenet

Expand All @@ -69,9 +74,15 @@ RUN apt-get update && \
libusb-1.0-0 \
python3 \
python3-numpy \
libbsd0 \
avahi-utils \
libnss-mdns \
tini && \
rm -rf /var/lib/apt/lists/*

# Allow mDNS resolution
RUN sed -i -e 's/files dns/files mdns4_minimal [NOTFOUND=return] dns/g' /etc/nsswitch.conf

# Copy compiled dependencies from the build container.
COPY --from=build /root/target /
RUN ldconfig
Expand Down
54 changes: 46 additions & 8 deletions rx/WenetPackets.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
# Check if we are running in Python 2 or 3
PY3 = sys.version_info[0] == 3

WENET_VERSION = "1.1.0"
WENET_VERSION = "1.2.1"

WENET_IMAGE_UDP_PORT = 7890
WENET_TELEMETRY_UDP_PORT = 55672
Expand All @@ -36,9 +36,9 @@ class WENET_PACKET_TYPES:


class WENET_PACKET_LENGTHS:
GPS_TELEMETRY = 35
ORIENTATION_TELEMETRY = 43
IMAGE_TELEMETRY = 80
GPS_TELEMETRY = 73
ORIENTATION_TELEMETRY = 43
IMAGE_TELEMETRY = 80


def decode_packet_type(packet):
Expand Down Expand Up @@ -178,7 +178,8 @@ def gps_telemetry_decoder(packet):
""" Extract GPS telemetry data from a packet, and return it as a dictionary.
Keyword Arguments:
packet: A GPS telemetry packet, as per https://docs.google.com/document/d/12230J1X3r2-IcLVLkeaVmIXqFeo3uheurFakElIaPVo/edit?usp=sharing
packet: A GPS telemetry packet, as per
https://github.com/projecthorus/wenet/wiki/Modem-&-Packet-Format-Details#0x01---gps-telemetry
This can be provided as either a string, or a list of integers, which will be converted
to a string prior to decoding.
Expand Down Expand Up @@ -207,7 +208,7 @@ def gps_telemetry_decoder(packet):
# Wrap the next bit in exception handling.
try:
# Unpack the packet into a list.
data = struct.unpack('>BHIBffffffBBB', packet)
data = struct.unpack(">BHIBffffffBBBffHfffffff", packet)

gps_data['week'] = data[1]
gps_data['iTOW'] = data[2]/1000.0 # iTOW provided as milliseconds, convert to seconds.
Expand All @@ -221,6 +222,33 @@ def gps_telemetry_decoder(packet):
gps_data['numSV'] = data[10]
gps_data['gpsFix'] = data[11]
gps_data['dynamic_model'] = data[12]
# New fields 2024-09
gps_data['radio_temp'] = round(data[13],1)
gps_data['cpu_temp'] = round(data[14],1)
gps_data['cpu_speed'] = data[15]
gps_data['load_avg_1'] = round(data[16],3)
gps_data['load_avg_5'] = round(data[17],3)
gps_data['load_avg_15'] = round(data[18],3)
gps_data['disk_percent'] = round(data[19],3)
gps_data['lens_position'] = round(data[20],4)
gps_data['sensor_temp'] = round(data[21],1)
gps_data['focus_fom'] = int(data[22])
# Check to see if we actually have real data in these new fields.
# If its an old transmitter, it will have 0x55 in these spots, which we can detect
if gps_data['cpu_speed'] == 21845:
# 0x5555 -> 21825, which we use as an indication that padding is in use.
# Set all the new fields to invalid values
gps_data['radio_temp'] = -999.0
gps_data['cpu_temp'] = -999.0
gps_data['cpu_speed'] = 0
gps_data['load_avg_1'] = 0
gps_data['load_avg_5'] = 0
gps_data['load_avg_15'] = 0
gps_data['disk_percent'] = -1.0
gps_data['lens_position'] = -999.0
gps_data['sensor_temp'] = -999.0
gps_data['focus_fom'] = -999.0


# Perform some post-processing on the data, to make some of the fields easier to read.

Expand Down Expand Up @@ -281,7 +309,7 @@ def gps_telemetry_string(packet):
if gps_data['error'] != 'None':
return "GPS: ERROR Could not decode."
else:
gps_data_string = "GPS: %s Lat/Lon: %.5f,%.5f Alt: %dm, Speed: H %dkph V %.1fm/s, Heading: %d deg, Fix: %s, SVs: %d, Model: %s " % (
gps_data_string = "GPS: %s Lat/Lon: %.5f,%.5f Alt: %dm, Speed: H %dkph V %.1fm/s, Heading: %d deg, Fix: %s, SVs: %d, DynModel: %s, Radio Temp: %.1f, CPU Temp: %.1f, CPU Speed: %d, Load Avg: %.2f, %.2f, %.2f, Disk Usage: %.1f%%, Lens Pos: %.4f, Sensor Temp: %.1f, FocusFoM: %d" % (
gps_data['timestamp'],
gps_data['latitude'],
gps_data['longitude'],
Expand All @@ -291,7 +319,17 @@ def gps_telemetry_string(packet):
int(gps_data['heading']),
gps_data['gpsFix_str'],
gps_data['numSV'],
gps_data['dynamic_model_str']
gps_data['dynamic_model_str'],
gps_data['radio_temp'],
gps_data['cpu_temp'],
gps_data['cpu_speed'],
gps_data['load_avg_1'],
gps_data['load_avg_5'],
gps_data['load_avg_15'],
gps_data['disk_percent'],
gps_data['lens_position'],
gps_data['sensor_temp'],
int(gps_data['focus_fom'])
)

return gps_data_string
Expand Down
11 changes: 7 additions & 4 deletions rx/fskstatsudp.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,11 @@ def log_error(self, line):



def send_modem_stats(stats):
def send_modem_stats(stats, udp_port=WENET_IMAGE_UDP_PORT):
""" Send a JSON-encoded dictionary to the wenet frontend """
try:
gui_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
gui_socket.sendto(json.dumps(stats).encode('ascii'), ("127.0.0.1", WENET_IMAGE_UDP_PORT))
gui_socket.sendto(json.dumps(stats).encode('ascii'), ("127.0.0.1", udp_port))
gui_socket.close()

except Exception as e:
Expand All @@ -186,12 +186,15 @@ def send_modem_stats(stats):
parser.add_argument("--freq", default=441200000, type=float, help="IQ Centre Frequency (Hz)")
parser.add_argument("--samplerate", default=921416, type=float, help="Sample rate (Hz)")
parser.add_argument("--real", default=False, action="store_true", help="Real Samples (not IQ)")
parser.add_argument("--image_port", type=int, default=None, help="UDP port used for communication between Wenet decoder processes. Default: 7890")
args = parser.parse_args()

_averaging_time = 1.0/args.rate

stats_parser = FSKDemodStats(averaging_time=_averaging_time, peak_hold=True, freq=args.freq, sample_rate=args.samplerate, real=args.real)

# Overwrite the image UDP port if it has been provided
if args.image_port:
WENET_IMAGE_UDP_PORT = args.image_port

_last_update_time = time.time()

Expand Down Expand Up @@ -220,7 +223,7 @@ def send_modem_stats(stats):
'time': datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%SZ")
}

send_modem_stats(_stats)
send_modem_stats(_stats, udp_port=WENET_IMAGE_UDP_PORT)

_last_update_time = time.time()

Expand Down
5 changes: 5 additions & 0 deletions rx/rx_gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ def udp_rx():

parser = argparse.ArgumentParser()
parser.add_argument("-v", "--verbose", action='store_true', default=False, help="Verbose output")
parser.add_argument("--image_port", type=int, default=None, help="UDP port used for communication between Wenet decoder processes. Default: 7890")
args = parser.parse_args()

if args.verbose:
Expand All @@ -140,6 +141,10 @@ def udp_rx():

logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s', level=log_level)

# Overwrite the image UDP port if it has been provided
if args.image_port:
WENET_IMAGE_UDP_PORT = args.image_port

app = QtWidgets.QApplication(sys.argv)
app.setApplicationName('SSDV Viewer')

Expand Down
20 changes: 19 additions & 1 deletion rx/rx_ssdv.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,19 @@
parser.add_argument("-v", "--verbose", action='store_true', default=False, help="Verbose output")
parser.add_argument("--headless", action='store_true', default=False, help="Headless mode - broadcasts additional data via UDP.")
parser.add_argument("--rximages", default="./rx_images/", help="Location to save RX images and telemetry to.")
parser.add_argument("--image_port", type=int, default=None, help="UDP port used for communication between Wenet decoder processes. Default: 7890")
parser.add_argument("--telemetry_port", type=int, default=None, help="UDP port used to emit telemetry to other applications. Default: 55672")
args = parser.parse_args()

RX_IMAGES_DIR = args.rximages

# Overwrite the image and telemetry UDP ports if they have been provided
if args.image_port:
WENET_IMAGE_UDP_PORT = args.image_port

if args.telemetry_port:
WENET_TELEMETRY_UDP_PORT = args.telemetry_port

# Set up log output.
if args.verbose:
log_level = logging.DEBUG
Expand All @@ -50,6 +59,8 @@

# GUI updates are only sent locally.
def trigger_gui_update(filename, text = "None", metadata = None):
global WENET_IMAGE_UDP_PORT

message = {'filename': filename,
'text': text,
'metadata': metadata}
Expand All @@ -62,6 +73,7 @@ def trigger_gui_update(filename, text = "None", metadata = None):
# Telemetry packets are send via UDP broadcast in case there is other software on the local
# network that wants them.
def broadcast_telemetry_packet(data, headless=False):
global WENET_IMAGE_UDP_PORT, WENET_TELEMETRY_UDP_PORT
telemetry_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
# Set up the telemetry socket so it can be re-used.
telemetry_socket.setsockopt(socket.SOL_SOCKET,socket.SO_BROADCAST,1)
Expand Down Expand Up @@ -152,6 +164,11 @@ def log_telemetry_packet(packet):


while True:

# These reads can hang if the rtl_sdr locks up
# We should add some kind of watchdog system around this, so if we don't seee
# any packets for X minutes, the process exits, and is (hopefully) restarted by systemd.

if args.hex:
# Incoming data is as a hexadecimal string.
# We can read these in safely using sys.stdin.readline(),
Expand Down Expand Up @@ -212,7 +229,7 @@ def log_telemetry_packet(packet):

# Only proceed if there are no decode errors.
if packet_info['error'] != 'None':
logging.error(message['error'])
logging.error(packet_info['error'])
continue

if (packet_info['image_id'] != current_image) or (packet_info['callsign'] != current_callsign) :
Expand Down Expand Up @@ -264,4 +281,5 @@ def log_telemetry_packet(packet):
logging.debug("Unknown Packet Format.")

except Exception as e:
logging.exception(e)
logging.error("Error handling packet - " + str(e))
7 changes: 6 additions & 1 deletion rx/ssdvuploader.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def ssdv_encode_packet(self, packet):


def ssdv_upload_single(self, packet):
_packet_dict = self.ssdv_encode_packet(packet,callsign)
_packet_dict = self.ssdv_encode_packet(packet)

_attempts = 1
while _attempts <= self.upload_retries:
Expand Down Expand Up @@ -354,6 +354,7 @@ def telemetry_gui_update(queued, uploaded, discarded):
parser.add_argument("--file_mask", default="*.bin", help="File mask to watch (Defaut: *.bin)")
parser.add_argument("--queue_size", default=8192, type=int, help="Uploader queue size (Default: 8192 packets = ~2MiB)")
parser.add_argument("--upload_block_size", default=256, type=int, help="Upload block size (Default: 256 packets uploaded at a time.)")
parser.add_argument("--image_port", type=int, default=None, help="UDP port used for communication between Wenet decoder processes. Default: 7890")
parser.add_argument("-v", "--verbose", action='store_true', default=False, help="Verbose logging output.")
args = parser.parse_args()

Expand All @@ -368,6 +369,10 @@ def telemetry_gui_update(queued, uploaded, discarded):
logging.getLogger("urllib3").setLevel(logging.CRITICAL)


# Overwrite the image UDP port if it has been provided
if args.image_port:
WENET_IMAGE_UDP_PORT = args.image_port

_uploader = SSDVUploader(
uploader_callsign = args.callsign,
watch_directory = args.watch_dir,
Expand Down
Loading

0 comments on commit d491a3c

Please sign in to comment.