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

cfgadapt.c

/*****************************************************************************/

/*
 *    cfgadapt.c  --  Baycom USB modem Anchorchip/Xilinx firmware loading.
 *
 *    Copyright (C) 1999-2001
 *          Thomas Sailer (t.sailer@alumni.ethz.ch)
 *
 *    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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Please note that the GPL allows you to use the driver, NOT the radio.
 *  In order to use the radio, you need a license from the communications
 *  authority of your country.
 *
 *
 *  History:
 *   0.1  26.05.99  Created
 *
 */

/*****************************************************************************/

#define _GNU_SOURCE
#include <sys/types.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <math.h>

#include "trx.h"
#include "usbdrv.h"
#include "fpga/fsk_fpga.h"
#include "fpga/fsk_firmware.h"
#include "fpga/afsk_firmware.h"
#include "fpga/sample_firmware.h"
#include "firmware/reset2firmware.h"
#include "firmware/dl2firmware.h"
#include "firmware/bscanfirmware.h"
#include "firmware/fskfirmware.h"
#include "firmware/afskfirmware.h"

#if defined(WIN32) || defined(USERMODEDRV)
#include "firmware/audio2firmware.h"
#define audiofirmware audio2firmware
#define SAMPLERATE AUDIOSAMPLINGRATE
#else
#include "firmware/audiofirmware.h"
#define SAMPLERATE state->cfg.adapt.samplerate
#endif

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

static void printconfig(const struct trx_thread_state *state)
{
#if defined(WIN32)
      lprintf(1, "configuration for serial \"%s\"\n"
            "  adapter: mode %s, fclk %lu Hz, bitrate %lu/%lu, loopback %u, %spttmute, filtmode %lu gain %f\n"
            "  modem disconnect: output 0x%02lx, direction 0x%02lx, rxc %u, txc %u, txd %u\n",
            state->serial,
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_fsk) ? "fsk" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_external) ? "external" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_afsk) ? "afsk" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_audio) ? "audio" : "off", 
            state->cfg.adapt.fclk, state->cfg.adapt.bitraterx, state->cfg.adapt.bitratetx,
            state->cfg.adapt.loopback, state->cfg.adapt.pttmute ? "" : "no ",
            state->cfg.adapt.filtmode, state->cfg.adapt.gain,
            state->cfg.mdisc.output, state->cfg.mdisc.direction,
            state->cfg.mdisc.rxc, state->cfg.mdisc.txc, state->cfg.mdisc.txd);
#else
      lprintf(1, "configuration for serial \"%s\"\n"
            "  adapter: mode %s, fclk %lu Hz, bitrate %lu/%lu, loopback %u, %spttmute, filtmode %lu gain %f\n"
            "  channel access: txdelay %lums, slottime %lums, ppersistence %lu txtail %lums, %sduplex\n"
            "  interface: ifname %s, hwaddr %s, ipaddr %u.%u.%u.%u, netmask %u.%u.%u.%u, broadcast %u.%u.%u.%u\n"
            "  modem disconnect: output 0x%02lx, direction 0x%02lx, rxc %u, txc %u, txd %u\n",
            state->serial,
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_fsk) ? "fsk" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_external) ? "external" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_afsk) ? "afsk" :
            (state->cfg.adapt.mode == trxapi_baycomusb_mode_audio) ? "audio" : "off", 
            state->cfg.adapt.fclk, state->cfg.adapt.bitraterx, state->cfg.adapt.bitratetx,
            state->cfg.adapt.loopback, state->cfg.adapt.pttmute ? "" : "no ",
            state->cfg.adapt.filtmode, state->cfg.adapt.gain,
            state->cfg.chacc.txdelay, state->cfg.chacc.slottime, state->cfg.chacc.ppersistence,
            state->cfg.chacc.txtail, state->cfg.chacc.fullduplex ? "full" : "half",
            state->cfg.intf.ifname, state->cfg.intf.hwaddr,
            state->cfg.intf.ipaddr[0], state->cfg.intf.ipaddr[1], state->cfg.intf.ipaddr[2], state->cfg.intf.ipaddr[3],
            state->cfg.intf.netmask[0], state->cfg.intf.netmask[1], state->cfg.intf.netmask[2], state->cfg.intf.netmask[3],
            state->cfg.intf.broadcast[0], state->cfg.intf.broadcast[1], state->cfg.intf.broadcast[2], state->cfg.intf.broadcast[3],
            state->cfg.mdisc.output, state->cfg.mdisc.direction,
            state->cfg.mdisc.rxc, state->cfg.mdisc.txc, state->cfg.mdisc.txd);
