Skip to content
This repository was archived by the owner on Dec 25, 2025. It is now read-only.

Commit 172b347

Browse files
committed
Added online mode to use current time at caching QSO
1 parent 1ba658c commit 172b347

4 files changed

Lines changed: 100 additions & 42 deletions

File tree

README.md

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -127,32 +127,33 @@ The table shows all available pre- and postfixes. The following will work for AP
127127
Placeholder x for characters and 9 for numbers.
128128
Types marked with auto are prefilled but can be overwritten. Types marked with memory are retained for the session.
129129

130-
| Info | Format | Type | Comments |
131-
|--------------|--------------------------|---------|-----------------------------------------------------------------|
132-
| Callsign | xx9xx | | format checked |
133-
| Locator/QTH | @xx99xx or @QTH(Locator) | | format checked |
134-
| Name | 'xxxx | | _ for spaces |
135-
| Comment | #xxxx | memory | _ for spaces |
136-
| Band | valid ADIF band | memory | |
137-
| Mode | valid ADIF mode | memory | |
138-
| RST rcvd | .599 | auto | default CW 599, phone 59 |
139-
| RST sent | ,599 | auto | default CW 599, phone 59 |
140-
| QSL rcvd | * | | toggles the information |
141-
| Event ID | $xxxxxx | memory | Contest ID or one of POTA, SOTA |
142-
| Rcvd Exch | %xxxxx | | Contest exchange or xOTA reference |
143-
| Time | HHMMt | memory | partly time will be filled |
144-
| Date | YYYYMMDDd | memory | partly date will be filled |
145-
| Date/Time | = | auto | sync date/time to now |
146-
| Frequency | 99999f | memory | in kHz |
147-
| TX Power | 99p | memory | in W |
148-
| Your Call | -cxx9xx | memory | |
149-
| Your Locator | -lxx99xx | memory | |
150-
| Your Name | -nxxxx | memory | _ for spaces |
151-
| Finish QSO | linefeed | command | ENTER-Key |
152-
| Clear QSO | ~ | command | clears input not cached QSO |
153-
| Show QSO | ? | command | |
154-
| Sent Exch | -N9 or -Nxx | auto | set start value (if number) for contest QSO No. or own xOTA ref |
155-
| Show version | -V | command | |
130+
| Info | Format | Type | Comments |
131+
|---------------|--------------------------|---------|-----------------------------------------------------------------|
132+
| Callsign | xx9xx | | format checked |
133+
| Locator/QTH | @xx99xx or @QTH(Locator) | | format checked |
134+
| Name | 'xxxx | | _ for spaces |
135+
| Comment | #xxxx | memory | _ for spaces |
136+
| Band | valid ADIF band | memory | |
137+
| Mode | valid ADIF mode | memory | |
138+
| RST rcvd | .599 | auto | default CW 599, phone 59 |
139+
| RST sent | ,599 | auto | default CW 599, phone 59 |
140+
| QSL rcvd | * | | toggles the information |
141+
| Event ID | $xxxxxx | memory | Contest ID or one of POTA, SOTA |
142+
| Rcvd Exch | %xxxxx | | Contest exchange or xOTA reference |
143+
| Time | HHMMt | memory | partly time will be filled |
144+
| Date | YYYYMMDDd | memory | partly date will be filled |
145+
| Date/Time | = | auto | sync date/time to now (overwrites online mode for current QSO) |
146+
| Frequency | 99999f | memory | in kHz |
147+
| TX Power | 99p | memory | in W |
148+
| Your Call | -cxx9xx | memory | |
149+
| Your Locator | -lxx99xx | memory | |
150+
| Your Name | -nxxxx | memory | _ for spaces |
151+
| Finish QSO | linefeed | command | ENTER-Key |
152+
| Clear QSO | ~ | command | clears input not cached QSO |
153+
| Show QSO | ? | command | |
154+
| Sent Exch | -N9 or -Nxx | auto | set start value (if number) for contest QSO No. or own xOTA ref |
155+
| Toggle online | -o | command | toggles online (automatic date/time at saving) and offline |
156+
| Show version | -V | command | |
156157

157158
For callsigns, mode, locators, RST and contest id lowercase will be converted to uppecase.
158159

src/hamcc/__main__.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ def main():
131131
help='your locator and QTH i.e. "JO30uj" or "Eitelborn(JO30uj)"')
132132
parser.add_argument('-n', '--name', dest='own_name', default='',
133133
help='your name')
134+
parser.add_argument('-o', '--online', dest='online', action='store_true',
135+
help='set online mode at startup (console only)')
134136
parser.add_argument('-E', '--event', dest='event', default='',
135137
help='the event (contest ID or one of POTA, SOTA) to activate at startup')
136138
parser.add_argument('-N', '--exchange', dest='exchange', default=1,
@@ -156,7 +158,7 @@ def main():
156158
logger.addHandler(stderr_handler)
157159
logging.getLogger('hamcc').addHandler(stderr_handler)
158160

159-
qsos = sys.stdin if args.stdin else args.qso
161+
qsos = sys.stdin if args.stdin else args.qso
160162
process_qsos(qsos, args.file, args.own_call, args.own_loc, args.own_name,
161163
not args.overwrite, args.event, args.exchange)
162164
else:
@@ -176,7 +178,7 @@ def main():
176178
records = doc['RECORDS']
177179

178180
run_console(args.file, args.own_call, args.own_loc, args.own_name,
179-
args.overwrite, args.event, args.exchange, records)
181+
args.overwrite, args.event, args.exchange, records, args.online)
180182

