AudioScience HPI Version_4.11.

HPI tuner interface

HPI example for tuner cards

/******************************************************************************
$Header: /home/eliot/asi/repo/cvsrepo/Repository/drv/linux/test/asihpitune.c,v 1.47 2011/04/05 10:02:06 as-dxb Exp $

  Control tuners on ASI87xx, ASI8821 and ASI892x cards

  Usage: asihpitune --help

******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#ifdef HPI_OS_LINUX
#include <unistd.h>
#endif
#include <getopt.h>
#ifdef __APPLE__
#include <hpi/hpi.h>
#include <hpi/hpirds.h>
#include <hpi/hpidebug.h>
#else
#include <hpi.h>
#include <hpirds.h>
#include <hpidebug.h>
#endif

#define verbose_printf if (verbose) printf

typedef struct {
        uint16_t wControlType;  // HPI_CONTROL_METER, _VOLUME etc
        uint16_t wSrcNodeType;
        uint16_t wSrcNodeIndex;
        uint16_t wDstNodeType;
        uint16_t wDstNodeIndex;
} hpi_control_t;

static char *hpi_control_strings[] = HPI_CONTROL_TYPE_STRINGS;
static char *hpi_src_strings[] = HPI_SOURCENODE_STRINGS;
static char *hpi_dst_strings[] = HPI_DESTNODE_STRINGS;

#define nanosec 1000000

// local protos
static void HandleError(
        hpi_err_t err
);
static void HandleErrorComment(
        char *comment,
        hpi_err_t err
);
static void HandleErrorCommentContinue(
        char *comment,
        hpi_err_t err
);
static int getch(
        void
);
static void asi_sleep(
        unsigned int milliseconds
);

/* NOTE: indices must match HPI defines for each band */
static char *band_names[HPI_TUNER_BAND_LAST + 1] = {
        "invalid",
        "AM",
        "FM",
        "NTSC_M",
        "FM2",
        "Aux",
        "PAL_BG",
        "PAL_I",
        "PAL_DK",
        "Secam_L",
};

/* Option variables */
static unsigned int dump_mixer = 0;
static uint16_t wAdapterIndex = 0;
static uint16_t nTunerIndex = 0;
static uint16_t nBand = 0;
static uint32_t nTunerFrequency = 0;
static short wRssMode = -1;
static short wRdsMode = -1;
static int query_tuner_caps = 0;
static int query_tuner_settings = 0;
static int verbose = 0;
static int rds = 0;
static int rds_poll_ms = 1000;
static int rds_poll_loops = 100;
static short nMux = -1;

static struct option long_options[] = {
        {"adapter", required_argument, 0, 'a'},
        {"band", required_argument, 0, 'b'},
        {"query-caps", no_argument, 0, 'c'},
        {"dump-mixer", no_argument, 0, 'd'},
        {"frequency", required_argument, 0, 'f'},
        {"rss-mode", required_argument, 0, 'm'},
        {"rds-mode", required_argument, 0, 'n'},
        {"rds_poll_ms", required_argument, 0, 'p'},
        {"rds", optional_argument, 0, 'r'},
        {"settings", no_argument, 0, 's'},
        {"tuner", required_argument, 0, 't'},
        {"verbose", no_argument, 0, 'v'},
        {"mux", required_argument, 0, 'x'},
        {"help", no_argument, 0, 'h'},
        {0, 0, 0, 0}
};

static const char *short_options = "a:b:cdf:m:n:p:r::t:st:vx:h";

static const char *option_help[] = {
        "<adapter number> to test, default is 0.",
        "<band> see below for valid options",
        "Query tuner capabilities.",
        "Dump list of mixer controls.",
        "<freq in kHz> tuner frequency",
        "<mode> Set tuner RSS mode.",
        "<mode> Set tuner RDS mode.",
        "<milliseconds> Set RDS polling interval. Default 1000",
        "[optional loop count] Reads RDS data from the tuner. Default 100 loops",
        "Read back tuner settings.",
        "<tuner index> to query or set, default is 0.",
        "Enable verbose output.",
        "<n> Set audio out mux to tuner",
        "Show this text."
};
static void help(
        void
)
{
        int i = 0;
        printf("\nUsage - asihpitune [options]\n");
        while (long_options[i].name != 0) {
                printf("--%s -%c %s\n",
                        long_options[i].name,
                        (char)(long_options[i].val), option_help[i]);
                i++;
        }
        printf("Valid values for -b option are ");
        for (i = 1; i <= HPI_TUNER_BAND_LAST; i++)
                printf("%s, ", band_names[i]);
        printf("\n");
        exit(0);
}

