Logo Search packages:      
Sourcecode: hf version File versions

mt63hflink.c

/*
 *    mt63hflink.c  --  by GŁnther Montag DL4MGE
 *    "glue" - links Pawel Jalocha's MT63 code to
 *    Tom Sailer's hf code          
 *    for integration of MT63 into hf
 *          
 *
 *    hf and MT63 is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *    (at your option) any later version.
 *
 *    hf & MT63 is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with MT63; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/*DEBUG*/
#ifndef DEBUG
#define DEBUG printf("%s: function %s still running at line %d...\n", \
__FILE__, __FUNCTION__,  __LINE__);

#define D DEBUG
#endif /*DEBUG*/

#include <stdio.h>
#include <sys/stat.h>
//#include <fcntl.h> makes conflicts with types in msg.h
#include <errno.h>
#include <ctype.h>
#include <syslog.h>
#include <unistd.h>
#include <pthread.h>

#include "mt63hflink.h"
#include "mt63hf.h"
#include "fskl1.h"
#include "fskutil.h"
#include "msg.h"
#include "main.h"
#include "oss.h"
#ifdef HAVE_ALSA_ASOUNDLIB_H
#include "alsa.h"
#endif /* HAVE_ALSA_ASOUNDLIB_H */

// ============================================================================

struct mt63p mt63p = { 1000, 32, "MT63", 0 };

// ============================================================================

short mt63rxbuf[MT63RXBUFLEN];
short mt63txbuf[MT63TXBUFLEN];
int mt63rxbuf_written, mt63rxbuf_read;
int mt63txbuf_written, mt63txbuf_read;
short encodebuf[ENCODEBUFSIZE];
int encodelen;
pthread_mutex_t mt63_inputmut  = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  mt63_inputcond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mt63_outputmut  = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t  mt63_outputcond = PTHREAD_COND_INITIALIZER;
int switched_to_nommap = 0;

// ============================================================================

void mt63_set_params(unsigned int bandwidth, unsigned int integration,
    const unsigned char* cwcall, unsigned int doubleinterleave)
{
        errprintf(SEV_INFO, 
          "mt63 params: bandwidth %u Hz with %s interleave for tx, \n"
          "the time/frequency synchronizer integrates over %u symbols,\n"
          "at tx the call %s is sent in cw as background.\n",
          bandwidth, doubleinterleave ? "DOUBLE (64)" : "SINGLE (32)",
          integration, cwcall);
      mt63p.bandwidth = bandwidth;
      mt63p.doubleinterleave = doubleinterleave;
      mt63p.integration = integration;
      sprintf(mt63p.cwcall, "%s", cwcall);
}

/* --------------------------------------------------------------------- */

void l1_mt63_input_samples(short *samples, unsigned int nsamples)
{
      int i, input;
      int mt63rxbuf_old_written;

      mt63rxbuf_old_written = mt63rxbuf_written;
      if (pthread_mutex_lock(&mt63_inputmut))
          errstr(SEV_FATAL, "pthread_mutex_lock");
      for (i = 0; i < nsamples; i++) {
          mt63rxbuf[mt63rxbuf_written] = samples[i];
          mt63rxbuf_written++;
          if (mt63rxbuf_written >= MT63RXBUFLEN) {
            mt63rxbuf_written = 0;
          }
      }
      if ((input = ((mt63rxbuf_written + MT63RXBUFLEN - mt63rxbuf_read) 
          % MT63RXBUFLEN )) >= 512 ) {
          //printf("mt63 input: %d bytes available", input);
          pthread_cond_signal(&mt63_inputcond);
      }
      /*
      printf("mt63 input: written %d bytes to buffer \n",
          (mt63rxbuf_written - mt63rxbuf_old_written + MT63RXBUFLEN)
          % MT63RXBUFLEN );
      */
      if (pthread_mutex_unlock(&mt63_inputmut))
          errstr(SEV_FATAL, "pthread_mutex_unlock");
}

/* --------------------------------------------------------------------- */

