POCSAG: Allow all 128 ASCII characters to be transmitted

To allow all 128 ASCII characters, a null-terminated string cannot be
used. Instead a length is used to define string length, to allow
null-character in that the message string.

The print function in frame.c is improved and used to present the
string.
This commit is contained in:
Andreas Eversberg
2024-04-21 18:49:35 +02:00
parent b16b26d326
commit f391c0d947
5 changed files with 96 additions and 61 deletions

View File

@@ -38,7 +38,7 @@
static const char numeric[16] = "0123456789RU -]["; static const char numeric[16] = "0123456789RU -][";
static const char hex[16] = "0123456789abcdef"; static const char hex[16] = "0123456789abcdef";
static const char *ctrlchar[32] = { static const char *ctrl_char[33] = {
"<NUL>", "<NUL>",
"<SOH>", "<SOH>",
"<STX>", "<STX>",
@@ -71,8 +71,37 @@ static const char *ctrlchar[32] = {
"<GS>", "<GS>",
"<RS>", "<RS>",
"<US>", "<US>",
"<DEL>",
}; };
const char *print_message(const char *message, int message_length)
{
static char message_print[1024];
const char *c;
int i, ii, clen;
/* i is input counter, ii is output counter */
for (i = 0, ii = 0; i < message_length; i++) {
if (message[i] >= 0 && message[i] <= 31)
c = ctrl_char[(int)message[i]];
else if (message[i] == 127)
c = ctrl_char[(int)message[32]];
else {
message_print[ii++] = message[i];
continue;
}
clen = strlen(c);
if (ii + clen == sizeof(message_print))
break;
memcpy(message_print + ii, c, clen);
ii += clen;
}
message_print[ii++] = '\0';
return message_print;
}
static uint32_t pocsag_crc(uint32_t word) static uint32_t pocsag_crc(uint32_t word)
{ {
uint32_t denominator = 0x76900000; uint32_t denominator = 0x76900000;
@@ -371,11 +400,8 @@ int64_t get_codeword(pocsag_t *pocsag)
/* encode address */ /* encode address */
word = encode_address(msg); word = encode_address(msg);
/* link message, if there is data to be sent */ /* link message, if there is data to be sent */
if ((msg->function == POCSAG_FUNCTION_NUMERIC || msg->function == POCSAG_FUNCTION_ALPHA) && msg->data_length) { if (msg->function == POCSAG_FUNCTION_NUMERIC || msg->function == POCSAG_FUNCTION_ALPHA) {
char text[msg->data_length + 1]; LOGP_CHAN(DPOCSAG, LOGL_INFO, " -> Message text is \"%s\".\n", print_message(msg->data, msg->data_length));
memcpy(text, msg->data, msg->data_length);
text[msg->data_length] = '\0';
LOGP_CHAN(DPOCSAG, LOGL_INFO, " -> Message text is \"%s\".\n", text);
pocsag->current_msg = msg; pocsag->current_msg = msg;
msg->data_index = 0; msg->data_index = 0;
msg->bit_index = 0; msg->bit_index = 0;
@@ -420,31 +446,18 @@ int64_t get_codeword(pocsag_t *pocsag)
static void done_rx_msg(pocsag_t *pocsag) static void done_rx_msg(pocsag_t *pocsag)
{ {
const char *text;
if (!pocsag->rx_msg_valid) if (!pocsag->rx_msg_valid)
return; return;
pocsag->rx_msg_valid = 0; pocsag->rx_msg_valid = 0;
LOGP_CHAN(DPOCSAG, LOGL_INFO, "Received message from RIC '%d' / function '%d' (%s)\n", pocsag->rx_msg_ric, pocsag->rx_msg_function, pocsag_function_name[pocsag->rx_msg_function]); LOGP_CHAN(DPOCSAG, LOGL_INFO, "Received message from RIC '%d' / function '%d' (%s)\n", pocsag->rx_msg_ric, pocsag->rx_msg_function, pocsag_function_name[pocsag->rx_msg_function]);
{ text = print_message(pocsag->rx_msg_data, pocsag->rx_msg_data_length);
char text[pocsag->rx_msg_data_length * 5 + 1]; if (pocsag->rx_msg_function == POCSAG_FUNCTION_NUMERIC || pocsag->rx_msg_function == POCSAG_FUNCTION_ALPHA)
int i, j; LOGP_CHAN(DPOCSAG, LOGL_INFO, " -> Message text is \"%s\".\n", text);
for (i = 0, j = 0; i < pocsag->rx_msg_data_length; i++) { pocsag_msg_receive(pocsag->language, pocsag->sender.kanal, pocsag->rx_msg_ric, pocsag->rx_msg_function, text);
if (pocsag->rx_msg_data[i] == 127) {
strcpy(text + j, "<DEL>");
j += strlen(text + j);
} else
if (pocsag->rx_msg_data[i] < 32) {
strcpy(text + j, ctrlchar[(int)pocsag->rx_msg_data[i]]);
j += strlen(text + j);
} else
text[j++] = pocsag->rx_msg_data[i];
}
text[j] = '\0';
if ((pocsag->rx_msg_function == POCSAG_FUNCTION_NUMERIC || pocsag->rx_msg_function == POCSAG_FUNCTION_ALPHA) && text[0])
LOGP_CHAN(DPOCSAG, LOGL_INFO, " -> Message text is \"%s\".\n", text);
pocsag_msg_receive(pocsag->language, pocsag->sender.kanal, pocsag->rx_msg_ric, pocsag->rx_msg_function, text);
}
} }
void put_codeword(pocsag_t *pocsag, uint32_t word, int8_t slot, int8_t subslot) void put_codeword(pocsag_t *pocsag, uint32_t word, int8_t slot, int8_t subslot)

View File

@@ -1,4 +1,5 @@
const char *print_message(const char *message, int message_length);
int64_t get_codeword(pocsag_t *pocsag); int64_t get_codeword(pocsag_t *pocsag);
void put_codeword(pocsag_t *pocsag, uint32_t word, int8_t slot, int8_t subslot); void put_codeword(pocsag_t *pocsag, uint32_t word, int8_t slot, int8_t subslot);

View File

@@ -224,10 +224,9 @@ static void myhandler(void)
} }
/* send msg */ /* send msg */
if (i < pos) { if (i < pos) {
buffer[i] = '\0';
pos = 0; pos = 0;
if (tx) if (tx)
pocsag_msg_send(language, buffer); pocsag_msg_send(language, buffer, i);
else else
LOGP(DPOCSAG, LOGL_ERROR, "Failed to send message, transmitter is not enabled!\n"); LOGP(DPOCSAG, LOGL_ERROR, "Failed to send message, transmitter is not enabled!\n");
} }

View File

@@ -204,7 +204,7 @@ void pocsag_new_state(pocsag_t *pocsag, enum pocsag_state new_state)
} }
/* Create msg instance */ /* Create msg instance */
static pocsag_msg_t *pocsag_msg_create(pocsag_t *pocsag, uint32_t callref, uint32_t ric, enum pocsag_function function, const char *text) static pocsag_msg_t *pocsag_msg_create(pocsag_t *pocsag, uint32_t callref, uint32_t ric, enum pocsag_function function, const char *message, size_t message_length)
{ {
pocsag_msg_t *msg, **msgp; pocsag_msg_t *msg, **msgp;
@@ -216,9 +216,9 @@ static pocsag_msg_t *pocsag_msg_create(pocsag_t *pocsag, uint32_t callref, uint3
LOGP(DPOCSAG, LOGL_ERROR, "No mem!\n"); LOGP(DPOCSAG, LOGL_ERROR, "No mem!\n");
abort(); abort();
} }
if (strlen(text) > sizeof(msg->data)) { if (message_length > sizeof(msg->data)) {
LOGP(DPOCSAG, LOGL_ERROR, "Text too long!\n"); LOGP(DPOCSAG, LOGL_ERROR, "Text too long!\n");
return NULL; message_length = sizeof(msg->data);
} }
/* init */ /* init */
@@ -226,8 +226,8 @@ static pocsag_msg_t *pocsag_msg_create(pocsag_t *pocsag, uint32_t callref, uint3
msg->ric = ric; msg->ric = ric;
msg->function = function; msg->function = function;
msg->repeat = 0; msg->repeat = 0;
strncpy(msg->data, text, sizeof(msg->data)); memcpy(msg->data, message, message_length);
msg->data_length = (strlen(text) < sizeof(msg->data)) ? strlen(text) : sizeof(msg->data); msg->data_length = message_length;
msg->padding = pocsag->padding; msg->padding = pocsag->padding;
/* link */ /* link */
@@ -285,14 +285,14 @@ static int pocsag_scan_or_loopback(pocsag_t *pocsag)
message[0] = '\0'; message[0] = '\0';
} }
LOGP_CHAN(DPOCSAG, LOGL_NOTICE, "Transmitting %s message '%s' with RIC '%d'.\n", pocsag_function_name[pocsag->default_function], message, pocsag->scan_from); LOGP_CHAN(DPOCSAG, LOGL_NOTICE, "Transmitting %s message '%s' with RIC '%d'.\n", pocsag_function_name[pocsag->default_function], message, pocsag->scan_from);
pocsag_msg_create(pocsag, 0, pocsag->scan_from, pocsag->default_function, message); pocsag_msg_create(pocsag, 0, pocsag->scan_from, pocsag->default_function, message, strlen(message));
pocsag->scan_from++; pocsag->scan_from++;
return 1; return 1;
} }
if (pocsag->sender.loopback) { if (pocsag->sender.loopback) {
LOGP(DPOCSAG, LOGL_INFO, "Sending message for loopback test.\n"); LOGP(DPOCSAG, LOGL_INFO, "Sending message for loopback test.\n");
pocsag_msg_create(pocsag, 0, 1234567, POCSAG_FUNCTION_NUMERIC, "1234"); pocsag_msg_create(pocsag, 0, 1234567, POCSAG_FUNCTION_NUMERIC, "1234", 4);
return 1; return 1;
} }
@@ -406,25 +406,46 @@ void pocsag_destroy(sender_t *sender)
} }
/* application sends us a message, we need to deliver */ /* application sends us a message, we need to deliver */
void pocsag_msg_send(enum pocsag_language language, const char *text) void pocsag_msg_send(enum pocsag_language language, const char *text, size_t text_length)
{ {
char buffer[strlen(text) + 1], *p = buffer, *ric_string, *function_string, *message; char ric_string[text_length + 1];
char function_string[text_length + 1];
char message[text_length];
uint32_t ric; uint32_t ric;
uint8_t function; uint8_t function;
pocsag_t *pocsag; pocsag_t *pocsag;
int i, j, k; int message_length = 0;
int i, ii, j, k;
int rc; int rc;
strcpy(buffer, text); for (i = 0; text_length; i++) {
ric_string = strsep(&p, ","); if (*text == ',')
function_string = strsep(&p, ","); break;
message = p; ric_string[i] = *text++;
text_length--;
if (!ric_string || !function_string) { }
ric_string[i] = '\0';
if (!text_length) {
inval: inval:
LOGP(DNMT, LOGL_NOTICE, "Given message MUST be in the following format: RIC,function[,<message with comma and spaces>] (function must be A = 0 = numeric, B = 1 or C = 2 = beep, D = 3 = alphanumeric)\n"); LOGP(DNMT, LOGL_NOTICE, "Given message MUST be in the following format: RIC,function[,<message with comma and spaces>] (function must be A = 0 = numeric, B = 1 or C = 2 = beep, D = 3 = alphanumeric)\n");
return; return;
} }
text++;
text_length--;
for (i = 0; text_length; i++) {
if (*text == ',')
break;
function_string[i] = *text++;
text_length--;
}
function_string[i] = '\0';
if (text_length) {
text++;
text_length--;
memcpy(message, text, text_length);
message_length = text_length;
}
ric = atoi(ric_string); ric = atoi(ric_string);
if (ric > 2097151) { if (ric > 2097151) {
LOGP(DNMT, LOGL_NOTICE, "Illegal RIC %d. Maximum allowed RIC is (2^21)-1. (2097151)\n", ric); LOGP(DNMT, LOGL_NOTICE, "Illegal RIC %d. Maximum allowed RIC is (2^21)-1. (2097151)\n", ric);
@@ -443,42 +464,43 @@ inval:
} }
function = rc; function = rc;
if (message && (function == 1 || function == 2)) { if (message_length && (function == 1 || function == 2)) {
LOGP(DNMT, LOGL_NOTICE, "Message text is not allowed with function %d.\n", function); LOGP(DNMT, LOGL_NOTICE, "Message text is not allowed with function %d.\n", function);
goto inval; goto inval;
} }
if (message && language != LANGUAGE_DEFAULT) { if (message_length && language != LANGUAGE_DEFAULT) {
i = 0; i = 0;
p = message; /* input counter is ii, output counter is i */
while (*p) { for (ii = 0; ii < message_length; i++) {
/* encode special chracter */ /* encode special chracter */
for (j = 0; pocsag_lang[j][0]; j++) { for (j = 0; pocsag_lang[j][0]; j++) {
for (k = 0; pocsag_lang[j][k + 1]; k++) { for (k = 0; pocsag_lang[j][k + 1]; k++) {
/* implies that (p[k] == '\0') causes to break */ /* break if input buffer ends */
if (p[k] != pocsag_lang[j][k + 1]) if (ii + k == message_length)
break;
/* break if string does not match */
if (message[ii + k] != pocsag_lang[j][k + 1])
break; break;
} }
/* break, if k-loop was completed */
if (!pocsag_lang[j][k + 1]) if (!pocsag_lang[j][k + 1])
break; break;
} }
/* if character matches */ /* if character matches (k-loop was completed, j-loop not) */
if (pocsag_lang[j][0]) { if (pocsag_lang[j][0]) {
message[i++] = pocsag_lang[j][0]; message[i] = pocsag_lang[j][0];
p += k; ii += k;
} else } else
message[i++] = *p++; message[i] = message[ii++];
} }
message[i] = '\0'; message_length = i;
} }
if (!message) LOGP(DNMT, LOGL_INFO, "Message for ID '%d/%d' with text '%s'\n", ric, function, print_message(message, message_length));
message="";
LOGP(DNMT, LOGL_INFO, "Message for ID '%d/%d' with text '%s'\n", ric, function, message);
pocsag = (pocsag_t *) sender_head; pocsag = (pocsag_t *) sender_head;
pocsag_msg_create(pocsag, 0, ric, function, message); pocsag_msg_create(pocsag, 0, ric, function, message, message_length);
} }
void call_down_clock(void) void call_down_clock(void)
@@ -535,7 +557,7 @@ int call_down_setup(int callref, const char *caller_id, enum number_type __attri
message = pocsag->default_message; message = pocsag->default_message;
/* create call process to page station */ /* create call process to page station */
msg = pocsag_msg_create(pocsag, callref, ric, function, message); msg = pocsag_msg_create(pocsag, callref, ric, function, message, strlen(message));
if (!msg) if (!msg)
return -CAUSE_INVALNUMBER; return -CAUSE_INVALNUMBER;
return -CAUSE_NORMAL; return -CAUSE_NORMAL;

View File

@@ -102,7 +102,7 @@ void pocsag_new_state(pocsag_t *pocsag, enum pocsag_state new_state);
void pocsag_msg_receive(enum pocsag_language language, const char *channel, uint32_t ric, enum pocsag_function function, const char *message); void pocsag_msg_receive(enum pocsag_language language, const char *channel, uint32_t ric, enum pocsag_function function, const char *message);
int pocsag_create(const char *kanal, double frequency, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int tx, int rx, enum pocsag_language language, int baudrate, double deviation, double polarity, enum pocsag_function function, const char *message, char padding, uint32_t scan_from, uint32_t scan_to, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback); int pocsag_create(const char *kanal, double frequency, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, int tx, int rx, enum pocsag_language language, int baudrate, double deviation, double polarity, enum pocsag_function function, const char *message, char padding, uint32_t scan_from, uint32_t scan_to, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback);
void pocsag_destroy(sender_t *sender); void pocsag_destroy(sender_t *sender);
void pocsag_msg_send(enum pocsag_language language, const char *text); void pocsag_msg_send(enum pocsag_language language, const char *text, size_t text_length);
void pocsag_msg_destroy(pocsag_msg_t *msg); void pocsag_msg_destroy(pocsag_msg_t *msg);
void pocsag_get_id(pocsag_t *euro, char *id); void pocsag_get_id(pocsag_t *euro, char *id);
void pocsag_receive_id(pocsag_t *euro, char *id); void pocsag_receive_id(pocsag_t *euro, char *id);