Saturday, February 4, 2012

WSPR Encoder for Propeller Beacon Update

Well, after a bit of hair tearing, I have managed to get my WSPR encoder running on the propeller platform.  I am doing some cleanup of the code and will post it as soon as I have completed the changes.  I implemented it as a separate object, so to use it you would do something like this:

   BYTE sym[162]

   WSPR : "ko7mWSPREncode"

This declares a byte array to hold the encoded WSPR symbol set and includes the WSPR encoder in your code.  You would then call this WSPR object to encode your call, locator and power setting and provide the address of the sym BYTE array so it can fill it up with your message.  Typically this would be done in your initialization code.

WSPR.encodeWSPR(string("KO7M  "), string("CN87"), 27, @sym)

Then in you would in your main loop send each symbol returned.

PUB Main | iSym
    repeat iSym from 0 to 161
    Sync := nextSync
    repeat while SecondCnt // Sync

Pretty simple and it works quite well.  I have a couple of caveats that are important in the current implementation.

  1. Only standard WSPR messages are supported currently.  No six digit locators or calls with prefixes or suffixes such as KO7M/5 or JA2/KO7M.  I have more work to do to support these special message formats.
  2. Call signs must be exactly 6 characters and the third character must be a numeric.  This is according to Joe Taylor's specifications.  The point of this is that my routine does not do any error checking to be sure you passed in the call sign with the numeric aligned in the third character and that it is padded with spaces to make it exactly 6 characters.  You will need to attend to this in the parameter you pass to encodeWSPR or the results will not be predictable.  For example, my call is passed as KO7M<space><space>.  If you had a call like one of the special even calls of "K7S", it would need to be passed in as <space>K7S<space><space>.  I may attend to this in future versions if I get inspired to do the work.
I also ran into a caveat that I cannot yet explain.  I am looking for insights into why this is happening.

If I pass the parameters like so:

  mycall BYTE "KO7M  ", 0
  myloc  BYTE "CN87", 0
  mypwr  BYTE 27

WSPR.encodeWSPR(@mycall, @myloc, @mypwr, @sym)

The results are not encoded correctly.  Changing to use the "string("...") format rather than BYTE data block constants with exactly the same data shown above works correctly.  So, you will have to stick to this format until I figure out why there is any difference.  Any thoughts on this from any of you propeller hackers out there appreciated.


  1. Shouldn't that be BYTE "27" with quotes round it like the others?

    1. Nope, I don't believe so. The quotes following a BYTE indicates that each character of the quoted string is stored as a subsequent character in the list of bytes. The 27 is an integer value stored in a byte, sort of "byte-sized" data, eh? :) This will be something I check out because if on the receiving end it is getting a word sized or long sized bit of data, that can certainly change things. The dBm values are 0-60 decimal I believe in WSPR, so a byte should be sufficient. But, there is some "magic" compared to C in argument passing that I am still figuring out. Thanks for the tip though, I will investigate the argument passing details.

      What is the difference between these?

      dBm1 BYTE 27
      BYTE dBm2

      dBm2 = 27

      What is the difference between these?


      I believe in the first case I get a pointer to a byte and in the other, I get a byte value. Do you concur? The problem is that I have no way to specify what I expect to receive in the definition of the foo procedure. This leads my befuddled mind to conclude the data is somewhat non-deterministic.

      I suppose they could always pass a long size bit of data either with a pointer to the data or the data itself, but it is unclear to me.

      Or, I may just have a hole in my understanding of how this spin language works (most likely).