Skip to content

Commit 0595992

Browse files
authored
Support several multipliers for a QSO (Tlf#442)
* support several multipliers in one QSO as used in CQP * add EU-DX rules
1 parent b419a13 commit 0595992

File tree

13 files changed

+330
-5
lines changed

13 files changed

+330
-5
lines changed

rules/eudx/eudx

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
########################
2+
# EU-DX contest #
3+
########################
4+
# https://www.eudx-contest.com/rules/
5+
#
6+
# Provided by: HA5CQZ
7+
#
8+
CONTEST_MODE
9+
LOGFILE=eudx.log
10+
11+
CABRILLO=UNIVERSAL
12+
CABRILLO-CONTEST=EUDXC
13+
14+
#================================
15+
# Select one of following blocks:
16+
#--------------------------------
17+
#
18+
# non-EU stations send ITU zone
19+
#
20+
#CABRILLO-EXCHANGE=00
21+
#F3=@ ++5NN-- 00
22+
#S&P_TU_MSG=TU ++5NN-- 00
23+
#PLUGIN_CONFIG=DX
24+
#--------------------------------
25+
#
26+
# EU stations send region code
27+
#
28+
CABRILLO-EXCHANGE=XX00
29+
F3=@ ++5NN-- XX00
30+
S&P_TU_MSG=TU ++5NN-- XX00
31+
PLUGIN_CONFIG=IT
32+
#================================
33+
34+
MIXED
35+
36+
# Scoring:
37+
# (handled by eudx.py)
38+
39+
40+
# Multipliers:
41+
# EU regions and DXCC countries per band
42+
# (handled by eudx.py)
43+
GENERIC_MULT=BAND
44+

rules/eudx/eudx.py

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
"""
2+
EU-DX contest
3+
https://www.eudx-contest.com/
4+
"""
5+
import re
6+
7+
MY_COUNTRY = None
8+
MY_PREFIX = None
9+
MY_CONTINENT = None
10+
11+
EU_REGION_PATTERN = re.compile('([A-Z]{2})\d{2}') # two letters and two numbers
12+
13+
EU_COUNTRIES = ['AT', 'BE', 'BG', 'CZ', 'CY', 'HR', 'DK', 'EE',
14+
'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV',
15+
'LT', 'LX', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK',
16+
'SI', 'ES', 'SE']
17+
18+
#
19+
# - EU stations shall provide their ISO_3166-1_alpha-2 country code
20+
# as used in the contest (NOT the DXCC country code)
21+
# - non-EU stations shall use simply DX
22+
#
23+
def init(cfg):
24+
global MY_COUNTRY
25+
if cfg in EU_COUNTRIES:
26+
MY_COUNTRY = cfg
27+
else:
28+
MY_COUNTRY = 'DX' # normalize to DX
29+
30+
dxcc = tlf.get_dxcc(tlf.MY_CALL)
31+
global MY_PREFIX
32+
MY_PREFIX = dxcc.main_prefix
33+
global MY_CONTINENT
34+
MY_CONTINENT = dxcc.continent
35+
36+
37+
# a. European Union stations:
38+
# - your own country 2 points,
39+
# - another European Union country 10 points,
40+
# - with a non-European Union country in your continent 3 points,
41+
# - another continent 5 points.
42+
# b. Non- European Union stations:
43+
# - European Union 10 points,
44+
# - your own country 2 points,
45+
# - a different country in your continent 3 points,
46+
# - another continent 5 points.
47+
def score(qso):
48+
xchg = qso.exchange.strip()
49+
50+
m = EU_REGION_PATTERN.match(xchg)
51+
if m:
52+
eu_country = m.group(1)
53+
else:
54+
eu_country = None
55+
56+
if MY_COUNTRY != 'DX':
57+
if eu_country == MY_COUNTRY:
58+
return 2
59+
if eu_country:
60+
return 10
61+
dxcc = tlf.get_dxcc(qso.call)
62+
if dxcc.continent == MY_CONTINENT:
63+
return 3
64+
else:
65+
return 5
66+
else:
67+
if eu_country:
68+
return 10
69+
dxcc = tlf.get_dxcc(qso.call)
70+
if dxcc.main_prefix == MY_PREFIX:
71+
return 2
72+
if dxcc.continent == MY_CONTINENT:
73+
return 3
74+
else:
75+
return 5
76+
77+
78+
79+
def check_exchange(qso):
80+
xchg = qso.exchange.strip()
81+
dxcc = tlf.get_dxcc(qso.call)
82+
mult = dxcc.main_prefix
83+
84+
if EU_REGION_PATTERN.match(xchg):
85+
mult += ' ' + xchg
86+
87+
return {'mult1_value': mult}

src/addmult.c

+44-3
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,49 @@
3939

4040
GPtrArray *mults_possible;
4141

42+
/*
43+
* process a space separated list of multipliers from qso->mult1_value.
44+
* qso->mult1_value is updated with the list of actually applied new multipliers.
45+
* if none could be applied then it contains an empty string.
46+
*/
47+
static void remember_generic_mult(struct qso_t *qso, bool check_only) {
48+
static GRegex *regex = NULL;
49+
if (regex == NULL) {
50+
// words with trailing space(s) or at the end of string
51+
regex = g_regex_new("(\\S+(\\s+|$))", 0, 0, NULL);
52+
}
53+
54+
GMatchInfo *match_info;
55+
g_regex_match(regex, qso->mult1_value, 0, &match_info);
56+
57+
GString *applied_mults = g_string_new(NULL);
58+
59+
while (g_match_info_matches(match_info)) {
60+
gchar *word = g_match_info_fetch(match_info, 0);
61+
62+
gchar *mult = g_strdup(word);
63+
g_strchomp(mult); // remove trailing whitespace for mult check
64+
65+
int mult_index = remember_multi(mult, qso->bandindex, generic_mult, check_only);
66+
67+
if (mult_index >= 0) {
68+
// aggregate the original value incl. whitespace
69+
g_string_append(applied_mults, word);
70+
}
71+
72+
g_free(mult);
73+
g_free(word);
74+
g_match_info_next(match_info, NULL);
75+
}
76+
77+
g_match_info_free(match_info);
78+
79+
// copy applied_mults to mult1_value
80+
g_free(qso->mult1_value);
81+
qso->mult1_value = g_string_free(applied_mults, FALSE);
82+
83+
}
84+
4285
/*
4386
* \return - index in mults[] array if new mult or new on band
4487
* -1 if not a (new) mult
@@ -74,7 +117,6 @@ static int addmult_internal(struct qso_t *qso, bool check_only) {
74117

75118
// --------------------------- section_mult_once--------------------------
76119
else if (sectn_mult_once) {
77-
78120
/* is it a mult? */
79121
idx = get_exact_mult_index(qso->mult1_value);
80122
if (idx >= 0) {
@@ -118,8 +160,7 @@ static int addmult_internal(struct qso_t *qso, bool check_only) {
118160

119161
// ----------- generic: use mult1 -----------
120162
else if (generic_mult != MULT_NONE) {
121-
mult_index = remember_multi(qso->mult1_value, qso->bandindex, generic_mult,
122-
check_only);
163+
remember_generic_mult(qso, check_only);
123164
}
124165

125166
free(stripped_comment);

src/makelogline.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -290,9 +290,12 @@ void prepare_specific_part(char *logline, struct qso_t *qso) {
290290
new_cty = 0;
291291
}
292292

293+
} else if (generic_mult != MULT_NONE) {
294+
295+
strncat(logline, qso->mult1_value, 9);
296+
293297
} else if (wysiwyg_multi
294298
|| unique_call_multi != MULT_NONE
295-
|| generic_mult != MULT_NONE
296299
|| serial_section_mult
297300
|| sectn_mult
298301
|| sectn_mult_once

src/parse_logcfg.c

-1
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,6 @@ static int cfg_countrylist(const cfg_arg_t arg) {
686686
g_strlcpy(buffer, parameter, buffer_len);
687687
g_strchomp(buffer); /* drop trailing whitespace */
688688

689-
printf("%s\n", buffer);
690689
if ((fp = fopen(buffer, "r")) != NULL) {
691690
char *prefix = g_strdup_printf("%s:", whichcontest);
692691

test/rules/cqp_dx/cqp.log

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
40CW 21-Nov-23 22:34 0001 AB1AAA --- --- 4ELDO ELDO 3
2+
40CW 21-Nov-23 22:34 0002 AB1BBB --- --- 007 ELDO 3
3+
40CW 21-Nov-23 22:35 0003 AB1CCC --- --- 123 KING TULA KING TUL 3
4+
40CW 21-Nov-23 22:36 0004 AB1DDD --- --- 27TULA 3
5+
40CW 21-Nov-23 22:36 0005 AB1EEE --- --- 64ORAN ORAN 3
6+
40SSB 21-Nov-23 22:37 0006 AB1FFF --- --- 8 BUTT BUTT 2
7+
40SSB 21-Nov-23 22:38 0007 AB1GGG --- --- 5 TULA KERN KERN 2

test/rules/cqp_dx/logcfg.dat

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
RULES=cqp
2+
CALL=AB6AAA

test/rules/cqp_dx/rules/cqp

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
########################
2+
#
3+
#
4+
#
5+
########################
6+
#
7+
CONTEST_MODE
8+
LOGFILE=cqp.log
9+
CABRILLO=UNIVERSAL
10+
GENERIC_MULT=BAND
11+
NO_RST
12+
PLUGIN_CONFIG=FL
13+
SSBPOINTS=2
14+
CWPOINTS=3
15+
#
16+
##################################
17+
# #
18+
# Messages F1= to F12= #
19+
# Message CQ_TU_MSG= #
20+
# Message S&P_TU_MSG= #
21+
# #
22+
# % = call #
23+
# @ = hiscall #
24+
# # = serial #
25+
# [ = RST #
26+
# + = increase cw speed #
27+
# - = decrease cw speed #
28+
# #
29+
##################################
30+
#
31+
F1=cq cqp %
32+
F2=@ DE %
33+
F3=# FL
34+
F4=TU
35+
F5=@
36+
F6=%
37+
F7=@ SRI QSO B4 GL
38+
F8=AGN
39+
F9= ?
40+
F10= QRZ?
41+
F11= PSE K
42+
F12=cq cqp %
43+
#
44+
CQ_TU_MSG=TU %
45+
S&P_TU_MSG=# FL
46+
#
47+
#ALT_0=
48+
#ALT_1=
49+
#ALT_2=
50+
#ALT_3=
51+
#ALT_4=
52+
#ALT_5=
53+
#ALT_6=
54+
#ALT_7=
55+
#ALT_8=
56+
#ALT_9=
57+
#
58+
#SEND_DE
59+
#
60+
CABRILLO-QSO-FORMAT=CQP
61+
CABRILLO-EXCHANGE=# FL
62+
CABRILLO-CONTEST=
63+
####### END #####################
64+

test/rules/cqp_dx/rules/cqp.py

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
CQP contest
3+
https://www.cqp.org/
4+
"""
5+
import re
6+
7+
MY_STATE = None
8+
9+
CA_COUNTIES = ['ALAM', 'ALPI', 'AMAD', 'BUTT', 'CALA', 'COLU', 'CCOS', 'DELN',
10+
'ELDO', 'FRES', 'GLEN', 'HUMB', 'IMPE', 'INYO', 'KERN', 'KING', 'LAKE',
11+
'LASS', 'LANG', 'MADE', 'MARN', 'MARP', 'MEND', 'MERC', 'MODO', 'MONO',
12+
'MONT', 'NAPA', 'NEVA', 'ORAN', 'PLAC', 'PLUM', 'RIVE', 'SACR', 'SBEN',
13+
'SBER', 'SDIE', 'SFRA', 'SJOA', 'SLUI', 'SMAT', 'SBAR', 'SCLA', 'SCRU',
14+
'SHAS', 'SIER', 'SISK', 'SOLA', 'SONO', 'STAN', 'SUTT', 'TEHA', 'TRIN',
15+
'TULA', 'TUOL', 'VENT', 'YOLO', 'YUBA']
16+
17+
STATES = ['AL', 'AK', 'AZ', 'AR',
18+
# 'CA' -- The first valid QSO logged with 4-letter county abbreviation will count as the multiplier for California.
19+
'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY',
20+
'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH',
21+
'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD',
22+
'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY',
23+
# Canada
24+
'AB', 'BC', 'MB', 'NB', 'NL', 'NT', 'NS', 'NU', 'ON', 'PE', 'QC', 'SK', 'YT'
25+
]
26+
27+
MULT_PATTERN = re.compile('[A-Z\s]+$') # trailing block of letters and spaces
28+
29+
def init(cfg):
30+
global MY_STATE
31+
MY_STATE = cfg
32+
33+
def check_exchange(qso):
34+
m = MULT_PATTERN.search(qso.exchange)
35+
if m:
36+
parts = m.group(0).split()
37+
else:
38+
parts = []
39+
40+
mult = ''
41+
42+
if MY_STATE == 'CA':
43+
if len(parts) == 0: # no value
44+
pass
45+
elif len(parts) == 1: # single value
46+
part = parts[0]
47+
if part in STATES:
48+
mult = part
49+
elif part in CA_COUNTIES:
50+
mult = 'CA'
51+
else: # multiple values, all must be valid CA counties
52+
ok = True
53+
for part in parts:
54+
if part not in CA_COUNTIES:
55+
ok = False
56+
if ok:
57+
mult = 'CA'
58+
else: # Non-California Station
59+
for part in parts:
60+
if part in CA_COUNTIES:
61+
mult += part + ' '
62+
63+
return {'mult1_value': mult}

test/rules/eudx/eudx.log

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
40CW 31-Jan-24 19:53 0001 OE1AAA 599 599 AT03 OE AT03 10
2+
40CW 31-Jan-24 19:53 0002 OE3BBB 599 599 AT04 AT04 10
3+
40CW 31-Jan-24 19:54 0003 OE5CCC 599 599 AT03 10
4+
40CW 31-Jan-24 19:54 0004 LZ1DDD 599 599 BG01 LZ BG01 10
5+
20CW 31-Jan-24 19:54 0005 LZ2EEE 599 599 BG01 LZ BG01 10
6+
40SSB 31-Jan-24 19:56 0006 LZ1DDD 599 599 BG01 10
7+
40CW 31-Jan-24 19:57 0007 IS9FFF 599 599 IT15 IS IT15 2
8+
40CW 31-Jan-24 19:58 0008 IG9X 599 599 IT17 IG9 IT17 2
9+
40CW 31-Jan-24 19:59 0009 I9QQQ 599 599 IT04 I IT04 2
10+
40CW 31-Jan-24 20:00 0010 K1WWW 599 599 07 K 5
11+
40CW 31-Jan-24 20:01 0011 ER9RRR 599 599 29 ER 3

test/rules/eudx/logcfg.dat

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
RULES=eudx
2+
CALL=IK1AAA

test/rules/eudx/rules/eudx

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../rules/eudx/eudx

test/rules/eudx/rules/eudx.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../rules/eudx/eudx.py

0 commit comments

Comments
 (0)