Exemplo n.º 1
0
int demod_init (struct audio_s *pa)
{
	int j;
	int chan;		/* Loop index over number of radio channels. */
	char profile;
	


/*
 * Save audio configuration for later use.
 */

	save_audio_config_p = pa;

	for (chan = 0; chan < MAX_CHANS; chan++) {

	 if (save_audio_config_p->achan[chan].valid) {

	  char *p;
	  char just_letters[16];
	  int num_letters;
	  int have_plus;

	  switch (save_audio_config_p->achan[chan].modem_type) {

	    case MODEM_OFF:
	      break;

	    case MODEM_AFSK:

/*
 * Tear apart the profile and put it back together in a normalized form:
 *	- At least one letter, supply suitable default if necessary.
 *	- Upper case only.
 *	- Any plus will be at the end.
 */
	      num_letters = 0;
	      just_letters[num_letters] = '\0';
	      have_plus = 0;
	      for (p = save_audio_config_p->achan[chan].profiles; *p != '\0'; p++) {

	        if (islower(*p)) {
	          just_letters[num_letters] = toupper(*p);
	          num_letters++;
	          just_letters[num_letters] = '\0';
	        }

	        else if (isupper(*p)) {
	          just_letters[num_letters] = *p;
	          num_letters++;
	          just_letters[num_letters] = '\0';
	        }

	        else if (*p == '+') {
	          have_plus = 1;
	          if (p[1] != '\0') {
		    text_color_set(DW_COLOR_ERROR);
		    dw_printf ("Channel %d: + option must appear at end of demodulator types \"%s\" \n", 
					chan, save_audio_config_p->achan[chan].profiles);
		  }	    
	        }

	        else if (*p == '-') {
	          have_plus = -1;
	          if (p[1] != '\0') {
		    text_color_set(DW_COLOR_ERROR);
		    dw_printf ("Channel %d: - option must appear at end of demodulator types \"%s\" \n", 
					chan, save_audio_config_p->achan[chan].profiles);
		  }	
    
	        } else {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("Channel %d: Demodulator types \"%s\" can contain only letters and + - characters.\n", 
					chan, save_audio_config_p->achan[chan].profiles);
	        }
	      }

	      assert (num_letters == strlen(just_letters));

/*
 * Pick a good default demodulator if none specified. 
 */
	      if (num_letters == 0) {

	        if (save_audio_config_p->achan[chan].baud < 600) {

	          /* This has been optimized for 300 baud. */

	          strcpy (just_letters, "D");

	        }
	        else {
#if __arm__
	          /* We probably don't have a lot of CPU power available. */
	          /* Previously we would use F if possible otherwise fall back to A. */
#if 0
	          if (save_audio_config_p->achan[chan].baud == FFF_BAUD &&
		      save_audio_config_p->achan[chan].mark_freq == FFF_MARK_FREQ && 
		      save_audio_config_p->achan[chan].space_freq == FFF_SPACE_FREQ &&
		      save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec == FFF_SAMPLES_PER_SEC) {

	            just_letters[0] = FFF_PROFILE;
	            just_letters[1] = '\0';
	          }
	          else {
	            strcpy (just_letters, "A");
	          }
#else
	          /* In version 1.2, new default is E+ /3. */
	          strcpy (just_letters, "E");			// version 1.2 now E.
	          if (have_plus != -1) have_plus = 1;		// Add as default for version 1.2
								// If not explicitly turned off.
	          if (save_audio_config_p->achan[chan].decimate == 0) {
	            save_audio_config_p->achan[chan].decimate = 3;
	          }
#endif

#else
	          strcpy (just_letters, "E");			// version 1.2 changed C to E.
	          if (have_plus != -1) have_plus = 1;		// Add as default for version 1.2
								// If not explicitly turned off.
#endif
	        }
	        num_letters = 1;
	      }

	      assert (num_letters == strlen(just_letters));

/*
 * Put it back together again.
 */

		/* At this point, have_plus can have 3 values: */
		/* 	1 = turned on, either explicitly or by applied default */
		/*	-1 = explicitly turned off.  change to 0 here so it is false. */
		/* 	0 = off by default. */

	      if (have_plus == -1) have_plus = 0;

	      strcpy (save_audio_config_p->achan[chan].profiles, just_letters);
	      
	      assert (strlen(save_audio_config_p->achan[chan].profiles) >= 1);

	      if (have_plus) {
	        strcat (save_audio_config_p->achan[chan].profiles, "+");
	      }

	      /* These can be increased later for the multi-frequency case. */

	      save_audio_config_p->achan[chan].num_subchan = num_letters;
	      save_audio_config_p->achan[chan].num_demod = num_letters;		
	   

/*
 * Some error checking - Can use only one of these:
 *
 *	- Multiple letters.
 *	- New + multi-slicer.
 *	- Multiple frequencies.
 */

	      if (have_plus && num_letters > 1) {

		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("Channel %d: Demodulator + option can't be combined with multiple letters.\n", chan);

	          strcpy (save_audio_config_p->achan[chan].profiles, "C+");	// Reduce to one letter.
		  num_letters = 1;
	          save_audio_config_p->achan[chan].num_demod = 1;
	          save_audio_config_p->achan[chan].num_subchan = 1;	// Will be set higher later.
	          save_audio_config_p->achan[chan].num_freq = 1;
	      }

	      if (have_plus && save_audio_config_p->achan[chan].num_freq > 1) {

		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("Channel %d: Demodulator + option can't be combined with multiple frequencies.\n", chan);

	          save_audio_config_p->achan[chan].num_demod = 1;
	          save_audio_config_p->achan[chan].num_subchan = 1;	// Will be set higher later.
	          save_audio_config_p->achan[chan].num_freq = 1;
	      }

	      if (num_letters > 1 && save_audio_config_p->achan[chan].num_freq > 1) {

		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("Channel %d: Multiple demodulator types can't be combined with multiple frequencies.\n", chan);

	          save_audio_config_p->achan[chan].profiles[1] = '\0';
		  num_letters = 1;
	      }

	      if (save_audio_config_p->achan[chan].decimate == 0) {
	        save_audio_config_p->achan[chan].decimate = 1;
		if (strchr (just_letters, 'D') != NULL && save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec > 40000) {
		  save_audio_config_p->achan[chan].decimate = 3;
		}
	      }

	      text_color_set(DW_COLOR_DEBUG);
	      dw_printf ("Channel %d: %d baud, AFSK %d & %d Hz, %s, %d sample rate",
		    chan, save_audio_config_p->achan[chan].baud, 
		    save_audio_config_p->achan[chan].mark_freq, save_audio_config_p->achan[chan].space_freq,
		    save_audio_config_p->achan[chan].profiles,
		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec);
	      if (save_audio_config_p->achan[chan].decimate != 1) 
	        dw_printf (" / %d", save_audio_config_p->achan[chan].decimate);
	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF) 
	        dw_printf (", DTMF decoder enabled");
	      dw_printf (".\n");


/* 
 * Initialize the demodulator(s).
 *
 * We have 3 cases to consider.
 */


	      if (num_letters > 1) {
	        int d;

/*	
 * Multiple letters, usually for 1200 baud.
 * Each one corresponds to a demodulator and subchannel.
 *
 * An interesting experiment but probably not too useful.
 * Can't have multiple frequency pairs or the + option.
 */

	        save_audio_config_p->achan[chan].num_subchan = num_letters;
	        save_audio_config_p->achan[chan].num_demod = num_letters;
		

		if (save_audio_config_p->achan[chan].num_demod != num_letters) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_demod(%d) != strlen(\"%s\")\n",
				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_demod, save_audio_config_p->achan[chan].profiles);
		}

	        if (save_audio_config_p->achan[chan].num_freq != 1) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != 1\n",
				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq);
		}
	  
	        for (d = 0; d < save_audio_config_p->achan[chan].num_demod; d++) {

	          int mark, space;
	          assert (d >= 0 && d < MAX_SUBCHANS);

	          struct demodulator_state_s *D;
	          D = &demodulator_state[chan][d];

	          profile = save_audio_config_p->achan[chan].profiles[d];
	          mark = save_audio_config_p->achan[chan].mark_freq;
	          space = save_audio_config_p->achan[chan].space_freq;

	          if (save_audio_config_p->achan[chan].num_demod != 1) {
	            text_color_set(DW_COLOR_DEBUG);
	            dw_printf ("        %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
	          }
      
	          demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate, 
			    save_audio_config_p->achan[chan].baud,
		            mark, 
	                    space,
			    profile,
			    D);

	          /* For siginal level reporting, we want a longer term view. */
		  // TODO: Should probably move this into the init functions.

	          D->quick_attack = D->agc_fast_attack * 0.2;
	          D->sluggish_decay = D->agc_slow_decay * 0.2;
	        }
	      }
	      else if (have_plus) {
	       
/*
 * PLUS - which implies we have only one letter and one frequency pair.
 *
 * One demodulator feeds multiple slicers, each a subchannel.
 */

	        if (num_letters != 1) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, strlen(\"%s\") != 1\n",
				__FILE__, __LINE__, chan, just_letters);
		}

	        if (save_audio_config_p->achan[chan].num_freq != 1) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != 1\n",
				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq);
		}

	        if (save_audio_config_p->achan[chan].num_demod != save_audio_config_p->achan[chan].num_demod) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, num_freq(%d) != num_demod(%d)\n",
				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].num_freq, save_audio_config_p->achan[chan].num_demod);
		}
	  

	        struct demodulator_state_s *D;
	        D = &demodulator_state[chan][0];

		/* I'm not happy about putting this hack here. */
		/* This belongs in demod_afsk_init but it doesn't have access to the audio config. */

	        save_audio_config_p->achan[chan].num_demod = 1;
	        save_audio_config_p->achan[chan].num_subchan = MAX_SUBCHANS;
     
	        demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate, 
			save_audio_config_p->achan[chan].baud,
			save_audio_config_p->achan[chan].mark_freq, 
	                save_audio_config_p->achan[chan].space_freq,
			save_audio_config_p->achan[chan].profiles[0],
			D);

		/* I'm not happy about putting this hack here. */
		/* should pass in as a parameter rather than adding on later. */

		D->num_slicers = MAX_SUBCHANS;

	        /* For siginal level reporting, we want a longer term view. */

	        D->quick_attack = D->agc_fast_attack * 0.2;
	        D->sluggish_decay = D->agc_slow_decay * 0.2;
	      }	
	      else {
	        int d;
/*
 * One letter.
 * Can be combined with multiple frequencies.
 */

	        if (num_letters != 1) {
		  text_color_set(DW_COLOR_ERROR);
		  dw_printf ("INTERNAL ERROR, %s:%d, chan=%d, strlen(\"%s\") != 1\n",
				__FILE__, __LINE__, chan, save_audio_config_p->achan[chan].profiles);
		}

	        save_audio_config_p->achan[chan].num_demod = save_audio_config_p->achan[chan].num_freq;
	        save_audio_config_p->achan[chan].num_subchan = save_audio_config_p->achan[chan].num_freq;

	        for (d = 0; d < save_audio_config_p->achan[chan].num_freq; d++) {

	          int mark, space, k;
	          assert (d >= 0 && d < MAX_SUBCHANS);

	          struct demodulator_state_s *D;
	          D = &demodulator_state[chan][d];

	          profile = save_audio_config_p->achan[chan].profiles[0];

	          k = d * save_audio_config_p->achan[chan].offset - ((save_audio_config_p->achan[chan].num_freq - 1) * save_audio_config_p->achan[chan].offset) / 2;
	          mark = save_audio_config_p->achan[chan].mark_freq + k;
	          space = save_audio_config_p->achan[chan].space_freq + k;

	          if (save_audio_config_p->achan[chan].num_freq != 1) {
	            text_color_set(DW_COLOR_DEBUG);
	            dw_printf ("        %d.%d: %c %d & %d\n", chan, d, profile, mark, space);
	          }
      
	          demod_afsk_init (save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec / save_audio_config_p->achan[chan].decimate, 
			save_audio_config_p->achan[chan].baud,
			mark, space,
			profile,
			D);

	          /* For siginal level reporting, we want a longer term view. */

	          D->quick_attack = D->agc_fast_attack * 0.2;
	          D->sluggish_decay = D->agc_slow_decay * 0.2;

	        } 	  /* for each freq pair */
	      }	
	      break;

