Hojo and the case of the garbled WSPR packet
Problem
After implementing my third telemetry packet, I found that data was getting garbled in my WSPR packets. Gathering some data, It appeared that the garbling was occurring as follows:
Expected Data | Received Data |
---|---|
QE6IAB |
QE6IAB (correct)
|
Q86IAB
|
Q8AIA (garbled)
|
Q26IAB |
Q2AIA (garbled)
|
Diagnostics
False start
I spent a lot of time assuming that this problem was in my data, and that somehow my unsigned integer data got converted to signed integer, and the arithmetic to convert the integers to characters was garbling the string. After a bunch of debugging, I did make one minor code change that would have dealt with that situation, but I wasn't confident I had nailed it.Conclusive data
While testing the fix above, I was confident that my code should now generate clean telemetry strings, even if I didn't exactly understand the failure scenario that caused the problem in the first place.. I had run through every scenario I could think of with both good and bad data, and the strings were being created correctly. I had moved on to other testing in preparation for flight, when I happened to notice that the data, as received by WSPR on my radio, was NOT what my program intended to send. In fact, the data in the tracker was correct, but it was incorrect when received and decoded by the radio. Ah hah!!! The problem was not in the encoding of my ASCII string. It was lower down, in the WSPR encoding routines!
I ran some diagnostics, and confirmed the problem. I generate a "tone array" based on the characters to send. Here's a sample of the tone array, as generated by my code, and what the tone array should have been, when running the "wsprcode.exe" program, shipped for Windows.
From my code:
From wsprcode.exe:Building Tone array for Q36FAA FN12 603 1 2 0 2 2 2 2 1 0 0 0 3 1 3 2 2 0 3 0 2 1 0 3 3 1 3 0 2 00 2 0 0 3 0 2 3 2 1 0 0 2 0 2 2 1 0 3 3 2 0 1 1 2 1 2 2 0 33 2 3 0 2 0 2 3 1 2 3 2 1 2 1 2 3 0 0 1 0 0 1 2 1 3 0 2 2 31 2 1 0 3 0 2 2 3 0 2 0 2 2 3 2 0 1 2 0 3 3 3 2 3 3 2 0 1 30 1 0 0 0 1 1 1 2 0 0 2 2 1 2 1 0 0 3 1 2 0 0 2 2 0 0 3 1 21 0 3 3 0 0 2 3 1 0 2 0
Channel symbols:
3 1 0 0 2 0 2 2 3 0 2 0 3 1 1 2 2 0 3 0 2 3 0 3 1 3 3 0 0 2
2 2 2 2 1 0 0 1 0 1 2 2 2 0 0 0 3 0 1 1 0 0 1 1 0 1 0 0 2 3
3 2 1 0 0 0 0 3 3 2 3 2 3 0 3 2 1 2 0 1 2 0 3 2 3 1 2 2 2 1
3 2 1 0 3 0 0 0 1 0 2 2 2 2 1 0 2 1 2 2 1 3 1 2 1 3 0 2 1 3
0 3 2 0 2 1 1 1 2 2 0 2 0 1 0 1 0 0 1 1 2 0 2 2 0 0 0 3 3 0
1 0 3 3 0 0 0 3 1 0 2 0They don't match!
I had gotten a wspr encoding subroutine from a blog post by Mark VandeWettering (K6HX). I love the code because it's really lean. There are other routines out there, but they're using malloc() and free() calls and doing all kinds of whacky stuff. Mark's routine was short, elegant, and brutally efficient.
The comments at the code made it very clear what the problem might be, once I realized it was an encoding issue:
/* Callsigns must be 2x3, 1x3, 2x1, or 1x2 for the purposes of this code */
Therein lies the rub. "2x3" means "Two characters before the digit, and three after." So, a telemetry callsign like "QE6IAB" fits that beautifully. However, a telemetry callsign like "Q86IAB" is ambiguous. I needed to read his code.
Looking at the code, he was basically right-adjusting the string into an array, forcing the digit to be in column 3 (array index 2).
The Fix
Looking at the code, he was basically right-adjusting the string into an array, forcing the digit to be in column 3 (array index 2).
if (isdigit(callsign[1])) {
/* 1x callsigns... */
for (i=0; i<strlen(callsign); i++)
call[1+i] = callsign[i] ;
} else if (isdigit(callsign[2])) {
/* 2x callsigns... */
for (i=0; i<strlen(callsign); i++)
call[i] = callsign[i] ;
} else {
return 0 ;
}
This code was misinterpreting the callsign, in the event of two consecutive digits. A quick and dirty fix was this:
if ( (isdigit(callsign[1])) && (!isdigit(callsign[2])) ) {
/* 1x callsigns... */
for (i=0; i<strlen(callsign); i++)
call[1+i] = callsign[i] ;
} else if (isdigit(callsign[2])) {
/* 2x callsigns... */
for (i=0; i<strlen(callsign); i++)
call[i] = callsign[i] ;
} else {
return 0 ;
}
Conclusion
| 2016-09-25 14:04 | KD2EAT | 14.097061 | IN29 | +33 | DC5AL-R | 20m |
| 2016-09-25 14:06 | QQ6LFT | 14.097055 | IN29 | +53 | DG7BBP | 20m |
| 2016-09-25 14:08 | Q46LAB | 14.097060 | IN29 | +60 | DC5AL-R | 20m |
No comments:
Post a Comment