#endif
}

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

static unsigned int readconfigrom(const unsigned char *firmware, const unsigned long rom[16])
{
        unsigned ret = 0, mask = 1, i, j;

        for (i = 0; i < 16; i++, mask <<= 1) {
                j = rom[i];
                if (!(firmware[j >> 3] & (1 << (j & 7))))
                        ret |= mask;
        }
        return ret & 0xffff;
}

/* warning: if used, don't use CRC bitstream, there's currently no code to recalc the CRC */
static void writeconfigrom(unsigned char *firmware, const unsigned long rom[16], unsigned val)
{
        unsigned mask = 1, i, j;

        for (i = 0; i < 16; i++, mask <<= 1) {
                j = rom[i];
                if (val & mask) 
                        firmware[j >> 3] &= ~(1 << (j & 7));
                else
                        firmware[j >> 3] |= 1 << (j & 7);
        }
}

/* ---------------------------------------------------------------------- */
/*
 * Filter calc routines
 */

static const float filt_comp[32] = {
   -0.0000,   -0.0071,   -0.0144,   -0.0160,
   -0.0028,    0.0279,    0.0617,    0.0683,
    0.0208,   -0.0765,   -0.1732,   -0.1877,
   -0.0525,    0.2365,    0.5993,    0.9000,
    1.0122,    0.8857,    0.5741,    0.2060,
   -0.0825,   -0.2130,   -0.1919,   -0.0888,
    0.0138,    0.0649,    0.0606,    0.0281,
   -0.0021,   -0.0152,   -0.0139,   -0.0070
};

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

#define HAMMING(x) (0.54-0.46*cos(2*M_PI*(x)));

extern inline float hamming(float x)
{
        return 0.54-0.46*cos(2*M_PI*x);
}

extern inline float sinc(float x)
{
        if (x == 0)
                return 1;
        x *= M_PI;
        return sin(x)/x;
}

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

#if 0
static void filt_printfcoeff(const float coeff[32])
{
        int i;

        lprintf(3, "filter coefficients:");
        for (i = 0; i < 32; i++) {
                if (!(i & 7))
                        lprintf(3, "\n  ");
                lprintf(3, "%6.2f", coeff[i]);
        }
        lprintf(3, '\n');
}

static void filt_printicoeff(const int coeff[32])
{
        int i;

        lprintf(3, "filter coefficients:");
        for (i = 0; i < 32; i++) {
                if (!(i & 7))
                        lprintf(3, "\n  ");
                lprintf(3, "%5i", coeff[i]);
        }
        lprintf(3, '\n');
}
#endif

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

static void filt_genideal(float coeff[32])
{
        int i;

        for (i = 0; i < 32; i++)
                coeff[i] = hamming(i / 31.0) * sinc((i - 15.5) / 4.0);
}

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

