Golay: Add voice message support
A voice message can be sent with a wave file. Pagers that support voice messages will listen to the wave file on the radio channel. Use the following command to send a voice message: $ echo "1709829,v,<wave file>" > /tmp/golay_msg_send
This commit is contained in:
@@ -25,12 +25,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include "../libsample/sample.h"
|
#include "../libsample/sample.h"
|
||||||
#include "../libdebug/debug.h"
|
#include "../libdebug/debug.h"
|
||||||
#include "golay.h"
|
#include "golay.h"
|
||||||
#include "dsp.h"
|
#include "dsp.h"
|
||||||
|
|
||||||
#define MAX_DISPLAY 1.4 /* something above speech level, no emphasis */
|
#define MAX_DISPLAY 1.4 /* something above speech level, no emphasis */
|
||||||
|
#define VOICE_BANDWIDTH 3000 /* just guessing */
|
||||||
|
|
||||||
static void dsp_init_ramp(gsc_t *gsc)
|
static void dsp_init_ramp(gsc_t *gsc)
|
||||||
{
|
{
|
||||||
@@ -172,12 +174,63 @@ void sender_receive(sender_t __attribute__((unused)) *sender, sample_t __attribu
|
|||||||
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
|
void sender_send(sender_t *sender, sample_t *samples, uint8_t *power, int length)
|
||||||
{
|
{
|
||||||
gsc_t *gsc = (gsc_t *) sender;
|
gsc_t *gsc = (gsc_t *) sender;
|
||||||
|
int rc;
|
||||||
|
|
||||||
again:
|
again:
|
||||||
/* get word */
|
/* play 2 seconds of pause */
|
||||||
|
if (gsc->wait_2_sec) {
|
||||||
|
int tosend = MIN(length, gsc->wait_2_sec);
|
||||||
|
memset(power, 1, tosend);
|
||||||
|
memset(samples, 0, sizeof(samples) * tosend);
|
||||||
|
power += tosend;
|
||||||
|
samples += tosend;
|
||||||
|
gsc->wait_2_sec -= tosend;
|
||||||
|
if (gsc->wait_2_sec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* play wave file, if open */
|
||||||
|
if (gsc->wave_tx_play.left) {
|
||||||
|
int wave_num, s;
|
||||||
|
wave_num = samplerate_upsample_input_num(&gsc->wave_tx_upsample, length);
|
||||||
|
sample_t buffer[wave_num * 2], *wave_samples[2] = { buffer, buffer + wave_num };
|
||||||
|
wave_read(&gsc->wave_tx_play, wave_samples, wave_num);
|
||||||
|
if (gsc->wave_tx_channels == 2) {
|
||||||
|
for (s = 0; s < wave_num; s++) {
|
||||||
|
wave_samples[0][s] += wave_samples[1][s];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
samplerate_upsample(&gsc->wave_tx_upsample, wave_samples[0], wave_num, samples, length);
|
||||||
|
if (!gsc->wave_tx_play.left) {
|
||||||
|
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Voice message sent.\n");
|
||||||
|
wave_destroy_playback(&gsc->wave_tx_play);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get FSK bits or start playing wave file */
|
||||||
if (!gsc->fsk_tx_buffer_length) {
|
if (!gsc->fsk_tx_buffer_length) {
|
||||||
int8_t bit = get_bit(gsc);
|
int8_t bit = get_bit(gsc);
|
||||||
|
|
||||||
|
/* bit == 2 means voice transmission. */
|
||||||
|
if (bit == 2) {
|
||||||
|
if (gsc->wave_tx_filename[0]) {
|
||||||
|
gsc->wave_tx_samplerate = gsc->wave_tx_channels = 0;
|
||||||
|
rc = wave_create_playback(&gsc->wave_tx_play, gsc->wave_tx_filename, &gsc->wave_tx_samplerate, &gsc->wave_tx_channels, gsc->fsk_deviation);
|
||||||
|
if (rc < 0) {
|
||||||
|
gsc->wave_tx_play.left = 0;
|
||||||
|
PDEBUG_CHAN(DDSP, DEBUG_ERROR, "Failed to open wave file '%s' for voice message.\n", gsc->wave_tx_filename);
|
||||||
|
} else {
|
||||||
|
PDEBUG_CHAN(DDSP, DEBUG_INFO, "Sending wave file '%s' for voice message after 2 seconds.\n", gsc->wave_tx_filename);
|
||||||
|
init_samplerate(&gsc->wave_tx_upsample, gsc->wave_tx_samplerate, gsc->sender.samplerate, VOICE_BANDWIDTH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gsc->wait_2_sec = gsc->sender.samplerate * 2.0;
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
/* no message, power is off */
|
/* no message, power is off */
|
||||||
if (bit < 0) {
|
if (bit < 0) {
|
||||||
memset(samples, 0, sizeof(samples) * length);
|
memset(samples, 0, sizeof(samples) * length);
|
||||||
@@ -206,4 +259,3 @@ again:
|
|||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -32,6 +32,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include "../libsample/sample.h"
|
#include "../libsample/sample.h"
|
||||||
#include "../libdebug/debug.h"
|
#include "../libdebug/debug.h"
|
||||||
#include "../libmobile/call.h"
|
#include "../libmobile/call.h"
|
||||||
@@ -98,18 +99,10 @@ void golay_destroy(sender_t *sender)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Create message and add to queue */
|
/* Create message and add to queue */
|
||||||
static gsc_msg_t *golay_msg_create(gsc_t *gsc, const char *address, const char *text, int force_type)
|
static gsc_msg_t *golay_msg_create(gsc_t *gsc, const char *address, const char *text, enum gsc_msg_type type)
|
||||||
{
|
{
|
||||||
gsc_msg_t *msg, **msgp;
|
gsc_msg_t *msg, **msgp;
|
||||||
|
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Creating msg instance to page address '%s'.\n", address);
|
|
||||||
|
|
||||||
/* create */
|
|
||||||
msg = calloc(1, sizeof(*msg));
|
|
||||||
if (!msg) {
|
|
||||||
PDEBUG(DGOLAY, DEBUG_ERROR, "No mem!\n");
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
if (strlen(address) != sizeof(msg->address) - 1) {
|
if (strlen(address) != sizeof(msg->address) - 1) {
|
||||||
PDEBUG(DGOLAY, DEBUG_NOTICE, "Address has incorrect length, cannot page!\n");
|
PDEBUG(DGOLAY, DEBUG_NOTICE, "Address has incorrect length, cannot page!\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -119,10 +112,39 @@ static gsc_msg_t *golay_msg_create(gsc_t *gsc, const char *address, const char *
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get type from last digit, if automatic type is given */
|
||||||
|
if (type == TYPE_AUTO) {
|
||||||
|
switch (address[6]) {
|
||||||
|
case '1': type = TYPE_VOICE; break;
|
||||||
|
case '2': type = TYPE_VOICE; break;
|
||||||
|
case '3': type = TYPE_VOICE; break;
|
||||||
|
case '4': type = TYPE_VOICE; break;
|
||||||
|
case '5': type = TYPE_ALPHA; break;
|
||||||
|
case '6': type = TYPE_ALPHA; break;
|
||||||
|
case '7': type = TYPE_ALPHA; break;
|
||||||
|
case '8': type = TYPE_ALPHA; break;
|
||||||
|
case '9': type = TYPE_TONE; break;
|
||||||
|
case '0': type = TYPE_TONE; break;
|
||||||
|
default:
|
||||||
|
PDEBUG(DGOLAY, DEBUG_NOTICE, "Illegal function suffix '%c' in last address digit.\n", address[6]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
PDEBUG(DGOLAY, DEBUG_INFO, "Overriding message type as defined by sender.\n");
|
||||||
|
|
||||||
|
PDEBUG(DGOLAY, DEBUG_INFO, "Creating msg instance to page address '%s'.\n", address);
|
||||||
|
|
||||||
|
/* create */
|
||||||
|
msg = calloc(1, sizeof(*msg));
|
||||||
|
if (!msg) {
|
||||||
|
PDEBUG(DGOLAY, DEBUG_ERROR, "No mem!\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
/* init */
|
/* init */
|
||||||
strcpy(msg->address, address);
|
memcpy(msg->address, address, MIN(sizeof(msg->address) - 1, strlen(address) + 1));
|
||||||
msg->force_type = force_type;
|
msg->type = type;
|
||||||
strcpy(msg->data, text);
|
memcpy(msg->data, text, MIN(sizeof(msg->data) - 1, strlen(text) + 1));
|
||||||
|
|
||||||
/* link */
|
/* link */
|
||||||
msgp = &gsc->msg_list;
|
msgp = &gsc->msg_list;
|
||||||
@@ -240,6 +262,7 @@ static const uint16_t preamble_values[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const uint32_t start_code = 713;
|
static const uint32_t start_code = 713;
|
||||||
|
static const uint32_t activation_code = 2563;
|
||||||
|
|
||||||
/* Rep. 900-2 Table VI */
|
/* Rep. 900-2 Table VI */
|
||||||
static const uint16_t word1s[50] = {
|
static const uint16_t word1s[50] = {
|
||||||
@@ -455,6 +478,7 @@ static inline void queue_reset(gsc_t *gsc)
|
|||||||
{
|
{
|
||||||
gsc->bit_index = 0;
|
gsc->bit_index = 0;
|
||||||
gsc->bit_num = 0;
|
gsc->bit_num = 0;
|
||||||
|
gsc->bit_ac = 0;
|
||||||
gsc->bit_overflow = 0;
|
gsc->bit_overflow = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -489,9 +513,8 @@ static inline void queue_comma(gsc_t *gsc, int bits, uint8_t polarity)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int queue_batch(gsc_t *gsc, const char *address, int force_type, const char *message)
|
static int queue_batch(gsc_t *gsc, const char *address, enum gsc_msg_type type, const char *message)
|
||||||
{
|
{
|
||||||
int type;
|
|
||||||
int preamble;
|
int preamble;
|
||||||
uint16_t word1, word2;
|
uint16_t word1, word2;
|
||||||
uint8_t function;
|
uint8_t function;
|
||||||
@@ -514,33 +537,34 @@ static int queue_batch(gsc_t *gsc, const char *address, int force_type, const ch
|
|||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* calculate function */
|
/* get function from last digit */
|
||||||
switch (address[6]) {
|
switch (address[6]) {
|
||||||
case '1': type = TYPE_VOICE; function = 0; break;
|
case '1': function = 0; break;
|
||||||
case '2': type = TYPE_VOICE; function = 1; break;
|
case '2': function = 1; break;
|
||||||
case '3': type = TYPE_VOICE; function = 2; break;
|
case '3': function = 2; break;
|
||||||
case '4': type = TYPE_VOICE; function = 3; break;
|
case '4': function = 3; break;
|
||||||
case '5': type = TYPE_ALPHA; function = 0; break;
|
case '5': function = 0; break;
|
||||||
case '6': type = TYPE_ALPHA; function = 1; break;
|
case '6': function = 1; break;
|
||||||
case '7': type = TYPE_ALPHA; function = 2; break;
|
case '7': function = 2; break;
|
||||||
case '8': type = TYPE_ALPHA; function = 3; break;
|
case '8': function = 3; break;
|
||||||
case '9': type = TYPE_TONE; function = 0; break;
|
case '9': function = 0; break;
|
||||||
case '0': type = TYPE_TONE; function = 1; break;
|
case '0': function = 1; break;
|
||||||
default:
|
default:
|
||||||
PDEBUG(DGOLAY, DEBUG_NOTICE, "Illegal function suffix '%c' in last address digit.\n", address[6]);
|
PDEBUG(DGOLAY, DEBUG_NOTICE, "Illegal function suffix '%c' in last address digit.\n", address[6]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* override type */
|
switch (type) {
|
||||||
if (force_type >= 0) {
|
case TYPE_ALPHA:
|
||||||
type = force_type;
|
case TYPE_NUMERIC:
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Overriding message type as defined by sender.\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == TYPE_ALPHA || type == TYPE_NUMERIC)
|
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Coding text message for functional address '%s' and message '%s'.\n", address, message);
|
PDEBUG(DGOLAY, DEBUG_INFO, "Coding text message for functional address '%s' and message '%s'.\n", address, message);
|
||||||
else
|
break;
|
||||||
|
case TYPE_VOICE:
|
||||||
|
PDEBUG(DGOLAY, DEBUG_INFO, "Coding voice message for functional address %s with wave file '%s'.\n", address, message);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Coding tone only message for functional address %s.\n", address);
|
PDEBUG(DGOLAY, DEBUG_INFO, "Coding tone only message for functional address %s.\n", address);
|
||||||
|
}
|
||||||
|
|
||||||
/* encode preamble and store */
|
/* encode preamble and store */
|
||||||
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding preamble '%d'.\n", preamble);
|
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding preamble '%d'.\n", preamble);
|
||||||
@@ -573,7 +597,8 @@ static int queue_batch(gsc_t *gsc, const char *address, int force_type, const ch
|
|||||||
queue_dup(gsc, golay, 23);
|
queue_dup(gsc, golay, 23);
|
||||||
|
|
||||||
/* encode message */
|
/* encode message */
|
||||||
if (type == TYPE_ALPHA) {
|
switch (type) {
|
||||||
|
case TYPE_ALPHA:
|
||||||
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding %d alphanumeric digits.\n", (int)strlen(message));
|
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding %d alphanumeric digits.\n", (int)strlen(message));
|
||||||
for (i = 0; *message; i++) {
|
for (i = 0; *message; i++) {
|
||||||
if (i == MAX_ADB) {
|
if (i == MAX_ADB) {
|
||||||
@@ -608,8 +633,8 @@ static int queue_batch(gsc_t *gsc, const char *address, int force_type, const ch
|
|||||||
queue_bit(gsc, (bch[k] >> j) & 1);
|
queue_bit(gsc, (bch[k] >> j) & 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
if (type == TYPE_NUMERIC) {
|
case TYPE_NUMERIC:
|
||||||
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding %d numeric digits.\n", (int)strlen(message));
|
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding %d numeric digits.\n", (int)strlen(message));
|
||||||
shifted = 0;
|
shifted = 0;
|
||||||
for (i = 0; *message; i++) {
|
for (i = 0; *message; i++) {
|
||||||
@@ -658,12 +683,27 @@ static int queue_batch(gsc_t *gsc, const char *address, int force_type, const ch
|
|||||||
queue_bit(gsc, (bch[k] >> j) & 1);
|
queue_bit(gsc, (bch[k] >> j) & 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case TYPE_VOICE:
|
||||||
|
/* store wave file name */
|
||||||
|
memcpy(gsc->wave_tx_filename, message, MIN(sizeof(gsc->wave_tx_filename) - 1, strlen(message) + 1));
|
||||||
|
/* store bit number for activation code. this is used to play the AC again after voice message. */
|
||||||
|
gsc->bit_ac = gsc->bit_num;
|
||||||
|
/* encode activation code and store */
|
||||||
|
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding activation code.\n");
|
||||||
|
golay = calc_golay(activation_code);
|
||||||
|
queue_comma(gsc, 28, golay & 1);
|
||||||
|
queue_dup(gsc, golay, 23);
|
||||||
|
golay ^= 0x7fffff;
|
||||||
|
queue_bit(gsc, (golay & 1) ^ 1);
|
||||||
|
queue_dup(gsc, golay, 23);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* encode comma after message and store */
|
||||||
|
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding 'comma' sequence after message.\n");
|
||||||
|
queue_comma(gsc, 121 * 8, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* encode comma after message and store */
|
|
||||||
PDEBUG(DGOLAY, DEBUG_DEBUG, "Encoding 'comma' sequence after message.\n");
|
|
||||||
queue_comma(gsc, 121 * 8, 1);
|
|
||||||
|
|
||||||
/* check overflow */
|
/* check overflow */
|
||||||
if (gsc->bit_overflow) {
|
if (gsc->bit_overflow) {
|
||||||
PDEBUG(DGOLAY, DEBUG_ERROR, "Bit stream (%d bits) overflows bit buffer size (%d bits), please fix!\n", gsc->bit_num, (int)sizeof(gsc->bit));
|
PDEBUG(DGOLAY, DEBUG_ERROR, "Bit stream (%d bits) overflows bit buffer size (%d bits), please fix!\n", gsc->bit_num, (int)sizeof(gsc->bit));
|
||||||
@@ -680,21 +720,31 @@ static int queue_batch(gsc_t *gsc, const char *address, int force_type, const ch
|
|||||||
* if there is a message, return next bit to be transmitted.
|
* if there is a message, return next bit to be transmitted.
|
||||||
*
|
*
|
||||||
* if there is a message in the queue, encode message and return its first bit.
|
* if there is a message in the queue, encode message and return its first bit.
|
||||||
|
*
|
||||||
|
* if there is a voice message, return 2 at the end, to tell the DSP to send voice.
|
||||||
*/
|
*/
|
||||||
int8_t get_bit(gsc_t *gsc)
|
int8_t get_bit(gsc_t *gsc)
|
||||||
{
|
{
|
||||||
gsc_msg_t *msg;
|
gsc_msg_t *msg;
|
||||||
uint8_t bit;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* if currently transmiting message, send next bit */
|
/* if currently transmiting message, send next bit */
|
||||||
if (gsc->bit_num) {
|
if (gsc->bit_num) {
|
||||||
bit = gsc->bit[gsc->bit_index++];
|
/* Transmission complete. */
|
||||||
if (gsc->bit_index == gsc->bit_num) {
|
if (gsc->bit_index == gsc->bit_num) {
|
||||||
|
/* on voice message... */
|
||||||
|
if (gsc->bit_ac) {
|
||||||
|
/* rewind to play the AC again after voice transmission */
|
||||||
|
gsc->bit_index = gsc->bit_ac;
|
||||||
|
gsc->bit_ac = 0;
|
||||||
|
/* indicate voice message to DSP */
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
queue_reset(gsc);
|
queue_reset(gsc);
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Done transmitting message.\n");
|
PDEBUG(DGOLAY, DEBUG_INFO, "Done transmitting message.\n");
|
||||||
|
goto next_msg;
|
||||||
}
|
}
|
||||||
return bit;
|
return gsc->bit[gsc->bit_index++];
|
||||||
}
|
}
|
||||||
|
|
||||||
next_msg:
|
next_msg:
|
||||||
@@ -705,7 +755,7 @@ next_msg:
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* encode first message in queue */
|
/* encode first message in queue */
|
||||||
rc = queue_batch(gsc, msg->address, msg->force_type, msg->data);
|
rc = queue_batch(gsc, msg->address, msg->type, msg->data);
|
||||||
if (rc >= 0)
|
if (rc >= 0)
|
||||||
PDEBUG(DGOLAY, DEBUG_INFO, "Transmitting message to address '%s'.\n", msg->address);
|
PDEBUG(DGOLAY, DEBUG_INFO, "Transmitting message to address '%s'.\n", msg->address);
|
||||||
golay_msg_destroy(gsc, msg);
|
golay_msg_destroy(gsc, msg);
|
||||||
@@ -713,33 +763,37 @@ next_msg:
|
|||||||
goto next_msg;
|
goto next_msg;
|
||||||
|
|
||||||
/* return first bit */
|
/* return first bit */
|
||||||
bit = gsc->bit[gsc->bit_index++];
|
return gsc->bit[gsc->bit_index++];
|
||||||
return bit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void golay_msg_send(const char *text)
|
void golay_msg_send(const char *text)
|
||||||
{
|
{
|
||||||
char buffer[strlen(text) + 1], *p = buffer, *address_string, *message;
|
char buffer[strlen(text) + 1], *p = buffer, *address_string, *message;
|
||||||
gsc_t *gsc;
|
gsc_t *gsc;
|
||||||
int force_type = -1;
|
enum gsc_msg_type type = TYPE_AUTO;
|
||||||
|
|
||||||
strcpy(buffer, text);
|
strcpy(buffer, text);
|
||||||
address_string = strsep(&p, ",");
|
address_string = strsep(&p, ",");
|
||||||
message = p;
|
message = p;
|
||||||
if (message) {
|
switch ((message[0] << 8) | message[1]) {
|
||||||
if (message[0] == 'a' && message[1] == ',') {
|
case ('a' << 8) | ',':
|
||||||
force_type = TYPE_ALPHA;
|
type = TYPE_ALPHA;
|
||||||
message += 2;
|
message += 2;
|
||||||
} else
|
break;
|
||||||
if (message[0] == 'n' && message[1] == ',') {
|
case ('n' << 8) | ',':
|
||||||
force_type = TYPE_NUMERIC;
|
type = TYPE_NUMERIC;
|
||||||
message += 2;
|
message += 2;
|
||||||
}
|
break;
|
||||||
} else
|
case ('v' << 8) | ',':
|
||||||
|
type = TYPE_VOICE;
|
||||||
|
message += 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
message = "";
|
message = "";
|
||||||
|
}
|
||||||
|
|
||||||
gsc = (gsc_t *) sender_head;
|
gsc = (gsc_t *) sender_head;
|
||||||
golay_msg_create(gsc, address_string, message, force_type);
|
golay_msg_create(gsc, address_string, message, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void call_down_clock(void)
|
void call_down_clock(void)
|
||||||
@@ -785,7 +839,7 @@ int call_down_setup(int __attribute__((unused)) callref, const char *caller_id,
|
|||||||
message = gsc->default_message;
|
message = gsc->default_message;
|
||||||
|
|
||||||
/* create call process to page station */
|
/* create call process to page station */
|
||||||
msg = golay_msg_create(gsc, address, message, -1);
|
msg = golay_msg_create(gsc, address, message, TYPE_AUTO);
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -CAUSE_INVALNUMBER;
|
return -CAUSE_INVALNUMBER;
|
||||||
return -CAUSE_NORMAL;
|
return -CAUSE_NORMAL;
|
||||||
|
@@ -1,9 +1,13 @@
|
|||||||
#include "../libmobile/sender.h"
|
#include "../libmobile/sender.h"
|
||||||
|
|
||||||
#define TYPE_TONE 0 /* TONE only */
|
enum gsc_msg_type {
|
||||||
#define TYPE_VOICE 1 /* TONE + VOICE */
|
TYPE_AUTO = 0, /* Defined by 7th digit */
|
||||||
#define TYPE_ALPHA 2 /* TONE + DATA */
|
TYPE_TONE, /* TONE only */
|
||||||
#define TYPE_NUMERIC 3 /* TONE + DATA */
|
TYPE_VOICE, /* TONE + VOICE */
|
||||||
|
TYPE_ALPHA, /* TONE + DATA */
|
||||||
|
TYPE_NUMERIC, /* TONE + DATA */
|
||||||
|
};
|
||||||
|
|
||||||
#define MAX_ADB 10 /* 80 characters */
|
#define MAX_ADB 10 /* 80 characters */
|
||||||
#define MAX_NDB 2 /* 24 digits */
|
#define MAX_NDB 2 /* 24 digits */
|
||||||
|
|
||||||
@@ -11,7 +15,7 @@
|
|||||||
typedef struct gsc_msg {
|
typedef struct gsc_msg {
|
||||||
struct gsc_msg *next;
|
struct gsc_msg *next;
|
||||||
char address[8]; /* 7 digits + EOL */
|
char address[8]; /* 7 digits + EOL */
|
||||||
int force_type; /* override type from address digit 7 */
|
enum gsc_msg_type type; /* type of message */
|
||||||
char data[256]; /* message to be transmitted */
|
char data[256]; /* message to be transmitted */
|
||||||
} gsc_msg_t;
|
} gsc_msg_t;
|
||||||
|
|
||||||
@@ -25,6 +29,7 @@ typedef struct gsc {
|
|||||||
/* current trasmitting message */
|
/* current trasmitting message */
|
||||||
uint8_t bit[4096];
|
uint8_t bit[4096];
|
||||||
int bit_num;
|
int bit_num;
|
||||||
|
int bit_ac; /* where activation code starts (voice only). */
|
||||||
int bit_index; /* when playing out */
|
int bit_index; /* when playing out */
|
||||||
int bit_overflow;
|
int bit_overflow;
|
||||||
|
|
||||||
@@ -41,6 +46,14 @@ typedef struct gsc {
|
|||||||
int fsk_tx_buffer_pos; /* current position sending buffer */
|
int fsk_tx_buffer_pos; /* current position sending buffer */
|
||||||
double fsk_tx_phase; /* current bit position */
|
double fsk_tx_phase; /* current bit position */
|
||||||
uint8_t fsk_tx_lastbit; /* last bit of last message, to correctly ramp */
|
uint8_t fsk_tx_lastbit; /* last bit of last message, to correctly ramp */
|
||||||
|
|
||||||
|
/* voice message */
|
||||||
|
int wait_2_sec; /* counter to wait 2 seconds before playback */
|
||||||
|
char wave_tx_filename[256];
|
||||||
|
int wave_tx_samplerate;
|
||||||
|
int wave_tx_channels;
|
||||||
|
wave_play_t wave_tx_play; /* wave playback */
|
||||||
|
samplerate_t wave_tx_upsample; /* wave upsampler */
|
||||||
} gsc_t;
|
} gsc_t;
|
||||||
|
|
||||||
int golay_create(const char *kanal, double frequency, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, double deviation, double polarity, const char *message, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback);
|
int golay_create(const char *kanal, double frequency, const char *device, int use_sdr, int samplerate, double rx_gain, double tx_gain, double deviation, double polarity, const char *message, const char *write_rx_wave, const char *write_tx_wave, const char *read_rx_wave, const char *read_tx_wave, int loopback);
|
||||||
|
@@ -73,6 +73,7 @@ void print_help(const char *arg0)
|
|||||||
printf(" Write \"<address>[,message]\" to it, to send a default message.\n");
|
printf(" Write \"<address>[,message]\" to it, to send a default message.\n");
|
||||||
printf(" Write \"<address>,n,message\" to it, to send a numeric message.\n");
|
printf(" Write \"<address>,n,message\" to it, to send a numeric message.\n");
|
||||||
printf(" Write \"<address>,a,message\" to it, to send an alphanumeric message.\n");
|
printf(" Write \"<address>,a,message\" to it, to send an alphanumeric message.\n");
|
||||||
|
printf(" Write \"<address>,v,<wave file name>\" to it, to send a voice message.\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("By default, an alphanumic message is sent, if last digit of the functional\n");
|
printf("By default, an alphanumic message is sent, if last digit of the functional\n");
|
||||||
printf("address is 5..8. Otherwise a tone only message is sent.\n");
|
printf("address is 5..8. Otherwise a tone only message is sent.\n");
|
||||||
|
Reference in New Issue
Block a user