static void parse_options(
        int argc,
        char *argv[]
)
{
        int c;
    /*********** Parse the command line options ***************/
        while (1) {
                // int this_option_optind = optind ? optind : 1;
                int option_index = 0;

                c = getopt_long(argc, argv, short_options,
                        long_options, &option_index);
                if (c == -1)
                        break;

                switch (c) {
                case 0:
                        printf("option %s", long_options[option_index].name);
                        if (optarg)
                                printf(" with arg %s", optarg);
                        printf("\n");
                        break;
                case 'a':
                        wAdapterIndex = atoi(optarg);
                        break;
                case 'b':
                        {
                                int i;
                                for (i = 1; i <= HPI_TUNER_BAND_LAST; i++)
                                        if (strcmp(band_names[i], optarg) ==
                                                0)
                                                nBand = i;
                                if (!nBand) {
                                        printf("\n****** Invalid band: %s ******\n", optarg);
                                        help();
                                }

                                query_tuner_settings = 1;
                        }
                        break;
                case 'c':
                        query_tuner_caps = 1;
                        break;
                case 'd':
                        dump_mixer = 1;
                        break;
                case 'f':
                        nTunerFrequency = atoi(optarg);
                        query_tuner_settings = 1;
                        break;
                case 'm':
                        wRssMode = atoi(optarg);
                        query_tuner_settings = 1;
                        break;
                case 'n':
                        wRdsMode = atoi(optarg);
                        query_tuner_settings = 1;
                        break;
                case 'p':
                        rds_poll_ms = atoi(optarg);
                        rds = 1;
                        break;
                case 'r':
                        rds = 1;
                        if (optarg)
                                rds_poll_loops = atoi(optarg);
                        break;
                case 's':
                        query_tuner_settings = 1;
                        break;
                case 't':
                        nTunerIndex = atoi(optarg);
                        break;
                case 'v':
                        verbose = 1;
                        break;
                case 'x':
                        nMux = atoi(optarg);
                        break;
                case '?':
                case 'h':
                        help();
                        break;

                default:
                        printf("?? getopt returned character code 0%o ??\n",
                                c);
                }
        }

        if (optind < argc) {
                // printf ("non-option ARGV-elements: ");
                /*
                   nNumFiles=0;
                   while ((optind < argc) && (nNumFiles < MAX_FILES))  {
                   strcpy( szFile[nNumFiles], argv[optind++] );
                   printf("File %d is %s\n",nNumFiles,szFile[nNumFiles]);
                   nNumFiles++;
                   }
                 */
        }

}

static void print_mixer_controls(hpi_hsubsys_t *hSubSys, hpi_handle_t hMixer)
{
        uint16_t f;
        hpi_handle_t hTuner;
        uint32_t err;
        for (f = 0; f < 256; f++) {
                hpi_control_t asihpi_control;

                err = HPI_MixerGetControlByIndex(hSubSys, hMixer, f, &asihpi_control.wSrcNodeType, &asihpi_control.wSrcNodeIndex, &asihpi_control.wDstNodeType, &asihpi_control.wDstNodeIndex, &asihpi_control.wControlType,    // HPI_CONTROL_METER, _VOLUME etc
                        &hTuner);
                if (err == HPI_ERROR_CONTROL_DISABLED)
                        printf("DISABLED ");
                else if (err)
                        break;

                printf("HPI Control %d, %s:%s[%d]->%s[%d]\n",
                        f,
                        hpi_control_strings[asihpi_control.wControlType],
                        hpi_src_strings[asihpi_control.wSrcNodeType -
                                HPI_SOURCENODE_NONE],
                        asihpi_control.wSrcNodeIndex,
                        hpi_dst_strings[asihpi_control.wDstNodeType -
                                HPI_DESTNODE_NONE],
                        asihpi_control.wDstNodeIndex);
                if (asihpi_control.wControlType == HPI_CONTROL_MULTIPLEXER) {
                        uint16_t l;
                        for (l = 0; l < 256; l++) {
                                err = HPI_Multiplexer_QuerySource(hSubSys,
                                        hTuner, l,
                                        &asihpi_control.
                                        wSrcNodeType,
                                        &asihpi_control.wSrcNodeIndex);
                                if (!err)
                                        printf("\tSource %d %s[%d]\n",
                                                l,
                                                hpi_src_strings
                                                [asihpi_control.wSrcNodeType -
                                                        HPI_SOURCENODE_NONE],
                                                asihpi_control.wSrcNodeIndex);
                                else
                                        break;
                        }
                }
        }
        printf("%d controls found\n\n", f);
}

