1199ab85e9
Co-authored-by: Codex <codex@openai.com> Signed-off-by: Stanislaw Grams <stanislawgrams@gmail.com>
287 lines
10 KiB
C
287 lines
10 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
#include <stdbool.h>
|
|
|
|
#include "ft8/text.h"
|
|
#include "ft8/encode.h"
|
|
#include "ft8/constants.h"
|
|
|
|
#include "fft/kiss_fftr.h"
|
|
#include "common/common.h"
|
|
#include "ft8/message.h"
|
|
|
|
#define LOG_LEVEL LOG_INFO
|
|
#include "ft8/debug.h"
|
|
|
|
// void convert_8bit_to_6bit(uint8_t* dst, const uint8_t* src, int nBits)
|
|
// {
|
|
// // Zero-fill the destination array as we will only be setting bits later
|
|
// for (int j = 0; j < (nBits + 5) / 6; ++j)
|
|
// {
|
|
// dst[j] = 0;
|
|
// }
|
|
|
|
// // Set the relevant bits
|
|
// uint8_t mask_src = (1 << 7);
|
|
// uint8_t mask_dst = (1 << 5);
|
|
// for (int i = 0, j = 0; nBits > 0; --nBits)
|
|
// {
|
|
// if (src[i] & mask_src)
|
|
// {
|
|
// dst[j] |= mask_dst;
|
|
// }
|
|
// mask_src >>= 1;
|
|
// if (mask_src == 0)
|
|
// {
|
|
// mask_src = (1 << 7);
|
|
// ++i;
|
|
// }
|
|
// mask_dst >>= 1;
|
|
// if (mask_dst == 0)
|
|
// {
|
|
// mask_dst = (1 << 5);
|
|
// ++j;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
/*
|
|
bool test1() {
|
|
//const char *msg = "CQ DL7ACA JO40"; // 62, 32, 32, 49, 37, 27, 59, 2, 30, 19, 49, 16
|
|
const char *msg = "VA3UG F1HMR 73"; // 52, 54, 60, 12, 55, 54, 7, 19, 2, 23, 59, 16
|
|
//const char *msg = "RA3Y VE3NLS 73"; // 46, 6, 32, 22, 55, 20, 11, 32, 53, 23, 59, 16
|
|
uint8_t a72[9];
|
|
|
|
int rc = packmsg(msg, a72);
|
|
if (rc < 0) return false;
|
|
|
|
LOG(LOG_INFO, "8-bit packed: ");
|
|
for (int i = 0; i < 9; ++i) {
|
|
LOG(LOG_INFO, "%02x ", a72[i]);
|
|
}
|
|
LOG(LOG_INFO, "\n");
|
|
|
|
uint8_t a72_6bit[12];
|
|
convert_8bit_to_6bit(a72_6bit, a72, 72);
|
|
LOG(LOG_INFO, "6-bit packed: ");
|
|
for (int i = 0; i < 12; ++i) {
|
|
LOG(LOG_INFO, "%d ", a72_6bit[i]);
|
|
}
|
|
LOG(LOG_INFO, "\n");
|
|
|
|
char msg_out_raw[14];
|
|
unpack(a72, msg_out_raw);
|
|
|
|
char msg_out[14];
|
|
fmtmsg(msg_out, msg_out_raw);
|
|
LOG(LOG_INFO, "msg_out = [%s]\n", msg_out);
|
|
return true;
|
|
}
|
|
|
|
|
|
void test2() {
|
|
uint8_t test_in[11] = { 0xF1, 0x02, 0x03, 0x04, 0x05, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xFF };
|
|
uint8_t test_out[22];
|
|
|
|
encode174(test_in, test_out);
|
|
|
|
for (int j = 0; j < 22; ++j) {
|
|
LOG(LOG_INFO, "%02x ", test_out[j]);
|
|
}
|
|
LOG(LOG_INFO, "\n");
|
|
}
|
|
|
|
|
|
void test3() {
|
|
uint8_t test_in2[10] = { 0x11, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x10, 0x04, 0x01, 0x00 };
|
|
uint16_t crc1 = ftx_compute_crc(test_in2, 76); // Calculate CRC of 76 bits only
|
|
LOG(LOG_INFO, "CRC: %04x\n", crc1); // should be 0x0708
|
|
}
|
|
*/
|
|
|
|
#define CHECK(condition) \
|
|
if (!(condition)) \
|
|
{ \
|
|
printf("FAIL! Condition \'" #condition "' failed\n\n"); \
|
|
return; \
|
|
}
|
|
|
|
#define CHECK_EQ_VAL(this, that) \
|
|
if ((this) != (that)) \
|
|
{ \
|
|
printf("FAIL! Expected " #this " (%d) == " #that " (%d)\n\n", \
|
|
(this), (that)); \
|
|
return; \
|
|
}
|
|
|
|
#define TEST_END printf("Test OK\n\n")
|
|
|
|
#define CALLSIGN_HASHTABLE_SIZE 256
|
|
|
|
struct
|
|
{
|
|
char callsign[12];
|
|
uint32_t hash;
|
|
} callsign_hashtable[CALLSIGN_HASHTABLE_SIZE];
|
|
|
|
void hashtable_init(void)
|
|
{
|
|
// for (int idx = 0; idx < CALLSIGN_HASHTABLE_SIZE; ++idx)
|
|
// {
|
|
// callsign_hashtable[idx]->callsign[0] = '\0';
|
|
// }
|
|
memset(callsign_hashtable, 0, sizeof(callsign_hashtable));
|
|
}
|
|
|
|
void hashtable_add(const char* callsign, uint32_t hash)
|
|
{
|
|
int idx_hash = (hash * 23) % CALLSIGN_HASHTABLE_SIZE;
|
|
while (callsign_hashtable[idx_hash].callsign[0] != '\0')
|
|
{
|
|
if ((callsign_hashtable[idx_hash].hash == hash) && (0 == strcmp(callsign_hashtable[idx_hash].callsign, callsign)))
|
|
{
|
|
LOG(LOG_DEBUG, "Found a duplicate [%s]\n", callsign);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LOG(LOG_DEBUG, "Hash table clash!\n");
|
|
// Move on to check the next entry in hash table
|
|
idx_hash = (idx_hash + 1) % CALLSIGN_HASHTABLE_SIZE;
|
|
}
|
|
}
|
|
strncpy(callsign_hashtable[idx_hash].callsign, callsign, 11);
|
|
callsign_hashtable[idx_hash].callsign[11] = '\0';
|
|
callsign_hashtable[idx_hash].hash = hash;
|
|
}
|
|
|
|
bool hashtable_lookup(ftx_callsign_hash_type_t hash_type, uint32_t hash, char* callsign)
|
|
{
|
|
uint32_t hash_mask = (hash_type == FTX_CALLSIGN_HASH_10_BITS) ? 0x3FFu : (hash_type == FTX_CALLSIGN_HASH_12_BITS ? 0xFFFu : 0x3FFFFFu);
|
|
int idx_hash = (hash * 23) % CALLSIGN_HASHTABLE_SIZE;
|
|
while (callsign_hashtable[idx_hash].callsign[0] != '\0')
|
|
{
|
|
if ((callsign_hashtable[idx_hash].hash & hash_mask) == hash)
|
|
{
|
|
strcpy(callsign, callsign_hashtable[idx_hash].callsign);
|
|
return true;
|
|
}
|
|
// Move on to check the next entry in hash table
|
|
idx_hash = (idx_hash + 1) % CALLSIGN_HASHTABLE_SIZE;
|
|
}
|
|
callsign[0] = '\0';
|
|
return false;
|
|
}
|
|
|
|
ftx_callsign_hash_interface_t hash_if = {
|
|
.lookup_hash = hashtable_lookup,
|
|
.save_hash = hashtable_add
|
|
};
|
|
|
|
void test_std_msg(const char* call_to_tx, ftx_field_t to_field, const char* call_de_tx, ftx_field_t de_field, const char* extra_tx, ftx_field_t extra_field)
|
|
{
|
|
ftx_message_t msg;
|
|
ftx_message_init(&msg);
|
|
|
|
ftx_message_rc_t rc_encode = ftx_message_encode_std(&msg, &hash_if, call_to_tx, call_de_tx, extra_tx);
|
|
printf("Encoded [%s] [%s] [%s]\n", call_to_tx, call_de_tx, extra_tx);
|
|
CHECK_EQ_VAL(rc_encode, FTX_MESSAGE_RC_OK);
|
|
|
|
char call_to_arr[14];
|
|
char call_de_arr[14];
|
|
char extra[14];
|
|
char *call_to = call_to_arr;
|
|
char *call_de = call_de_arr;
|
|
ftx_field_t types[FTX_MAX_MESSAGE_FIELDS];
|
|
ftx_message_rc_t rc_decode = ftx_message_decode_std(&msg, &hash_if, call_to, call_de, extra, types);
|
|
CHECK_EQ_VAL(rc_decode, FTX_MESSAGE_RC_OK);
|
|
printf("Decoded [%s] [%s] [%s]\n", call_to, call_de, extra);
|
|
call_to = trim_brackets(call_to);
|
|
call_de = trim_brackets(call_de);
|
|
CHECK_EQ_VAL(0, strcmp(call_to, call_to_tx));
|
|
CHECK_EQ_VAL(0, strcmp(call_de, call_de_tx));
|
|
CHECK_EQ_VAL(0, strcmp(extra, extra_tx));
|
|
CHECK_EQ_VAL(to_field, types[0]);
|
|
CHECK_EQ_VAL(de_field, types[1]);
|
|
CHECK_EQ_VAL(extra_field, types[2]);
|
|
TEST_END;
|
|
}
|
|
|
|
void test_msg(const char* message_text, ftx_message_type_t expected_type, const char* expected, ftx_callsign_hash_interface_t* hash_if)
|
|
{
|
|
printf("Testing [%s]\n", message_text);
|
|
|
|
ftx_message_t msg;
|
|
ftx_message_init(&msg);
|
|
|
|
ftx_message_rc_t rc_encode = ftx_message_encode(&msg, hash_if, message_text);
|
|
CHECK_EQ_VAL(rc_encode, FTX_MESSAGE_RC_OK);
|
|
CHECK_EQ_VAL(expected_type, ftx_message_get_type(&msg));
|
|
|
|
char message_decoded[12 + 12 + 20];
|
|
ftx_message_offsets_t offsets;
|
|
ftx_message_rc_t rc_decode = ftx_message_decode(&msg, hash_if, message_decoded, &offsets);
|
|
CHECK_EQ_VAL(rc_decode, FTX_MESSAGE_RC_OK);
|
|
printf("Decoded [%s]; offsets %d:%d %d:%d %d:%d\n", message_decoded,
|
|
offsets.offsets[0], offsets.types[0], offsets.offsets[1], offsets.types[1], offsets.offsets[2], offsets.types[2]);
|
|
CHECK_EQ_VAL(0, strcmp(expected, message_decoded));
|
|
// TODO check offsets
|
|
TEST_END;
|
|
}
|
|
|
|
#define SIZEOF_ARRAY(x) (sizeof(x) / sizeof((x)[0]))
|
|
|
|
int main()
|
|
{
|
|
// test1();
|
|
// test4();
|
|
const char* callsigns[] = { "YL3JG", "W1A", "W1A/R", "W5AB", "W8ABC", "DE6ABC", "DE6ABC/R", "DE7AB", "DE9A", "3DA0X", "3DA0XYZ", "3DA0XYZ/R", "3XZ0AB", "3XZ0A", "CQ1CQ" };
|
|
const char* tokens[] = { "CQ", "QRZ", "CQ 123", "CQ 000", "CQ POTA", "CQ SA", "CQ O", "CQ ASD" };
|
|
const ftx_field_t token_types[] = { FTX_FIELD_TOKEN, FTX_FIELD_TOKEN, FTX_FIELD_TOKEN_WITH_ARG, FTX_FIELD_TOKEN_WITH_ARG, FTX_FIELD_TOKEN_WITH_ARG, FTX_FIELD_TOKEN_WITH_ARG, FTX_FIELD_TOKEN_WITH_ARG, FTX_FIELD_TOKEN_WITH_ARG };
|
|
const char* grids[] = { "KO26", "RR99", "AA00", "RR09", "AA01", "RRR", "RR73", "73", "R+10", "R+05", "R-12", "R-02", "+10", "+05", "-02", "-02", "" };
|
|
const ftx_field_t grid_types[] = { FTX_FIELD_GRID, FTX_FIELD_GRID, FTX_FIELD_GRID, FTX_FIELD_GRID, FTX_FIELD_GRID, FTX_FIELD_TOKEN, FTX_FIELD_TOKEN, FTX_FIELD_TOKEN, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_RST, FTX_FIELD_NONE };
|
|
|
|
for (int idx_grid = 0; idx_grid < SIZEOF_ARRAY(grids); ++idx_grid)
|
|
{
|
|
for (int idx_callsign = 0; idx_callsign < SIZEOF_ARRAY(callsigns); ++idx_callsign)
|
|
{
|
|
for (int idx_callsign2 = 0; idx_callsign2 < SIZEOF_ARRAY(callsigns); ++idx_callsign2)
|
|
{
|
|
test_std_msg(callsigns[idx_callsign], FTX_FIELD_CALL, callsigns[idx_callsign2], FTX_FIELD_CALL, grids[idx_grid], grid_types[idx_grid]);
|
|
}
|
|
}
|
|
for (int idx_token = 0; idx_token < SIZEOF_ARRAY(tokens); ++idx_token)
|
|
{
|
|
for (int idx_callsign2 = 0; idx_callsign2 < SIZEOF_ARRAY(callsigns); ++idx_callsign2)
|
|
{
|
|
test_std_msg(tokens[idx_token], token_types[idx_token], callsigns[idx_callsign2], FTX_FIELD_CALL, grids[idx_grid], grid_types[idx_grid]);
|
|
}
|
|
}
|
|
}
|
|
test_msg("CQ K7IHZ DM43", FTX_MESSAGE_TYPE_STANDARD,
|
|
"CQ K7IHZ DM43", &hash_if);
|
|
test_msg("CQ EA8/G5LSI", FTX_MESSAGE_TYPE_NONSTD_CALL,
|
|
"CQ EA8/G5LSI", &hash_if);
|
|
test_msg("EA8/G5LSI R2RFE RR73", FTX_MESSAGE_TYPE_STANDARD,
|
|
"<EA8/G5LSI> R2RFE RR73", &hash_if);
|
|
test_msg("R2RFE/P EA8/G5LSI R+12", FTX_MESSAGE_TYPE_STANDARD,
|
|
"R2RFE/P <EA8/G5LSI> R+12", &hash_if);
|
|
test_msg("TNX BOB 73 GL", FTX_MESSAGE_TYPE_FREE_TEXT,
|
|
"TNX BOB 73 GL", &hash_if); // message with 4 tokens must be free text
|
|
test_msg("TNX BOB 73", FTX_MESSAGE_TYPE_STANDARD,
|
|
"<TNX> <BOB> 73", &hash_if); // can't distinguish special callsigns from other tokens
|
|
test_msg("CQ YL/LB2JK KO16sw", FTX_MESSAGE_TYPE_NONSTD_CALL,
|
|
"CQ YL/LB2JK", &hash_if); // grid not allowed with nonstandard call
|
|
test_msg("CQ POTA YL/LB2JK KO16sw", FTX_MESSAGE_TYPE_NONSTD_CALL,
|
|
"CQ YL/LB2JK", &hash_if); // CQ modifier not allowed with nonstandard call
|
|
test_msg("CQ JA LB2JK JO59", FTX_MESSAGE_TYPE_STANDARD,
|
|
"CQ JA LB2JK JO59", &hash_if);
|
|
test_msg("CQ 123 LB2JK JO59", FTX_MESSAGE_TYPE_STANDARD,
|
|
"CQ 123 LB2JK JO59", &hash_if);
|
|
|
|
return 0;
|
|
}
|