File: WSJTXMessageMapper.cpp

package info (click to toggle)
js8call 2.5.2%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 24,720 kB
  • sloc: cpp: 562,651; sh: 898; python: 132; ansic: 102; makefile: 4
file content (224 lines) | stat: -rw-r--r-- 9,012 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
#include "WSJTXMessageMapper.h"
#include "JS8_UI/mainwindow.h"
#include <QLoggingCategory>
#include <limits>

Q_LOGGING_CATEGORY(wsjtx_mapper_js8, "wsjtx.mapper.js8", QtWarningMsg)

/**
 * @brief Construct a WSJT-X message mapper
 *
 * Sets up signal connections to handle incoming WSJT-X protocol messages
 * and map them to JS8Call actions.
 *
 * @param client WSJT-X message client to send messages through
 * @param main_window Main window instance for accessing JS8Call state
 * @param parent Parent QObject
 */
WSJTXMessageMapper::WSJTXMessageMapper(WSJTXMessageClient *client,
                                       MainWindow *main_window, QObject *parent)
    : QObject{parent}, client_{client}, main_window_{main_window} {
    connect(client_, &WSJTXMessageClient::reply, this,
            &WSJTXMessageMapper::handleReply);
    connect(client_, &WSJTXMessageClient::free_text, this,
            &WSJTXMessageMapper::handleFreeText);
    connect(client_, &WSJTXMessageClient::halt_tx, this,
            &WSJTXMessageMapper::handleHaltTx);
    connect(client_, &WSJTXMessageClient::location, this,
            &WSJTXMessageMapper::handleLocation);
}

/**
 * @brief Send a Status update message
 *
 * Maps JS8Call's status information to WSJT-X Status message format and
 * sends it through the WSJT-X message client.
 *
 * @param dial_freq Dial frequency (Hz)
 * @param offset Frequency offset (Hz)
 * @param mode Operating mode string
 * @param dx_call DX station callsign (selected station)
 * @param de_call My callsign
 * @param de_grid My grid square
 * @param dx_grid DX station grid square
 * @param tx_enabled Whether TX is enabled
 * @param transmitting Whether currently transmitting
 * @param decoding Whether currently decoding
 * @param tx_message Current TX message text
 */
void WSJTXMessageMapper::sendStatusUpdate(
    Radio::Frequency dial_freq, Radio::Frequency offset, QString const &mode,
    QString const &dx_call, QString const &de_call, QString const &de_grid,
    QString const &dx_grid, bool tx_enabled, bool transmitting, bool decoding,
    QString const &tx_message) {
    qCDebug(wsjtx_mapper_js8)
        << "WSJTXMessageMapper: sendStatusUpdate called"
        << "dial_freq:" << dial_freq << "offset:" << offset << "mode:" << mode
        << "dx_call:" << dx_call << "de_call:" << de_call
        << "de_grid:" << de_grid << "dx_grid:" << dx_grid
        << "tx_enabled:" << tx_enabled << "transmitting:" << transmitting
        << "decoding:" << decoding;
    Radio::Frequency freq = dial_freq + offset;
    QString submode = mode;     // JS8Call submode
    bool fast_mode = false;     // Map from JS8Call speed
    quint8 special_op_mode = 0; // NONE
    quint32 frequency_tolerance = std::numeric_limits<quint32>::max();
    quint32 tr_period = std::numeric_limits<quint32>::max();
    QString configuration_name = "";

    client_->status_update(
        freq, mode, dx_call, "", mode, tx_enabled, transmitting, decoding,
        static_cast<quint32>(offset), static_cast<quint32>(offset), de_call,
        de_grid, dx_grid, false, submode, fast_mode, special_op_mode,
        frequency_tolerance, tr_period, configuration_name, tx_message);
}

/**
 * @brief Send a Decode message
 *
 * Maps JS8Call's decode information to WSJT-X Decode message format and
 * sends it through the WSJT-X message client.
 *
 * @param is_new Whether this is a new decode
 * @param time Decode time
 * @param snr Signal-to-noise ratio (dB)
 * @param delta_time Time offset from expected time (seconds)
 * @param delta_frequency Frequency offset from nominal (Hz)
 * @param mode Operating mode string
 * @param message Decoded message text
 * @param low_confidence Whether decode confidence is low
 */
void WSJTXMessageMapper::sendDecode(bool is_new, QTime time, qint32 snr,
                                    float delta_time, quint32 delta_frequency,
                                    QString const &mode, QString const &message,
                                    bool low_confidence) {
    qCDebug(wsjtx_mapper_js8)
        << "WSJTXMessageMapper: sendDecode called"
        << "is_new:" << is_new << "time:" << time.toString("hh:mm:ss")
        << "snr:" << snr << "delta_time:" << delta_time
        << "delta_frequency:" << delta_frequency << "mode:" << mode
        << "message:" << message << "low_confidence:" << low_confidence;
    client_->decode(is_new, time, snr, delta_time, delta_frequency, mode,
                    message, low_confidence, false);
}