static void filt_rom(const float coeff[32], unsigned rom[16])
{
        float max = 0.000001, s;
        int ocoeff[32];
        int i, j;

        /* scale filter values */
        for(i = 0; i < 4; i++) {
                for(s = 0, j = i; j < 32; j += 4)
                        s += fabs(coeff[j]);
                if (s > max)
                        max = s;
        }
        s = 126.0 / max;
        for(i = 0; i < 32; i++)
                ocoeff[i] = s * coeff[i];
        /* convert to internal ROM representation */
        memset(rom, 0, sizeof(rom[0])*16);
        for (i = 0; i < 8; i++)
                for (j = 0; j < 16; j++) {
                        if ((1 << i) & ocoeff[j])
                                rom[i] |= 1 << (((j + 1) & 3) | (j & 12));
                        if ((1 << i) & ocoeff[j+16])
                                rom[i+8] |= 1 << j;
                }
}

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

static int writecpucs(struct usbdevice *dev, unsigned char buf)
{
        int r;

        r = usb_control_msg(dev, 0x40, 0xa0, 0x7F92, 0, 1, &buf, 5000);
        if (r != 1) {
                lprintf(2, "ezusb: writecpucs(0x%02x) failed %d\n", buf, r);
                return -1;
        }
        return 0;
}

static int loadmem(struct usbdevice *dev, const unsigned char *fw, unsigned int len)
{
        unsigned addr, sz;
        int r;

        if (writecpucs(dev, 1))
                return -1;
        for (addr = 0; addr < len; addr += 64) {
                sz = len - addr;
                if (sz > 64)
                        sz = 64;
                r = usb_control_msg(dev, 0x40, 0xa0, addr, 0, sz, (void *)(fw+addr), 5000);
                if (r != sz) {
                        lprintf(2, "ezusb: code download(sz=%d,addr=0x%04x) returned %d\n", sz, addr, r);
                        return -1;
                }
        }
        return 0;
}

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

static int displaymem(struct usbdevice *dev)
{
        unsigned char buf[16];
        unsigned addr, u;
        int r;

        printf("EZUSB Memory contents:\n");
        for (addr = 0; addr < 0x2000; addr += 16) {
                r = usb_control_msg(dev, 0xc0, 0xa0, addr, 0, 16, buf, 5000);
                if (r != 16) {
                        lprintf(2, "ezusb: code upload(sz=%d,addr=0x%04x) returned %d\n", 16, addr, r);
                        return -1;
                }
                printf("%04x:", addr);
                for (u = 0; u < 16; u++)
                        printf(" %02x", buf[u]);
                printf("\n");
        }
        r = usb_control_msg(dev, 0xc0, 0xa0, 0x7F92, 0, 1, buf, 5000);
        if (r != 1) {
                lprintf(2, "ezusb: readcpucs returned %d\n", r);
                return -1;
        }
        printf("CPUCS: %02x\n", buf[0]);
        return 0;
}

static int displaycpucs(struct usbdevice *dev)
{
        unsigned char buf;
        int r;

        r = usb_control_msg(dev, 0xc0, 0xa0, 0x7F92, 0, 1, &buf, 5000);
        if (r != 1) {
                lprintf(2, "ezusb: readcpucs returned %d\n", r);
                return -1;
        }
        printf("CPUCS: %02x\n", buf);
        return 0;
}

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

int adapter_reset(struct usbdevice *dev)
{
        /* first download the loader firmware to the AnchorChips core */
      lprintf(30, "baycomusb: downloading reset2 firmware\n");
        if (loadmem(dev, reset2firmware, sizeof(reset2firmware)) ||
            /* start AnchorChips core */
            writecpucs(dev, 0))
                return -1;
        return 0;
}

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

struct anfwstat {
      unsigned char errcode;
      unsigned char errval;
      unsigned count;
};

static int anchor_fw_stat(struct usbdevice *dev, struct anfwstat *st)
{
      unsigned char buf[4];
      int r;

      r = usb_control_msg(dev, 0xc0, 0xb1, 0, 0, 4, buf, 5000);
      if (r != 4) {
            lprintf(2, "usb_control_msg(0xb1) error %s\n", strerror(errno));
            return -1;
      }
      lprintf(4, "ezusb: anchorstat: errcode 0x%02x  errval 0x%02x  cfgcntr 0x%04x\n",
            buf[0], buf[1], buf[2] | (buf[3] << 8));
      st->errcode = buf[0];
      st->errval = buf[1];
      st->count = buf[2] | (buf[3] << 8);
      return 0;
}

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