//TODO: how about MODEM_OFF case?

	    case MODEM_BASEBAND:
	    case MODEM_SCRAMBLE:
	    default:	/* Not AFSK */
	      {

	      if (strcmp(save_audio_config_p->achan[chan].profiles, "") == 0) {

		/* Apply default if not set earlier. */
		/* Not sure if it should be on for ARM too. */
		/* Need to take a look at CPU usage and performance difference. */

#ifndef __arm__
	        strcpy (save_audio_config_p->achan[chan].profiles, "+");
#endif
	      }

	      text_color_set(DW_COLOR_DEBUG);
	      dw_printf ("Channel %d: %d baud, K9NG/G3RUH, %s, %d sample rate x %d",
		    chan, save_audio_config_p->achan[chan].baud, 
		    save_audio_config_p->achan[chan].profiles,
		    save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, UPSAMPLE);
	      if (save_audio_config_p->achan[chan].dtmf_decode != DTMF_DECODE_OFF) 
	        dw_printf (", DTMF decoder enabled");
	      dw_printf (".\n");
	      
	      struct demodulator_state_s *D;
	      D = &demodulator_state[chan][0];	// first subchannel

	      save_audio_config_p->achan[chan].num_subchan = 1;
	      save_audio_config_p->achan[chan].num_demod = 1;		

	      if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {

		/* I'm not happy about putting this hack here. */
		/* This belongs in demod_9600_init but it doesn't have access to the audio config. */

	        save_audio_config_p->achan[chan].num_demod = 1;
	        save_audio_config_p->achan[chan].num_subchan = MAX_SUBCHANS;
     	      }
	        
	      demod_9600_init (UPSAMPLE * save_audio_config_p->adev[ACHAN2ADEV(chan)].samples_per_sec, save_audio_config_p->achan[chan].baud, D);

	      if (strchr(save_audio_config_p->achan[chan].profiles, '+') != NULL) {

		/* I'm not happy about putting this hack here. */
		/* should pass in as a parameter rather than adding on later. */

		D->num_slicers = MAX_SUBCHANS;
	      }

	      /* For siginal level reporting, we want a longer term view. */

	      D->quick_attack = D->agc_fast_attack * 0.2;
	      D->sluggish_decay = D->agc_slow_decay * 0.2;
	      }
	      break;

	  }  /* switch on modulation type. */
    
	 }  /* if channel number is valid */

	}  /* for chan ... */


        return (0);

} /* end demod_init */
Exemplo n.º 2
0
static void xmit_ax25_frames (int c, int p, packet_t pp)
{

  	unsigned char fbuf[AX25_MAX_PACKET_LEN+2];
    	int flen;
	char stemp[1024];	/* max size needed? */
	int info_len;
	unsigned char *pinfo;
	int pre_flags, post_flags;
	int num_bits;		/* Total number of bits in transmission */
				/* including all flags and bit stuffing. */
	int duration;		/* Transmission time in milliseconds. */
	int already;
	int wait_more;

	int maxframe;		/* Maximum number of frames for one transmission. */
	int numframe;		/* Number of frames sent during this transmission. */

/*
 * These are for timing of a transmission.
 * All are in usual unix time (seconds since 1/1/1970) but higher resolution
 */
	double time_ptt;	/* Time when PTT is turned on. */
	double time_now;	/* Current time. */


	int nb;

	maxframe = (p == TQ_PRIO_0_HI) ? 1 : 7;


/*
 * Print trasmitted packet.  Prefix by channel and priority.
 * Do this before we get into the time critical part.
 */
	ax25_format_addrs (pp, stemp);
	info_len = ax25_get_info (pp, &pinfo);
	text_color_set(DW_COLOR_XMIT);
	dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
	dw_printf ("%s", stemp);			/* stations followed by : */
	ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
	dw_printf ("\n");
	(void)ax25_check_addresses (pp);

/* Optional hex dump of packet. */

	if (g_debug_xmit_packet) {

	  text_color_set(DW_COLOR_DEBUG);
	  dw_printf ("------\n");
	  ax25_hex_dump (pp);
    	  dw_printf ("------\n");
	}

/* 
 * Turn on transmitter.
 * Start sending leading flag bytes.
 */
	time_ptt = dtime_now ();

#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	dw_printf ("xmit_thread: Turn on PTT now for channel %d. speed = %d\n", c, xmit_bits_per_sec[c]);
#endif
	ptt_set (OCTYPE_PTT, c, 1);

	pre_flags = MS_TO_BITS(xmit_txdelay[c] * 10, c) / 8;
	num_bits =  hdlc_send_flags (c, pre_flags, 0);
#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	dw_printf ("xmit_thread: txdelay=%d [*10], pre_flags=%d, num_bits=%d\n", xmit_txdelay[c], pre_flags, num_bits);
#endif


/*
 * Transmit the frame.
 */	
	flen = ax25_pack (pp, fbuf);
	assert (flen >= 1 && flen <= sizeof(fbuf));
	nb = hdlc_send_frame (c, fbuf, flen);
	num_bits += nb;
	numframe = 1;
#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	dw_printf ("xmit_thread: flen=%d, nb=%d, num_bits=%d, numframe=%d\n", flen, nb, num_bits, numframe);
#endif
	ax25_delete (pp);

/*
 * Additional packets if available and not exceeding max.
 */

	while (numframe < maxframe && tq_count (c,p) > 0) {

	  pp = tq_remove (c, p);
#if DEBUG
	 text_color_set(DW_COLOR_DEBUG);
	 dw_printf ("xmit_thread: tq_remove(chan=%d, prio=%d) returned %p\n", c, p, pp);
#endif
	 ax25_format_addrs (pp, stemp);
	 info_len = ax25_get_info (pp, &pinfo);
	 text_color_set(DW_COLOR_XMIT);
	 dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');
	 dw_printf ("%s", stemp);			/* stations followed by : */
	 ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
	 dw_printf ("\n");
	 (void)ax25_check_addresses (pp);

	 if (g_debug_xmit_packet) {
	    text_color_set(DW_COLOR_DEBUG);
	    dw_printf ("------\n");
	    ax25_hex_dump (pp);
    	    dw_printf ("------\n");
	  }

/*
 * Transmit the frame.
 */		
	  flen = ax25_pack (pp, fbuf);
	  assert (flen >= 1 && flen <= sizeof(fbuf));
	  nb = hdlc_send_frame (c, fbuf, flen);
	  num_bits += nb;
	  numframe++;
#if DEBUG
	  text_color_set(DW_COLOR_DEBUG);
	  dw_printf ("xmit_thread: flen=%d, nb=%d, num_bits=%d, numframe=%d\n", flen, nb, num_bits, numframe);
#endif
	  ax25_delete (pp);
	}

/* 
 * Need TXTAIL because we don't know exactly when the sound is done.
 */

	post_flags = MS_TO_BITS(xmit_txtail[c] * 10, c) / 8;
	nb = hdlc_send_flags (c, post_flags, 1);
	num_bits += nb;
#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	dw_printf ("xmit_thread: txtail=%d [*10], post_flags=%d, nb=%d, num_bits=%d\n", xmit_txtail[c], post_flags, nb, num_bits);
#endif


/* 
 * While demodulating is CPU intensive, generating the tones is not.
 * Example: on the RPi, with 50% of the CPU taken with two receive
 * channels, a transmission of more than a second is generated in
 * about 40 mS of elapsed real time.
 */

	audio_wait(ACHAN2ADEV(c));		

/* 
 * Ideally we should be here just about the time when the audio is ending.
 * However, the innards of "audio_wait" are not satisfactory in all cases.
 *
 * Calculate how long the frame(s) should take in milliseconds.
 */

	duration = BITS_TO_MS(num_bits, c);

/*
 * See how long it has been since PTT was turned on.
 * Wait additional time if necessary.
 */

	time_now = dtime_now();
	already = (int) ((time_now - time_ptt) * 1000.);
	wait_more = duration - already;

#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	dw_printf ("xmit_thread: xmit duration=%d, %d already elapsed since PTT, wait %d more\n", duration, already, wait_more );
#endif

	if (wait_more > 0) {
	  SLEEP_MS(wait_more);
	}
	else if (wait_more < -100) {

	  /* If we run over by 10 mSec or so, it's nothing to worry about. */
	  /* However, if PTT is still on about 1/10 sec after audio */
	  /* should be done, something is wrong. */

	  /* Looks like a bug with the RPi audio system. Never an issue with Ubuntu.  */
	  /* This runs over randomly sometimes. TODO:  investigate more fully sometime. */
#ifndef __arm__
	  text_color_set(DW_COLOR_ERROR);
	  dw_printf ("Transmit timing error: PTT is on %d mSec too long.\n", -wait_more);
#endif
	}

/*
 * Turn off transmitter.
 */
#if DEBUG
	text_color_set(DW_COLOR_DEBUG);
	time_now = dtime_now();
	dw_printf ("xmit_thread: Turn off PTT now. Actual time on was %d mS, vs. %d desired\n", (int) ((time_now - time_ptt) * 1000.), duration);
#endif
		
	ptt_set (OCTYPE_PTT, c, 0);

} /* end xmit_ax25_frames */
Exemplo n.º 3
0
static int wait_for_clear_channel (int channel, int nowait, int slottime, int persist)
{
	int r;
	int n;


	n = 0;

start_over_again:

	while (hdlc_rec_data_detect_any(channel)) {
	  SLEEP_MS(WAIT_CHECK_EVERY_MS);
	  n++;
	  if (n > (WAIT_TIMEOUT_MS / WAIT_CHECK_EVERY_MS)) {
	    return 0;
	  }
	}

//TODO1.2:  rethink dwait.

/*
 * Added in version 1.2 - for transceivers that can't
 * turn around fast enough when using squelch and VOX.
 */

	if (save_audio_config_p->achan[channel].dwait > 0) {
	  SLEEP_MS (save_audio_config_p->achan[channel].dwait * 10);
	}

	if (hdlc_rec_data_detect_any(channel)) {
	  goto start_over_again;
	}

	if ( ! nowait) {

	  while (1) {

	    SLEEP_MS (slottime * 10);

	    if (hdlc_rec_data_detect_any(channel)) {
	      goto start_over_again;
	    }

	    r = rand() & 0xff;
	    if (r <= persist) {
	      break;
 	    }	
	  }
	}

// TODO1.2

	while ( ! dw_mutex_try_lock(&(audio_out_dev_mutex[ACHAN2ADEV(channel)]))) {
	  SLEEP_MS(WAIT_CHECK_EVERY_MS);
	  n++;
	  if (n > (WAIT_TIMEOUT_MS / WAIT_CHECK_EVERY_MS)) {
	    return 0;
	  }
	}

	return 1;

} /* end wait_for_clear_channel */
Exemplo n.º 4
0
static void * xmit_thread (void *arg)
#endif
{
	int c = (int)(long)arg; // channel number.
	packet_t pp;
	int p;
	int ok;

/*
 * These are for timing of a transmission.
 * All are in usual unix time (seconds since 1/1/1970) but higher resolution
 */


	while (1) {

	  tq_wait_while_empty (c);
#if DEBUG
	  text_color_set(DW_COLOR_DEBUG);
	  dw_printf ("xmit_thread, channel %d: woke up\n", c);
#endif
	  
	  for (p=0; p<TQ_NUM_PRIO; p++) {

	      pp = tq_remove (c, p);
#if DEBUG
	      text_color_set(DW_COLOR_DEBUG);
	      dw_printf ("xmit_thread: tq_remove(chan=%d, prio=%d) returned %p\n", c, p, pp);
#endif
	      if (pp != NULL) {

/* 
 * Wait for the channel to be clear.
 * For the high priority queue, begin transmitting immediately.
 * For the low priority queue, wait a random amount of time, in hopes
 * of minimizing collisions.
 */
	        ok = wait_for_clear_channel (c, (p==TQ_PRIO_0_HI), xmit_slottime[c], xmit_persist[c]);

	        if (ok) {
/*
 * Channel is clear and we have lock on output device. 
 *
 * If destination is "SPEECH" send info part to speech synthesizer.
 * If destination is "MORSE" send as morse code.
 */
	          char dest[AX25_MAX_ADDR_LEN];
		  int ssid = 0;


	          if (ax25_is_aprs (pp)) { 

		    ax25_get_addr_no_ssid(pp, AX25_DESTINATION, dest);
		    ssid = ax25_get_ssid(pp, AX25_DESTINATION);
	 	  }
	 	  else {
		    strlcpy (dest, "", sizeof(dest));
	          }

		  if (strcmp(dest, "SPEECH") == 0) {
	            xmit_speech (c, pp);
	          }
		  else if (strcmp(dest, "MORSE") == 0) {

		    int wpm = ssid * 2;
		    if (wpm == 0) wpm = MORSE_DEFAULT_WPM;

		    // This is a bit of a hack so we don't respond too quickly for APRStt.
		    // It will be sent in high priority queue while a beacon wouldn't.  
		    // Add a little delay so user has time release PTT after sending #.
		    // This and default txdelay would give us a second.

		    if (p == TQ_PRIO_0_HI) {
	              //text_color_set(DW_COLOR_DEBUG);
		      //dw_printf ("APRStt morse xmit delay hack...\n");
		      SLEEP_MS (700);
		    }

	            xmit_morse (c, pp, wpm);
	          }
	          else {
	            xmit_ax25_frames (c, p, pp);
		  }

	          dw_mutex_unlock (&(audio_out_dev_mutex[ACHAN2ADEV(c)]));
	        }
	        else {
/*
 * Timeout waiting for clear channel.
 * Discard the packet.
 * Display with ERROR color rather than XMIT color.
 */
		  char stemp[1024];	/* max size needed? */
		  int info_len;
		  unsigned char *pinfo;


	          text_color_set(DW_COLOR_ERROR);
		  dw_printf ("Waited too long for clear channel.  Discarding packet below.\n");

	          ax25_format_addrs (pp, stemp);

	          info_len = ax25_get_info (pp, &pinfo);

	          text_color_set(DW_COLOR_INFO);
	          dw_printf ("[%d%c] ", c, p==TQ_PRIO_0_HI ? 'H' : 'L');

	          dw_printf ("%s", stemp);			/* stations followed by : */
	          ax25_safe_print ((char *)pinfo, info_len, ! ax25_is_aprs(pp));
	          dw_printf ("\n");
		  ax25_delete (pp);

		} /* wait for clear channel. */
	    } /* for high priority then low priority */
	  }
	}

	return 0;	/* unreachable but quiet the warning. */

} /* end xmit_thread */