int l1_mt63_output_samples(l1_time_t tstart, l1_time_t tinc,
      short *samples, unsigned int nsamples)
{
      int i, output = 0;
      static l1_time_t mytime = 0;

      if (pthread_mutex_lock(&mt63_outputmut))
          errstr(SEV_FATAL, "pthread_mutex_lock");
      if (mytime == 0) mytime = tstart;
      output = ((mt63txbuf_written + MT63TXBUFLEN - mt63txbuf_read) 
          % MT63TXBUFLEN );
      if (output < (MT63TXBUFLEN / 2) ) {
      //printf("mt63 output buf half empty, send signal to encoder...\n");
            pthread_cond_signal(&mt63_outputcond);
      }
      if (tstart > mytime ) {
          // if it 's time to send something new
          if (output > nsamples ) {
          // means if full count of samples available
          // for (i = 0; i < nsamples; i++) {
          // samples[i] = mt63txbuf[mt63txbuf_read];
          //  same is:        
            for (i = 0; i < nsamples; samples++, i++) {
                *samples = mt63txbuf[mt63txbuf_read];
                mt63txbuf_read++;

                if (mt63txbuf_read >= MT63TXBUFLEN) {
                  mt63txbuf_read -= MT63TXBUFLEN;
                }
            }  
            //printf("%do ",i);
            mytime += (tinc * nsamples); // nsamples fragments encoded
            if (pthread_mutex_unlock(&mt63_outputmut))
                errstr(SEV_FATAL, "pthread_mutex_unlock");
            return 1;
          } else {
            if (pthread_mutex_unlock(&mt63_outputmut))
                errstr(SEV_FATAL, "pthread_mutex_unlock");
            return 0;
          }
      } 
      // if it is not yet the time to send sting new
      printf("mt63 output samples came too early.\n");
      if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "pthread_mutex_unlock");
      return 0;
}

/* --------------------------------------------------------------------- */

static void mt63_inputcleanup(void *dummy)
{
      if (pthread_mutex_unlock(&mt63_inputmut))
            errstr(SEV_FATAL, "pthread_mutex_unlock");
      modefamily = 0;
}

/* --------------------------------------------------------------------- */

void l1_mt63_wait_input_request(void)
{
      if (pthread_mutex_lock(&mt63_inputmut))
            errstr(SEV_FATAL, "pthread_mutex_lock");

      pthread_cleanup_push(mt63_inputcleanup, NULL);

      if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
            errstr(SEV_FATAL, "pthread_setcancelstate");
      if (pthread_cond_wait(&mt63_inputcond, &mt63_inputmut))
            errstr(SEV_FATAL, "pthread_cond_wait");

      pthread_cleanup_pop(0);

      if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL))
            errstr(SEV_FATAL, "pthread_setcancelstate");
      if (pthread_mutex_unlock(&mt63_inputmut))
            errstr(SEV_FATAL, "pthread_mutex_unlock");
      return;
}

/* --------------------------------------------------------------------- */

static void mt63_outputcleanup(void *dummy)
{
      /* if Tom's mmap-using fdx driver was running before
       * i switched to mt63, 
       * we stopped it, started the no-mmap driver,
       * because mt63 decodes bug pieces of 800 samples = 100 ms
       * duration, and this decoding would disturbs the realtime driver
       * So, now all the thing in reverse order now... 
       */

      mt63_finish_tx();
      //printf("mt63 tx finished ...\n");
      if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "pthread_mutex_unlock");
      printf("mt63 outputmutex unlocked...\n");
      modefamily = 0;

      if (switched_to_nommap) {
          switched_to_nommap = 0; 
          l1_switch_to_mmap(); // is in l1/sound.c
          //printf("switched back to mmap driver...\n");
          
/*        // this is the same and also works: 

          if (pthread_cancel(thr_l1))
            errstr(SEV_FATAL, "pthread_cancel");
          if (pthread_join(thr_l1, NULL))
            errstr(SEV_FATAL, "pthread_join");
          l1_init();
          switched_to_nommap = 0;
          bufprintf(HFAPP_MSG_DATA_STATUS, 
            "switched back to Tom's good mmap-using sound driver");
          printf("switched back to Tom's good mmap-using sound driver.\n");
*/        
      }
}

