up
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
package adif
|
||||
|
||||
import "strings"
|
||||
|
||||
// This file embeds the complete ADIF 3.1.7 QSO-field dictionary. It is the
|
||||
// single source of truth for:
|
||||
// - the generic "ADIF fields" editor in the UI (any field becomes editable),
|
||||
// - the "standard ADIF" export mode (only spec fields are emitted),
|
||||
// - import diagnostics (a tag absent here is non-standard / vendor-specific).
|
||||
//
|
||||
// Promoted fields (those with dedicated QSO columns) are flagged Promoted=true
|
||||
// so the UI can hide them from the generic editor — they already have proper
|
||||
// inputs in the main tabs.
|
||||
|
||||
// FieldKind is a coarse input type used by the generic editor to pick a widget.
|
||||
type FieldKind string
|
||||
|
||||
const (
|
||||
KindText FieldKind = "text" // String / IntlString / MultilineString
|
||||
KindNumber FieldKind = "number" // Number / PositiveInteger
|
||||
KindDate FieldKind = "date" // ADIF Date (YYYYMMDD)
|
||||
KindTime FieldKind = "time" // ADIF Time (HHMMSS / HHMM)
|
||||
KindBool FieldKind = "boolean" // Boolean (Y/N)
|
||||
KindEnum FieldKind = "enum" // Enumeration
|
||||
KindLoc FieldKind = "location" // Location (e.g. "N048 09.000")
|
||||
)
|
||||
|
||||
// FieldDef describes one ADIF QSO field.
|
||||
type FieldDef struct {
|
||||
Name string `json:"name"` // canonical uppercase ADIF tag
|
||||
Kind FieldKind `json:"kind"` // editor widget hint
|
||||
Category string `json:"category"` // grouping for the UI
|
||||
Promoted bool `json:"promoted"` // has a dedicated QSO column
|
||||
Deprecated bool `json:"deprecated"` // import-only per the spec
|
||||
Intl bool `json:"intl"` // *_INTL UTF-8 variant
|
||||
}
|
||||
|
||||
// adifVersion is the ADIF spec version OpsLog targets for import/export.
|
||||
const adifVersion = "3.1.7"
|
||||
|
||||
// ADIFVersion returns the ADIF spec version OpsLog conforms to.
|
||||
func ADIFVersion() string { return adifVersion }
|
||||
|
||||
// Fields is the full ADIF 3.1.7 QSO-field set. Order is alphabetical within
|
||||
// each category; categories order is roughly "most-used first" for the UI.
|
||||
var Fields = []FieldDef{
|
||||
// ── Core / contact ──────────────────────────────────────────────
|
||||
{Name: "CALL", Kind: KindText, Category: "Core", Promoted: true},
|
||||
{Name: "QSO_DATE", Kind: KindDate, Category: "Core", Promoted: true},
|
||||
{Name: "TIME_ON", Kind: KindTime, Category: "Core", Promoted: true},
|
||||
{Name: "QSO_DATE_OFF", Kind: KindDate, Category: "Core", Promoted: true},
|
||||
{Name: "TIME_OFF", Kind: KindTime, Category: "Core", Promoted: true},
|
||||
{Name: "BAND", Kind: KindEnum, Category: "Core", Promoted: true},
|
||||
{Name: "BAND_RX", Kind: KindEnum, Category: "Core", Promoted: true},
|
||||
{Name: "MODE", Kind: KindEnum, Category: "Core", Promoted: true},
|
||||
{Name: "SUBMODE", Kind: KindEnum, Category: "Core", Promoted: true},
|
||||
{Name: "FREQ", Kind: KindNumber, Category: "Core", Promoted: true},
|
||||
{Name: "FREQ_RX", Kind: KindNumber, Category: "Core", Promoted: true},
|
||||
{Name: "RST_SENT", Kind: KindText, Category: "Core", Promoted: true},
|
||||
{Name: "RST_RCVD", Kind: KindText, Category: "Core", Promoted: true},
|
||||
{Name: "QSO_COMPLETE", Kind: KindEnum, Category: "Core", Promoted: true},
|
||||
{Name: "QSO_RANDOM", Kind: KindBool, Category: "Core", Promoted: true},
|
||||
{Name: "SWL", Kind: KindBool, Category: "Core", Promoted: true},
|
||||
|
||||
// ── Contacted station ───────────────────────────────────────────
|
||||
{Name: "NAME", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "NAME_INTL", Kind: KindText, Category: "Contacted", Intl: true},
|
||||
{Name: "QTH", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "QTH_INTL", Kind: KindText, Category: "Contacted", Intl: true},
|
||||
{Name: "ADDRESS", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "ADDRESS_INTL", Kind: KindText, Category: "Contacted", Intl: true},
|
||||
{Name: "EMAIL", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "WEB", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "GRIDSQUARE", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "GRIDSQUARE_EXT", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "VUCC_GRIDS", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "COUNTRY", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "COUNTRY_INTL", Kind: KindText, Category: "Contacted", Intl: true},
|
||||
{Name: "STATE", Kind: KindEnum, Category: "Contacted", Promoted: true},
|
||||
{Name: "CNTY", Kind: KindEnum, Category: "Contacted", Promoted: true},
|
||||
{Name: "CNTY_ALT", Kind: KindEnum, Category: "Contacted"},
|
||||
{Name: "DXCC", Kind: KindEnum, Category: "Contacted", Promoted: true},
|
||||
{Name: "CONT", Kind: KindEnum, Category: "Contacted", Promoted: true},
|
||||
{Name: "CQZ", Kind: KindNumber, Category: "Contacted", Promoted: true},
|
||||
{Name: "ITUZ", Kind: KindNumber, Category: "Contacted", Promoted: true},
|
||||
{Name: "IOTA", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "IOTA_ISLAND_ID", Kind: KindText, Category: "Contacted"},
|
||||
{Name: "REGION", Kind: KindEnum, Category: "Contacted", Promoted: true},
|
||||
{Name: "PFX", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "AGE", Kind: KindNumber, Category: "Contacted", Promoted: true},
|
||||
{Name: "LAT", Kind: KindLoc, Category: "Contacted", Promoted: true},
|
||||
{Name: "LON", Kind: KindLoc, Category: "Contacted", Promoted: true},
|
||||
{Name: "ALTITUDE", Kind: KindNumber, Category: "Contacted"},
|
||||
{Name: "DISTANCE", Kind: KindNumber, Category: "Contacted", Promoted: true},
|
||||
{Name: "RIG", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "RIG_INTL", Kind: KindText, Category: "Contacted", Intl: true},
|
||||
{Name: "ANT", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "CONTACTED_OP", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "EQ_CALL", Kind: KindText, Category: "Contacted", Promoted: true},
|
||||
{Name: "GUEST_OP", Kind: KindText, Category: "Contacted", Deprecated: true},
|
||||
{Name: "OWNER_CALLSIGN", Kind: KindText, Category: "Contacted"},
|
||||
{Name: "SILENT_KEY", Kind: KindBool, Category: "Contacted", Promoted: true},
|
||||
{Name: "USACA_COUNTIES", Kind: KindText, Category: "Contacted"},
|
||||
|
||||
// ── Special activity (POTA/SOTA/WWFF/SIG) ───────────────────────
|
||||
{Name: "SIG", Kind: KindText, Category: "Activity", Promoted: true},
|
||||
{Name: "SIG_INFO", Kind: KindText, Category: "Activity", Promoted: true},
|
||||
{Name: "SIG_INTL", Kind: KindText, Category: "Activity", Intl: true},
|
||||
{Name: "SIG_INFO_INTL", Kind: KindText, Category: "Activity", Intl: true},
|
||||
{Name: "POTA_REF", Kind: KindText, Category: "Activity", Promoted: true},
|
||||
{Name: "SOTA_REF", Kind: KindText, Category: "Activity", Promoted: true},
|
||||
{Name: "WWFF_REF", Kind: KindText, Category: "Activity", Promoted: true},
|
||||
|
||||
// ── Power / propagation / space wx ──────────────────────────────
|
||||
{Name: "TX_PWR", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "RX_PWR", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "A_INDEX", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "K_INDEX", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "SFI", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "PROP_MODE", Kind: KindEnum, Category: "Propagation", Promoted: true},
|
||||
{Name: "SAT_NAME", Kind: KindText, Category: "Propagation", Promoted: true},
|
||||
{Name: "SAT_MODE", Kind: KindText, Category: "Propagation", Promoted: true},
|
||||
{Name: "ANT_AZ", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "ANT_EL", Kind: KindNumber, Category: "Propagation", Promoted: true},
|
||||
{Name: "ANT_PATH", Kind: KindEnum, Category: "Propagation", Promoted: true},
|
||||
{Name: "FORCE_INIT", Kind: KindBool, Category: "Propagation"},
|
||||
{Name: "MAX_BURSTS", Kind: KindNumber, Category: "Propagation"},
|
||||
{Name: "MS_SHOWER", Kind: KindText, Category: "Propagation"},
|
||||
{Name: "NR_BURSTS", Kind: KindNumber, Category: "Propagation"},
|
||||
{Name: "NR_PINGS", Kind: KindNumber, Category: "Propagation"},
|
||||
|
||||
// ── QSL / confirmations ─────────────────────────────────────────
|
||||
{Name: "QSL_SENT", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "QSL_RCVD", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "QSLSDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "QSLRDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "QSL_VIA", Kind: KindText, Category: "QSL", Promoted: true},
|
||||
{Name: "QSL_SENT_VIA", Kind: KindEnum, Category: "QSL"},
|
||||
{Name: "QSL_RCVD_VIA", Kind: KindEnum, Category: "QSL"},
|
||||
{Name: "QSLMSG", Kind: KindText, Category: "QSL", Promoted: true},
|
||||
{Name: "QSLMSG_INTL", Kind: KindText, Category: "QSL", Intl: true},
|
||||
{Name: "QSLMSG_RCVD", Kind: KindText, Category: "QSL", Promoted: true},
|
||||
{Name: "LOTW_QSL_SENT", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "LOTW_QSL_RCVD", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "LOTW_QSLSDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "LOTW_QSLRDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "EQSL_QSL_SENT", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "EQSL_QSL_RCVD", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "EQSL_QSLSDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "EQSL_QSLRDATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "EQSL_AG", Kind: KindBool, Category: "QSL"},
|
||||
{Name: "DCL_QSL_SENT", Kind: KindEnum, Category: "QSL"},
|
||||
{Name: "DCL_QSL_RCVD", Kind: KindEnum, Category: "QSL"},
|
||||
{Name: "DCL_QSLSDATE", Kind: KindDate, Category: "QSL"},
|
||||
{Name: "DCL_QSLRDATE", Kind: KindDate, Category: "QSL"},
|
||||
{Name: "CLUBLOG_QSO_UPLOAD_DATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "CLUBLOG_QSO_UPLOAD_STATUS", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "HRDLOG_QSO_UPLOAD_DATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "HRDLOG_QSO_UPLOAD_STATUS", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "QRZCOM_QSO_UPLOAD_DATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "QRZCOM_QSO_UPLOAD_STATUS", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "QRZCOM_QSO_DOWNLOAD_DATE", Kind: KindDate, Category: "QSL", Promoted: true},
|
||||
{Name: "QRZCOM_QSO_DOWNLOAD_STATUS", Kind: KindEnum, Category: "QSL", Promoted: true},
|
||||
{Name: "HAMLOGEU_QSO_UPLOAD_DATE", Kind: KindDate, Category: "QSL"},
|
||||
{Name: "HAMLOGEU_QSO_UPLOAD_STATUS", Kind: KindEnum, Category: "QSL"},
|
||||
{Name: "HAMQTH_QSO_UPLOAD_DATE", Kind: KindDate, Category: "QSL"},
|
||||
{Name: "HAMQTH_QSO_UPLOAD_STATUS", Kind: KindEnum, Category: "QSL"},
|
||||
|
||||
// ── Awards / credits ────────────────────────────────────────────
|
||||
{Name: "CREDIT_SUBMITTED", Kind: KindText, Category: "Awards", Promoted: true},
|
||||
{Name: "CREDIT_GRANTED", Kind: KindText, Category: "Awards", Promoted: true},
|
||||
{Name: "AWARD_SUBMITTED", Kind: KindText, Category: "Awards"},
|
||||
{Name: "AWARD_GRANTED", Kind: KindText, Category: "Awards"},
|
||||
|
||||
// ── Contest ─────────────────────────────────────────────────────
|
||||
{Name: "CONTEST_ID", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "SRX", Kind: KindNumber, Category: "Contest", Promoted: true},
|
||||
{Name: "STX", Kind: KindNumber, Category: "Contest", Promoted: true},
|
||||
{Name: "SRX_STRING", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "STX_STRING", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "CHECK", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "CLASS", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "PRECEDENCE", Kind: KindText, Category: "Contest", Promoted: true},
|
||||
{Name: "ARRL_SECT", Kind: KindEnum, Category: "Contest", Promoted: true},
|
||||
|
||||
// ── Club memberships ────────────────────────────────────────────
|
||||
{Name: "SKCC", Kind: KindText, Category: "Clubs", Promoted: true},
|
||||
{Name: "FISTS", Kind: KindNumber, Category: "Clubs", Promoted: true},
|
||||
{Name: "FISTS_CC", Kind: KindNumber, Category: "Clubs"},
|
||||
{Name: "TEN_TEN", Kind: KindNumber, Category: "Clubs", Promoted: true},
|
||||
{Name: "UKSMG", Kind: KindNumber, Category: "Clubs"},
|
||||
{Name: "DARC_DOK", Kind: KindText, Category: "Clubs", Promoted: true},
|
||||
|
||||
// ── Morse key (3.1.5+) ──────────────────────────────────────────
|
||||
{Name: "MORSE_KEY_TYPE", Kind: KindEnum, Category: "Morse key"},
|
||||
{Name: "MORSE_KEY_INFO", Kind: KindText, Category: "Morse key"},
|
||||
|
||||
// ── Misc / crypto ───────────────────────────────────────────────
|
||||
{Name: "COMMENT", Kind: KindText, Category: "Misc", Promoted: true},
|
||||
{Name: "COMMENT_INTL", Kind: KindText, Category: "Misc", Intl: true},
|
||||
{Name: "NOTES", Kind: KindText, Category: "Misc", Promoted: true},
|
||||
{Name: "NOTES_INTL", Kind: KindText, Category: "Misc", Intl: true},
|
||||
{Name: "PUBLIC_KEY", Kind: KindText, Category: "Misc"},
|
||||
{Name: "VE_PROV", Kind: KindText, Category: "Misc", Deprecated: true},
|
||||
|
||||
// ── My station / operator ───────────────────────────────────────
|
||||
{Name: "STATION_CALLSIGN", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "OPERATOR", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_NAME", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_NAME_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_GRIDSQUARE", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_GRIDSQUARE_EXT", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_VUCC_GRIDS", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_COUNTRY", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_COUNTRY_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_STATE", Kind: KindEnum, Category: "My station", Promoted: true},
|
||||
{Name: "MY_CNTY", Kind: KindEnum, Category: "My station", Promoted: true},
|
||||
{Name: "MY_CNTY_ALT", Kind: KindEnum, Category: "My station"},
|
||||
{Name: "MY_DXCC", Kind: KindEnum, Category: "My station", Promoted: true},
|
||||
{Name: "MY_CQ_ZONE", Kind: KindNumber, Category: "My station", Promoted: true},
|
||||
{Name: "MY_ITU_ZONE", Kind: KindNumber, Category: "My station", Promoted: true},
|
||||
{Name: "MY_IOTA", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_IOTA_ISLAND_ID", Kind: KindText, Category: "My station"},
|
||||
{Name: "MY_SOTA_REF", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_POTA_REF", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_WWFF_REF", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_SIG", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_SIG_INFO", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_SIG_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_SIG_INFO_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_LAT", Kind: KindLoc, Category: "My station", Promoted: true},
|
||||
{Name: "MY_LON", Kind: KindLoc, Category: "My station", Promoted: true},
|
||||
{Name: "MY_ALTITUDE", Kind: KindNumber, Category: "My station"},
|
||||
{Name: "MY_STREET", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_STREET_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_CITY", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_CITY_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_POSTAL_CODE", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_POSTAL_CODE_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_RIG", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_RIG_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_ANTENNA", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_ANTENNA_INTL", Kind: KindText, Category: "My station", Intl: true},
|
||||
{Name: "MY_ARRL_SECT", Kind: KindEnum, Category: "My station", Promoted: true},
|
||||
{Name: "MY_USACA_COUNTIES", Kind: KindText, Category: "My station"},
|
||||
{Name: "MY_DARC_DOK", Kind: KindText, Category: "My station", Promoted: true},
|
||||
{Name: "MY_FISTS", Kind: KindNumber, Category: "My station"},
|
||||
{Name: "MY_MORSE_KEY_TYPE", Kind: KindEnum, Category: "My station"},
|
||||
{Name: "MY_MORSE_KEY_INFO", Kind: KindText, Category: "My station"},
|
||||
}
|
||||
|
||||
// fieldIndex maps an uppercase ADIF tag to its definition for O(1) lookup.
|
||||
var fieldIndex = func() map[string]FieldDef {
|
||||
m := make(map[string]FieldDef, len(Fields))
|
||||
for _, f := range Fields {
|
||||
m[f.Name] = f
|
||||
}
|
||||
return m
|
||||
}()
|
||||
|
||||
// IsStandardField reports whether tag (any case) is a defined ADIF 3.1.7
|
||||
// field. APP_* and USERDEF tags are non-standard and return false.
|
||||
func IsStandardField(tag string) bool {
|
||||
_, ok := fieldIndex[strings.ToUpper(strings.TrimSpace(tag))]
|
||||
return ok
|
||||
}
|
||||
|
||||
// LookupField returns the definition for a tag (any case), ok=false if unknown.
|
||||
func LookupField(tag string) (FieldDef, bool) {
|
||||
f, ok := fieldIndex[strings.ToUpper(strings.TrimSpace(tag))]
|
||||
return f, ok
|
||||
}
|
||||
Reference in New Issue
Block a user