Adapter behaviour for the first shipped import/export format (one of several — see the hub for siblings DM32, qDMR, CHIRP, …). Column semantics and conversion rules live in the authoritative OpenGD77 reference; per-radio variant limits in radio profiles.
Entity shapes: data model.
OpenGD77 CPS CSV is one interchange format shared by many radios. Import/export adapters are format-level; radio-specific limits (member column counts, feature availability) are profile-level at export time (#72). Today's exporter uses the Baofeng 1701 profile without a profile picker UI.
| Item | Location |
|---|---|
| Import adapter | src/lib/import/opengd77/adapter.ts |
| Import parsers | parse.ts |
| Import headers | columns.ts |
| Export serialisers | src/lib/export/opengd77/ |
detectKind(fileName, headerRow):
| Signal | Result |
|---|---|
Filename contains channel (case-insensitive) |
channels |
Filename contains zone |
zones |
Filename contains contact (not dtmf) |
contacts |
Filename contains tg_list or tg list |
rxGroupLists |
Headers include Contact Name + ID Type |
contacts |
Headers include TG List Name |
rxGroupLists |
Headers include Channel Name + Latitude |
channels |
Headers include Zone Name |
zones |
| Otherwise | unknown → skipped |
Typical filenames: Channels.csv, Zones.csv, Contacts.csv, TG_Lists.csv. DTMF.csv and APRS.csv are skipped on import.
Follows the generic import naming rules. When Home import creates a project (not merge into active):
| User selection | Default project name |
|---|---|
| Folder (Choose folder or drop a directory) | Leaf directory name (e.g. opengd77-cps-export) |
| Loose files (one or more CSVs without folder context) | OpenGD77 YYYY-MM-DD (ISO date, UTC) |
This adapter sets projectNameLabel: 'OpenGD77'; importFiles stamps ImportResult.suggestedProjectName. Operators can rename on Summary later.
| File kind | Parser | Model output |
|---|---|---|
channels |
parseChannels |
Channel[] (wire Channel Number column ignored) |
zones |
parseZones |
ParsedZone[] → resolved to Zone[] with memberChannelIds |
contacts |
parseContacts |
TalkGroup[] + Contact[] |
rxGroupLists |
parseRxGroupLists |
ParsedRxGroupList[] → RxGroupList[] |
Zone member names resolve to channel ids via resolveZoneMembers in codeplug.ts — case-sensitive, first-wins on duplicate channel names.
| Outcome | When |
|---|---|
| Skipped | DTMF.csv, APRS.csv, other unknown files |
| Error | Recognised file fails parse (missing required columns, empty CSV) |
| Recognised | channels, zones, contacts, rxGroupLists |
Full skip/error table: reference hub.
- Per-file download:
Channels.csv,Zones.csv,Contacts.csv,TG_Lists.csv - ZIP: all six CPS files;
DTMF.csvandAPRS.csvare header-only (not modelled) Channel Number: assigned sequentially (1..n in channel list order) when serialisingChannels.csv— not stored in the internal model. Original import numbers are not preserved on round-trip.
Round-trip test: roundtrip.test.ts (semantic model equality). Fidelity tiers: import-export-fidelity-contract.md.
| CPS file | Reference |
|---|---|
Channels.csv |
channels.md |
Zones.csv |
zones.md |
Contacts.csv |
contacts.md |
TG_Lists.csv |
tg-lists.md |
DTMF.csv / APRS.csv |
dtmf-aprs.md |