static unsigned int prepare_fsk(struct trx_thread_state *state, unsigned char *fpga, unsigned char *fw)
{
        float fcoeff[32];
        unsigned int filtrom[16];
        unsigned int dividerrx, dividertx;
        unsigned int i;

      /* copy FPGA firmware */
        memcpy(fpga, fsk_firmware, FPGA_CONFIGSIZE);
      memcpy(fw, fskfirmware, sizeof(fskfirmware));
      strncpy(&fw[0xf0], state->serial, 0x10);
      fw[0xe6] = (state->cfg.adapt.mode == trxapi_baycomusb_mode_external);
      fw[0xe7] = state->cfg.adapt.pttmute;
        /* calculate the divider */
        dividerrx = (state->cfg.adapt.fclk + 8 * state->cfg.adapt.bitraterx) / (16 * state->cfg.adapt.bitraterx);
        if (dividerrx < 1)
                dividerrx = 1;
        if (dividerrx > 1024)
                dividerrx = 1024;
        state->cfg.adapt.bitraterx = (state->cfg.adapt.fclk + 8 * dividerrx) / (16 * dividerrx);
        dividertx = (state->cfg.adapt.fclk + 8 * state->cfg.adapt.bitratetx) / (16 * state->cfg.adapt.bitratetx);
        if (dividertx < 1)
                dividertx = 1;
        if (dividertx > 1024)
                dividertx = 1024;
        state->cfg.adapt.bitratetx = (state->cfg.adapt.fclk + 8 * dividertx) / (16 * dividertx);
      fw[0xe0] = state->cfg.adapt.bitratetx;
      fw[0xe1] = state->cfg.adapt.bitratetx >> 8;
      fw[0xe2] = state->cfg.adapt.bitratetx >> 16;
      fw[0xe3] = state->cfg.adapt.bitraterx;
      fw[0xe4] = state->cfg.adapt.bitraterx >> 8;
      fw[0xe5] = state->cfg.adapt.bitraterx >> 16;
      /* patch configuration ROM's */
#if 0
        if (state->cfg.adapt.intclk)
                writeconfigrom(fpga, fsk_roms+FSK_ROM_CLKSELROM, 0);
#endif
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX0, 1 << ((dividerrx-1) & 0xf));
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX1, 1 << (((dividerrx-1) >> 4) & 0xf));
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX2, 0x1000 << (((dividerrx-1) >> 8) & 0x3));
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX0, 1 << ((dividertx-1) & 0xf));
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX1, 1 << (((dividertx-1) >> 4) & 0xf));
      writeconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX2, 0x1000 << (((dividertx-1) >> 8) & 0x3));
      if (state->cfg.adapt.mode == trxapi_baycomusb_mode_external) {
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMID, 0xcccc);
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIC, 0x0c0c); /* RxC: rising edge */
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOC, 0x3030); /* TxC: falling edge */
                /* switch off scrambler and differential */
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOE, 0xaaaa);
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOS, 0xaaaa);
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIE, 0xaaaa);
                writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIS, 0xaaaa);
            /* switch on data output to MDISC */
            writeconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMTXD, 0xcccc);
      } else {
            if (state->cfg.mdisc.rxc)
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMRXC, 0xcccc);
            if (state->cfg.mdisc.txc)
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMTXC, 0xcccc);
            if (state->cfg.mdisc.txd)
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMTXD, 0xcccc);
            switch (state->cfg.adapt.loopback) {
            default:
                  break;

            case trxapi_baycomusb_loopback_scrambler:
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMID, 0xf0f0);
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIC, 0xff00); /* modem output clock */
                  break;
                  
            case trxapi_baycomusb_loopback_modem:
                  writeconfigrom(fpga, fsk_roms+FSK_ROM_MDMINROM, 0xcccc);
                  break;
            }
        }
        if (state->cfg.adapt.filtmode == 1) {
                filt_rom(filt_comp, filtrom);
                for (i = 0; i < 16; i++)
                        writeconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_0+16*i, filtrom[i]);
        } else if (state->cfg.adapt.filtmode == 2) {
                filt_genideal(fcoeff);
                filt_rom(fcoeff, filtrom);
                for (i = 0; i < 16; i++)
                        writeconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_0+16*i, filtrom[i]);
        }
        /* print configuration ROM's (mainly a debugging action) */
        lprintf(2, "config: coeff: %04x %04x %04x %04x %04x %04x %04x %04x\n"
                "config: coeff: %04x %04x %04x %04x %04x %04x %04x %04x\n",
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_0),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_1),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_2),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_3),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_4),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_5),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_6),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM0_R_7),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_0),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_1),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_2),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_3),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_4),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_5),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_6),
                readconfigrom(fpga, fsk_roms+FSK_ROM_CROM1_R_7));