/* --------------------------------------------------------------------- */
 
void l1_mt63_wait_output_request(void)
{
      if (pthread_mutex_lock(&mt63_outputmut))
            errstr(SEV_FATAL, "pthread_mutex_lock");
      pthread_cleanup_push(mt63_outputcleanup, NULL);
      if (pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL))
            errstr(SEV_FATAL, "pthread_setcancelstate");
      if (pthread_cond_wait(&mt63_outputcond, &mt63_outputmut))
            errstr(SEV_FATAL, "pthread_cond_wait");
      pthread_cleanup_pop(0);
      if (pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL))
            errstr(SEV_FATAL, "pthread_setcancelstate");
      if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "pthread_mutex_unlock");
      return;
}

/* --------------------------------------------------------------------- */

void *mode_mt63_direct_rx(void *dummy)
{
      errprintf(SEV_INFO, "mode: mt63 rx\n");
      //bufprintf(HFAPP_MSG_DATA_STATUS, "MT63 direct RX test");
      mt63_direct_rx();
          return 0;
}

/* --------------------------------------------------------------------- */

void mt63_rx_test()
{
      errprintf(SEV_INFO, "test: mt63 rx\n");
//    bufprintf(HFAPP_MSG_DATA_STATUS, "MT63 RX test ");
      mt63_rx_start
          (1000,  // bandwidth, 
          0,            //doubleinterleave, 
          32,     //integration,
          snd_corr);
          return;
}

/* --------------------------------------------------------------------- */

void mt63_tx_test()
{
      errprintf(SEV_INFO, "test: mt63 tx\n");
//    bufprintf(HFAPP_MSG_DATA_STATUS, "MT63 RX ");
      mt63_direct_tx();
      return;
}

/* --------------------------------------------------------------------- */

void *mode_mt63_rx(void *dummy)
{
      int i;
      
      modefamily = MT63;
      errprintf(SEV_INFO, "mode: mt63 rx\n");
      send_short_msg(HFAPP_MSG_STATE_MT63_RX, ERR_NOERR);

      mt63_rx_start
          (mt63p.bandwidth, mt63p.doubleinterleave, 
            mt63p.integration, snd_corr);
/*
      bufprintf(HFAPP_MSG_DATA_STATUS, 
          "MT63 RX.\nBandwidth %u, interleave: %s,\n"
          "integration: %u -> Please wait %1.1f seconds ... ", 
          mt63p.bandwidth, 
          mt63p.doubleinterleave ? "DOUBLE (64)" : "SINGLE (32)",
          mt63p.integration, 
          mt63p.integration / 10.0);
*/
      printf("MT63 RX.\nBandwidth %u, interleave: %s,\n"
          "integration: %u -> Please wait %1.1f seconds ... ", 
          mt63p.bandwidth, 
          mt63p.doubleinterleave ? "DOUBLE (64)" : "SINGLE (32)",
          mt63p.integration, 
          mt63p.integration / 10.0);

      for(;;) {
          l1_mt63_wait_input_request();
          mt63_decode(mt63rxbuf + mt63rxbuf_read, 512);
          mt63rxbuf_read += 512;
          while (mt63rxbuf_read >= MT63RXBUFLEN) {
            mt63rxbuf_read -= MT63RXBUFLEN;
          }
          //printf(/*MT63 rx data:*/"%s", code);
          for(i=0; i<strlen(code); i++) { 
            if((code[i]>=' ')||(code[i]==0x08)||(code[i]==0x09)) {
                bufprintf(HFAPP_MSG_DATA_RECEIVE, "%c", code[i]);
                bufprintf(HFAPP_MSG_DATA_MONITOR, "%c",code[i]);
                printf("%c",code[i]);
            } else if ((code[i] == 10) || (code[i] == 13))  {//'\r') {
                      code[i] = '\n'; //outcomment = test for mailbox
                bufprintf(HFAPP_MSG_DATA_RECEIVE, "%c", code[i]);
                bufprintf(HFAPP_MSG_DATA_MONITOR, "%c", code[i]);
                printf("%c", code[i]);
            } else if(code[i]!='\0') {
                //bufprintf(HFAPP_MSG_DATA_MONITOR, "<%02x> ", code[i]);
                bufprintf(HFAPP_MSG_DATA_MONITOR, "<%d>", (int)code[i]);
                    //printf("<%02X> ",code[i]); //orig !!
                      printf("<%d>", (int)code[i]); //test  !!
            }
            }
          fflush(stdout);
      }
}

