diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/Makefile | 35 | ||||
| -rw-r--r-- | tools/bitdiff.py | 166 | ||||
| -rwxr-xr-x | tools/check_for_bug.sh | 7 | ||||
| -rwxr-xr-x | tools/checkpatch.sh | 72 | ||||
| -rw-r--r-- | tools/cpep8.blacklist | 3 | ||||
| -rw-r--r-- | tools/cpep8.exceptions | 10 | ||||
| -rw-r--r-- | tools/cpep8.manifest | 152 | ||||
| -rwxr-xr-x | tools/cpep8.py | 137 | ||||
| -rwxr-xr-x | tools/icomsio.sh | 95 | ||||
| -rw-r--r-- | tools/img2thd72.py | 127 | ||||
| -rw-r--r-- | tools/serialsniff.c | 440 |
11 files changed, 1244 insertions, 0 deletions
diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000..a9f08af --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,35 @@ +# +# +# Makefile for serialsniff +# +# Author: IT2 Stuart Blake Tener, USNR (N3GWG) +# +# Version 1.00 +# +# This makefile checks to see if we are running under the OS "Darwin" +# and passes the proper macro flag ("MACOS") if we are. +# +# Incidentally, it is noteworthy that MacOS (Darwin) is not the only +# operating system which is deficient some of the library routines +# MacOS is currently defficient. Thus, it is instructive that other +# operating systems names might need to be added for compilation to +# become occurring in their environments. +# +# + +ifndef SYSNAME + SYSNAME := $(shell uname -s) + ifeq ($(SYSNAME),Darwin) + MYFLAGS := "-DMACOS" + REMOVE := srm -vrfz + else + REMOVE := rm -rf + endif +endif + +serialsniff: serialsniff.c + $(CC) $? -o $@ $(LDFLAGS) $(CFLAGS) $(MYFLAGS) + +clean: + $(REMOVE) serialsniff *~ *.o *.bak core tags shar a.out + diff --git a/tools/bitdiff.py b/tools/bitdiff.py new file mode 100644 index 0000000..d06bdb2 --- /dev/null +++ b/tools/bitdiff.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# +# Copyright 2013 Jens Jensen AF5MI <kd4tjx@yahoo.com> + +import sys +import os +import argparse +import time + + +def printDiff(pos, byte1, byte2, args): + bits1 = '{0:08b}'.format(byte1) + bits2 = '{0:08b}'.format(byte2) + print "@%04Xh" % pos + print "1:%02Xh, %sb" % (byte1, bits1) + print "2:%02Xh, %sb" % (byte2, bits2) + if args.csv: + writeDiffCSV(pos, byte1, byte2, args) + + +def writeDiffCSV(pos, byte1, byte2, args): + bits1 = '{0:08b}'.format(byte1) + bits2 = '{0:08b}'.format(byte2) + csvline = '%s, %s, %04X, %02X, %s, %02X, %s, %s, %s' % \ + (args.file1, args.file2, pos, byte1, bits1, + byte2, bits2, args.setting, args.value) + if not os.path.isfile(args.csv): + fh = open(args.csv, "w") + header = "filename1, filename2, byte_offset, byte1, " \ + "bits1, byte2, bits2, item_msg, value_msg" + fh.write(header + os.linesep) + else: + fh = open(args.csv, "a") + fh.write(csvline + os.linesep) + fh.close() + + +def compareFiles(args): + f1 = open(args.file1, "rb") + f1.seek(args.offset) + f2 = open(args.file2, "rb") + f2.seek(args.offset) + + while True: + pos = f1.tell() - args.offset + c1 = f1.read(1) + c2 = f2.read(1) + if not (c1 and c2): + break + b1 = ord(c1) + b2 = ord(c2) + if b1 != b2: + printDiff(pos, b1, b2, args) + + pos = f1.tell() - args.offset + print "bytes read: %02d" % pos + f1.close() + f2.close() + + +def compareFilesDat(args): + f1 = open(args.file1, "r") + f1contents = f1.read() + f1.close() + f2 = open(args.file2, "r") + f2contents = f2.read() + f2.close() + + f1strlist = f1contents.split() + f1intlist = map(int, f1strlist) + f2strlist = f2contents.split() + f2intlist = map(int, f2strlist) + f1bytes = bytearray(f1intlist) + f2bytes = bytearray(f2intlist) + + length = len(f1intlist) + for i in range(length): + b1 = f1bytes[i] + b2 = f2bytes[i] + pos = i + if b1 != b2: + printDiff(pos, b1, b2, args) + + pos = length + print "bytes read: %02d" % pos + + +def convertFileToBin(args): + f1 = open(args.file1, "r") + f1contents = f1.read() + f1.close() + f1strlist = f1contents.split() + f1intlist = map(int, f1strlist) + f1bytes = bytearray(f1intlist) + f2 = open(args.file2, "wb") + f2.write(f1bytes) + f2.close + + +def convertFileToDat(args): + f1 = open(args.file1, "rb") + f1contents = f1.read() + f1.close() + f2 = open(args.file2, "w") + for i in range(0, len(f1contents)): + f2.write(" %d " % (ord(f1contents[i]), )) + if i % 16 == 15: + f2.write("\r\n") + f2.close + + +# main + +ap = argparse.ArgumentParser(description="byte-/bit- comparison of two files") +ap.add_argument("file1", help="first (reference) file to parse") +ap.add_argument("file2", help="second file to parse") + +mutexgrp1 = ap.add_mutually_exclusive_group() +mutexgrp1.add_argument("-o", "--offset", default=0, + help="offset (hex) to start comparison") +mutexgrp1.add_argument("-d", "--dat", action="store_true", + help="process input files from .DAT/.ADJ format " + "(from 'jujumao' oem programming software " + "for chinese radios)") +mutexgrp1.add_argument("--convert2bin", action="store_true", + help="convert file1 from .dat/.adj to " + "binary image file2") +mutexgrp1.add_argument("--convert2dat", action="store_true", + help="convert file1 from bin to .dat/.adj file2") + +ap.add_argument("-w", "--watch", action="store_true", + help="'watch' changes. runs in a loop") + +csvgrp = ap.add_argument_group("csv output") +csvgrp.add_argument("-c", "--csv", + help="file to append csv results. format: filename1, " + "filename2, byte_offset, byte1, bits1, byte2, " + "bits2, item_msg, value_msg") +csvgrp.add_argument("-s", "--setting", + help="user-meaningful field indicating setting/item " + "modified, e.g. 'beep' or 'txtone'") +csvgrp.add_argument("-v", "--value", + help="user-meaningful field indicating values " + "changed, e.g. 'true->false' or '110.9->100.0'") + +args = ap.parse_args() +if args.offset: + args.offset = int(args.offset, 16) + +print "f1:", args.file1, " f2:", args.file2 +if args.setting or args.value: + print "setting:", args.setting, "- value:", args.value + +while True: + if (args.dat): + compareFilesDat(args) + elif (args.convert2bin): + convertFileToBin(args) + elif (args.convert2dat): + convertFileToDat(args) + else: + compareFiles(args) + if not args.watch: + break + print "------" + time.sleep(delay) diff --git a/tools/check_for_bug.sh b/tools/check_for_bug.sh new file mode 100755 index 0000000..c8b042d --- /dev/null +++ b/tools/check_for_bug.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +# This checks a given revision to make sure that it has a bug number +# in it, of the form "#123". It should be used in your pretxncommit +# hook + +hg log -r $1 --template {desc} | egrep -q "\#[0-9]+" diff --git a/tools/checkpatch.sh b/tools/checkpatch.sh new file mode 100755 index 0000000..5cf3a6f --- /dev/null +++ b/tools/checkpatch.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# CHIRP coding standards compliance script +# +# To add a test to this file, create a new check_foo() function +# and then add it to the list of TESTS= below +# + +TESTS="check_long_lines check_bug_number check_commit_message_line_length" + +function check_long_lines() { + local rev="$1" + local files="$2" + + # For now, ignore this check on chirp/ + files=$(echo $files | sed -r 's#\bchirp[^ ]*\b##') + + if [ -z "$files" ]; then + return + fi + + pep8 --select=E501 $files || \ + error "Please use <80 columns in source files" +} + +function check_bug_number() { + local rev="$1" + hg log -vr $rev | grep -qE '#[0-9]+' || \ + error "A bug number is required like #123" +} + +function _less_than_80() { + while true; do + read line + if [ -z "$line" ]; then + break + elif [ $(echo -n "$line" | wc -c) -ge 80 ]; then + return 1 + fi + done +} + +function check_commit_message_line_length() { + local rev="$1" + hg log -vr $rev | (_less_than_80) || \ + error "Please keep commit message lines to <80 columns" +} + +# --- END OF TEST FUNCTIONS --- + +function error() { + echo FAIL: $* + ERROR=1 +} + +function get_touched_files() { + local rev="$1" + hg status -n --change $rev | grep '\.py$' +} + +rev=${1:-tip} +files=$(get_touched_files $rev) + +for testname in $TESTS; do + eval "$testname $rev \"$files\"" +done + +if [ -z "$ERROR" ]; then + echo "Patch '${rev}' is OK" +else + exit 1 +fi diff --git a/tools/cpep8.blacklist b/tools/cpep8.blacklist new file mode 100644 index 0000000..6a98e72 --- /dev/null +++ b/tools/cpep8.blacklist @@ -0,0 +1,3 @@ +# cpep8.blacklist: The list of files that do not meet PEP8 standards. +# DO NOT ADD NEW FILES!! Instead, fix the code to be compliant. +# Over time, this list should shrink and (eventually) be eliminated. diff --git a/tools/cpep8.exceptions b/tools/cpep8.exceptions new file mode 100644 index 0000000..4efef30 --- /dev/null +++ b/tools/cpep8.exceptions @@ -0,0 +1,10 @@ +# This file contains a list of per-file exceptions to the pep8 style rules +# Each line must contain the file name, a tab, and a comma-separated list +# of style rules to ignore in that file. This mechanism should be used +# sparingly and as a measure of last resort. +./share/make_supported.py E402 +./tests/run_tests E402 +./tests/unit/test_memedit_edits.py E402 +./chirpw E402 +./chirp/memmap.py E731 +./chirp/util.py E731 diff --git a/tools/cpep8.manifest b/tools/cpep8.manifest new file mode 100644 index 0000000..368c6d2 --- /dev/null +++ b/tools/cpep8.manifest @@ -0,0 +1,152 @@ +./chirp/__init__.py +./chirp/bandplan.py +./chirp/bandplan_au.py +./chirp/bandplan_iaru_r1.py +./chirp/bandplan_iaru_r2.py +./chirp/bandplan_iaru_r3.py +./chirp/bandplan_na.py +./chirp/bitwise.py +./chirp/bitwise_grammar.py +./chirp/chirp_common.py +./chirp/detect.py +./chirp/directory.py +./chirp/drivers/__init__.py +./chirp/drivers/alinco.py +./chirp/drivers/anytone.py +./chirp/drivers/ap510.py +./chirp/drivers/baofeng_uv3r.py +./chirp/drivers/baofeng_wp970i.py +./chirp/drivers/bjuv55.py +./chirp/drivers/btech.py +./chirp/drivers/ft1500m.py +./chirp/drivers/ft1802.py +./chirp/drivers/ft1d.py +./chirp/drivers/ft2800.py +./chirp/drivers/ft2900.py +./chirp/drivers/ft4.py +./chirp/drivers/ft50.py +./chirp/drivers/ft60.py +./chirp/drivers/ft7100.py +./chirp/drivers/ft7800.py +./chirp/drivers/ft817.py +./chirp/drivers/ft818.py +./chirp/drivers/ft857.py +./chirp/drivers/ft90.py +./chirp/drivers/ftm350.py +./chirp/drivers/generic_csv.py +./chirp/drivers/generic_tpe.py +./chirp/drivers/h777.py +./chirp/drivers/ic208.py +./chirp/drivers/ic2100.py +./chirp/drivers/ic2200.py +./chirp/drivers/ic2720.py +./chirp/drivers/ic2730.py +./chirp/drivers/ic2820.py +./chirp/drivers/ic9x.py +./chirp/drivers/ic9x_icf.py +./chirp/drivers/ic9x_icf_ll.py +./chirp/drivers/ic9x_ll.py +./chirp/drivers/icf.py +./chirp/drivers/icomciv.py +./chirp/drivers/icq7.py +./chirp/drivers/ict70.py +./chirp/drivers/ict7h.py +./chirp/drivers/ict8.py +./chirp/drivers/icw32.py +./chirp/drivers/icx8x.py +./chirp/drivers/icx8x_ll.py +./chirp/drivers/id31.py +./chirp/drivers/id51.py +./chirp/drivers/id800.py +./chirp/drivers/id880.py +./chirp/drivers/idrp.py +./chirp/drivers/kenwood_hmk.py +./chirp/drivers/kenwood_itm.py +./chirp/drivers/kenwood_live.py +./chirp/drivers/kguv8d.py +./chirp/drivers/kguv9dplus.py +./chirp/drivers/kyd.py +./chirp/drivers/leixen.py +./chirp/drivers/puxing.py +./chirp/drivers/radioddity_r2.py +./chirp/drivers/rfinder.py +./chirp/drivers/template.py +./chirp/drivers/th350.py +./chirp/drivers/th9800.py +./chirp/drivers/th_uv3r.py +./chirp/drivers/th_uv3r25.py +./chirp/drivers/th_uv8000.py +./chirp/drivers/th_uvf8d.py +./chirp/drivers/thd72.py +./chirp/drivers/thuv1f.py +./chirp/drivers/tk8102.py +./chirp/drivers/tk8180.py +./chirp/drivers/tmv71.py +./chirp/drivers/tmv71_ll.py +./chirp/drivers/ts480.py +./chirp/drivers/ts590.py +./chirp/drivers/uv5r.py +./chirp/drivers/uvb5.py +./chirp/drivers/vx170.py +./chirp/drivers/vx2.py +./chirp/drivers/vx3.py +./chirp/drivers/vx5.py +./chirp/drivers/vx510.py +./chirp/drivers/vx6.py +./chirp/drivers/vx7.py +./chirp/drivers/vx8.py +./chirp/drivers/vxa700.py +./chirp/drivers/wouxun.py +./chirp/drivers/wouxun_common.py +./chirp/drivers/yaesu_clone.py +./chirp/elib_intl.py +./chirp/errors.py +./chirp/import_logic.py +./chirp/logger.py +./chirp/memmap.py +./chirp/platform.py +./chirp/pyPEG.py +./chirp/radioreference.py +./chirp/settings.py +./chirp/ui/__init__.py +./chirp/ui/bandplans.py +./chirp/ui/bankedit.py +./chirp/ui/clone.py +./chirp/ui/cloneprog.py +./chirp/ui/common.py +./chirp/ui/config.py +./chirp/ui/dstaredit.py +./chirp/ui/editorset.py +./chirp/ui/fips.py +./chirp/ui/importdialog.py +./chirp/ui/inputdialog.py +./chirp/ui/mainapp.py +./chirp/ui/memdetail.py +./chirp/ui/memedit.py +./chirp/ui/miscwidgets.py +./chirp/ui/radiobrowser.py +./chirp/ui/reporting.py +./chirp/ui/settingsedit.py +./chirp/ui/shiftdialog.py +./chirp/util.py +./chirpc +./chirpw +./locale/check_parameters.py +./rpttool +./setup.py +./share/make_supported.py +./tests/__init__.py +./tests/run_tests +./tests/unit/__init__.py +./tests/unit/base.py +./tests/unit/test_bitwise.py +./tests/unit/test_chirp_common.py +./tests/unit/test_import_logic.py +./tests/unit/test_mappingmodel.py +./tests/unit/test_memedit_edits.py +./tests/unit/test_platform.py +./tests/unit/test_settings.py +./tests/unit/test_shiftdialog.py +./tools/bitdiff.py +./tools/cpep8.py +./tools/img2thd72.py diff --git a/tools/cpep8.py b/tools/cpep8.py new file mode 100755 index 0000000..2bf55d0 --- /dev/null +++ b/tools/cpep8.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# +# cpep8.py - Check Python source files for PEP8 compliance. +# +# Copyright 2015 Zachary T Welch <zach@mandolincreekfarm.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +import os +import sys +import logging +import argparse +import pep8 + +parser = argparse.ArgumentParser() +parser.add_argument("-a", "--all", action="store_true", + help="Check all files, ignoring blacklist") +parser.add_argument("-d", "--dir", action="store", default=".", + help="Root directory of source tree") +parser.add_argument("-s", "--stats", action="store_true", + help="Only show statistics") +parser.add_argument("--strict", action="store_true", + help="Ignore listed exceptions") +parser.add_argument("-S", "--scan", action="store_true", + help="Scan for additional files") +parser.add_argument("-u", "--update", action="store_true", + help="Update manifest/blacklist files") +parser.add_argument("-v", "--verbose", action="store_true", + help="Display list of checked files") +parser.add_argument("files", metavar="file", nargs='*', + help="List of files to check (if none, check all)") +args = parser.parse_args() + + +def file_to_lines(name): + fh = file(name, "r") + lines = fh.read().split("\n") + lines.pop() + fh.close() + return lines + + +scriptdir = os.path.dirname(sys.argv[0]) +manifest_filename = os.path.join(scriptdir, "cpep8.manifest") +blacklist_filename = os.path.join(scriptdir, "cpep8.blacklist") +exceptions_filename = os.path.join(scriptdir, "cpep8.exceptions") + +manifest = [] +if args.scan: + for root, dirs, files in os.walk(args.dir): + for f in files: + filename = os.path.join(root, f) + if f.endswith('.py'): + manifest.append(filename) + continue + with file(filename, "r") as fh: + shebang = fh.readline() + if shebang.startswith("#!/usr/bin/env python"): + manifest.append(filename) +else: + manifest += file_to_lines(manifest_filename) + + +# unless we are being --strict, load per-file style exceptions +exceptions = {} +if not args.strict: + exception_lines = file_to_lines(exceptions_filename) + exception_lists = [x.split('\t') + for x in exception_lines if not x.startswith('#')] + for filename, codes in exception_lists: + exceptions[filename] = codes + + +def get_exceptions(f): + try: + ignore = exceptions[f] + except KeyError: + ignore = None + return ignore + +if args.update: + print "Starting update of %d files" % len(manifest) + bad = [] + for f in manifest: + checker = pep8.StyleGuide(quiet=True, ignore=get_exceptions(f)) + results = checker.check_files([f]) + if results.total_errors: + bad.append(f) + print "%s: %s" % (results.total_errors and "FAIL" or "PASS", f) + + with file(blacklist_filename, "w") as fh: + print >>fh, """\ +# cpep8.blacklist: The list of files that do not meet PEP8 standards. +# DO NOT ADD NEW FILES!! Instead, fix the code to be compliant. +# Over time, this list should shrink and (eventually) be eliminated.""" + print >>fh, "\n".join(sorted(bad)) + + if args.scan: + with file(manifest_filename, "w") as fh: + print >>fh, "\n".join(sorted(manifest)) + sys.exit(0) + +if args.files: + manifest = args.files + +# read the blacklisted source files +blacklist = file_to_lines(blacklist_filename) + +check_list = [] +for f in manifest: + if args.all or f not in blacklist: + check_list.append(f) +check_list = sorted(check_list) + +total_errors = 0 +for f in check_list: + if args.verbose: + print "Checking %s" % f + + checker = pep8.Checker(f, quiet=args.stats, ignore=get_exceptions(f)) + results = checker.check_all() + if args.stats: + checker.report.print_statistics() + total_errors += results + +sys.exit(total_errors and 1 or 0) diff --git a/tools/icomsio.sh b/tools/icomsio.sh new file mode 100755 index 0000000..f5f126d --- /dev/null +++ b/tools/icomsio.sh @@ -0,0 +1,95 @@ +#!/usr/bin/env bash +# +# ICOM ID-RP* serial helper script +# +# Copyright 2009 Dan Smith <dsmith@danplanet.com> +# +# This script will scan the USB bus on this system and determine +# the product ID of any attached ICOM repeater modules. It will +# unload and then reload the FTDI serial driver with the proper +# options to detect the device. After that, it will determine the +# device name and link /dev/icom to that device for easy access. + +LINK="icom" +VENDOR="0x0c26" +DEVICE=$(lsusb -d ${VENDOR}: | cut -d ' ' -f 6 | cut -d : -f 2 | sed -r 's/\n/ /g') + +product_to_name() { + local prod=$1 + + if [ "$prod" = "0012" ]; then + echo "ID-RP2000V TX" + elif [ "$prod" = "0013" ]; then + echo "ID-RP2000V RX" + elif [ "$prod" = "0010" ]; then + echo "ID-RP4000V TX" + elif [ "$prod" = "0011" ]; then + echo "ID-RP4000V RX" + elif [ "$prod" = "000b" ]; then + echo "ID-RP2D" + elif [ "$prod" = "000c" ]; then + echo "ID-RP2V TX" + elif [ "$prod" = "000d" ]; then + echo "ID-RP2V RX" + else + echo "Unknown module (id=${prod})" + fi +} + +if [ $(id -u) != 0 ]; then + echo "This script must be run as root" + exit 1 +fi + +if [ -z "$DEVICE" ]; then + echo "No devices found" + exit 1 +fi + +if echo $DEVICE | grep -q ' '; then + echo "Multiple devices found. Choose one:" + i=0 + for dev in $DEVICE; do + name=$(product_to_name $dev) + echo " ${i}: ${name}" + i=$(($i + 1)) + done + + echo -n "> " + read num + + array=($DEVICE) + + DEVICE=${array[$num]} + if [ -z "$DEVICE" ]; then + exit + fi +fi + +modprobe -r ftdi_sio || { + echo "Unable to unload ftdi_sio" + exit 1 +} + +modprobe ftdi_sio vendor=${VENDOR} product=0x${DEVICE} || { + echo "Failed to load ftdi_sio" + exit 1 +} + +sleep 0.5 + +info=$(lsusb -d ${VENDOR}:0x${DEVICE}) +bus=$(echo $info | cut -d ' ' -f 2 | sed 's/^0*//') +dev=$(echo $info | cut -d ' ' -f 4 | sed 's/^0*//') + +for usbserial in /sys/class/tty/ttyUSB*; do + driver=$(basename $(readlink -f ${usbserial}/device/driver)) + device=$(basename $usbserial) + if [ "$driver" = "ftdi_sio" ]; then + name=$(product_to_name $DEVICE) + ln -sf /dev/${device} /dev/${LINK} + echo "Device $name is /dev/${device} -> /dev/${LINK}" + break + fi +done + diff --git a/tools/img2thd72.py b/tools/img2thd72.py new file mode 100644 index 0000000..407bdf7 --- /dev/null +++ b/tools/img2thd72.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +# coding=utf-8 +# ex: set tabstop=4 expandtab shiftwidth=4 softtabstop=4: +# +# © Copyright Vernon Mauery <vernon@mauery.com>, 2010. All Rights Reserved +# +# This is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or (at +# your option) any later version. +# +# This sofware is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public +# License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this software. If not, see <http://www.gnu.org/licenses/>. + + +import sys +import getopt +from PIL import Image as im + + +def die(msg): + print msg + sys.exit(1) + + +def thd72bitmap(fname, invert): + img = im.open(ifname) + if img.size != (120, 48): + die("Image has wrong dimensions: must be 120x48") + + colors = img.getcolors() + if len(colors) != 2: + die("Image must be 1 bits per pixel (black and white)") + + if ('-i', '') in opts: + c, black = colors[0] + c, white = colors[1] + else: + c, white = colors[0] + c, black = colors[1] + + colors = {black: 1, white: 0} + data = img.getdata() + buf = '' + for y in range(6): + for x in range(120): + b = 0 + for i in range(8): + b |= colors[data[x + 120 * (y * 8 + i)]] << i + buf += chr(b) + return buf + + +def display_thd72(buf): + dots = {0: '*', 1: ' '} + lines = [] + for y in range(48): + line = '' + for x in range(120): + byte = y/8*120 + x + line += dots[(ord(buf[byte]) >> (y % 8)) & 0x01] + lines.append(line) + for l in lines: + print l + + +def usage(): + print "\nUsage: %s <-s|-g> [-i] [-d] " \ + "<image-file> <thd72-nvram-file>" % sys.argv[0] + print "\nThis program will modify whatever nvram file provided or will" + print "create a new one if the file does not exist. After using this to" + print "modify the image, you can use that file to upload all or part of" + print "it to your radio" + print "\nOption explanations:" + print " -s Save as the startup image" + print " -g Save as the GPS logger image" + print " -i Invert colors (black for white)" + print " Depending on the file format the bits may be inverted." + print " If your bitmap file turns out to be inverted, use -i." + print " -d Display the bitmap as dots (for confirmation)" + print " Each black pixel is '*' and each white pixel is ' '" + print " This will print up to 120 dots wide, so beware your" + print " terminal size." + sys.exit(1) + +if __name__ == "__main__": + opts, args = getopt.getopt(sys.argv[1:], "idgs") + if len(args) != 2: + usage() + ifname = args[0] + ofname = args[1] + invert = ('-i', '') in opts + gps = ('-g', '') in opts + startup = ('-s', '') in opts + if (gps and startup) or not (gps or startup): + usage() + if gps: + imgpos = 0xe800 + tagpos = 18 + else: + imgpos = 0xe500 + tagpos = 17 + + buf = thd72bitmap(ifname, invert) + imgfname = ifname + '\xff' * (48-len(ifname)) + of = file(ofname, "rb+") + of.seek(tagpos) + of.write('\x01') + of.seek(imgpos) + of.write(buf) + of.write(imgfname) + of.seek(65536) + of.close() + + if ('-d', '') in opts: + display_thd72(buf) + + blocks = [0, ] + blocks.append(imgpos/256) + blocks.append(1+imgpos/256) + blocks.append(2+imgpos/256) + print "Modified block list:", blocks diff --git a/tools/serialsniff.c b/tools/serialsniff.c new file mode 100644 index 0000000..7a80ac4 --- /dev/null +++ b/tools/serialsniff.c @@ -0,0 +1,440 @@ +/* + * + * Copyright 2008 Dan Smith <dsmith@danplanet.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * + * Modifications made by: + * Stuart Blake Tener, N3GWG + * Email: <teners@bh90210.net> + * Mobile phone: +1 (310) 358-0202 + * + * 02 MAR 2009 - Version 1.01 + * + * Logic was changed to use "ptsname" instead of "ptsname_r" + * in pursuance of provisioning greater compatibility with other + * Unix variants and Open Standards Unix flavors which have not + * otherwise implemented the "ptsname_r" system call. + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + * Added "--quiescent" switch, which when used on the command + * line prevents the printing of "Timeout" and count notices + * on the console. + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + * Added program title and version tagline, printed when the + * software is first started. + * + * 03 MAR 2009 - Version 1.02 + * + * Added "--digits" switch, which when used on the command + * line allows for setting the number of hex digits print per + * line. + * + * Added code to allow "-q" shorthand for "quiescent mode". + * + * Changes were made to add "#ifdef" statements so that only code + * appropriate to MacOS would be compiled if a "#define MACOS" is + * defined early within the source code. + * + * Cleaned up comments in the source for my new source code. + * + * Changes developed and tested under MacOS 10.5.6 (Leopard) + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <fcntl.h> +#include <sys/select.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <getopt.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <arpa/inet.h> + +#define STREQ(a,b) (strcmp(a,b) == 0) + +char *version = "1.02 (03 MAR 2009)"; +int quiescent = 0; +int total_hex = 20; + +struct path { + int fd; + char path[1024]; + char name[1024]; + int rawlog_fd; +}; + +void hexdump(char *buf, int len, FILE *dest) +{ + /* + * In precedence to the modification of this procedure to support the + * variable size hexadecimal output, the total bytes output was fixed + * to be a length of 8. + * + * The amendment of this procedure to support the "total_hex" variable + * allows for the user to pass a command line argument instantiating a + * desired number of hexadecimal bytes (and their ASCII equivelent) to + * be displayed. + * + */ + + int i; + int j; + + for (i = 0; i < len; i += total_hex) { + for (j = i; j < i + total_hex; j++) { + if ((j % 4) == 0) + fprintf(dest, " "); + + if (j < len) + fprintf(dest, "%02x", buf[j] & 0xFF); + else + fprintf(dest, "--"); + } + + fprintf(dest, " "); + + for (j = i; j < i + total_hex; j++) { + if ((j % 4) == 0) + fprintf(dest, " "); + + if (j > len) + fprintf(dest, "."); + else if ((buf[j] > ' ') && (buf[j] < '~')) + fprintf(dest, "%c", buf[j]); + else + fprintf(dest, "."); + } + + fprintf(dest, "\n"); + } +} + +int saferead(int fd, char *buf, int len) +{ + struct itimerval val; + int ret; + int count = 0; + + memset(&val, 0, sizeof(val)); + val.it_value.tv_usec = 50000; + setitimer(ITIMER_REAL, &val, NULL); + + while (count < len) { + getitimer(ITIMER_REAL, &val); + if ((val.it_value.tv_sec == 0) && + (val.it_value.tv_usec == 0)) { + if (!quiescent) + printf("Timeout\n"); + break; + } + + ret = read(fd, &(buf[count]), len - count); + if (ret > 0) + count += ret; + } + + return count; +} + +void proxy(struct path *pathA, struct path *pathB) +{ + fd_set rfds; + int ret; + struct timeval tv; + + while (1) { + int count = 0; + int ret; + char buf[4096]; + + FD_ZERO(&rfds); + + FD_SET(pathA->fd, &rfds); + FD_SET(pathB->fd, &rfds); + + ret = select(30, &rfds, NULL, NULL, NULL); + if (ret == -1) { + perror("select"); + break; + } + + if (FD_ISSET(pathA->fd, &rfds)) { + count = saferead(pathA->fd, buf, sizeof(buf)); + if (count < 0) + break; + + ret = write(pathB->fd, buf, count); + if (ret != count) + printf("Failed to write %i (%i)\n", count, ret); + if (!quiescent) + printf("%s %i:\n", pathA->name, count); + hexdump(buf, count, stdout); + + if (pathA->rawlog_fd >= 0) { + ret = write(pathA->rawlog_fd, buf, count); + if (ret != count) + printf("Failed to write %i to %s log", + count, + pathA->name); + } + + } + + if (FD_ISSET(pathB->fd, &rfds)) { + count = saferead(pathB->fd, buf, sizeof(buf)); + if (count < 0) + break; + + ret = write(pathA->fd, buf, count); + if (ret != count) + printf("Failed to write %i (%i)\n", count, ret); + if (!quiescent) + printf("%s %i:\n", pathB->name, count); + hexdump(buf, count, stdout); + + if (pathB->rawlog_fd >= 0) { + ret = write(pathB->rawlog_fd, buf, count); + if (ret != count) + printf("Failed to write %i to %s log", + count, + pathB->name); + } + } + } +} + +static bool open_pty(struct path *path) +{ +#ifdef MACOS + char *ptsname_path; +#endif + + path->fd = posix_openpt(O_RDWR); + if (path->fd < 0) { + perror("posix_openpt"); + return false; + } + + grantpt(path->fd); + unlockpt(path->fd); + +#ifdef MACOS + ptsname_path = ptsname(path->fd); + strncpy(path->path,ptsname_path,sizeof(path->path) - 1); +#else + ptsname_r(path->fd, path->path, sizeof(path->path)); +#endif + + fprintf(stderr, "%s\n", path->path); + + return true; +} + +static bool open_serial(const char *serpath, struct path *path) +{ + path->fd = open(serpath, O_RDWR); + if (path->fd < 0) + perror(serpath); + + strncpy(path->path, serpath, sizeof(path->path)); + + return path->fd >= 0; +} + +static bool open_socket(const char *foo, struct path *path) +{ + int lfd; + struct sockaddr_in srv; + struct sockaddr_in cli; + unsigned int cli_len = sizeof(cli); + int optval = 1; + + lfd = socket(AF_INET, SOCK_STREAM, 0); + if (lfd < 0) { + perror("socket"); + return false; + } + + srv.sin_family = AF_INET; + srv.sin_port = htons(2000); + srv.sin_addr.s_addr = INADDR_ANY; + + setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)); + + if (bind(lfd, (struct sockaddr *)&srv, sizeof(srv)) < 0) { + perror("bind"); + return false; + } + + if (listen(lfd, 1) < 0) { + perror("listen"); + return false; + } + + printf("Waiting...\n"); + + path->fd = accept(lfd, (struct sockaddr *)&cli, &cli_len); + if (path->fd < 0) { + perror("accept"); + return false; + } + + printf("Accepted socket client\n"); + + strcpy(path->path, "SOCKET"); + + return true; +} + +static bool open_path(const char *opt, struct path *path) +{ + if (STREQ(opt, "pty")) + return open_pty(path); + else if (STREQ(opt, "listen")) + return open_socket(opt, path); + else + return open_serial(opt, path); +} + +static bool open_log(const char *filename, struct path *path) +{ + path->rawlog_fd = open(filename, O_WRONLY | O_CREAT, 0644); + if (path->rawlog_fd < 0) + perror(filename); + + return path->rawlog_fd >= 0; +} + +static void usage() +{ + printf("Usage:\n" + "serialsniff [OPTIONS]\n" + "Where OPTIONS are:\n" + "\n" + " -A,--pathA=DEV Path to device A (or 'pty')\n" + " -B,--pathB=DEV Path to device B (or 'pty')\n" + " --logA=FILE Log pathA (raw) to FILE\n" + " --logB=FILE Log pathB (raw) to FILE\n" + " --nameA=NAME Set pathA name to NAME\n" + " --nameB=NAME Set pathB name to NAME\n" + " --q,-q,--quiescent Run in quiescent mode\n" + " --d,-d,--digits Number of hex digits to print in one line\n\n" + " --d=nn or -d nn or --digits nn\n" + "\n" + ); +} + +int main(int argc, char **argv) +{ + + struct sigaction sa; + + struct path pathA; + struct path pathB; + + int c; + + strcpy(pathA.name, "A"); + strcpy(pathB.name, "B"); + pathA.fd = pathA.rawlog_fd = -1; + pathB.fd = pathB.rawlog_fd = -1; + + printf("\nserialsniff - Version %s\n\n",version); + + while (1) { + int optind; + static struct option lopts[] = { + {"pathA", 1, 0, 'A'}, + {"pathB", 1, 0, 'B'}, + {"logA", 1, 0, 1 }, + {"logB", 1, 0, 2 }, + {"nameA", 1, 0, 3 }, + {"nameB", 1, 0, 4 }, + {"quiescent", 0, 0, 'q' }, + {"digits", 1, 0, 'd'}, + {0, 0, 0, 0} + }; + + c = getopt_long(argc, argv, "A:B:d:l:q", + lopts, &optind); + if (c == -1) + break; + + switch (c) { + + case 'A': + if (!open_path(optarg, &pathA)) + return 1; + break; + + case 'B': + if (!open_path(optarg, &pathB)) + return 2; + break; + + case 1: + if (!open_log(optarg, &pathA)) + return 3; + break; + + case 2: + if (!open_log(optarg, &pathB)) + return 4; + break; + + case 3: + strncpy(pathA.name, optarg, sizeof(pathA.name)); + break; + + case 4: + strncpy(pathB.name, optarg, sizeof(pathB.name)); + break; + + case 'q': + quiescent = 1; + break; + + case 'd': + total_hex=atoi(optarg); + break; + + case '?': + return 3; + } + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_IGN; + sigaction(SIGALRM, &sa, NULL); + + if ((pathA.fd < 0) || (pathB.fd < 0)) { + usage(); + return -1; + } + + proxy(&pathA, &pathB); + + return 0; +} |