#if 0
        lprintf(2, "config: ClkSel: %04x  PTT mute: %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_CLKSELROM),
                readconfigrom(fpga, fsk_roms+FSK_ROM_PTTMUTEROM));
        lprintf(2, "config: DCD: %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMDCD));
#endif
        lprintf(2, "config: DivRx: %04x %04x %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX0),
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX1),
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMRX2));
        lprintf(2, "config: DivTx: %04x %04x %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX0),
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX1),
                readconfigrom(fpga, fsk_roms+FSK_ROM_DIVROMTX2));
        lprintf(2, "config: IClk: %04x ID: %04x IE: %04x IS: %04x\n",
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIC),
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMID),
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIE),
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMIS));
        lprintf(2, "config: OClk: %04x OE: %04x OS: %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOC),
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOE),
                readconfigrom(fpga, fsk_roms+FSK_ROM_SWROMOS));
        lprintf(2, "config: MDISC: RxC: %04x TxC: %04x TxD: %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMRXC),
                readconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMTXC),
                readconfigrom(fpga, fsk_roms+FSK_ROM_MDISCROMTXD));
        lprintf(2, "config: Modem: in: %04x\n", 
                readconfigrom(fpga, fsk_roms+FSK_ROM_MDMINROM));
      return sizeof(fskfirmware);
}

static unsigned int prepare_afsk(struct trx_thread_state *state, unsigned char *fpga, unsigned char *fw)
{
        /* copy FPGA firmware */
        memcpy(fpga, afsk_firmware, FPGA_CONFIGSIZE);
      memcpy(fw, afskfirmware, sizeof(afskfirmware));
      strncpy(&fw[0xf0], state->serial, 0x10);
      fw[0xe0] = (1200) & 0xff;
      fw[0xe1] = (1200 >> 8) & 0xff;
      fw[0xe2] = (1200 >> 16) & 0xff;
      fw[0xe3] = (1200) & 0xff;
      fw[0xe4] = (1200 >> 8) & 0xff;
      fw[0xe5] = (1200 >> 16) & 0xff;
      fw[0xe6] = 0;
      fw[0xe7] = state->cfg.adapt.pttmute;
        /* patch configuration ROM's */
      /* only swromie/swromoe could be patched, for differential decoding */
        /* print configuration ROM's (mainly a debugging action) */
        lprintf(2, "config: IE: %04x OE: %04x\n",
                readconfigrom(fpga, afsk_roms+AFSK_ROM_SWROMIE),
                readconfigrom(fpga, afsk_roms+AFSK_ROM_SWROMOE));
      return sizeof(afskfirmware);
}