/**
 * @brief Send a QSO Logged message
 *
 * Maps JS8Call's QSO log information to WSJT-X QSOLogged message format and
 * sends it through the WSJT-X message client.
 *
 * @param time_off QSO end time
 * @param dx_call DX station callsign
 * @param dx_grid DX station grid square
 * @param dial_frequency Dial frequency (Hz)
 * @param mode Operating mode
 * @param report_sent Report sent to DX station
 * @param report_received Report received from DX station
 * @param my_call My callsign
 * @param my_grid My grid square
 */
void WSJTXMessageMapper::sendQSOLogged(
    QDateTime time_off, QString const &dx_call, QString const &dx_grid,
    Radio::Frequency dial_frequency, QString const &mode,
    QString const &report_sent, QString const &report_received,
    QString const &my_call, QString const &my_grid) {
    qCDebug(wsjtx_mapper_js8)
        << "WSJTXMessageMapper: sendQSOLogged called"
        << "time_off:" << time_off.toString(Qt::ISODate)
        << "dx_call:" << dx_call << "dx_grid:" << dx_grid
        << "dial_frequency:" << dial_frequency << "mode:" << mode
        << "report_sent:" << report_sent
        << "report_received:" << report_received << "my_call:" << my_call
        << "my_grid:" << my_grid;
    QDateTime time_on = time_off; // JS8Call doesn't track time_on separately
    QString operator_call = "";
    QString exchange_sent = "";
    QString exchange_rcvd = "";
    QString propmode = "";

    client_->qso_logged(time_off, dx_call, dx_grid, dial_frequency, mode,
                        report_sent, report_received, "", "", "", time_on,
                        operator_call, my_call, my_grid, exchange_sent,
                        exchange_rcvd, propmode);
}

/**
 * @brief Handle incoming Reply message from WSJT-X protocol
 *
 * Maps WSJT-X Reply message to JS8Call action. This would trigger a reply
 * in JS8Call similar to double-clicking a decode.
 *
 * @param time Reply time (unused)
 * @param snr Signal-to-noise ratio (unused)
 * @param delta_time Time offset (unused)
 * @param delta_frequency Frequency offset (unused)
 * @param mode Operating mode (unused)
 * @param message_text Reply message text (unused)
 * @param low_confidence Whether decode confidence is low (unused)
 * @param modifiers Message modifiers (unused)
 */
void WSJTXMessageMapper::handleReply(QTime /*time*/, qint32 /*snr*/,
                                     float /*delta_time*/,
                                     quint32 /*delta_frequency*/,
                                     QString const & /*mode*/,
                                     QString const & /*message_text*/,
                                     bool /*low_confidence*/,
                                     quint8 /*modifiers*/) {
    // Map WSJT-X Reply to JS8Call action
    // This would trigger a reply in JS8Call similar to double-clicking a decode
    // Implementation depends on MainWindow API - for now, just send as network
    // message
    if (main_window_) {
        // TODO: Map to appropriate JS8Call action
        // main_window_->sendNetworkMessage("REPLY", message_text);
    }
}

/**
 * @brief Handle incoming Free Text message from WSJT-X protocol
 *
 * Maps WSJT-X Free Text message to JS8Call TX.SET_TEXT and optionally
 * TX.SEND_MESSAGE network messages.
 *
 * @param text Free text to send
 * @param send Whether to send immediately
 */
void WSJTXMessageMapper::handleFreeText(QString const &text, bool send) {
    // Map to JS8Call TX.SET_TEXT message
    if (main_window_) {
        main_window_->sendNetworkMessage("TX.SET_TEXT", text);
        if (send) {
            main_window_->sendNetworkMessage("TX.SEND_MESSAGE", text);
        }
    }
}

/**
 * @brief Handle incoming Halt TX message from WSJT-X protocol
 *
 * Maps WSJT-X Halt TX message to JS8Call TX halt action.
 *
 * @param auto_only If true, only halt auto sequences
 */
void WSJTXMessageMapper::handleHaltTx(bool auto_only) {
    // Stop transmission
    if (main_window_ && !auto_only) {
        // TODO: Stop TX immediately
        // main_window_->sendNetworkMessage("TX.HALT", "");
    }
}

/**
 * @brief Handle incoming Location message from WSJT-X protocol
 *
 * Maps WSJT-X Location message to JS8Call STATION.SET_GRID network message.
 *
 * @param location Grid square or location string
 */
void WSJTXMessageMapper::handleLocation(QString const &location) {
    // Map to JS8Call STATION.SET_GRID
    if (main_window_) {
        main_window_->sendNetworkMessage("STATION.SET_GRID", location);
    }
}