Logo Search packages:      
Sourcecode: acfax version File versions  Download package

sblaster.c

/*
    ACfax - Fax reception with X11-interface for amateur radio
    Copyright (C) 1995-1998 Andreas Czechanowski, DL4SDC

    This program 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.

    This program 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 this program; if not, write to the Free Software Foundation,
    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    andreas.czechanowski@ins.uni-stuttgart.de
*/
    
/*
 * sblaster.c - this file should contain all hardware-dependent functions
 *          on top of mod_demod.c for the SoundBlaster under linux.
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#include "mod_demod.h"
#include "sblaster.h"
#include <unistd.h>

static int afd, mfd;
static int blsize;
static int decsize;
static int amode;
static int aspeed;
static int afilter;
static int adevi;
static int amaxval;
int   rx_level;
int   dspfd;
char  *smplptr;
char  *decptr;

/* this constants should go to a configuration file in future.... */
unsigned fm_smplf = (unsigned)(FM_SMPLF * 65536);
unsigned am_smplf = (unsigned)(AM_SMPLF * 65536);

static void set_speed(int);

/* initialize the interface: open it, set it to mono, 8bits per sample,
 * and allocate space for the input- and output-buffers of the modem-
 * routines. return a pointer to the decoded data and the number of
 * values per call to do_receive.
 */
void interface_init(char **dta_return, int *cnt_return)
{
  int speed = 8000;
  int bits = 8;
  int stereo = 0;
  int linevol = 80;
  int mastervol = 55;
#ifdef SBL_16
  int recsrc = SOUND_MASK_LINE;
#endif
  static int inited = 0;

  /* already initialized ? return values although... */
  if (inited) {
    *dta_return = decptr;
    *cnt_return = decsize;
    return;
  }

  fprintf(stderr, "opening and initializing sound-interface\n");
  if ((afd = open(DSPDEV, O_RDWR, 0666)) < 0) {
    perror("open_dsp");
    exit(1);
  }
  dspfd = afd;
#ifdef SBL_16
  if ((mfd = open(MIXDEV, O_RDWR, 0666)) < 0) {
    perror("open_mixer");
    exit(1);
  }
  linevol &= 0xff;
  linevol += linevol << 8;
  mastervol &= 0xff;
  mastervol += mastervol << 8;
  if ((ioctl(mfd, SOUND_MIXER_WRITE_LINE, &linevol) < 0) ||
      (ioctl(mfd, SOUND_MIXER_WRITE_VOLUME, &mastervol) < 0) ||
      (ioctl(mfd, SOUND_MIXER_WRITE_RECSRC, &recsrc) < 0)) {
    perror("mixer_ioctl");
    exit(1);
  }
  close (mfd);
#endif
  if ((ioctl(afd, SNDCTL_DSP_SPEED, &speed) < 0) ||
      (ioctl(afd, SNDCTL_DSP_SAMPLESIZE, &bits) < 0) ||
      (ioctl(afd, SNDCTL_DSP_STEREO, &stereo) < 0) ||
      (ioctl(afd, SNDCTL_DSP_GETBLKSIZE, &blsize) < 0)) {
    perror("dsp_ioctl");
    exit(1);
  }
  decsize = blsize / 2;
  /* set up defaults for the modem */
  amode = MOD_FM;
  afilter = FIL_MIDL;
  adevi = 400;
  set_modem_param (afilter, amaxval, adevi);
  if (!(decptr = malloc((decsize))) ||
      !(smplptr = malloc(blsize))) {
    perror("setup_buffers");
    exit(1);
  }
  printf("block size is %d bytes\n", blsize);
  *dta_return = decptr;
  *cnt_return = decsize;

  inited = -1;
}

/* stop the interface, don't let it overrun by no more reading/writing */
void interface_stop(void)
{
  if (ioctl(afd, SNDCTL_DSP_RESET, NULL) < 0) {
    perror("interface_stop: cannot reset pcm");
  }
}

/* set up the desired mode, the decoded value range and the deviation for
 * FM. Return the number of demodulated sample-points per second (for APT)
 */