static unsigned int prepare_audio(struct trx_thread_state *state, unsigned char *fpga, unsigned char *fw)
{
        unsigned divider;
        unsigned int i;

      /* copy FPGA firmware */
        memcpy(fpga, sample_firmware, FPGA_CONFIGSIZE);
      memcpy(fw, audiofirmware, sizeof(audiofirmware));
      strncpy(&fw[0xf0], state->serial, 0x10);
      /* calculate the true bitrate (aka samplerate) */
      state->cfg.adapt.samplerate = (SAMPLERATE + 500) / 1000 * 1000;
      if (state->cfg.adapt.samplerate < 8000 && state->cfg.adapt.samplerate != 2000 && state->cfg.adapt.samplerate != 3000)
                state->cfg.adapt.samplerate = 8000;
        if (state->cfg.adapt.samplerate > 24000)
                state->cfg.adapt.samplerate = 24000;
      divider = (24000000 + state->cfg.adapt.samplerate/2) / state->cfg.adapt.samplerate;
      fw[0xe0] = state->cfg.adapt.samplerate / 1000;
        /* calculate the gain */
        i = (state->cfg.adapt.gain * (1 << 24)) / divider;
        if (i > 65535)
                i = 65535;
        if (i < 1)
                i = 1;
        /* patch configuration ROM's */
        writeconfigrom(fpga, sample_roms+SAMPLE_ROM_MULROM, i);
        /* print configuration ROM's (mainly a debugging action) */
        lprintf(2, "config: InputGain: %04x\n",
                readconfigrom(fpga, sample_roms+SAMPLE_ROM_MULROM));
      return sizeof(audiofirmware);
}

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