/* --------------------------------------------------------------------- */

unsigned char mt63_getcharbits(void)
{
      unsigned char bp;
      unsigned short ch;
      static int idlecount = 0; 
      int eof_ack_start = 16; // 32
      
      kbd_negack();
      if ((ch = kbd_get()) == KBD_EOF) {
          idlecount++;
          //bufprintf(HFAPP_MSG_DATA_STATUS, 
            //"mt63_getcharbits: KBD_EOF nr. %d", idlecount);
          if (idlecount >= eof_ack_start) {
            //bufprintf(HFAPP_MSG_DATA_STATUS, 
                //"mt63_getcharbits: I kbd_ack() the EOF at %d", idlecount);
            kbd_ack();
            idlecount = 0;
          }
          return 0; //0xff;
      } else idlecount = 0; //something to transmit: -> reset of idlecount
      ch &= KBD_CHAR;
      bp = (unsigned char)ch;
      kbd_ack();
      return bp;
}

/* --------------------------------------------------------------------- */

void mt63_finish_tx()
{
      int tx_hangover  = 2 * (mt63p.doubleinterleave ? 64 : 32);
      int i, j;
      char txchar = 0;
      
      printf("mt63 tx: Flushing data interleaver ...\n");
      errprintf(SEV_INFO, "mt63 tx: Flushing data interleaver ...\n");
/*
      bufprintf(HFAPP_MSG_DATA_STATUS, 
          "MT63 TX: \nFlushing data interleaver for %1.1f seconds",
            tx_hangover / 10.0);
*/
      /*
       * this long hangover because otherwise receiver's squelch will
       * cut off tail of the data !
       */
      for(i=0; i< tx_hangover; i++) { 
          //l1_mt63_wait_output_request(); this causes hang while cleanup!!
          if (pthread_cond_wait(&mt63_outputcond, &mt63_outputmut))
            errstr(SEV_FATAL, "pthread_cond_wait");
          bufprintf(HFAPP_MSG_DATA_MONITOR, 
            //"%02d ", (int)((txchar >> 1) & 0x1f));
            ".");
          memset(encodebuf, 0, sizeof(encodebuf));
          encodelen = mt63_encode(txchar);
          for(j = 0; j < encodelen; j++) {
            mt63txbuf[mt63txbuf_written] = encodebuf[j];
            mt63txbuf_written++;
            if (mt63txbuf_written >= MT63TXBUFLEN)
                mt63txbuf_written -= MT63TXBUFLEN;
          }
          //printf("written %d rest-samples from encodebuf to outbuf...\n", j);
          if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "mt63 tx: pthread_mutex_unlock");
      }
      printf("o.k., flushed encodebuf, %d cycles...\n", i);
      
      errprintf(SEV_INFO, "mt63 tx: Sending jamming waveform ...\n");
