@@ 1,5 1,5 @@
--
--- Copyright (c) 2022-2024 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
+-- Copyright (c) 2022-2025 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
@@ 25,13 25,6 @@ local ALLOWED_BANDS = {
[6000] = 1,
}
-local dup_table = {}
-local mults = {}
-
-for band, _ in pairs(ALLOWED_BANDS) do
- dup_table[band] = {}
-end
-
local function mkgrid(g)
if g == nil then
return ""
@@ 40,61 33,16 @@ local function mkgrid(g)
return g:sub(1,4)
end
-local function hash(mgrid, tgrid)
- return string.format("%s-%s", mkgrid(mgrid), mkgrid(tgrid))
-end
-
-local function duphash(qso)
- local mgrid = mkgrid(qso.tx.grid)
- local tgrid = mkgrid(qso.rx.grid)
-
+local function duphash(qso, tx, rx)
return string.format("%s-%s-%s-%s",
- mgrid, qso.rx.station_call, tgrid, qso.tx.band)
+ qso.rx.station_call,
+ qso.tx.band,
+ mkgrid(tx),
+ mkgrid(rx))
end
-local function check(band, who, mgrid, tgrid)
- local where = hash(mgrid, tgrid)
- local info = dup_table[band][who]
-
- if info == nil then
- return 1 -- callsign not seen before on this band ==> not dup
- end
-
- if info[where] then
- return 3 -- exact match ==> dup
- end
-
- for cur, _ in pairs(info) do
- if cur:find(where, 1, true) == 1 then
- return 2 -- where is a prefix of cur ==> maybe dup
- end
- end
-
- return 1 -- no prefix found ==> not dup
-end
-
-local function update_dup_table(qso)
- local where = hash(qso.tx.grid, qso.rx.grid)
- local mult = string.format("%u-%s", qso.tx.band, where)
-
- if dup_table[qso.tx.band][qso.rx.station_call] == nil then
- dup_table[qso.tx.band][qso.rx.station_call] = {}
- end
- dup_table[qso.tx.band][qso.rx.station_call][where] = true
-
- mults[mult] = true
-end
-
-local function qso_done(qso)
- if not ALLOWED_BANDS[qso.tx.band] then
- return -- ignore out-of-band contacts
- end
-
- qso.additional['contest-id'] = 'CQ-WW-VHF'
- qso.additional['contest-year'] = contest.year
-
- update_dup_table(qso)
-end
+-- The object keeping all the state
+local vhf
--
-- Annunciator color
@@ 102,31 50,20 @@ end
-- There are three colors we can display: "not a dup", "maybe a dup", and
-- "definitely a dup". When we have full information (i.e., callsign and
-- grid), it is easy to check and return either "not a dup" or "definitely a
--- dup". Things get more complicated when we don't have all the info. In
--- general, we try to do a prefix match with the entered grid square. This
--- allows us to indicate whether or not there is some chance of a dup.
-local function is_dup(qso, band, color_none, color_warn, color_dup)
- local colors = { color_none, color_warn, color_dup }
- local who = qso.rx.station_call
- local where = qso.rx.grid
-
+-- dup". When we don't have full information (i.e., 4-digit grid), we just
+-- warn that it may be a duplicate.
+local function is_dup(qso, color_none, color_warn, color_dup)
--
-- complete information
--
- if where ~= nil and where:len() >= 4 then
- local colors = { color_none, nil, color_dup }
-
- return colors[check(band, who, qso.tx.grid, where)]
+ if qso.rx.grid ~= nil and qso.rx.grid:len() >= 4 then
+ return vhf:is_dup(qso) and color_dup or color_none
end
--
-- incomplete information
--
- if where ~= nil then
- return colors[check(band, who, qso.tx.grid, where)]
- end
-
- return colors[check(band, who, qso.tx.grid, "")]
+ return color_warn
end
local function field_changed(qso, fields, field)
@@ 142,79 79,53 @@ local function field_changed(qso, fields
error(string.format("Unknown field '%s' encountered", field))
end
- if not ALLOWED_BANDS[qso.tx.band] then
- return -- ignore out-of-band contacts
- end
-
return nil, {
- ["2m"] = is_dup(qso, 2000, "green", "magenta", "off"),
- ["6m"] = is_dup(qso, 6000, "green", "magenta", "off"),
- ["DUP"] = is_dup(qso, qso.tx.band, "black", "black", "red"),
+ ["DUP"] = is_dup(qso, "black", "black", "red"),
+ ["OOB"] = ALLOWED_BANDS[qso.tx.band] ~= nil and "black" or "red",
}
end
-local function add_entry(all, dups, qso)
- if qso.additional['contest-id'] ~= "CQ-WW-VHF" or
- qso.additional['contest-year'] ~= contest.year then
- return
+local function qexchange(side, ex)
+ if ex == nil then
+ return "????", false
+ else
+ return mkgrid(ex), true
end
-
- if qso.tx.band == nil then
- print(string.format("Error: %s QSO lacks band info", qso.uuid))
- return
- end
-
- assert(qso.tx.station_call ~= nil)
-
- local dupkey = duphash(qso)
-
- table.insert(all, qso)
- dups[dupkey] = qso
end
-local function mkexchange(side)
- local ok = true
- local out = mkgrid(side.grid)
+local function qpoints(qso, tx, rx)
+ return ALLOWED_BANDS[qso.tx.band]
+end
- if out == "" then
- ok = false
- out = "??"
- end
-
- return out, ok
+local function qmult(qso, tx, rx)
+ return string.format("%u-%s-%s", qso.tx.band, mkgrid(tx), mkgrid(rx))
end
local function export(outfname)
- local all = {}
- local dups = {}
+ local all
+ local station
+ local ops
+ local points
+ local mults
- for qso in hlog.index.history(true) do
- add_entry(all, dups, qso)
- end
+ all, station, ops, points, mults = vhf:export_prep(contest.id, contest.year,
+ qpoints, qmult, qexchange)
- local qpoints = 0
- local mults = {}
- for _, qso in pairs(dups) do
- qpoints = qpoints + ALLOWED_BANDS[qso.tx.band]
- mults[string.format("%s-%s-%s",
- mkgrid(qso.tx.grid),
- mkgrid(qso.rx.grid),
- qso.tx.band)] = true
- end
+ hlog.cabrillo.print_header(contest.id,
+ station,
+ ops:as_array(),
+ points * mults:count_items())
- local score = qpoints * hlog.utils.count_items(mults)
-
- -- TODO: print cabrillo header
-
- for _, qso in ipairs(all) do
- local tx, txok = mkexchange(qso.tx, qso.additional['contest-tx'])
- local rx, rxok = mkexchange(qso.rx, qso.additional['contest-rx'])
- local xqso = not txok or not rxok
+ for _, rec in ipairs(all) do
+ local qso = rec[1]
+ local tx = rec[2]
+ local rx = rec[3]
+ local xqso = not rec[4]
hlog.cabrillo.print_qso(qso, tx, rx, xqso)
end
- -- TODO: print cabrillo footer
+ hlog.cabrillo.print_footer()
end
return {
@@ 231,17 142,20 @@ return {
},
annunciators = {
- { 0, 31, "DUP", "black" },
- { 0, 35, "6m", "black" },
- { 0, 38, "2m", "black" },
+ { 0, 31, "OOB", "black" },
+ { 0, 35, "DUP", "black" },
},
events = {
+ export = export,
startup = function(template)
+ vhf = hlog.contest_helper.grid(contest.id, contest.year, duphash)
+
+ -- load previous contacts from history
for qso in hlog.index.history(true) do
if qso.additional['contest-id'] == 'CQ-WW-VHF' and
qso.additional['contest-year'] == contest.year then
- update_dup_table(qso)
+ vhf:qso_load(qso)
end
end
@@ 255,11 169,14 @@ return {
template.tx.operator_call = op
end,
- export = export,
qso_init = function(qso)
contest.lcd(mkgrid(qso.tx.grid))
end,
- qso_done = qso_done,
+ qso_done = function(qso)
+ if ALLOWED_BANDS[qso.tx.band] then
+ vhf:qso_done(qso)
+ end
+ end,
field_changed = field_changed,
},
}