static int adapter_download(struct trx_thread_state *state)
{
      unsigned char stat[5];
      unsigned u, ln;
      unsigned char fpga[FPGA_CONFIGSIZE], firmware[8192];
      unsigned int fwlen;
      int i;

      switch (state->cfg.adapt.mode) {
      case trxapi_baycomusb_mode_fsk:
      case trxapi_baycomusb_mode_external:
            fwlen = prepare_fsk(state, fpga, firmware);
            break;

      case trxapi_baycomusb_mode_afsk:
            fwlen = prepare_afsk(state, fpga, firmware);
            break;

      case trxapi_baycomusb_mode_audio:
            fwlen = prepare_audio(state, fpga, firmware);
            break;

      default:
            return -1;
      }
      printconfig(state);
      /* claim interface 0 */
      if (usb_claiminterface(state->usbdev, 0)) {
            lprintf(2, "FPGAdownload: cannot claim interface 0\n");
            return -1;
      }
      /* set interface 0 altsetting 1, to enable the bulk ep's */
      if (usb_setinterface(state->usbdev, 0, 1)) {
            lprintf(2, "FPGAdownload: cannot set interface 0 altsetting 1\n");
            return -1;
      }
      if (usb_resetep(state->usbdev, 0x81)) {
            lprintf(2, "FPGAdownload: cannot reset ep1 in\n");
            //return -1;
      }
      if (usb_resetep(state->usbdev, 0x02)) {
            lprintf(2, "FPGAdownload: cannot reset ep2 out\n");
            //return -1;
      }
#if 1
      i = usb_control_msg(state->usbdev, 0xc0, 0xb1, 0, 0, 4, stat, 5000);
      if (i != 4)
            lprintf(2, "usb_control_msg(0xc0, 0xb1) failure (%d)\n", i);
      else
            lprintf(3, "FPGAdownload: stat: 0x%02x 0x%02x 0x%02x 0x%02x\n", stat[0], stat[1], stat[2], stat[3]);
#endif
      /* download FPGA firmware using bulk transfers */
      for (;;) {
#if 1
            i = usb_bulk_msg(state->usbdev, 0x81, sizeof(stat), stat, 5000);
#else
            i = usb_control_msg(state->usbdev, 0xc0, 0xb2, 0, 0, 5, stat, 5000);
#endif
            if (i != sizeof(stat)) {
                  lprintf(2, "usb_bulk ep1 in failure (%d)\n", i);
#if 1
                  i = usb_control_msg(state->usbdev, 0xc0, 0xb1, 0, 0, 4, stat, 5000);
                  if (i != 4)
                        lprintf(2, "usb_control_msg(0xc0, 0xb1) failure (%d)\n", i);
                  else
                        lprintf(3, "FPGAdownload: stat: 0x%02x 0x%02x 0x%02x 0x%02x\n", stat[0], stat[1], stat[2], stat[3]);
#endif
                  return -1;
            }
            lprintf(3, "FPGAdownload: stat: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", stat[0], stat[1], stat[2], stat[3], stat[4]);
            if (stat[0] == 0x10)
                  break;
            if (stat[0] & 0x80) {
                  lprintf(2, "FPGA download error code 0x%02x\n", stat[0]);
                  return -1;
            }
        }
#define MAXSZ 256
      for (u = 0; u < FPGA_CONFIGSIZE; ) {
            ln = FPGA_CONFIGSIZE - u;
            if (ln > MAXSZ)
                  ln = MAXSZ;
            i = usb_bulk_msg(state->usbdev, 0x02, ln, (void *)(fpga+u), 5000);
            if (i != ln) {
                  lprintf(2, "usb_bulk_msg ep2 out failure (%d,len=%u,addr=%u)\n", i, ln, u);
                  return -1;
            }
            u += ln;
#if 1
            i = usb_bulk_msg(state->usbdev, 0x81, sizeof(stat), stat, 5000);
#else
            i = usb_control_msg(state->usbdev, 0xc0, 0xb2, 0, 0, 5, stat, 5000);
#endif
            if (i != sizeof(stat)) {
                  lprintf(2, "usb_bulk_msg ep1 in failure (%d)\n", i);
                  return -1;
            }
      }
      for (;;) {
#if 1
            i = usb_bulk_msg(state->usbdev, 0x81, sizeof(stat), stat, 5000);
#else
            i = usb_control_msg(state->usbdev, 0xc0, 0xb2, 0, 0, 5, stat, 5000);
#endif
            if (i != sizeof(stat)) {
                  lprintf(2, "usb_bulk_msg ep1 in failure (%d)\n", i);
                  return -1;
            }
            lprintf(3, "FPGAdownload: stat: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", stat[0], stat[1], stat[2], stat[3], stat[4]);
            if (stat[0] == 0x20)
                  break;
            if (stat[0] & 0x80 || stat[0] == 0x10) {
                  lprintf(2, "FPGA download error code 0x%02x\n", stat[0]);
                  return -1;
            }
        }
      /* download the firmware to the AnchorChips core */
      switch (state->cfg.adapt.mode) {
      case trxapi_baycomusb_mode_fsk:
      case trxapi_baycomusb_mode_external:
            lprintf(30, "baycomusb: downloading fsk firmware\n");
            break;

      case trxapi_baycomusb_mode_afsk:
            lprintf(30, "baycomusb: downloading afsk firmware\n");
            break;

      case trxapi_baycomusb_mode_audio:
            lprintf(30, "baycomusb: downloading audio firmware\n");
            break;

      default:
            return -1;
      }
      if (loadmem(state->usbdev, firmware, fwlen))
            return -1;
      /* start AnchorChips core */
      if (writecpucs(state->usbdev, 0))
            return -1;
      return 0;
}
/* ---------------------------------------------------------------------- */

