瀏覽代碼

First commit

Pierre Bourdin 1 年之前
當前提交
192e839fe7
共有 2 個文件被更改,包括 223 次插入0 次删除
  1. 0 0
      README.md
  2. 223 0
      sa828.py

+ 0 - 0
README.md


+ 223 - 0
sa828.py

@@ -0,0 +1,223 @@
+#!/usr/bin/python3
+
+import logging
+import serial
+import argparse
+import sys
+import os
+import time
+
+logging.basicConfig(format='%(name)s: %(levelname)s: %(message)s', level=logging.INFO)
+logger = logging.getLogger('SA828')
+
+CTCSSCDCSS_CODES = [
+  "None", "67.0", "71.9", "74.4", "77.0", "79.7", "82.5", "85.4", "88.5",
+  "91.5", "94.8", "97.4", "100.0", "103.5", "107.2", "110.9", "114.8", "118.8",
+  "123.0", "127.3", "131.8", "136.5", "141.3", "146.2", "151.4", "156.7",
+  "162.2", "167.9", "173.8", "179.9", "186.2", "192.8", "203.5", "210.7",
+  "218.1", "225.7", "233.6", "241.8", "250.3",
+  "023I", "025I", "026I", "031I", "032I", "036I", "043I", "047I", "051I", "053I", "054I",
+  "065I", "071I", "072I", "073I", "074I", "114I", "115I", "116I", "125I", "131I", "132I",
+  "134I", "143I", "152I", "155I", "156I", "162I", "165I", "172I", "174I", "205I", "223I",
+  "226I", "243I", "244I", "245I", "251I", "261I", "263I", "265I", "271I", "306I", "311I",
+  "315I", "331I", "343I", "346I", "351I", "364I", "365I", "371I", "411I", "412I", "413I",
+  "423I", "431I", "432I", "445I", "464I", "465I", "466I", "503I", "506I", "516I", "532I",
+  "546I", "565I", "606I", "612I", "624I", "627I", "631I", "632I", "654I", "662I", "664I",
+  "703I", "712I", "723I", "731I", "732I", "734I", "743I", "754I",
+  "023I", "025I", "026I", "031I", "032I", "036I", "043I", "047I", "051I", "053I", "054I",
+  "065I", "071I", "072I", "073I", "074I", "114I", "115I", "116I", "125I", "131I", "132I",
+  "134I", "143I", "152I", "155I", "156I", "162I", "165I", "172I", "174I", "205I", "223I",
+  "226I", "243I", "244I", "245I", "251I", "261I", "263I", "265I", "271I", "306I", "311I",
+  "315I", "331I", "343I", "346I", "351I", "364I", "365I", "371I", "411I", "412I", "413I",
+  "423I", "431I", "432I", "445I", "464I", "465I", "466I", "503I", "506I", "516I", "532I",
+  "546I", "565I", "606I", "612I", "624I", "627I", "631I", "632I", "654I", "662I", "664I",
+  "703I", "712I", "723I", "731I", "732I", "734I", "743I", "754I"
+]
+
+DEFAULT_BAUDRATE = 9600
+BAUD_RATES = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]
+
+class SA828:
+  EOL = "\r\n"
+  RETOK = "OK\r\n"
+  RETERROR = "ERROR\r\n"
+  READ_TIMEOUT = 3
+
+  def __init__(self, port=None, baud=DEFAULT_BAUDRATE):
+    self.serial = None
+    try:
+      self.serial = serial.Serial(port=port,
+                                  baudrate=baud,
+                                  parity=serial.PARITY_NONE,
+                                  stopbits=serial.STOPBITS_ONE,
+                                  bytesize=serial.EIGHTBITS,
+                                  timeout=self.READ_TIMEOUT)
+      logger.debug(self.serial)
+    except serial.SerialException as err:
+      logger.debug(err)
+
+    if not isinstance(self.serial, serial.Serial):
+      raise IOError('Error openning the serial port')
+
+  def close(self):
+    self.serial.close()
+
+  def send(self, *args):
+    data = ','.join(args)
+    logger.debug('Sending: %s', data)
+    data = bytes(data + self.EOL, 'ascii')
+    try:
+      self.serial.write(data)
+    except serial.SerialException as err:
+      logger.error(err)
+
+  def readline(self):
+    try:
+      line = self.serial.readline()
+    except serial.SerialException as err:
+      logger.warning(err)
+      return None
+    try:
+      line = line.decode('ascii')
+    except UnicodeDecodeError:
+      logger.debug(line)
+      logger.error('Character decode error: Check your baudrate')
+    logger.debug('Received: %s', line.rstrip())
+    return line.rstrip()
+
+  def version(self):
+    self.send("\x41\x41\x46\x41\x41")
+    time.sleep(0.5)
+    reply = self.readline()
+    return reply
+
+  def read_parameter(self):
+    self.send("AAFA1")
+    time.sleep(0.5)
+    reply = self.readline()
+    return reply
+
+  def reset(self):
+    self.send("AAFA2")
+    time.sleep(0.5)
+    reply = self.readline()
+    return reply
+
+  def set_parameter(self, data):
+    self.send("AAFA3" + data)
+    time.sleep(3)
+    reply = self.readline()
+    return reply
+
+def main():
+  
+  parser = argparse.ArgumentParser(description="generate configuration for switch port")
+  parser.add_argument("--debug", action="store_true", default=False)
+  parser.add_argument("--port", type=str, default="/dev/ttyUSB0", help="Serial port [default: linux console port]")
+  parser.add_argument('--speed', type=int, choices=BAUD_RATES, default=DEFAULT_BAUDRATE, help="Connection speed")
+
+  subparsers = parser.add_subparsers()
+
+  p_readversion = subparsers.add_parser("version", help='Read the version of the radio')
+  p_readversion.set_defaults(func="version")
+
+  p_reset = subparsers.add_parser("reset", help='Reset the radio')
+  p_reset.set_defaults(func="reset")
+
+  p_readparameter = subparsers.add_parser("readparameter", help='Read the full configuration of the radio')
+  p_readparameter.set_defaults(func="readparameter")
+
+  p_setparameter = subparsers.add_parser("setparameter", help='Set the configuration of the radio')
+  p_setparameter.set_defaults(func="setparameter")
+  p_setparameter.add_argument("--channel", required=True, help="Channel number, [1-16]")
+  p_setparameter.add_argument("--txfreq",required=True, help="Transmit frequency : format '145.4500'")
+  p_setparameter.add_argument("--rxfreq",required=True, help="Receive frequency : format '145.4500'")
+  p_setparameter.add_argument("--txctcss",required=True, help="Transmit CTCSS : format 'None' or '88.5' or 023I or 023N")
+  p_setparameter.add_argument("--rxctcss",required=True, help="Receive CTCSS : format 'None' or '88.5' or 023I or 023N")
+  p_setparameter.add_argument("--squelch",required=True, help="Set the Squelch : [0-8]")
+
+  opts = parser.parse_args()
+  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)
+    sys.exit(os.EX_USAGE)
+
+
+  try:
+    radio = SA828(opts.port, opts.speed)
+  except (IOError, SystemError) as err:
+    logger.error(err)
+    sys.exit(os.EX_IOERR)
+
+  if opts.debug:
+    logger.setLevel(logging.DEBUG)
+  logger.debug(opts)
+
+  if opts.func == 'version':
+    logger.info('Version: %s', radio.version())
+
+  if opts.func == 'reset':
+    logger.info('Resetting the radio')
+    radio.reset()
+
+  if opts.func == 'readparameter':
+    params=radio.read_parameter().split(",")
+    params[0]=params[0][2:]
+    print("Configuration:")
+    print("==============")
+    for i in range(0, 16):
+      if i == 0:
+        print("Channel %s:\tTx : %s\tRx : %s" % (i+1, params[i], params[i+1]))
+      else:
+        print("Channel %s:\tTx : %s\tRx : %s" % (i+1, params[i*2], params[i*2+1]))
+
+    print("CTCS/CDCS :\tTx : %s\t Rx : %s" % (CTCSSCDCSS_CODES[int(params[32])], CTCSSCDCSS_CODES[int(params[33])]))
+    print("Squelch :\t%s" % params[34])
+
+
+
+  if opts.func == 'setparameter':
+    logger.info('Setting the radio')
+    params=radio.read_parameter().split(",")
+    params[0]=params[0][2:]
+    channel = {}
+
+    for i in range(0, 16):
+      if i == 0:
+        channel[i+1]=[params[i],params[i+1]]
+      else:
+        channel[i+1]=[params[i*2],params[i*2+1]]
+    channel[int(opts.channel)]=[opts.txfreq,opts.rxfreq]
+
+    # Creation de la chaine complete
+    for i in range(0, 16):
+      if i == 0:
+        tosend="%s,%s," % (channel[i+1][0],channel[i+1][1])
+      else:
+        tosend=tosend+"%s,%s," % (channel[i+1][0],channel[i+1][1])
+
+    #search value in array and return position
+    for i in range(0,len(CTCSSCDCSS_CODES)):
+      if CTCSSCDCSS_CODES[i] == opts.txctcss:
+        txctcss=i
+        break
+      else:
+        txctcss=0
+
+    for i in range(0,len(CTCSSCDCSS_CODES)): 
+      if CTCSSCDCSS_CODES[i] == opts.rxctcss:
+        rxctcss=i
+        break
+      else:
+        rxctcss=0
+
+    tosend=tosend+"%03d,%03d,%s" % (txctcss,rxctcss,opts.squelch)
+    radio.set_parameter(tosend)
+
+
+
+
+
+if __name__ == "__main__":
+  main()