/************************************** MAIN ***********************/
int main(
        int argc,
        char *argv[]
)
{
        hpi_hsubsys_t *hSubSys;
        hpi_err_t err = 0;              // HPI error
        uint32_t dwVersion = 0;
        int numAdapters = 0;
        uint16_t wVersion;
        uint32_t dwSerialNumber;
        uint16_t wType;
        uint16_t wNumOutStreams;
        uint16_t wNumInStreams;
        int i;

        hpi_handle_t hMixer = 0;
        hpi_handle_t hTuner = 0, hMux = 0;

        parse_options(argc, argv);

        /* */
        verbose_printf
                ("********************************************************************\n");
        verbose_printf
                ("\n** $Id: asihpitune.c,v 1.47 2011/04/05 10:02:06 as-dxb Exp $ **\n");
        verbose_printf("\n** HPI test code for tuners **\n");
        /*
           if (argc>1)
           sscanf(argv[1],"%d",&wAdapterIndex);
           else {
           printf("Usage:\n:Dump the mixer map of the adapter: test8700 <adapter index>\n");
           printf("Show tuner bands: test8700 <adapter index> <tuner index>\n");
           printf("Set a tuner: test8700 <adapter index> <tuner index> <band> <frequency in kHz>\n");

           exit (0);
           }
         */
        /* */
        // open subsystem and find adapters
        verbose_printf
                ("********************************************************************\n");
        printf("HPI_SubSysCreate\n");
        hSubSys = HPI_SubSysCreate();
        if (hSubSys == NULL) {
                printf("hSubSys==NULL\n");
                exit(1);
        }

        err = HPI_SubSysGetVersionEx(hSubSys, &dwVersion);
        HandleError(err);
        verbose_printf("HPI_SubSysGetVersionEx=%d.%02d.%02d\n",
                dwVersion >> 16, (dwVersion >> 8) & 0xff, dwVersion & 0xff);

        err = HPI_SubSysGetNumAdapters(hSubSys, &numAdapters);
        HandleError(err);
        verbose_printf("HPI_SubSysGetNumAdapters NumberAdapters=%d ",
                numAdapters);
        for (i = 0; i < numAdapters; i++) {
                uint32_t dwAdapterIndex;
                uint16_t wAdapterType;
                err =  HPI_SubSysGetAdapter(hSubSys,
                                i, &dwAdapterIndex, &wAdapterType);
                verbose_printf("%d=%X\n ", dwAdapterIndex, wAdapterType);
        }

        err = HPI_AdapterClose(hSubSys, wAdapterIndex);
        HandleError(err);
        verbose_printf("HPI_AdapterClose \n");

        // open 1st adapter
        err = HPI_AdapterOpen(hSubSys, wAdapterIndex);
        HandleError(err);
        verbose_printf("HPI_AdapterOpen \n");

        err = HPI_AdapterGetInfo(hSubSys,
                wAdapterIndex,
                &wNumOutStreams,
                &wNumInStreams, &wVersion, &dwSerialNumber, &wType);
        HandleError(err);
        verbose_printf("HPI_AdapterGetInfo\n");
        verbose_printf("Adapter ID=%4X Index=%d NumOutStreams=%d NumInStreams=%d S/N=%d\n\tHw Version %c%d ", wType, wAdapterIndex, wNumOutStreams, wNumInStreams, dwSerialNumber, ((wVersion >> 3) & 0xf) + 'A',       // Hw version major
                wVersion & 0x7  // Hw version minor
                );

        if (verbose) {
                uint16_t major, minor;
                err = HPI_AdapterGetProperty(hSubSys,
                        wAdapterIndex,
                        HPI_ADAPTER_PROPERTY_SOFTWARE_VERSION,
                        &major, &minor);
                HandleError(err);
                verbose_printf("DSP code version %d.%02d.%02d\n", major >> 8,
                        major & 0xff, minor);
        }
        // open the mixer of this adapter
        err = HPI_MixerOpen(hSubSys, wAdapterIndex, &hMixer);
        verbose_printf("HPI_MixerOpen: handle=%X\n", hMixer);
        HandleError(err);
        printf("\n");

    /******** Dump mixer ******/
        if (dump_mixer)
                print_mixer_controls(hSubSys, hMixer);

        if ((wType & 0xF000) != 0x8000) {
                printf("Only ASI87xx, ASI8821 and ASI89xx adapters are supported/n");
                goto close;
        }

        err = HPI_MixerGetControl(hSubSys, hMixer, HPI_SOURCENODE_TUNER,
                nTunerIndex, 0, 0, HPI_CONTROL_TUNER, &hTuner);
        HandleErrorComment("Get Tuner Control", err);
        if (err)
                goto close;

        err = HPI_MixerGetControl(hSubSys, hMixer, 0, 0,
                HPI_DESTNODE_LINEOUT, 0, HPI_CONTROL_MULTIPLEXER, &hMux);
        HandleErrorComment("Get Mux", err);

        /******** Mode setting ******/
        if (wRssMode >= 0) {
                        err = HPI_Tuner_SetMode(hSubSys, hTuner,
                                HPI_TUNER_MODE_RSS, wRssMode);
                        HandleErrorComment("SetMode RSS", err);
        }

        if (wRdsMode >= 0) {
                        err = HPI_Tuner_SetMode(hSubSys, hTuner,
                                HPI_TUNER_MODE_RDS, wRdsMode);
                        HandleErrorComment("SetMode RDS", err);
        }

        /******** Mux setting ******/
        if (hMux && (nMux >= 0) && (nMux < 8)) {

                HandleErrorComment("Get mux ctrl", err);
                err = HPI_Multiplexer_SetSource(hSubSys, hMux,
                        HPI_SOURCENODE_TUNER, nMux);
                HandleErrorComment("SetMuxSource", err);

        }

/******** Band setting ******/
        if (nBand) {
                err = HPI_Tuner_SetBand(hSubSys, hTuner, nBand);
                HandleErrorComment("SetBand", err);
        }

/******** Frequency setting ******/
        if (nTunerFrequency) {
                err = HPI_Tuner_SetFrequency(hSubSys, hTuner,
                        nTunerFrequency);
                HandleErrorComment("SetFrequency", err);
        }
        asi_sleep(nanosec / 1000000);

/******** Query capabilities ******/
        if (query_tuner_caps) {
                uint32_t dwIndex;
                uint16_t wSetting;

                err = HPI_MixerGetControl(hSubSys, hMixer,
                        HPI_SOURCENODE_TUNER,
                        nTunerIndex, 0, 0, HPI_CONTROL_TUNER, &hTuner);
                if (err == 0) {
                        printf("\nTuner %d supports\n", nTunerIndex);
                        for (dwIndex = 0; dwIndex < 100; dwIndex++) {
                                err = HPI_Tuner_QueryBand(hSubSys,
                                        hTuner, dwIndex, &wSetting);
                                if (err != 0)
                                        break;
                                if ((wSetting == 0)
                                        || (wSetting > HPI_TUNER_BAND_LAST)) {
                                        printf("Unknown band type %d\n",
                                                wSetting);
                                        continue;
                                }

                                printf("%i %s : ", dwIndex,
                                        band_names[wSetting]);
                                {
                                        uint32_t dwStart, dwEnd, dwStep;
                                        err = HPI_Tuner_QueryFrequency
                                                (hSubSys, hTuner, 0, wSetting,
                                                &dwStart);
                                        err = HPI_Tuner_QueryFrequency
                                                (hSubSys, hTuner, 1, wSetting,
                                                &dwEnd);
                                        err = HPI_Tuner_QueryFrequency
                                                (hSubSys, hTuner, 2, wSetting,
                                                &dwStep);
                                        printf("from %ikHz to %ikHz step %ikHz\n", dwStart, dwEnd, dwStep);
                                }
                        }
                }
        }
/******** Query settings ******/
        if (query_tuner_settings) {
                uint16_t nTunerBand = 0;
                short int nRfLevel = 0;
                uint32_t nTunerFrequency = 0;
                uint32_t wMode = 0;
                uint16_t wMuxIndex = 0;
                uint16_t wStatus = 0;
                uint16_t wStatusMask = 0;

                err = HPI_Tuner_GetBand(hSubSys, hTuner, &nTunerBand);
                HandleErrorComment("HPI_Tuner_GetBand", err);
                err = HPI_Tuner_GetFrequency(hSubSys, hTuner,
                        &nTunerFrequency);
                HandleErrorComment("HPI_Tuner_GetFrequency", err);

                err = HPI_Tuner_GetRFLevel(hSubSys, hTuner, &nRfLevel);
                HandleErrorComment("HPI_Tuner_GetRFLevel", err);

                err = HPI_Multiplexer_GetSource(hSubSys, hMux, 0, &wMuxIndex);
                HandleErrorComment("HPI_Multiplexer_GetSource", err);

                err = HPI_Tuner_GetStatus(hSubSys, hTuner,
                        &wStatusMask, &wStatus);
                HandleErrorComment("HPI_Tuner_GetStatus", err);

                printf("Current Settings  %s band, frequency %i. Mode %d.  RF level %3.2fdBuV. Mux=%d\n",
                                band_names[nTunerBand], nTunerFrequency, wMode, nRfLevel / 100.0, wMuxIndex);
                printf("Status mask %08X, value %08X\n", wStatusMask,
                        wStatus);
                err = HPI_Tuner_GetMode(hSubSys, hTuner,
                        HPI_TUNER_MODE_RSS, &wMode);
                if (err == HPI_ERROR_INVALID_CONTROL_ATTRIBUTE) {
                        verbose_printf("Tuner does not have MODEs.\n");
                        wMode = 0;
                } else if ( err ==  HPI_ERROR_INVALID_CONTROL_VALUE) {
                        verbose_printf("TUNER_MODE_RSS not supported\n");
                        wMode = 0;
                } else {
                        HandleErrorComment("HPI_Tuner_GetMode", err);
                        printf("TUNER_MODE_RSS %d\n", wMode);
                }

                if (err != HPI_ERROR_INVALID_CONTROL_ATTRIBUTE) {
                        err = HPI_Tuner_GetMode(hSubSys, hTuner,
                                HPI_TUNER_MODE_RDS, &wMode);
                        if ( err ==  HPI_ERROR_INVALID_CONTROL_VALUE) {
                                verbose_printf("TUNER_MODE_RDS not supported\n");
                                wMode = 0;
                        } else {
                                HandleErrorComment("HPI_Tuner_GetMode", err);
                                printf("TUNER_MODE_RDS %d\n", wMode);
                        }
                }
        }
/******** RDS ******/
        if (rds) {
                hpi_handle_t hPad = 0;
                unsigned int nRDSloopcount = rds_poll_loops;
                uint32_t dwPTY = 0, dwPI = 0;
                hpi_err_t ecn = 0, ec = 0, epi = 0;

                err = HPI_MixerGetControl(hSubSys, hMixer,
                        HPI_SOURCENODE_TUNER,
                        nTunerIndex, 0, 0, HPI_CONTROL_PAD, &hPad);
                HandleErrorComment("HPI_MixerGetControl (HPI_CONTROL_PAD)",
                        err);

                if (err)
                        nRDSloopcount = 1;

                while (--nRDSloopcount) {
                        char szPAD[HPI_PAD_COMMENT_LEN];

                        printf("\nLoop - %d\n", nRDSloopcount);
                        if (verbose) {
                                unsigned char aRDS[12]; // RDS data group of (4 blocks each of 16 bits) plus 4 chars of error information

                                err = HPI_Tuner_GetRDS(hSubSys, hTuner,
                                        (char *)aRDS);
                                if (!err) {
                                        int i;

                                        printf("RDS block data ");
                                        for (i = 0; i < 12; i++)
                                                printf("%u ", aRDS[i]);
                                        printf("\n");

                                        /*
                                           Output PI from RDS data.
                                         */
                                        printf("PI from        ^---^ = 0x%X\n", aRDS[1] << 8 | aRDS[0]);
                                } else
                                        HandleErrorCommentContinue
                                                ("HPI_Tuner_GetRDS", err);
                        }
                        /*
                           Note, depending on whether the tuner supports HDRadio PAD information
                           or FM RDS information, different attributes may be valid.
                         */
                        if (!ecn) {
                                ecn = HPI_PAD_GetChannelName(hSubSys, hPad,
                                        szPAD, sizeof(szPAD));
                                HandleErrorCommentContinue
                                        ("HPI_PAD_GetChannelName", ecn);
                                if (!ecn)
                                        printf("ChannelName : %s\n", szPAD);
                        }

                        err = HPI_PAD_GetArtist(hSubSys, hPad,
                                szPAD, sizeof(szPAD));
                        HandleErrorComment("HPI_PAD_GetArtist", err);
                        if (!err)
                                printf("Artist/RT : %s\n", szPAD);

                        err = HPI_PAD_GetTitle(hSubSys, hPad,
                                szPAD, sizeof(szPAD));
                        HandleErrorComment("HPI_PAD_GetTitle", err);
                        if (!err)
                                printf("Title/PS : %s\n", szPAD);

                        if (!ec) {
                                ec = HPI_PAD_GetComment(hSubSys, hPad,
                                        szPAD, sizeof(szPAD));
                                HandleErrorCommentContinue
                                        ("HPI_PAD_GetComment", ec);
                                if (!ec)
                                        printf("Comment/PS : %s\n", szPAD);
                        }

                        err = HPI_PAD_GetProgramType(hSubSys, hPad, &dwPTY);
                        HandleErrorComment("HPI_PAD_GetProgramType", err);
                        if (!err) {
                                err = HPI_PAD_GetProgramTypeString(hSubSys,
                                        hPad, HPI_RDS_DATATYPE_RBDS, dwPTY,
                                        szPAD, sizeof(szPAD));
                                if (!err)
                                        printf("PTY : %d, %s\n", dwPTY,
                                                szPAD);
                        }

                        if (!epi) {
                                epi = HPI_PAD_GetRdsPI(hSubSys, hPad, &dwPI);
                                HandleErrorCommentContinue("HPI_PAD_GetRdsPI",
                                        epi);
                                if (!epi)
                                        printf("PI : 0x%X\n", dwPI);
                        }

                        asi_sleep(rds_poll_ms);
                }
        }
        /* if (rds) */
close:
        err = HPI_MixerClose(hSubSys, hMixer);
        verbose_printf("\nHPI_MixerClose\n");
        HandleError(err);

        err = HPI_AdapterClose(hSubSys, wAdapterIndex);
        verbose_printf("HPI_AdapterClose\n");
        HandleError(err);

        err = HPI_AdapterClose(hSubSys, wAdapterIndex);

        HPI_SubSysFree(hSubSys);
        return 0;
}