/*
      bufprintf(HFAPP_MSG_DATA_STATUS, 
          "MT63 TX: Sending jamming waveform ...");
*/
      for ( i = 0; i < 20; i++) { 
          l1_mt63_wait_output_request();
          if (pthread_mutex_lock(&mt63_outputmut))
            errstr(SEV_FATAL, "mt63 tx: pthread_mutex_lock");
          memset(encodebuf, 0, sizeof(encodebuf));
          mt63_tx_send_jam();
          for(j = 0; j < encodelen; j++) {
            mt63txbuf[mt63txbuf_written] = encodebuf[j];
            mt63txbuf_written++;
            if (mt63txbuf_written >= MT63TXBUFLEN)
                mt63txbuf_written -= MT63TXBUFLEN;
          }
          if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "mt63 tx: pthread_mutex_unlock");
      }
      printf("sent %d cycles of jam ...\n", i);
} 

/* --------------------------------------------------------------------- */

void *mode_mt63_tx(void *dummy)
{
      int i, j; 
      char txchar;
      char * testchar = "\n  mt63  \n";
      
      modefamily = MT63;

      /*reset buffers */
      memset(encodebuf, 0, sizeof(encodebuf));
      mt63txbuf_written = mt63txbuf_read = 0;
      memset(mt63txbuf, 0, sizeof(mt63txbuf));

      /* initialize mt36 params */
      mt63_tx_start (mt63p.bandwidth, mt63p.doubleinterleave, 
            snd_corr, mt63p.cwcall);

      /* messages */
      errprintf(SEV_INFO, "mode: mt63 tx\n");
//    bufprintf(HFAPP_MSG_DATA_STATUS, "MT63 TX ");
/*
      bufprintf(HFAPP_MSG_DATA_STATUS, 
          "MT63 TX:\nBandwidth: %u, interleave: %s, \nCW id: %s",
          mt63p.bandwidth, 
          mt63p.doubleinterleave ? "DOUBLE (64)" : "SINGLE (32)",
          mt63p.cwcall);
*/
      send_short_msg(HFAPP_MSG_STATE_MT63_TX, ERR_NOERR);

      // prefill output buffer 
      if (pthread_mutex_lock(&mt63_outputmut))
          errstr(SEV_FATAL, "mt63 tx: pthread_mutex_lock");
      for (j = 0; j < strlen(testchar); j++) {
          txchar = testchar[j]; // mt63_getcharbits();
          bufprintf(HFAPP_MSG_DATA_MONITOR, 
            "%02d ", (int)((txchar >> 1) & 0x1f));
          memset(encodebuf, 0, sizeof(encodebuf));
          encodelen = mt63_encode(txchar);
          for(i = 0; i < encodelen; i++) {
            mt63txbuf[mt63txbuf_written] = encodebuf[i];
            mt63txbuf_written++;
            if (mt63txbuf_written >= MT63TXBUFLEN)
                mt63txbuf_written -= MT63TXBUFLEN;
          }
      }
      if (pthread_mutex_unlock(&mt63_outputmut))
          errstr(SEV_FATAL, "mt63 tx: pthread_mutex_unlock");
      //for(j = 0; j < 24; j++) {   
      for(;;) {
          l1_mt63_wait_output_request();
          if (pthread_mutex_lock(&mt63_outputmut))
            errstr(SEV_FATAL, "mt63 tx: pthread_mutex_lock");
          txchar = mt63_getcharbits();
          //txchar = 'f';
          bufprintf(HFAPP_MSG_DATA_MONITOR, 
            "%02d ", (int)((txchar >> 1) & 0x1f));
          memset(encodebuf, 0, sizeof(encodebuf));
          encodelen = mt63_encode(txchar);
          for(i = 0; i < encodelen; i++) {
            mt63txbuf[mt63txbuf_written] = encodebuf[i];
            mt63txbuf_written++;
            if (mt63txbuf_written >= MT63TXBUFLEN)
                mt63txbuf_written -= MT63TXBUFLEN;
          }
          //printf("written %d samples from encodebuf to outbuf...\n",i);
          if (pthread_mutex_unlock(&mt63_outputmut))
            errstr(SEV_FATAL, "mt63 tx: pthread_mutex_unlock");
      }
      // mt63_outputcleanup(NULL);
      // pthread_exit(NULL);
}

/* --------------------------------------------------------------------- */ 

Generated by  Doxygen 1.6.0   Back to index