... | ... |
@@ -117,7 +117,9 @@ dDcs = { '23':'000', '25':'001', '26':'002', '31':'003', '32':'004', |
117 | 117 |
dRxClar = { 'OFF':'0', 'ON':'1' } |
118 | 118 |
dTxClar = { 'OFF':'0', 'ON':'1' } |
119 | 119 |
|
120 |
-# Define 'get' methods to encapsulate FT991 commands that return status info. |
|
120 |
+############################################################################# |
|
121 |
+# Define 'get' methods to encapsulate FT991 commands returning status info. # |
|
122 |
+############################################################################# |
|
121 | 123 |
|
122 | 124 |
def getMemory(memloc): |
123 | 125 |
""" |
... | ... |
@@ -127,17 +129,11 @@ def getMemory(memloc): |
127 | 129 |
""" |
128 | 130 |
dMem = {} |
129 | 131 |
|
130 |
- # Set memory location pointer in FT991. This is done |
|
131 |
- # by sending the memory location select (MC) command. |
|
132 |
- sCmd = 'MC%0.3d;' % (memloc) |
|
133 |
- sResult = sendCommand(sCmd) |
|
134 |
- # Skip blank memory locations, which return '?;'. |
|
135 |
- if sResult == '?;': |
|
136 |
- return None |
|
137 |
- |
|
138 | 132 |
# Send the get memory settings string to the FT991. |
139 | 133 |
sCmd = 'MT%0.3d;' % (memloc) |
140 | 134 |
sResult = sendCommand(sCmd) |
135 |
+ if sResult == '?;': |
|
136 |
+ return None |
|
141 | 137 |
|
142 | 138 |
# Parse memory settings string returned by the FT991 |
143 | 139 |
memloc = sResult[2:5] |
... | ... |
@@ -188,7 +184,37 @@ def getDCS(): |
188 | 184 |
return dDcs.keys()[dDcs.values().index(dcs)] |
189 | 185 |
## end def |
190 | 186 |
|
191 |
-# Define 'set' functions to encapsulate the various FT991 CAT commands. |
|
187 |
+def getRxClarifier(): |
|
188 |
+ """ |
|
189 |
+ Description: Gets the state of the Rx clarifier. |
|
190 |
+ Parameters: none |
|
191 |
+ Returns: string containing the state of the clarifier |
|
192 |
+ """ |
|
193 |
+ # An exception will automatically be raised if incorrect data is |
|
194 |
+ # supplied - most likely a "key not found" error. |
|
195 |
+ sCmd = 'RT;' |
|
196 |
+ sResult = sendCommand(sCmd) |
|
197 |
+ state = sResult[2] |
|
198 |
+ return dRxClar.keys()[dRxClar.values().index(state)] |
|
199 |
+## end def |
|
200 |
+ |
|
201 |
+def getTxClarifier(): |
|
202 |
+ """ |
|
203 |
+ Description: Gets the state of the Tx clarifier. |
|
204 |
+ Parameters: none |
|
205 |
+ Returns: string containing the state of the clarifier |
|
206 |
+ """ |
|
207 |
+ # An exception will automatically be raised if incorrect data is |
|
208 |
+ # supplied - most likely a "key not found" error. |
|
209 |
+ sCmd = 'XT;' |
|
210 |
+ sResult = sendCommand(sCmd) |
|
211 |
+ state = sResult[2] |
|
212 |
+ return dTxClar.keys()[dTxClar.values().index(state)] |
|
213 |
+## end def |
|
214 |
+ |
|
215 |
+######################################################################### |
|
216 |
+# Define 'set' functions to encapsulate the various FT991 CAT commands. # |
|
217 |
+######################################################################### |
|
192 | 218 |
|
193 | 219 |
def setMemory(dMem): |
194 | 220 |
""" |
... | ... |
@@ -206,25 +232,17 @@ def setMemory(dMem): |
206 | 232 |
shift - the direction of the repeater shift |
207 | 233 |
tag - a label for the memory location |
208 | 234 |
|
209 |
- Returns: a string containing the formatted command |
|
235 |
+ Returns: nothing |
|
210 | 236 |
""" |
211 |
- # Format the set memory location (MC) command. |
|
212 |
- iMemloc = int(dMem['memloc']) |
|
213 |
- # Validate memory location data and send the command. |
|
214 |
- if iMemloc < 1 or iMemloc > 118: |
|
237 |
+ # Format the set memory with tag command (MT). |
|
238 |
+ sCmd = 'MT' |
|
239 |
+ |
|
240 |
+ # Validate and append memory location data. |
|
241 |
+ iLocation = int(dMem['memloc']) |
|
242 |
+ if iLocation < 1 or iLocation > 118: |
|
215 | 243 |
raise Exception('Memory location must be between 1 and ' \ |
216 | 244 |
'118, inclusive.') |
217 |
- sCmd = 'MC%0.3d;' % iMemloc |
|
218 |
- sResult = sendCommand(sCmd) |
|
219 |
- |
|
220 |
- # While the 'MW' and 'MT' commands can be used to turn the Rx |
|
221 |
- # and Tx clarifiers on, the clarifier states can only be turned |
|
222 |
- # off by sending the 'RT0' and 'XT0' commands. This situation is |
|
223 |
- # probably due to a bug in the CAT interface. |
|
224 |
- sResult = sendCommand('RC;RT0;XT0;') |
|
225 |
- |
|
226 |
- # Format the set memory with tag command (MT). |
|
227 |
- sCmd = 'MT%0.3d' % iMemloc |
|
245 |
+ sCmd += '%0.3d' % iLocation |
|
228 | 246 |
|
229 | 247 |
# Validate and append the vfo-a frequency data. |
230 | 248 |
iRxfreq = int(float(dMem['rxfreq']) * 1E6) # vfo-a frequency in Hz |
... | ... |
@@ -261,7 +279,8 @@ def setMemory(dMem): |
261 | 279 |
|
262 | 280 |
# Send the completed command. |
263 | 281 |
sResult = sendCommand(sCmd) |
264 |
- return sResult |
|
282 |
+ if sResult == '?;': |
|
283 |
+ raise Exception('setMemory error') |
|
265 | 284 |
## end def |
266 | 285 |
|
267 | 286 |
def setCTCSS(tone): |
... | ... |
@@ -270,12 +289,15 @@ def setCTCSS(tone): |
270 | 289 |
CTCSS tone. |
271 | 290 |
Parameters: tone - a string containing the CTCSS tone in Hz, e.g., |
272 | 291 |
'100 Hz' |
273 |
- Returns: a string containing the formatted command |
|
292 |
+ Returns: nothing |
|
274 | 293 |
""" |
275 | 294 |
# An exception will automatically be raised if incorrect data is |
276 | 295 |
# supplied - most likely a "key not found" error. |
277 | 296 |
sCmd = 'CN00%s;' % dTones[tone] |
278 |
- return sendCommand(sCmd) |
|
297 |
+ # Send the completed command. |
|
298 |
+ sResult = sendCommand(sCmd) |
|
299 |
+ if sResult == '?;': |
|
300 |
+ raise Exception('setCTCSS error') |
|
279 | 301 |
## end def |
280 | 302 |
|
281 | 303 |
def setDCS(code): |
... | ... |
@@ -283,12 +305,15 @@ def setDCS(code): |
283 | 305 |
Description: Sends a formatted CN command that sets the desired |
284 | 306 |
DCS code. |
285 | 307 |
Parameters: code - a string containing the DCS code, e.g., '23' |
286 |
- Returns: a string containing the formatted command |
|
308 |
+ Returns: nothing |
|
287 | 309 |
""" |
288 | 310 |
# An exception will automatically be raised if incorrect data is |
289 | 311 |
# supplied - most likely a "key not found" error. |
290 | 312 |
sCmd = 'CN01%s;' % dDcs[code] |
291 |
- return sendCommand(sCmd) |
|
313 |
+ # Send the completed command. |
|
314 |
+ sResult = sendCommand(sCmd) |
|
315 |
+ if sResult == '?;': |
|
316 |
+ raise Exception('setDCS error') |
|
292 | 317 |
## end def |
293 | 318 |
|
294 | 319 |
def setPower(power): |
... | ... |
@@ -296,17 +321,73 @@ def setPower(power): |
296 | 321 |
Description: Sends a PC command that sets the desired |
297 | 322 |
RF transmit power level. |
298 | 323 |
Parameters: power - Watts, an integer between 5 and 100 |
299 |
- Returns: a string containing the formatted command |
|
324 |
+ Returns: nothing |
|
300 | 325 |
""" |
301 | 326 |
power = int(power) |
302 | 327 |
# Validate power data and format command. |
303 | 328 |
if power < 5 or power > 100: |
304 | 329 |
raise Exception('Power must be between 0 and 100 watts, inclusive.') |
305 | 330 |
sCmd += 'PC%03.d;' % power |
306 |
- return sendCommand(sCmd) |
|
331 |
+ # Send the completed command. |
|
332 |
+ sResult = sendCommand(sCmd) |
|
333 |
+ if sResult == '?;': |
|
334 |
+ raise Exception('setPower error') |
|
335 |
+ |
|
307 | 336 |
## end def |
308 | 337 |
|
309 |
-# Helper functions to assist in various tasks. |
|
338 |
+def setRxClarifier(state='OFF'): |
|
339 |
+ """ |
|
340 |
+ Description: Sends a formatted RT command that turns the Rx clarifier |
|
341 |
+ on or off. |
|
342 |
+ Parameters: state - string 'OFF' or 'ON' |
|
343 |
+ Returns: nothing |
|
344 |
+ """ |
|
345 |
+ # An exception will automatically be raised if incorrect data is |
|
346 |
+ # supplied - most likely a "key not found" error. |
|
347 |
+ sCmd = 'RT%s;' % dRxClar[state] |
|
348 |
+ # Send the completed command. |
|
349 |
+ sResult = sendCommand(sCmd) |
|
350 |
+ if sResult == '?;': |
|
351 |
+ raise Exception('setRxClarifier error') |
|
352 |
+## end def |
|
353 |
+ |
|
354 |
+def setTxClarifier(state='OFF'): |
|
355 |
+ """ |
|
356 |
+ Description: Sends a formatted XT command that turns the Rx clarifier |
|
357 |
+ on or off. |
|
358 |
+ Parameters: state - string 'OFF' or 'ON' |
|
359 |
+ Returns: nothing |
|
360 |
+ """ |
|
361 |
+ # An exception will automatically be raised if incorrect data is |
|
362 |
+ # supplied - most likely a "key not found" error. |
|
363 |
+ sCmd = 'XT%s;' % dTxClar[state] |
|
364 |
+ # Send the completed command. |
|
365 |
+ sResult = sendCommand(sCmd) |
|
366 |
+ if sResult == '?;': |
|
367 |
+ raise Exception('setTxClarifier error') |
|
368 |
+## end def |
|
369 |
+ |
|
370 |
+def setMemoryLocation(iLocation): |
|
371 |
+ """ |
|
372 |
+ Description: Sends a formatted MC command that sets the current |
|
373 |
+ memory location. |
|
374 |
+ Parameters: location - integer specifying memory location |
|
375 |
+ Returns: nothing |
|
376 |
+ """ |
|
377 |
+ # Validate memory location data and send the command. |
|
378 |
+ if iLocation < 1 or iLocation > 118: |
|
379 |
+ raise Exception('Memory location must be an integer between 1 and ' \ |
|
380 |
+ '118, inclusive.') |
|
381 |
+ sCmd = 'MC%0.3d;' % iLocation |
|
382 |
+ # Send the completed command. |
|
383 |
+ sResult = sendCommand(sCmd) |
|
384 |
+ if sResult == '?;': |
|
385 |
+ raise Exception('setMemoryLocation error') |
|
386 |
+## end def |
|
387 |
+ |
|
388 |
+############################################################################ |
|
389 |
+# Helper functions to assist in various tasks. # |
|
390 |
+############################################################################ |
|
310 | 391 |
|
311 | 392 |
def parseCsvData(sline): |
312 | 393 |
""" |
... | ... |
@@ -476,14 +557,41 @@ def main(): |
476 | 557 |
|
477 | 558 |
# Instantiate serial connection to FT991 |
478 | 559 |
begin() |
479 |
- # Commands that send a setting |
|
480 |
- dMem = {'rxfreq': '146.52', 'shift': 'OFF', 'encode': 'OFF', \ |
|
481 |
- 'txclar': 'OFF', 'tag': 'KA7JLO', 'mode': 'FM', 'rxclar': 'OFF', \ |
|
482 |
- 'memloc': '99', 'clarfreq': '0'} |
|
560 |
+ # Set and receive a memory channel |
|
561 |
+ dMem = {'memloc': '98', 'rxfreq': '146.52', 'shift': 'OFF', \ |
|
562 |
+ 'mode': 'FM', 'encode': 'TONE ENC', 'tag': 'KA7JLO', \ |
|
563 |
+ 'clarfreq': '1234', 'rxclar': 'ON', 'txclar': 'ON' \ |
|
564 |
+ } |
|
483 | 565 |
setMemory(dMem) |
484 |
- sendCommand('MC002;') |
|
485 |
- # Commands that return data |
|
566 |
+ setMemoryLocation(int(dMem['memloc'])) |
|
567 |
+ setRxClarifier(dMem['rxclar']) |
|
568 |
+ setTxClarifier(dMem['txclar']) |
|
569 |
+ setCTCSS('127.3 Hz') |
|
570 |
+ setDCS('115') |
|
571 |
|
|
572 |
+ getMemory(98) |
|
573 |
|
|
574 |
+ # Set and receive a memory channel |
|
575 |
+ dMem = {'memloc': '99', 'rxfreq': '146.52', 'shift': 'OFF', \ |
|
576 |
+ 'mode': 'FM', 'encode': 'OFF', 'tag': 'KA7JLO', \ |
|
577 |
+ 'clarfreq': '0', 'rxclar': 'OFF', 'txclar': 'OFF' \ |
|
578 |
+ } |
|
579 |
+ setMemory(dMem) |
|
580 |
+ setMemoryLocation(int(dMem['memloc'])) |
|
581 |
+ setRxClarifier(dMem['rxclar']) |
|
582 |
+ setTxClarifier(dMem['txclar']) |
|
583 |
+ setCTCSS('141.3 Hz') |
|
584 |
+ setDCS('445') |
|
585 |
|
|
486 | 586 |
getMemory(99) |
587 |
|
|
588 |
+ |
|
589 |
+ # Test set commands |
|
590 |
+ #setMemoryLocation(2) |
|
591 |
+ # Test get commands |
|
592 |
+ # commands... |
|
593 |
+ # Test CAT commands via direct pass-through |
|
594 |
+ # Commands that return data |
|
487 | 595 |
sendCommand('IF;') |
488 | 596 |
# Invalid command handling |
489 | 597 |
sendCommand('ZZZ;') |
... | ... |
@@ -266,16 +266,19 @@ def readMemorySettings(): |
266 | 266 |
'Repeater Shift,Mode,Tag,Encoding,Tone,DCS,' \ |
267 | 267 |
'Clarifier, RxClar, TxClar' ] |
268 | 268 |
|
269 |
- for memoryLocation in range(1, _MAX_NUMBER_OF_MEMORY_ITEMS): |
|
269 |
+ for iLocation in range(1, _MAX_NUMBER_OF_MEMORY_ITEMS): |
|
270 |
+ |
|
270 | 271 |
# For each memory location get the memory contents. Note that |
271 | 272 |
# several CAT commands are required to get the entire contents |
272 | 273 |
# of a memory location. Specifically, additional commands are |
273 | 274 |
# required to get DCS code and CTCSS tone. |
274 |
- dMem = ft991.getMemory(memoryLocation) |
|
275 |
+ dMem = ft991.getMemory(iLocation) |
|
275 | 276 |
# If a memory location is empty (has not been programmed or has |
276 | 277 |
# been erased), do not created a list entry for that location. |
277 | 278 |
if dMem == None: |
278 | 279 |
continue |
280 |
+ # Set current memory location to the channel being set. |
|
281 |
+ sResult = ft991.setMemoryLocation(iLocation) |
|
279 | 282 |
# Get DCS and CTCSS. |
280 | 283 |
tone = ft991.getCTCSS() |
281 | 284 |
dcs = ft991.getDCS() |
... | ... |
@@ -289,8 +292,6 @@ def readMemorySettings(): |
289 | 292 |
dMem['txclar'] ) |
290 | 293 |
# Add the comma-delimited string to the list object. |
291 | 294 |
lSettings.append(sCsvFormat) |
292 |
- if ft991.verbose: |
|
293 |
|
|
294 | 295 |
return lSettings |
295 | 296 |
# end def |
296 | 297 |
|
... | ... |
@@ -308,25 +309,28 @@ def writeMemorySettings(lSettings): |
308 | 309 |
# so ignore this item. (parseData returns None for this item.) |
309 | 310 |
if dItem == None: |
310 | 311 |
continue |
311 |
- sResult = '' |
|
312 | 312 |
try: |
313 |
- # Set memory channel vfo, mode, and other data. |
|
314 |
- sResult += ft991.setMemory(dItem) |
|
313 |
+ # Set the parameters for the memory location. |
|
314 |
+ ft991.setMemory(dItem) |
|
315 |
+ # Set current channel to memory location being set. |
|
316 |
+ ft991.setMemoryLocation(int(dItem['memloc'])) |
|
315 | 317 |
# Set CTCSS tone for memory channel. |
316 |
- sResult += ft991.setCTCSS(dItem['tone']) |
|
318 |
+ ft991.setCTCSS(dItem['tone']) |
|
317 | 319 |
# Set DCS code for memory channel. |
318 |
- sResult += ft991.setDCS(dItem['dcs']) |
|
320 |
+ ft991.setDCS(dItem['dcs']) |
|
321 |
+ # Set clarifier mode. Note that |
|
322 |
+ # while the 'MW' and 'MT' commands can be used to turn the Rx |
|
323 |
+ # and Tx clarifiers on, the clarifier states can only be turned |
|
324 |
+ # off by sending the 'RT0' and 'XT0' commands. This situation |
|
325 |
+ # is probably due to a bug in the CAT interface. |
|
326 |
+ ft991.setRxClarifier(dItem['rxclar']) |
|
327 |
+ ft991.setTxClarifier(dItem['txclar']) |
|
319 | 328 |
except Exception, e: |
320 |
- print 'Backup settings file corrupted or incorrectly formatted.\n' \ |
|
321 |
- 'Please make sure all values are correctly entered.' |
|
329 |
+ print 'Memory settings restore operation failed. Most likely\n' \ |
|
330 |
+ 'this is due to the backup settings file corrupted or\n' \ |
|
331 |
+ 'incorrectly formatted. Look for the following error: \n' |
|
322 | 332 |
print e |
323 | 333 |
exit(1) |
324 |
- |
|
325 |
- # Process any errors returned by the CAT interface. |
|
326 |
- if sResult.find('?;') > -1: |
|
327 |
- print 'Error restoring memory setting: %s' % sResult |
|
328 |
- if ft991.verbose: |
|
329 |
|
|
330 | 334 |
## end def |
331 | 335 |
|
332 | 336 |
def readMenuSettings(): |