diff --git a/99-dmr.rules b/99-dmr.rules index ab74745..f9f7b6d 100644 --- a/99-dmr.rules +++ b/99-dmr.rules @@ -10,3 +10,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="666" # Baofeng RD-5R SUBSYSTEM=="usb", ATTRS{idVendor}=="15a2", ATTRS{idProduct}=="0073", MODE="666" + +# Anytone AT-D868UV +# Ignore this device in Modem Manager +ATTRS{idVendor}=="28e9" ATTRS{idProduct}=="018a", ENV{ID_MM_DEVICE_IGNORE}="1" diff --git a/Makefile b/Makefile index e084c79..122707c 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ UNAME = $(shell uname) CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"' LDFLAGS = -g -OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o +OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o rd5r.o gd77.o hid.o serial.o d868uv.o LIBS = -lusb-1.0 # @@ -48,6 +48,7 @@ dmrconfig.linux: dmrconfig strip $@ ### +d868uv.o: d868uv.c radio.h util.h dfu-libusb.o: dfu-libusb.c util.h dfu-windows.o: dfu-windows.c util.h gd77.o: gd77.c radio.h util.h @@ -59,5 +60,6 @@ main.o: main.c radio.h util.h md380.o: md380.c radio.h util.h radio.o: radio.c radio.h util.h rd5r.o: rd5r.c radio.h util.h +serial.o: serial.c util.h util.o: util.c util.h uv380.o: uv380.c radio.h util.h diff --git a/Makefile-mingw b/Makefile-mingw index d6bf430..242a941 100644 --- a/Makefile-mingw +++ b/Makefile-mingw @@ -5,7 +5,7 @@ GITCOUNT = $(shell git rev-list HEAD --count) CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"' LDFLAGS = -g -s -OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o +OBJS = main.o util.o radio.o dfu-windows.o uv380.o md380.o rd5r.o gd77.o hid.o hid-windows.o serial.o d868uv.o LIBS = -lhid -lsetupapi # Compiling Windows binary from Linux @@ -33,6 +33,7 @@ install: dmrconfig install -c -s dmrconfig /usr/local/bin/dmrconfig ### +d868uv.o: d868uv.c radio.h util.h dfu-libusb.o: dfu-libusb.c util.h dfu-windows.o: dfu-windows.c util.h gd77.o: gd77.c radio.h util.h @@ -44,5 +45,6 @@ main.o: main.c radio.h util.h md380.o: md380.c radio.h util.h radio.o: radio.c radio.h util.h rd5r.o: rd5r.c radio.h util.h +serial.o: serial.c util.h util.o: util.c util.h uv380.o: uv380.c radio.h util.h diff --git a/contact5.diff b/contact5.diff new file mode 100644 index 0000000..94c12e1 --- /dev/null +++ b/contact5.diff @@ -0,0 +1,38 @@ +--- d868uv-contacts.hd 2018-10-26 16:58:56.070106184 -0700 ++++ d868uv-contacts-delete5.hd 2018-10-26 17:10:11.651995288 -0700 +@@ -18204,10 +18204,9 @@ + 000764e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 000764f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 00076500 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 |................| --- List of contacts? +-00076510 04 00 00 00 ff ff ff ff ff ff ff ff ff ff ff ff |................| +-00076520 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| ++00076510 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * +-00080140 e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| ++00080140 f0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| --- Bitmap of invalid contacts + 00080150 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * + 00080620 ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +@@ -18233,43 +18232,12 @@ + 00080790 44 44 44 01 00 00 00 00 00 00 00 00 00 00 00 00 |DDD.............| + 000807a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + * +-000807d0 00 43 6f 6e 74 61 63 74 20 35 00 00 00 00 00 00 |.Contact 5......| --- Contact5 structure +-000807e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +-000807f0 00 00 00 15 55 55 55 02 00 00 00 00 00 00 00 00 |....UUU.........| +-00080800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +-* +-00080840 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| ++000807d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * +@@ -18306,8 +18274,7 @@ + 00174c30 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * + 00188380 f1 ac 68 24 00 00 00 00 66 66 66 26 02 00 00 00 |..h$....fff&....| +-00188390 88 88 88 28 03 00 00 00 aa aa aa 2a 04 00 00 00 |...(.......*....| +-001883a0 2a e4 ee 2c 01 00 00 00 ff ff ff ff ff ff ff ff |*..,............| +-001883b0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| ++00188390 88 88 88 28 03 00 00 00 2a e4 ee 2c 01 00 00 00 |...(....*..,....| --- Unknown data ++001883a0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * + 00188680 diff --git a/d868uv-map.h b/d868uv-map.h new file mode 100644 index 0000000..7d7a97b --- /dev/null +++ b/d868uv-map.h @@ -0,0 +1,580 @@ +/* + * Address map of D868UV memory space. + */ +{ 0x02fa0010, 0x40 }, // Radio name and timestamp +{ 0x00800000, 0x2000 }, // Channels 1-128 +{ 0x00840000, 0x2000 }, // Channels 129-256 +{ 0x00880000, 0x2000 }, // Channels 257-384 +{ 0x008c0000, 0x2000 }, // Channels 385-512 +{ 0x00900000, 0x2000 }, // Channels 513-640 +{ 0x00940000, 0x2000 }, // Channels 641-768 +{ 0x00980000, 0x2000 }, // Channels 769-896 +{ 0x009c0000, 0x2000 }, // Channels 897-1024 +{ 0x00a00000, 0x2000 }, // Channels 1025-1152 +{ 0x00a40000, 0x2000 }, // Channels 1153-1280 +{ 0x00a80000, 0x2000 }, // Channels 1281-1408 +{ 0x00ac0000, 0x2000 }, // Channels 1409-1536 +{ 0x00b00000, 0x2000 }, // Channels 1537-1664 +{ 0x00b40000, 0x2000 }, // Channels 1665-1792 +{ 0x00b80000, 0x2000 }, // Channels 1793-1920 +{ 0x00bc0000, 0x2000 }, // Channels 1921-2048 +{ 0x00c00000, 0x2000 }, // Channels 2049-2176 +{ 0x00c40000, 0x2000 }, // Channels 2177-2304 +{ 0x00c80000, 0x2000 }, // Channels 2305-2432 +{ 0x00cc0000, 0x2000 }, // Channels 2433-2560 +{ 0x00d00000, 0x2000 }, // Channels 2561-2688 +{ 0x00d40000, 0x2000 }, // Channels 2689-2816 +{ 0x00d80000, 0x2000 }, // Channels 2817-2944 +{ 0x00dc0000, 0x2000 }, // Channels 2945-3072 +{ 0x00e00000, 0x2000 }, // Channels 3073-3200 +{ 0x00e40000, 0x2000 }, // Channels 3201-3328 +{ 0x00e80000, 0x2000 }, // Channels 3329-3456 +{ 0x00ec0000, 0x2000 }, // Channels 3457-3584 +{ 0x00f00000, 0x2000 }, // Channels 3585-3712 +{ 0x00f40000, 0x2000 }, // Channels 3713-3840 +{ 0x00f80000, 0x2000 }, // Channels 3841-3968 +{ 0x00fc0000, 0x0880 }, // Channels 3969-4000, VFO A, VFO B +{ 0x01000000, 0x1f400 }, // Unknown bitmap +{ 0x01080000, 0xc0 }, // Scanlist 1 +{ 0x01080200, 0xc0 }, // Scanlist 2 +{ 0x01080400, 0xc0 }, // Scanlist 3 +{ 0x01080600, 0xc0 }, // Scanlist 4 +{ 0x01080800, 0xc0 }, // Scanlist 5 +{ 0x01080a00, 0xc0 }, // Scanlist 6 +{ 0x01080c00, 0xc0 }, // Scanlist 7 +{ 0x01080e00, 0xc0 }, // Scanlist 8 +{ 0x01081000, 0xc0 }, // Scanlist 9 +{ 0x01081200, 0xc0 }, // Scanlist 10 +{ 0x01081400, 0xc0 }, // Scanlist 11 +{ 0x01081600, 0xc0 }, // Scanlist 12 +{ 0x01081800, 0xc0 }, // Scanlist 13 +{ 0x01081a00, 0xc0 }, // Scanlist 14 +{ 0x01081c00, 0xc0 }, // Scanlist 15 +{ 0x01081e00, 0xc0 }, // Scanlist 16 +{ 0x010c0000, 0xc0 }, // Scanlist 17 +{ 0x010c0200, 0xc0 }, // Scanlist 18 +{ 0x010c0400, 0xc0 }, // Scanlist 19 +{ 0x010c0600, 0xc0 }, // Scanlist 20 +{ 0x010c0800, 0xc0 }, // Scanlist 21 +{ 0x010c0a00, 0xc0 }, // Scanlist 22 +{ 0x010c0c00, 0xc0 }, // Scanlist 23 +{ 0x010c0e00, 0xc0 }, // Scanlist 24 +{ 0x010c1000, 0xc0 }, // Scanlist 25 +{ 0x010c1200, 0xc0 }, // Scanlist 26 +{ 0x010c1400, 0xc0 }, // Scanlist 27 +{ 0x010c1600, 0xc0 }, // Scanlist 28 +{ 0x010c1800, 0xc0 }, // Scanlist 29 +{ 0x010c1a00, 0xc0 }, // Scanlist 30 +{ 0x010c1c00, 0xc0 }, // Scanlist 31 +{ 0x010c1e00, 0xc0 }, // Scanlist 32 +{ 0x01100000, 0xc0 }, // Scanlist 33 +{ 0x01100200, 0xc0 }, // Scanlist 34 +{ 0x01100400, 0xc0 }, // Scanlist 35 +{ 0x01100600, 0xc0 }, // Scanlist 36 +{ 0x01100800, 0xc0 }, // Scanlist 37 +{ 0x01100a00, 0xc0 }, // Scanlist 38 +{ 0x01100c00, 0xc0 }, // Scanlist 39 +{ 0x01100e00, 0xc0 }, // Scanlist 40 +{ 0x01101000, 0xc0 }, // Scanlist 41 +{ 0x01101200, 0xc0 }, // Scanlist 42 +{ 0x01101400, 0xc0 }, // Scanlist 43 +{ 0x01101600, 0xc0 }, // Scanlist 44 +{ 0x01101800, 0xc0 }, // Scanlist 45 +{ 0x01101a00, 0xc0 }, // Scanlist 46 +{ 0x01101c00, 0xc0 }, // Scanlist 47 +{ 0x01101e00, 0xc0 }, // Scanlist 48 +{ 0x01140000, 0xc0 }, // Scanlist 49 +{ 0x01140200, 0xc0 }, // Scanlist 50 +{ 0x01140400, 0xc0 }, // Scanlist 51 +{ 0x01140600, 0xc0 }, // Scanlist 52 +{ 0x01140800, 0xc0 }, // Scanlist 53 +{ 0x01140a00, 0xc0 }, // Scanlist 54 +{ 0x01140c00, 0xc0 }, // Scanlist 55 +{ 0x01140e00, 0xc0 }, // Scanlist 56 +{ 0x01141000, 0xc0 }, // Scanlist 57 +{ 0x01141200, 0xc0 }, // Scanlist 58 +{ 0x01141400, 0xc0 }, // Scanlist 59 +{ 0x01141600, 0xc0 }, // Scanlist 60 +{ 0x01141800, 0xc0 }, // Scanlist 61 +{ 0x01141a00, 0xc0 }, // Scanlist 62 +{ 0x01141c00, 0xc0 }, // Scanlist 63 +{ 0x01141e00, 0xc0 }, // Scanlist 64 +{ 0x01180000, 0xc0 }, // Scanlist 65 +{ 0x01180200, 0xc0 }, // Scanlist 66 +{ 0x01180400, 0xc0 }, // Scanlist 67 +{ 0x01180600, 0xc0 }, // Scanlist 68 +{ 0x01180800, 0xc0 }, // Scanlist 69 +{ 0x01180a00, 0xc0 }, // Scanlist 70 +{ 0x01180c00, 0xc0 }, // Scanlist 71 +{ 0x01180e00, 0xc0 }, // Scanlist 72 +{ 0x01181000, 0xc0 }, // Scanlist 73 +{ 0x01181200, 0xc0 }, // Scanlist 74 +{ 0x01181400, 0xc0 }, // Scanlist 75 +{ 0x01181600, 0xc0 }, // Scanlist 76 +{ 0x01181800, 0xc0 }, // Scanlist 77 +{ 0x01181a00, 0xc0 }, // Scanlist 78 +{ 0x01181c00, 0xc0 }, // Scanlist 79 +{ 0x01181e00, 0xc0 }, // Scanlist 80 +{ 0x011c0000, 0xc0 }, // Scanlist 81 +{ 0x011c0200, 0xc0 }, // Scanlist 82 +{ 0x011c0400, 0xc0 }, // Scanlist 83 +{ 0x011c0600, 0xc0 }, // Scanlist 84 +{ 0x011c0800, 0xc0 }, // Scanlist 85 +{ 0x011c0a00, 0xc0 }, // Scanlist 86 +{ 0x011c0c00, 0xc0 }, // Scanlist 87 +{ 0x011c0e00, 0xc0 }, // Scanlist 88 +{ 0x011c1000, 0xc0 }, // Scanlist 89 +{ 0x011c1200, 0xc0 }, // Scanlist 90 +{ 0x011c1400, 0xc0 }, // Scanlist 91 +{ 0x011c1600, 0xc0 }, // Scanlist 92 +{ 0x011c1800, 0xc0 }, // Scanlist 93 +{ 0x011c1a00, 0xc0 }, // Scanlist 94 +{ 0x011c1c00, 0xc0 }, // Scanlist 95 +{ 0x011c1e00, 0xc0 }, // Scanlist 96 +{ 0x01200000, 0xc0 }, // Scanlist 97 +{ 0x01200200, 0xc0 }, // Scanlist 98 +{ 0x01200400, 0xc0 }, // Scanlist 99 +{ 0x01200600, 0xc0 }, // Scanlist 100 +{ 0x01200800, 0xc0 }, // Scanlist 101 +{ 0x01200a00, 0xc0 }, // Scanlist 102 +{ 0x01200c00, 0xc0 }, // Scanlist 103 +{ 0x01200e00, 0xc0 }, // Scanlist 104 +{ 0x01201000, 0xc0 }, // Scanlist 105 +{ 0x01201200, 0xc0 }, // Scanlist 106 +{ 0x01201400, 0xc0 }, // Scanlist 107 +{ 0x01201600, 0xc0 }, // Scanlist 108 +{ 0x01201800, 0xc0 }, // Scanlist 109 +{ 0x01201a00, 0xc0 }, // Scanlist 110 +{ 0x01201c00, 0xc0 }, // Scanlist 111 +{ 0x01201e00, 0xc0 }, // Scanlist 112 +{ 0x01240000, 0xc0 }, // Scanlist 113 +{ 0x01240200, 0xc0 }, // Scanlist 114 +{ 0x01240400, 0xc0 }, // Scanlist 115 +{ 0x01240600, 0xc0 }, // Scanlist 116 +{ 0x01240800, 0xc0 }, // Scanlist 117 +{ 0x01240a00, 0xc0 }, // Scanlist 118 +{ 0x01240c00, 0xc0 }, // Scanlist 119 +{ 0x01240e00, 0xc0 }, // Scanlist 120 +{ 0x01241000, 0xc0 }, // Scanlist 121 +{ 0x01241200, 0xc0 }, // Scanlist 122 +{ 0x01241400, 0xc0 }, // Scanlist 123 +{ 0x01241600, 0xc0 }, // Scanlist 124 +{ 0x01241800, 0xc0 }, // Scanlist 125 +{ 0x01241a00, 0xc0 }, // Scanlist 126 +{ 0x01241c00, 0xc0 }, // Scanlist 127 +{ 0x01241e00, 0xc0 }, // Scanlist 128 +{ 0x01280000, 0xc0 }, // Scanlist 129 +{ 0x01280200, 0xc0 }, // Scanlist 130 +{ 0x01280400, 0xc0 }, // Scanlist 131 +{ 0x01280600, 0xc0 }, // Scanlist 132 +{ 0x01280800, 0xc0 }, // Scanlist 133 +{ 0x01280a00, 0xc0 }, // Scanlist 134 +{ 0x01280c00, 0xc0 }, // Scanlist 135 +{ 0x01280e00, 0xc0 }, // Scanlist 136 +{ 0x01281000, 0xc0 }, // Scanlist 137 +{ 0x01281200, 0xc0 }, // Scanlist 138 +{ 0x01281400, 0xc0 }, // Scanlist 139 +{ 0x01281600, 0xc0 }, // Scanlist 140 +{ 0x01281800, 0xc0 }, // Scanlist 141 +{ 0x01281a00, 0xc0 }, // Scanlist 142 +{ 0x01281c00, 0xc0 }, // Scanlist 143 +{ 0x01281e00, 0xc0 }, // Scanlist 144 +{ 0x012c0000, 0xc0 }, // Scanlist 145 +{ 0x012c0200, 0xc0 }, // Scanlist 146 +{ 0x012c0400, 0xc0 }, // Scanlist 147 +{ 0x012c0600, 0xc0 }, // Scanlist 148 +{ 0x012c0800, 0xc0 }, // Scanlist 149 +{ 0x012c0a00, 0xc0 }, // Scanlist 150 +{ 0x012c0c00, 0xc0 }, // Scanlist 151 +{ 0x012c0e00, 0xc0 }, // Scanlist 152 +{ 0x012c1000, 0xc0 }, // Scanlist 153 +{ 0x012c1200, 0xc0 }, // Scanlist 154 +{ 0x012c1400, 0xc0 }, // Scanlist 155 +{ 0x012c1600, 0xc0 }, // Scanlist 156 +{ 0x012c1800, 0xc0 }, // Scanlist 157 +{ 0x012c1a00, 0xc0 }, // Scanlist 158 +{ 0x012c1c00, 0xc0 }, // Scanlist 159 +{ 0x012c1e00, 0xc0 }, // Scanlist 160 +{ 0x01300000, 0xc0 }, // Scanlist 161 +{ 0x01300200, 0xc0 }, // Scanlist 162 +{ 0x01300400, 0xc0 }, // Scanlist 163 +{ 0x01300600, 0xc0 }, // Scanlist 164 +{ 0x01300800, 0xc0 }, // Scanlist 165 +{ 0x01300a00, 0xc0 }, // Scanlist 166 +{ 0x01300c00, 0xc0 }, // Scanlist 167 +{ 0x01300e00, 0xc0 }, // Scanlist 168 +{ 0x01301000, 0xc0 }, // Scanlist 169 +{ 0x01301200, 0xc0 }, // Scanlist 170 +{ 0x01301400, 0xc0 }, // Scanlist 171 +{ 0x01301600, 0xc0 }, // Scanlist 172 +{ 0x01301800, 0xc0 }, // Scanlist 173 +{ 0x01301a00, 0xc0 }, // Scanlist 174 +{ 0x01301c00, 0xc0 }, // Scanlist 175 +{ 0x01301e00, 0xc0 }, // Scanlist 176 +{ 0x01340000, 0xc0 }, // Scanlist 177 +{ 0x01340200, 0xc0 }, // Scanlist 178 +{ 0x01340400, 0xc0 }, // Scanlist 179 +{ 0x01340600, 0xc0 }, // Scanlist 180 +{ 0x01340800, 0xc0 }, // Scanlist 181 +{ 0x01340a00, 0xc0 }, // Scanlist 182 +{ 0x01340c00, 0xc0 }, // Scanlist 183 +{ 0x01340e00, 0xc0 }, // Scanlist 184 +{ 0x01341000, 0xc0 }, // Scanlist 185 +{ 0x01341200, 0xc0 }, // Scanlist 186 +{ 0x01341400, 0xc0 }, // Scanlist 187 +{ 0x01341600, 0xc0 }, // Scanlist 188 +{ 0x01341800, 0xc0 }, // Scanlist 189 +{ 0x01341a00, 0xc0 }, // Scanlist 190 +{ 0x01341c00, 0xc0 }, // Scanlist 191 +{ 0x01341e00, 0xc0 }, // Scanlist 192 +{ 0x01380000, 0xc0 }, // Scanlist 193 +{ 0x01380200, 0xc0 }, // Scanlist 194 +{ 0x01380400, 0xc0 }, // Scanlist 195 +{ 0x01380600, 0xc0 }, // Scanlist 196 +{ 0x01380800, 0xc0 }, // Scanlist 197 +{ 0x01380a00, 0xc0 }, // Scanlist 198 +{ 0x01380c00, 0xc0 }, // Scanlist 199 +{ 0x01380e00, 0xc0 }, // Scanlist 200 +{ 0x01381000, 0xc0 }, // Scanlist 201 +{ 0x01381200, 0xc0 }, // Scanlist 202 +{ 0x01381400, 0xc0 }, // Scanlist 203 +{ 0x01381600, 0xc0 }, // Scanlist 204 +{ 0x01381800, 0xc0 }, // Scanlist 205 +{ 0x01381a00, 0xc0 }, // Scanlist 206 +{ 0x01381c00, 0xc0 }, // Scanlist 207 +{ 0x01381e00, 0xc0 }, // Scanlist 208 +{ 0x013c0000, 0xc0 }, // Scanlist 209 +{ 0x013c0200, 0xc0 }, // Scanlist 210 +{ 0x013c0400, 0xc0 }, // Scanlist 211 +{ 0x013c0600, 0xc0 }, // Scanlist 212 +{ 0x013c0800, 0xc0 }, // Scanlist 213 +{ 0x013c0a00, 0xc0 }, // Scanlist 214 +{ 0x013c0c00, 0xc0 }, // Scanlist 215 +{ 0x013c0e00, 0xc0 }, // Scanlist 216 +{ 0x013c1000, 0xc0 }, // Scanlist 217 +{ 0x013c1200, 0xc0 }, // Scanlist 218 +{ 0x013c1400, 0xc0 }, // Scanlist 219 +{ 0x013c1600, 0xc0 }, // Scanlist 220 +{ 0x013c1800, 0xc0 }, // Scanlist 221 +{ 0x013c1a00, 0xc0 }, // Scanlist 222 +{ 0x013c1c00, 0xc0 }, // Scanlist 223 +{ 0x013c1e00, 0xc0 }, // Scanlist 224 +{ 0x01400000, 0xc0 }, // Scanlist 225 +{ 0x01400200, 0xc0 }, // Scanlist 226 +{ 0x01400400, 0xc0 }, // Scanlist 227 +{ 0x01400600, 0xc0 }, // Scanlist 228 +{ 0x01400800, 0xc0 }, // Scanlist 229 +{ 0x01400a00, 0xc0 }, // Scanlist 230 +{ 0x01400c00, 0xc0 }, // Scanlist 231 +{ 0x01400e00, 0xc0 }, // Scanlist 232 +{ 0x01401000, 0xc0 }, // Scanlist 233 +{ 0x01401200, 0xc0 }, // Scanlist 234 +{ 0x01401400, 0xc0 }, // Scanlist 235 +{ 0x01401600, 0xc0 }, // Scanlist 236 +{ 0x01401800, 0xc0 }, // Scanlist 237 +{ 0x01401a00, 0xc0 }, // Scanlist 238 +{ 0x01401c00, 0xc0 }, // Scanlist 239 +{ 0x01401e00, 0xc0 }, // Scanlist 240 +{ 0x01440000, 0xc0 }, // Scanlist 241 +{ 0x01440200, 0xc0 }, // Scanlist 242 +{ 0x01440400, 0xc0 }, // Scanlist 243 +{ 0x01440600, 0xc0 }, // Scanlist 244 +{ 0x01440800, 0xc0 }, // Scanlist 245 +{ 0x01440a00, 0xc0 }, // Scanlist 246 +{ 0x01440c00, 0xc0 }, // Scanlist 247 +{ 0x01440e00, 0xc0 }, // Scanlist 248 +{ 0x01441000, 0xc0 }, // Scanlist 249 +{ 0x01441200, 0xc0 }, // Scanlist 250 +{ 0x01640000, 0x640 }, // Unknown index +{ 0x01640800, 0xc0 }, // Zeroes? +{ 0x02140000, 0x800 }, // Messages 1-8 +{ 0x02180000, 0x800 }, // Messages 9-16 +{ 0x021c0000, 0x800 }, // Messages 17-24 +{ 0x02200000, 0x800 }, // Messages 25-32 +{ 0x02240000, 0x800 }, // Messages 33-40 +{ 0x02280000, 0x800 }, // Messages 41-48 +{ 0x022c0000, 0x800 }, // Messages 49-56 +{ 0x02300000, 0x800 }, // Messages 57-64 +{ 0x02340000, 0x800 }, // Messages 65-72 +{ 0x02380000, 0x800 }, // Messages 73-80 +{ 0x023c0000, 0x800 }, // Messages 81-88 +{ 0x02400000, 0x800 }, // Messages 89-96 +{ 0x02440000, 0x400 }, // Messages 97-100 +{ 0x02480000, 0x1c0 }, // Unknown index +{ 0x02480200, 0x40 }, // Unknown bitmap +{ 0x024c0000, 0x40 }, // Unknown data +{ 0x024c0c80, 0x40 }, // Unknown data +{ 0x024c0d00, 0x200 }, // Zeroes? +{ 0x024c1000, 0x140 }, // Unknown data +{ 0x024c1280, 0x40 }, // Unknown data +{ 0x024c1300, 0x80 }, // Unknown data +{ 0x024c1400, 0x80 }, // Unknown data +{ 0x024c1500, 0x240 }, // Channel bitmap +{ 0x024c1800, 0x500 }, // Zeroes? +{ 0x024c2000, 0x440 }, // Unknown data +{ 0x024c2600, 0x40 }, // Unknown data +{ 0x02500000, 0x640 }, // Unknown data +{ 0x02501000, 0x40 }, // Unknown data +{ 0x02501100, 0x140 }, // GPS message +{ 0x02540000, 0x1f40 }, // Zones 1-250 +{ 0x02580000, 0x1f40 }, // Radio ID 1-250 +{ 0x025c0000, 0x880 }, // Unknown data, status message +{ 0x025c0b00, 0x40 }, // Unknown data +{ 0x02600000, 0x9c40 }, // Unknown data, bitmap +{ 0x02640000, 0x500 }, // Unknown data, bitmap +{ 0x02680000, 0xf4240 }, // Contacts 1-10000 +{ 0x02900000, 0x80 }, // Unknown index +{ 0x02900100, 0x80 }, // Unknown index +{ 0x02940000, 0x180 }, // AnalogContacts 1-128 +{ 0x02980000, 0x140 }, // Grouplist 1 +{ 0x02980200, 0x140 }, // Grouplist 2 +{ 0x02980400, 0x140 }, // Grouplist 3 +{ 0x02980600, 0x140 }, // Grouplist 4 +{ 0x02980800, 0x140 }, // Grouplist 5 +{ 0x02980a00, 0x140 }, // Grouplist 6 +{ 0x02980c00, 0x140 }, // Grouplist 7 +{ 0x02980e00, 0x140 }, // Grouplist 8 +{ 0x02981000, 0x140 }, // Grouplist 9 +{ 0x02981200, 0x140 }, // Grouplist 10 +{ 0x02981400, 0x140 }, // Grouplist 11 +{ 0x02981600, 0x140 }, // Grouplist 12 +{ 0x02981800, 0x140 }, // Grouplist 13 +{ 0x02981a00, 0x140 }, // Grouplist 14 +{ 0x02981c00, 0x140 }, // Grouplist 15 +{ 0x02981e00, 0x140 }, // Grouplist 16 +{ 0x02982000, 0x140 }, // Grouplist 17 +{ 0x02982200, 0x140 }, // Grouplist 18 +{ 0x02982400, 0x140 }, // Grouplist 19 +{ 0x02982600, 0x140 }, // Grouplist 20 +{ 0x02982800, 0x140 }, // Grouplist 21 +{ 0x02982a00, 0x140 }, // Grouplist 22 +{ 0x02982c00, 0x140 }, // Grouplist 23 +{ 0x02982e00, 0x140 }, // Grouplist 24 +{ 0x02983000, 0x140 }, // Grouplist 25 +{ 0x02983200, 0x140 }, // Grouplist 26 +{ 0x02983400, 0x140 }, // Grouplist 27 +{ 0x02983600, 0x140 }, // Grouplist 28 +{ 0x02983800, 0x140 }, // Grouplist 29 +{ 0x02983a00, 0x140 }, // Grouplist 30 +{ 0x02983c00, 0x140 }, // Grouplist 31 +{ 0x02983e00, 0x140 }, // Grouplist 32 +{ 0x02984000, 0x140 }, // Grouplist 33 +{ 0x02984200, 0x140 }, // Grouplist 34 +{ 0x02984400, 0x140 }, // Grouplist 35 +{ 0x02984600, 0x140 }, // Grouplist 36 +{ 0x02984800, 0x140 }, // Grouplist 37 +{ 0x02984a00, 0x140 }, // Grouplist 38 +{ 0x02984c00, 0x140 }, // Grouplist 39 +{ 0x02984e00, 0x140 }, // Grouplist 40 +{ 0x02985000, 0x140 }, // Grouplist 41 +{ 0x02985200, 0x140 }, // Grouplist 42 +{ 0x02985400, 0x140 }, // Grouplist 43 +{ 0x02985600, 0x140 }, // Grouplist 44 +{ 0x02985800, 0x140 }, // Grouplist 45 +{ 0x02985a00, 0x140 }, // Grouplist 46 +{ 0x02985c00, 0x140 }, // Grouplist 47 +{ 0x02985e00, 0x140 }, // Grouplist 48 +{ 0x02986000, 0x140 }, // Grouplist 49 +{ 0x02986200, 0x140 }, // Grouplist 50 +{ 0x02986400, 0x140 }, // Grouplist 51 +{ 0x02986600, 0x140 }, // Grouplist 52 +{ 0x02986800, 0x140 }, // Grouplist 53 +{ 0x02986a00, 0x140 }, // Grouplist 54 +{ 0x02986c00, 0x140 }, // Grouplist 55 +{ 0x02986e00, 0x140 }, // Grouplist 56 +{ 0x02987000, 0x140 }, // Grouplist 57 +{ 0x02987200, 0x140 }, // Grouplist 58 +{ 0x02987400, 0x140 }, // Grouplist 59 +{ 0x02987600, 0x140 }, // Grouplist 60 +{ 0x02987800, 0x140 }, // Grouplist 61 +{ 0x02987a00, 0x140 }, // Grouplist 62 +{ 0x02987c00, 0x140 }, // Grouplist 63 +{ 0x02987e00, 0x140 }, // Grouplist 64 +{ 0x02988000, 0x140 }, // Grouplist 65 +{ 0x02988200, 0x140 }, // Grouplist 66 +{ 0x02988400, 0x140 }, // Grouplist 67 +{ 0x02988600, 0x140 }, // Grouplist 68 +{ 0x02988800, 0x140 }, // Grouplist 69 +{ 0x02988a00, 0x140 }, // Grouplist 70 +{ 0x02988c00, 0x140 }, // Grouplist 71 +{ 0x02988e00, 0x140 }, // Grouplist 72 +{ 0x02989000, 0x140 }, // Grouplist 73 +{ 0x02989200, 0x140 }, // Grouplist 74 +{ 0x02989400, 0x140 }, // Grouplist 75 +{ 0x02989600, 0x140 }, // Grouplist 76 +{ 0x02989800, 0x140 }, // Grouplist 77 +{ 0x02989a00, 0x140 }, // Grouplist 78 +{ 0x02989c00, 0x140 }, // Grouplist 79 +{ 0x02989e00, 0x140 }, // Grouplist 80 +{ 0x0298a000, 0x140 }, // Grouplist 81 +{ 0x0298a200, 0x140 }, // Grouplist 82 +{ 0x0298a400, 0x140 }, // Grouplist 83 +{ 0x0298a600, 0x140 }, // Grouplist 84 +{ 0x0298a800, 0x140 }, // Grouplist 85 +{ 0x0298aa00, 0x140 }, // Grouplist 86 +{ 0x0298ac00, 0x140 }, // Grouplist 87 +{ 0x0298ae00, 0x140 }, // Grouplist 88 +{ 0x0298b000, 0x140 }, // Grouplist 89 +{ 0x0298b200, 0x140 }, // Grouplist 90 +{ 0x0298b400, 0x140 }, // Grouplist 91 +{ 0x0298b600, 0x140 }, // Grouplist 92 +{ 0x0298b800, 0x140 }, // Grouplist 93 +{ 0x0298ba00, 0x140 }, // Grouplist 94 +{ 0x0298bc00, 0x140 }, // Grouplist 95 +{ 0x0298be00, 0x140 }, // Grouplist 96 +{ 0x0298c000, 0x140 }, // Grouplist 97 +{ 0x0298c200, 0x140 }, // Grouplist 98 +{ 0x0298c400, 0x140 }, // Grouplist 99 +{ 0x0298c600, 0x140 }, // Grouplist 100 +{ 0x0298c800, 0x140 }, // Grouplist 101 +{ 0x0298ca00, 0x140 }, // Grouplist 102 +{ 0x0298cc00, 0x140 }, // Grouplist 103 +{ 0x0298ce00, 0x140 }, // Grouplist 104 +{ 0x0298d000, 0x140 }, // Grouplist 105 +{ 0x0298d200, 0x140 }, // Grouplist 106 +{ 0x0298d400, 0x140 }, // Grouplist 107 +{ 0x0298d600, 0x140 }, // Grouplist 108 +{ 0x0298d800, 0x140 }, // Grouplist 109 +{ 0x0298da00, 0x140 }, // Grouplist 110 +{ 0x0298dc00, 0x140 }, // Grouplist 111 +{ 0x0298de00, 0x140 }, // Grouplist 112 +{ 0x0298e000, 0x140 }, // Grouplist 113 +{ 0x0298e200, 0x140 }, // Grouplist 114 +{ 0x0298e400, 0x140 }, // Grouplist 115 +{ 0x0298e600, 0x140 }, // Grouplist 116 +{ 0x0298e800, 0x140 }, // Grouplist 117 +{ 0x0298ea00, 0x140 }, // Grouplist 118 +{ 0x0298ec00, 0x140 }, // Grouplist 119 +{ 0x0298ee00, 0x140 }, // Grouplist 120 +{ 0x0298f000, 0x140 }, // Grouplist 121 +{ 0x0298f200, 0x140 }, // Grouplist 122 +{ 0x0298f400, 0x140 }, // Grouplist 123 +{ 0x0298f600, 0x140 }, // Grouplist 124 +{ 0x0298f800, 0x140 }, // Grouplist 125 +{ 0x0298fa00, 0x140 }, // Grouplist 126 +{ 0x0298fc00, 0x140 }, // Grouplist 127 +{ 0x0298fe00, 0x140 }, // Grouplist 128 +{ 0x02990000, 0x140 }, // Grouplist 129 +{ 0x02990200, 0x140 }, // Grouplist 130 +{ 0x02990400, 0x140 }, // Grouplist 131 +{ 0x02990600, 0x140 }, // Grouplist 132 +{ 0x02990800, 0x140 }, // Grouplist 133 +{ 0x02990a00, 0x140 }, // Grouplist 134 +{ 0x02990c00, 0x140 }, // Grouplist 135 +{ 0x02990e00, 0x140 }, // Grouplist 136 +{ 0x02991000, 0x140 }, // Grouplist 137 +{ 0x02991200, 0x140 }, // Grouplist 138 +{ 0x02991400, 0x140 }, // Grouplist 139 +{ 0x02991600, 0x140 }, // Grouplist 140 +{ 0x02991800, 0x140 }, // Grouplist 141 +{ 0x02991a00, 0x140 }, // Grouplist 142 +{ 0x02991c00, 0x140 }, // Grouplist 143 +{ 0x02991e00, 0x140 }, // Grouplist 144 +{ 0x02992000, 0x140 }, // Grouplist 145 +{ 0x02992200, 0x140 }, // Grouplist 146 +{ 0x02992400, 0x140 }, // Grouplist 147 +{ 0x02992600, 0x140 }, // Grouplist 148 +{ 0x02992800, 0x140 }, // Grouplist 149 +{ 0x02992a00, 0x140 }, // Grouplist 150 +{ 0x02992c00, 0x140 }, // Grouplist 151 +{ 0x02992e00, 0x140 }, // Grouplist 152 +{ 0x02993000, 0x140 }, // Grouplist 153 +{ 0x02993200, 0x140 }, // Grouplist 154 +{ 0x02993400, 0x140 }, // Grouplist 155 +{ 0x02993600, 0x140 }, // Grouplist 156 +{ 0x02993800, 0x140 }, // Grouplist 157 +{ 0x02993a00, 0x140 }, // Grouplist 158 +{ 0x02993c00, 0x140 }, // Grouplist 159 +{ 0x02993e00, 0x140 }, // Grouplist 160 +{ 0x02994000, 0x140 }, // Grouplist 161 +{ 0x02994200, 0x140 }, // Grouplist 162 +{ 0x02994400, 0x140 }, // Grouplist 163 +{ 0x02994600, 0x140 }, // Grouplist 164 +{ 0x02994800, 0x140 }, // Grouplist 165 +{ 0x02994a00, 0x140 }, // Grouplist 166 +{ 0x02994c00, 0x140 }, // Grouplist 167 +{ 0x02994e00, 0x140 }, // Grouplist 168 +{ 0x02995000, 0x140 }, // Grouplist 169 +{ 0x02995200, 0x140 }, // Grouplist 170 +{ 0x02995400, 0x140 }, // Grouplist 171 +{ 0x02995600, 0x140 }, // Grouplist 172 +{ 0x02995800, 0x140 }, // Grouplist 173 +{ 0x02995a00, 0x140 }, // Grouplist 174 +{ 0x02995c00, 0x140 }, // Grouplist 175 +{ 0x02995e00, 0x140 }, // Grouplist 176 +{ 0x02996000, 0x140 }, // Grouplist 177 +{ 0x02996200, 0x140 }, // Grouplist 178 +{ 0x02996400, 0x140 }, // Grouplist 179 +{ 0x02996600, 0x140 }, // Grouplist 180 +{ 0x02996800, 0x140 }, // Grouplist 181 +{ 0x02996a00, 0x140 }, // Grouplist 182 +{ 0x02996c00, 0x140 }, // Grouplist 183 +{ 0x02996e00, 0x140 }, // Grouplist 184 +{ 0x02997000, 0x140 }, // Grouplist 185 +{ 0x02997200, 0x140 }, // Grouplist 186 +{ 0x02997400, 0x140 }, // Grouplist 187 +{ 0x02997600, 0x140 }, // Grouplist 188 +{ 0x02997800, 0x140 }, // Grouplist 189 +{ 0x02997a00, 0x140 }, // Grouplist 190 +{ 0x02997c00, 0x140 }, // Grouplist 191 +{ 0x02997e00, 0x140 }, // Grouplist 192 +{ 0x02998000, 0x140 }, // Grouplist 193 +{ 0x02998200, 0x140 }, // Grouplist 194 +{ 0x02998400, 0x140 }, // Grouplist 195 +{ 0x02998600, 0x140 }, // Grouplist 196 +{ 0x02998800, 0x140 }, // Grouplist 197 +{ 0x02998a00, 0x140 }, // Grouplist 198 +{ 0x02998c00, 0x140 }, // Grouplist 199 +{ 0x02998e00, 0x140 }, // Grouplist 200 +{ 0x02999000, 0x140 }, // Grouplist 201 +{ 0x02999200, 0x140 }, // Grouplist 202 +{ 0x02999400, 0x140 }, // Grouplist 203 +{ 0x02999600, 0x140 }, // Grouplist 204 +{ 0x02999800, 0x140 }, // Grouplist 205 +{ 0x02999a00, 0x140 }, // Grouplist 206 +{ 0x02999c00, 0x140 }, // Grouplist 207 +{ 0x02999e00, 0x140 }, // Grouplist 208 +{ 0x0299a000, 0x140 }, // Grouplist 209 +{ 0x0299a200, 0x140 }, // Grouplist 210 +{ 0x0299a400, 0x140 }, // Grouplist 211 +{ 0x0299a600, 0x140 }, // Grouplist 212 +{ 0x0299a800, 0x140 }, // Grouplist 213 +{ 0x0299aa00, 0x140 }, // Grouplist 214 +{ 0x0299ac00, 0x140 }, // Grouplist 215 +{ 0x0299ae00, 0x140 }, // Grouplist 216 +{ 0x0299b000, 0x140 }, // Grouplist 217 +{ 0x0299b200, 0x140 }, // Grouplist 218 +{ 0x0299b400, 0x140 }, // Grouplist 219 +{ 0x0299b600, 0x140 }, // Grouplist 220 +{ 0x0299b800, 0x140 }, // Grouplist 221 +{ 0x0299ba00, 0x140 }, // Grouplist 222 +{ 0x0299bc00, 0x140 }, // Grouplist 223 +{ 0x0299be00, 0x140 }, // Grouplist 224 +{ 0x0299c000, 0x140 }, // Grouplist 225 +{ 0x0299c200, 0x140 }, // Grouplist 226 +{ 0x0299c400, 0x140 }, // Grouplist 227 +{ 0x0299c600, 0x140 }, // Grouplist 228 +{ 0x0299c800, 0x140 }, // Grouplist 229 +{ 0x0299ca00, 0x140 }, // Grouplist 230 +{ 0x0299cc00, 0x140 }, // Grouplist 231 +{ 0x0299ce00, 0x140 }, // Grouplist 232 +{ 0x0299d000, 0x140 }, // Grouplist 233 +{ 0x0299d200, 0x140 }, // Grouplist 234 +{ 0x0299d400, 0x140 }, // Grouplist 235 +{ 0x0299d600, 0x140 }, // Grouplist 236 +{ 0x0299d800, 0x140 }, // Grouplist 237 +{ 0x0299da00, 0x140 }, // Grouplist 238 +{ 0x0299dc00, 0x140 }, // Grouplist 239 +{ 0x0299de00, 0x140 }, // Grouplist 240 +{ 0x0299e000, 0x140 }, // Grouplist 241 +{ 0x0299e200, 0x140 }, // Grouplist 242 +{ 0x0299e400, 0x140 }, // Grouplist 243 +{ 0x0299e600, 0x140 }, // Grouplist 244 +{ 0x0299e800, 0x140 }, // Grouplist 245 +{ 0x0299ea00, 0x140 }, // Grouplist 246 +{ 0x0299ec00, 0x140 }, // Grouplist 247 +{ 0x0299ee00, 0x140 }, // Grouplist 248 +{ 0x0299f000, 0x140 }, // Grouplist 249 +{ 0x0299f200, 0x140 }, // Grouplist 250 +{ 0x04280000, 0x300 }, // Unknown index +{ 0, 0 }, diff --git a/d868uv.c b/d868uv.c new file mode 100644 index 0000000..8923cd3 --- /dev/null +++ b/d868uv.c @@ -0,0 +1,1279 @@ +/* + * Interface to Anytone D868UV. + * + * Copyright (C) 2018 Serge Vakulenko, KK6ABQ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include "radio.h" +#include "util.h" + +// +// Sizes of configuration tables. +// +#define NCHAN 4000 +#define NCONTACTS 10000 +#define NZONES 250 +#define NGLISTS 250 +#define NSCANL 250 +#define NMESSAGES 100 + +// +// Offsets in the image file. +// +#define OFFSET_BANK1 0x000040 // Channels +#define OFFSET_ZONELISTS 0x03e8c0 // Channel lists of zones +#define OFFSET_CHAN_MAP 0x070a40 // Bitmap of valid channels +#define OFFSET_ZONE_MAP 0x070940 // Bitmap of valid zones +#define OFFSET_SETTINGS 0x071600 // General settings +#define OFFSET_ZONENAMES 0x071dc0 // Names of zones +#define OFFSET_RADIOID 0x073d00 // Table of radio IDs +#define OFFSET_CONTACT_MAP 0x080140 // Bitmap of invalid contacts +#define OFFSET_CONTACTS 0x080640 // Contacts + +#define GET_SETTINGS() ((general_settings_t*) &radio_mem[OFFSET_SETTINGS]) +#define GET_RADIOID() ((radioid_t*) &radio_mem[OFFSET_RADIOID]) +#define GET_ZONEMAP() (&radio_mem[OFFSET_ZONE_MAP]) +#define GET_CONTACT_MAP() (&radio_mem[OFFSET_CONTACT_MAP]) +#define GET_ZONENAME(i) (&radio_mem[OFFSET_ZONENAMES + (i)*32]) +#define GET_ZONELIST(i) ((uint16_t*) &radio_mem[OFFSET_ZONELISTS + (i)*512]) +#define GET_CONTACT(i) ((contact_t*) &radio_mem[OFFSET_CONTACTS + (i)*100]) + +#define VALID_TEXT(txt) (*(txt) != 0 && *(txt) != 0xff) + +// +// Size of memory image. +// Essentialy a sum of all fragments defined ind868um-map.h. +// +#define MEMSZ 1607296 + +// +// D868UV radio has a huge internal address space, more than 64 Mbytes. +// The configuration data are dispersed over this space. +// Here is a table of fragments: starting address and length. +// We read these fragments and save them into a file continuously. +// +typedef struct { + unsigned address; + unsigned length; +} fragment_t; + +static fragment_t region_map[] = { +#include "d868uv-map.h" +}; + +// +// Channel data. +// +typedef struct { + + // Bytes 0-7 + uint32_t rx_frequency; // RX Frequency: 8 digits BCD + uint32_t tx_offset; // TX Offset: 8 digits BCD + + // Byte 8 + uint8_t channel_mode : 2, // Mode: Analog or Digital +#define MODE_ANALOG 0 // Analog +#define MODE_DIGITAL 1 // Digital +#define MODE_A_D 2 // A+D, transmit analog +#define MODE_D_A 3 // D+A, transmit digital + + power : 2, // Power: Low, Middle, High, Turbo +#define POWER_LOW 0 +#define POWER_MIDDLE 1 +#define POWER_HIGH 2 +#define POWER_TURBO 3 + + bandwidth : 1, // Bandwidth: 12.5 or 25 kHz +#define BW_12_5_KHZ 0 +#define BW_25_KHZ 1 + + _unused8 : 1, // 0 + repeater_mode : 2; // Sign of TX frequency offset +#define RM_SIMPLEX 0 // TX frequency = RX frequency +#define RM_TXPOS 1 // Positive TX offset +#define RM_TXNEG 2 // Negative TX offset + + // Byte 9 + uint8_t rx_ctcss : 1, // CTCSS Decode + rx_dcs : 1, // DCS Decode + tx_ctcss : 1, // CTCSS Encode + tx_dcs : 1, // DCS Encode + reverse : 1, // Reverse + rx_only : 1, // TX Prohibit + call_confirm : 1, // Call Confirmation + talkaround : 1; // Talk Around + + // Bytes 10-15 + uint8_t ctcss_transmit; // CTCSS Encode: 0=62.5, 50=254.1, 51=Define + uint8_t ctcss_receive; // CTCSS Decode: 0=62.5, 50=254.1, 51=Define + uint16_t dcs_transmit; // DCS Encode: 0=D000N, 17=D021N, 1023=D777N + uint16_t dcs_receive; // DCS Decode: 0=D000N, 17=D021N, 1023=D777N + + // Bytes 16-19 + uint16_t custom_ctcss; // 0x09cf=251.1, 0x0a28=260 + uint8_t tone2_decode; // 2Tone Decode: 0x00=1, 0x0f=16 + uint8_t _unused19; // 0 + + // Bytes 20-23 + uint16_t contact_index; // Contact: 0=Contact1, 1=Contact2, ... + uint16_t _unused22; // 0 + + // Byte 24 + uint8_t id_index; // Index in Radio ID table + + // Byte 25 + uint8_t ptt_id : 2, // PTT ID +#define PTTID_OFF 0 +#define PTTID_START 1 +#define PTTID_END 2 +#define PTTID_START_END 3 + + _unused25_1 : 2, // 0 + + squelch_mode : 1, // Squelch Mode +#define SQ_CARRIER 0 // Carrier +#define SQ_TONE 1 // CTCSS/DCS + + _unused25_2 : 3; // 0 + + // Byte 26 + uint8_t tx_permit : 2, // TX Permit +#define PERMIT_ALWAYS 0 // Always +#define PERMIT_CH_FREE 1 // Channel Free +#define PERMIT_CC_DIFF 2 // Different Color Code +#define PERMIT_CC_SAME 3 // Same Color Code + + _unused26_1 : 2, // 0 + + _opt_signal : 2, // Optional Signal +#define OPTSIG_OFF 0 // Off +#define OPTSIG_DTMF 1 // DTMF +#define OPTSIG_2TONE 2 // 2Tone +#define OPTSIG_5TONE 3 // 5Tone + + _unused26_2 : 2; // 0 + + // Bytes 27-31 + uint8_t scan_list_index; // Scan List: 0xff=None, 0=ScanList1... + uint8_t group_list_index; // Receive Group List: 0xff=None, 0=GroupList1... + uint8_t id_2tone; // 2Tone ID: 0=1, 0x17=24 + uint8_t id_5tone; // 5Tone ID: 0=1, 0x63=100 + uint8_t id_dtmf; // DTMF ID: 0=1, 0x0f=16 + + // Byte 32 + uint8_t color_code; // Color Code: 0-15 + + // Byte 33 + uint8_t slot2 : 1, // Slot: Slot2 + _unused33_1 : 1, // 0 + simplex_tdma : 1, // Simplex TDMA: On + _unused33_2 : 1, // 0 + tdma_adaptive : 1, // TDMA Adaptive: On + _unused33_3 : 1, // 0 + enh_encryption : 1, // Encryption Type: Enhanced Encryption + work_alone : 1; // Work Alone: On + + // Byte 34 + uint8_t encryption; // Digital Encryption: 1-32, 0=Off + + // Bytes 35-51 + uint8_t name[16]; // Channel Name, zero filled + uint8_t _unused51; // 0 + + // Byte 52 + uint8_t ranging : 1, // Ranging: On + through_mode : 1, // Through Mode: On + _unused52 : 6; // 0 + + // Byte 53 + uint8_t aprs_report : 1, // APRS Report: On + _unused53 : 7; // 0 + + // Bytes 54-63 + uint8_t aprs_channel; // APRS Report Channel: 0x00=1, ... 0x07=8 + uint8_t _unused55[9]; // 0 +} channel_t; + +// +// General settings: 0x640 bytes at 0x02500000. +// TODO: verify the general settings with official CPS +// +typedef struct { + // Bytes 0-5. + uint8_t _unused0[6]; + + // Bytes 6-7. + uint8_t power_on; // Power-on Interface +#define PWON_DEFAULT 0 // Default +#define PWON_CUST_CHAR 1 // Custom Char +#define PWON_CUST_PICT 2 // Custom Picture + + uint8_t _unused7; + + // Bytes 8-0x5ff. + uint8_t _unused8[0x5f8]; + + // Bytes 0x600-0x61f + uint8_t intro_line1[16]; // Up to 14 characters + uint8_t intro_line2[16]; // Up to 14 characters + + // Bytes 0x620-0x63f + uint8_t password[16]; // Up to 8 ascii digits + uint8_t _unused630[16]; // 0xff + +} general_settings_t; + +// +// Radio ID table: 250 entries, 0x1f40 bytes at 0x02580000. +// +typedef struct { + // Bytes 0-3. + uint8_t id[4]; // Up to 8 BCD digits +#define GET_ID(x) (((x)[0] >> 4) * 10000000 +\ + ((x)[0] & 15) * 1000000 +\ + ((x)[1] >> 4) * 100000 +\ + ((x)[1] & 15) * 10000 +\ + ((x)[2] >> 4) * 1000 +\ + ((x)[2] & 15) * 100 +\ + ((x)[3] >> 4) * 10 +\ + ((x)[3] & 15)) + // Byte 4. + uint8_t _unused4; // 0 + + // Bytes 5-20 + uint8_t name[16]; // Name + + // Bytes 21-31 + uint8_t _unused21[11]; // 0 + +} radioid_t; + +// +// Contact data: 100 bytes per record. +// +typedef struct { + + // Byte 0 + uint8_t type; // Call Type: Group Call, Private Call or All Call +#define CALL_PRIVATE 0 +#define CALL_GROUP 1 +#define CALL_ALL 2 + + // Bytes 1-16 + uint8_t name[16]; // Contact Name (ASCII) + + // Bytes 17-34 + uint8_t _unused17[18]; // 0 + + // Bytes 35-38 + uint8_t id[4]; // Call ID: BCD coded 8 digits +#define GET_ID(x) (((x)[0] >> 4) * 10000000 +\ + ((x)[0] & 15) * 1000000 +\ + ((x)[1] >> 4) * 100000 +\ + ((x)[1] & 15) * 10000 +\ + ((x)[2] >> 4) * 1000 +\ + ((x)[2] & 15) * 100 +\ + ((x)[3] >> 4) * 10 +\ + ((x)[3] & 15)) +#define CONTACT_ID(ct) GET_ID((ct)->id) + + // Byte 39 + uint8_t call_alert; // Call Alert: None, Ring, Online Alert +#define ALERT_NONE 0 +#define ALERT_RING 1 +#define ALERT_ONLINE 2 + + // Bytes 40-99 + uint8_t _unused40[60]; // 0 + +} contact_t; + +static const char *POWER_NAME[] = { "Low", "Mid", "High", "Turbo" }; +static const char *DIGITAL_ADMIT_NAME[] = { "-", "Free", "NColor", "Color" }; +static const char *ANALOG_ADMIT_NAME[] = { "-", "Tone", "Free", "Free" }; +static const char *BANDWIDTH[] = { "12.5", "25" }; +static const char *CONTACT_TYPE[] = { "Private", "Group", "All", "Unknown" }; +static const char *ALERT_TYPE[] = { "-", "+", "Online", "Unknown" }; + +// +// CTCSS tones, Hz*10. +// +#define NCTCSS 51 + +static const int CTCSS_TONES[NCTCSS] = { + 625, 670, 693, 719, 744, 770, 797, 825, 854, 885, + 915, 948, 974, 1000, 1035, 1072, 1109, 1148, 1188, 1230, + 1273, 1318, 1365, 1413, 1462, 1514, 1567, 1598, 1622, 1655, + 1679, 1713, 1738, 1773, 1799, 1835, 1862, 1899, 1928, 1966, + 1995, 2035, 2065, 2107, 2181, 2257, 2291, 2336, 2418, 2503, + 2541, +}; + +// +// Print a generic information about the device. +// +static void d868uv_print_version(radio_device_t *radio, FILE *out) +{ + //TODO +#if 0 + unsigned char *timestamp = GET_TIMESTAMP(); + static const char charmap[16] = "0123456789:;<=>?"; + + if (*timestamp != 0xff) { + fprintf(out, "Last Programmed Date: %d%d%d%d-%d%d-%d%d", + timestamp[0] >> 4, timestamp[0] & 15, timestamp[1] >> 4, timestamp[1] & 15, + timestamp[2] >> 4, timestamp[2] & 15, timestamp[3] >> 4, timestamp[3] & 15); + fprintf(out, " %d%d:%d%d:%d%d\n", + timestamp[4] >> 4, timestamp[4] & 15, timestamp[5] >> 4, timestamp[5] & 15, + timestamp[6] >> 4, timestamp[6] & 15); + fprintf(out, "CPS Software Version: V%c%c.%c%c\n", + charmap[timestamp[7] & 15], charmap[timestamp[8] & 15], + charmap[timestamp[9] & 15], charmap[timestamp[10] & 15]); + } +#endif +} + +// +// Read memory image from the device. +// +static void d868uv_download(radio_device_t *radio) +{ + fragment_t *f; + unsigned file_offset = 0; + unsigned last_printed = 0; + + for (f=region_map; f->length; f++) { + unsigned addr = f->address; + unsigned nbytes = f->length; + + while (nbytes > 0) { + unsigned n = (nbytes > 32*1024) ? 32*1024 : nbytes; + serial_read_region(addr, &radio_mem[file_offset], n); + file_offset += n; + addr += n; + nbytes -= n; + + if (file_offset / (32*1024) != last_printed) { + fprintf(stderr, "#"); + fflush(stderr); + last_printed = file_offset / (32*1024); + } + } + } + if (file_offset != MEMSZ) { + fprintf(stderr, "\nWrong MEMSZ=%u for D868UV!\n", MEMSZ); + fprintf(stderr, "Should be %u; check d868uv-map.h!\n", file_offset); + exit(-1); + } +} + +// +// Write memory image to the device. +// +static void d868uv_upload(radio_device_t *radio, int cont_flag) +{ + fragment_t *f; + unsigned file_offset; + unsigned last_printed = 0; + + // Skip first region. + file_offset = region_map[0].length; + for (f=region_map+1; f->length; f++) { + unsigned addr = f->address; + unsigned nbytes = f->length; + + while (nbytes > 0) { + unsigned n = (nbytes > 32*1024) ? 32*1024 : nbytes; + serial_write_region(addr, &radio_mem[file_offset], n); + file_offset += n; + addr += n; + nbytes -= n; + + if (file_offset / (32*1024) != last_printed) { + fprintf(stderr, "#"); + fflush(stderr); + last_printed = file_offset / (32*1024); + } + } + } + if (file_offset != MEMSZ) { + fprintf(stderr, "\nWrong MEMSZ=%u for D868UV!\n", MEMSZ); + fprintf(stderr, "Should be %u; check d868uv-map.h!\n", file_offset); + exit(-1); + } +} + +// +// Check whether the memory image is compatible with this device. +// +static int d868uv_is_compatible(radio_device_t *radio) +{ + return 1; +} + +static void print_id(FILE *out, int verbose) +{ + radioid_t *ri = GET_RADIOID(); + unsigned id = GET_ID(ri->id); + + if (verbose) + fprintf(out, "\n# Unique DMR ID and name of this radio."); + fprintf(out, "\nID: %u\nName: ", id); + if (VALID_TEXT(ri->name)) { + print_ascii(out, ri->name, 16, 0); + } else { + fprintf(out, "-"); + } + fprintf(out, "\n"); +} + +static void print_intro(FILE *out, int verbose) +{ + general_settings_t *gs = GET_SETTINGS(); + + if (verbose) + fprintf(out, "\n# Text displayed when the radio powers up.\n"); + fprintf(out, "Intro Line 1: "); + if (VALID_TEXT(gs->intro_line1)) { + print_ascii(out, gs->intro_line1, 14, 0); + } else { + fprintf(out, "-"); + } + fprintf(out, "\nIntro Line 2: "); + if (VALID_TEXT(gs->intro_line2)) { + print_ascii(out, gs->intro_line2, 14, 0); + } else { + fprintf(out, "-"); + } + fprintf(out, "\n"); +} + +// +// Get channel bank by index. +// +static channel_t *get_bank(int i) +{ + return (channel_t*) &radio_mem[OFFSET_BANK1 + i*0x2000]; +} + +// +// Get channel by index. +// +static channel_t *get_channel(int i) +{ + channel_t *bank = get_bank(i >> 7); + uint8_t *bitmap = &radio_mem[OFFSET_CHAN_MAP]; + + if ((bitmap[i / 8] >> (i & 7)) & 1) + return &bank[i % 128]; + else + return 0; +} + +// +// Do we have any channels of given mode? +// +static int have_channels(int mode) +{ + int i; + + for (i=0; ichannel_mode == mode) + return 1; + + // Treat D+A mode as digital. + if (mode == MODE_DIGITAL && ch->channel_mode == MODE_D_A) + return 1; + + // Treat A+D mode as analog. + if (mode == MODE_ANALOG && ch->channel_mode == MODE_A_D) + return 1; + } + return 0; +} + +// +// Return true when any contacts are present. +// +static int have_contacts() +{ + uint8_t *cmap = GET_CONTACT_MAP(); + int i; + + for (i=0; i<(NCONTACTS+7)/8; i++) { + if (cmap[i] != 0xff) + return 1; + } + return 0; +} + +// +// Get contact by index. +// +static contact_t *get_contact(int i) +{ + uint8_t *cmap = GET_CONTACT_MAP(); + + if ((cmap[i / 8] >> (i & 7)) & 1) + return 0; + + return GET_CONTACT(i); +} + +// +// Print frequency (BCD value). +// +static void print_rx_freq(FILE *out, unsigned data) +{ + fprintf(out, "%d%d%d.%d%d%d", (data >> 4) & 15, data & 15, + (data >> 12) & 15, (data >> 8) & 15, + (data >> 20) & 15, (data >> 16) & 15); + + if (((data >> 24) & 0xff) == 0) { + fputs(" ", out); + } else { + fprintf(out, "%d", (data >> 28) & 15); + if (((data >> 24) & 15) == 0) { + fputs(" ", out); + } else { + fprintf(out, "%d", (data >> 24) & 15); + } + } +} + +// +// Convert a 4-byte frequency value from binary coded decimal +// to integer format (in Hertz). +// +static int bcd_to_hz(unsigned bcd) +{ + int a = (bcd >> 4) & 15; + int b = bcd & 15; + int c = (bcd >> 12) & 15; + int d = (bcd >> 8) & 15; + int e = (bcd >> 20) & 15; + int f = (bcd >> 16) & 15; + int g = (bcd >> 28) & 15; + int h = (bcd >> 24) & 15; + + return (((((((a*10 + b) * 10 + c) * 10 + d) * 10 + e) * 10 + f) * 10 + g) * 10 + h) * 10; +} + +// +// Print the transmit offset or frequency. +// TX value is a delta. +// +static void print_tx_offset(FILE *out, unsigned tx_offset_bcd, unsigned mode) +{ + int offset; + + switch (mode) { + default: + case RM_SIMPLEX: // TX frequency = RX frequency + fprintf(out, "+0 "); + break; + + case RM_TXPOS: // Positive TX offset + offset = bcd_to_hz(tx_offset_bcd); + fprintf(out, "+"); + print_mhz(out, offset); + break; + + case RM_TXNEG: // Negative TX offset + offset = bcd_to_hz(tx_offset_bcd); + fprintf(out, "-"); + print_mhz(out, offset); + break; + } +} + +// +// Print base parameters of the channel: +// Name +// RX Frequency +// TX Frequency +// Power +// Scan List +// TOT +// RX Only +// +static void print_chan_base(FILE *out, channel_t *ch, int cnum) +{ + fprintf(out, "%5d ", cnum); + print_ascii(out, ch->name, 16, 1); + fprintf(out, " "); + print_rx_freq(out, ch->rx_frequency); + fprintf(out, " "); + print_tx_offset(out, ch->tx_offset, ch->repeater_mode); + + fprintf(out, "%-5s ", POWER_NAME[ch->power]); + + if (ch->scan_list_index == 0xff) + fprintf(out, "- "); + else + fprintf(out, "%-4d ", ch->scan_list_index + 1); + + //TODO +// if (ch->tot == 0) + fprintf(out, "- "); +// else +// fprintf(out, "%-3d ", ch->tot * 15); + + fprintf(out, "%c ", "-+"[ch->rx_only]); +} + +static void print_digital_channels(FILE *out, int verbose) +{ + int i; + + if (verbose) { + fprintf(out, "# Table of digital channels.\n"); + fprintf(out, "# 1) Channel number: 1-%d\n", NCHAN); + fprintf(out, "# 2) Name: up to 16 characters, use '_' instead of space\n"); + fprintf(out, "# 3) Receive frequency in MHz\n"); + fprintf(out, "# 4) Transmit frequency or +/- offset in MHz\n"); + fprintf(out, "# 5) Transmit power: High, Mid, Low, Turbo\n"); + fprintf(out, "# 6) Scan list: - or index in Scanlist table\n"); + fprintf(out, "# 7) Transmit timeout timer: (unused)\n"); + fprintf(out, "# 8) Receive only: -, +\n"); + fprintf(out, "# 9) Admit criteria: -, Free, Color, NColor\n"); + fprintf(out, "# 10) Color code: 0, 1, 2, 3... 15\n"); + fprintf(out, "# 11) Time slot: 1 or 2\n"); + fprintf(out, "# 12) Receive group list: - or index in Grouplist table\n"); + fprintf(out, "# 13) Contact for transmit: - or index in Contacts table\n"); + fprintf(out, "#\n"); + } + fprintf(out, "Digital Name Receive Transmit Power Scan TOT RO Admit Color Slot RxGL TxContact"); + fprintf(out, "\n"); + for (i=0; ichannel_mode != MODE_DIGITAL && ch->channel_mode != MODE_D_A) { + // Select digital channels + continue; + } + print_chan_base(out, ch, i+1); + + // Print digital parameters of the channel: + // Admit Criteria + // Color Code + // Repeater Slot + // Group List + // Contact Name + fprintf(out, "%-6s ", DIGITAL_ADMIT_NAME[ch->tx_permit]); + fprintf(out, "%-5d %-3d ", ch->color_code, 1 + ch->slot2); + + if (ch->group_list_index == 0xff) + fprintf(out, "- "); + else + fprintf(out, "%-4d ", ch->group_list_index + 1); + + if (ch->contact_index == 0xffff) + fprintf(out, "-"); + else + fprintf(out, "%-4d", ch->contact_index + 1); + + // Print contact name as a comment. + if (ch->contact_index != 0xffff) { + contact_t *ct = get_contact(ch->contact_index); + + if (ct) { + fprintf(out, " # "); + print_ascii(out, ct->name, 16, 0); + } + } + fprintf(out, "\n"); + } +} + +// +// Print CTSS tone. +// +static void print_ctcss(FILE *out, unsigned index, unsigned custom) +{ + int dhz = (index < NCTCSS) ? CTCSS_TONES[index] : custom; + unsigned a = dhz / 1000; + unsigned b = (dhz / 100) % 10; + unsigned c = (dhz / 10) % 10; + unsigned d = dhz % 10; + + if (a == 0) + fprintf(out, "%d%d.%d ", b, c, d); + else + fprintf(out, "%d%d%d.%d", a, b, c, d); +} + +// +// Print DCS tone. +// +static void print_dcs(FILE *out, unsigned dcs) +{ + unsigned i = (dcs >> 9) & 1; + unsigned a = (dcs >> 6) & 7; + unsigned b = (dcs >> 3) & 7; + unsigned c = dcs & 7; + + fprintf(out, "D%d%d%d%c", a, b, c, i ? 'I' : 'N'); +} + +static void print_analog_channels(FILE *out, int verbose) +{ + int i; + + if (verbose) { + fprintf(out, "# Table of analog channels.\n"); + fprintf(out, "# 1) Channel number: 1-%d\n", NCHAN); + fprintf(out, "# 2) Name: up to 16 characters, use '_' instead of space\n"); + fprintf(out, "# 3) Receive frequency in MHz\n"); + fprintf(out, "# 4) Transmit frequency or +/- offset in MHz\n"); + fprintf(out, "# 5) Transmit power: High, Mid, Low, Turbo\n"); + fprintf(out, "# 6) Scan list: - or index\n"); + fprintf(out, "# 7) Transmit timeout timer: (unused)\n"); + fprintf(out, "# 8) Receive only: -, +\n"); + fprintf(out, "# 9) Admit criteria: -, Free, Tone\n"); + fprintf(out, "# 10) Squelch level: Normal (unused)\n"); + fprintf(out, "# 11) Guard tone for receive, or '-' to disable\n"); + fprintf(out, "# 12) Guard tone for transmit, or '-' to disable\n"); + fprintf(out, "# 13) Bandwidth in kHz: 12.5, 25\n"); + fprintf(out, "#\n"); + } + fprintf(out, "Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxTone TxTone Width"); + fprintf(out, "\n"); + for (i=0; ichannel_mode != MODE_ANALOG && ch->channel_mode != MODE_A_D) { + // Select analog channels + continue; + } + print_chan_base(out, ch, i+1); + + // Print analog parameters of the channel: + // Admit Criteria + // Squelch + // CTCSS/DCS Dec + // CTCSS/DCS Enc + // Bandwidth + fprintf(out, "%-6s ", ANALOG_ADMIT_NAME[ch->tx_permit]); + fprintf(out, "%-7s ", "Normal"); + + if (ch->rx_ctcss) + print_ctcss(out, ch->ctcss_receive, ch->custom_ctcss); + else if (ch->rx_dcs) + print_dcs(out, ch->dcs_receive); + else + fprintf(out, "- "); + + fprintf(out, " "); + if (ch->tx_ctcss) + print_ctcss(out, ch->ctcss_transmit, ch->custom_ctcss); + else if (ch->tx_dcs) + print_dcs(out, ch->dcs_transmit); + else + fprintf(out, "- "); + + fprintf(out, " %s", BANDWIDTH[ch->bandwidth]); + fprintf(out, "\n"); + } +} + +// +// Return true when any zones are present. +// +static int have_zones() +{ + uint8_t *zmap = GET_ZONEMAP(); + int i; + + for (i=0; i<(NZONES+7)/8; i++) { + if (zmap[i] != 0) + return 1; + } + return 0; +} + +// +// Find a zone with given index. +// Return false when zone is not valid. +// Set zname and zlist to a zone name and member list. +// +static int get_zone(int i, uint8_t **zname, uint16_t **zlist) +{ + uint8_t *zmap = GET_ZONEMAP(); + + if ((zmap[i / 8] >> (i & 7)) & 1) { + // Zone is valid. + *zname = GET_ZONENAME(i); + *zlist = GET_ZONELIST(i); + return 1; + } else { + return 0; + } +} + +static void print_chanlist(FILE *out, uint16_t *unsorted, int nchan) +{ + int last = -1; + int range = 0; + int n; + uint16_t data[nchan]; + + // Sort the list before printing. + memcpy(data, unsorted, nchan * sizeof(uint16_t)); + qsort(data, nchan, sizeof(uint16_t), compare_index_ffff); + for (n=0; n 0) + fprintf(out, ","); + fprintf(out, "%d", cnum); + } + last = cnum; + } + if (range) + fprintf(out, "-%d", last); +} + +// +// Print full information about the device configuration. +// +static void d868uv_print_config(radio_device_t *radio, FILE *out, int verbose) +{ + int i; + + fprintf(out, "Radio: %s\n", radio->name); + if (verbose) + d868uv_print_version(radio, out); + + // + // Channels. + // + if (have_channels(MODE_DIGITAL)) { + fprintf(out, "\n"); + print_digital_channels(out, verbose); + } + if (have_channels(MODE_ANALOG)) { + fprintf(out, "\n"); + print_analog_channels(out, verbose); + } + + // + // Zones. + // + if (have_zones()) { + fprintf(out, "\n"); + if (verbose) { + fprintf(out, "# Table of channel zones.\n"); + fprintf(out, "# 1) Zone number: 1-%d\n", NZONES); + fprintf(out, "# 2) Name: up to 16 characters, use '_' instead of space\n"); + fprintf(out, "# 3) List of channels: numbers and ranges (N-M) separated by comma\n"); + fprintf(out, "#\n"); + } + fprintf(out, "Zone Name Channels\n"); + for (i=0; iname, 16, 1); + fprintf(out, " %-7s %-8d %s\n", CONTACT_TYPE[ct->type & 3], + CONTACT_ID(ct), ALERT_TYPE[ct->call_alert & 3]); + } + } + + // + // Group lists. + // + //TODO + + // + // Text messages. + // + //TODO + + // General settings. + print_id(out, verbose); + print_intro(out, verbose); +} + +// +// Read memory image from the binary file. +// +static void d868uv_read_image(radio_device_t *radio, FILE *img) +{ + struct stat st; + + // Guess device type by file size. + if (fstat(fileno(img), &st) < 0) { + fprintf(stderr, "Cannot get file size.\n"); + exit(-1); + } + switch (st.st_size) { + case MEMSZ: + // IMG file. + if (fread(&radio_mem[0], 1, MEMSZ, img) != MEMSZ) { + fprintf(stderr, "Error reading image data.\n"); + exit(-1); + } + break; + default: + fprintf(stderr, "Unrecognized file size %u bytes.\n", (int) st.st_size); + exit(-1); + } +} + +// +// Save memory image to the binary file. +// +static void d868uv_save_image(radio_device_t *radio, FILE *img) +{ + fwrite(&radio_mem[0], 1, MEMSZ, img); +} + +// +// Parse the scalar parameter. +// +static void d868uv_parse_parameter(radio_device_t *radio, char *param, char *value) +{ + if (strcasecmp("Radio", param) == 0) { + if (!radio_is_compatible(value)) { + fprintf(stderr, "Incompatible model: %s\n", value); + exit(-1); + } + return; + } + + radioid_t *ri = GET_RADIOID(); + if (strcasecmp ("Name", param) == 0) { + ascii_decode(ri->name, value, 16, 0); + return; + } + if (strcasecmp ("ID", param) == 0) { + uint32_t id = strtoul(value, 0, 0); + ri->id[0] = ((id / 10000000) << 4) | ((id / 1000000) % 10); + ri->id[1] = ((id / 100000 % 10) << 4) | ((id / 10000) % 10); + ri->id[2] = ((id / 1000 % 10) << 4) | ((id / 100) % 10); + ri->id[3] = ((id / 10 % 10) << 4) | (id % 10); + return; + } + + general_settings_t *gs = GET_SETTINGS(); + if (strcasecmp ("Intro Line 1", param) == 0) { + ascii_decode_uppercase(gs->intro_line1, value, 14, 0); + gs->power_on = PWON_CUST_CHAR; + return; + } + if (strcasecmp ("Intro Line 2", param) == 0) { + ascii_decode_uppercase(gs->intro_line2, value, 14, 0); + gs->power_on = PWON_CUST_CHAR; + return; + } + fprintf(stderr, "Unknown parameter: %s = %s\n", param, value); + exit(-1); +} + +// +// Parse table header. +// Return table id, or 0 in case of error. +// +static int d868uv_parse_header(radio_device_t *radio, char *line) +{ + if (strncasecmp(line, "Digital", 7) == 0) + return 'D'; + if (strncasecmp(line, "Analog", 6) == 0) + return 'A'; + if (strncasecmp(line, "Zone", 4) == 0) + return 'Z'; + if (strncasecmp(line, "Scanlist", 8) == 0) + return 'S'; + if (strncasecmp(line, "Contact", 7) == 0) + return 'C'; + if (strncasecmp(line, "Grouplist", 9) == 0) + return 'G'; + if (strncasecmp(line, "Message", 7) == 0) + return 'M'; + return 0; +} + +// +// Parse one line of table data. +// Return 0 on failure. +// +static int d868uv_parse_row(radio_device_t *radio, int table_id, int first_row, char *line) +{ + //TODO +#if 0 + switch (table_id) { + case 'D': return parse_digital_channel(radio, first_row, line); + case 'A': return parse_analog_channel(radio, first_row, line); + case 'Z': return parse_zones(first_row, line); + case 'S': return parse_scanlist(first_row, line); + case 'C': return parse_contact(first_row, line); + case 'G': return parse_grouplist(first_row, line); + case 'M': return parse_messages(first_row, line); + } +#endif + return 0; +} + +// +// Update timestamp. +// +static void d868uv_update_timestamp(radio_device_t *radio) +{ + // No timestamp. +} + +// +// Check that configuration is correct. +// Return 0 on error. +// +static int d868uv_verify_config(radio_device_t *radio) +{ + //TODO +#if 0 + int i, k, nchannels = 0, nzones = 0, nscanlists = 0, ngrouplists = 0; + int ncontacts = 0, nerrors = 0; + + // Channels: check references to scanlists, contacts and grouplists. + for (i=0; iscan_list_index != 0) { + scanlist_t *sl = GET_SCANLIST(ch->scan_list_index - 1); + + if (!VALID_SCANLIST(sl)) { + fprintf(stderr, "Channel %d '", i+1); + print_ascii(stderr, ch->name, 16, 0); + fprintf(stderr, "': scanlist %d not found.\n", ch->scan_list_index); + nerrors++; + } + } + if (ch->contact_index != 0) { + contact_t *ct = get_contact(ch->contact_index - 1); + + if (!ct) { + fprintf(stderr, "Channel %d '", i+1); + print_ascii(stderr, ch->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", ch->contact_index); + nerrors++; + } + } + if (ch->group_list_index != 0) { + grouplist_t *gl = GET_GROUPLIST(ch->group_list_index - 1); + + if (!VALID_GROUPLIST(gl)) { + fprintf(stderr, "Channel %d '", i+1); + print_ascii(stderr, ch->name, 16, 0); + fprintf(stderr, "': grouplist %d not found.\n", ch->group_list_index); + nerrors++; + } + } + } + + // Zones: check references to channels. + for (i=0; imember[k]; + + if (cnum != 0) { + channel_t *ch = get_channel(cnum - 1); + + if (!ch) { + fprintf(stderr, "Scanlist %d '", i+1); + print_ascii(stderr, sl->name, 16, 0); + fprintf(stderr, "': channel %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Grouplists: check references to contacts. + for (i=0; imember[k]; + + if (cnum != 0) { + contact_t *ct = get_contact(cnum - 1); + + if (!ct) { + fprintf(stderr, "Grouplist %d '", i+1); + print_ascii(stderr, gl->name, 16, 0); + fprintf(stderr, "': contact %d not found.\n", cnum); + nerrors++; + } + } + } + } + + // Count contacts. + for (i=0; i 0) { + fprintf(stderr, "Total %d errors.\n", nerrors); + return 0; + } + fprintf(stderr, "Total %d channels, %d zones, %d scanlists, %d contacts, %d grouplists.\n", + nchannels, nzones, nscanlists, ncontacts, ngrouplists); +#endif + return 1; +} + +// +// TYT MD-UV380 +// +radio_device_t radio_d868uv = { + "Anytone AT-D868UV", + d868uv_download, + d868uv_upload, + d868uv_is_compatible, + d868uv_read_image, + d868uv_save_image, + d868uv_print_version, + d868uv_print_config, + d868uv_verify_config, + d868uv_parse_parameter, + d868uv_parse_header, + d868uv_parse_row, + d868uv_update_timestamp, + //d868uv_write_csv, +}; diff --git a/examples/rd5r-south-bay-area.conf b/examples/rd5r-south-bay-area.conf index ebe0f27..baa6cf1 100644 --- a/examples/rd5r-south-bay-area.conf +++ b/examples/rd5r-south-bay-area.conf @@ -1,167 +1,191 @@ # # Generic DMR configuration for South Bay Area. # -# Schedules (PDT): -# Monday 8-10 pm: PAPA DMR Roundtable, California (3106/TS1) -# Tuesday 8-9 pm: SNARS DMR Net (31328/TS1) -# Wednesday 5:30-6:30 pm: Texas Statewide Net (3148/TS1) -# Thursday 7-7:30 pm: NorCal DMR Net (31068/TS2) -# Thursday 8-10 pm: PAPA Tech Roundtable, XRF012A, analog&D-STAR (31078/TS1) -# Saturday 9-11 am: Worldwide Net (91/TS1) -# Radio: Baofeng RD-5R # Table of digital channels. -# 1) Channel number: 1-1000 +# 1) Channel number: 1-1024 # 2) Name: up to 16 characters, use '_' instead of space # 3) Receive frequency in MHz # 4) Transmit frequency or +/- offset in MHz # 5) Transmit power: High, Low # 6) Scan list: - or index in Scanlist table -# 7) Autoscan flag: -, + -# 8) Transmit timeout timer in seconds: 0, 15, 30, 45... 555 -# 9) Receive only: -, + -# 10) Admit criteria: -, Free, Color -# 11) Color code: 1, 2, 3... 15 -# 12) Time slot: 1 or 2 -# 13) In call criteria: -, Admit, TXInt -# 14) Receive group list: - or index in Grouplist table -# 15) Contact for transmit: - or index in Contacts table +# 7) Transmit timeout timer in seconds: 0, 15, 30, 45... 555 +# 8) Receive only: -, + +# 9) Admit criteria: -, Free, Color +# 10) Color code: 0, 1, 2, 3... 15 +# 11) Time slot: 1 or 2 +# 12) Receive group list: - or index in Grouplist table +# 13) Contact for transmit: - or index in Contacts table # Digital Name Receive Transmit Power Scan TOT RO Admit Color Slot RxGL TxContact # (1) W6TCP, Milpitas, NorCal - 1 Mi_California 440.125 +5 High - 180 - Free 3 1 3 6 # 3106 California Static - 2 Mi_TAC_310 440.125 +5 High - 180 - Free 3 1 3 5 # 310 TAC 310 Dynamic - 3 Mi_Bay-Net 440.125 +5 High - 180 - Free 3 1 3 13 # 31075 Bay-Net Dynamic - 4 Mi_World 440.125 +5 High - 180 - Free 3 1 3 3 # 91 Worldwide Dynamic - 5 Mi_NorCal 440.125 +5 High - 180 - Free 3 2 3 11 # 31068 NorCal Static - 6 Mi_Anarchy 440.125 +5 High - 180 - Free 3 2 3 18 # 31666 DMR of Anarchy Static - 7 Mi_NC_5150 440.125 +5 High - 180 - Free 3 2 3 19 # 95150 NorCal 5150 Static - 8 Mi_Parrot 440.125 +5 High - 180 - Free 3 2 3 24 # 9990 Parrot Private + 1 Mi_RX_All 440.125 +5 Low - 180 + Color 3 1 1 - # Receive only + 2 Mi_World 440.125 +5 High - 180 - Color 3 1 11 91 # 91 Worldwide Dynamic + 3 Mi_North_America 440.125 +5 High - 180 - Color 3 1 12 93 # 93 North America Dynamic + 4 Mi_TAC_310 440.125 +5 High - 180 - Color 3 1 13 10 # 310 TAC 310 Dynamic + 5 Mi_TAC_311 440.125 +5 High - 180 - Color 3 1 14 11 # 311 TAC 311 Dynamic + 6 Mi_USA_Nation 440.125 +5 High - 180 - Color 3 1 15 100 # 3100 USA Nationwide Dynamic + 7 Mi_California 440.125 +5 High - 180 - Color 3 1 16 106 # 3106 California Static + 8 Mi_NorCal 440.125 +5 High - 180 - Color 3 2 19 68 # 31068 NorCal Static + 9 Mi_Bay-Net 440.125 +5 High - 180 - Color 3 1 20 75 # 31075 Bay-Net Dynamic + 10 Mi_Anarchy 440.125 +5 High - 180 - Color 3 2 23 66 # 31666 DMR of Anarchy Static + 11 Mi_NC_5150 440.125 +5 High - 180 - Color 3 2 24 95 # 95150 NorCal 5150 Static + 12 Mi_Parrot 440.125 +5 High - 180 - Color 3 1 - 90 # 9990 Parrot Private # (2) N6AMG, San Bruno, Baycom - 11 Br_North_America 440.500 +5 High - 180 - Free 1 1 3 4 # 93 North America Static - 12 Br_California 440.500 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 13 Br_NC_AllStr 440.500 +5 High - 180 - Free 1 1 3 10 # 31065 NorCal AllStar Static - 14 Br_Bay-Net 440.500 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Static - 15 Br_USA_Area6 440.500 +5 High - 180 - Free 1 1 3 15 # 31096 USA Area 6 Static - 16 Br_TAC_310 440.500 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 17 Br_World 440.500 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 18 Br_Baycom 440.500 +5 High - 180 - Free 1 2 3 20 # 97150 Baycom Static - 19 Br_NorCal 440.500 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Dynamic - 20 Br_Anarchy 440.500 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 21 Br_NC_5150 440.500 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 22 Br_Parrot 440.500 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 21 Br_RX_All 440.500 +5 Low - 180 + Color 1 1 1 - # Receive only + 22 Br_World 440.500 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 23 Br_North_America 440.500 +5 High - 180 - Color 1 1 12 93 # 93 North America Static + 24 Br_TAC_310 440.500 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 25 Br_TAC_311 440.500 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 26 Br_USA_Nation 440.500 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 27 Br_California 440.500 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 28 Br_NC_AllStr 440.500 +5 High - 180 - Color 1 1 18 65 # 31065 NorCal AllStar Static + 29 Br_NorCal 440.500 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Dynamic + 30 Br_Bay-Net 440.500 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Static + 31 Br_USA_Area6 440.500 +5 High - 180 - Color 1 1 22 96 # 31096 USA Area 6 Static + 32 Br_Anarchy 440.500 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 33 Br_NC_5150 440.500 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 34 Br_Baycom 440.500 +5 High - 180 - Color 1 2 25 97 # 97150 Baycom Static + 35 Br_Parrot 440.500 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (3) WB6ECE, Boulder Creek, Baycom - 31 Bo_North_America 440.5875 +5 High - 180 - Free 2 1 3 4 # 93 North America Static - 32 Bo_California 440.5875 +5 High - 180 - Free 2 1 3 6 # 3106 California Static - 33 Bo_Santa_Clara 440.5875 +5 High - 180 - Free 2 1 3 9 # 31064 Santa Clara County Static - 34 Bo_NC_AllStr 440.5875 +5 High - 180 - Free 2 1 3 10 # 31065 NorCal AllStar Static - 35 Bo_Bay-Net 440.5875 +5 High - 180 - Free 2 1 3 13 # 31075 Bay-Net Static - 36 Bo_USA_Area6 440.5875 +5 High - 180 - Free 2 1 3 15 # 31096 USA Area 6 Static - 37 Bo_TAC_310 440.5875 +5 High - 180 - Free 2 1 3 5 # 310 TAC 310 Dynamic - 38 Bo_World 440.5875 +5 High - 180 - Free 2 1 3 3 # 91 Worldwide Dynamic - 39 Bo_Baycom 440.5875 +5 High - 180 - Free 2 2 3 20 # 97150 Baycom Static - 40 Bo_NorCal 440.5875 +5 High - 180 - Free 2 2 3 11 # 31068 NorCal Dynamic - 41 Bo_Anarchy 440.5875 +5 High - 180 - Free 2 2 3 18 # 31666 DMR of Anarchy Dynamic - 42 Bo_NC_5150 440.5875 +5 High - 180 - Free 2 2 3 19 # 95150 NorCal 5150 Dynamic - 43 Bo_Parrot 440.5875 +5 High - 180 - Free 2 2 3 24 # 9990 Parrot Private + 41 Bo_RX_All 440.5875 +5 Low - 180 + Color 2 1 1 - # Receive only + 42 Bo_World 440.5875 +5 High - 180 - Color 2 1 11 91 # 91 Worldwide Dynamic + 43 Bo_North_America 440.5875 +5 High - 180 - Color 2 1 12 93 # 93 North America Static + 44 Bo_TAC_310 440.5875 +5 High - 180 - Color 2 1 13 10 # 310 TAC 310 Dynamic + 45 Bo_TAC_311 440.5875 +5 High - 180 - Color 2 1 14 11 # 311 TAC 311 Dynamic + 46 Bo_USA_Nation 440.5875 +5 High - 180 - Color 2 1 15 100 # 3100 USA Nationwide Dynamic + 47 Bo_California 440.5875 +5 High - 180 - Color 2 1 16 106 # 3106 California Static + 48 Bo_Santa_Clara 440.5875 +5 High - 180 - Color 2 1 17 64 # 31064 Santa Clara County Static + 49 Bo_NC_AllStr 440.5875 +5 High - 180 - Color 2 1 18 65 # 31065 NorCal AllStar Static + 50 Bo_NorCal 440.5875 +5 High - 180 - Color 2 2 19 68 # 31068 NorCal Dynamic + 51 Bo_Bay-Net 440.5875 +5 High - 180 - Color 2 1 20 75 # 31075 Bay-Net Static + 52 Bo_USA_Area6 440.5875 +5 High - 180 - Color 2 1 22 96 # 31096 USA Area 6 Static + 53 Bo_Anarchy 440.5875 +5 High - 180 - Color 2 2 23 66 # 31666 DMR of Anarchy Dynamic + 54 Bo_NC_5150 440.5875 +5 High - 180 - Color 2 2 24 95 # 95150 NorCal 5150 Dynamic + 55 Bo_Baycom 440.5875 +5 High - 180 - Color 2 2 25 97 # 97150 Baycom Static + 56 Bo_Parrot 440.5875 +5 High - 180 - Color 2 1 - 90 # 9990 Parrot Private # (4) K6OTR, Palo Alto, Baycom - 51 PA_North_America 441.850 +5 High - 180 - Free 1 1 3 4 # 93 North America Static - 52 PA_California 441.850 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 53 PA_NC_AllStr 441.850 +5 High - 180 - Free 1 1 3 10 # 31065 NorCal AllStar Static - 54 PA_Bay-Net 441.850 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Static - 55 PA_USA_Area6 441.850 +5 High - 180 - Free 1 1 3 15 # 31096 USA - Area 6 4646 Static - 56 PA_TAC_310 441.850 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 57 PA_World 441.850 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 58 PA_Baycom 441.850 +5 High - 180 - Free 1 2 3 20 # 97150 Baycom Static - 59 PA_NorCal 441.850 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Dynamic - 60 PA_Anarchy 441.850 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 61 PA_NC_5150 441.850 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 62 PA_Parrot 441.850 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 61 PA_RX_All 441.850 +5 Low - 180 + Color 1 1 1 - # Receive only + 62 PA_World 441.850 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 63 PA_North_America 441.850 +5 High - 180 - Color 1 1 12 93 # 93 North America Static + 64 PA_TAC_310 441.850 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 65 PA_TAC_311 441.850 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 66 USA_Nation 441.850 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 67 PA_California 441.850 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 68 PA_NC_AllStr 441.850 +5 High - 180 - Color 1 1 18 65 # 31065 NorCal AllStar Static + 69 PA_NorCal 441.850 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Dynamic + 70 PA_Bay-Net 441.850 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Static + 71 PA_USA_Area6 441.850 +5 High - 180 - Color 1 1 22 96 # 31096 USA - Area 6 4646 Static + 72 PA_Anarchy 441.850 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 73 PA_NC_5150 441.850 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 74 PA_Baycom 441.850 +5 High - 180 - Color 1 2 25 97 # 97150 Baycom Static + 75 PA_Parrot 441.850 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (5) KK6USZ, Saratoga - 71 Sa_Nebraska 441.950 +5 High - 180 - Free 1 1 3 7 # 3131 Nebraska Static - 72 Sa_World 441.950 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 73 Sa_California 441.950 +5 High - 180 - Free 1 1 3 6 # 3106 California Dynamic - 74 Sa_Texas 441.950 +5 High - 180 - Free 1 1 3 8 # 3148 Texas Dynamic - 75 Sa_PAPA 441.950 +5 High - 180 - Free 1 1 3 14 # 31078 XLX013D PAPA Dynamic - 76 Sa_TAC_310 441.950 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 77 Sa_Santa_Clara 441.950 +5 High - 180 - Free 1 2 3 9 # 31064 Santa Clara County Static - 78 Sa_NorCal 441.950 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Static - 79 Sa_Bay-Net 441.950 +5 High - 180 - Free 1 2 3 13 # 31075 Bay-Net Static - 80 Sa_Baycom 441.950 +5 High - 180 - Free 1 2 3 20 # 97150 Baycom Static - 81 Sa_Clst_KK6USZ 441.950 +5 High - 180 - Free 1 2 3 21 # 110670 Cluster KK6USZ Static - 82 Sa_Anarchy 441.950 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 83 Sa_NC_5150 441.950 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 84 Sa_Parrot 441.950 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 81 Sa_RX_All 441.950 +5 Low - 180 + Color 1 1 1 - # Receive only + 82 Sa_World 441.950 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 83 Sa_North_America 441.950 +5 High - 180 - Color 1 1 12 93 # 93 North America Dynamic + 84 Sa_TAC_310 441.950 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 85 Sa_TAC_311 441.950 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 86 Sa_USA_Nation 441.950 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 87 Sa_California 441.950 +5 High - 180 - Color 1 1 16 106 # 3106 California Dynamic + 88 Sa_Nebraska 441.950 +5 High - 180 - Color 1 1 26 131 # 3131 Nebraska Static + 89 Sa_Texas 441.950 +5 High - 180 - Color 1 1 27 148 # 3148 Texas Dynamic + 90 Sa_Santa_Clara 441.950 +5 High - 180 - Color 1 2 17 64 # 31064 Santa Clara County Static + 91 Sa_NorCal 441.950 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Static + 92 Sa_Bay-Net 441.950 +5 High - 180 - Color 1 2 20 75 # 31075 Bay-Net Static + 93 Sa_Anarchy 441.950 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 94 Sa_NC_5150 441.950 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 95 Sa_Baycom 441.950 +5 High - 180 - Color 1 2 25 97 # 97150 Baycom Static + 96 Sa_Parrot 441.950 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (6) WA6YCZ, Mt Umunhum, Baycom - 91 Um_North_America 442.5375 +5 High - 180 - Free 1 1 3 4 # 93 North America Static - 92 Um_California 442.5375 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 93 Um_Santa_Clara 442.5375 +5 High - 180 - Free 1 1 3 9 # 31064 Santa Clara County Static - 94 Um_NC_AllStr 442.5375 +5 High - 180 - Free 1 1 3 10 # 31065 NorCal AllStar Static - 95 Um_Bay-Net 442.5375 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Static - 96 Um_USA_Area6 442.5375 +5 High - 180 - Free 1 1 3 15 # 31096 USA Area 6 Static - 97 Um_TAC_310 442.5375 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 98 Um_World 442.5375 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 99 Um_Baycom 442.5375 +5 High - 180 - Free 1 2 3 20 # 97150 Baycom Static - 100 Um_NorCal 442.5375 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Dynamic - 101 Um_Anarchy 442.5375 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 102 Um_NC_5150 442.5375 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 103 Um_Parrot 442.5375 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 101 Um_RX_All 442.5375 +5 Low - 180 + Color 1 1 1 - # Receive only + 102 Um_World 442.5375 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 103 Um_North_America 442.5375 +5 High - 180 - Color 1 1 12 93 # 93 North America Static + 104 Um_TAC_310 442.5375 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 105 Um_TAC_311 442.5375 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 106 Um_USA_Nation 442.5375 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 107 Um_California 442.5375 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 108 Um_Santa_Clara 442.5375 +5 High - 180 - Color 1 1 17 64 # 31064 Santa Clara County Static + 109 Um_NC_AllStr 442.5375 +5 High - 180 - Color 1 1 18 65 # 31065 NorCal AllStar Static + 110 Um_NorCal 442.5375 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Dynamic + 111 Um_Bay-Net 442.5375 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Static + 112 Um_USA_Area6 442.5375 +5 High - 180 - Color 1 1 22 96 # 31096 USA Area 6 Static + 113 Um_Anarchy 442.5375 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 114 Um_NC_5150 442.5375 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 115 Um_Baycom 442.5375 +5 High - 180 - Color 1 2 25 97 # 97150 Baycom Static + 116 Um_Parrot 442.5375 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (7) K6LNK, Berkeley, NorCal, Carla - 101 Be_California 443.500 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 102 Be_KPARN 443.500 +5 High - 180 - Free 1 1 3 12 # 31072 KPARN Static - 103 Be_SNARS 443.500 +5 High - 180 - Free 1 1 3 16 # 31328 SNARS (Reno/Tahoe) Static - 104 Be_SNARS_2 443.500 +5 High - 180 - Free 1 1 3 17 # 31329 SNARS 2 Static - 105 Be_Clst_K6LNK 443.500 +5 High - 180 - Free 1 1 3 2 # 23 Cluster K6LNK Static - 106 Be_TAC_310 443.500 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 107 Be_Bay-Net 443.500 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Dynamic - 108 Be_World 443.500 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 109 Be_NorCal 443.500 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Static - 110 Be_CARLA 443.500 +5 High - 180 - Free 1 2 3 22 # 310604 CARLA Static - 111 Be_Tri-LERT 443.500 +5 High - 180 - Free 1 2 3 23 # 310703 Tri-LERT Static - 112 Be_Clst_CARLA 443.500 +5 High - 180 - Free 1 2 3 1 # 21 Cluster CARLA Static - 113 Be_Anarchy 443.500 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 114 Be_NC_5150 443.500 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 115 Be_Parrot 443.500 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 121 Be_RX_All 443.500 +5 Low - 180 + Color 1 1 1 - # Receive only + 122 Be_World 443.500 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 123 Be_North_America 443.500 +5 High - 180 - Color 1 1 12 93 # 93 North America Dynamic + 124 Be_TAC_310 443.500 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 125 Be_TAC_311 443.500 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 126 Be_USA_Nation 443.500 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 127 Be_California 443.500 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 128 Be_NorCal 443.500 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Static + 129 Be_Bay-Net 443.500 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Dynamic + 130 Be_Anarchy 443.500 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 131 Be_NC_5150 443.500 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 132 Be_Parrot 443.500 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (8) K6HLE, Loma Prieta, NorCal, AREA - 121 Lo_North_America 444.025 +5 High - 180 - Free 1 1 3 4 # 93 North America Static - 122 Lo_California 444.025 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 123 Lo_USA_Area_6 444.025 +5 High - 180 - Free 1 1 3 15 # 31096 USA - Area 6 4646 Static - 124 Lo_TAC_310 444.025 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 125 Lo_Bay-Net 444.025 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Dynamic - 126 Lo_World 444.025 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 127 Lo_NorCal 444.025 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Static - 128 Lo_Anarchy 444.025 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 129 Lo_NC_5150 444.025 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 130 Lo_Parrot 444.025 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 141 Lo_RX_All 444.025 +5 Low - 180 + Color 1 1 1 - # Receive only + 142 Lo_World 444.025 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 143 Lo_North_America 444.025 +5 High - 180 - Color 1 1 12 93 # 93 North America Static + 144 Lo_TAC_310 444.025 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 145 Lo_TAC_311 444.025 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 146 Lo_USA_Nation 444.025 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 147 Lo_California 444.025 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 148 Lo_NorCal 444.025 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Static + 149 Lo_Bay-Net 444.025 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Dynamic + 150 Lo_USA_Area6 444.025 +5 High - 180 - Color 1 1 22 96 # 31096 USA - Area 6 4646 Static + 151 Lo_Anarchy 444.025 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 152 Lo_NC_5150 444.025 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 153 Lo_Parrot 444.025 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (9) WW6BAY, Palo Alto, Bay-Net - 141 Bay_Santa_Clara 444.350 +5 High - 180 - Free 1 1 3 9 # 31064 Santa Clara County Static - 142 Bay_TAC_310 444.350 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 143 Bay_World 444.350 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 144 Bay_Bay-Net 444.350 +5 High - 180 - Free 1 2 3 13 # 31075 Bay-Net Static - 145 Bay_NorCal 444.350 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Dynamic - 146 Bay_Anarchy 444.350 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 147 Bay_NC_5150 444.350 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 148 Bay_Parrot 444.350 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 161 Bay_RX_All 444.350 +5 Low - 180 + Color 1 1 1 - # Receive only + 162 Bay_World 444.350 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 163 Bay_North_Am 444.350 +5 High - 180 - Color 1 1 12 93 # 93 North America Dynamic + 164 Bay_TAC_310 444.350 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 165 Bay_TAC_311 444.350 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 166 Bay_USA_Nation 444.350 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 167 Bay_Santa_Clara 444.350 +5 High - 180 - Color 1 1 17 64 # 31064 Santa Clara County Static + 168 Bay_NorCal 444.350 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Dynamic + 169 Bay_Bay-Net 444.350 +5 High - 180 - Color 1 2 20 75 # 31075 Bay-Net Static + 170 Bay_Anarchy 444.350 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 171 Bay_NC_5150 444.350 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 172 Bay_Parrot 444.350 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private # (10) W6OTX, Alum Rock, NorCal, PAARA - 151 Al_California 444.475 +5 High - 180 - Free 1 1 3 6 # 3106 California Static - 152 Al_TAC_310 444.475 +5 High - 180 - Free 1 1 3 5 # 310 TAC 310 Dynamic - 153 Al_Bay-Net 444.475 +5 High - 180 - Free 1 1 3 13 # 31075 Bay-Net Dynamic - 154 Al_World 444.475 +5 High - 180 - Free 1 1 3 3 # 91 Worldwide Dynamic - 155 Al_NorCal 444.475 +5 High - 180 - Free 1 2 3 11 # 31068 NorCal Static - 156 Al_Anarchy 444.475 +5 High - 180 - Free 1 2 3 18 # 31666 DMR of Anarchy Dynamic - 157 Al_NC_5150 444.475 +5 High - 180 - Free 1 2 3 19 # 95150 NorCal 5150 Dynamic - 158 Al_Parrot 444.475 +5 High - 180 - Free 1 2 3 24 # 9990 Parrot Private + 181 Al_RX_All 444.475 +5 Low - 180 + Color 1 1 1 - # Receive only + 182 Al_World 444.475 +5 High - 180 - Color 1 1 11 91 # 91 Worldwide Dynamic + 183 Al_North_Am 444.475 +5 High - 180 - Color 1 1 12 93 # 93 North America Dynamic + 184 Al_TAC_310 444.475 +5 High - 180 - Color 1 1 13 10 # 310 TAC 310 Dynamic + 185 Al_TAC_311 444.475 +5 High - 180 - Color 1 1 14 11 # 311 TAC 311 Dynamic + 186 Al_USA_Nation 444.475 +5 High - 180 - Color 1 1 15 100 # 3100 USA Nationwide Dynamic + 187 Al_California 444.475 +5 High - 180 - Color 1 1 16 106 # 3106 California Static + 188 Al_NorCal 444.475 +5 High - 180 - Color 1 2 19 68 # 31068 NorCal Static + 189 Al_Bay-Net 444.475 +5 High - 180 - Color 1 1 20 75 # 31075 Bay-Net Dynamic + 190 Al_Anarchy 444.475 +5 High - 180 - Color 1 2 23 66 # 31666 DMR of Anarchy Dynamic + 191 Al_NC_5150 444.475 +5 High - 180 - Color 1 2 24 95 # 95150 NorCal 5150 Dynamic + 192 Al_Parrot 444.475 +5 High - 180 - Color 1 1 - 90 # 9990 Parrot Private + +# (11) DMR simplex + 701 441.0 441.000 +0 High 3 555 - - 1 1 9 99 + 702 446.5 446.500 +0 High 3 555 - - 1 1 9 99 + 703 446.075 446.075 +0 High 3 555 - - 1 1 9 99 + 704 433.45 433.450 +0 High 3 555 - - 1 1 9 99 + 705 145.79 145.790 +0 High 3 555 - - 1 1 9 99 + 706 145.51 145.510 +0 High 3 555 - - 1 1 9 99 # Table of analog channels. # 1) Channel number: 1-1024 @@ -180,7 +204,7 @@ Digital Name Receive Transmit Power Scan TOT RO Admit Color Slot # Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxTone TxTone Width -# VHF Band 144-148 +# (12) VHF Band 144-148 201 Palo_Alto_N6NFI 145.230 -0.6 High 1 180 - Free 1 - 100.0 25 202 Milpitas_W6MLP 145.430 -0.6 High 1 180 - Free 1 - 85.4 25 203 Saratoga_K6SA 146.655 -0.6 High 1 180 - Free 1 - 114.8 25 @@ -194,7 +218,7 @@ Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxT 211 Morgan_Hil_K7DAA 147.330 +0.6 High 1 180 - Free 1 - 103.5 25 212 Los_Gatos_AB6LI 147.945 -0.6 High 1 180 - Free 1 - 156.7 25 -# UHF Band 440-446 +# (13) UHF Band 440-446 301 San_Jose_W6YOP 440.275 +5 High 1 180 - Free 1 - 127.3 25 302 Woodside_N6ZX 440.450 +5 High 1 180 - Free 1 - 107.2 25 303 Campbell_NO1PC 441.025 +5 High 1 180 - Free 1 - 110.9 25 @@ -210,7 +234,7 @@ Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxT 313 San_Jose_K6GOD 444.725 +5 High 1 180 - Free 1 - 162.2 25 314 Los_Gatos_WB6KHP 444.975 +5 High 1 180 - Free 1 - 127.3 25 -# Simplex frequencies +# (14) Simplex frequencies 401 S_446.0 446.000 +0 High 2 180 - Free 1 - - 25 402 S_446.5 446.500 +0 High 2 180 - Free 1 - - 25 403 S_441.0 441.000 +0 High 2 180 - Free 1 - - 25 @@ -220,45 +244,27 @@ Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxT 407 WX_1 162.450 +0 Low - 180 + Free 1 - - 25 408 WX_5 162.550 +0 Low - 180 + Free 1 - - 25 -# FRS/GMRS Band - 501 GMRS-1 462.5625 +0 High 3 300 - Free 1 - - 25 - 502 GMRS-2 462.5875 +0 High 3 300 - Free 1 - - 25 - 503 GMRS-3 462.6125 +0 High 3 300 - Free 1 - - 25 - 504 GMRS-4 462.6375 +0 High 3 300 - Free 1 - - 25 - 505 GMRS-5 462.6625 +0 High 3 300 - Free 1 - - 25 - 506 GMRS-6 462.6875 +0 High 3 300 - Free 1 - - 25 - 507 GMRS-7 462.7125 +0 High 3 300 - Free 1 - - 25 - 508 FRS-8 467.5625 +0 Low 3 300 - Free 1 - - 25 - 509 FRS-9 467.5875 +0 Low 3 300 - Free 1 - - 25 - 510 FRS-10 467.6125 +0 Low 3 300 - Free 1 - - 25 - 511 FRS-11 467.6375 +0 Low 3 300 - Free 1 - - 25 - 512 FRS-12 467.6625 +0 Low 3 300 - Free 1 - - 25 - 513 FRS-13 467.6875 +0 Low 3 300 - Free 1 - - 25 - 514 FRS-14 467.7125 +0 Low 3 300 - Free 1 - - 25 - -# # Table of channel zones. # 1) Zone number: 1-250 # 2) Name: up to 16 characters, use '_' instead of space # 3) List of channels: numbers and ranges (N-M) separated by comma # Zone Name Channels - 1 Milpitas 1-8 # 440.125 W6TCP - 2 San_Bruno 11-22 # 440.500 N6AMG - 3 Boulder_Creek 31-43 # 440.5875 WB6ECE - 4 Palo_Alto 51-62 # 441.850 K6OTR - 5 Saratoga 71-84 # 441.950 KK6USZ - 6 Mt_Umunhum 91-103 # 442.5375 WA6YCZ - 7 Berkeley 101-115 # 443.500 K6LNK - 8 Loma_Prieta 121-130 # 444.025 K6HLE - 9 Baynet_Palo_Alto 141-148 # 444.350 WW6BAY - 10 Alum_Rock 151-158 # 444.475 W6OTX - 11 VHF 201-212 # 144-148 VHF Band - 12 UHF 301-314 # 440-446 UHF Band - 13 Simplex 401-408 # Simplex VHF, UHF - 14 GMRS 501-514 # 462-467 GMRS + 1 Milpitas 1-12 # 440.125 W6TCP + 2 San_Bruno 21-35 # 440.500 N6AMG + 3 Boulder_Creek 41-56 # 440.5875 WB6ECE + 4 Palo_Alto 61-75 # 441.850 K6OTR + 5 Saratoga 81-96 # 441.950 KK6USZ + 6 Mt_Umunhum 101-116 # 442.5375 WA6YCZ + 7 Berkeley 121-132 # 443.500 K6LNK + 8 Loma_Prieta 141-153 # 444.025 K6HLE + 9 Baynet_Palo_Alto 161-172 # 444.350 WW6BAY + 10 Alum_Rock 181-192 # 444.475 W6OTX + 11 DMR_Simplex 701-706 # DMR Simplex: UHF, VHF + 12 VHF 201-212 # 144-148 VHF Band + 13 UHF 301-314 # 440-446 UHF Band + 14 FM_Simplex 401-408 # FM Simplex: VHF, UHF -# # Table of scan lists. # 1) Scan list number: 1-250 # 2) Name: up to 16 characters, use '_' instead of space @@ -269,64 +275,53 @@ Zone Name Channels # Scanlist Name PCh1 PCh2 TxCh Channels 1 Analog - - Last 201-212,301-314 - 2 Simplex - - Last 401-406 - 3 GMRS - - Last 501-514 + 2 FM_Simplex - - Last 401-406 + 3 DMR_Simplex - - Last 701-706 -# # Table of group lists. -# 1) Group list number: 1-250 +# 1) Group list number: 1-64 # 2) Name: up to 16 characters, use '_' instead of space # 3) List of contacts: numbers and ranges (N-M) separated by comma # Grouplist Name Contacts - 1 Timeslot_1 2 # 23 Cluster K6LNK - 1 Timeslot_1 3 # 91 Worldwide - 1 Timeslot_1 4 # 93 North America - 1 Timeslot_1 5 # 310 TAC 310 - 1 Timeslot_1 6 # 3106 California - 1 Timeslot_1 7 # 3131 Nebraska - 1 Timeslot_1 8 # 3148 Texas - 1 Timeslot_1 9 # 31064 Santa Clara County - 1 Timeslot_1 10 # 31065 NorCal AllStar - 1 Timeslot_1 12 # 31072 KPARN - 1 Timeslot_1 13 # 31075 Bay-Net - 1 Timeslot_1 14 # 31078 XLX013D PAPA - 1 Timeslot_1 15 # 31096 USA - Area 6 4646 - 1 Timeslot_1 16 # 31328 SNARS (Reno/Tahoe) - 1 Timeslot_1 17 # 31329 SNARS 2 + 1 All_Groups 91 # 91 Worldwide + 1 All_Groups 93 # 93 North America + 1 All_Groups 10 # 310 TAC 310 + 1 All_Groups 11 # 311 TAC 311 + 1 All_Groups 100 # 3100 USA Nationwide + 1 All_Groups 106 # 3106 California + 1 All_Groups 64 # 31064 Santa Clara County + 1 All_Groups 65 # 31065 NorCal AllStar + 1 All_Groups 68 # 31068 NorCal + 1 All_Groups 75 # 31075 Bay-Net + 1 All_Groups 78 # 31078 XLX013D PAPA + 1 All_Groups 96 # 31096 USA - Area 6 4646 + 1 All_Groups 66 # 31666 DMR of Anarchy + 1 All_Groups 95 # 95150 NorCal 5150 + 1 All_Groups 97 # 97150 Baycom - 2 Timeslot_2 1 # 21 Cluster CARLA - 2 Timeslot_2 22 # 310604 CARLA - 2 Timeslot_2 21 # 110670 Cluster KK6USZ - 2 Timeslot_2 23 # 310703 Tri-LERT - 2 Timeslot_2 9 # 31064 Santa Clara County - 2 Timeslot_2 11 # 31068 NorCal - 2 Timeslot_2 13 # 31075 Bay-Net - 2 Timeslot_2 18 # 31666 DMR of Anarchy - 2 Timeslot_2 19 # 95150 NorCal 5150 - 2 Timeslot_2 20 # 97150 Baycom + 9 Simplex 99 # 99 Simplex + 11 Worldwide 91 # 91 Worldwide + 12 North_America 93 # 93 North America + 13 TAC_310 10 # 310 TAC 310 + 14 TAC_311 11 # 311 TAC 311 + 15 USA_Nationwide 100 # 3100 USA Nationwide + 16 California 106 # 3106 California + 17 Santa_Clara_Cnty 64 # 31064 Santa Clara County + 18 NorCal_AllStar 65 # 31065 NorCal AllStar + 19 NorCal 68 # 31068 NorCal + 20 Bay-Net 75 # 31075 Bay-Net + 21 XLX013D_PAPA 78 # 31078 XLX013D PAPA + 22 USA_Area_6 96 # 31096 USA - Area 6 4646 + 23 DMR_of_Anarchy 66 # 31666 DMR of Anarchy + 24 NorCal_5150 95 # 95150 NorCal 5150 + 25 Baycom 97 # 97150 Baycom + 26 Nebraska 131 # 3131 Nebraska + 27 Texas 148 # 3148 Texas - 3 Both 3 # 91 Worldwide - 3 Both 4 # 93 North America - 3 Both 5 # 310 TAC 310 - 3 Both 6 # 3106 California - 3 Both 7 # 3131 Nebraska - 3 Both 8 # 3148 Texas - 3 Both 9 # 31064 Santa Clara County - 3 Both 10 # 31065 NorCal AllStar - 3 Both 11 # 31068 NorCal - 3 Both 13 # 31075 Bay-Net - 3 Both 14 # 31078 XLX013D PAPA - 3 Both 15 # 31096 USA - Area 6 4646 - 3 Both 18 # 31666 DMR of Anarchy - 3 Both 19 # 95150 NorCal 5150 - 3 Both 20 # 97150 Baycom - 3 Both 22 # 310604 CARLA - -# # Table of contacts. -# 1) Contact number: 1-10000 +# 1) Contact number: 1-256 # 2) Name: up to 16 characters, use '_' instead of space # 3) Call type: Group, Private, All # 4) Call ID: 1...16777215 @@ -335,29 +330,40 @@ Grouplist Name Contacts Contact Name Type ID RxTone # From all Bay Area repeaters - 1 Cluster_CARLA Group 21 - - 2 Cluster_K6LNK Group 23 - - 3 Worldwide Group 91 - - 4 North_America Group 93 - - 5 TAC_310 Group 310 - - 6 California Group 3106 - - 7 Nebraska Group 3131 - - 8 Texas Group 3148 - - 9 Santa_Clara_Cnty Group 31064 - - 10 NorCal_AllStar Group 31065 - - 11 NorCal Group 31068 - - 12 KPARN Group 31072 - - 13 Bay-Net Group 31075 - - 14 XLX013D_PAPA Group 31078 - - 15 USA_Area_6 Group 31096 - - 16 SNARS Group 31328 - - 17 SNARS_2 Group 31329 - - 18 DMR_of_Anarchy Group 31666 - - 19 NorCal_5150 Group 95150 - - 20 Baycom Group 97150 - - 21 Cluster_KK6USZ Group 110670 - - 22 CARLA Group 310604 - - 23 Tri-LERT Group 310703 - + 91 Worldwide Group 91 - + 93 North_America Group 93 - + 99 Simplex Group 99 - + 10 TAC_310 Group 310 - + 11 TAC_311 Group 311 - + 100 USA_Nationwide Group 3100 - + 106 California Group 3106 - + 131 Nebraska Group 3131 - + 148 Texas Group 3148 - + 64 Santa_Clara_Cnty Group 31064 - + 65 NorCal_AllStar Group 31065 - + 68 NorCal Group 31068 - + 72 KPARN Group 31072 - + 75 Bay-Net Group 31075 - + 78 XLX013D_PAPA Group 31078 - + 96 USA_Area_6 Group 31096 - + 28 SNARS Group 31328 - + 29 SNARS_2 Group 31329 - + 66 DMR_of_Anarchy Group 31666 - + 95 NorCal_5150 Group 95150 - + 97 Baycom Group 97150 - # Private - 24 Parrot Private 9990 - + 90 Parrot Private 9990 - + 42 Sergey_KK6ABQ Private 3114542 + # Sergey Vakulenko + +# Table of text messages. +# 1) Message number: 1-32 +# 2) Text: up to 144 characters +# +Message Text + 1 Hi there! + 2 QSY Norcal 31068, pls + 3 QSY California 3106, pls + 4 Be Right Back + 5 My email is callsign@arrl.net + 6 73 . . . diff --git a/gd77.c b/gd77.c index b401727..93b130b 100644 --- a/gd77.c +++ b/gd77.c @@ -419,7 +419,7 @@ static void setup_zone(int index, const char *name) zonetab_t *zt = GET_ZONETAB(); zone_t *z = &zt->zone[index]; - ascii_decode(z->name, name, sizeof(z->name)); + ascii_decode(z->name, name, sizeof(z->name), 0xff); memset(z->member, 0, sizeof(z->member)); // Set valid bit. @@ -483,7 +483,7 @@ static void setup_scanlist(int index, const char *name, scanlist_t *sl = &st->scanlist[index]; memset(sl, 0, 88); - ascii_decode(sl->name, name, sizeof(sl->name)); + ascii_decode(sl->name, name, sizeof(sl->name), 0xff); sl->priority_ch1 = prio1; sl->priority_ch2 = prio2; @@ -571,7 +571,7 @@ static void setup_contact(int index, const char *name, int type, int id, int rxt ct->ring_style = 0; // TODO ct->_unused23 = (type < CALL_ALL) ? 0 : 0xff; - ascii_decode(ct->name, name, 16); + ascii_decode(ct->name, name, 16, 0xff); } // @@ -593,7 +593,7 @@ static void setup_grouplist(int index, const char *name) grouptab_t *gt = GET_GROUPTAB(); grouplist_t *gl = >->grouplist[index]; - ascii_decode(gl->name, name, sizeof(gl->name)); + ascii_decode(gl->name, name, sizeof(gl->name), 0xff); // Enable grouplist. gt->nitems1[index] = 1; @@ -712,7 +712,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ ch->ctcss_dcs_receive = rxtone; ch->ctcss_dcs_transmit = txtone; - ascii_decode(ch->name, name, sizeof(ch->name)); + ascii_decode(ch->name, name, sizeof(ch->name), 0xff); // Set valid bit. b->bitmap[i % 128 / 8] |= 1 << (i & 7); @@ -1475,7 +1475,7 @@ static void gd77_parse_parameter(radio_device_t *radio, char *param, char *value general_settings_t *gs = GET_SETTINGS(); if (strcasecmp ("Name", param) == 0) { - ascii_decode(gs->radio_name, value, 8); + ascii_decode(gs->radio_name, value, 8, 0xff); return; } if (strcasecmp ("ID", param) == 0) { @@ -1497,11 +1497,11 @@ static void gd77_parse_parameter(radio_device_t *radio, char *param, char *value intro_text_t *it = GET_INTRO(); if (strcasecmp ("Intro Line 1", param) == 0) { - ascii_decode(it->intro_line1, value, 16); + ascii_decode(it->intro_line1, value, 16, 0xff); return; } if (strcasecmp ("Intro Line 2", param) == 0) { - ascii_decode(it->intro_line2, value, 16); + ascii_decode(it->intro_line2, value, 16, 0xff); return; } fprintf(stderr, "Unknown parameter: %s = %s\n", param, value); diff --git a/main.c b/main.c index 9357024..6c43b6a 100644 --- a/main.c +++ b/main.c @@ -39,29 +39,29 @@ extern int optind; void usage() { - fprintf(stderr, _("DMR Config, Version %s, %s\n"), version, copyright); - fprintf(stderr, _("Usage:\n")); - fprintf(stderr, _(" dmrconfig -r [-t]\n")); - fprintf(stderr, _(" Read codeplug from the radio to a file 'device.img'.\n")); - fprintf(stderr, _(" Save configuration to a text file 'device.conf'.\n")); - fprintf(stderr, _(" dmrconfig -w [-t] file.img\n")); - fprintf(stderr, _(" Write codeplug to the radio.\n")); - fprintf(stderr, _(" dmrconfig -c [-t] file.conf\n")); - fprintf(stderr, _(" Apply configuration script to the radio.\n")); - fprintf(stderr, _(" dmrconfig -c file.img file.conf\n")); - fprintf(stderr, _(" Apply configuration script to the codeplug image.\n")); - fprintf(stderr, _(" Store modified copy to a file 'device.img'.\n")); - fprintf(stderr, _(" dmrconfig file.img\n")); - fprintf(stderr, _(" Display configuration from the codeplug image.\n")); - fprintf(stderr, _(" dmrconfig -u [-t] file.csv\n")); - fprintf(stderr, _(" Update contacts database from CSV file.\n")); - fprintf(stderr, _("Options:\n")); - fprintf(stderr, _(" -r Read codeplug from the radio.\n")); - fprintf(stderr, _(" -w Write codeplug to the radio.\n")); - fprintf(stderr, _(" -c Configure the radio from a text script.\n")); - fprintf(stderr, _(" -u Update contacts database.\n")); - fprintf(stderr, _(" -l List all supported radios.\n")); - fprintf(stderr, _(" -t Trace USB protocol.\n")); + fprintf(stderr, "DMR Config, Version %s, %s\n", version, copyright); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, " dmrconfig -r [-t]\n"); + fprintf(stderr, " Read codeplug from the radio to a file 'device.img'.\n"); + fprintf(stderr, " Save configuration to a text file 'device.conf'.\n"); + fprintf(stderr, " dmrconfig -w [-t] file.img\n"); + fprintf(stderr, " Write codeplug to the radio.\n"); + fprintf(stderr, " dmrconfig -c [-t] file.conf\n"); + fprintf(stderr, " Apply configuration script to the radio.\n"); + fprintf(stderr, " dmrconfig -c file.img file.conf\n"); + fprintf(stderr, " Apply configuration script to the codeplug image.\n"); + fprintf(stderr, " Store modified copy to a file 'device.img'.\n"); + fprintf(stderr, " dmrconfig file.img\n"); + fprintf(stderr, " Display configuration from the codeplug image.\n"); + fprintf(stderr, " dmrconfig -u [-t] file.csv\n"); + fprintf(stderr, " Update contacts database from CSV file.\n"); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -r Read codeplug from the radio.\n"); + fprintf(stderr, " -w Write codeplug to the radio.\n"); + fprintf(stderr, " -c Configure the radio from a text script.\n"); + fprintf(stderr, " -u Update contacts database.\n"); + fprintf(stderr, " -l List all supported radios.\n"); + fprintf(stderr, " -t Trace USB protocol.\n"); exit(-1); } @@ -70,18 +70,7 @@ int main(int argc, char **argv) int read_flag = 0, write_flag = 0, config_flag = 0, csv_flag = 0; int list_flag = 0; - // Set locale and message catalogs. - setlocale(LC_ALL, ""); -#ifdef MINGW32 - // Files with localized messages should be placed in - // in c:/Program Files/dmrconfig/ directory. - bindtextdomain("dmrconfig", "c:/Program Files/dmrconfig"); -#else - bindtextdomain("dmrconfig", "/usr/local/share/locale"); -#endif - textdomain("dmrconfig"); - - copyright = _("Copyright (C) 2018 Serge Vakulenko KK6ABQ"); + copyright = "Copyright (C) 2018 Serge Vakulenko KK6ABQ"; trace_flag = 0; for (;;) { switch (getopt(argc, argv, "tcwrul")) { diff --git a/md380.c b/md380.c index a9d46fe..f6ae98d 100644 --- a/md380.c +++ b/md380.c @@ -402,7 +402,7 @@ static void md380_upload(radio_device_t *radio, int cont_flag) // static int md380_is_compatible(radio_device_t *radio) { - return 1; + return strncmp("D868UVE", (char*)&radio_mem[0], 7) == 0; } // @@ -948,9 +948,9 @@ static void print_analog_channels(FILE *out, int verbose) fprintf(out, "# 13) Bandwidth in kHz: 12.5, 20, 25\n"); fprintf(out, "#\n"); } - fprintf(out, "Analog Name Receive Transmit Power Scan AS TOT RO Admit Squelch RxTone TxTone Width"); + fprintf(out, "Analog Name Receive Transmit Power Scan TOT RO Admit Squelch RxTone TxTone Width"); #ifdef PRINT_RARE_PARAMS - fprintf(out, " Dly RxRef TxRef LW VOX TA RxSign TxSign ID"); + fprintf(out, " AS Dly RxRef TxRef LW VOX TA RxSign TxSign ID"); #endif fprintf(out, "\n"); for (i=0; i<:", &radio_rt27d }, // Radtel RT-27D - { "BF-5R", &radio_rd5r }, // Baofeng RD-5R - { "MD-760P", &radio_gd77 }, // Radioddity GD-77, version 3.1.1 and later { 0, 0 } }; -unsigned char radio_mem [1024*1024]; // Radio memory contents, up to 1Mbyte +unsigned char radio_mem [1024*1024*67]; // Radio memory contents, up to 67 Mbytes int radio_progress; // Read/write progress counter static radio_device_t *device; // Device-dependent interface @@ -68,6 +69,7 @@ void radio_disconnect() dfu_reboot(); dfu_close(); hid_close(); + serial_close(); } // @@ -89,10 +91,15 @@ void radio_connect() // Try TYT MD family. ident = dfu_init(0x0483, 0xdf11); if (! ident) { - // Try RD-5R. + // Try RD-5R and GD-77. if (hid_init(0x15a2, 0x0073) >= 0) ident = hid_identify(); } + if (! ident) { + // Try AT-D868UV. + if (serial_init(0x28e9, 0x018a) >= 0) + ident = serial_identify(); + } if (! ident) { fprintf(stderr, "No radio detected.\n"); fprintf(stderr, "Check your USB cable!\n"); @@ -193,6 +200,9 @@ void radio_read_image(const char *filename) case 262709: device = &radio_md380; break; + case 1607296: + device = &radio_d868uv; + break; case 131072: if (fread(ident, 1, 8, img) != 8) { fprintf(stderr, "%s: Cannot read header.\n", filename); diff --git a/radio.h b/radio.h index b7dabe7..99f8582 100644 --- a/radio.h +++ b/radio.h @@ -124,6 +124,7 @@ extern radio_device_t radio_dp880; // Zastone DP880 extern radio_device_t radio_rt27d; // Radtel RT-27D extern radio_device_t radio_rd5r; // Baofeng RD-5R extern radio_device_t radio_gd77; // Radioddity GD-77, version 3.1.1 and later +extern radio_device_t radio_d868uv; // Anytone AT-D868UV // // Radio: memory contents. diff --git a/rd5r.c b/rd5r.c index e1cc553..9c670f0 100644 --- a/rd5r.c +++ b/rd5r.c @@ -419,7 +419,7 @@ static void setup_zone(int index, const char *name) zonetab_t *zt = GET_ZONETAB(); zone_t *z = &zt->zone[index]; - ascii_decode(z->name, name, sizeof(z->name)); + ascii_decode(z->name, name, sizeof(z->name), 0xff); memset(z->member, 0, sizeof(z->member)); // Set valid bit. @@ -483,7 +483,7 @@ static void setup_scanlist(int index, const char *name, scanlist_t *sl = &st->scanlist[index]; memset(sl, 0, 88); - ascii_decode(sl->name, name, sizeof(sl->name)); + ascii_decode(sl->name, name, sizeof(sl->name), 0xff); sl->priority_ch1 = prio1; sl->priority_ch2 = prio2; @@ -571,7 +571,7 @@ static void setup_contact(int index, const char *name, int type, int id, int rxt ct->ring_style = 0; // TODO ct->_unused23 = (type < CALL_ALL) ? 0 : 0xff; - ascii_decode(ct->name, name, 16); + ascii_decode(ct->name, name, 16, 0xff); } // @@ -593,7 +593,7 @@ static void setup_grouplist(int index, const char *name) grouptab_t *gt = GET_GROUPTAB(); grouplist_t *gl = >->grouplist[index]; - ascii_decode(gl->name, name, sizeof(gl->name)); + ascii_decode(gl->name, name, sizeof(gl->name), 0xff); // Enable grouplist. gt->nitems1[index] = 1; @@ -716,7 +716,7 @@ static void setup_channel(int i, int mode, char *name, double rx_mhz, double tx_ ch->ctcss_dcs_receive = rxtone; ch->ctcss_dcs_transmit = txtone; - ascii_decode(ch->name, name, sizeof(ch->name)); + ascii_decode(ch->name, name, sizeof(ch->name), 0xff); // Set valid bit. b->bitmap[i % 128 / 8] |= 1 << (i & 7); @@ -1479,7 +1479,7 @@ static void rd5r_parse_parameter(radio_device_t *radio, char *param, char *value general_settings_t *gs = GET_SETTINGS(); if (strcasecmp ("Name", param) == 0) { - ascii_decode(gs->radio_name, value, 8); + ascii_decode(gs->radio_name, value, 8, 0xff); return; } if (strcasecmp ("ID", param) == 0) { @@ -1501,11 +1501,11 @@ static void rd5r_parse_parameter(radio_device_t *radio, char *param, char *value intro_text_t *it = GET_INTRO(); if (strcasecmp ("Intro Line 1", param) == 0) { - ascii_decode(it->intro_line1, value, 16); + ascii_decode(it->intro_line1, value, 16, 0xff); return; } if (strcasecmp ("Intro Line 2", param) == 0) { - ascii_decode(it->intro_line2, value, 16); + ascii_decode(it->intro_line2, value, 16, 0xff); return; } fprintf(stderr, "Unknown parameter: %s = %s\n", param, value); diff --git a/serial.c b/serial.c new file mode 100644 index 0000000..6141047 --- /dev/null +++ b/serial.c @@ -0,0 +1,725 @@ +/* + * Interface to virtual serial USB port. + * + * Copyright (C) 2018 Serge Vakulenko, KK6ABQ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include "util.h" + +#if defined(__WIN32__) || defined(WIN32) + #include + #include + static void *fd = INVALID_HANDLE_VALUE; + static DCB saved_mode; +#else + #include + static int fd = -1; + static struct termios saved_mode; +#endif + +#ifdef __linux__ +# include +#endif + +#ifdef __APPLE__ +# include +# include +# include +#endif + +static char *dev_path; + +static const unsigned char CMD_PRG[] = "PROGRAM"; +static const unsigned char CMD_PRG2[] = "\2"; +static const unsigned char CMD_QX[] = "QX\6"; +static const unsigned char CMD_ACK[] = "\6"; +static const unsigned char CMD_READ[] = "Raaaan"; +static const unsigned char CMD_WRITE[] = "Waaaan..."; +static const unsigned char CMD_END[] = "END"; + +#if defined(__WIN32__) || defined(WIN32) + // No need for this function. +#else +// +// Encode the speed in bits per second into bit value +// accepted by cfsetspeed() function. +// Return -1 when speed is not supported. +// +static int baud_encode(int bps) +{ + // Linux: only a limited set of values permitted. + switch (bps) { +#ifdef B75 + case 75: return B75; +#endif +#ifdef B110 + case 110: return B110; +#endif +#ifdef B134 + case 134: return B134; +#endif +#ifdef B150 + case 150: return B150; +#endif +#ifdef B200 + case 200: return B200; +#endif +#ifdef B300 + case 300: return B300; +#endif +#ifdef B600 + case 600: return B600; +#endif +#ifdef B1200 + case 1200: return B1200; +#endif +#ifdef B1800 + case 1800: return B1800; +#endif +#ifdef B2400 + case 2400: return B2400; +#endif +#ifdef B4800 + case 4800: return B4800; +#endif +#ifdef B9600 + case 9600: return B9600; +#endif +#ifdef B19200 + case 19200: return B19200; +#endif +#ifdef B38400 + case 38400: return B38400; +#endif +#ifdef B57600 + case 57600: return B57600; +#endif +#ifdef B115200 + case 115200: return B115200; +#endif +#ifdef B230400 + case 230400: return B230400; +#endif +#ifdef B460800 + case 460800: return B460800; +#endif +#ifdef B500000 + case 500000: return B500000; +#endif +#ifdef B576000 + case 576000: return B576000; +#endif +#ifdef B921600 + case 921600: return B921600; +#endif +#ifdef B1000000 + case 1000000: return B1000000; +#endif +#ifdef B1152000 + case 1152000: return B1152000; +#endif +#ifdef B1500000 + case 1500000: return B1500000; +#endif +#ifdef B2000000 + case 2000000: return B2000000; +#endif +#ifdef B2500000 + case 2500000: return B2500000; +#endif +#ifdef B3000000 + case 3000000: return B3000000; +#endif +#ifdef B3500000 + case 3500000: return B3500000; +#endif +#ifdef B4000000 + case 4000000: return B4000000; +#endif + } + return -1; +} +#endif /* WIN32 */ + +// +// Send data to device. +// Return number of bytes, or -1 on error. +// +int serial_write(const unsigned char *data, int len) +{ +#if defined(__WIN32__) || defined(WIN32) + DWORD written; + + if (! WriteFile(fd, data, len, &written, 0)) + return -1; + return written; +#else + return write(fd, data, len); +#endif +} + +// +// Receive data from device. +// Return number of bytes, or -1 on error. +// +int serial_read(unsigned char *data, int len, int timeout_msec) +{ +#if defined(__WIN32__) || defined(WIN32) + DWORD got; + COMMTIMEOUTS ctmo; + + // Reset the Windows RX timeout to the current timeout_msec + // value, as it may have changed since the last read. + // + memset(&ctmo, 0, sizeof(ctmo)); + ctmo.ReadIntervalTimeout = 0; + ctmo.ReadTotalTimeoutMultiplier = 0; + ctmo.ReadTotalTimeoutConstant = timeout_msec; + if (! SetCommTimeouts(fd, &ctmo)) { + fprintf(stderr, "Cannot set timeouts in serial_read()\n"); + return -1; + } + + if (! ReadFile(fd, data, len, &got, 0)) { + fprintf(stderr, "serial_read: read error\n"); + exit(-1); + } +#else + struct timeval timeout, to2; + long got; + fd_set rfds; + + timeout.tv_sec = timeout_msec / 1000; + timeout.tv_usec = timeout_msec % 1000 * 1000; +again: + to2 = timeout; + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + got = select(fd + 1, &rfds, 0, 0, &to2); + if (got < 0) { + if (errno == EINTR || errno == EAGAIN) { + if (trace_flag > 0) + printf("serial_read: retry on select\n"); + goto again; + } + fprintf(stderr, "serial_read: select error: %s\n", strerror(errno)); + exit(-1); + } +#endif + if (got == 0) { + if (trace_flag > 0) + printf("serial_read: no characters to read\n"); + return 0; + } + +#if ! defined(__WIN32__) && ! defined(WIN32) + got = read(fd, data, (len > 1024) ? 1024 : len); + if (got < 0) { + fprintf(stderr, "serial_read: read error\n"); + exit(-1); + } +#endif + return got; +} + +// +// Open the serial port. +// Return -1 on error. +// +int serial_open(const char *devname, int baud_rate) +{ +#if defined(__WIN32__) || defined(WIN32) + DCB new_mode; +#else + struct termios new_mode; +#endif + +#if defined(__WIN32__) || defined(WIN32) + // Check for the Windows device syntax and bend a DOS device + // into that syntax to allow higher COM numbers than 9 + // + if (devname[0] != '\\') { + // Prepend device prefix: COM23 -> \\.\COM23 + char *buf = alloca(5 + strlen(devname)); + if (! buf) { + fprintf(stderr, "%s: Out of memory\n", devname); + return -1; + } + strcpy(buf, "\\\\.\\"); + strcat(buf, devname); + devname = buf; + } + + // Open port + fd = CreateFile(devname, GENERIC_READ | GENERIC_WRITE, + 0, 0, OPEN_EXISTING, 0, 0); + if (fd == INVALID_HANDLE_VALUE) { + fprintf(stderr, "%s: Cannot open\n", devname); + return -1; + } + + // Set serial attributes + memset(&saved_mode, 0, sizeof(saved_mode)); + if (! GetCommState(fd, &saved_mode)) { + fprintf(stderr, "%s: Cannot get state\n", devname); + return -1; + } + + new_mode = saved_mode; + + new_mode.fDtrControl = DTR_CONTROL_ENABLE; + new_mode.BaudRate = baud_rate; + new_mode.ByteSize = 8; + new_mode.StopBits = ONESTOPBIT; + new_mode.Parity = 0; + new_mode.fParity = FALSE; + new_mode.fOutX = FALSE; + new_mode.fInX = FALSE; + new_mode.fOutxCtsFlow = FALSE; + new_mode.fOutxDsrFlow = FALSE; + new_mode.fRtsControl = RTS_CONTROL_ENABLE; + new_mode.fNull = FALSE; + new_mode.fAbortOnError = FALSE; + new_mode.fBinary = TRUE; + if (! SetCommState(fd, &new_mode)) { + fprintf(stderr, "%s: Cannot set state\n", devname); + return -1; + } +#else + // Encode baud rate. + int baud_code = baud_encode(baud_rate); + if (baud_code < 0) { + fprintf(stderr, "%s: Bad baud rate %d\n", devname, baud_rate); + return -1; + } + + // Open port + fd = open(devname, O_RDWR | O_NOCTTY | O_NONBLOCK); + if (fd < 0) { + perror(devname); + return -1; + } + + // Set serial attributes + memset(&saved_mode, 0, sizeof(saved_mode)); + tcgetattr(fd, &saved_mode); + + // 8n1, ignore parity + memset(&new_mode, 0, sizeof(new_mode)); + new_mode.c_cflag = CS8 | CLOCAL | CREAD; + new_mode.c_iflag = IGNBRK; + new_mode.c_oflag = 0; + new_mode.c_lflag = 0; + new_mode.c_cc[VTIME] = 0; + new_mode.c_cc[VMIN] = 1; + cfsetispeed(&new_mode, baud_code); + cfsetospeed(&new_mode, baud_code); + tcflush(fd, TCIFLUSH); + tcsetattr(fd, TCSANOW, &new_mode); + + // Clear O_NONBLOCK flag. + int flags = fcntl(fd, F_GETFL, 0); + if (flags >= 0) + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); +#endif + return 0; +} + +// +// Find a device path by vid/pid. +// +static char *find_path(int vid, int pid) +{ + char *result = 0; + +#if defined(__linux__) + // Create the udev object. + struct udev *udev = udev_new(); + if (! udev) { + printf("Can't create udev\n"); + return 0; + } + + // Create a list of the devices in the 'tty' subsystem. + struct udev_enumerate *enumerate = udev_enumerate_new(udev); + udev_enumerate_add_match_subsystem(enumerate, "tty"); + udev_enumerate_scan_devices(enumerate); + + struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate); + + // For each item enumerated, figure out its information. + struct udev_list_entry *dev_list_entry; + udev_list_entry_foreach(dev_list_entry, devices) { + // Get the filename of the /sys entry for the device + // and create a udev_device object (dev) representing it. + const char *syspath = udev_list_entry_get_name(dev_list_entry); + struct udev_device *comport = udev_device_new_from_syspath(udev, syspath); + //printf("syspath = %s\n", syspath); + + // Get the parent device with the subsystem/devtype pair + // of "usb"/"usb_device". + struct udev_device *parent = udev_device_get_parent_with_subsystem_devtype(comport, + "usb", "usb_device"); + if (! parent) { + //printf("Unable to find parent usb device.\n"); + continue; + } + + // Get the path to the device node in /dev. + const char *devpath = udev_device_get_devnode(comport); + //printf("devpath = %s\n", devpath); + //printf("parent = %s\n", udev_device_get_devnode(parent)); + + const char *idVendor = udev_device_get_sysattr_value(parent, "idVendor"); + const char *idProduct = udev_device_get_sysattr_value(parent, "idProduct"); + if (! idVendor || ! idProduct) { + // No vendor and product ID. + continue; + } + //printf("vid = %s\n", idVendor); + //printf("pid = %s\n", idProduct); + + unsigned vendor_id = strtoul(idVendor, 0, 16); + unsigned product_id = strtoul(idProduct, 0, 16); + if (vendor_id != vid || product_id != pid) { + // Wrong ID. + continue; + } + + // Print names of vendor and product. + //const char *vendor = udev_device_get_sysattr_value(parent, "manufacturer"); + //const char *product = udev_device_get_sysattr_value(parent, "product"); + //printf("vendor = %s\n", vendor); + //printf("product = %s\n", product); + + // Return result. + udev_device_unref(parent); + result = strdup(devpath); + break; + } + + // Free the enumerator object + udev_enumerate_unref(enumerate); + udev_unref(udev); + +#elif defined(__APPLE__) + // Create a list of the devices in the 'IOSerialBSDClient' class. + CFMutableDictionaryRef dict = IOServiceMatching(kIOSerialBSDServiceValue); + if (! dict) { + printf("Cannot create IO Service dictionary.\n"); + return 0; + } + + io_iterator_t devices = IO_OBJECT_NULL; + kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, + dict, &devices); + if (ret != KERN_SUCCESS) { + printf("Cannot find matching IO services.\n"); + return 0; + } + + // For each matching device, print out its information. + io_object_t device; + while ((device = IOIteratorNext(devices)) != MACH_PORT_NULL) { + // Get device path. + char devname[1024]; + CFStringRef ref = (CFStringRef) IORegistryEntrySearchCFProperty(device, + kIOServicePlane, CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, kIORegistryIterateRecursively); + if (! ref || ! CFStringGetCString(ref, devname, sizeof(devname), kCFStringEncodingUTF8)) { + // Cannot get device path. + continue; + } + //printf("%s\n", devname); + + // Get device parent. + io_registry_entry_t parent = 0; + if (KERN_SUCCESS != IORegistryEntryGetParentEntry(device, kIOServicePlane, &parent)) { + //printf("Cannot get device parent.\n"); + continue; + } + + // Get device grandparent. + io_registry_entry_t grandparent = 0; + if (KERN_SUCCESS != IORegistryEntryGetParentEntry(parent, kIOServicePlane, &grandparent)) { + //printf("Cannot get device grandparent.\n"); + continue; + } + + // Get vendor ID. + int vendor_id; + ref = IORegistryEntryCreateCFProperty(grandparent, + CFSTR(kUSBVendorID), kCFAllocatorDefault, 0); + if (! ref || ! CFNumberGetValue((CFNumberRef)ref, kCFNumberIntType, &vendor_id)) { + //printf("Cannot get vendor ID.\n"); + continue; + } + + // Get product ID. + int product_id; + ref = IORegistryEntryCreateCFProperty(grandparent, + CFSTR(kUSBProductID), kCFAllocatorDefault, 0); + if (! ref || ! CFNumberGetValue((CFNumberRef)ref, kCFNumberIntType, &product_id)) { + //printf("Cannot get product ID.\n"); + continue; + } + + if (vendor_id != vid || product_id != pid) { + // Wrong ID. + continue; + } + + result = strdup(devname); + break; + } + + // Free the iterator object + IOObjectRelease(devices); + +#else + printf("Don't know how to get the list of CD devices on this system.\n"); +#endif + + return result; +} + +// +// Connect to the specified device. +// Initiate the programming session. +// +int serial_init(int vid, int pid) +{ + dev_path = find_path(vid, pid); + if (!dev_path) { + if (trace_flag) { + fprintf(stderr, "Cannot find USB device %04x:%04x\n", + vid, pid); + } + return -1; + } + + // Succeeded. + printf("Serial port: %s\n", dev_path); + return 0; +} + +// +// Send the command sequence and get back a response. +// +static int send_recv(const unsigned char *cmd, int cmdlen, + unsigned char *response, int reply_len) +{ + unsigned char *p; + int len, i, got; + + // + // Send command. + // + if (trace_flag > 0) { + fprintf(stderr, "----Send [%d] %x", cmdlen, cmd[0]); + for (i=1; i 0) { + fprintf(stderr, "----Recv [%d] %x", reply_len, response[0]); + for (i=1; i= 0) { + unsigned char ack[1]; + + send_recv(CMD_END, 3, ack, 1); + + tcsetattr(fd, TCSANOW, &saved_mode); + close(fd); + fd = -1; + } +#endif +} + +// +// Query and return the device identification string. +// On error, return NULL. +// +const char *serial_identify() +{ + static unsigned char reply[16]; + unsigned char ack[3]; + int retry = 0; + + if (serial_open(dev_path, 115200) < 0) { + return 0; + } + +again: +#if defined(__WIN32__) || defined(WIN32) + //TODO: flush pending input and output buffers. +#else + tcflush(fd, TCIOFLUSH); +#endif + send_recv(CMD_PRG, 7, ack, 3); + if (memcmp(ack, CMD_QX, 3) != 0) { + if (++retry >= 10) { + fprintf(stderr, "%s: Wrong PRG acknowledge %02x-%02x-%02x, expected %02x-%02x-%02x\n", + __func__, ack[0], ack[1], ack[2], CMD_QX[0], CMD_QX[1], CMD_QX[2]); + return 0; + } + usleep(500000); + goto again; + } + + // Reply: + // 49 44 38 36 38 55 56 45 00 56 31 30 32 00 00 06 + // I D 8 6 8 U V E V 1 0 2 + send_recv(CMD_PRG2, 1, reply, 16); + if (reply[0] != 'I' || reply[15] != CMD_ACK[0]) { + if (++retry >= 10) { + fprintf(stderr, "%s: Wrong PRG2 reply %02x-...-%02x, expected %02x-...-%02x\n", + __func__, reply[0], reply[15], 'I', CMD_ACK[0]); + return 0; + } + usleep(500000); + goto again; + } + + // Terminate the string. + reply[8] = 0; + return (char*)&reply[1]; +} + +void serial_read_region(int addr, unsigned char *data, int nbytes) +{ + static const int DATASZ = 64; + unsigned char cmd[6], reply[8 + DATASZ]; + int n, i, retry = 0; + + for (n=0; n> 24; + cmd[2] = (addr + n) >> 16; + cmd[3] = (addr + n) >> 8; + cmd[4] = addr + n; + cmd[5] = DATASZ; +again: + send_recv(cmd, 6, reply, sizeof(reply)); + if (reply[0] != CMD_WRITE[0] || reply[7+DATASZ] != CMD_ACK[0]) { + fprintf(stderr, "%s: Wrong read reply %02x-...-%02x, expected %02x-...-%02x\n", + __func__, reply[0], reply[7+DATASZ], CMD_WRITE[0], CMD_ACK[0]); + exit(-1); + } + + // Compute checksum. + unsigned char sum = reply[1]; + for (i=2; i<6+DATASZ; i++) + sum += reply[i]; + if (reply[6+DATASZ] != sum) { + fprintf(stderr, "%s: Wrong read checksum %02x, expected %02x\n", + __func__, sum, reply[6+DATASZ]); + if (retry++ < 3) + goto again; + exit(-1); + } + + memcpy(data + n, reply + 6, DATASZ); + } +} + +void serial_write_region(int addr, unsigned char *data, int nbytes) +{ + //static const int DATASZ = 64; + static const int DATASZ = 16; + unsigned char ack, cmd[8 + DATASZ]; + int n, i; + + for (n=0; n> 24; + cmd[2] = (addr + n) >> 16; + cmd[3] = (addr + n) >> 8; + cmd[4] = addr + n; + cmd[5] = DATASZ; + memcpy(cmd + 6, data + n, DATASZ); + + // Compute checksum. + unsigned char sum = cmd[1]; + for (i=2; i<6+DATASZ; i++) + sum += cmd[i]; + + cmd[6 + DATASZ] = sum; + cmd[7 + DATASZ] = CMD_ACK[0]; + + send_recv(cmd, 8 + DATASZ, &ack, 1); + if (ack != CMD_ACK[0]) { + fprintf(stderr, "%s: Wrong acknowledge %#x, expected %#x\n", + __func__, ack, CMD_ACK[0]); + exit(-1); + } + } +} diff --git a/util.c b/util.c index 27816ea..9da742f 100644 --- a/util.c +++ b/util.c @@ -334,7 +334,7 @@ void utf8_decode(unsigned short *dst, const char *src, unsigned nsym) // Replace underscore by space. // Fill the rest with 0xff. // -void ascii_decode(unsigned char *dst, const char *src, unsigned nsym) +void ascii_decode(unsigned char *dst, const char *src, unsigned nsym, unsigned fill) { if (src[0] == '-' && src[1] == 0) src = ""; @@ -345,7 +345,7 @@ void ascii_decode(unsigned char *dst, const char *src, unsigned nsym) if (ch == 0) { // Clear the remaining bytes. while (nsym-- > 0) - *dst++ = 0xff; + *dst++ = fill; break; } if (ch == '_') @@ -355,6 +355,34 @@ void ascii_decode(unsigned char *dst, const char *src, unsigned nsym) } } +// +// Copy ASCII string, at most nsym characters. +// Replace underscore by space. +// Fill the rest with 0xff. +// +void ascii_decode_uppercase(unsigned char *dst, const char *src, unsigned nsym, unsigned fill) +{ + if (src[0] == '-' && src[1] == 0) + src = ""; + + for (; nsym > 0; nsym--) { + int ch = *src++; + + if (ch == 0) { + // Clear the remaining bytes. + while (nsym-- > 0) + *dst++ = fill; + break; + } + if (ch == '_') + ch = ' '; + else if (ch >= 'a' && ch <= 'z') + ch += 'A' - 'a'; + + *dst++ = ch; + } +} + // // Convert tone string to BCD format. // Four possible formats: @@ -531,6 +559,7 @@ void print_offset(FILE *out, unsigned rx_bcd, unsigned tx_bcd) // // Compare channel index for qsort(). +// Treat 0 as empty element. // int compare_index(const void *pa, const void *pb) { @@ -548,6 +577,26 @@ int compare_index(const void *pa, const void *pb) return 0; } +// +// Compare channel index for qsort(). +// Treat 0xffff as empty element. +// +int compare_index_ffff(const void *pa, const void *pb) +{ + unsigned short a = *(unsigned short*) pa; + unsigned short b = *(unsigned short*) pb; + + if (a == 0xffff) + return (b != 0xffff); + if (b == 0xffff) + return -1; + if (a < b) + return -1; + if (a > b) + return 1; + return 0; +} + // // Print CTSS or DCS tone. // diff --git a/util.h b/util.h index b5c1245..7b2b8c9 100644 --- a/util.h +++ b/util.h @@ -26,19 +26,6 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -// -// Localization. -// -#if 0 -#include -#define _(str) gettext(str) -#else -#define _(str) str -#define setlocale(x,y) /* empty */ -#define bindtextdomain(x,y) /* empty */ -#define textdomain(x) /* empty */ -#endif - // // Program version. // @@ -77,6 +64,15 @@ void hid_read_finish(void); void hid_write_block(int bno, unsigned char *data, int nbytes); void hid_write_finish(void); +// +// Serial functions. +// +int serial_init(int vid, int pid); +const char *serial_identify(void); +void serial_close(void); +void serial_read_region(int addr, unsigned char *data, int nbytes); +void serial_write_region(int addr, unsigned char *data, int nbytes); + // // Delay in milliseconds. // @@ -153,7 +149,8 @@ void utf8_decode(unsigned short *dst, const char *src, unsigned nsym); // Copy ASCII string, at most nsym characters. // Replace underscore by space. // -void ascii_decode(unsigned char *dst, const char *src, unsigned nsym); +void ascii_decode(unsigned char *dst, const char *src, unsigned nsym, unsigned fill); +void ascii_decode_uppercase(unsigned char *dst, const char *src, unsigned nsym, unsigned fill); // // Get local time in format: YYYYMMDDhhmmss @@ -196,6 +193,7 @@ void print_offset(FILE *out, unsigned rx_bcd, unsigned tx_bcd); // Compare channel index for qsort(). // int compare_index(const void *pa, const void *pb); +int compare_index_ffff(const void *pa, const void *pb); // // Print CTSS or DCS tone. diff --git a/zone3.diff b/zone3.diff new file mode 100644 index 0000000..ecd198c --- /dev/null +++ b/zone3.diff @@ -0,0 +1,44 @@ +--- d868uv-full.hd 2018-10-26 13:07:36.694185870 -0700 ++++ d868uv-full-zone3.hd 2018-10-26 13:10:26.798620813 -0700 +@@ -16046,9 +16046,6 @@ + 0003ead0 08 00 09 00 ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0003eae0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * +-0003ecc0 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| --- Zone list +-0003ecd0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +-* + 0003eec0 00 00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 0003eed0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * +@@ -19683,6 +19680,7 @@ + 00070910 00 00 00 00 00 00 00 00 00 05 05 0a 0a 64 01 00 |.............d..| + 00070920 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * ++00070940 fb ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| --- Zone valid bit + 00070950 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 03 |................| + 00070960 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + 00070970 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 03 |................| +@@ -19732,10 +19730,10 @@ + 000716c0 00 5a 62 02 00 6c dc 02 00 00 00 00 00 ff ff 00 |.Zb..l..........| + 000716d0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| + * +-00071700 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| --- Unknown: 'A' channel for zone 3? ++00071700 00 00 08 00 08 00 00 00 00 00 00 00 00 00 00 00 |................| + 00071710 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + * +-00071900 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| --- Unknown: 'B' channel for zone 3? ++00071900 01 00 04 00 04 00 00 00 00 00 00 00 00 00 00 00 |................| + 00071910 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + * + 00071b00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| +@@ -19757,8 +19755,8 @@ + 00071dd0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 00071de0 5a 6f 6e 65 20 32 00 00 00 00 00 00 00 00 00 00 |Zone 2..........| + 00071df0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +-00071e00 5a 6f 6e 65 20 33 00 00 00 00 00 00 00 00 00 00 |Zone 3..........| --- Zone name +-00071e10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| ++00071e00 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| ++* + 00071e20 5a 6f 6e 65 20 34 00 00 00 00 00 00 00 00 00 00 |Zone 4..........| + 00071e30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| + 00071e40 5a 6f 6e 65 20 35 00 00 00 00 00 00 00 00 00 00 |Zone 5..........|