Compare commits
2 Commits
dde80e5696
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| ec4af751cd | |||
| 6ca18411cf |
@@ -1,62 +0,0 @@
|
|||||||
# Next Steps
|
|
||||||
|
|
||||||
## Priority
|
|
||||||
|
|
||||||
1. Investigate Protocol 2 stop handling.
|
|
||||||
2. Complete Protocol 2 Alex support for boards with `Alex1`.
|
|
||||||
3. Continue UI cleanup for Protocol 2 specific hardware presentation.
|
|
||||||
|
|
||||||
## Immediate Issues To Debug
|
|
||||||
|
|
||||||
### Protocol 2 stop crash
|
|
||||||
|
|
||||||
- Re-test why the application crashes when the user presses `Stop` while working with a Protocol 2 device.
|
|
||||||
- Re-verify why the Protocol 2 stop command may still not be correctly sent to the transceiver.
|
|
||||||
- Check the shutdown path across:
|
|
||||||
- `src/DataEngine/cusdr_dataEngine.cpp`
|
|
||||||
- `src/DataEngine/cusdr_dataIO.cpp`
|
|
||||||
- `src/DataEngine/cusdr_protocol2_io.cpp`
|
|
||||||
- Already fixed one likely cause in `src/DataEngine/cusdr_protocol2_io.cpp`:
|
|
||||||
- duplicate `P2 stop` send,
|
|
||||||
- stop without `m_running`,
|
|
||||||
- timer/socket signal disconnect before deletion.
|
|
||||||
- Already fixed a second class of issues in `src/DataEngine/cusdr_dataEngine.cpp`:
|
|
||||||
- `DataIO` control calls now go through `QMetaObject::invokeMethod(..., Qt::BlockingQueuedConnection)`,
|
|
||||||
- so start/stop/init execute in the `DataIO` thread instead of the caller thread.
|
|
||||||
- Already fixed a concrete `Protocol 2` destructor bug in `src/DataEngine/cusdr_dataIO.cpp`:
|
|
||||||
- `m_dataIOSocketOn == true` with `m_dataIOSocket == 0` could dereference a null pointer during shutdown.
|
|
||||||
- Already moved `CSoundOut` deletion out of `DataIO::stop()` and into the destructor to reduce timer/thread teardown issues.
|
|
||||||
- Pay special attention to:
|
|
||||||
- socket lifetime,
|
|
||||||
- timer lifetime,
|
|
||||||
- `QObject` ownership and deletion thread,
|
|
||||||
- repeated stop calls,
|
|
||||||
- `networkDeviceStartStop(0)`,
|
|
||||||
- `Protocol2DataPath::stop()`,
|
|
||||||
- `sendHighPriorityPacket(false)`,
|
|
||||||
- whether the command socket is still valid when stop is triggered,
|
|
||||||
- whether `DataIO` / `Protocol2DataPath` should be destroyed via `deleteLater()` in their own thread instead of direct delete from `DataEngine`,
|
|
||||||
- whether the target `P2` board expects additional shutdown packets or repeated `run = 0` frames.
|
|
||||||
|
|
||||||
## Protocol 2 Functional Work
|
|
||||||
|
|
||||||
- Implement proper `Alex1/BPF2/RX2` handling for boards that support a second Alex register:
|
|
||||||
- Orion MkII
|
|
||||||
- SATURN / ANAN-G2
|
|
||||||
- Use Appendix D from `doc/openHPSDR Ethernet Protocol v4.3.docx` to map the second Alex register bits correctly.
|
|
||||||
- Consider extending Protocol 2 capability handling beyond board defaults where discovery returns more precise information.
|
|
||||||
- Consider support for XML/full hardware description discovery replies for board `254/255`.
|
|
||||||
|
|
||||||
## UI Work
|
|
||||||
|
|
||||||
- Review UI areas that still assume `Metis/Hermes` semantics internally.
|
|
||||||
- Make Protocol 2 model/capability presentation more explicit where useful:
|
|
||||||
- selected model,
|
|
||||||
- protocol version,
|
|
||||||
- ADC/DDC count,
|
|
||||||
- Alex availability.
|
|
||||||
|
|
||||||
## Reference
|
|
||||||
|
|
||||||
- Detailed log of completed work:
|
|
||||||
- `WORKLOG_PROTOCOL2_2026-04-13.md`
|
|
||||||
@@ -1,187 +0,0 @@
|
|||||||
# cudaSDR Protocol 2 Worklog
|
|
||||||
|
|
||||||
Date: 2026-04-13
|
|
||||||
|
|
||||||
This file records the Protocol 2 related work completed in this repository so future sessions can quickly restore context.
|
|
||||||
|
|
||||||
## Implemented Earlier In This Session History
|
|
||||||
|
|
||||||
- Added separate openHPSDR Protocol 2 transport implementation:
|
|
||||||
- `src/DataEngine/cusdr_protocol2_io.h`
|
|
||||||
- `src/DataEngine/cusdr_protocol2_io.cpp`
|
|
||||||
- Added separate Protocol 2 discovery implementation:
|
|
||||||
- `src/DataEngine/cusdr_discoverer_P2.h`
|
|
||||||
- `src/DataEngine/cusdr_discoverer_P2.cpp`
|
|
||||||
- Wired Protocol 2 into the existing project flow without replacing Protocol 1.
|
|
||||||
- Updated `DataIO` so it delegates network start/stop and receive path to the separate Protocol 2 module when the selected device reports `protocolVersion >= 2`.
|
|
||||||
- Added Protocol 2 fallback search after Protocol 1 and fixed the `Search` button path so manual search also tries Protocol 2.
|
|
||||||
- Added initial RX-only Alex support for Protocol 2:
|
|
||||||
- General packet enables Alex.
|
|
||||||
- High Priority packet sends `Alex 0`.
|
|
||||||
- Filters switch automatically by band/frequency using existing Alex settings.
|
|
||||||
|
|
||||||
## Implemented Today
|
|
||||||
|
|
||||||
### 1. Device capability model for Protocol 2
|
|
||||||
|
|
||||||
- Extended `TNetworkDevicecard` in `src/cusdr_settings.h` with Protocol 2 specific fields:
|
|
||||||
- `adcCount`
|
|
||||||
- `ddcCount`
|
|
||||||
- `dspClockHz`
|
|
||||||
- `iqFormatFlags`
|
|
||||||
- `phaseWords`
|
|
||||||
- `hasAlex0`
|
|
||||||
- `hasAlex1`
|
|
||||||
|
|
||||||
### 2. Separate board profile helper
|
|
||||||
|
|
||||||
- Added:
|
|
||||||
- `src/DataEngine/cusdr_protocol2_profile.h`
|
|
||||||
- `src/DataEngine/cusdr_protocol2_profile.cpp`
|
|
||||||
- This helper maps Protocol 2 board ID to default hardware capabilities and human-readable model name.
|
|
||||||
- It also provides a summary string for UI device lists.
|
|
||||||
|
|
||||||
### 3. Discovery improvements for Protocol 2
|
|
||||||
|
|
||||||
- Updated `src/DataEngine/cusdr_discoverer_P2.cpp` to:
|
|
||||||
- use board profiles,
|
|
||||||
- fill the new capability fields in `TNetworkDevicecard`,
|
|
||||||
- parse extra discovery reply fields from the documentation:
|
|
||||||
- byte 20: number of implemented DDCs,
|
|
||||||
- byte 21: frequency vs phase word,
|
|
||||||
- byte 22: supported IQ/endian formats.
|
|
||||||
- Updated `src/DataEngine/cusdr_discoverer_P1.cpp` to initialize the new fields to safe defaults for Protocol 1 devices.
|
|
||||||
|
|
||||||
### 4. Protocol 2 initialization based on actual device profile
|
|
||||||
|
|
||||||
- Updated `src/DataEngine/cusdr_protocol2_io.cpp`:
|
|
||||||
- fixed General packet bit handling,
|
|
||||||
- enabled phase-word mode where required,
|
|
||||||
- selected IQ format only when the discovery flags say it is supported,
|
|
||||||
- used discovered/default ADC count in the DDC Specific packet,
|
|
||||||
- routed DDCs across ADCs,
|
|
||||||
- limited receiver count to hardware DDC count,
|
|
||||||
- used board DSP clock to compute phase words,
|
|
||||||
- preserved RX-only behavior.
|
|
||||||
|
|
||||||
### 5. Data engine behavior for Protocol 2 devices
|
|
||||||
|
|
||||||
- Updated `src/DataEngine/cusdr_dataEngine.cpp` so Protocol 2 devices:
|
|
||||||
- are treated as modern integrated hardware instead of legacy Mercury/Penelope stacks,
|
|
||||||
- automatically clamp receiver count to discovered DDC count,
|
|
||||||
- publish Hermes firmware field from the Protocol 2 discovery result for existing UI/status paths,
|
|
||||||
- enable Alex UI only if the selected Protocol 2 board profile says Alex is present.
|
|
||||||
|
|
||||||
### 6. UI modernization for Protocol 2 devices
|
|
||||||
|
|
||||||
- Updated `src/cusdr_networkWidget.cpp` so the device list shows a summary instead of only IP address.
|
|
||||||
- Updated `src/GL/cusdr_oglDisplayPanel.h` and `src/GL/cusdr_oglDisplayPanel.cpp` so the top status display uses the real Protocol 2 model name instead of always showing `Hermes`.
|
|
||||||
|
|
||||||
### 7. Documentation-driven corrections made today
|
|
||||||
|
|
||||||
- Re-read local documentation:
|
|
||||||
- `doc/openHPSDR Ethernet Protocol v4.3.docx`
|
|
||||||
- Corrected Protocol 2 board naming and assumptions from the document:
|
|
||||||
- board 1: `Hermes / ANAN-10/100`
|
|
||||||
- board 2: `Hermes / ANAN-10E/100B`
|
|
||||||
- board 5: `Orion MkII / ANAN-7/8000DLE`
|
|
||||||
- board 10: `Saturn / ANAN-G2`
|
|
||||||
- Corrected one important capability assumption:
|
|
||||||
- board 2 no longer auto-enables Alex RX support, because the document indicates no Alex receive filters for that board.
|
|
||||||
|
|
||||||
## Build Status
|
|
||||||
|
|
||||||
- Full build completed successfully:
|
|
||||||
- `make -j4`
|
|
||||||
- Output binary:
|
|
||||||
- `bin/cudaSDR`
|
|
||||||
|
|
||||||
## Additional Fix Applied Later Today
|
|
||||||
|
|
||||||
### Protocol 2 stop path hardening
|
|
||||||
|
|
||||||
- Investigated the stop path after a reported crash when pressing `Stop` with a Protocol 2 device.
|
|
||||||
- Confirmed that the shutdown flow was effectively hitting Protocol 2 stop twice:
|
|
||||||
- first through `DataEngine::stop() -> DataIO::networkDeviceStartStop(0)`,
|
|
||||||
- then again through `DataIO::stop() -> Protocol2DataPath::stop()`.
|
|
||||||
- Updated `src/DataEngine/cusdr_protocol2_io.cpp` so that:
|
|
||||||
- `Protocol2DataPath::stop()` only sends the final `run = 0` High Priority packet if the path was actually running,
|
|
||||||
- `networkDeviceStartStop(0)` returns immediately if Protocol 2 is already stopped,
|
|
||||||
- `closeSockets()` explicitly disconnects timer and socket signals before deletion.
|
|
||||||
- This removes the most obvious duplicate-stop race and reduces the chance of a timer/socket callback firing during teardown.
|
|
||||||
- Build was re-checked after this fix:
|
|
||||||
- `make -j4`
|
|
||||||
- success
|
|
||||||
|
|
||||||
### Still needs runtime verification
|
|
||||||
|
|
||||||
- This stop-path fix is compile-verified but still needs validation on real Protocol 2 hardware.
|
|
||||||
- If the transceiver still does not stop cleanly, the next thing to verify is whether the specific board expects more than a single `High Priority run = 0` packet before socket teardown.
|
|
||||||
|
|
||||||
## Additional Investigation And Fixes After Emulator Testing
|
|
||||||
|
|
||||||
### 1. Cross-thread DataIO control calls
|
|
||||||
|
|
||||||
- Emulator testing showed that Protocol 2 startup and shutdown were still unreliable.
|
|
||||||
- Investigation found that `DataIO` is moved to its own `QThread`, but `DataEngine` was still calling these methods directly from another thread:
|
|
||||||
- `sendInitFramesToNetworkDevice(...)`
|
|
||||||
- `networkDeviceStartStop(...)`
|
|
||||||
- `stop()`
|
|
||||||
- Updated `src/DataEngine/cusdr_dataEngine.cpp` to route those calls through:
|
|
||||||
- `QMetaObject::invokeMethod(..., Qt::BlockingQueuedConnection)`
|
|
||||||
- This was done so the Protocol 2 sockets and timers are manipulated from the `DataIO` thread they belong to.
|
|
||||||
|
|
||||||
### 2. Additional Protocol 2 stop crash findings
|
|
||||||
|
|
||||||
- User logs then showed:
|
|
||||||
- `QObject::killTimer: Timers cannot be stopped from another thread`
|
|
||||||
- `QObject::~QObject: Timers cannot be stopped from another thread`
|
|
||||||
- `DataEngine:: data IO thread not yet finished...`
|
|
||||||
- This indicated there were still object-lifetime issues during teardown, not only packet-order issues.
|
|
||||||
|
|
||||||
### 3. DataIO destructor bug in Protocol 2 mode
|
|
||||||
|
|
||||||
- Found a concrete bug in `src/DataEngine/cusdr_dataIO.cpp`:
|
|
||||||
- in Protocol 2 mode, `m_dataIOSocketOn` can be true while `m_dataIOSocket` is never created,
|
|
||||||
- but `DataIO::~DataIO()` still dereferenced `m_dataIOSocket`.
|
|
||||||
- Fixed destructor logic so the legacy socket is only closed/deleted when the pointer is valid.
|
|
||||||
- This was a direct segfault candidate in Protocol 2 shutdown.
|
|
||||||
|
|
||||||
### 4. Sound output teardown issue
|
|
||||||
|
|
||||||
- Found that `DataIO::stop()` was stopping and deleting `CSoundOut` while Protocol 2 shutdown was already in progress.
|
|
||||||
- Adjusted `src/DataEngine/cusdr_dataIO.cpp` so:
|
|
||||||
- `DataIO::stop()` no longer deletes the sound object,
|
|
||||||
- `CSoundOut` shutdown is deferred to `DataIO::~DataIO()`.
|
|
||||||
- This was done to reduce cross-thread/timer teardown problems during the live stop sequence.
|
|
||||||
|
|
||||||
### Current status after these fixes
|
|
||||||
|
|
||||||
- Build re-checked successfully after each change:
|
|
||||||
- `make -j4`
|
|
||||||
- Protocol 2 stop handling is more robust than before, but user testing still shows there may be at least one remaining shutdown/lifetime issue.
|
|
||||||
- Most likely next area:
|
|
||||||
- final deletion order of `DataIO` / `Protocol2DataPath` and their child `QObject`s after `m_dataIOThread->quit()`.
|
|
||||||
|
|
||||||
## Known Limitations / Remaining Work
|
|
||||||
|
|
||||||
- Protocol 2 implementation is still RX-only.
|
|
||||||
- Protocol 2 Alex support currently sends `Alex 0` only.
|
|
||||||
- Boards with `Alex1` support such as Orion MkII / SATURN are not yet fully mapped to the second Alex register according to Appendix D.
|
|
||||||
- Full XML or extended hardware-description discovery modes (`board 254/255`) are not implemented.
|
|
||||||
- Wideband Protocol 2 path is still not integrated.
|
|
||||||
- Some UI sections still conceptually assume old `Metis/Hermes` naming internally even though the visible device/model handling is now better.
|
|
||||||
|
|
||||||
## Good Starting Points For Next Session
|
|
||||||
|
|
||||||
- If continuing Protocol 2 work, read these files first:
|
|
||||||
- `src/DataEngine/cusdr_protocol2_profile.cpp`
|
|
||||||
- `src/DataEngine/cusdr_discoverer_P2.cpp`
|
|
||||||
- `src/DataEngine/cusdr_protocol2_io.cpp`
|
|
||||||
- `src/DataEngine/cusdr_dataEngine.cpp`
|
|
||||||
- `src/cusdr_networkWidget.cpp`
|
|
||||||
- `src/GL/cusdr_oglDisplayPanel.cpp`
|
|
||||||
- For documentation reference, use:
|
|
||||||
- `doc/openHPSDR Ethernet Protocol v4.3.docx`
|
|
||||||
- Highest value next task:
|
|
||||||
- implement proper `Alex1/BPF2/RX2` handling for Protocol 2 boards that support a second Alex register.
|
|
||||||
+1689
-1692
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,3 @@
|
|||||||
[General]
|
[General]
|
||||||
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\0\0\0\x5@\0\0\x3\x1b\0\0\0\0\0\0\0\x1c\0\0\x5@\0\0\x3\x1b\0\0\0\0\0\0\0\0\n\0\0\0\0\0\0\0\0\x1c\0\0\x5@\0\0\x3\x1b)
|
geometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\x5\x36\0\0\0\x37\0\0\t\xb2\0\0\x2\xaa\0\0\x5\x36\0\0\0S\0\0\t\xb2\0\0\x2\xaa\0\0\0\0\0\0\0\0\n\0\0\0\x5\x36\0\0\0S\0\0\t\xb2\0\0\x2\xaa)
|
||||||
windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\0\xf5\0\0\x2<\xfc\x2\0\0\0\x5\xfb\0\0\0\x12\0R\0\x61\0\x64\0i\0o\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x14\0S\0\x65\0r\0v\0\x65\0r\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x12\0H\0P\0S\0\x44\0R\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x12\0\x43\0h\0i\0r\0p\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x16\0\x44\0i\0s\0p\0l\0\x61\0y\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\0\0\x5\x41\0\0\x2<\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\xa5\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\x1\0\0\0\x18\0\x44\0i\0s\0p\0l\0\x61\0y\0P\0\x61\0n\0\x65\0l\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x2\0\0\0\x1\0\0\0\x16\0M\0\x61\0i\0n\0\x42\0u\0t\0t\0o\0n\0s\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
|
windowState="@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x1\0\0\0\x1\0\0\0\xf5\0\0\x3,\xfc\x2\0\0\0\x5\xfb\0\0\0\x12\0R\0\x61\0\x64\0i\0o\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x14\0S\0\x65\0r\0v\0\x65\0r\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x12\0H\0P\0S\0\x44\0R\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x12\0\x43\0h\0i\0r\0p\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\xfb\0\0\0\x16\0\x44\0i\0s\0p\0l\0\x61\0y\0\x43\0t\0r\0l\0\0\0\0\0\xff\xff\xff\xff\0\0\0/\0\xff\xff\xff\0\0\x4}\0\0\x1\x94\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\n\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\0\0\0\0\x2\0\0\0\x1\0\0\0\x18\0\x44\0i\0s\0p\0l\0\x61\0y\0P\0\x61\0n\0\x65\0l\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x2\0\0\0\x1\0\0\0\x16\0M\0\x61\0i\0n\0\x42\0u\0t\0t\0o\0n\0s\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)"
|
||||||
|
|||||||
+4116
-921
File diff suppressed because it is too large
Load Diff
+13
-5
@@ -1,6 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!DOCTYPE QtCreatorProject>
|
<!DOCTYPE QtCreatorProject>
|
||||||
<!-- Written by QtCreator 19.0.0, 2026-04-13T20:38:08. -->
|
<!-- Written by QtCreator 19.0.0, 2026-04-14T22:57:19. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
@@ -161,14 +161,18 @@
|
|||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes">
|
||||||
|
<value type="QString">QT_QPA_PLATFORM=xcb</value>
|
||||||
|
<value type="QString">QT_OPENGL=desktop</value>
|
||||||
|
</valuelist>
|
||||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/vladimir/Документы/source/cudaSDR/Source/cudaSDR.pro</value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/vladimir/Документы/source/cudaSDR/Source/cudaSDR.pro</value>
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||||
|
<value type="bool" key="RunConfiguration.Arguments.multi">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
@@ -273,14 +277,18 @@
|
|||||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes">
|
||||||
|
<value type="QString">QT_QPA_PLATFORM=xcb</value>
|
||||||
|
<value type="QString">QT_OPENGL=desktop</value>
|
||||||
|
</valuelist>
|
||||||
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
<value type="bool" key="PE.EnvironmentAspect.PrintOnRun">false</value>
|
||||||
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
<value type="QString" key="PerfRecordArgsId">-e cpu-cycles --call-graph dwarf,4096 -F 250</value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4RunConfiguration:</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/vladimir/Документы/source/cudaSDR/Source/cudaSDR.pro</value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey">/home/vladimir/Документы/source/cudaSDR/Source/cudaSDR.pro</value>
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">true</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||||
|
<value type="bool" key="RunConfiguration.Arguments.multi">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
<value type="bool" key="RunConfiguration.UseLibrarySearchPath">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
|
|||||||
@@ -338,6 +338,12 @@ void DataEngine::setupConnections() {
|
|||||||
this,
|
this,
|
||||||
SLOT(searchHpsdrNetworkDevices()));
|
SLOT(searchHpsdrNetworkDevices()));
|
||||||
|
|
||||||
|
CHECKED_CONNECT(
|
||||||
|
set,
|
||||||
|
SIGNAL(widebandDataChanged(QObject *, bool)),
|
||||||
|
this,
|
||||||
|
SLOT(setWidebandData(QObject *, bool)));
|
||||||
|
|
||||||
/*CHECKED_CONNECT(
|
/*CHECKED_CONNECT(
|
||||||
set,
|
set,
|
||||||
SIGNAL(spectrumAveragingChanged(QObject*, int, bool)),
|
SIGNAL(spectrumAveragingChanged(QObject*, int, bool)),
|
||||||
@@ -442,7 +448,7 @@ bool DataEngine::startDataEngineWithoutConnection() {
|
|||||||
if (!m_dataProcessor) createDataProcessor();
|
if (!m_dataProcessor) createDataProcessor();
|
||||||
|
|
||||||
// data receiver thread
|
// data receiver thread
|
||||||
if (!startDataIO(QThread::NormalPriority)) {
|
if (!startDataIO(QThread::HighestPriority)) {
|
||||||
|
|
||||||
setSystemState(QSDR::DataReceiverThreadError, m_hwInterface, m_serverMode, QSDR::DataEngineDown);
|
setSystemState(QSDR::DataReceiverThreadError, m_hwInterface, m_serverMode, QSDR::DataEngineDown);
|
||||||
return false;
|
return false;
|
||||||
@@ -556,8 +562,28 @@ bool DataEngine::findHPSDRDevices() {
|
|||||||
set->setPennyLanePresence(false);
|
set->setPennyLanePresence(false);
|
||||||
set->setExcaliburPresence(false);
|
set->setExcaliburPresence(false);
|
||||||
set->setAlexPresence(currentDevice.hasAlex0 || currentDevice.hasAlex1);
|
set->setAlexPresence(currentDevice.hasAlex0 || currentDevice.hasAlex1);
|
||||||
|
if (!currentDevice.widebandData && set->getWidebandData())
|
||||||
|
set->setWidebandData(this, false);
|
||||||
if (currentDevice.ddcCount > 0 && set->getNumberOfReceivers() > currentDevice.ddcCount)
|
if (currentDevice.ddcCount > 0 && set->getNumberOfReceivers() > currentDevice.ddcCount)
|
||||||
set->setReceivers(this, currentDevice.ddcCount);
|
set->setReceivers(this, currentDevice.ddcCount);
|
||||||
|
if (currentDevice.maxDdcSampleRateKsps > 0 || currentDevice.minDdcSampleRateKsps > 0) {
|
||||||
|
const int supportedRates[] = {48000, 96000, 192000, 384000, 768000, 1536000};
|
||||||
|
const int minRate = currentDevice.minDdcSampleRateKsps > 0 ? currentDevice.minDdcSampleRateKsps * 1000 : 48000;
|
||||||
|
const int maxRate = currentDevice.maxDdcSampleRateKsps > 0 ? currentDevice.maxDdcSampleRateKsps * 1000 : 1536000;
|
||||||
|
int fallbackRate = 0;
|
||||||
|
for (unsigned int i = 0; i < sizeof(supportedRates) / sizeof(supportedRates[0]); ++i) {
|
||||||
|
if (supportedRates[i] >= minRate && supportedRates[i] <= maxRate) {
|
||||||
|
if (fallbackRate == 0)
|
||||||
|
fallbackRate = supportedRates[i];
|
||||||
|
if (supportedRates[i] <= set->getSampleRate())
|
||||||
|
fallbackRate = supportedRates[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fallbackRate == 0)
|
||||||
|
fallbackRate = 48000;
|
||||||
|
if (set->getSampleRate() < minRate || set->getSampleRate() > maxRate)
|
||||||
|
set->setSampleRate(this, fallbackRate);
|
||||||
|
}
|
||||||
io.hermesFW = set->getCurrentMetisCard().firmwareVersion;
|
io.hermesFW = set->getCurrentMetisCard().firmwareVersion;
|
||||||
set->setHermesVersion(io.hermesFW);
|
set->setHermesVersion(io.hermesFW);
|
||||||
return true;
|
return true;
|
||||||
@@ -624,7 +650,7 @@ bool DataEngine::getFirmwareVersions() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// data IO thread
|
// data IO thread
|
||||||
if (!startDataIO(QThread::NormalPriority)) {// ::NormalPriority)) {
|
if (!startDataIO(QThread::HighestPriority)) {// ::NormalPriority)) {
|
||||||
|
|
||||||
DATA_ENGINE_DEBUG << "data IO thread could not be started.";
|
DATA_ENGINE_DEBUG << "data IO thread could not be started.";
|
||||||
return false;
|
return false;
|
||||||
@@ -634,9 +660,12 @@ bool DataEngine::getFirmwareVersions() {
|
|||||||
SleeperThread::msleep(100);
|
SleeperThread::msleep(100);
|
||||||
|
|
||||||
// pre-conditioning
|
// pre-conditioning
|
||||||
for (int i = 0; i < io.receivers; i++)
|
const bool protocol2Active = (set->getCurrentMetisCard().protocolVersion >= 2);
|
||||||
invokeDataIOInitFrame(m_dataIO, i);
|
if (!protocol2Active) {
|
||||||
|
for (int i = 0; i < io.receivers; i++)
|
||||||
|
invokeDataIOInitFrame(m_dataIO, i);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_serverMode == QSDR::SDRMode)
|
if (m_serverMode == QSDR::SDRMode)
|
||||||
invokeDataIOStartStop(m_dataIO, 0x01); // 0x01 for starting Metis without wide band data
|
invokeDataIOStartStop(m_dataIO, 0x01); // 0x01 for starting Metis without wide band data
|
||||||
|
|
||||||
@@ -1021,7 +1050,7 @@ bool DataEngine::start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// data IO thread
|
// data IO thread
|
||||||
if (!startDataIO(QThread::NormalPriority)) {// ::NormalPriority::HighPriority)) {
|
if (!startDataIO(QThread::HighestPriority)) {// ::NormalPriority::HighPriority)) {
|
||||||
|
|
||||||
DATA_ENGINE_DEBUG << "data IO thread could not be started.";
|
DATA_ENGINE_DEBUG << "data IO thread could not be started.";
|
||||||
return false;
|
return false;
|
||||||
@@ -1040,8 +1069,11 @@ bool DataEngine::start() {
|
|||||||
SleeperThread::msleep(100);
|
SleeperThread::msleep(100);
|
||||||
|
|
||||||
// pre-conditioning
|
// pre-conditioning
|
||||||
for (int i = 0; i < io.receivers; i++)
|
const bool protocol2Active = (set->getCurrentMetisCard().protocolVersion >= 2);
|
||||||
invokeDataIOInitFrame(m_dataIO, i);
|
if (!protocol2Active) {
|
||||||
|
for (int i = 0; i < io.receivers; i++)
|
||||||
|
invokeDataIOInitFrame(m_dataIO, i);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_serverMode == QSDR::SDRMode && set->getWidebandData())
|
if (m_serverMode == QSDR::SDRMode && set->getWidebandData())
|
||||||
invokeDataIOStartStop(m_dataIO, 0x03); // 0x03 for starting the device with wide band data
|
invokeDataIOStartStop(m_dataIO, 0x03); // 0x03 for starting the device with wide band data
|
||||||
@@ -2259,6 +2291,18 @@ void DataEngine::setSampleRate(QObject *sender, int value) {
|
|||||||
io.outputMultiplier = 8;
|
io.outputMultiplier = 8;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 768000:
|
||||||
|
io.samplerate = value;
|
||||||
|
io.speed = 3;
|
||||||
|
io.outputMultiplier = 16;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1536000:
|
||||||
|
io.samplerate = value;
|
||||||
|
io.speed = 3;
|
||||||
|
io.outputMultiplier = 32;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DATA_ENGINE_DEBUG << "invalid sample rate !\n";
|
DATA_ENGINE_DEBUG << "invalid sample rate !\n";
|
||||||
stop();
|
stop();
|
||||||
@@ -2567,6 +2611,19 @@ void DataEngine::setFrequency(QObject* sender, int mode, int rx, long frequency)
|
|||||||
io.tx_freq_change = rx;
|
io.tx_freq_change = rx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataEngine::setWidebandData(QObject *sender, bool value) {
|
||||||
|
Q_UNUSED(sender)
|
||||||
|
|
||||||
|
if (m_dataEngineState != QSDR::DataEngineUp || !m_dataIO)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const TNetworkDevicecard device = set->getCurrentMetisCard();
|
||||||
|
if (device.protocolVersion >= 2)
|
||||||
|
return;
|
||||||
|
|
||||||
|
invokeDataIOStartStop(m_dataIO, value ? 0x03 : 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
void DataEngine::loadWavFile(const QString &fileName) {
|
void DataEngine::loadWavFile(const QString &fileName) {
|
||||||
|
|
||||||
if (m_audioEngine->loadFile(fileName))
|
if (m_audioEngine->loadFile(fileName))
|
||||||
@@ -3649,6 +3706,9 @@ void DataProcessor::encodeCCBytes() {
|
|||||||
|
|
||||||
void DataProcessor::writeData() {
|
void DataProcessor::writeData() {
|
||||||
|
|
||||||
|
if (set->getCurrentMetisCard().protocolVersion >= 2)
|
||||||
|
return;
|
||||||
|
|
||||||
if (m_setNetworkDeviceHeader) {
|
if (m_setNetworkDeviceHeader) {
|
||||||
|
|
||||||
//RRK updated for 4byte int and network order
|
//RRK updated for 4byte int and network order
|
||||||
@@ -3845,8 +3905,8 @@ void WideBandDataProcessor::processWideBandInputBuffer(const QByteArray &buffer)
|
|||||||
|
|
||||||
for (int i = 0; i < length; i += 2) {
|
for (int i = 0; i < length; i += 2) {
|
||||||
|
|
||||||
s = (int)((qint8 ) buffer.at(i+1)) << 8;
|
s = (int)((qint8 ) buffer.at(i)) << 8;
|
||||||
s += (int)((quint8) buffer.at(i));
|
s += (int)((quint8) buffer.at(i+1));
|
||||||
sample = (float)(s * norm);
|
sample = (float)(s * norm);
|
||||||
|
|
||||||
cpxWBIn[i/2].re = sample * io->wbWindow.at(i/2);
|
cpxWBIn[i/2].re = sample * io->wbWindow.at(i/2);
|
||||||
|
|||||||
@@ -141,11 +141,12 @@ public slots:
|
|||||||
void set122_88MhzSource(QObject *sender, int source);
|
void set122_88MhzSource(QObject *sender, int source);
|
||||||
void setMicSource(QObject *sender, int source);
|
void setMicSource(QObject *sender, int source);
|
||||||
void setMercuryClass(QObject *sender, int value);
|
void setMercuryClass(QObject *sender, int value);
|
||||||
void setMercuryTiming(QObject* sender, int value);
|
void setMercuryTiming(QObject* sender, int value);
|
||||||
void setHamBand(QObject *sender, int rx, bool byBtn, HamBand band);
|
void setHamBand(QObject *sender, int rx, bool byBtn, HamBand band);
|
||||||
void setFrequency(QObject* sender, int mode, int rx, long frequency);
|
void setFrequency(QObject* sender, int mode, int rx, long frequency);
|
||||||
|
void setWidebandData(QObject *sender, bool value);
|
||||||
void loadWavFile(const QString &fileName);
|
|
||||||
|
void loadWavFile(const QString &fileName);
|
||||||
void suspend();
|
void suspend();
|
||||||
void startPlayback();
|
void startPlayback();
|
||||||
void showSettingsDialog();
|
void showSettingsDialog();
|
||||||
|
|||||||
@@ -24,8 +24,6 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LOG_DATAIO
|
|
||||||
|
|
||||||
#include "cusdr_dataIO.h"
|
#include "cusdr_dataIO.h"
|
||||||
#include "cusdr_protocol2_io.h"
|
#include "cusdr_protocol2_io.h"
|
||||||
#include "soundout.h"
|
#include "soundout.h"
|
||||||
@@ -155,7 +153,21 @@ void DataIO::initDataReceiverSocket() {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
if (io->samplerate == 384000) {
|
if (io->samplerate == 1536000) {
|
||||||
|
|
||||||
|
newBufferSize = 512*1024;//512 * 1032;
|
||||||
|
io->networkIOMutex.lock();
|
||||||
|
DATAIO_DEBUG << "socket buffer size set to 512 kB.";
|
||||||
|
io->networkIOMutex.unlock();
|
||||||
|
}
|
||||||
|
else if (io->samplerate == 768000) {
|
||||||
|
|
||||||
|
newBufferSize = 256*1024;//256 * 1032;
|
||||||
|
io->networkIOMutex.lock();
|
||||||
|
DATAIO_DEBUG << "socket buffer size set to 256 kB.";
|
||||||
|
io->networkIOMutex.unlock();
|
||||||
|
}
|
||||||
|
else if (io->samplerate == 384000) {
|
||||||
|
|
||||||
newBufferSize = 128*1024;//128 * 1032;
|
newBufferSize = 128*1024;//128 * 1032;
|
||||||
io->networkIOMutex.lock();
|
io->networkIOMutex.lock();
|
||||||
@@ -185,9 +197,27 @@ void DataIO::initDataReceiverSocket() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_dataIOSocket->bind(QHostAddress(set->getHPSDRDeviceLocalAddr()),
|
const QHostAddress localAddress(set->getHPSDRDeviceLocalAddr());
|
||||||
set->getMetisPort(),
|
const quint16 requestedPort = set->getMetisPort();
|
||||||
QUdpSocket::DontShareAddress))
|
bool socketBound = m_dataIOSocket->bind(localAddress,
|
||||||
|
requestedPort,
|
||||||
|
QUdpSocket::DontShareAddress);
|
||||||
|
|
||||||
|
if (!socketBound && requestedPort != 0) {
|
||||||
|
io->networkIOMutex.lock();
|
||||||
|
DATAIO_DEBUG << "data receiver socket binding failed on port " << requestedPort
|
||||||
|
<< ", trying an ephemeral local port.";
|
||||||
|
io->networkIOMutex.unlock();
|
||||||
|
|
||||||
|
m_dataIOSocket->close();
|
||||||
|
socketBound = m_dataIOSocket->bind(localAddress,
|
||||||
|
0,
|
||||||
|
QUdpSocket::DontShareAddress);
|
||||||
|
if (socketBound)
|
||||||
|
set->setMetisPort(this, m_dataIOSocket->localPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socketBound)
|
||||||
//QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress))
|
//QUdpSocket::ReuseAddressHint | QUdpSocket::ShareAddress))
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -684,6 +714,16 @@ void DataIO::setSampleRate(QObject *sender, int value) {
|
|||||||
DATAIO_DEBUG << "socket buffer size set to 128 kB.";
|
DATAIO_DEBUG << "socket buffer size set to 128 kB.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 768000:
|
||||||
|
bufferSize = 256*1024;//256 * 1032
|
||||||
|
DATAIO_DEBUG << "socket buffer size set to 256 kB.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1536000:
|
||||||
|
bufferSize = 512*1024;//512 * 1032
|
||||||
|
DATAIO_DEBUG << "socket buffer size set to 512 kB.";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DATAIO_DEBUG << "invalid sample rate !\n";
|
DATAIO_DEBUG << "invalid sample rate !\n";
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -231,8 +231,21 @@ int DiscovererP1::findHPSDRDevices() {
|
|||||||
mcP1.adcCount = 0;
|
mcP1.adcCount = 0;
|
||||||
mcP1.ddcCount = 0;
|
mcP1.ddcCount = 0;
|
||||||
mcP1.dspClockHz = 0;
|
mcP1.dspClockHz = 0;
|
||||||
|
mcP1.individualDdcSampleRates = false;
|
||||||
|
mcP1.minDdcSampleRateKsps = 48;
|
||||||
|
mcP1.maxDdcSampleRateKsps = 384;
|
||||||
|
mcP1.widebandData = false;
|
||||||
|
mcP1.widebandSamplesPerPacket = 0;
|
||||||
|
mcP1.widebandBitsPerSample = 0;
|
||||||
|
mcP1.ducCount = 1;
|
||||||
|
mcP1.ducSampleRateKsps = 48;
|
||||||
|
mcP1.ducBitsPerSample = 24;
|
||||||
|
mcP1.ducSamplesPerPacket = 0;
|
||||||
mcP1.iqFormatFlags = 0;
|
mcP1.iqFormatFlags = 0;
|
||||||
mcP1.phaseWords = false;
|
mcP1.phaseWords = false;
|
||||||
|
mcP1.ducPhaseWords = false;
|
||||||
|
mcP1.ddcAttenuator = false;
|
||||||
|
mcP1.ducRxAttenuator = false;
|
||||||
mcP1.hasAlex0 = false;
|
mcP1.hasAlex0 = false;
|
||||||
mcP1.hasAlex1 = false;
|
mcP1.hasAlex1 = false;
|
||||||
io->networkIOMutex.lock();
|
io->networkIOMutex.lock();
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ int DiscovererP2::findHPSDRDevices() {
|
|||||||
m_deviceDatagram[3] == (char)0) {
|
m_deviceDatagram[3] == (char)0) {
|
||||||
status = m_deviceDatagram[4] & 0xFF;
|
status = m_deviceDatagram[4] & 0xFF;
|
||||||
|
|
||||||
if (status == 2 || status == 3) {
|
if (status == 2 || status == 3 || status == 0xFE || status == 0xFF) {
|
||||||
|
|
||||||
sprintf(mcP2.mac_address, "%02X:%02X:%02X:%02X:%02X:%02X",
|
sprintf(mcP2.mac_address, "%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
m_deviceDatagram[5] & 0xFF, m_deviceDatagram[6] & 0xFF, m_deviceDatagram[7] & 0xFF,
|
m_deviceDatagram[5] & 0xFF, m_deviceDatagram[6] & 0xFF, m_deviceDatagram[7] & 0xFF,
|
||||||
@@ -215,8 +215,21 @@ int DiscovererP2::findHPSDRDevices() {
|
|||||||
mcP2.adcCount = profile.adcCount;
|
mcP2.adcCount = profile.adcCount;
|
||||||
mcP2.ddcCount = profile.defaultDdcCount;
|
mcP2.ddcCount = profile.defaultDdcCount;
|
||||||
mcP2.dspClockHz = profile.dspClockHz;
|
mcP2.dspClockHz = profile.dspClockHz;
|
||||||
|
mcP2.individualDdcSampleRates = profile.individualDdcSampleRates;
|
||||||
|
mcP2.minDdcSampleRateKsps = profile.minDdcSampleRateKsps;
|
||||||
|
mcP2.maxDdcSampleRateKsps = profile.maxDdcSampleRateKsps;
|
||||||
|
mcP2.widebandData = profile.widebandData;
|
||||||
|
mcP2.widebandSamplesPerPacket = profile.widebandSamplesPerPacket;
|
||||||
|
mcP2.widebandBitsPerSample = profile.widebandBitsPerSample;
|
||||||
|
mcP2.ducCount = profile.ducCount;
|
||||||
|
mcP2.ducSampleRateKsps = profile.ducSampleRateKsps;
|
||||||
|
mcP2.ducBitsPerSample = profile.ducBitsPerSample;
|
||||||
|
mcP2.ducSamplesPerPacket = profile.ducSamplesPerPacket;
|
||||||
mcP2.iqFormatFlags = 0;
|
mcP2.iqFormatFlags = 0;
|
||||||
mcP2.phaseWords = profile.phaseWords;
|
mcP2.phaseWords = profile.phaseWords;
|
||||||
|
mcP2.ducPhaseWords = profile.ducPhaseWords;
|
||||||
|
mcP2.ddcAttenuator = profile.ddcAttenuator;
|
||||||
|
mcP2.ducRxAttenuator = profile.ducRxAttenuator;
|
||||||
mcP2.hasAlex0 = profile.hasAlex0;
|
mcP2.hasAlex0 = profile.hasAlex0;
|
||||||
mcP2.hasAlex1 = profile.hasAlex1;
|
mcP2.hasAlex1 = profile.hasAlex1;
|
||||||
|
|
||||||
@@ -226,13 +239,43 @@ int DiscovererP2::findHPSDRDevices() {
|
|||||||
mcP2.iqFormatFlags = m_deviceDatagram[22] & 0xFF;
|
mcP2.iqFormatFlags = m_deviceDatagram[22] & 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_deviceDatagram.size() >= 97 && (m_deviceDatagram[4] & 0xFF) >= 0xFE) {
|
||||||
|
mcP2.ddcCount = m_deviceDatagram[39] & 0xFF;
|
||||||
|
mcP2.phaseWords = (m_deviceDatagram[40] & 0x01) != 0;
|
||||||
|
mcP2.ddcAttenuator = (m_deviceDatagram[41] & 0x01) != 0;
|
||||||
|
mcP2.widebandData = (m_deviceDatagram[42] & 0x01) != 0;
|
||||||
|
mcP2.widebandSamplesPerPacket =
|
||||||
|
((m_deviceDatagram[43] & 0xFF) << 8) | (m_deviceDatagram[44] & 0xFF);
|
||||||
|
mcP2.widebandBitsPerSample = m_deviceDatagram[46] & 0xFF;
|
||||||
|
mcP2.individualDdcSampleRates = (m_deviceDatagram[51] & 0x01) != 0;
|
||||||
|
mcP2.minDdcSampleRateKsps =
|
||||||
|
((m_deviceDatagram[52] & 0xFF) << 8) | (m_deviceDatagram[53] & 0xFF);
|
||||||
|
mcP2.maxDdcSampleRateKsps =
|
||||||
|
((m_deviceDatagram[54] & 0xFF) << 8) | (m_deviceDatagram[55] & 0xFF);
|
||||||
|
mcP2.ducCount = m_deviceDatagram[70] & 0xFF;
|
||||||
|
mcP2.ducPhaseWords = (m_deviceDatagram[78] & 0x01) != 0;
|
||||||
|
mcP2.ducSampleRateKsps = m_deviceDatagram[79] & 0xFF;
|
||||||
|
mcP2.ducBitsPerSample = m_deviceDatagram[80] & 0xFF;
|
||||||
|
mcP2.ducSamplesPerPacket =
|
||||||
|
((m_deviceDatagram[81] & 0xFF) << 8) | (m_deviceDatagram[82] & 0xFF);
|
||||||
|
mcP2.ducRxAttenuator = (m_deviceDatagram[92] & 0x01) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
io->networkIOMutex.lock();
|
io->networkIOMutex.lock();
|
||||||
DISCOVERER_DEBUG << "Protocol 2 device board ID: " << device;
|
DISCOVERER_DEBUG << "Protocol 2 device board ID: " << device;
|
||||||
DISCOVERER_DEBUG << "Protocol 2 device is: " << qPrintable(str);
|
DISCOVERER_DEBUG << "Protocol 2 device is: " << qPrintable(str);
|
||||||
DISCOVERER_DEBUG << "Protocol 2 capabilities: "
|
DISCOVERER_DEBUG << "Protocol 2 capabilities: "
|
||||||
<< mcP2.adcCount << " ADC, "
|
<< mcP2.adcCount << " ADC, "
|
||||||
<< mcP2.ddcCount << " DDC, phaseWords="
|
<< mcP2.ddcCount << " DDC, DDC rate "
|
||||||
<< mcP2.phaseWords << ", iqFlags=0x"
|
<< mcP2.minDdcSampleRateKsps << "-"
|
||||||
|
<< mcP2.maxDdcSampleRateKsps
|
||||||
|
<< " ksps, phaseWords="
|
||||||
|
<< mcP2.phaseWords
|
||||||
|
<< ", DUC " << mcP2.ducSampleRateKsps
|
||||||
|
<< " ksps/" << mcP2.ducBitsPerSample
|
||||||
|
<< " bit, wideband="
|
||||||
|
<< mcP2.widebandData
|
||||||
|
<< ", iqFlags=0x"
|
||||||
<< QString::number(mcP2.iqFormatFlags, 16);
|
<< QString::number(mcP2.iqFormatFlags, 16);
|
||||||
io->networkIOMutex.unlock();
|
io->networkIOMutex.unlock();
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,11 @@
|
|||||||
|
|
||||||
#include "cusdr_settings.h"
|
#include "cusdr_settings.h"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <QMutex>
|
||||||
|
#include <QSet>
|
||||||
|
#include <QThread>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
|
|
||||||
@@ -17,6 +21,8 @@ struct Protocol2IQSample {
|
|||||||
qint32 q;
|
qint32 q;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Protocol2ReceiveThread;
|
||||||
|
|
||||||
class Protocol2DataPath : public QObject {
|
class Protocol2DataPath : public QObject {
|
||||||
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -32,16 +38,43 @@ public:
|
|||||||
void networkDeviceStartStop(char value);
|
void networkDeviceStartStop(char value);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
void readCommandData();
|
||||||
void readStatusData();
|
void readStatusData();
|
||||||
void readDdcData();
|
void readDdcData();
|
||||||
|
void readWidebandData();
|
||||||
void sendHeartbeat();
|
void sendHeartbeat();
|
||||||
|
void handleNumberOfRxChanged(QObject *sender, int value);
|
||||||
|
void handleSampleRateChanged(QObject *sender, int value);
|
||||||
|
void handleDitherChanged(QObject *sender, int value);
|
||||||
|
void handleRandomChanged(QObject *sender, int value);
|
||||||
|
void handleCtrFrequencyChanged(QObject *sender, int mode, int rx, long frequency);
|
||||||
|
void handleVfoFrequencyChanged(QObject *sender, int mode, int rx, long frequency);
|
||||||
|
void handleCurrentReceiverChanged(QObject *sender, int rx);
|
||||||
|
void handleHamBandChanged(QObject *sender, int rx, bool byButton, HamBand band);
|
||||||
|
void handleAlexConfigurationChanged(quint16 config);
|
||||||
|
void handleAlexStateChanged(HamBand band, const QList<int> &states);
|
||||||
|
void handleAlexPresenceChanged(bool value);
|
||||||
|
void handleWidebandDataChanged(QObject *sender, bool value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
friend class Protocol2ReceiveThread;
|
||||||
|
|
||||||
|
QList<int> activeDdcIndexes() const;
|
||||||
void closeSockets();
|
void closeSockets();
|
||||||
|
void processReceivedDatagram(const QByteArray &datagram, quint16 senderPort);
|
||||||
|
void processIgnoredDatagram(const char *data, int length, quint16 senderPort);
|
||||||
|
bool sendNativeDatagram(const QByteArray &datagram, const QHostAddress &address, quint16 port);
|
||||||
void sendGeneralPacket();
|
void sendGeneralPacket();
|
||||||
void sendDdcSpecificPacket();
|
void sendDdcSpecificPacket();
|
||||||
|
void sendDucSpecificPacket();
|
||||||
void sendHighPriorityPacket(bool run);
|
void sendHighPriorityPacket(bool run);
|
||||||
|
void softRestartDdcStream();
|
||||||
|
void refreshDdcConfiguration(bool rebuildSockets);
|
||||||
|
void refreshHighPriorityState();
|
||||||
|
void refreshWidebandConfiguration();
|
||||||
void updateLegacyControlBytes(const QByteArray &statusDatagram);
|
void updateLegacyControlBytes(const QByteArray &statusDatagram);
|
||||||
|
void handleDdcDatagram(int rx, const QByteArray &datagram);
|
||||||
|
void handleWidebandDatagram(const QByteArray &datagram);
|
||||||
void tryProduceLegacyFrames();
|
void tryProduceLegacyFrames();
|
||||||
int samplesPerLegacyHalfFrame() const;
|
int samplesPerLegacyHalfFrame() const;
|
||||||
quint32 encodeFrequency(long frequency) const;
|
quint32 encodeFrequency(long frequency) const;
|
||||||
@@ -51,17 +84,54 @@ private:
|
|||||||
Settings* set;
|
Settings* set;
|
||||||
THPSDRParameter* io;
|
THPSDRParameter* io;
|
||||||
QUdpSocket* m_commandSocket;
|
QUdpSocket* m_commandSocket;
|
||||||
|
Protocol2ReceiveThread* m_receiveThread;
|
||||||
|
int m_commandSocketFd;
|
||||||
|
quint16 m_commandPort;
|
||||||
|
int m_commandReceiveBufferSize;
|
||||||
QUdpSocket* m_statusSocket;
|
QUdpSocket* m_statusSocket;
|
||||||
|
QUdpSocket* m_widebandSocket;
|
||||||
QList<QUdpSocket*> m_ddcSockets;
|
QList<QUdpSocket*> m_ddcSockets;
|
||||||
QList<QList<Protocol2IQSample> > m_ddcSampleBuffers;
|
QList<QByteArray> m_ddcSampleBuffers;
|
||||||
|
QList<QByteArray> m_legacySampleBuffers;
|
||||||
QTimer* m_heartbeatTimer;
|
QTimer* m_heartbeatTimer;
|
||||||
QByteArray m_partialLegacyFrame;
|
QByteArray m_partialLegacyFrame;
|
||||||
QByteArray m_statusDatagram;
|
QByteArray m_statusDatagram;
|
||||||
QByteArray m_legacyControlBytes;
|
QByteArray m_legacyControlBytes;
|
||||||
|
QByteArray m_widebandDatagram;
|
||||||
bool m_running;
|
bool m_running;
|
||||||
|
bool m_collectWideband;
|
||||||
|
quint32 m_widebandSequence;
|
||||||
|
quint32 m_widebandSequencePrevious;
|
||||||
|
int m_widebandPacketCount;
|
||||||
quint32 m_generalSequence;
|
quint32 m_generalSequence;
|
||||||
quint32 m_ddcSequence;
|
quint32 m_ddcSequence;
|
||||||
|
quint32 m_ducSequence;
|
||||||
quint32 m_highPrioritySequence;
|
quint32 m_highPrioritySequence;
|
||||||
|
int m_heartbeatTick;
|
||||||
|
quint64 m_ddcDatagramsReceived;
|
||||||
|
quint64 m_ddcSamplesReceived;
|
||||||
|
quint32 m_lastDdcSequence;
|
||||||
|
quint64 m_ddcSequenceGaps;
|
||||||
|
quint64 m_ddcRecoveryAttempts;
|
||||||
|
quint64 m_legacyFramesEnqueued;
|
||||||
|
quint64 m_legacyFramesQueued;
|
||||||
|
quint64 m_legacyFramesDropped;
|
||||||
|
quint64 m_statusPacketsReceived;
|
||||||
|
quint64 m_highPriorityPacketsSent;
|
||||||
|
quint64 m_micPacketsIgnored;
|
||||||
|
quint64 m_widebandPacketsIgnored;
|
||||||
|
quint64 m_widebandPacketsLogged;
|
||||||
|
bool m_dropWidebandReceivePackets;
|
||||||
|
QHash<quint16, quint64> m_commandPortCounters;
|
||||||
|
QSet<quint16> m_loggedFirstSourcePorts;
|
||||||
|
QMutex m_receiveMutex;
|
||||||
|
bool m_logConfigPackets;
|
||||||
|
uchar m_lastStatusByte4;
|
||||||
|
uchar m_lastStatusByte5;
|
||||||
|
bool m_loggedFirstDdcDatagram;
|
||||||
|
quint64 m_prevDdcDatagramsReceived; // to detect stream stop
|
||||||
|
int m_lastDdcGrowthTick;
|
||||||
|
int m_lastDdcRecoveryTick;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _CUSDR_PROTOCOL2_IO_H
|
#endif // _CUSDR_PROTOCOL2_IO_H
|
||||||
|
|||||||
@@ -15,7 +15,20 @@ static Protocol2BoardProfile makeDefaultProfile(int boardId) {
|
|||||||
profile.adcCount = 1;
|
profile.adcCount = 1;
|
||||||
profile.defaultDdcCount = 2;
|
profile.defaultDdcCount = 2;
|
||||||
profile.dspClockHz = 122880000;
|
profile.dspClockHz = 122880000;
|
||||||
|
profile.individualDdcSampleRates = true;
|
||||||
|
profile.minDdcSampleRateKsps = 48;
|
||||||
|
profile.maxDdcSampleRateKsps = 1536;
|
||||||
|
profile.widebandData = true;
|
||||||
|
profile.widebandSamplesPerPacket = 512;
|
||||||
|
profile.widebandBitsPerSample = 16;
|
||||||
|
profile.ducCount = 1;
|
||||||
|
profile.ducSampleRateKsps = 192;
|
||||||
|
profile.ducBitsPerSample = 24;
|
||||||
|
profile.ducSamplesPerPacket = 240;
|
||||||
profile.phaseWords = true;
|
profile.phaseWords = true;
|
||||||
|
profile.ducPhaseWords = true;
|
||||||
|
profile.ddcAttenuator = true;
|
||||||
|
profile.ducRxAttenuator = true;
|
||||||
profile.hasAlex0 = true;
|
profile.hasAlex0 = true;
|
||||||
profile.hasAlex1 = false;
|
profile.hasAlex1 = false;
|
||||||
return profile;
|
return profile;
|
||||||
@@ -35,6 +48,7 @@ Protocol2BoardProfile protocol2BoardProfile(int boardId) {
|
|||||||
profile.defaultDdcCount = 4;
|
profile.defaultDdcCount = 4;
|
||||||
profile.dspClockHz = 122880000;
|
profile.dspClockHz = 122880000;
|
||||||
profile.phaseWords = false;
|
profile.phaseWords = false;
|
||||||
|
profile.ducPhaseWords = false;
|
||||||
profile.hasAlex0 = true;
|
profile.hasAlex0 = true;
|
||||||
profile.hasAlex1 = false;
|
profile.hasAlex1 = false;
|
||||||
break;
|
break;
|
||||||
@@ -62,9 +76,10 @@ Protocol2BoardProfile protocol2BoardProfile(int boardId) {
|
|||||||
case 3:
|
case 3:
|
||||||
profile.boardName = "Angelia / ANAN-100D";
|
profile.boardName = "Angelia / ANAN-100D";
|
||||||
profile.adcCount = 2;
|
profile.adcCount = 2;
|
||||||
profile.defaultDdcCount = 4;
|
profile.defaultDdcCount = 7;
|
||||||
profile.dspClockHz = 122880000;
|
profile.dspClockHz = 122880000;
|
||||||
profile.phaseWords = true;
|
profile.phaseWords = true;
|
||||||
|
profile.ducSamplesPerPacket = 238;
|
||||||
profile.hasAlex0 = true;
|
profile.hasAlex0 = true;
|
||||||
profile.hasAlex1 = false;
|
profile.hasAlex1 = false;
|
||||||
break;
|
break;
|
||||||
@@ -75,6 +90,7 @@ Protocol2BoardProfile protocol2BoardProfile(int boardId) {
|
|||||||
profile.defaultDdcCount = 4;
|
profile.defaultDdcCount = 4;
|
||||||
profile.dspClockHz = 122880000;
|
profile.dspClockHz = 122880000;
|
||||||
profile.phaseWords = true;
|
profile.phaseWords = true;
|
||||||
|
profile.ducSamplesPerPacket = 240;
|
||||||
profile.hasAlex0 = true;
|
profile.hasAlex0 = true;
|
||||||
profile.hasAlex1 = false;
|
profile.hasAlex1 = false;
|
||||||
break;
|
break;
|
||||||
@@ -99,6 +115,16 @@ Protocol2BoardProfile protocol2BoardProfile(int boardId) {
|
|||||||
profile.hasAlex1 = false;
|
profile.hasAlex1 = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 100:
|
||||||
|
profile.boardName = "Hermes Lite 2 / C25";
|
||||||
|
profile.adcCount = 1;
|
||||||
|
profile.defaultDdcCount = 2;
|
||||||
|
profile.dspClockHz = 76800000;
|
||||||
|
profile.phaseWords = true;
|
||||||
|
profile.hasAlex0 = false;
|
||||||
|
profile.hasAlex1 = false;
|
||||||
|
break;
|
||||||
|
|
||||||
case 10:
|
case 10:
|
||||||
profile.boardName = "Saturn / ANAN-G2";
|
profile.boardName = "Saturn / ANAN-G2";
|
||||||
profile.adcCount = 2;
|
profile.adcCount = 2;
|
||||||
@@ -129,6 +155,9 @@ QString protocol2DeviceSummary(const TNetworkDevicecard &device) {
|
|||||||
if (device.adcCount > 0 || device.ddcCount > 0)
|
if (device.adcCount > 0 || device.ddcCount > 0)
|
||||||
summary += QString(" %1ADC/%2DDC").arg(device.adcCount).arg(device.ddcCount);
|
summary += QString(" %1ADC/%2DDC").arg(device.adcCount).arg(device.ddcCount);
|
||||||
|
|
||||||
|
if (device.maxDdcSampleRateKsps > 0)
|
||||||
|
summary += QString(" %1ksps").arg(device.maxDdcSampleRateKsps);
|
||||||
|
|
||||||
if (device.phaseWords)
|
if (device.phaseWords)
|
||||||
summary += " phase";
|
summary += " phase";
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,20 @@ struct Protocol2BoardProfile {
|
|||||||
int adcCount;
|
int adcCount;
|
||||||
int defaultDdcCount;
|
int defaultDdcCount;
|
||||||
int dspClockHz;
|
int dspClockHz;
|
||||||
|
bool individualDdcSampleRates;
|
||||||
|
int minDdcSampleRateKsps;
|
||||||
|
int maxDdcSampleRateKsps;
|
||||||
|
bool widebandData;
|
||||||
|
int widebandSamplesPerPacket;
|
||||||
|
int widebandBitsPerSample;
|
||||||
|
int ducCount;
|
||||||
|
int ducSampleRateKsps;
|
||||||
|
int ducBitsPerSample;
|
||||||
|
int ducSamplesPerPacket;
|
||||||
bool phaseWords;
|
bool phaseWords;
|
||||||
|
bool ducPhaseWords;
|
||||||
|
bool ddcAttenuator;
|
||||||
|
bool ducRxAttenuator;
|
||||||
bool hasAlex0;
|
bool hasAlex0;
|
||||||
bool hasAlex1;
|
bool hasAlex1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -369,14 +369,22 @@ void Receiver::setSampleRate(QObject *sender, int value) {
|
|||||||
m_samplerate = value;
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 384000:
|
case 384000:
|
||||||
m_samplerate = value;
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case 768000:
|
||||||
RECEIVER_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, or 384 kHz)!\n";
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
case 1536000:
|
||||||
|
m_samplerate = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
RECEIVER_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, 384, 768, or 1536 kHz)!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (qtdsp)
|
if (qtdsp)
|
||||||
qtdsp->setSampleRate(this, m_samplerate);
|
qtdsp->setSampleRate(this, m_samplerate);
|
||||||
|
|||||||
@@ -2679,13 +2679,24 @@ void QGLDistancePanel::setPanGridStatus(bool value) {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGLDistancePanel::sampleRateChanged(QObject *sender, int value) {
|
void QGLDistancePanel::sampleRateChanged(QObject *sender, int value) {
|
||||||
|
|
||||||
Q_UNUSED(sender)
|
Q_UNUSED(sender)
|
||||||
|
|
||||||
m_sampleRate = value;
|
if (m_sampleRate == value)
|
||||||
update();
|
return;
|
||||||
}
|
|
||||||
|
m_sampleRate = value;
|
||||||
|
m_freqScalePanadapterUpdate = true;
|
||||||
|
m_freqScalePanadapterRenew = true;
|
||||||
|
m_panGridUpdate = true;
|
||||||
|
m_panGridRenew = true;
|
||||||
|
m_spectrumUpdate = true;
|
||||||
|
m_spectrumVertexColorUpdate = true;
|
||||||
|
m_spectrumColorsChanged = true;
|
||||||
|
m_panadapterBins.clear();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void QGLDistancePanel::setPanadapterColors() {
|
void QGLDistancePanel::setPanadapterColors() {
|
||||||
|
|
||||||
|
|||||||
@@ -4311,20 +4311,39 @@ void QGLReceiverPanel::setHairCrossStatus(bool value, int rx) {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGLReceiverPanel::sampleRateChanged(QObject *sender, int value) {
|
void QGLReceiverPanel::sampleRateChanged(QObject *sender, int value) {
|
||||||
|
|
||||||
Q_UNUSED(sender)
|
Q_UNUSED(sender)
|
||||||
|
|
||||||
m_sampleRate = value;
|
if (m_sampleRate == value)
|
||||||
m_deltaF = (qreal)(1.0*m_deltaFrequency/m_sampleRate);
|
return;
|
||||||
|
|
||||||
m_freqScalePanadapterUpdate = true;
|
m_sampleRate = value;
|
||||||
m_panGridUpdate = true;
|
if (m_vfoFrequency > m_centerFrequency + m_sampleRate/2)
|
||||||
m_peakHoldBufferResize = true;
|
m_vfoFrequency = m_centerFrequency + m_sampleRate/2;
|
||||||
m_filterChanged = true;
|
else if (m_vfoFrequency < m_centerFrequency - m_sampleRate/2)
|
||||||
|
m_vfoFrequency = m_centerFrequency - m_sampleRate/2;
|
||||||
update();
|
|
||||||
}
|
m_deltaFrequency = m_centerFrequency - m_vfoFrequency;
|
||||||
|
m_deltaF = (qreal)(1.0*m_deltaFrequency/m_sampleRate);
|
||||||
|
|
||||||
|
m_freqScalePanadapterUpdate = true;
|
||||||
|
m_freqScalePanadapterRenew = true;
|
||||||
|
m_panGridUpdate = true;
|
||||||
|
m_panGridRenew = true;
|
||||||
|
m_waterfallUpdate = true;
|
||||||
|
m_waterfallDisplayUpdate = true;
|
||||||
|
m_secScaleWaterfallUpdate = true;
|
||||||
|
m_peakHoldBufferResize = true;
|
||||||
|
m_filterChanged = true;
|
||||||
|
m_spectrumVertexColorUpdate = true;
|
||||||
|
m_spectrumColorsChanged = true;
|
||||||
|
m_panadapterBins.clear();
|
||||||
|
m_panPeakHoldBins.clear();
|
||||||
|
m_waterfallPixel.clear();
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void QGLReceiverPanel::setMercuryAttenuator(QObject* sender, HamBand band, int value) {
|
void QGLReceiverPanel::setMercuryAttenuator(QObject* sender, HamBand band, int value) {
|
||||||
|
|
||||||
|
|||||||
@@ -2023,13 +2023,24 @@ void QGLWidebandPanel::setPanGridStatus(bool value, int rx) {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QGLWidebandPanel::sampleRateChanged(QObject *sender, int value) {
|
void QGLWidebandPanel::sampleRateChanged(QObject *sender, int value) {
|
||||||
|
|
||||||
Q_UNUSED(sender)
|
Q_UNUSED(sender)
|
||||||
|
|
||||||
m_sampleRate = value;
|
if (m_sampleRate == value)
|
||||||
update();
|
return;
|
||||||
}
|
|
||||||
|
m_sampleRate = value;
|
||||||
|
m_freqScaleUpdate = true;
|
||||||
|
m_freqScaleRenew = true;
|
||||||
|
m_panGridUpdate = true;
|
||||||
|
m_panGridRenew = true;
|
||||||
|
m_spectrumUpdate = true;
|
||||||
|
m_spectrumVertexColorUpdate = true;
|
||||||
|
m_spectrumColorsChanged = true;
|
||||||
|
m_widebandPanSpectrumBins.clear();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void QGLWidebandPanel::freqScaleUpdate(bool value) {
|
void QGLWidebandPanel::freqScaleUpdate(bool value) {
|
||||||
|
|
||||||
|
|||||||
@@ -320,14 +320,22 @@ void QDSPEngine::setSampleRate(QObject *sender, int value) {
|
|||||||
m_samplerate = value;
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 384000:
|
case 384000:
|
||||||
m_samplerate = value;
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
case 768000:
|
||||||
DSP_ENGINE_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, or 384 kHz)!\n";
|
m_samplerate = value;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
|
case 1536000:
|
||||||
|
m_samplerate = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
DSP_ENGINE_DEBUG << "invalid sample rate (possible values are: 48, 96, 192, 384, 768, or 1536 kHz)!\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
//DSP_ENGINE_DEBUG << "set sample rate to " << m_samplerate;
|
//DSP_ENGINE_DEBUG << "set sample rate to " << m_samplerate;
|
||||||
//setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
|
//setNCOFrequency(m_rx, m_rxData.vfoFrequency - m_rxData.ctrFrequency);
|
||||||
|
|||||||
@@ -116,9 +116,9 @@ HPSDRWidget::~HPSDRWidget() {
|
|||||||
|
|
||||||
void HPSDRWidget::setupConnections() {
|
void HPSDRWidget::setupConnections() {
|
||||||
|
|
||||||
CHECKED_CONNECT(
|
CHECKED_CONNECT(
|
||||||
set,
|
set,
|
||||||
SIGNAL(systemStateChanged(
|
SIGNAL(systemStateChanged(
|
||||||
QObject *,
|
QObject *,
|
||||||
QSDR::_Error,
|
QSDR::_Error,
|
||||||
QSDR::_HWInterfaceMode,
|
QSDR::_HWInterfaceMode,
|
||||||
@@ -128,10 +128,22 @@ void HPSDRWidget::setupConnections() {
|
|||||||
SLOT(systemStateChanged(
|
SLOT(systemStateChanged(
|
||||||
QObject *,
|
QObject *,
|
||||||
QSDR::_Error,
|
QSDR::_Error,
|
||||||
QSDR::_HWInterfaceMode,
|
QSDR::_HWInterfaceMode,
|
||||||
QSDR::_ServerMode,
|
QSDR::_ServerMode,
|
||||||
QSDR::_DataEngineState)));
|
QSDR::_DataEngineState)));
|
||||||
}
|
|
||||||
|
CHECKED_CONNECT(
|
||||||
|
set,
|
||||||
|
SIGNAL(sampleRateChanged(QObject *, int)),
|
||||||
|
this,
|
||||||
|
SLOT(sampleRateValueChanged(QObject *, int)));
|
||||||
|
|
||||||
|
CHECKED_CONNECT(
|
||||||
|
set,
|
||||||
|
SIGNAL(hpsdrNetworkDeviceChanged(TNetworkDevicecard)),
|
||||||
|
this,
|
||||||
|
SLOT(setCurrentNetworkDevice(TNetworkDevicecard)));
|
||||||
|
}
|
||||||
|
|
||||||
QGroupBox* HPSDRWidget::hpsdrHardwareBtnGroup() {
|
QGroupBox* HPSDRWidget::hpsdrHardwareBtnGroup() {
|
||||||
|
|
||||||
@@ -455,51 +467,94 @@ QGroupBox *HPSDRWidget::sampleRateExclusiveGroup() {
|
|||||||
samplerate384Btn = new AeroButton("384 kHz", this);
|
samplerate384Btn = new AeroButton("384 kHz", this);
|
||||||
samplerate384Btn->setRoundness(0);
|
samplerate384Btn->setRoundness(0);
|
||||||
samplerate384Btn->setFixedSize (50, btn_height);
|
samplerate384Btn->setFixedSize (50, btn_height);
|
||||||
samplerate384Btn->setStyleSheet(set->getMiniButtonStyle());
|
samplerate384Btn->setStyleSheet(set->getMiniButtonStyle());
|
||||||
//samplerate384Btn->setEnabled(false);
|
//samplerate384Btn->setEnabled(false);
|
||||||
samplerateBtnList.append(samplerate384Btn);
|
samplerateBtnList.append(samplerate384Btn);
|
||||||
CHECKED_CONNECT(samplerate384Btn, SIGNAL(released()), this, SLOT(sampleRateChanged()));
|
CHECKED_CONNECT(samplerate384Btn, SIGNAL(released()), this, SLOT(sampleRateChanged()));
|
||||||
|
|
||||||
switch(set->getSampleRate()) {
|
samplerate768Btn = new AeroButton("768 kHz", this);
|
||||||
|
samplerate768Btn->setRoundness(0);
|
||||||
case 48000:
|
samplerate768Btn->setFixedSize (56, btn_height);
|
||||||
samplerate48Btn->setBtnState(AeroButton::ON);
|
samplerate768Btn->setStyleSheet(set->getMiniButtonStyle());
|
||||||
samplerate96Btn->setBtnState(AeroButton::OFF);
|
samplerateBtnList.append(samplerate768Btn);
|
||||||
samplerate192Btn->setBtnState(AeroButton::OFF);
|
CHECKED_CONNECT(samplerate768Btn, SIGNAL(released()), this, SLOT(sampleRateChanged()));
|
||||||
samplerate384Btn->setBtnState(AeroButton::OFF);
|
|
||||||
break;
|
samplerate1536Btn = new AeroButton("1536 kHz", this);
|
||||||
|
samplerate1536Btn->setRoundness(0);
|
||||||
case 96000:
|
samplerate1536Btn->setFixedSize (64, btn_height);
|
||||||
samplerate48Btn->setBtnState(AeroButton::OFF);
|
samplerate1536Btn->setStyleSheet(set->getMiniButtonStyle());
|
||||||
samplerate96Btn->setBtnState(AeroButton::ON);
|
samplerateBtnList.append(samplerate1536Btn);
|
||||||
samplerate192Btn->setBtnState(AeroButton::OFF);
|
CHECKED_CONNECT(samplerate1536Btn, SIGNAL(released()), this, SLOT(sampleRateChanged()));
|
||||||
samplerate384Btn->setBtnState(AeroButton::OFF);
|
|
||||||
break;
|
switch(set->getSampleRate()) {
|
||||||
|
|
||||||
case 192000:
|
case 48000:
|
||||||
samplerate48Btn->setBtnState(AeroButton::OFF);
|
samplerate48Btn->setBtnState(AeroButton::ON);
|
||||||
samplerate96Btn->setBtnState(AeroButton::OFF);
|
samplerate96Btn->setBtnState(AeroButton::OFF);
|
||||||
samplerate192Btn->setBtnState(AeroButton::ON);
|
samplerate192Btn->setBtnState(AeroButton::OFF);
|
||||||
samplerate384Btn->setBtnState(AeroButton::OFF);
|
samplerate384Btn->setBtnState(AeroButton::OFF);
|
||||||
break;
|
samplerate768Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::OFF);
|
||||||
case 384000:
|
break;
|
||||||
samplerate48Btn->setBtnState(AeroButton::OFF);
|
|
||||||
samplerate96Btn->setBtnState(AeroButton::OFF);
|
case 96000:
|
||||||
samplerate192Btn->setBtnState(AeroButton::OFF);
|
samplerate48Btn->setBtnState(AeroButton::OFF);
|
||||||
samplerate384Btn->setBtnState(AeroButton::ON);
|
samplerate96Btn->setBtnState(AeroButton::ON);
|
||||||
break;
|
samplerate192Btn->setBtnState(AeroButton::OFF);
|
||||||
}
|
samplerate384Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate768Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::OFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 192000:
|
||||||
|
samplerate48Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate96Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate192Btn->setBtnState(AeroButton::ON);
|
||||||
|
samplerate384Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate768Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::OFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 384000:
|
||||||
|
samplerate48Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate96Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate192Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate384Btn->setBtnState(AeroButton::ON);
|
||||||
|
samplerate768Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::OFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 768000:
|
||||||
|
samplerate48Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate96Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate192Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate384Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate768Btn->setBtnState(AeroButton::ON);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::OFF);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1536000:
|
||||||
|
samplerate48Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate96Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate192Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate384Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate768Btn->setBtnState(AeroButton::OFF);
|
||||||
|
samplerate1536Btn->setBtnState(AeroButton::ON);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
QHBoxLayout *hbox = new QHBoxLayout();
|
QHBoxLayout *hbox = new QHBoxLayout();
|
||||||
hbox->setSpacing(4);
|
hbox->setSpacing(4);
|
||||||
hbox->addStretch();
|
hbox->addStretch();
|
||||||
hbox->addWidget(samplerate48Btn);
|
hbox->addWidget(samplerate48Btn);
|
||||||
hbox->addWidget(samplerate96Btn);
|
hbox->addWidget(samplerate96Btn);
|
||||||
hbox->addWidget(samplerate192Btn);
|
hbox->addWidget(samplerate192Btn);
|
||||||
hbox->addWidget(samplerate384Btn);
|
hbox->addWidget(samplerate384Btn);
|
||||||
|
hbox->addWidget(samplerate768Btn);
|
||||||
QVBoxLayout *vbox = new QVBoxLayout();
|
hbox->addWidget(samplerate1536Btn);
|
||||||
|
updateSampleRateButtons();
|
||||||
|
|
||||||
|
QVBoxLayout *vbox = new QVBoxLayout();
|
||||||
vbox->setSpacing(4);
|
vbox->setSpacing(4);
|
||||||
vbox->addSpacing(6);
|
vbox->addSpacing(6);
|
||||||
vbox->addLayout(hbox);
|
vbox->addLayout(hbox);
|
||||||
@@ -940,21 +995,18 @@ void HPSDRWidget::source122_88MhzChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HPSDRWidget::sampleRateChanged() {
|
void HPSDRWidget::sampleRateChanged() {
|
||||||
|
|
||||||
AeroButton *button = qobject_cast<AeroButton *>(sender());
|
AeroButton *button = qobject_cast<AeroButton *>(sender());
|
||||||
int btnHit = samplerateBtnList.indexOf(button);
|
int btnHit = samplerateBtnList.indexOf(button);
|
||||||
|
|
||||||
foreach(AeroButton *btn, samplerateBtnList) {
|
const QList<int> rates = QList<int>() << 48000 << 96000 << 192000 << 384000 << 768000 << 1536000;
|
||||||
|
if (btnHit < 0 || btnHit >= rates.size() || !sampleRateSupported(rates.at(btnHit))) {
|
||||||
btn->setBtnState(AeroButton::OFF);
|
updateSampleRateButtons();
|
||||||
btn->update();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
button->setBtnState(AeroButton::ON);
|
switch (btnHit) {
|
||||||
button->update();
|
|
||||||
|
|
||||||
switch (btnHit) {
|
|
||||||
|
|
||||||
case 0:
|
case 0:
|
||||||
set->setSampleRate(this, 48000);
|
set->setSampleRate(this, 48000);
|
||||||
@@ -971,12 +1023,108 @@ void HPSDRWidget::sampleRateChanged() {
|
|||||||
HPSDR_WIDGET_DEBUG << "set sample rate to 192 kHz.";
|
HPSDR_WIDGET_DEBUG << "set sample rate to 192 kHz.";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
set->setSampleRate(this, 384000);
|
set->setSampleRate(this, 384000);
|
||||||
HPSDR_WIDGET_DEBUG << "set sample rate to 384 kHz.";
|
HPSDR_WIDGET_DEBUG << "set sample rate to 384 kHz.";
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
case 4:
|
||||||
|
set->setSampleRate(this, 768000);
|
||||||
|
HPSDR_WIDGET_DEBUG << "set sample rate to 768 kHz.";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
set->setSampleRate(this, 1536000);
|
||||||
|
HPSDR_WIDGET_DEBUG << "set sample rate to 1536 kHz.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSampleRateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HPSDRWidget::sampleRateValueChanged(QObject *sender, int value) {
|
||||||
|
|
||||||
|
Q_UNUSED(sender)
|
||||||
|
Q_UNUSED(value)
|
||||||
|
|
||||||
|
updateSampleRateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HPSDRWidget::setCurrentNetworkDevice(TNetworkDevicecard card) {
|
||||||
|
|
||||||
|
Q_UNUSED(card)
|
||||||
|
|
||||||
|
updateSampleRateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HPSDRWidget::protocol2SampleRatesEnabled() const {
|
||||||
|
|
||||||
|
const TNetworkDevicecard device = set->getCurrentMetisCard();
|
||||||
|
return device.protocolVersion >= 2 && device.individualDdcSampleRates;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HPSDRWidget::sampleRateSupported(int rate) const {
|
||||||
|
|
||||||
|
const TNetworkDevicecard device = set->getCurrentMetisCard();
|
||||||
|
if (device.protocolVersion < 2)
|
||||||
|
return rate <= 384000;
|
||||||
|
|
||||||
|
if (!device.individualDdcSampleRates)
|
||||||
|
return rate == 48000;
|
||||||
|
|
||||||
|
const int minRate = qMax(48000, device.minDdcSampleRateKsps > 0 ? device.minDdcSampleRateKsps * 1000 : 48000);
|
||||||
|
const int maxRate = device.maxDdcSampleRateKsps > 0 ? device.maxDdcSampleRateKsps * 1000 : 1536000;
|
||||||
|
return rate >= minRate && rate <= maxRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HPSDRWidget::updateSampleRateButtons() {
|
||||||
|
|
||||||
|
if (samplerateBtnList.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
const QList<int> rates = QList<int>() << 48000 << 96000 << 192000 << 384000 << 768000 << 1536000;
|
||||||
|
for (int i = 0; i < samplerateBtnList.size() && i < rates.size(); ++i)
|
||||||
|
samplerateBtnList.at(i)->setEnabled(sampleRateSupported(rates.at(i)));
|
||||||
|
|
||||||
|
if (!sampleRateSupported(set->getSampleRate())) {
|
||||||
|
int fallbackRate = 0;
|
||||||
|
for (int i = 0; i < rates.size(); ++i) {
|
||||||
|
if (sampleRateSupported(rates.at(i))) {
|
||||||
|
if (fallbackRate == 0)
|
||||||
|
fallbackRate = rates.at(i);
|
||||||
|
if (rates.at(i) <= set->getSampleRate())
|
||||||
|
fallbackRate = rates.at(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fallbackRate == 0)
|
||||||
|
fallbackRate = 48000;
|
||||||
|
set->setSampleRate(this, fallbackRate);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int currentRate = set->getSampleRate();
|
||||||
|
for (int i = 0; i < samplerateBtnList.size(); ++i) {
|
||||||
|
AeroButton *btn = samplerateBtnList.at(i);
|
||||||
|
btn->setBtnState(AeroButton::OFF);
|
||||||
|
btn->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
int selected = 0;
|
||||||
|
switch (currentRate) {
|
||||||
|
case 48000: selected = 0; break;
|
||||||
|
case 96000: selected = 1; break;
|
||||||
|
case 192000: selected = 2; break;
|
||||||
|
case 384000: selected = 3; break;
|
||||||
|
case 768000: selected = 4; break;
|
||||||
|
case 1536000: selected = 5; break;
|
||||||
|
default: selected = 0; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected >= 0 && selected < samplerateBtnList.size()) {
|
||||||
|
samplerateBtnList.at(selected)->setBtnState(AeroButton::ON);
|
||||||
|
samplerateBtnList.at(selected)->update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void HPSDRWidget::setNumberOfReceivers(int receivers) {
|
void HPSDRWidget::setNumberOfReceivers(int receivers) {
|
||||||
|
|
||||||
@@ -1017,7 +1165,8 @@ void HPSDRWidget::enableButtons() {
|
|||||||
penelopeBtn->setEnabled(true);
|
penelopeBtn->setEnabled(true);
|
||||||
mercuryBtn->setEnabled(true);
|
mercuryBtn->setEnabled(true);
|
||||||
penelope2Btn->setEnabled(true);
|
penelope2Btn->setEnabled(true);
|
||||||
mercury2Btn->setEnabled(true);
|
mercury2Btn->setEnabled(true);
|
||||||
|
|
||||||
m_receiverComboBox->setEnabled(true);
|
m_receiverComboBox->setEnabled(true);
|
||||||
}
|
updateSampleRateButtons();
|
||||||
|
}
|
||||||
|
|||||||
@@ -94,9 +94,11 @@ private:
|
|||||||
AeroButton *penelope2Btn;
|
AeroButton *penelope2Btn;
|
||||||
AeroButton *mercury2Btn;
|
AeroButton *mercury2Btn;
|
||||||
AeroButton *samplerate48Btn;
|
AeroButton *samplerate48Btn;
|
||||||
AeroButton *samplerate96Btn;
|
AeroButton *samplerate96Btn;
|
||||||
AeroButton *samplerate192Btn;
|
AeroButton *samplerate192Btn;
|
||||||
AeroButton *samplerate384Btn;
|
AeroButton *samplerate384Btn;
|
||||||
|
AeroButton *samplerate768Btn;
|
||||||
|
AeroButton *samplerate1536Btn;
|
||||||
|
|
||||||
QList<AeroButton *> hardwareBtnList;
|
QList<AeroButton *> hardwareBtnList;
|
||||||
QList<AeroButton *> source10MhzBtnList;
|
QList<AeroButton *> source10MhzBtnList;
|
||||||
@@ -117,9 +119,12 @@ private:
|
|||||||
int m_hpsdrHardware;
|
int m_hpsdrHardware;
|
||||||
int m_socketBufferSize;
|
int m_socketBufferSize;
|
||||||
|
|
||||||
void setupConnections();
|
void setupConnections();
|
||||||
void createSource10MhzExclusiveGroup();
|
void createSource10MhzExclusiveGroup();
|
||||||
void createSource122_88MhzExclusiveGroup();
|
void createSource122_88MhzExclusiveGroup();
|
||||||
|
void updateSampleRateButtons();
|
||||||
|
bool protocol2SampleRatesEnabled() const;
|
||||||
|
bool sampleRateSupported(int rate) const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void systemStateChanged(
|
void systemStateChanged(
|
||||||
@@ -132,10 +137,12 @@ private slots:
|
|||||||
void setHPSDRHardware();
|
void setHPSDRHardware();
|
||||||
void source10MhzChanged();
|
void source10MhzChanged();
|
||||||
void setNumberOfReceivers(int value);
|
void setNumberOfReceivers(int value);
|
||||||
void disableButtons();
|
void disableButtons();
|
||||||
void enableButtons();
|
void enableButtons();
|
||||||
void firmwareCheckChanged();
|
void firmwareCheckChanged();
|
||||||
void sampleRateChanged();
|
void sampleRateChanged();
|
||||||
|
void sampleRateValueChanged(QObject *sender, int value);
|
||||||
|
void setCurrentNetworkDevice(TNetworkDevicecard card);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void messageEvent(QString message);
|
void messageEvent(QString message);
|
||||||
|
|||||||
@@ -368,15 +368,11 @@ void MainWindow::setup() {
|
|||||||
// set the main window title
|
// set the main window title
|
||||||
updateTitle();
|
updateTitle();
|
||||||
|
|
||||||
// show the wideband data panel as specified in the settings.ini
|
// show the wideband data panel as specified in the settings.ini
|
||||||
if (set->getWidebandData()) {
|
wideBandBtn->setEnabled(m_serverMode != QSDR::ChirpWSPR);
|
||||||
|
if (set->getWidebandStatus()) {
|
||||||
wideBandBtn->setEnabled(true);
|
wideBandBtnClickedEvent();
|
||||||
|
}
|
||||||
if (set->getWidebandStatus()) {
|
|
||||||
wideBandBtnClickedEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the network interfaces
|
// get the network interfaces
|
||||||
getNetworkInterfaces();
|
getNetworkInterfaces();
|
||||||
@@ -1555,29 +1551,34 @@ void MainWindow::startButtonClickedEvent() {
|
|||||||
/*!
|
/*!
|
||||||
\brief implements the Show/Hide functionality of the wide band data widget.
|
\brief implements the Show/Hide functionality of the wide band data widget.
|
||||||
*/
|
*/
|
||||||
void MainWindow::wideBandBtnClickedEvent() {
|
void MainWindow::wideBandBtnClickedEvent() {
|
||||||
|
|
||||||
if (wideBandBtn->btnState() == AeroButton::OFF) {
|
if (wideBandBtn->btnState() == AeroButton::OFF) {
|
||||||
|
|
||||||
wideBandBtn->setBtnState(AeroButton::ON);
|
wideBandBtn->setBtnState(AeroButton::ON);
|
||||||
set->setWidebandStatus(this, true);
|
set->setWidebandData(this, true);
|
||||||
widebandDock->show();
|
set->setWidebandStatus(this, true);
|
||||||
//showMessage("[server]: wide band data on.");
|
widebandDock->show();
|
||||||
}
|
//showMessage("[server]: wide band data on.");
|
||||||
else if (wideBandBtn->btnState() == AeroButton::ON) {
|
}
|
||||||
|
else if (wideBandBtn->btnState() == AeroButton::ON) {
|
||||||
wideBandBtn->setBtnState(AeroButton::OFF);
|
|
||||||
set->setWidebandStatus(this, false);
|
wideBandBtn->setBtnState(AeroButton::OFF);
|
||||||
widebandDock->hide();
|
set->setWidebandData(this, false);
|
||||||
//showMessage("[server]: wide band data off.");
|
set->setWidebandStatus(this, false);
|
||||||
}
|
widebandDock->hide();
|
||||||
}
|
//showMessage("[server]: wide band data off.");
|
||||||
|
}
|
||||||
void MainWindow::widebandVisibilityChanged(bool value) {
|
}
|
||||||
|
|
||||||
if (value)
|
void MainWindow::widebandVisibilityChanged(bool value) {
|
||||||
wideBandBtn->setBtnState(AeroButton::ON);
|
|
||||||
else
|
set->setWidebandData(this, value);
|
||||||
|
set->setWidebandStatus(this, value);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
wideBandBtn->setBtnState(AeroButton::ON);
|
||||||
|
else
|
||||||
wideBandBtn->setBtnState(AeroButton::OFF);
|
wideBandBtn->setBtnState(AeroButton::OFF);
|
||||||
|
|
||||||
wideBandBtn->update();
|
wideBandBtn->update();
|
||||||
|
|||||||
@@ -65,6 +65,33 @@ Settings::Settings(QObject *parent)
|
|||||||
qRegisterMetaType<QList<TNetworkDevicecard> >();
|
qRegisterMetaType<QList<TNetworkDevicecard> >();
|
||||||
qRegisterMetaType<qVectorFloat>("qVectorFloat");
|
qRegisterMetaType<qVectorFloat>("qVectorFloat");
|
||||||
|
|
||||||
|
m_currentHPSDRDevice.ip_address = QHostAddress();
|
||||||
|
m_currentHPSDRDevice.mac_address[0] = '\0';
|
||||||
|
m_currentHPSDRDevice.boardID = -1;
|
||||||
|
m_currentHPSDRDevice.boardName = "";
|
||||||
|
m_currentHPSDRDevice.protocolVersion = 0;
|
||||||
|
m_currentHPSDRDevice.firmwareVersion = 0;
|
||||||
|
m_currentHPSDRDevice.adcCount = 0;
|
||||||
|
m_currentHPSDRDevice.ddcCount = 0;
|
||||||
|
m_currentHPSDRDevice.dspClockHz = 0;
|
||||||
|
m_currentHPSDRDevice.individualDdcSampleRates = false;
|
||||||
|
m_currentHPSDRDevice.minDdcSampleRateKsps = 48;
|
||||||
|
m_currentHPSDRDevice.maxDdcSampleRateKsps = 384;
|
||||||
|
m_currentHPSDRDevice.widebandData = false;
|
||||||
|
m_currentHPSDRDevice.widebandSamplesPerPacket = 0;
|
||||||
|
m_currentHPSDRDevice.widebandBitsPerSample = 0;
|
||||||
|
m_currentHPSDRDevice.ducCount = 0;
|
||||||
|
m_currentHPSDRDevice.ducSampleRateKsps = 0;
|
||||||
|
m_currentHPSDRDevice.ducBitsPerSample = 0;
|
||||||
|
m_currentHPSDRDevice.ducSamplesPerPacket = 0;
|
||||||
|
m_currentHPSDRDevice.iqFormatFlags = 0;
|
||||||
|
m_currentHPSDRDevice.phaseWords = false;
|
||||||
|
m_currentHPSDRDevice.ducPhaseWords = false;
|
||||||
|
m_currentHPSDRDevice.ddcAttenuator = false;
|
||||||
|
m_currentHPSDRDevice.ducRxAttenuator = false;
|
||||||
|
m_currentHPSDRDevice.hasAlex0 = false;
|
||||||
|
m_currentHPSDRDevice.hasAlex1 = false;
|
||||||
|
|
||||||
startTime = QDateTime::currentDateTime();
|
startTime = QDateTime::currentDateTime();
|
||||||
|
|
||||||
qDebug() << "************************************************************************";
|
qDebug() << "************************************************************************";
|
||||||
@@ -289,7 +316,8 @@ int Settings::loadSettings() {
|
|||||||
//checkHPSDRDevices();
|
//checkHPSDRDevices();
|
||||||
|
|
||||||
value = settings->value("server/sample_rate", 48000).toInt();
|
value = settings->value("server/sample_rate", 48000).toInt();
|
||||||
if ((value != 48000) & (value != 96000) & (value != 192000) & (value != 384000)) value = 48000;
|
if ((value != 48000) && (value != 96000) && (value != 192000) &&
|
||||||
|
(value != 384000) && (value != 768000) && (value != 1536000)) value = 48000;
|
||||||
setSampleRate(this, value);
|
setSampleRate(this, value);
|
||||||
|
|
||||||
str = settings->value("server/dither", "off").toString();
|
str = settings->value("server/dither", "off").toString();
|
||||||
@@ -642,7 +670,7 @@ int Settings::loadSettings() {
|
|||||||
//******************************************************************
|
//******************************************************************
|
||||||
// wideband settings
|
// wideband settings
|
||||||
|
|
||||||
str = settings->value("wideband/widebandData", "on").toString();
|
str = settings->value("wideband/widebandData", "off").toString();
|
||||||
if (str.toLower() == "on")
|
if (str.toLower() == "on")
|
||||||
m_widebandOptions.wideBandData = true;
|
m_widebandOptions.wideBandData = true;
|
||||||
else if (str.toLower() == "off")
|
else if (str.toLower() == "off")
|
||||||
@@ -658,7 +686,10 @@ int Settings::loadSettings() {
|
|||||||
else
|
else
|
||||||
m_widebandOptions.wideBandDisplayStatus = false;
|
m_widebandOptions.wideBandDisplayStatus = false;
|
||||||
|
|
||||||
if (!m_widebandOptions.wideBandData) m_widebandOptions.wideBandDisplayStatus = false;
|
if (!m_widebandOptions.wideBandData)
|
||||||
|
m_widebandOptions.wideBandDisplayStatus = false;
|
||||||
|
if (!m_widebandOptions.wideBandDisplayStatus)
|
||||||
|
m_widebandOptions.wideBandData = false;
|
||||||
|
|
||||||
str = settings->value("wideband/averaging", "on").toString();
|
str = settings->value("wideband/averaging", "on").toString();
|
||||||
if (str.toLower() == "on")
|
if (str.toLower() == "on")
|
||||||
@@ -3352,16 +3383,30 @@ void Settings::setSampleRate(QObject *sender, int value) {
|
|||||||
m_outputSampleIncrement = 8;
|
m_outputSampleIncrement = 8;
|
||||||
m_chirpDownSampleRate = 32;
|
m_chirpDownSampleRate = 32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 768000:
|
||||||
|
m_sampleRate = value;
|
||||||
|
m_mercurySpeed = 3;
|
||||||
|
m_outputSampleIncrement = 16;
|
||||||
|
m_chirpDownSampleRate = 64;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1536000:
|
||||||
|
m_sampleRate = value;
|
||||||
|
m_mercurySpeed = 3;
|
||||||
|
m_outputSampleIncrement = 32;
|
||||||
|
m_chirpDownSampleRate = 128;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
SETTINGS_DEBUG << "Invalid sample rate (must be 48, 96,192, or 384 kHz)!\n";
|
SETTINGS_DEBUG << "Invalid sample rate (must be 48, 96, 192, 384, 768, or 1536 kHz)!\n";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < MAX_RECEIVERS; i++)
|
for (int i = 0; i < MAX_RECEIVERS; i++)
|
||||||
m_receiverDataList[i].sampleRate = m_sampleRate;
|
m_receiverDataList[i].sampleRate = m_sampleRate;
|
||||||
|
|
||||||
emit sampleRateChanged(sender, value);
|
emit sampleRateChanged(sender, m_sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Settings::setMercuryAttenuator(QObject *sender, int value) {
|
void Settings::setMercuryAttenuator(QObject *sender, int value) {
|
||||||
|
|||||||
@@ -488,8 +488,21 @@ typedef struct _networkDeviceCard {
|
|||||||
int adcCount;
|
int adcCount;
|
||||||
int ddcCount;
|
int ddcCount;
|
||||||
int dspClockHz;
|
int dspClockHz;
|
||||||
|
bool individualDdcSampleRates;
|
||||||
|
int minDdcSampleRateKsps;
|
||||||
|
int maxDdcSampleRateKsps;
|
||||||
|
bool widebandData;
|
||||||
|
int widebandSamplesPerPacket;
|
||||||
|
int widebandBitsPerSample;
|
||||||
|
int ducCount;
|
||||||
|
int ducSampleRateKsps;
|
||||||
|
int ducBitsPerSample;
|
||||||
|
int ducSamplesPerPacket;
|
||||||
int iqFormatFlags;
|
int iqFormatFlags;
|
||||||
bool phaseWords;
|
bool phaseWords;
|
||||||
|
bool ducPhaseWords;
|
||||||
|
bool ddcAttenuator;
|
||||||
|
bool ducRxAttenuator;
|
||||||
bool hasAlex0;
|
bool hasAlex0;
|
||||||
bool hasAlex1;
|
bool hasAlex1;
|
||||||
|
|
||||||
|
|||||||
+25
@@ -27,3 +27,28 @@
|
|||||||
пн апр. 13 21:24:23 2026: planning FFT size 128 ...
|
пн апр. 13 21:24:23 2026: planning FFT size 128 ...
|
||||||
пн апр. 13 21:24:23 2026: planning FFT size 256 ...
|
пн апр. 13 21:24:23 2026: planning FFT size 256 ...
|
||||||
пн апр. 13 21:24:24 2026: planning FFT size 512 ...
|
пн апр. 13 21:24:24 2026: planning FFT size 512 ...
|
||||||
|
ср апр. 29 16:23:06 2026: ************************************************************************
|
||||||
|
ср апр. 29 16:23:06 2026: Settings:: start at: ср апр. 29 16:23:06 2026
|
||||||
|
ср апр. 29 16:23:06 2026: cudaSDR BETA
|
||||||
|
ср апр. 29 16:23:07 2026: Settings:: Alex config: 4098
|
||||||
|
ср апр. 29 16:23:07 2026: Settings:: reading done.
|
||||||
|
ср апр. 29 16:23:07 2026: Init:: OpenGL found.
|
||||||
|
ср апр. 29 16:23:07 2026: Init:: Framebuffer Objects found.
|
||||||
|
ср апр. 29 16:23:07 2026: Init:: main window setup ...
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: main window init done
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: server ip from ini-file: "192.168.122.1"
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: HPSDR device local ip from ini-file: "172.16.2.99"
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: network interface "bridge0" :
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: -> broadcast address: 172.16.2.255
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: -> ip address: 172.16.2.99
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: network interface "virbr0" :
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: -> broadcast address: 192.168.122.255
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: -> ip address: 192.168.122.1
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: found 2 valid ip addresses.
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: HPSDR network device interface set to: "bridge0"("172.16.2.99")
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: HPSDR network device interface set to: "bridge0"("172.16.2.99")
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: using ip address 192.168.122.1 for the server.
|
||||||
|
ср апр. 29 16:23:08 2026: MainWindow:: using ip address 172.16.2.99 for connecting to a HPSDR device.
|
||||||
|
ср апр. 29 16:23:08 2026: Init:: main window setup done.
|
||||||
|
ср апр. 29 16:23:08 2026: Init:: current path: /home/vladimir/Документы/source/cudaSDR
|
||||||
|
ср апр. 29 16:23:08 2026: Init:: fftw_wisdom does not exist - planning FFT...
|
||||||
|
|||||||
Reference in New Issue
Block a user