blob: 8b0d54dc34d61d8ff752f14bd88cfb2382b14ccd [file] [log] [blame]
/*
** Copyright (c) 2013-2017 by Silicon Laboratories, Inc.
**
** $Id: audio.c 6477 2017-05-03 02:19:47Z nizajerk $
**
** audio.c
**
** This file contains proprietary information.
** No dissemination allowed without prior written permission from
** Silicon Laboratories, Inc.
**
** File Description:
**
** This file contains example implementation and use of ProSLIC API
** audio resources
**
*/
#include "api_demo.h"
#include "macro.h"
#include "user_intf.h"
#ifndef DISABLE_FSK_SETUP
/*****************************************************************************************************/
uInt8 checkSum(uInt8 *str)
{
int i=0;
uInt8 sum = 0;
while(str[i] != 0)
{
sum += str[i++];
}
return -sum;
}
/*****************************************************************************************************/
/* Wait for FSK buffer to be available... */
static void waitForCIDDone(SiVoiceChanType_ptr pChan)
{
uInt8 tmp = 0;
do
{
ProSLIC_CheckCIDBuffer(pChan, &tmp);
#if defined(TARGET_mmp_asr1828) || defined(TARGET_mmp_asr1806)
Delay(pProTimer,3);
#endif
}
while(tmp == 0);
}
/*****************************************************************************************************/
void fskSetup(demo_state_t *pState)
{
ProSLIC_FSKSetup(pState->currentChanPtr, 0);
}
/* This is 7-FSKBUFDEPTH = number of bytes we can safely send after getting
and interrupt that the buffer is "empty" */
int FSK_DEPTH_TRIG;
/*****************************************************************************************************/
void sendFSKData(demo_state_t *pState, uInt8 *stream, int preamble_enable)
{
int i;
uInt8 *cptr;
uInt8 cid_preamble[] = {'U','U','U','U','U','U','U','U'};
uInt8 buffdatadelay[] = {59,50,42,34,25,17,9};
ProSLIC_EnableCID(pState->currentChanPtr);
/* Enable FSKBUF interrupt so we can check it later. */
demo_save_slic_irqens(pState);
SiVoice_WriteReg(pState->currentChanPtr,PROSLIC_REG_IRQEN1,0x40);
(void)SiVoice_ReadReg(pState->currentChanPtr,
PROSLIC_REG_IRQ1); /* Clear IRQ1 */
if(preamble_enable)
{
/* Send preamble */
for(i=0; i<30; i+=FSK_DEPTH_TRIG)
{
if(i >= 8) /* The FIFO depth is 8 bytes, start waiting for it to empty */
{
waitForCIDDone(pState->currentChanPtr);
}
ProSLIC_SendCID(pState->currentChanPtr, cid_preamble, FSK_DEPTH_TRIG);
}
if (30%FSK_DEPTH_TRIG)
{
waitForCIDDone(pState->currentChanPtr);
}
ProSLIC_SendCID(pState->currentChanPtr,cid_preamble,30%FSK_DEPTH_TRIG);
waitForCIDDone(pState->currentChanPtr);
/* Make sure the last byte is shifted out prior to idle mark bits. */
Delay(pProTimer,buffdatadelay[FSK_DEPTH_TRIG-1]);
/* Delay > 130ms for idle mark bits */
Delay(pProTimer,140); //for China.
}
stream[stream[1]+2] = 0;
stream[stream[1]+2] = checkSum(stream);
cptr = stream;
/* At this point the FIFO buffer is empty, fill it with the maximum of 8 bytes.
The +3 is for header, checksum + mark bits
*/
ProSLIC_SendCID(pState->currentChanPtr, cptr, SI_MIN(stream[1]+3, 8));
cptr += SI_MIN(stream[1]+3, 8);
/* now loop until we've sent all the data. */
for(i = stream[1]-3; i>0; i-= FSK_DEPTH_TRIG)
{
/* Since we filled the CID FIFO buffer earlier, wait for it to become "free" to put more data*/
waitForCIDDone(pState->currentChanPtr);
if( i >= FSK_DEPTH_TRIG )
{
ProSLIC_SendCID(pState->currentChanPtr, cptr, FSK_DEPTH_TRIG);
cptr += FSK_DEPTH_TRIG;
}
else
{
ProSLIC_SendCID(pState->currentChanPtr, cptr, i);
}
}
/* Make sure the last byte is shifted out prior to disabling CID. */
Delay(pProTimer,buffdatadelay[FSK_DEPTH_TRIG-1]);
/* CID spec requirement: >=200ms for China.*/
Delay(pProTimer, 200);
ProSLIC_DisableCID(pState->currentChanPtr);
demo_restore_slic_irqens(pState);
}
/*****************************************************************************************************/
/*
** Sequential (blocking) example of CID transmission
*/
static void sendCIDStream(demo_state_t *pState)
{
uInt8 cid_msg[] =
"\x80" /* MDMF Type */
"\x28" /* Message Length */
"\x01" /* Date/Time Param */
"\x08" /* 8-byte Date/Time */
"07040815" /* July 4th 08:15 am */
"\x02" /* Calling Number Param */
"\x0B" /* 11-byte Calling Number */
"13914750000" /* Phone Number */
"\x07" /* Calling Name Param */
"\x0F" /* 15-byte Calling Name */
"Nice" /* Calling Name */
"\x20" /* Calling Name (whitespace) */
"ProSLIC!!!" /* Calling Name */
"\x00" /* Placeholder for Checksum */
"\x00" /* Markout */
;
uInt8 reg_tmp;
fskSetup(pState);
ProSLIC_RingSetup(pState->currentChanPtr,0);
reg_tmp =SiVoice_ReadReg(pState->currentChanPtr,PROSLIC_REG_RINGCON);
SiVoice_WriteReg(pState->currentChanPtr,PROSLIC_REG_RINGCON,reg_tmp&0xF0);
/* Ensure OFFHOOK Active */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_ACTIVE);
Delay(pProTimer,500);
/* 1st Ring Burst */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_RINGING);
Delay(pProTimer,2000);
/* OHT - the alternative is to have the configuration for ringing set OHT mode automatically... */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_OHT);
/*
** CID spec requires delay 500~1500ms.
** But for some telephone models, delay 1500ms will lead to about 1/30 possibility no CID displayed.
*/
Delay(pProTimer,1300);
/* SEND CID HERE */
sendFSKData(pState, cid_msg, 1);
/* Restore to normal operational mode */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_ACTIVE);
}
/*****************************************************************************************************/
/*
** Sequential (blocking) example of VMWI transmission
*/
void sendVMWIStream(demo_state_t *pState,int enable_flag)
{
uInt8 *vmwi_msg;
// VMWI Message
uInt8 vmwi_msg_enable[] =
"\x06" /* SDMF VMWI Type */
"\x03" /* Message Length (always 3 for SDMF VMWI) */
"\x42" /* VMWI On */
"\x42" /* VMWI On */
"\x42" /* VMWI On */
"\x00" /* Placeholder for Checksum */
"\x00" /* Markout */
;
uInt8 vmwi_msg_disable[] =
"\x06" /* SDMF VMWI Type */
"\x03" /* Message Length (always 3 for SDMF VMWI) */
"\x6f" /* VMWI Off */
"\x6f" /* VMWI Off */
"\x6f" /* VMWI Off */
"\x00" /* Placeholder for Checksum */
"\x00" /* Markout */
;
if(enable_flag)
{
vmwi_msg = vmwi_msg_enable;
}
else
{
vmwi_msg = vmwi_msg_disable;
}
fskSetup(pState);
/* OHT */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_OHT);
Delay(pProTimer,1400); /* Delay 250 to 3600ms (1400) */
sendFSKData(pState, vmwi_msg, 1);
}
#endif
/*****************************************************************************************************/
/* DTMF setup*/
static void setup_cid_dtmf(SiVoiceChanType_ptr currentChanPtr, uInt8 character)
{
int i;
typedef struct
{
char dtmfChar;
char toneIndex;
} dtmfMap_t;
dtmfMap_t dtmfMapping[] =
{
{'0', DTMF_0},
{'1', DTMF_1},
{'2', DTMF_2},
{'3', DTMF_3},
{'4', DTMF_4},
{'5', DTMF_5},
{'6', DTMF_6},
{'7', DTMF_7},
{'8', DTMF_8},
{'9', DTMF_9},
{'A', DTMF_A},
{'B', DTMF_B},
{'C', DTMF_C},
{'D', DTMF_D},
{'*', DTMF_STAR},
{'#', DTMF_POUND},
{0,0}
};
for(i = 0; dtmfMapping[i].dtmfChar; i++)
{
if( dtmfMapping[i].dtmfChar == character )
{
ProSLIC_ToneGenSetup(currentChanPtr, dtmfMapping[i].toneIndex );
return;
}
}
}
/*****************************************************************************************************/
void sendDTMFData(demo_state_t *pState, uInt8 *cptr)
{
while(*cptr)
{
setup_cid_dtmf(pState->currentChanPtr,*cptr);
ProSLIC_ToneGenStart(pState->currentChanPtr,1);
Delay(pProTimer,100);
ProSLIC_ToneGenStop(pState->currentChanPtr);
Delay(pProTimer,100);
cptr++;
}
}
static void send_cid_dtmf(demo_state_t *pState, uInt8 *str)
{
uInt8 *cptr = str;
/* 1st Ring Burst */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_RINGING);
Delay(pProTimer,1000);
/* OHT - the alternative is to have the configuration for ringing set OHT mode automatically... */
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_OHT);
Delay(pProTimer,500);
sendDTMFData(pState, cptr);
ProSLIC_SetLinefeedStatus(pState->currentChanPtr,LF_FWD_ACTIVE);
}
/*****************************************************************************************************/
void audioMenu(demo_state_t *pState)
{
int presetNum;
int32 rxgain, txgain;
uInt16 rxcount, txcount;
int user_selection;
const char *menu_items[] =
{
"Change Audio Gains",
"Load Impedance Preset",
"Send Caller ID by FSK",
"Send VMWI Enable",
"Send VMWI Disable",
"Load PCM Preset",
"Set PCM RX/TX timeslots",
"Enable PCM Bus",
"Disable PCM Bus",
"Print FSK settings",
"Send Caller ID by DTMF",
NULL
};
do
{
user_selection = get_menu_selection( display_menu("Audio Menu", menu_items),
pState->currentChannel);
printf("\n\n");
switch( user_selection )
{
case 0:
presetNum = demo_get_preset( DEMO_IMPEDANCE_PRESET );
ProSLIC_ZsynthSetup(pState->currentChanPtr,presetNum);
#ifdef ENABLE_HIRES_GAIN
do
{
printf("Enter Desired RX Gain (%d - %d(0.1 dB) %s", PROSLIC_GAIN_MIN*10,
PROSLIC_GAIN_MAX*10, PROSLIC_PROMPT);
rxgain = get_int(PROSLIC_GAIN_MIN*10, PROSLIC_EXTENDED_GAIN_MAX*10);
}
while(rxgain > PROSLIC_EXTENDED_GAIN_MAX*10);
do
{
printf("Enter Desired TX Gain (%d - %d(0.1 dB) %s", PROSLIC_GAIN_MIN*10,
PROSLIC_GAIN_MAX*10, PROSLIC_PROMPT);
txgain = get_int(PROSLIC_GAIN_MIN*10, PROSLIC_EXTENDED_GAIN_MAX*10);
}
while(txgain > PROSLIC_EXTENDED_GAIN_MAX*10);
ProSLIC_AudioGainSetup(pState->currentChanPtr,rxgain,txgain,presetNum);
printf("\nRX Gain = %d (0.1 dB)\n", rxgain);
printf("TX Gain = %d (0.1 dB)\n", txgain);
#else
do
{
printf("Enter Desired RX Gain (%d - %d(dB) %s", PROSLIC_GAIN_MIN,
PROSLIC_GAIN_MAX, PROSLIC_PROMPT);
rxgain = get_int(PROSLIC_GAIN_MIN, PROSLIC_EXTENDED_GAIN_MAX);
}
while(rxgain > PROSLIC_EXTENDED_GAIN_MAX);
do
{
printf("Enter Desired TX Gain (%d - %d(dB) %s", PROSLIC_GAIN_MIN,
PROSLIC_GAIN_MAX, PROSLIC_PROMPT);
txgain = get_int(PROSLIC_GAIN_MIN, PROSLIC_EXTENDED_GAIN_MAX);
}
while(txgain > PROSLIC_EXTENDED_GAIN_MAX);
ProSLIC_AudioGainSetup(pState->currentChanPtr,rxgain,txgain,presetNum);
printf("\nRX Gain = %d dB\n", (int)rxgain);
printf("TX Gain = %d dB\n", (int)txgain);
#endif
printf("Preset = %d\n", presetNum);
break;
case 1:
presetNum = demo_get_preset( DEMO_IMPEDANCE_PRESET );
ProSLIC_ZsynthSetup(pState->currentChanPtr, presetNum);
break;
case 2:
#ifdef DISABLE_FSK_SETUP
printf("%sFSK_SETUP Disabled in proslic_api_config.h- aborting request\n",
LOGPRINT_PREFIX);
#else
printf("%sSending CID Stream...\n", LOGPRINT_PREFIX);
sendCIDStream(pState);
#endif
break;
case 3:
#ifdef DISABLE_FSK_SETUP
printf("%sFSK_SETUP Disabled in proslic_api_config.h- aborting request\n",
LOGPRINT_PREFIX);
#else
printf("%sSending VMWI Enable...\n", LOGPRINT_PREFIX);
sendVMWIStream(pState,1);
#endif
break;
case 4:
#ifdef DISABLE_FSK_SETUP
printf("%sFSK_SETUP Disabled in proslic_api_config.h- aborting request\n",
LOGPRINT_PREFIX);
#else
printf("%sSending VMWI Disable...\n", LOGPRINT_PREFIX);
sendVMWIStream(pState,0);
#endif
break;
case 5:
#ifdef DISABLE_PCM_SETUP
printf("%sFSK_SETUP Disabled in proslic_api_config.h- aborting request\n",
LOGPRINT_PREFIX);
#else
presetNum = demo_get_preset( DEMO_PCM_PRESET );
ProSLIC_PCMSetup(pState->currentChanPtr,presetNum);
#endif
break;
case 6:
do
{
printf("Enter RX Count %s ",PROSLIC_PROMPT);
rxcount = get_int(0,0x3FF);
}
while(rxcount > 0x3FF);
do
{
printf("Enter TX Count %s ",PROSLIC_PROMPT);
txcount = get_int(0,0x3FF);
}
while(txcount > 0x3FF);
ProSLIC_PCMTimeSlotSetup(pState->currentChanPtr,rxcount,txcount);
break;
case 7:
printf("Starting PCM Bus\n");
ProSLIC_PCMStart(pState->currentChanPtr);
break;
case 8:
printf("%sStopping PCM Bus\n", LOGPRINT_PREFIX);
ProSLIC_PCMStop(pState->currentChanPtr);
break;
case 9:
#ifndef DISABLE_FSK_SETUP
printf("%sBytes sent per interrupt: %d\n", LOGPRINT_PREFIX,
FSK_DEPTH_TRIG);
printf("%sFSK buf depth: %u\n", LOGPRINT_PREFIX,
ProSLIC_ReadReg(pState->currentChanPtr, PROSLIC_REG_FSKDEPTH));
#else
printf("%sFSK not enabled\n", LOGPRINT_PREFIX);
#endif
break;
case 10:
//The start code of DTMF caller ID should be 'D' or 'A', the end of it should be 'C'
send_cid_dtmf(pState,"A9876543210C");
break;
default:
break;
}
}
while(user_selection != QUIT_MENU);
}