|
#!/usr/bin/env python3
|
|
'''
|
|
[rx_status, rx_frequence, tx_status, tx_frequence, rx_dcs, tx_dcs]
|
|
status bits :
|
|
0: Rig ON(0)/OFF(1)
|
|
1: DCS ON(0)/OFF(1)
|
|
2: ARTS ON(0)/OFF(1)
|
|
rxs rx frequence txs tx frequence rx dcx tx dcs
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
111 0111110100000 110 0111110100000 11111111 11111111
|
|
|
|
Weather channels
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
1111111111111111
|
|
|
|
* Voici une representation de la matrice initiale.
|
|
* Le premier octet est toujours 0x01 et l'avant dernier est 0x0. Les dernier est un checksum.
|
|
* 00000001 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11101111 10100000 11001111 10100000 11111111
|
|
* 11111111 11111111 11111111 11111111 11111111 11111111
|
|
* 11111111 11111111 11111111 11111111 11111111 11111111
|
|
* 11111111 11111111 11111111 11111111 11111111 11111111
|
|
* 11111111 11111111 11111111 00000000 11111111
|
|
*
|
|
|
|
* Exemple d'un fichier CSV valide
|
|
Channel,RX on,RX DCS on,RX ARTS on,RX Frequency,RX DCS,TX on,TX DCS on,TX ARTS on,TX Frequency,TX DCS
|
|
1,True,True,True,462.5625,23,True,True,True,462.5625,23
|
|
2,True,True,True,462.5875,23,True,True,True,462.5875,23
|
|
3,True,True,True,462.6125,23,True,True,True,462.6125,23
|
|
4,True,True,True,462.6375,23,True,True,True,462.6375,23
|
|
5,True,True,True,462.6625,23,True,True,True,462.6625,23
|
|
6,True,True,True,462.6875,23,True,True,True,462.6875,23
|
|
7,True,True,True,462.7125,23,True,True,True,462.7125,23
|
|
8,True,True,True,467.5625,23,True,True,True,467.5625,23
|
|
9,True,True,True,467.5875,23,True,True,True,467.5875,23
|
|
10,True,True,True,467.6125,23,True,True,True,467.6125,23
|
|
11,True,True,True,467.6375,23,True,True,True,467.6375,23
|
|
12,True,True,True,467.6625,23,True,True,True,467.6625,23
|
|
13,True,True,True,467.6875,23,True,True,True,467.6875,23
|
|
14,True,True,True,467.7125,23,True,True,True,467.7125,23
|
|
Weather Frequency
|
|
162.4
|
|
162.425
|
|
162.45
|
|
162.475
|
|
162.5
|
|
162.525
|
|
162.55
|
|
""
|
|
""
|
|
""
|
|
|
|
'''
|
|
|
|
import serial
|
|
import csv
|
|
|
|
class vxf20(object):
|
|
def __init__(self):
|
|
self.channels = dict()
|
|
self.ch_weather = list()
|
|
|
|
def decode_pgmbytes(self, pgmbytes):
|
|
for ch in range(0, 14):
|
|
i = ch * 6 + 1
|
|
channel = dict()
|
|
rx = dict()
|
|
tx = dict()
|
|
rx['status'] = self.get_status(pgmbytes[i] >> 5)
|
|
rx['frequency'] = self.get_frequency( (pgmbytes[i] & 0x1f) << 8 | pgmbytes[i+1] )
|
|
|
|
tx['status'] = self.get_status(pgmbytes[i+2] >> 5)
|
|
tx['frequency'] = self.get_frequency( (pgmbytes[i+2] & 0x1f) << 8 | pgmbytes[i+3] )
|
|
|
|
rx['dcs'] = self.get_dcs(pgmbytes[i+4])
|
|
tx['dcs'] = self.get_dcs(pgmbytes[i+5])
|
|
|
|
channel['rx'] = rx
|
|
channel['tx'] = tx
|
|
self.channels[ch + 1] = channel
|
|
|
|
for wch in range(0, 10):
|
|
i = wch * 2 + 85
|
|
ch_weather = self.get_weather_frequency(pgmbytes[i] << 8 | pgmbytes[i+1])
|
|
self.ch_weather.append(ch_weather)
|
|
|
|
def encode_pgmbytes(self):
|
|
pgmlist = [1]
|
|
for ch in self.channels:
|
|
rx = (self.set_status(self.channels[ch]['rx']['status']) << 5+8) | self.set_frequency(self.channels[ch]['rx']['frequency'])
|
|
rxHIGH = (rx & 0xff00) >> 8
|
|
rxLOW = rx & 0xff
|
|
|
|
tx = (self.set_status(self.channels[ch]['tx']['status']) << 5+8) | self.set_frequency(self.channels[ch]['tx']['frequency'])
|
|
txHIGH = (tx & 0xff00) >> 8
|
|
txLOW = tx & 0xff
|
|
|
|
rxDCS = self.set_dcs(self.channels[ch]['rx']['dcs'])
|
|
txDCS = self.set_dcs(self.channels[ch]['rx']['dcs'])
|
|
pgmlist += [rxHIGH, rxLOW, txHIGH, txLOW, rxDCS, txDCS]
|
|
|
|
for wch in self.ch_weather:
|
|
fr = self.set_weather_frequency(wch)
|
|
frHIGH = (fr & 0xff00) >> 8
|
|
frLOW = fr & 0xff
|
|
pgmlist += [frHIGH, frLOW]
|
|
|
|
|
|
pgmlist += [0x00, self.set_checksum(bytes(pgmlist))]
|
|
pgmbytes = bytes(pgmlist)
|
|
print(pgmbytes)
|
|
|
|
return pgmbytes
|
|
|
|
def read(self, com = '/dev/ttyUSB0'):
|
|
with serial.Serial(com, 2400, timeout=5) as rig:
|
|
print('Press PTT...')
|
|
pgmbytes = rig.read(107)
|
|
|
|
print(pgmbytes)
|
|
self.decode_pgmbytes(pgmbytes)
|
|
|
|
def write(self, com = '/dev/ttyUSB0'):
|
|
pgmbytes = self.encode_pgmbytes()
|
|
|
|
with serial.Serial(com, 2400, timeout=5) as rig:
|
|
rig.write(pgmbytes)
|
|
checkback = rig.read(107)
|
|
|
|
pgmlist = list(pgmbytes)
|
|
#pgmlist += [0xff]
|
|
if bytes(pgmlist) == checkback:
|
|
#rig.write(bytes([0x06]))
|
|
print('done')
|
|
|
|
def get_frequency(self, fr):
|
|
return (125 * fr + 4000000) / 10000
|
|
|
|
def set_frequency(self, fr):
|
|
return int((10000 * fr - 4000000) / 125)
|
|
|
|
def get_weather_frequency(self, wfr):
|
|
if wfr < 0xffff:
|
|
return (6.25 * wfr + 130025) / 1000
|
|
else:
|
|
return None
|
|
|
|
def set_weather_frequency(self, wfr):
|
|
if wfr is None:
|
|
return 0xffff
|
|
else:
|
|
return int((1000 * wfr - 130025) / 6.25)
|
|
|
|
def get_status(self, status):
|
|
s = dict()
|
|
s['rig'] = bool(~status & 0b100)
|
|
s['dcs'] = bool(~status & 0b010)
|
|
s['arts'] = bool(~status & 0b001)
|
|
return s
|
|
|
|
def set_status(self, status):
|
|
rig = int((not status['rig']) << 2)
|
|
dcs = int((not status['dcs']) << 1)
|
|
arts = int(not status['arts'])
|
|
return (rig | dcs | arts)
|
|
|
|
def get_dcs(self, dcs):
|
|
if dcs == 0:
|
|
return 23
|
|
elif dcs == 1:
|
|
return 25
|
|
elif dcs == 2:
|
|
return 26
|
|
elif dcs == 3:
|
|
return 31
|
|
elif dcs == 4:
|
|
return 32
|
|
elif dcs == 5:
|
|
return 36
|
|
elif dcs == 6:
|
|
return 43
|
|
elif dcs == 7:
|
|
return 47
|
|
elif dcs == 8:
|
|
return 51
|
|
elif dcs == 9:
|
|
return 53
|
|
elif dcs == 10:
|
|
return 54
|
|
elif dcs == 11:
|
|
return 65
|
|
elif dcs == 12:
|
|
return 71
|
|
elif dcs ==13:
|
|
return 72
|
|
elif dcs == 14:
|
|
return 73
|
|
elif dcs == 15:
|
|
return 74
|
|
elif dcs == 16:
|
|
return 114
|
|
elif dcs == 17:
|
|
return 115
|
|
elif dcs == 18:
|
|
return 116
|
|
elif dcs == 19:
|
|
return 122
|
|
elif dcs == 20:
|
|
return 125
|
|
elif dcs == 21:
|
|
return 131
|
|
elif dcs == 22:
|
|
return 132
|
|
elif dcs == 23:
|
|
return 134
|
|
elif dcs == 24:
|
|
return 143
|
|
elif dcs == 25:
|
|
return 145
|
|
elif dcs == 26:
|
|
return 152
|
|
elif dcs == 27:
|
|
return 155
|
|
elif dcs == 28:
|
|
return 156
|
|
elif dcs == 29:
|
|
return 162
|
|
elif dcs == 30:
|
|
return 165
|
|
elif dcs == 31:
|
|
return 172
|
|
elif dcs == 32:
|
|
return 174
|
|
elif dcs == 33:
|
|
return 205
|
|
elif dcs == 34:
|
|
return 212
|
|
elif dcs == 35:
|
|
return 223
|
|
elif dcs == 36:
|
|
return 225
|
|
elif dcs == 37:
|
|
return 226
|
|
elif dcs == 38:
|
|
return 243
|
|
elif dcs == 39:
|
|
return 244
|
|
elif dcs == 40:
|
|
return 245
|
|
elif dcs == 41:
|
|
return 246
|
|
elif dcs == 42:
|
|
return 251
|
|
elif dcs == 43:
|
|
return 252
|
|
elif dcs == 44:
|
|
return 255
|
|
elif dcs == 45:
|
|
return 261
|
|
elif dcs == 46:
|
|
return 263
|
|
elif dcs == 47:
|
|
return 265
|
|
elif dcs == 48:
|
|
return 266
|
|
elif dcs == 49:
|
|
return 271
|
|
elif dcs == 50:
|
|
return 274
|
|
elif dcs == 51:
|
|
return 306
|
|
elif dcs == 52:
|
|
return 311
|
|
elif dcs == 53:
|
|
return 315
|
|
elif dcs == 54:
|
|
return 325
|
|
elif dcs == 55:
|
|
return 331
|
|
elif dcs == 56:
|
|
return 332
|
|
elif dcs == 57:
|
|
return 343
|
|
elif dcs == 58:
|
|
return 346
|
|
elif dcs == 59:
|
|
return 351
|
|
elif dcs == 60:
|
|
return 356
|
|
elif dcs == 61:
|
|
return 364
|
|
elif dcs == 62:
|
|
return 365
|
|
elif dcs == 63:
|
|
return 371
|
|
elif dcs == 64:
|
|
return 411
|
|
elif dcs == 65:
|
|
return 412
|
|
elif dcs == 66:
|
|
return 413
|
|
elif dcs == 67:
|
|
return 423
|
|
elif dcs == 68:
|
|
return 431
|
|
elif dcs == 69:
|
|
return 432
|
|
elif dcs == 70:
|
|
return 445
|
|
elif dcs == 71:
|
|
return 446
|
|
elif dcs == 72:
|
|
return 452
|
|
elif dcs == 73:
|
|
return 454
|
|
elif dcs == 74:
|
|
return 455
|
|
elif dcs == 75:
|
|
return 462
|
|
elif dcs == 76:
|
|
return 464
|
|
elif dcs == 77:
|
|
return 465
|
|
elif dcs == 78:
|
|
return 466
|
|
elif dcs == 79:
|
|
return 503
|
|
elif dcs == 80:
|
|
return 506
|
|
elif dcs == 81:
|
|
return 513
|
|
elif dcs == 82:
|
|
return 523
|
|
elif dcs == 83:
|
|
return 526
|
|
elif dcs == 84:
|
|
return 532
|
|
elif dcs == 85:
|
|
return 546
|
|
elif dcs == 86:
|
|
return 565
|
|
elif dcs == 87:
|
|
return 606
|
|
elif dcs == 88:
|
|
return 612
|
|
elif dcs == 89:
|
|
return 624
|
|
elif dcs == 90:
|
|
return 627
|
|
elif dcs == 91:
|
|
return 631
|
|
elif dcs == 92:
|
|
return 632
|
|
elif dcs == 93:
|
|
return 654
|
|
elif dcs == 94:
|
|
return 662
|
|
elif dcs == 95:
|
|
return 664
|
|
elif dcs == 96:
|
|
return 703
|
|
elif dcs == 97:
|
|
return 712
|
|
elif dcs == 98:
|
|
return 723
|
|
elif dcs == 99:
|
|
return 731
|
|
elif dcs == 100:
|
|
return 732
|
|
elif dcs == 101:
|
|
return 734
|
|
elif dcs == 102:
|
|
return 743
|
|
elif dcs == 103:
|
|
return 754
|
|
else:
|
|
return 0
|
|
|
|
def set_dcs(self, dcs):
|
|
if dcs == 23:
|
|
return 0
|
|
elif dcs == 25:
|
|
return 1;
|
|
elif dcs == 26:
|
|
return 2;
|
|
elif dcs == 31:
|
|
return 3;
|
|
elif dcs == 32:
|
|
return 4;
|
|
elif dcs == 36:
|
|
return 5;
|
|
elif dcs == 43:
|
|
return 6;
|
|
elif dcs == 47:
|
|
return 7;
|
|
elif dcs == 51:
|
|
return 8;
|
|
elif dcs == 53:
|
|
return 9;
|
|
elif dcs == 54:
|
|
return 10;
|
|
elif dcs == 65:
|
|
return 11;
|
|
elif dcs == 71:
|
|
return 12;
|
|
elif dcs == 72:
|
|
return 13;
|
|
elif dcs == 73:
|
|
return 14;
|
|
elif dcs == 74:
|
|
return 15;
|
|
elif dcs == 114:
|
|
return 16;
|
|
elif dcs == 115:
|
|
return 16;
|
|
elif dcs == 116:
|
|
return 18;
|
|
elif dcs == 122:
|
|
return 19;
|
|
elif dcs == 125:
|
|
return 20;
|
|
elif dcs == 131:
|
|
return 21;
|
|
elif dcs == 132:
|
|
return 22;
|
|
elif dcs == 134:
|
|
return 23;
|
|
elif dcs == 143:
|
|
return 24;
|
|
elif dcs == 145:
|
|
return 25;
|
|
elif dcs == 152:
|
|
return 26;
|
|
elif dcs == 155:
|
|
return 27;
|
|
elif dcs == 156:
|
|
return 28;
|
|
elif dcs == 162:
|
|
return 29;
|
|
elif dcs == 165:
|
|
return 30;
|
|
elif dcs == 172:
|
|
return 31;
|
|
elif dcs == 174:
|
|
return 32;
|
|
elif dcs == 205:
|
|
return 33;
|
|
elif dcs == 212:
|
|
return 34;
|
|
elif dcs == 223:
|
|
return 35;
|
|
elif dcs == 225:
|
|
return 36;
|
|
elif dcs == 226:
|
|
return 37;
|
|
elif dcs == 243:
|
|
return 38;
|
|
elif dcs == 244:
|
|
return 39;
|
|
elif dcs == 245:
|
|
return 40;
|
|
elif dcs == 246:
|
|
return 41;
|
|
elif dcs == 251:
|
|
return 42;
|
|
elif dcs == 252:
|
|
return 43;
|
|
elif dcs == 255:
|
|
return 44;
|
|
elif dcs == 261:
|
|
return 45;
|
|
elif dcs == 263:
|
|
return 46;
|
|
elif dcs == 265:
|
|
return 47;
|
|
elif dcs == 266:
|
|
return 48;
|
|
elif dcs == 271:
|
|
return 49;
|
|
elif dcs == 274:
|
|
return 50;
|
|
elif dcs == 306:
|
|
return 51;
|
|
elif dcs == 311:
|
|
return 52;
|
|
elif dcs == 315:
|
|
return 53;
|
|
elif dcs == 325:
|
|
return 54;
|
|
elif dcs == 331:
|
|
return 55;
|
|
elif dcs == 332:
|
|
return 56;
|
|
elif dcs == 343:
|
|
return 57;
|
|
elif dcs == 346:
|
|
return 58;
|
|
elif dcs == 351:
|
|
return 59;
|
|
elif dcs == 356:
|
|
return 60;
|
|
elif dcs == 364:
|
|
return 61;
|
|
elif dcs == 365:
|
|
return 62;
|
|
elif dcs == 371:
|
|
return 63;
|
|
elif dcs == 411:
|
|
return 64;
|
|
elif dcs ==412:
|
|
return 65;
|
|
elif dcs == 413:
|
|
return 66;
|
|
elif dcs == 423:
|
|
return 67;
|
|
elif dcs == 431:
|
|
return 68;
|
|
elif dcs == 432:
|
|
return 69;
|
|
elif dcs == 445:
|
|
return 70;
|
|
elif dcs == 446:
|
|
return 71;
|
|
elif dcs == 452:
|
|
return 72;
|
|
elif dcs == 454:
|
|
return 73;
|
|
elif dcs == 455:
|
|
return 74;
|
|
elif dcs == 462:
|
|
return 75;
|
|
elif dcs == 464:
|
|
return 76;
|
|
elif dcs == 465:
|
|
return 77;
|
|
elif dcs == 466:
|
|
return 78;
|
|
elif dcs == 503:
|
|
return 79;
|
|
elif dcs == 506:
|
|
return 80;
|
|
elif dcs == 513:
|
|
return 81;
|
|
elif dcs == 523:
|
|
return 82;
|
|
elif dcs == 526:
|
|
return 83;
|
|
elif dcs == 532:
|
|
return 84;
|
|
elif dcs == 546:
|
|
return 85;
|
|
elif dcs == 565:
|
|
return 86;
|
|
elif dcs == 606:
|
|
return 87;
|
|
elif dcs == 612:
|
|
return 88;
|
|
elif dcs == 624:
|
|
return 89;
|
|
elif dcs == 627:
|
|
return 90;
|
|
elif dcs == 631:
|
|
return 91;
|
|
elif dcs == 632:
|
|
return 92;
|
|
elif dcs == 654:
|
|
return 93;
|
|
elif dcs == 662:
|
|
return 94;
|
|
elif dcs == 664:
|
|
return 95;
|
|
elif dcs == 703:
|
|
return 96;
|
|
elif dcs == 712:
|
|
return 97;
|
|
elif dcs == 723:
|
|
return 98;
|
|
elif dcs == 731:
|
|
return 99;
|
|
elif dcs == 732:
|
|
return 100;
|
|
elif dcs == 734:
|
|
return 101;
|
|
elif dcs == 743:
|
|
return 102;
|
|
elif dcs == 754:
|
|
return 103;
|
|
else:
|
|
return 0xff;
|
|
|
|
def write_csv(self, filename = 'vxf20ab.csv'):
|
|
with open(filename, 'w') as f:
|
|
headers = ['Channel', 'RX on', 'RX DCS on', 'RX ARTS on', 'RX Frequency', 'RX DCS', 'TX on', 'TX DCS on', 'TX ARTS on', 'TX Frequency', 'TX DCS']
|
|
writer = csv.writer(f)
|
|
|
|
writer.writerow(headers)
|
|
for ch in self.channels:
|
|
writer.writerow([ch,
|
|
self.channels[ch]['rx']['status']['rig'],
|
|
self.channels[ch]['rx']['status']['dcs'],
|
|
self.channels[ch]['rx']['status']['arts'],
|
|
self.channels[ch]['rx']['frequency'],
|
|
self.channels[ch]['rx']['dcs'],
|
|
self.channels[ch]['tx']['status']['rig'],
|
|
self.channels[ch]['tx']['status']['dcs'],
|
|
self.channels[ch]['tx']['status']['arts'],
|
|
self.channels[ch]['tx']['frequency'],
|
|
self.channels[ch]['tx']['dcs']])
|
|
|
|
writer.writerow(['Weather Frequency'])
|
|
for wch in self.ch_weather:
|
|
writer.writerow([wch])
|
|
|
|
def read_csv(self, filename = 'vxf20ab.csv'):
|
|
wch = False
|
|
|
|
with open(filename, 'r') as f:
|
|
reader = csv.DictReader(f)
|
|
for row in reader:
|
|
if(not wch):
|
|
if(row['Channel'] != 'Weather Frequency'):
|
|
channel = dict()
|
|
rx = dict()
|
|
tx = dict()
|
|
rx_status = dict()
|
|
tx_status = dict()
|
|
|
|
ch = int(row['Channel'])
|
|
rx_status['rig'] = bool(row['RX on'])
|
|
rx_status['dcs'] = bool(row['RX DCS on'])
|
|
rx_status['arts'] = bool(row['RX ARTS on'])
|
|
rx['status'] = rx_status
|
|
rx['frequency'] = float(row['RX Frequency'])
|
|
rx['dcs'] = int(row['RX DCS'])
|
|
|
|
tx_status['rig'] = bool(row['TX on'])
|
|
tx_status['dcs'] = bool(row['TX DCS on'])
|
|
tx_status['arts'] = bool(row['TX ARTS on'])
|
|
tx['status'] = tx_status
|
|
tx['frequency'] = float(row['TX Frequency'])
|
|
tx['dcs'] = int(row['TX DCS'])
|
|
channel['rx'] = rx
|
|
channel['tx'] = tx
|
|
self.channels[ch] = channel
|
|
else:
|
|
wch = True
|
|
else:
|
|
if row['Channel'] != '':
|
|
self.ch_weather.append(float(row['Channel']))
|
|
else:
|
|
self.ch_weather.append(None)
|
|
|
|
def get_checksum(self, pgmbytes):
|
|
cs = 0
|
|
for i in pgmbytes:
|
|
cs+=i
|
|
|
|
first = pgmbytes[0]
|
|
last = pgmbytes[-1]
|
|
cs = cs - first - last
|
|
if cs % 256 == last:
|
|
return last
|
|
else:
|
|
return False
|
|
|
|
def set_checksum(self, pgmbytes):
|
|
cs = 0
|
|
for i in pgmbytes:
|
|
cs+=i
|
|
|
|
cs = (cs - 1) % 256
|
|
print(hex(cs))
|
|
return cs
|
|
|
|
def main():
|
|
myrig = vxf20()
|
|
myrig.read_csv()
|
|
myrig.write()
|
|
myrig.read()
|
|
print(myrig.channels)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|