181183
logger.info('Stopped console')
182184

src/hamcc/_console_.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@
3131

3232

3333
def qso2str(qso, pos, cnt) -> tuple[str, str]:
34-
d = adif_date2iso(qso["QSO_DATE"])
35-
t = adif_time2iso(qso["TIME_ON"])
34+
d = adif_date2iso(qso['QSO_DATE'][:8])
35+
t = adif_time2iso(qso['TIME_ON'][:4])
36+
if '*' in qso['QSO_DATE']:
37+
d += '*'
38+
if '*' in qso['TIME_ON']:
39+
t += '*'
3640

3741
opt_info = ''
3842
for i, f in (
@@ -89,8 +93,11 @@ def read_adi(file: str) -> tuple[dict[str, str], dict[str, tuple[str, str]]]:
8993

9094

9195
def command_console(stdscr, file, own_call, own_loc, own_name, append=False, # noqa: C901
92-
contest_id='', qso_number=1, records: list = []):
96+
contest_id='', qso_number=1, records: list = None, online=False):
9397
adi_f = None
98+
if records is None:
99+
records = []
100+
94101
try:
95102
fmode = 'a' if append else 'w'
96103
fexists = os.path.isfile(file)
@@ -118,7 +125,7 @@ def command_console(stdscr, file, own_call, own_loc, own_name, append=False, #
118125
if records:
119126
last_qso = records[-1]
120127

121-
cc = CassiopeiaConsole(own_call, own_loc, own_name, contest_id, qso_number, last_qso, worked_calls)
128+
cc = CassiopeiaConsole(own_call, own_loc, own_name, contest_id, qso_number, last_qso, worked_calls, online)
122129
if records:
123130
logger.info('Loading QSOs...')
124131
for r in records:
@@ -233,9 +240,9 @@ def command_console(stdscr, file, own_call, own_loc, own_name, append=False, #
233240
logger.info('Closed ADIF file')
234241

235242

236-
def run_console(file, own_call, own_loc, own_name, overwrite, event, exchange, records):
243+
def run_console(file, own_call, own_loc, own_name, overwrite, event, exchange, records, online=False):
237244
if os.name == 'nt':
238245
os.system("mode con cols=120 lines=25")
239246

240247
wrapper(command_console, file, own_call, own_loc, own_name,
241-
not overwrite, event, exchange, records)
248+
not overwrite, event, exchange, records, online)

src/hamcc/hamcc.py

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import os
66
import re
7+
import sys
78
import json
89
from copy import deepcopy
910
import datetime
@@ -27,15 +28,25 @@ def __read_json__(file) -> list:
2728
MODES = __read_json__('data/modes.json')
2829

2930

31+
def get_cur_adif_dt() -> tuple[str, str]:
32+
"""Get current date in ADIF format independant of Python version"""
33+
if sys.version_info[0] == 3 and sys.version_info[1] < 11:
34+
# noinspection PyDeprecation
35+
dt = datetime.datetime.utcnow()
36+
else:
37+
dt = datetime.datetime.now(datetime.UTC)
38+
return dt.strftime('%Y%m%d'), dt.strftime('%H%M')
39+
40+
3041
def adif_date2iso(date: str) -> str | None:
3142
if not date or len(date) != 8:
32-
return
43+
return None
3344
return date[:4] + '-' + date[4:6] + '-' + date[6:8]
3445

3546

3647
def adif_time2iso(time: str) -> str | None:
3748
if not time or len(time) != 4:
38-
return
49+
return None
3950
return time[:2] + ':' + time[2:4]
4051

4152

@@ -95,7 +106,7 @@ class CassiopeiaConsole:
95106

96107
def __init__(self, my_call: str = '', my_loc: str = '', my_name: str = '',
97108
event: str = '', event_ref: int = 1,
98-
init_qso: dict[str, str] = None, init_worked: dict[str, tuple[str, str]] = None):
109+
init_qso: dict[str, str] = None, init_worked: dict[str, tuple[str, str]] = None, online=False):
99110
logger.debug('Initialising...')
100111
if my_call and not self.check_format(self.REGEX_CALL, my_call):
101112
raise Exception('Wrong call format')
@@ -121,10 +132,16 @@ def __init__(self, my_call: str = '', my_loc: str = '', my_name: str = '',
121132
self.__my_name__ = my_name
122133

123134
self.__qsos__: list[dict] = []
135+
self.__online__ = online
124136

125137
# Mandatory
126-
self.__date__ = init_qso.get('QSO_DATE', datetime.datetime.utcnow().strftime('%Y%m%d'))
127-
self.__time__ = init_qso.get('TIME_ON', datetime.datetime.utcnow().strftime('%H%M'))
138+
date, time = get_cur_adif_dt()
139+
self.__date__ = init_qso.get('QSO_DATE', date)
140+
self.__time__ = init_qso.get('TIME_ON', time)
141+
if self.__online__:
142+
self.__date__ += '*'
143+
self.__time__ += '*'
144+
128145
self.__band__ = init_qso.get('BAND', '')
129146
self.__mode__ = init_qso.get('MODE', '')
130147

@@ -153,9 +170,12 @@ def __init__(self, my_call: str = '', my_loc: str = '', my_name: str = '',
153170
self.__qso_active__ = False
154171
self.clear()
155172

156-
def is_sig(self):
173+
def is_sig(self) -> bool:
157174
return self.__event__ in ('POTA', 'SOTA')
158175

176+
def is_online(self) -> bool:
177+
return self.__online__
178+
159179
def append_char(self, char: str) -> str:
160180
"""Append a single char to the sequence stack
161181
If a backspace \\b is appended, and it is possible to delete from the end of the sequence a \\b will be returned
@@ -215,6 +235,8 @@ def check_qth(self, qth_loc: str) -> None | tuple:
215235
m = re.fullmatch(self.REGEX_QTH, qth_loc.strip())
216236
if m:
217237
return m.groups()[:2]
238+
else:
239+
return None
218240

219241
def clear(self):
220242
"""Clear current QSO (input cache)"""
@@ -223,6 +245,11 @@ def clear(self):
223245
self.__qso_active__ = False
224246
self.__long_mode__ = False
225247

248+
if self.__online__:
249+
date, time = get_cur_adif_dt()
250+
self.__date__ = date + '*'
251+
self.__time__ = time + '*'
252+
226253
# Mandatory
227254
self.__cur_qso__ = {'STATION_CALLSIGN': self.__my_call__,
228255
'MY_GRIDSQUARE': self.__my_loc__,
@@ -324,6 +351,12 @@ def finalize_qso(self) -> str:
324351
else:
325352
res = 'Warning: Callsign missing for last QSO'
326353

354+
date, time = get_cur_adif_dt()
355+
if '*' in qso['QSO_DATE']:
356+
qso['QSO_DATE'] = date
357+
if '*' in qso['TIME_ON']:
358+
qso['TIME_ON'] = time
359+
327360
if self.__edit_pos__ == -1:
328361
self.__qsos__.append(qso)
329362
if qso["CALL"]:
@@ -534,6 +567,8 @@ def evaluate_extended(self, seq: str) -> str:
534567
return ''
535568
self.__my_name__ = seq[2:].replace('_', ' ')
536569
self.__cur_qso__['MY_NAME'] = self.__my_name__
570+
elif seq == '-o':
571+
return self.set_online(not self.is_online())
537572
elif seq.startswith('-N'): # Start contest qso ID
538573
if self.__event__:
539574
self.evaluate_own_event_ref(seq)
@@ -545,6 +580,18 @@ def evaluate_extended(self, seq: str) -> str:
545580
return 'Error: Unknown prefix'
546581
return ''
547582

583+
def set_online(self, state: bool = True) -> str:
584+
self.__online__ = state
585+
date, time = get_cur_adif_dt()
586+
self.__date__ = date
587+
self.__time__ = time
588+
if self.__online__:
589+
self.__date__ += '*'
590+
self.__time__ += '*'
591+
self.__cur_qso__['QSO_DATE'] = self.__date__
592+
self.__cur_qso__['TIME_ON'] = self.__time__
593+
return 'Online mode' if self.is_online() else 'Offline mode'
594+
548595
def evaluate_locator(self, seq: str) -> str:
549596
if seq == '':
550597
self.__cur_qso__.pop('GRIDSQUARE', '')
@@ -631,8 +678,9 @@ def evaluate(self, seq: str) -> str:
631678
else:
632679
self.__cur_qso__['QSL_RCVD'] = 'Y'
633680
elif seq == '=': # Sync date/time to now
634-
self.__date__ = datetime.datetime.utcnow().strftime('%Y%m%d')
635-
self.__time__ = datetime.datetime.utcnow().strftime('%H%M')
681+
date, time = get_cur_adif_dt()
682+
self.__date__ = date
683+
self.__time__ = time
636684
self.__cur_qso__['QSO_DATE'] = self.__date__
637685
self.__cur_qso__['TIME_ON'] = self.__time__
638686
elif seq[0] == '-': # different extended infos and commands

0 commit comments

Comments
 (0)