int adapter_finalinit(struct trx_thread_state *state)
{
      char buf[8];
      int i;

      if (state->cfg.adapt.mode != trxapi_baycomusb_mode_audio) {
            if (usb_setconfiguration(state->usbdev, 1))
                  return -1;
            /* claim interface 0 */
            if (usb_claiminterface(state->usbdev, 0)) {
                  lprintf(2, "adapter_finalinit: cannot claim interface 0\n");
                  return -1;
            }
            /* set interface 0 altsetting 1, to enable the bulk ep's */
            if (usb_setinterface(state->usbdev, 0, 1)) {
                  lprintf(2, "adapter_finalinit: cannot set interface 0 altsetting 1\n");
                  return -1;
            }
            /* kludge: the first OUT2 packet seems to arrive corrupted, so send this special "magic" packet */
            buf[0] = 0x55;
            if ((i = usb_bulk_msg(state->usbdev, 0x02, 1, buf, 500)) != 1) {
                  lprintf(2, "usb_bulk_msg ep2 out failure (%d)\n", i);
                  return -1;
            }
            if (usb_releaseinterface(state->usbdev, 0)) {
                  lprintf(2, "adapter_finalinit: cannot release interface 0\n");
                  return -1;
            }
      }
      return 0;
}

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

int adapter_init_getserial(struct trx_thread_state *state)
{
      struct usb_device_descriptor desc;
      unsigned char mode;
      int i;

      /* get product ID */
      if (usb_getdevicedescriptor(state->usbdev, &desc)) {
            lprintf(2, "usb_getdevicedescriptor error %s\n", strerror(errno));
            adapter_reset(state->usbdev);
            return -1;
      }
      if ((desc.idVendor[0] | (desc.idVendor[1] << 8)) != BAYCOMUSB_VENDORID) {
            lprintf(0, "usb_getdevicedescriptor: wrong vendor ID??\n");
            return -1;
      }
      switch (desc.idProduct[0] | (desc.idProduct[1] << 8)) {
      case BAYCOMUSB_PRODUCTID_EMPTY:
            adapter_reset(state->usbdev);
            return -1;

      case BAYCOMUSB_PRODUCTID_FPGALD:
            if (usb_setconfiguration(state->usbdev, 1)) {
                  adapter_reset(state->usbdev);
                  return -1;
            }
            /* retrieve serial number from EEPROM */
            i = usb_control_msg(state->usbdev, 0xc0, 0xb3, 0, 0, sizeof(state->serial)-1, state->serial, 5000);
            if (i < 0 || i >= sizeof(state->serial)) {
                  lprintf(2, "usb_control_msg(0xc0,0xb3) error %s\n", strerror(errno));
                  i = 0;
            }
            state->serial[i] = 0;
            if (!i) {
                  lprintf(1, "USB device has no serial number\n");
                  strncpy(state->serial, "blank", sizeof(state->serial));
            }
            config_loaddevice(state);
            if (adapter_download(state)) {
                  lprintf(2, "adapter_download failed\n");
                  adapter_reset(state->usbdev);
                  return -2;
            }
            return -1;

      case BAYCOMUSB_PRODUCTID_MODEM:
      case BAYCOMUSB_PRODUCTID_AUDIO:
            /* check status of configuration */
            i = usb_control_msg(state->usbdev, 0xc0, 0xc8, 0, 0, 1, &mode, 500);
            if (i != 1) {
                  lprintf(2, "usb_control_msg(0xc0,0xc8) error %s\n", strerror(errno));
                  state->mode = MODE_NONE;
                  adapter_reset(state->usbdev);
                  return -1;
            }
            state->mode = mode;
            i = usb_control_msg(state->usbdev, 0xc0, 0xc9, 0, 0, sizeof(state->serial)-1, state->serial, 500);
            if (i < 0 || i >= sizeof(state->serial)) {
                  lprintf(2, "usb_control_msg(0xc0,0xc9) error %s\n", strerror(errno));
                  lprintf(1, "USB device has no serial number\n");
                  strncpy(state->serial, "blank", sizeof(state->serial));
            } else {
                  state->serial[i] = 0;
            }
            return 0;

      default:
            lprintf(0, "usb_getdevicedescriptor: wrong product ID??\n");
            adapter_reset(state->usbdev);
            return -1;
      }
}

Generated by  Doxygen 1.6.0   Back to index