1 #ifndef NETWORK_MESSAGE_HPP__
2 #define NETWORK_MESSAGE_HPP__
3 
4 /*
5  * WSJT-X Message Formats
6  * ======================
7  *
8  * All messages are written or  read using the QDataStream derivatives
9  * defined  below, note  that we  are using  the default  for floating
10  * point precision  which means all  are double precision  i.e. 64-bit
11  * IEEE format.
12  *
13  *  Message is big endian format
14  *
15  *   Header format:
16  *
17  *      32-bit unsigned integer magic number 0xadbccbda
18  *      32-bit unsigned integer schema number
19  *
20  *   Payload format:
21  *
22  *      As per the QDataStream format,  see below for version used and
23  *      here:
24  *
25  *        http://doc.qt.io/qt-5/datastreamformat.html
26  *
27  *      for the  serialization details for  each type, at the  time of
28  *      writing the above document is for Qt_5_0 format which is buggy
29  *      so we use Qt_5_4 format, differences are:
30  *
31  *      QDateTime:
32  *           QDate      qint64    Julian day number
33  *           QTime      quint32   Milli-seconds since midnight
34  *           timespec   quint8    0=local, 1=UTC, 2=Offset from UTC
35  *                                                 (seconds)
36  *                                3=time zone
37  *           offset     qint32    only present if timespec=2
38  *           timezone   several-fields only present if timespec=3
39  *
40  *      we  will avoid  using  QDateTime fields  with  time zones  for
41  *      simplicity.
42  *
43  * Type utf8  is a  utf-8 byte  string formatted  as a  QByteArray for
44  * serialization purposes  (currently a quint32 size  followed by size
45  * bytes, no terminator is present or counted).
46  *
47  * The QDataStream  format document linked  above is not  complete for
48  * the QByteArray serialization  format, it is similar  to the QString
49  * serialization  format  in  that  it  differentiates  between  empty
50  * strings  and null  strings. Empty  strings  have a  length of  zero
51  * whereas null strings have a length field of 0xffffffff.
52  *
53  *
54  * Schema Negotiation
55  * ------------------
56  *
57  * The NetworkMessage::Builder  class specifies a schema  number which
58  * may be  incremented from time to  time. It represents a  version of
59  * the underlying encoding schemes used to store data items. Since the
60  * underlying  encoding  is   defined  by  the  Qt   project  in  it's
61  * QDataStream  stream operators,  it  is essential  that clients  and
62  * servers  of  this protocol  can  agree  on  a common  scheme.   The
63  * NetworkMessage  utility classes  below exchange  the schema  number
64  * actually used.  The handling of  the schema is backwards compatible
65  * to  an  extent,  so  long   as  clients  and  servers  are  written
66  * correctly. For  example a server  written to any  particular schema
67  * version can communicate with a client written to a later schema.
68  *
69  * Schema Version 1:- this schema used the QDataStream::Qt_5_0 version
70  *  which is broken.
71  *
72  * Schema Version 2:- this schema uses the QDataStream::Qt_5_2 version.
73  *
74  * Schema Version 3:- this schema uses the QDataStream::Qt_5_4 version.
75  *
76  *
77  * Backward Compatibility
78  * ----------------------
79  *
80  * It  is important  that  applications developed  at different  times
81  * remain  compatible  with this  protocol  and  with older  or  newer
82  * versions  of   WSJT-X.   This  is  achieved   by  both  third-party
83  * applications and WSJT-X honouring two basic rules.
84  *
85  * 1. New  message types may be  added to the protocol  in the future,
86  *    third-party applications  and WSJT-X  shall ignore  silently any
87  *    message types they do not recognize.
88  *
89  * 2. New  fields may be  added to  existing message types,  they will
90  *    always be added to the end of the existing fields and the number
91  *    and type  of existing fields shall  not change. If a  field type
92  *    must be  changed; a  new field  will be  added and  the existing
93  *    field  will  remain. The  originator  of  such a  message  shall
94  *    populate   both  the   new   and  old   field  with   reasonable
95  *    values.  Third-party   applications  and  WSJT-X   shall  ignore
96  *    silently any extra  data received in datagrams  after the fields
97  *    they know about.
98  *
99  * Note  that these  rules are  unrelated to  the schema  number above
100  * whose purpose is to distinguish between non-compatible encodings of
101  * field data  types. New message  types and extra fields  in existing
102  * messages can and will be added without any change in schema number.
103  *
104  *
105  * Message Types
106  * -------------
107  *
108  * Message       Direction Value                  Type
109  * ------------- --------- ---------------------- -----------
110  * Heartbeat     Out/In    0                      quint32
111  *                         Id (unique key)        utf8
112  *                         Maximum schema number  quint32
113  *                         version                utf8
114  *                         revision               utf8
115  *
116  *    The heartbeat  message shall be  sent on a periodic  basis every
117  *    NetworkMessage::pulse   seconds   (see    below),   the   WSJT-X
118  *    application  does  that  using the  MessageClient  class.   This
119  *    message is intended to be used by servers to detect the presence
120  *    of a  client and also  the unexpected disappearance of  a client
121  *    and  by clients  to learn  the schema  negotiated by  the server
122  *    after it receives  the initial heartbeat message  from a client.
123  *    The message_aggregator reference server does just that using the
124  *    MessageServer class. Upon  initial startup a client  must send a
125  *    heartbeat message as soon as  is practical, this message is used
126  *    to negotiate the maximum schema  number common to the client and
127  *    server. Note  that the  server may  not be  able to  support the
128  *    client's  requested maximum  schema  number, in  which case  the
129  *    first  message received  from the  server will  specify a  lower
130  *    schema number (never a higher one  as that is not allowed). If a
131  *    server replies  with a lower  schema number then no  higher than
132  *    that number shall be used for all further outgoing messages from
133  *    either clients or the server itself.
134  *
135  *    Note: the  "Maximum schema number"  field was introduced  at the
136  *    same time as schema 3, therefore servers and clients must assume
137  *    schema 2 is the highest schema number supported if the Heartbeat
138  *    message does not contain the "Maximum schema number" field.
139  *
140  *
141  * Status        Out       1                      quint32
142  *                         Id (unique key)        utf8
143  *                         Dial Frequency (Hz)    quint64
144  *                         Mode                   utf8
145  *                         DX call                utf8
146  *                         Report                 utf8
147  *                         Tx Mode                utf8
148  *                         Tx Enabled             bool
149  *                         Transmitting           bool
150  *                         Decoding               bool
151  *                         Rx DF                  quint32
152  *                         Tx DF                  quint32
153  *                         DE call                utf8
154  *                         DE grid                utf8
155  *                         DX grid                utf8
156  *                         Tx Watchdog            bool
157  *                         Sub-mode               utf8
158  *                         Fast mode              bool
159  *                         Special Operation Mode quint8
160  *                         Frequency Tolerance    quint32
161  *                         T/R Period             quint32
162  *                         Configuration Name     utf8
163  *                         Tx Message             utf8
164  *
165  *    WSJT-X  sends this  status message  when various  internal state
166  *    changes to allow the server to  track the relevant state of each
167  *    client without the need for  polling commands. The current state
168  *    changes that generate status messages are:
169  *
170  *      Application start up,
171  *      "Enable Tx" button status changes,
172  *      dial frequency changes,
173  *      changes to the "DX Call" field,
174  *      operating mode, sub-mode or fast mode changes,
175  *      transmit mode changed (in dual JT9+JT65 mode),
176  *      changes to the "Rpt" spinner,
177  *      after an old decodes replay sequence (see Replay below),
178  *      when switching between Tx and Rx mode,
179  *      at the start and end of decoding,
180  *      when the Rx DF changes,
181  *      when the Tx DF changes,
182  *      when settings are exited,
183  *      when the DX call or grid changes,
184  *      when the Tx watchdog is set or reset,
185  *      when the frequency tolerance is changed,
186  *      when the T/R period is changed,
187  *      when the configuration name changes,
188  *      when the message being transmitted changes.
189  *
190  *    The Special operation mode is  an enumeration that indicates the
191  *    setting  selected  in  the  WSJT-X  "Settings->Advanced->Special
192  *    operating activity" panel. The values are as follows:
193  *
194  *       0 -> NONE
195  *       1 -> NA VHF
196  *       2 -> EU VHF
197  *       3 -> FIELD DAY
198  *       4 -> RTTY RU
199  *       5 -> WW DIGI
200  *       6 -> FOX
201  *       7 -> HOUND
202  *
203  *    The Frequency Tolerance  and T/R period fields may  have a value
204  *    of  the maximum  quint32 value  which implies  the field  is not
205  *    applicable.
206  *
207  *
208  * Decode        Out       2                      quint32
209  *                         Id (unique key)        utf8
210  *                         New                    bool
211  *                         Time                   QTime
212  *                         snr                    qint32
213  *                         Delta time (S)         float (serialized as double)
214  *                         Delta frequency (Hz)   quint32
215  *                         Mode                   utf8
216  *                         Message                utf8
217  *                         Low confidence         bool
218  *                         Off air                bool
219  *
220  *      The decode message is sent when  a new decode is completed, in
221  *      this case the 'New' field is true. It is also used in response
222  *      to  a "Replay"  message where  each  old decode  in the  "Band
223  *      activity" window, that  has not been erased, is  sent in order
224  *      as a one of these messages  with the 'New' field set to false.
225  *      See  the "Replay"  message below  for details  of usage.   Low
226  *      confidence decodes are flagged  in protocols where the decoder
227  *      has knows that  a decode has a higher  than normal probability
228  *      of  being  false, they  should  not  be reported  on  publicly
229  *      accessible services  without some attached warning  or further
230  *      validation. Off air decodes are those that result from playing
231  *      back a .WAV file.
232  *
233  *
234  * Clear         Out/In    3                      quint32
235  *                         Id (unique key)        utf8
236  *                         Window                 quint8 (In only)
237  *
238  *      This message is  send when all prior "Decode"  messages in the
239  *      "Band Activity"  window have been discarded  and therefore are
240  *      no long available for actioning  with a "Reply" message. It is
241  *      sent when the user erases  the "Band activity" window and when
242  *      WSJT-X  closes down  normally. The  server should  discard all
243  *      decode messages upon receipt of this message.
244  *
245  *      It may  also be  sent to  a WSJT-X instance  in which  case it
246  *      clears one or  both of the "Band Activity"  and "Rx Frequency"
247  *      windows.  The Window  argument  can be  one  of the  following
248  *      values:
249  *
250  *         0  - clear the "Band Activity" window (default)
251  *         1  - clear the "Rx Frequency" window
252  *         2  - clear both "Band Activity" and "Rx Frequency" windows
253  *
254  *
255  * Reply         In        4                      quint32
256  *                         Id (target unique key) utf8
257  *                         Time                   QTime
258  *                         snr                    qint32
259  *                         Delta time (S)         float (serialized as double)
260  *                         Delta frequency (Hz)   quint32
261  *                         Mode                   utf8
262  *                         Message                utf8
263  *                         Low confidence         bool
264  *                         Modifiers              quint8
265  *
266  *      In order for a server  to provide a useful cooperative service
267  *      to WSJT-X it  is possible for it to initiate  a QSO by sending
268  *      this message to a client. WSJT-X filters this message and only
269  *      acts upon it  if the message exactly describes  a prior decode
270  *      and that decode  is a CQ or QRZ message.   The action taken is
271  *      exactly equivalent to the user  double clicking the message in
272  *      the "Band activity" window. The  intent of this message is for
273  *      servers to be able to provide an advanced look up of potential
274  *      QSO partners, for example determining if they have been worked
275  *      before  or if  working them  may advance  some objective  like
276  *      award progress.  The  intention is not to  provide a secondary
277  *      user  interface for  WSJT-X,  it is  expected  that after  QSO
278  *      initiation the rest  of the QSO is carried  out manually using
279  *      the normal WSJT-X user interface.
280  *
281  *      The  Modifiers   field  allows  the  equivalent   of  keyboard
282  *      modifiers to be sent "as if" those modifier keys where pressed
283  *      while  double-clicking  the  specified  decoded  message.  The
284  *      modifier values (hexadecimal) are as follows:
285  *
286  *          no modifier     0x00
287  *          SHIFT           0x02
288  *          CTRL            0x04  CMD on Mac
289  *          ALT             0x08
290  *          META            0x10  Windows key on MS Windows
291  *          KEYPAD          0x20  Keypad or arrows
292  *          Group switch    0x40  X11 only
293  *
294  *
295  * QSO Logged    Out       5                      quint32
296  *                         Id (unique key)        utf8
297  *                         Date & Time Off        QDateTime
298  *                         DX call                utf8
299  *                         DX grid                utf8
300  *                         Tx frequency (Hz)      quint64
301  *                         Mode                   utf8
302  *                         Report sent            utf8
303  *                         Report received        utf8
304  *                         Tx power               utf8
305  *                         Comments               utf8
306  *                         Name                   utf8
307  *                         Date & Time On         QDateTime
308  *                         Operator call          utf8
309  *                         My call                utf8
310  *                         My grid                utf8
311  *                         Exchange sent          utf8
312  *                         Exchange received      utf8
313  *                         ADIF Propagation mode  utf8
314  *
315  *      The  QSO logged  message is  sent  to the  server(s) when  the
316  *      WSJT-X user accepts the "Log  QSO" dialog by clicking the "OK"
317  *      button.
318  *
319  *
320  * Close         Out/In    6                      quint32
321  *                         Id (unique key)        utf8
322  *
323  *      Close is  sent by  a client immediately  prior to  it shutting
324  *      down gracefully. When sent by  a server it requests the target
325  *      client to close down gracefully.
326  *
327  *
328  * Replay        In        7                      quint32
329  *                         Id (unique key)        utf8
330  *
331  *      When a server starts it may  be useful for it to determine the
332  *      state  of preexisting  clients. Sending  this message  to each
333  *      client as it is discovered  will cause that client (WSJT-X) to
334  *      send a "Decode" message for each decode currently in its "Band
335  *      activity"  window. Each  "Decode" message  sent will  have the
336  *      "New" flag set to false so that they can be distinguished from
337  *      new decodes. After  all the old decodes have  been broadcast a
338  *      "Status" message  is also broadcast.  If the server  wishes to
339  *      determine  the  status  of  a newly  discovered  client;  this
340  *      message should be used.
341  *
342  *
343  * Halt Tx       In        8
344  *                         Id (unique key)        utf8
345  *                         Auto Tx Only           bool
346  *
347  *      The server may stop a client from transmitting messages either
348  *      immediately or at  the end of the  current transmission period
349  *      using this message.
350  *
351  *
352  * Free Text     In        9
353  *                         Id (unique key)        utf8
354  *                         Text                   utf8
355  *                         Send                   bool
356  *
357  *      This message  allows the server  to set the current  free text
358  *      message content. Sending this  message with a non-empty "Text"
359  *      field is equivalent to typing  a new message (old contents are
360  *      discarded) in to  the WSJT-X free text message  field or "Tx5"
361  *      field (both  are updated) and if  the "Send" flag is  set then
362  *      clicking the "Now" radio button for the "Tx5" field if tab one
363  *      is current or clicking the "Free  msg" radio button if tab two
364  *      is current.
365  *
366  *      It is the responsibility of the  sender to limit the length of
367  *      the  message   text  and   to  limit   it  to   legal  message
368  *      characters. Despite this,  it may be difficult  for the sender
369  *      to determine the maximum message length without reimplementing
370  *      the complete message encoding protocol. Because of this is may
371  *      be better  to allow any  reasonable message length and  to let
372  *      the WSJT-X application encode and possibly truncate the actual
373  *      on-air message.
374  *
375  *      If the  message text is  empty the  meaning of the  message is
376  *      refined  to send  the  current free  text  unchanged when  the
377  *      "Send" flag is set or to  clear the current free text when the
378  *      "Send" flag is  unset.  Note that this API does  not include a
379  *      command to  determine the  contents of  the current  free text
380  *      message.
381  *
382  *
383  * WSPRDecode    Out       10                     quint32
384  *                         Id (unique key)        utf8
385  *                         New                    bool
386  *                         Time                   QTime
387  *                         snr                    qint32
388  *                         Delta time (S)         float (serialized as double)
389  *                         Frequency (Hz)         quint64
390  *                         Drift (Hz)             qint32
391  *                         Callsign               utf8
392  *                         Grid                   utf8
393  *                         Power (dBm)            qint32
394  *                         Off air                bool
395  *
396  *      The decode message is sent when  a new decode is completed, in
397  *      this case the 'New' field is true. It is also used in response
398  *      to  a "Replay"  message where  each  old decode  in the  "Band
399  *      activity" window, that  has not been erased, is  sent in order
400  *      as  a one  of  these  messages with  the  'New'  field set  to
401  *      false.  See   the  "Replay"  message  below   for  details  of
402  *      usage. The off air field indicates that the decode was decoded
403  *      from a played back recording.
404  *
405  *
406  * Location       In       11
407  *                         Id (unique key)        utf8
408  *                         Location               utf8
409  *
410  *      This  message allows  the server  to set  the current  current
411  *      geographical location  of operation. The supplied  location is
412  *      not persistent but  is used as a  session lifetime replacement
413  *      loction that overrides the Maidenhead  grid locater set in the
414  *      application  settings.  The  intent  is to  allow an  external
415  *      application  to  update  the  operating  location  dynamically
416  *      during a mobile period of operation.
417  *
418  *      Currently  only Maidenhead  grid  squares  or sub-squares  are
419  *      accepted, i.e.  4- or 6-digit  locators. Other formats  may be
420  *      accepted in future.
421  *
422  *
423  * Logged ADIF    Out      12                     quint32
424  *                         Id (unique key)        utf8
425  *                         ADIF text              utf8
426  *
427  *      The  logged ADIF  message is  sent to  the server(s)  when the
428  *      WSJT-X user accepts the "Log  QSO" dialog by clicking the "OK"
429  *      button. The  "ADIF text" field  consists of a valid  ADIF file
430  *      such that  the WSJT-X  UDP header information  is encapsulated
431  *      into a valid ADIF header. E.g.:
432  *
433  *          <magic-number><schema-number><type><id><32-bit-count>  # binary encoded fields
434  *          # the remainder is the contents of the ADIF text field
435  *          <adif_ver:5>3.0.7
436  *          <programid:6>WSJT-X
437  *          <EOH>
438  *          ADIF log data fields ...<EOR>
439  *
440  *      Note that  receiving applications can treat  the whole message
441  *      as a valid ADIF file with one record without special parsing.
442  *
443  *
444  * Highlight Callsign In   13                     quint32
445  *                         Id (unique key)        utf8
446  *                         Callsign               utf8
447  *                         Background Color       QColor
448  *                         Foreground Color       QColor
449  *                         Highlight last         bool
450  *
451  *      The server  may send  this message at  any time.   The message
452  *      specifies  the background  and foreground  color that  will be
453  *      used  to  highlight  the  specified callsign  in  the  decoded
454  *      messages  printed  in the  Band  Activity  panel.  The  WSJT-X
455  *      clients maintain a list of such instructions and apply them to
456  *      all decoded  messages in the  band activity window.   To clear
457  *      and  cancel  highlighting send  an  invalid  QColor value  for
458  *      either or both  of the background and  foreground fields. When
459  *      using  this mode  the  total number  of callsign  highlighting
460  *      requests should be limited otherwise the performance of WSJT-X
461  *      decoding may be  impacted. A rough rule of thumb  might be too
462  *      limit the  number of active  highlighting requests to  no more
463  *      than 100.
464  *
465  *      The "Highlight last"  field allows the sender  to request that
466  *      all instances of  "Callsign" in the last  period only, instead
467  *      of all instances in all periods, be highlighted.
468  *
469  *
470  * SwitchConfiguration  In 14                     quint32
471  *                         Id (unique key)        utf8
472  *                         Configuration Name     utf8
473  *
474  *      The server  may send  this message at  any time.   The message
475  *      specifies the name of the  configuration to switch to. The new
476  *      configuration must exist.
477  *
478  *
479  * Configure      In       15                     quint32
480  *                         Id (unique key)        utf8
481  *                         Mode                   utf8
482  *                         Frequency Tolerance    quint32
483  *                         Submode                utf8
484  *                         Fast Mode              bool
485  *                         T/R Period             quint32
486  *                         Rx DF                  quint32
487  *                         DX Call                utf8
488  *                         DX Grid                utf8
489  *                         Generate Messages      bool
490  *
491  *      The server  may send  this message at  any time.   The message
492  *      specifies  various  configuration  options.  For  utf8  string
493  *      fields an empty value implies no change, for the quint32 Rx DF
494  *      and  Frequency  Tolerance  fields the  maximum  quint32  value
495  *      implies  no change.   Invalid or  unrecognized values  will be
496  *      silently ignored.
497  */
498 
499 #include <QDataStream>
500 
501 #include "pimpl_h.hpp"
502 
503 class QIODevice;
504 class QByteArray;
505 class QString;
506 
507 namespace NetworkMessage
508 {
509   // NEVER DELETE MESSAGE TYPES
510   enum Type
511     {
512       Heartbeat,
513       Status,
514       Decode,
515       Clear,
516       Reply,
517       QSOLogged,
518       Close,
519       Replay,
520       HaltTx,
521       FreeText,
522       WSPRDecode,
523       Location,
524       LoggedADIF,
525       HighlightCallsign,
526       SwitchConfiguration,
527       Configure,
528       maximum_message_type_     // ONLY add new message types
529                                 // immediately before here
530     };
531 
532   quint32 constexpr pulse {15}; // seconds
533 
534   //
535   // NetworkMessage::Builder - build a message containing serialized Qt types
536   //
537   class Builder
538     : public QDataStream
539   {
540   public:
541     static quint32 constexpr magic {0xadbccbda}; // never change this
542 
543     // increment this if a newer Qt schema is required and add decode
544     // logic to the Builder and Reader class implementations
545 #if QT_VERSION >= QT_VERSION_CHECK (5, 4, 0)
546     static quint32 constexpr schema_number {3};
547 #elif QT_VERSION >= QT_VERSION_CHECK (5, 2, 0)
548     static quint32 constexpr schema_number {2};
549 #else
550     // Schema 1 (Qt_5_0) is broken
551 #error "Qt version 5.2 or greater required"
552 #endif
553 
554     explicit Builder (QIODevice *, Type, QString const& id, quint32 schema);
555     explicit Builder (QByteArray *, Type, QString const& id, quint32 schema);
556     Builder (Builder const&) = delete;
557     Builder& operator = (Builder const&) = delete;
558 
559   private:
560     void common_initialization (Type type, QString const& id, quint32 schema);
561   };
562 
563   //
564   // NetworkMessage::Reader - read a message containing serialized Qt types
565   //
566   // Message  is as  per NetworkMessage::Builder  above, the  schema()
567   // member  may be  used  to  determine the  schema  of the  original
568   // message.
569   //
570   class Reader
571     : public QDataStream
572   {
573   public:
574     explicit Reader (QIODevice *);
575     explicit Reader (QByteArray const&);
576     Reader (Reader const&) = delete;
577     Reader& operator = (Reader const&) = delete;
578     ~Reader ();
579 
580     quint32 schema () const;
581     Type type () const;
582     QString id () const;
583 
584   private:
585     class impl;
586     pimpl<impl> m_;
587   };
588 }
589 
590 #endif
591