Skip to content

Commit

Permalink
Make commands less ambiguous
Browse files Browse the repository at this point in the history
 - The `filters` arguments use enable/disable instead of yes/no
 - The `radio` argument `close_tail` has been replace by `tail`.
     The `tail` options are open/close.
 - Changed the README file to reflect the new options.
  • Loading branch information
0x9900 committed Apr 23, 2024
1 parent d319160 commit 68a2f36
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 105 deletions.
45 changes: 26 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ SA818: INFO: Firmware version: V4.2
SA818: INFO: +DMOSETGROUP:0, BW: Wide, Frequency (RX: 145.2300 / TX: 144.6300), CTCSS (TX: 100.0 / RX: 100.0), squelch: 4, OK
[root@allstar ~]# sa818 volume --level 5
SA818: INFO: +DMOSETVOLUME:0 Volume level: 5
SA818: INFO: +DMOSETVOLUME:0 Volume level: 5, OK
```

If you use an FTDI dongle to program the SA828 module the USB port can
Expand All @@ -67,7 +67,8 @@ This program has for sections:
- version: display the firmware version of the SA818 module

```
usage: sa818 [-h] [--port PORT] [--debug]
usage: sa818 [-h] [--debug] [--port PORT]
[--speed {300,1200,2400,4800,9600,19200,38400,57600,115200}]
{radio,volume,filters,version} ...
generate configuration for switch port
Expand All @@ -76,53 +77,59 @@ positional arguments:
{radio,volume,filters,version}
radio Program the radio (frequency/tome/squelch)
volume Set the volume level
filters Set filters
filters Enable/Disable filters
version Show the firmware version of the SA818
optional arguments:
options:
-h, --help show this help message and exit
--port PORT Serial port [default: linux console port]
--debug
--port PORT Serial port [default: linux console port]
--speed {300,1200,2400,4800,9600,19200,38400,57600,115200}
Connection speed
```

### Radio

```
usage: sa818 radio [-h] --frequency FREQUENCY [--offset OFFSET]
[--squelch SQUELCH] [--ctcss CTCSS | --dcs DCS]
usage: sa818 radio [-h] [--bw {0,1}] --frequency FREQUENCY
[--offset OFFSET] [--squelch SQUELCH]
[--ctcss CTCSS | --dcs DCS] [--tail TAIL]
optional arguments:
options:
-h, --help show this help message and exit
--bw {0,1} Bandwidth 0=NARROW (12.5KHz), 1=WIDE (25KHx) [default:
WIDE]
--frequency FREQUENCY
Transmit frequency
--offset OFFSET 0.0 for no offset [default: 0.0]
--squelch SQUELCH Squelch value (1 to 9) [default: 4]
Receive frequency
--offset OFFSET Offset in MHz, 0 for no offset [default: 0.0]
--squelch SQUELCH Squelch value (0 to 8) [default: 4]
--ctcss CTCSS CTCSS (PL Tone) 0 for no CTCSS [default: None]
--dcs DCS DCS code must me the number followed by [N normal] or
--dcs DCS DCS code must be the number followed by [N normal] or
[I inverse] [default: None]
--tail TAIL Close CTCSS Tail Tone (Open/Close)
```

### Volume

```
usage: sa818 volume [-h] [--level LEVEL]
optional arguments:
options:
-h, --help show this help message and exit
--level LEVEL Volume value (1 to 8) [default: 4]
```

### Filters

```
usage: sa818 filters [-h] [--emphasis EMPHASIS] [--highpass HIGHPASS]
[--lowpass LOWPASS]
usage: sa818 filters [-h] --emphasis EMPHASIS --highpass HIGHPASS --lowpass
LOWPASS
optional arguments:
options:
-h, --help show this help message and exit
--emphasis EMPHASIS Disable [Pr/De]-emphasis (yes/no) [default: no]
--highpass HIGHPASS Disable high pass filter (yes/no) [default: no]
--lowpass LOWPASS Disable low pass filters (yes/no) [default: no]
--emphasis EMPHASIS [Pr/De]-emphasis (Enable/Disable)
--highpass HIGHPASS High pass filter (Enable/Disable)
--lowpass LOWPASS Low pass filters (Enable/Disable)
```

## CTCSS codes (PL Tones)
Expand Down
101 changes: 60 additions & 41 deletions sa818.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def __init__(self, port=None, baud=DEFAULT_BAUDRATE):
self.send(self.INIT)
reply = self.readline()
if reply != "+DMOCONNECT:0":
raise SystemError('Connection error')
raise SystemError('Connection error') from None

def close(self):
self.serial.close()
Expand Down Expand Up @@ -153,24 +153,26 @@ def set_radio(self, opts):
msg = "%s, BW: %s, RX frequency: %s, TX frequency: %s, squelch: %s, OK"
logger.info(msg, response, bw_label, rx_freq, tx_freq, opts.squelch)

if opts.close_tail is not None and opts.ctcss is not None:
self.close_tail(opts)
elif opts.close_tail is not None:
logger.warning('Ignoring "--close-tail" specified without ctcss')
if opts.tail is not None and opts.ctcss is not None:
self.tail(opts)
elif opts.tail is not None:
logger.warning('Ignoring "--tail" specified without ctcss')

def set_filter(self, opts):
_yn = {True: "Yes", False: "No"}
for key in ("emphasis", "highpass", "lowpass"):
if getattr(opts, key) is None:
setattr(opts, key, 1)
_rx = {0: 'enabled', 1: 'disabled'}
# filters are pre-emphasis, high-pass, low-pass
cmd = (f"{self.FILTER}={int(not opts.emphasis)},"
f"{int(not opts.highpass)},{int(not opts.lowpass)}")
cmd = (f"{self.FILTER}={opts.emphasis},{opts.highpass},{opts.lowpass}")
self.send(cmd)
time.sleep(1)
response = self.readline()
if response != "+DMOSETFILTER:0":
logger.error('SA818 set filter error')
else:
logger.info("%s filters [Pre/De]emphasis: %s, high-pass: %s, low-pass: %s",
response, _yn[opts.emphasis], _yn[opts.highpass], _yn[opts.lowpass])
response, _rx[opts.emphasis], _rx[opts.highpass], _rx[opts.lowpass])

def set_volume(self, opts):
cmd = f"{self.VOLUME}={opts.level:d}"
Expand All @@ -182,23 +184,23 @@ def set_volume(self, opts):
else:
logger.info("%s Volume level: %d, OK", response, opts.level)

def close_tail(self, opts):
_yn = {True: "Yes", False: "No"}
cmd = f"{self.TAIL}={int(opts.close_tail)}"
def tail(self, opts):
_oc = {True: "open", False: "close"}
cmd = f"{self.TAIL}={int(opts.tail)}"
self.send(cmd)
time.sleep(1)
response = self.readline()
if response != "+DMOSETTAIL:0":
logger.error('SA818 set filter error')
else:
logger.info("%s close tail: %s", response, _yn[opts.close_tail])
logger.info("%s tail: %s", response, _oc[opts.tail])


def type_frequency(parg):
try:
frequency = float(parg)
except ValueError:
raise argparse.ArgumentTypeError from None
raise argparse.ArgumentError from None

if not 144 < frequency < 148 and not 420 < frequency < 450:
logger.error('Frequency outside the amateur bands')
Expand Down Expand Up @@ -282,20 +284,22 @@ def type_level(parg):
return value


def yesno(parg):
yes_strings = ["y", "yes", "true", "1", "on"]
no_strings = ["n", "no", "false", "0", "off"]
if parg.lower() in yes_strings:
return True
if parg.lower() in no_strings:
return False
raise argparse.ArgumentError
def enabledisable(parg):
if parg.lower() == 'enable':
return 0
if parg.lower() == 'disable':
return 1
raise argparse.ArgumentTypeError("Possible values are [Enable/Disable]") from None


def noneyesno(parg):
if parg is not None:
return yesno(parg)
return None
def openclose(parg):
if parg is None:
return None
if parg.lower() in "open":
return True
if parg.lower() in "close":
return False
raise argparse.ArgumentTypeError("Possible values are [Open/Close]") from None


def set_loglevel():
Expand Down Expand Up @@ -324,8 +328,7 @@ def format_codes():
return ''.join(codes)


def main():
set_loglevel()
def command_parser():
parser = argparse.ArgumentParser(
description="generate configuration for switch port",
epilog=format_codes(),
Expand Down Expand Up @@ -354,32 +357,43 @@ def main():
code_group.add_argument("--dcs", default=None, type=type_dcs,
help=("DCS code must be the number followed by [N normal] or "
"[I inverse] [default: %(default)s]"))
p_radio.add_argument("--close-tail", default=None, type=noneyesno,
help="Close CTCSS Tail Tone (yes/no)")
p_radio.add_argument("--tail", default=None, type=openclose,
help="Close CTCSS Tail Tone (Open/Close)")

p_volume = subparsers.add_parser("volume", help="Set the volume level")
p_volume.set_defaults(func="volume")
p_volume.add_argument("--level", type=type_level, default=4,
help="Volume value (1 to 8) [default: %(default)s]")

p_filter = subparsers.add_parser("filters", help="Set/Unset filters")
p_filter = subparsers.add_parser("filters", aliases=['filter'], help="Enable/Disable filters")
p_filter.set_defaults(func="filters")
p_filter.add_argument("--emphasis", type=yesno, required=True,
help="Disable [Pr/De]-emphasis (yes/no)")
p_filter.add_argument("--highpass", type=yesno, required=True,
help="Disable high pass filter (yes/no)")
p_filter.add_argument("--lowpass", type=yesno, required=True,
help="Disable low pass filters (yes/no)")
p_filter.add_argument("--emphasis", type=enabledisable,
help="[Pr/De]-emphasis (Enable/Disable) [default: disable]")
p_filter.add_argument("--highpass", type=enabledisable,
help="High pass filter (Enable/Disable) [default: disable]")
p_filter.add_argument("--lowpass", type=enabledisable,
help="Low pass filters (Enable/Disable) [default: disable]")

p_version = subparsers.add_parser("version", help="Show the firmware version of the SA818")
p_version.set_defaults(func="version")

opts = parser.parse_args()
try:
opts = parser.parse_args()
except argparse.ArgumentTypeError as err:
parser.error(str(err))

if not hasattr(opts, 'func'):
print('sa818: error: the following arguments are required: {radio,volume,filters,version}\n'
'use --help for more informatiion',
file=sys.stderr)
raise SystemExit(os.EX_USAGE) from None
raise SystemExit('Argument Error') from None

return opts


def main():
set_loglevel()
opts = command_parser()

if opts.debug:
logger.setLevel(logging.DEBUG)
Expand All @@ -389,14 +403,19 @@ def main():
try:
radio = SA818(opts.port, opts.speed)
except (IOError, SystemError) as err:
logger.error(err)
raise SystemExit(os.EX_IOERR) from None
raise SystemExit(err) from None

if opts.func == 'version':
radio.version()
elif opts.func == 'radio':
radio.set_radio(opts)
elif opts.func == 'filters':
for key in ('emphasis', 'highpass', 'lowpass'):
if getattr(opts, key) is not None:
break
else:
logger.error('filters need at least one argument')
raise SystemExit('Argument error') from None
radio.set_filter(opts)
elif opts.func == 'volume':
radio.set_volume(opts)
Expand Down
83 changes: 38 additions & 45 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,59 +14,52 @@
## SA818 Programming
Use this software to program the frequency, ctcss, dcs and filters ont
Use this software to program the frequency, ctcss, dcs and filters on
the radio module SA818
### Installation
```
$ pip install sa818
```
### Example
```
$ sa818 radio --frequency 145.230 --offset -.6 --ctcss 100
SA818: INFO: +DMOSETGROUP:0, RX frequency: 145.2300, TX frequency: 144.6300, ctcss: 100.0,
squelch: 4, OK
$ sa818 volume --level 5
SA818: INFO: +DMOSETVOLUME:0 Volume level: 5
```
"""

__author__ = "Fred C. (W6BSD)"
__version__ = '0.2.5'
__version__ = '0.2.6'
__license__ = 'BSD'

py_version = sys.version_info[:2]
if py_version < (3, 8):
raise RuntimeError('SA818 requires Python 3.8 or later')

setup(
name='sa818',
version=__version__,
description='SA818 Programming Software',
long_description=__doc__,
long_description_content_type='text/markdown',
url='https://github.com/0x9900/SA818/',
license=__license__,
author=__author__,
author_email='[email protected]',
py_modules=['sa818'],
install_requires=['pyserial'],
entry_points={
'console_scripts': ['sa818 = sa818:main'],
},
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Topic :: Communications :: Ham Radio',
],
)

def readme():
return open('README.md', 'r', encoding='utf-8').read()


def main():
setup(
name='sa818',
version=__version__,
description='SA818 Programming Software',
long_description=readme(),
long_description_content_type='text/markdown',
url='https://github.com/0x9900/SA818/',
license=__license__,
author=__author__,
author_email='[email protected]',
py_modules=['sa818'],
install_requires=['pyserial'],
entry_points={
'console_scripts': ['sa818 = sa818:main'],
},
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.8',
'Topic :: Communications :: Ham Radio',
],
)


if __name__ == "__main__":
main()

0 comments on commit 68a2f36

Please sign in to comment.