Skip to content

Commit

Permalink
Support several multipliers for a QSO (#442)
Browse files Browse the repository at this point in the history
* support several multipliers in one QSO as used in CQP

* add EU-DX rules
  • Loading branch information
zcsahok authored Oct 24, 2024
1 parent b419a13 commit 0595992
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 5 deletions.
44 changes: 44 additions & 0 deletions rules/eudx/eudx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
########################
# EU-DX contest #
########################
# https://www.eudx-contest.com/rules/
#
# Provided by: HA5CQZ
#
CONTEST_MODE
LOGFILE=eudx.log

CABRILLO=UNIVERSAL
CABRILLO-CONTEST=EUDXC

#================================
# Select one of following blocks:
#--------------------------------
#
# non-EU stations send ITU zone
#
#CABRILLO-EXCHANGE=00
#F3=@ ++5NN-- 00
#S&P_TU_MSG=TU ++5NN-- 00
#PLUGIN_CONFIG=DX
#--------------------------------
#
# EU stations send region code
#
CABRILLO-EXCHANGE=XX00
F3=@ ++5NN-- XX00
S&P_TU_MSG=TU ++5NN-- XX00
PLUGIN_CONFIG=IT
#================================

MIXED

# Scoring:
# (handled by eudx.py)


# Multipliers:
# EU regions and DXCC countries per band
# (handled by eudx.py)
GENERIC_MULT=BAND

87 changes: 87 additions & 0 deletions rules/eudx/eudx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""
EU-DX contest
https://www.eudx-contest.com/
"""
import re

MY_COUNTRY = None
MY_PREFIX = None
MY_CONTINENT = None

EU_REGION_PATTERN = re.compile('([A-Z]{2})\d{2}') # two letters and two numbers

EU_COUNTRIES = ['AT', 'BE', 'BG', 'CZ', 'CY', 'HR', 'DK', 'EE',
'FI', 'FR', 'DE', 'GR', 'HU', 'IE', 'IT', 'LV',
'LT', 'LX', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK',
'SI', 'ES', 'SE']

#
# - EU stations shall provide their ISO_3166-1_alpha-2 country code
# as used in the contest (NOT the DXCC country code)
# - non-EU stations shall use simply DX
#
def init(cfg):
global MY_COUNTRY
if cfg in EU_COUNTRIES:
MY_COUNTRY = cfg
else:
MY_COUNTRY = 'DX' # normalize to DX

dxcc = tlf.get_dxcc(tlf.MY_CALL)
global MY_PREFIX
MY_PREFIX = dxcc.main_prefix
global MY_CONTINENT
MY_CONTINENT = dxcc.continent


# a. European Union stations:
# - your own country 2 points,
# - another European Union country 10 points,
# - with a non-European Union country in your continent 3 points,
# - another continent 5 points.
# b. Non- European Union stations:
# - European Union 10 points,
# - your own country 2 points,
# - a different country in your continent 3 points,
# - another continent 5 points.
def score(qso):
xchg = qso.exchange.strip()

m = EU_REGION_PATTERN.match(xchg)
if m:
eu_country = m.group(1)
else:
eu_country = None

if MY_COUNTRY != 'DX':
if eu_country == MY_COUNTRY:
return 2
if eu_country:
return 10
dxcc = tlf.get_dxcc(qso.call)
if dxcc.continent == MY_CONTINENT:
return 3
else:
return 5
else:
if eu_country:
return 10
dxcc = tlf.get_dxcc(qso.call)
if dxcc.main_prefix == MY_PREFIX:
return 2
if dxcc.continent == MY_CONTINENT:
return 3
else:
return 5



def check_exchange(qso):
xchg = qso.exchange.strip()
dxcc = tlf.get_dxcc(qso.call)
mult = dxcc.main_prefix

if EU_REGION_PATTERN.match(xchg):
mult += ' ' + xchg

return {'mult1_value': mult}
47 changes: 44 additions & 3 deletions src/addmult.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,49 @@

GPtrArray *mults_possible;

/*
* process a space separated list of multipliers from qso->mult1_value.
* qso->mult1_value is updated with the list of actually applied new multipliers.
* if none could be applied then it contains an empty string.
*/
static void remember_generic_mult(struct qso_t *qso, bool check_only) {
static GRegex *regex = NULL;
if (regex == NULL) {
// words with trailing space(s) or at the end of string
regex = g_regex_new("(\\S+(\\s+|$))", 0, 0, NULL);
}

GMatchInfo *match_info;
g_regex_match(regex, qso->mult1_value, 0, &match_info);

GString *applied_mults = g_string_new(NULL);

while (g_match_info_matches(match_info)) {
gchar *word = g_match_info_fetch(match_info, 0);

gchar *mult = g_strdup(word);
g_strchomp(mult); // remove trailing whitespace for mult check

int mult_index = remember_multi(mult, qso->bandindex, generic_mult, check_only);

if (mult_index >= 0) {
// aggregate the original value incl. whitespace
g_string_append(applied_mults, word);
}

g_free(mult);
g_free(word);
g_match_info_next(match_info, NULL);
}

g_match_info_free(match_info);

// copy applied_mults to mult1_value
g_free(qso->mult1_value);
qso->mult1_value = g_string_free(applied_mults, FALSE);

}

/*
* \return - index in mults[] array if new mult or new on band
* -1 if not a (new) mult
Expand Down Expand Up @@ -74,7 +117,6 @@ static int addmult_internal(struct qso_t *qso, bool check_only) {

// --------------------------- section_mult_once--------------------------
else if (sectn_mult_once) {

/* is it a mult? */
idx = get_exact_mult_index(qso->mult1_value);
if (idx >= 0) {
Expand Down Expand Up @@ -118,8 +160,7 @@ static int addmult_internal(struct qso_t *qso, bool check_only) {

// ----------- generic: use mult1 -----------
else if (generic_mult != MULT_NONE) {
mult_index = remember_multi(qso->mult1_value, qso->bandindex, generic_mult,
check_only);
remember_generic_mult(qso, check_only);
}

free(stripped_comment);
Expand Down
5 changes: 4 additions & 1 deletion src/makelogline.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,9 +290,12 @@ void prepare_specific_part(char *logline, struct qso_t *qso) {
new_cty = 0;
}

} else if (generic_mult != MULT_NONE) {

strncat(logline, qso->mult1_value, 9);

} else if (wysiwyg_multi
|| unique_call_multi != MULT_NONE
|| generic_mult != MULT_NONE
|| serial_section_mult
|| sectn_mult
|| sectn_mult_once
Expand Down
1 change: 0 additions & 1 deletion src/parse_logcfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,6 @@ static int cfg_countrylist(const cfg_arg_t arg) {
g_strlcpy(buffer, parameter, buffer_len);
g_strchomp(buffer); /* drop trailing whitespace */

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

Expand Down
7 changes: 7 additions & 0 deletions test/rules/cqp_dx/cqp.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
40CW 21-Nov-23 22:34 0001 AB1AAA --- --- 4ELDO ELDO 3
40CW 21-Nov-23 22:34 0002 AB1BBB --- --- 007 ELDO 3
40CW 21-Nov-23 22:35 0003 AB1CCC --- --- 123 KING TULA KING TUL 3
40CW 21-Nov-23 22:36 0004 AB1DDD --- --- 27TULA 3
40CW 21-Nov-23 22:36 0005 AB1EEE --- --- 64ORAN ORAN 3
40SSB 21-Nov-23 22:37 0006 AB1FFF --- --- 8 BUTT BUTT 2
40SSB 21-Nov-23 22:38 0007 AB1GGG --- --- 5 TULA KERN KERN 2
2 changes: 2 additions & 0 deletions test/rules/cqp_dx/logcfg.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
RULES=cqp
CALL=AB6AAA
64 changes: 64 additions & 0 deletions test/rules/cqp_dx/rules/cqp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
########################
#
#
#
########################
#
CONTEST_MODE
LOGFILE=cqp.log
CABRILLO=UNIVERSAL
GENERIC_MULT=BAND
NO_RST
PLUGIN_CONFIG=FL
SSBPOINTS=2
CWPOINTS=3
#
##################################
# #
# Messages F1= to F12= #
# Message CQ_TU_MSG= #
# Message S&P_TU_MSG= #
# #
# % = call #
# @ = hiscall #
# # = serial #
# [ = RST #
# + = increase cw speed #
# - = decrease cw speed #
# #
##################################
#
F1=cq cqp %
F2=@ DE %
F3=# FL
F4=TU
F5=@
F6=%
F7=@ SRI QSO B4 GL
F8=AGN
F9= ?
F10= QRZ?
F11= PSE K
F12=cq cqp %
#
CQ_TU_MSG=TU %
S&P_TU_MSG=# FL
#
#ALT_0=
#ALT_1=
#ALT_2=
#ALT_3=
#ALT_4=
#ALT_5=
#ALT_6=
#ALT_7=
#ALT_8=
#ALT_9=
#
#SEND_DE
#
CABRILLO-QSO-FORMAT=CQP
CABRILLO-EXCHANGE=# FL
CABRILLO-CONTEST=
####### END #####################

63 changes: 63 additions & 0 deletions test/rules/cqp_dx/rules/cqp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
CQP contest
https://www.cqp.org/
"""
import re

MY_STATE = None

CA_COUNTIES = ['ALAM', 'ALPI', 'AMAD', 'BUTT', 'CALA', 'COLU', 'CCOS', 'DELN',
'ELDO', 'FRES', 'GLEN', 'HUMB', 'IMPE', 'INYO', 'KERN', 'KING', 'LAKE',
'LASS', 'LANG', 'MADE', 'MARN', 'MARP', 'MEND', 'MERC', 'MODO', 'MONO',
'MONT', 'NAPA', 'NEVA', 'ORAN', 'PLAC', 'PLUM', 'RIVE', 'SACR', 'SBEN',
'SBER', 'SDIE', 'SFRA', 'SJOA', 'SLUI', 'SMAT', 'SBAR', 'SCLA', 'SCRU',
'SHAS', 'SIER', 'SISK', 'SOLA', 'SONO', 'STAN', 'SUTT', 'TEHA', 'TRIN',
'TULA', 'TUOL', 'VENT', 'YOLO', 'YUBA']

STATES = ['AL', 'AK', 'AZ', 'AR',
# 'CA' -- The first valid QSO logged with 4-letter county abbreviation will count as the multiplier for California.
'CO', 'CT', 'DE', 'FL', 'GA', 'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY',
'LA', 'ME', 'MD', 'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH',
'NJ', 'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC', 'SD',
'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY',
# Canada
'AB', 'BC', 'MB', 'NB', 'NL', 'NT', 'NS', 'NU', 'ON', 'PE', 'QC', 'SK', 'YT'
]

MULT_PATTERN = re.compile('[A-Z\s]+$') # trailing block of letters and spaces

def init(cfg):
global MY_STATE
MY_STATE = cfg

def check_exchange(qso):
m = MULT_PATTERN.search(qso.exchange)
if m:
parts = m.group(0).split()
else:
parts = []

mult = ''

if MY_STATE == 'CA':
if len(parts) == 0: # no value
pass
elif len(parts) == 1: # single value
part = parts[0]
if part in STATES:
mult = part
elif part in CA_COUNTIES:
mult = 'CA'
else: # multiple values, all must be valid CA counties
ok = True
for part in parts:
if part not in CA_COUNTIES:
ok = False
if ok:
mult = 'CA'
else: # Non-California Station
for part in parts:
if part in CA_COUNTIES:
mult += part + ' '

return {'mult1_value': mult}
11 changes: 11 additions & 0 deletions test/rules/eudx/eudx.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
40CW 31-Jan-24 19:53 0001 OE1AAA 599 599 AT03 OE AT03 10
40CW 31-Jan-24 19:53 0002 OE3BBB 599 599 AT04 AT04 10
40CW 31-Jan-24 19:54 0003 OE5CCC 599 599 AT03 10
40CW 31-Jan-24 19:54 0004 LZ1DDD 599 599 BG01 LZ BG01 10
20CW 31-Jan-24 19:54 0005 LZ2EEE 599 599 BG01 LZ BG01 10
40SSB 31-Jan-24 19:56 0006 LZ1DDD 599 599 BG01 10
40CW 31-Jan-24 19:57 0007 IS9FFF 599 599 IT15 IS IT15 2
40CW 31-Jan-24 19:58 0008 IG9X 599 599 IT17 IG9 IT17 2
40CW 31-Jan-24 19:59 0009 I9QQQ 599 599 IT04 I IT04 2
40CW 31-Jan-24 20:00 0010 K1WWW 599 599 07 K 5
40CW 31-Jan-24 20:01 0011 ER9RRR 599 599 29 ER 3
2 changes: 2 additions & 0 deletions test/rules/eudx/logcfg.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
RULES=eudx
CALL=IK1AAA
1 change: 1 addition & 0 deletions test/rules/eudx/rules/eudx
1 change: 1 addition & 0 deletions test/rules/eudx/rules/eudx.py

0 comments on commit 0595992

Please sign in to comment.