Skip to content

Commit

Permalink
Ci stuff (#35)
Browse files Browse the repository at this point in the history
* init
 
* added a bunch of tests, and made minor code mods to increase (mostly) code coverage

* maybe 3.11 does not like tuples in foreaches?
  • Loading branch information
peads authored Jul 17, 2024
1 parent 9a1c195 commit 40e9724
Show file tree
Hide file tree
Showing 15 changed files with 221 additions and 88 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
echo "checksum matched: ${i}"
cnt=$(( cnt + 1 ));
else
printf "${setBlue}FAILED: ${i}\n\tEXPECTED: ${sums["$i"]}\n\tRECEIVED: ${z["$i"]}\n${setNormal}" 1>&2;
printf "\033[31mFAILED: ${i}\n\tEXPECTED: ${sums["$i"]}\n\tRECEIVED: ${z["$i"]}\n\033[31m" 1>&2;
fi
done
(( cnt == total ))
(( cnt == total ))
2 changes: 1 addition & 1 deletion example.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ if [[ -z ${DSD_CMD} ]]; then
fi

if [[ -z ${OUT_PATH} ]]; then
OUT_PATH=/mnt/d/simo;
OUT_PATH=/tmp;
fi

echo $SDRTERM_EXEC;
Expand Down
2 changes: 1 addition & 1 deletion example_simo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ if [[ -z ${DSD_CMD} ]]; then
fi

if [[ -z ${OUT_PATH} ]]; then
OUT_PATH=/mnt/d/simo;
OUT_PATH=/tmp;
fi

declare -A pids;
Expand Down
30 changes: 17 additions & 13 deletions src/dsp/dsp_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from scipy.signal import decimate, dlti, savgol_filter, sosfilt, ellip

from dsp.data_processor import DataProcessor
from dsp.demodulation import amDemod, fmDemod
from dsp.demodulation import amDemod, fmDemod, realOutput, imagOutput
from misc.general_util import vprint


Expand Down Expand Up @@ -56,6 +56,7 @@ def __init__(self,
fileInfo: dict = None,
**kwargs):

self._demod = None
self._pool = None
self._shift = None
self.bandwidth \
Expand Down Expand Up @@ -131,36 +132,39 @@ def demod(x):
setattr(self, 'demod', demod)
return ret

def _demod(self, y: ndarray[any, dtype[complex64 | complex128]]) -> ndarray[any, dtype[float32 | float64]]:
pass

def _setDemod(self,
fun: Callable[[ndarray[any, dtype[complex64 | complex128]]], ndarray[any, dtype[float32 | float64]]],
*filters) \
-> Callable[[ndarray[any, dtype[complex64 | complex128]]], ndarray[any, dtype[float32 | float64]]]:

if fun is not None and len(filters):
if fun is not None:
self._outputFilters.clear()
self._outputFilters.extend(*filters)
if len(filters):
self._outputFilters.extend(*filters)
setattr(self, '_demod', fun)
return self.demod
raise ValueError("Demodulation function, or filters not defined")

def selectOuputFm(self):
def selectOutputFm(self):
vprint('NFM Selected')
self.bandwidth = 12500
self._setDemod(fmDemod, generateEllipFilter(self.__decimatedFs, self._FILTER_DEGREE, self.omegaOut, 'lowpass'))

def selectOuputWfm(self):
vprint('WFM Selected')
self.bandwidth = 25000
self._setDemod(fmDemod, generateEllipFilter(self.__decimatedFs, self._FILTER_DEGREE, self.omegaOut, 'lowpass'))

def selectOuputAm(self):
def selectOutputAm(self):
vprint('AM Selected')
self.bandwidth = 10000
self._setDemod(amDemod, generateEllipFilter(self.__decimatedFs, self._FILTER_DEGREE, self.omegaOut, 'lowpass'))

def selectOutputReal(self):
vprint('I output Selected')
self.bandwidth = self.decimatedFs
self._setDemod(realOutput)

def selectOutputImag(self):
vprint('Q output Selected')
self.bandwidth = self.decimatedFs
self._setDemod(imagOutput)

def _processChunk(self, y: ndarray) -> ndarray[any, dtype[float32 | float64]]:
if self._shift is not None:
'''
Expand Down
11 changes: 8 additions & 3 deletions src/dsp/vfo_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,12 @@ def __init__(self, fs, vfoHost: str = 'localhost', vfos: str = None, **kwargs):
self.vfos = array(self.vfos)
self._nFreq = len(self.vfos)
self.__omega = -2j * pi * (self.vfos / self.fs)
self.host = vfoHost

if ':' in vfoHost:
self.host, self.port = vfoHost.split(':')
self.port = int(self.port)
else:
self.host = vfoHost
self.port = findPort(self.host)
self.__queue: Queue[str] | None = None
self.__clients: dict[str, RawIOBase] | None = None
self.__event: Event | None = None
Expand Down Expand Up @@ -98,7 +102,7 @@ def handle(self):
self.outer_self.queue.task_done()
self.outer_self.event.wait()

with ThreadedTCPServer((self.host, findPort(self.host)), ThreadedTCPRequestHandler) as server:
with ThreadedTCPServer((self.host, self.port), ThreadedTCPRequestHandler) as server:
st = Thread(target=server.serve_forever)

try:
Expand All @@ -120,5 +124,6 @@ def handle(self):
with self.__queue.all_tasks_done:
self.__queue.all_tasks_done.notify_all()
st.join()
self._pool.shutdown(wait=False, cancel_futures=True)
vprint('Multi-VFO writer halted')
return
84 changes: 50 additions & 34 deletions src/misc/io_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,34 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from enum import Enum
from multiprocessing import Queue, Process
from typing import Callable

from misc.general_util import tprint

def selectDemodulation(demodType: str, processor) -> Callable:
if demodType == 'fm' or demodType == 'nfm':
return processor.selectOuputFm
elif demodType == 'am':
return processor.selectOuputAm
else:
raise ValueError(f'Invalid demod type {demodType}')

class DemodulationChoices(str, Enum):
FM = "fm"
AM = "am"
REAL = "re"
IMAG = "im"

def __str__(self):
return self.value


def selectDemodulation(demodType: DemodulationChoices, processor) -> Callable:
tprint(f'{demodType} requested')
if 'fm' == demodType or 'nfm' == demodType:
return processor.selectOutputFm
elif 'am' == demodType:
return processor.selectOutputAm
elif 're' == demodType:
return processor.selectOutputReal
elif 'im' == demodType:
return processor.selectOutputImag
raise ValueError(f'Invalid demod type {demodType}')


def selectPlotType(plotType: str):
Expand Down Expand Up @@ -65,12 +82,12 @@ def __init__(self, verbose: int = 0, **kwargs):
kwargs['fileInfo'] = checkWavHeader(kwargs['inFile'], kwargs['fs'], kwargs['enc'])
kwargs['fs'] = kwargs['fileInfo']['sampRate']

IOArgs.__initializeOutputHandlers(**kwargs)
IOArgs._initializeOutputHandlers(**kwargs)
kwargs['isDead'].value = 0

@classmethod
def __initializeProcess(cls, isDead: Value, processor, *args,
name: str = 'Process', **kwargs) -> tuple[Queue, Process]:
def _initializeProcess(cls, isDead: Value, processor, *args,
name: str = 'Process', **kwargs) -> tuple[Queue, Process]:
if processor is None:
raise ValueError('Processor must be provided')
buffer = Queue()
Expand All @@ -79,16 +96,16 @@ def __initializeProcess(cls, isDead: Value, processor, *args,
return buffer, proc

@classmethod
def __initializeOutputHandlers(cls,
isDead: Value = None,
fs: int = 0,
dm: str = None,
outFile: str = None,
simo: bool = False,
pl: str = None,
processes: list[Process] = None,
buffers: list[Queue] = None,
**kwargs) -> None:
def _initializeOutputHandlers(cls,
isDead: Value = None,
fs: int = 0,
dm: DemodulationChoices | str = None,
outFile: str = None,
simo: bool = False,
pl: str = None,
processes: list[Process] = None,
buffers: list[Queue] = None,
**kwargs) -> None:
import os
from misc.general_util import eprint

Expand All @@ -107,19 +124,18 @@ def __initializeOutputHandlers(cls,
else:
for p in pl.split(','):
psplot = selectPlotType(p)
if psplot is not None:
kwargs['bandwidth'] = cls.strct['processor'].bandwidth
buffer, proc = cls.__initializeProcess(isDead,
psplot,
fs, name="Plotter-",
**kwargs)
processes.append(proc)
buffers.append(buffer)

buffer, proc = cls.__initializeProcess(isDead,
cls.strct['processor'],
outFile,
name="File writer-",
**kwargs)
kwargs['bandwidth'] = cls.strct['processor'].bandwidth
buffer, proc = cls._initializeProcess(isDead,
psplot,
fs, name="Plotter-",
**kwargs)
processes.append(proc)
buffers.append(buffer)

buffer, proc = cls._initializeProcess(isDead,
cls.strct['processor'],
outFile,
name="File writer-",
**kwargs)
processes.append(proc)
buffers.append(buffer)
4 changes: 1 addition & 3 deletions src/misc/keyboard_interruptable_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,14 @@

class KeyboardInterruptableThread(Thread):
def __init__(self, func: Callable[[], None], target: Callable, group=None, name=None, args=(), daemon=None):
self._handleException = None
if func is None:
raise ValueError("func cannot be None")
super().__init__(group=group, target=target, name=name, args=args, daemon=daemon)
setattr(self, '_handleException', func)
import threading
threading.excepthook = self.handleException

def _handleException(self):
pass

def handleException(self, e):
from misc.general_util import tprint
from sys import __excepthook__
Expand Down
1 change: 0 additions & 1 deletion src/misc/read_file.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def readFile(bitsPerSample: dtype = None,
correctIq: bool = False,
normalize: bool = False,
**_) -> None:

from array import array
from io import BufferedReader
from sys import stdin
Expand Down
26 changes: 8 additions & 18 deletions src/sdrterm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from enum import Enum
from multiprocessing import Value
from os import getpid
from typing import Annotated
Expand All @@ -27,16 +26,7 @@
from typer import run as typerRun, Option

from misc.file_util import DataType


class DemodulationChoices(str, Enum):
FM = "fm"
AM = "am"
REAL = "re"
IMAG = "im"

def __str__(self):
return self.value
from misc.io_args import DemodulationChoices


def parseStrDataType(value: str) -> str:
Expand All @@ -46,9 +36,11 @@ def parseStrDataType(value: str) -> str:
raise BadParameter(str(ex))


def parseIntString(value: str) -> int:
def parseIntString(value: str | int) -> int:
if value is None:
raise BadParameter('Value cannot be None')
elif isinstance(value, int):
return value
elif 'k' in value:
return int(float(value.replace('k', '')) * 10E+2)
elif 'M' in value:
Expand All @@ -67,7 +59,7 @@ def main(fs: Annotated[int, Option('--fs', '-r',
center: Annotated[int, Option('--center-frequency', '-c',
metavar='NUMBER',
parser=parseIntString,
help='Offset from tuned frequency in k/M/Hz')] = '0',
help='Offset from tuned frequency in k/M/Hz')] = 0,
inFile: Annotated[str, Option('--input', '-i',
show_default='stdin',
help='Input device')] = None,
Expand All @@ -93,7 +85,7 @@ def main(fs: Annotated[int, Option('--fs', '-r',
omegaOut: Annotated[int, Option('--omega-out', '-w',
metavar='NUMBER',
parser=parseIntString,
help='Output cutoff frequency in k/M/Hz')] = '12500',
help='Output cutoff frequency in k/M/Hz')] = 12500,
correct_iq: Annotated[bool, Option(help='Toggle iq correction')] = False,
simo: Annotated[bool, Option(help='''
Enable using sockets to output data processed from multiple channels specified by the vfos option.
Expand All @@ -111,7 +103,6 @@ def main(fs: Annotated[int, Option('--fs', '-r',
help='Swap input endianness',
show_default='False => system-default, or as defined in RIFF header')] = False,
normalize_input: Annotated[bool, Option(help='Normalize input data.')] = False, ):

from misc.io_args import IOArgs
from misc.read_file import readFile
from multiprocessing import Process, Queue
Expand Down Expand Up @@ -181,13 +172,12 @@ def __setStartMethod():
from misc.general_util import printException

if 'spawn' in get_all_start_methods():
from multiprocessing import set_start_method
try:
from multiprocessing import set_start_method

set_start_method('spawn')
except Exception as e:
printException(e)
raise NotImplementedError('Setting start method to spawn failed')
set_start_method('spawn', True)


def __generatePidFile(pid):
Expand Down
Loading

0 comments on commit 40e9724

Please sign in to comment.