void setup_mode(int mode, int maxval, int devi, unsigned *smplf)
{
  char *dummy1;
  int dummy2;
  int id;

  /* be sure interface is initialized */
  interface_init(&dummy1, &dummy2);

  if ((id = (mode & MOD_BITS))) {
    switch (id) {
      case MOD_FM:
      set_speed(8000);
      break;
      case MOD_AM:
      set_speed(9600);
      break;
    }
    amode = id;
    fprintf(stderr, "setting demodulator mode to 0x%04x\n", amode);
  }
  /* range checking for afilter, adevi and amaxval is done in mod_demod.c */
  if ((id = mode & FIL_MASK)) {
    afilter = id;
    fprintf(stderr, "setting filter selection to 0x%04x\n", afilter);
  }
  if (devi) {
    adevi = devi;
    fprintf(stderr, "setting deviation to %d\n", adevi);
  }
  if (maxval) {
    amaxval = maxval;
    fprintf(stderr, "setting max.demod.value to %d\n", amaxval);
  }
  if ((mode & FIL_MASK) | (devi) | (maxval)) {
    set_modem_param (afilter, amaxval, adevi);
  }
  /* return the number of samples per second (16 bits int, 16 bits frac) */
  if (smplf) {
    switch(amode) {
      case MOD_AM:
      *smplf = am_smplf;
      break;
      case MOD_FM:
      *smplf = fm_smplf;
      break;
    }
  }
}

/* receive the signal, demodulate it, ant put the demodulated values
 * into an array starting at decptr with decsize bytes. (1 byte / value)
 */
void do_receive(void)
{
  int cnt;
  int hi, lo;
  int i, sample;

  cnt = read(afd, smplptr, blsize);
  if (cnt <= 0) {
    perror("do_receive");
    exit(1);
  }
  fputc('<', stderr);
  switch(amode) {
    case MOD_AM:
      am_demod(smplptr, cnt, decptr);
      break;
    case MOD_FM:
      fm_demod(smplptr, cnt, decptr);
      break;
    default:
      return;
  }
  /* determine the signal level and put it into rx_level (0..255) */
  lo = 255;
  hi = 0;
  for (i = 0; i < blsize / 4; i++)
  {
    sample = smplptr[i] & 0xff;
    if (sample > hi) hi = sample;
    if (sample < lo) lo = sample;
  }
  rx_level = hi - lo;
}

/* modulate the sample-values from decptr into smplptr, and transmit them
 * over the interface. The number of input-values is always decsize.
 */
void do_transmit(void)
{
  int cnt;

  switch(amode) {
    case MOD_FM:
      fm_modulate(decptr, decsize, smplptr);
    case MOD_AM:
      am_modulate(decptr, decsize, smplptr);
    default:
      return;
  }
  cnt = write(afd, smplptr, blsize);
  if (cnt <= 0) {
    perror("do_transmit");
    exit(1);
  }
  fputc('>', stderr);
}

/* check for signal level, return a value between 0 and 256 */
int signal_level(void)
{
  char buf[512];
  int i, p, lo, hi;
  
  if (read(afd, buf, 512) != 512) {
    perror("signal_level: cannot get samples");
  }
  if (ioctl(afd, SNDCTL_DSP_SYNC, NULL) < 0) {
    perror("signal_level: cannot reset pcm");
  }
  lo = 255;
  hi = 0;
  for (i=0; i<512; i++) {
    p = buf[i]&0xff;
    if (p > hi) hi = p;
    if (p < lo) lo = p;
  }
  return (hi-lo);
}

/* just assign new value to either the AM or FM sample-frequency,
   and hold values permanently until next change
*/
void tune_frequency(unsigned freq)
{
  switch(amode) {
    case MOD_FM:
      fm_smplf = freq;
    case MOD_AM:
      am_smplf = freq;
    default:
      return;
  }
}

/* set a new sample-rate for the DSP-device. We need to restart input
   in order to do so, because Linux does not update the SB-registers
   when sending the command, but only on start of input/output
*/
static void set_speed(int speed)
{
  if (ioctl(afd, SNDCTL_DSP_SPEED, &speed) < 0) {
    perror("set_speed: cannot set new sample-rate");
  }
  fprintf(stderr,"speed set to %d\n", speed);
  if (ioctl(afd, SNDCTL_DSP_SYNC, NULL) < 0) {
    perror("set_speed: cannot reset pcm");
  }
  aspeed = speed;
}

Generated by  Doxygen 1.6.0   Back to index