/****************************** HandleError **********************/
static void HandleErrorCommentContinue(
        char *comment,
        hpi_err_t err
)
{
        char szError[256];
        if (err) {
                printf("\t\t%s\n", comment);
                HPI_GetErrorText(err, szError);
                printf("\t\tERROR %s\n", szError);
        }

}
static void HandleError(
        hpi_err_t err
)
{
        char szError[256];
        char nK = 0;

        if (err) {
                HPI_GetErrorText(err, szError);
                printf("ERROR %d %s\n", err, szError);
                printf("\tpress Enter to continue, (q,Enter) to exit...\n");
                nK = getch();
                if (nK == 'q')
                        exit(0);
        }
}

static void HandleErrorComment(
        char *comment,
        hpi_err_t err
)
{
        if (err)
                printf("%s ", comment);
        HandleError(err);
}

static int getch(
        void
)
{
        return getchar();
}

/****************************** asi_sleep **********************/
static void asi_sleep(
        unsigned int milliseconds
)
{
#if defined(HPI_OS_LINUX) || defined(__APPLE__)
        struct timespec req =
                { milliseconds / 1000, (milliseconds % 1000) * 1000000 };
        nanosleep(&req, 0);
#else
        Sleep(milliseconds);
#endif
}

/* END_OF_CODE */