From e2cbc7a72414ce3d385760965351607b71acc214 Mon Sep 17 00:00:00 2001 From: VahidGharaee Date: Mon, 25 Nov 2019 08:23:15 +0330 Subject: Add support for TEF665x in agl-service-radio This is a NXP tuner AM/FM/RDS. The chip has analogue and digital sound output and input. Chip is controlled through i2c. I had to add a sound cart to the kernel to be able to capture the i2s data from the chip. Some of the verbs still to be implemented. I test it on a costum board with imx6solo. Bug-AGL SPEC-3071 Signed-off-by: VahidGharaee Change-Id: I868706e6d275aef77f77138f815b1b53d64780be --- .gitignore | 3 + binding/CMakeLists.txt | 3 +- binding/radio-binding.c | 5 + binding/radio_impl_tef665x.c | 1205 ++++++++++++++++++++++++++++++++++++++++++ binding/radio_impl_tef665x.h | 23 + binding/tef665x.h | 375 +++++++++++++ 6 files changed, 1613 insertions(+), 1 deletion(-) create mode 100644 binding/radio_impl_tef665x.c create mode 100644 binding/radio_impl_tef665x.h create mode 100644 binding/tef665x.h diff --git a/.gitignore b/.gitignore index c08c06a..6622992 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ *~ build* +.vscode* +binding/tempo.c + diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt index 75b30bf..712e165 100644 --- a/binding/CMakeLists.txt +++ b/binding/CMakeLists.txt @@ -27,7 +27,8 @@ PROJECT_TARGET_ADD(radio-binding) set(radio_SOURCES radio-binding.c radio_impl_kingfisher.c - radio_impl_rtlsdr.c) + radio_impl_rtlsdr.c + radio_impl_tef665x.c) PKG_CHECK_MODULES(SOUND REQUIRED gstreamer-1.0) diff --git a/binding/radio-binding.c b/binding/radio-binding.c index 81de631..6df4b6d 100644 --- a/binding/radio-binding.c +++ b/binding/radio-binding.c @@ -29,6 +29,7 @@ #include "radio_impl.h" #include "radio_impl_rtlsdr.h" #include "radio_impl_kingfisher.h" +#include "radio_impl_tef665x.h" static radio_impl_ops_t *radio_impl_ops; @@ -561,6 +562,10 @@ static int init(afb_api_t api) radio_impl_ops = &kf_impl_ops; rc = radio_impl_ops->init(); } + if(rc != 0) { + radio_impl_ops = &tef665x_impl_ops; + rc = radio_impl_ops->init(); + } if (rc != 0) { AFB_API_ERROR(afbBindingV3root, "No radio device found, exiting"); } diff --git a/binding/radio_impl_tef665x.c b/binding/radio_impl_tef665x.c new file mode 100644 index 0000000..a3284f2 --- /dev/null +++ b/binding/radio_impl_tef665x.c @@ -0,0 +1,1205 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + TODO: + at this point: + - complete the rest of verbs. + - find a way to tell the service which i2c chanel is used. + - separate the functions of driver from the verbs by creating new c file. + - find a way of monitoring the quality of tuning and correct it time by time. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//#include +//#include + +#include + +#include "radio_impl.h" +#include "tef665x.h" + + +#define I2C_ADDRESS 0x64 +#define I2C_DEV "/dev/i2c-3" +#define VERSION "0.1" + +#define TEF665x_CMD_LEN_MAX 20 +#define SET_SUCCESS 1 +#define TEF665X_SPLIT_SIZE 24 + +#define TEF665x_REF_CLK 9216000 //reference clock frequency +#define TEF665x_IS_CRYSTAL_CLK 0 //crstal +#define TEF665x_IS_EXT_CLK 1 //external clock input + +#define High_16bto8b(a) ((u8)((a) >> 8)) +#define Low_16bto8b(a) ((u8)(a)) +#define Convert8bto16b(a) ((ushort)(((ushort)(*(a))) << 8 |((ushort)(*(a+1))))) + +#define GST_PIPELINE_LEN 256 + +const u8 tef665x_patch_cmdTab1[] = {3, 0x1c,0x00,0x00}; +const u8 tef665x_patch_cmdTab2[] = {3, 0x1c,0x00,0x74}; +const u8 tef665x_patch_cmdTab3[] = {3, 0x1c,0x00,0x75}; + +typedef struct { + char *name; + uint32_t min; + uint32_t max; + uint32_t step; +} band_plan_t; + +static band_plan_t known_fm_band_plans[5] = { + { .name = "US", .min = 87900000, .max = 107900000, .step = 200000 }, + { .name = "JP", .min = 76000000, .max = 95000000, .step = 100000 }, + { .name = "EU", .min = 87500000, .max = 108000000, .step = 50000 }, + { .name = "ITU-1", .min = 87500000, .max = 108000000, .step = 50000 }, + { .name = "ITU-2", .min = 87900000, .max = 107900000, .step = 50000 } +}; +static band_plan_t known_am_band_plans[1] = { + { .name = "W-ASIA", .min = 522000, .max = 1620000, .step = 5000 } +}; + +static unsigned int fm_bandplan = 2; +static unsigned int am_bandplan = 0; +static bool corking = false; +static bool present = false; +static bool scanning = false; + +// stream state +static GstElement *pipeline; +static bool running; + +#define DEBUG 0 + +#if DEBUG == 1 +#define _debug(x, y) printf("function: %s, %s : %d\n", __FUNCTION__, #x, y) +#else +#define _debug(x, y) +#endif + +static uint file_desc; + +static radio_band_t current_band; +static uint32_t current_am_frequency; +static uint32_t current_fm_frequency; + +static gboolean handle_message(GstBus *bus, GstMessage *msg, __attribute__((unused)) void *ptr) +{ + GstState state; + + if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_REQUEST_STATE) { + + gst_message_parse_request_state(msg, &state); + + if (state == GST_STATE_PAUSED) + corking = true; + else if (state == GST_STATE_PLAYING) + corking = false; + + } + + return TRUE; +} + +static int tef665x_set_cmd(int i2c_file_desc, TEF665x_MODULE module, u8 cmd, int len, ...) +{ + int i, ret; + u8 buf[TEF665x_CMD_LEN_MAX]; + ushort temp; + va_list vArgs; + + va_start(vArgs, len); + + buf[0] = module; //module, FM/AM/APP + buf[1] = cmd; //cmd, 1,2,10,... + buf[2] = 0x01; //index, always 1 + + for(i = 3; i < len; i++) + { + temp = va_arg(vArgs,int); + + buf[i++] = High_16bto8b(temp); + buf[i] = Low_16bto8b(temp); + } + + va_end(vArgs); + + ret = write(i2c_file_desc, buf, len); + + temp = (ret == len) ? 1 : 0; + _debug("return value", temp); + return temp; +} + +static int tef665x_get_cmd(int i2c_file_desc, TEF665x_MODULE module, u8 cmd, u8 *receive, int len) +{ + u8 temp; + u8 buf[3]; + int ret; + + buf[0]= module; //module, FM/AM/APP + buf[1]= cmd; //cmd, 1,2,10,... + buf[2]= 1; //index, always 1 + + write(i2c_file_desc, buf, 3); + + ret = read(i2c_file_desc, receive, len); + temp = (ret == len) ? 1 : 0; + _debug("return value", temp); + return temp; +} + +/* +module 64 APPL +cmd 128 Get_Operation_Status | status +index +1 status + Device operation status + 0 = boot state; no command support + 1 = idle state + 2 = active state; radio standby + 3 = active state; FM + 4 = active state; AM +*/ +static int appl_get_operation_status(int i2c_file_desc ,u8 *status) +{ + u8 buf[2]; + int ret; + + ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_APPL, + TEF665X_Cmd_Get_Operation_Status, + buf, sizeof(buf)); + + if(ret == SET_SUCCESS) + { + *status = Convert8bto16b(buf); + _debug("return value", 1); + return 1; + } + _debug("return value", 0); + return 0; +} + +static int get_operation_status(int i2c_file_desc, TEF665x_STATE *status) +{ + TEF665x_STATE data; + int ret; + if(SET_SUCCESS ==(ret = appl_get_operation_status(i2c_file_desc, &data))) + { + //printk( "appl_get_operation_status1 data= %d \n",data); + _debug("got status", ret); + switch(data) + { + case 0: + _debug("status: boot", ret); + *status = eDevTEF665x_Boot_state; + break; + case 1: + _debug("status: idle", ret); + *status = eDevTEF665x_Idle_state; + break; + default: + _debug("status: active", ret); + *status = eDevTEF665x_Active_state; + break; + } + } + return ret; +} + +static int tef665x_power_on(int i2c_file_desc) +{ + int ret; + TEF665x_STATE status; + usleep(5000); + if(SET_SUCCESS == (ret = get_operation_status(i2c_file_desc, &status))) //[ w 40 80 01 [ r 0000 ] + { + _debug("Powered ON", ret); + } + else + { + _debug("Powered ON FAILED!", ret); + } + + return ret; +} + +static int tef665x_writeTab(int i2c_file_desc,const u8 *tab) +{ + int ret; + ret = write(i2c_file_desc, tab + 1, tab[0]); + return (ret != tab[0]) ? 0 : 1; +} + +static int tef665x_patch_load(int i2c_file_desc, const u8 *bytes, ushort size) +{ + u8 buf[25]; //the size which we break the data into, is 24 bytes. + int ret, i; + + ushort num = size / 24; + ushort rem = size % 24; + + buf[0] = 0x1b; + + usleep(10000); + + for(i = 0; i < num; i++) + { + memcpy(buf + 1, bytes + (24 * i), 24); + + ret = write(i2c_file_desc, buf, 25); + + if(ret != 25) + { + _debug("FAILED, send patch error! in pack no", i); + return false; + } + usleep(50); + } + + memcpy(buf + 1, bytes + (num * 24), rem); + + ret = write(i2c_file_desc, buf, rem); + if(ret != rem) + { + _debug("FAILED, send patch error at the end!", 0); + return false; + } + usleep(50); + + _debug("return value", 1); + return true; +} + +static int tef665x_patch_init(int i2c_file_desc) +{ + int ret = 0; + ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ] + if(!ret) + { + _debug("1- tab1 load FAILED", ret); + return ret; + } + + ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab2); //[ w 1C 0074 ] + if(!ret) + { + _debug("2- tab2 load FAILED", ret); + return ret; + } + + ret = tef665x_patch_load(i2c_file_desc, pPatchBytes, patchSize); //table1 + if(!ret) + { + _debug("3- pPatchBytes load FAILED", ret); + return ret; + } + + ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ] + if(!ret) + { + _debug("4- tab1 load FAILED", ret); + return ret; + } + + ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab3); //[ w 1C 0075 ] + if(!ret) + { + _debug("5- tab3 load FAILED", ret); + return ret; + } + + ret = tef665x_patch_load(i2c_file_desc, pLutBytes, lutSize); //table2 + if(!ret) + { + _debug("6- pLutBytes load FAILED", ret); + return ret; + } + + ret = tef665x_writeTab(i2c_file_desc, tef665x_patch_cmdTab1); //[ w 1C 0000 ] + if(!ret) + { + _debug("7- tab1 load FAILED", ret); + return ret; + } + _debug("patch loaded", ret); + return ret; +} + +//Command start will bring the device into? idle state�: [ w 14 0001 ] +static int tef665x_start_cmd(int i2c_file_desc) +{ + + int ret; + unsigned char buf[3]; + + buf[0] = 0x14; + buf[1] = 0; + buf[2] = 1; + + ret = write(i2c_file_desc, buf, 3); + + if (ret != 3) + { + _debug("start cmd FAILED", 0); + return 0; + } + _debug("return true", 1); + return 1; +} + +static int tef665x_boot_state(int i2c_file_desc) +{ + int ret=0; + if(1 == tef665x_patch_init(i2c_file_desc)) + { + _debug("return true", 1); + } + else + { + _debug("return value", 0); + return 0; + } + + usleep(50000); + + if(1 == tef665x_start_cmd(i2c_file_desc)) + { + _debug("'start cmd'return true", 1); + } + else + { + _debug("return value", 0); + return 0; + } + + usleep(50000); + + return ret; +} + +/* +module 64 APPL +cmd 4 Set_ReferenceClock frequency + +index +1 frequency_high + [ 15:0 ] + MSB part of the reference clock frequency + [ 31:16 ] +2 frequency_low + [ 15:0 ] + LSB part of the reference clock frequency + [ 15:0 ] + frequency [*1 Hz] (default = 9216000) +3 type + [ 15:0 ] + clock type + 0 = crystal oscillator operation (default) + 1 = external clock input operation +*/ +static int tef665x_appl_set_referenceClock(uint i2c_file_desc, ushort frequency_high, ushort frequency_low, ushort type) +{ + return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL, + TEF665X_Cmd_Set_ReferenceClock, + 11, + frequency_high, frequency_low, type); +} + +static int appl_set_referenceClock(uint i2c_file_desc, uint frequency, bool is_ext_clk) //0x3d 0x900 +{ + return tef665x_appl_set_referenceClock(i2c_file_desc,(ushort)(frequency >> 16), (ushort)frequency, is_ext_clk); +} + +/* +module 64 APPL +cmd 5 Activate mode + +index +1 mode + [ 15:0 ] + 1 = goto �active� state with operation mode of �radio standby� +*/ +static int tef665x_appl_activate(uint i2c_file_desc ,ushort mode) +{ + return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL, + TEF665X_Cmd_Activate, + 5, + mode); +} + +static int appl_activate(uint i2c_file_desc) +{ + return tef665x_appl_activate(i2c_file_desc, 1); +} +/* +module 48 AUDIO +cmd 22 set_dig_io signal, format, operation, samplerate + +index +1 signal +[ 15:0 ] + digital audio input / output + 32 = I²S digital audio IIS_SD_0 (input) + 33 = I²S digital audio IIS_SD_1 (output) +(2) mode + 0 = off (default) + 1 = input (only available for signal = 32) + 2 = output (only available for signal = 33) +(3) format + [ 15:0 ] + digital audio format select + 16 = I²S 16 bits (fIIS_BCK = 32 * samplerate) + 32 = I²S 32 bits (fIIS_BCK = 64 * samplerate) (default) + 272 = lsb aligned 16 bit (fIIS_BCK = 64 * samplerate) + 274 = lsb aligned 18 bit (fIIS_BCK = 64 * samplerate) + 276 = lsb aligned 20 bit (fIIS_BCK = 64 * samplerate) + 280 = lsb aligned 24 bit (fIIS_BCK = 64 * samplerate) +(4) operation + [ 15:0 ] + operation mode + 0 = slave mode; IIS_BCK and IIS_WS input defined by source (default) + 256 = master mode; IIS_BCK and IIS_WS output defined by device +(5) samplerate + [ 15:0 ] 3200 = 32.0 kHz + 4410 = 44.1 kHz (default) + 4800 = 48.0 kHz +*/ +static int tef665x_audio_set_dig_io(u8 i2c_file_desc, ushort signal, ushort mode, ushort format, ushort operation, ushort samplerate) +{ + int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO, + TEF665X_Cmd_Set_Dig_IO, + 15, + signal, mode, format, operation, samplerate); + if(ret) + { + _debug("Digital In/Out is set ", signal); + } + else + { + _debug("FAILED, return", 0); + return 0; + } + return 1; +} + +/* +module 32 / 33 FM / AM +cmd 85 Set_Specials ana_out, dig_out + +index +1 signal + [ 15:0 ] + analog audio output + 128 = DAC L/R output +2 mode + [ 15:0 ] + output mode + 0 = off (power down) + 1 = output enabled (default) +*/ + +static int tef665x_audio_set_ana_out(uint i2c_file_desc, ushort signal,ushort mode) +{ + int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO, + TEF665X_Cmd_Set_Ana_Out, + 7, + signal, mode); + if(ret) + { + _debug("analog output is set to ", mode); + } + else + { + _debug("FAILED, return", 0); + return 0; + } + return 1; + +} + +/* +module 48 AUDIO +cmd 13 Set_Output_Source + +index +1 signal + [ 15:0 ] + audio output + 33 = I2S Digital audio + 128 = DAC L/R output (default) +2 source + [ 15:0 ] + source + 4 = analog radio + 32 = i2s digital audio input + 224 = audio processor (default) + 240 = sin wave generator +*/ +static int tef665x_set_output_src(uint i2c_file_desc, u8 signal, u8 src) +{ + int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO, + TEF665X_Cmd_Set_Output_Source, + 7, + signal, src); + if(ret) + { + _debug("Output is set ", signal); + } + else + { + _debug("FAILED, return", 0); + return 0; + } + return 1; +} + +static int tef665x_idle_state(int i2c_file_desc) +{ + TEF665x_STATE status; + + //mdelay(50); + + if(SET_SUCCESS == get_operation_status(i2c_file_desc, &status)) + { + _debug("got operation status", 1); + if(status != eDevTEF665x_Boot_state) + { + _debug("not in boot status", 1); + + if(SET_SUCCESS == appl_set_referenceClock(i2c_file_desc, TEF665x_REF_CLK, TEF665x_IS_CRYSTAL_CLK)) //TEF665x_IS_EXT_CLK + { + _debug("set the clock", TEF665x_REF_CLK); + if(SET_SUCCESS == appl_activate(i2c_file_desc))// APPL_Activate mode = 1.[ w 40 05 01 0001 ] + { + //usleep(100000); //Wait 100 ms + _debug("activate succeed", 1); + return 1; + } + else + { + _debug("activate FAILED", 1); + } + } + else + { + _debug("set the clock FAILED", TEF665x_REF_CLK); + } + + } + else + { + _debug("did not get operation status", 0); + } + + } + _debug("return value", 0); + return 0; +} + +static int tef665x_para_load(uint i2c_file_desc) +{ + int i; + int r; + const u8 *p = init_para; + + for(i = 0; i < sizeof(init_para); i += (p[i]+1)) + { + if(SET_SUCCESS != (r = tef665x_writeTab(i2c_file_desc, p + i))) + { + break; + } + } + + _debug("return value", r); + return r; +} + +/* +module 32 / 33 FM / AM +cmd 1 Tune_To mode, frequency + +index +1 mode + [ 15:0 ] + tuning actions + 0 = no action (radio mode does not change as function of module band) + 1 = Preset Tune to new program with short mute time + 2 = Search Tune to new program and stay muted + FM 3 = AF-Update Tune to alternative frequency, store quality + and tune back with inaudible mute + 4 = Jump Tune to alternative frequency with short + inaudible mute + 5 = Check Tune to alternative frequency and stay + muted + AM 3 � 5 = reserved + 6 = reserved + 7 = End Release the mute of a Search or Check action + (frequency is not required and ignored) +2 frequency +[ 15:0 ] + tuning frequency + FM 6500 � 10800 65.00 � 108.00 MHz / 10 kHz step size + AM LW 144 � 288 144 � 288 kHz / 1 kHz step size + MW 522 � 1710 522 � 1710 kHz / 1 kHz step size + SW 2300 � 27000 2.3 � 27 MHz / 1 kHz step size +*/ +static int tef665x_radio_tune_to (uint i2c_file_desc, bool fm, ushort mode,ushort frequency ) +{ + return tef665x_set_cmd(i2c_file_desc, fm ? TEF665X_MODULE_FM: TEF665X_MODULE_AM, + TEF665X_Cmd_Tune_To, + ( mode <= 5 ) ? 7 : 5, + mode, frequency); +} + +static int FM_tune_to(uint i2c_file_desc, AR_TuningAction_t mode, ushort frequency) +{ + int ret = tef665x_radio_tune_to(i2c_file_desc, 1, (ushort)mode, frequency); + _debug("return value", ret); + return ret; +} + +static int AM_tune_to(uint i2c_file_desc, AR_TuningAction_t mode,ushort frequency) +{ + int ret = tef665x_radio_tune_to(i2c_file_desc, 0, (ushort)mode, frequency); + _debug("return value", ret); + return ret; +} + +/* +module 48 AUDIO +cmd 11 Set_Mute mode + +index +1 mode + [ 15:0 ] + audio mute + 0 = mute disabled + 1 = mute active (default) +*/ +int tef665x_audio_set_mute(uint i2c_file_desc, ushort mode) +{ + int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO, + TEF665X_Cmd_Set_Mute, + 5, + mode); + if(ret) + { + _debug("mute state changed , mode", mode); + } + else + { + _debug("FAILED, return", 0); + return 0; + } + return 1; +} + +/* +module 48 AUDIO +cmd 10 Set_Volume volume + +index +1 volume + [ 15:0 ] (signed) + audio volume + -599 � +240 = -60 � +24 dB volume + 0 = 0 dB (default)f665x_patch_init function: "3"t,int16_t volume) +*/ +static int tef665x_audio_set_volume(uint i2c_file_desc, ushort volume) +{ + return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO, + TEF665X_Cmd_Set_Volume, + 5, + volume*10); +} +/* +module 64 APPL +cmd 130 Get_Identification +index +1 device +2 hw_version +3 sw_version +*/ +int appl_get_identification(int i2c_file_desc) +{ + u8 buf[6]; + int ret; + + ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_APPL, + TEF665X_Cmd_Get_Identification, + buf, sizeof(buf)); +// should be completed for further use +// extracting chip versions ... + if(ret == SET_SUCCESS) + { + for(int i = 0; i<6;i++) + printf("buf[%i] = %x\n", i, buf[i]); + return 1; + } + _debug("return value", 0); + return 0; +} + + +//mute=1, unmute=0 +int audio_set_mute(uint i2c_file_desc, bool mute) +{ + return tef665x_audio_set_mute(i2c_file_desc, mute);//AUDIO_Set_Mute mode = 0 : disable mute +} + +//-60 � +24 dB volume +int audio_set_volume(uint i2c_file_desc, int vol) +{ + return tef665x_audio_set_volume(i2c_file_desc, (ushort)vol); +} + +/* +module 64 APPL +cmd 1 Set_OperationMode mode + +index +1 mode + [ 15:0 ] + device operation mode + 0 = normal operation + 1 = radio standby mode (low-power mode without radio functionality) + (default) +*/ + +static int tef665x_audio_set_operationMode(uint i2c_file_desc, ushort mode) +{ + _debug("normal: 0 standby: 1 requested", 1); + int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL, + TEF665X_Cmd_Set_OperationMode, + 5, + mode); + if(ret) + { + _debug("was able to set the mode", ret); + } + else + { + _debug("FAILED, return", 0); + return 0; + } + return 1; +} + + + +//TRUE = ON; +//FALSE = OFF +static void radio_powerSwitch(uint i2c_file_desc, bool OnOff) +{ + tef665x_audio_set_operationMode(i2c_file_desc, OnOff? 0 : 1);//standby mode = 1 +} + +static void radio_modeSwitch(uint i2c_file_desc, bool mode_switch, AR_TuningAction_t mode, ushort frequency) +{ + + if(mode_switch) //FM + { + FM_tune_to(i2c_file_desc, mode, frequency); + } + else //AM + { + AM_tune_to(i2c_file_desc, mode, frequency); + } +} + +static int tef665x_wait_active(uint i2c_file_desc) +{ + TEF665x_STATE status; + //usleep(50000); + if(SET_SUCCESS == appl_get_operation_status(i2c_file_desc, &status)) + { + AFB_INFO("got status", 1); + if((status != eDevTEF665x_Boot_state) && (status != eDevTEF665x_Idle_state)) + { + AFB_INFO("active status", 1); + + if(SET_SUCCESS == tef665x_para_load(i2c_file_desc)) + { + _debug("parameters loaded", 1); + } + else + { + _debug("parameters not loaded", 0); + return 0; + } + + if(current_band == BAND_FM){ + FM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_fm_frequency / 10000);// tune to min + } else { + AM_tune_to(i2c_file_desc, eAR_TuningAction_Preset, current_am_frequency / 1000);// tune to min + } + + if(SET_SUCCESS == audio_set_mute(i2c_file_desc, 1))//unmute=0 + { + _debug("muted", 1); + } + else + { + _debug("not muted", 0); + return 0; + } + + if(SET_SUCCESS == audio_set_volume(i2c_file_desc, 23))//set to -10db + { + _debug("set vol to", 25); + } + else + { + _debug("vol not set", 0); + return 0; + } + return 1; + } + } + + return 0; +} + +static void tef665x_chip_init(int i2c_file_desc) +{ + if(1 == tef665x_power_on(i2c_file_desc)) _debug("tef665x_power_on", 1); + usleep(50000); + if(1 == tef665x_boot_state(i2c_file_desc)) _debug("tef665x_boot_state", 1); + usleep(100000); + if(1 == tef665x_idle_state(i2c_file_desc)) _debug("tef665x_idle_state", 1); + usleep(200000); + if(1 == tef665x_wait_active(i2c_file_desc)) _debug("tef665x_wait_active", 1); + //if you want to use analog output comment below command, or pass 1 to it. + if(SET_SUCCESS != tef665x_audio_set_ana_out(i2c_file_desc, TEF665X_Cmd_Set_Output_signal_dac, 0)) + { + _debug("Set DAC to OFF failed", 0); + //return 0; + } + + if(SET_SUCCESS != tef665x_set_output_src(i2c_file_desc, TEF665X_Cmd_Set_Output_signal_i2s, + TEF665X_Cmd_Set_Output_source_aProcessor)) + { + _debug("Set output failed", 0); + //return 0; + } + //this is needed to use digital output + if(SET_SUCCESS != tef665x_audio_set_dig_io(i2c_file_desc, TEF665X_AUDIO_CMD_22_SIGNAL_i2s1, + TEF665X_AUDIO_CMD_22_MODE_voltage, + TEF665X_AUDIO_CMD_22_FORMAT_16, + TEF665X_AUDIO_CMD_22_OPERATION_slave, + TEF665X_AUDIO_CMD_22_SAMPLERATE_48K)) + { + _debug("Setup i2s failed", 0); + //return 0; + } + + +} + + +static int i2c_init(const char *i2c, int state, uint *i2c_file_desc) +{ + int fd, t; + + if(state == _open) + { + fd = open(i2c, O_RDWR); + + if(fd < 0) + { + _debug("could not open %s", i2c); + return fd; + } + + t = ioctl(fd, I2C_SLAVE, I2C_ADDRESS); + if (t < 0) + { + _debug("could not set up slave ", 0); + return t; + } + *i2c_file_desc = fd; + } + else + { + close(*i2c_file_desc); + } + + return 0; +} + +static void tef665x_start(void) +{ + int ret; + if(!present) + return; + + _debug("file_desc ", file_desc); + + audio_set_mute(file_desc, 0); + + if(!running) { + + // Start pipeline + ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); + _debug("gst_element_set_state to play", ret); + running = true; + } + } + +static void tef665x_stop(void) +{ + int ret; + GstEvent *event; + audio_set_mute(file_desc, 1); + + if(present && running) { + // Stop pipeline + running = false; + ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); + _debug("gst_element_set_state to pause", ret); + + // Flush pipeline + // This seems required to avoidstatic stutters on starts after a stop + event = gst_event_new_flush_start(); + gst_element_send_event(GST_ELEMENT(pipeline), event); + event = gst_event_new_flush_stop(TRUE); + gst_element_send_event(GST_ELEMENT(pipeline), event); + } +} + +static int tef665x_init() +{ + char gst_pipeline_str[GST_PIPELINE_LEN]; + int rc; + int ret = i2c_init(I2C_DEV, _open, &file_desc); + + current_am_frequency = known_am_band_plans[am_bandplan].min; + current_fm_frequency = known_fm_band_plans[fm_bandplan].min; + + _debug("file_desc= ", file_desc); + + ret = appl_get_identification(file_desc); + if(ret != 1){ + AFB_ERROR("no tef665x!"); + return -1; + } + + current_band = BAND_AM; + + radio_powerSwitch(file_desc, 1); + + tef665x_chip_init(file_desc); + + // Initialize GStreamer + gst_init(NULL, NULL); + + // Use PipeWire output + // This pipeline is working on imx6solo, the important thing, up to now, is that it gets xrun error every few seconds. + // I believe it's related to wireplumber on imx6. + rc = snprintf(gst_pipeline_str, + GST_PIPELINE_LEN, + "alsasrc ! audioconvert ! audioresample ! audio/x-raw, rate=(int)48000, channels=(int)2 \ + ! pwaudiosink stream-properties=\"p,media.role=Multimedia\" latency-time=(int)35000"); + + if(rc >= GST_PIPELINE_LEN) { + AFB_ERROR("pipeline string too long"); + return -1; + } + printf("pipeline: , %s\n", gst_pipeline_str); + + pipeline = gst_parse_launch(gst_pipeline_str, NULL); + if(!pipeline) { + AFB_ERROR("pipeline construction failed!"); + return -1; + } + + // Start pipeline in paused state + ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); + _debug("gst_element_set_state to pause (at the begining)", ret); + + ret = gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL); + _debug("gst_bus_add_watch ret", ret); + + present = true; + + return 0; +} + +static void tef665x_set_frequency_callback(radio_freq_callback_t callback, + void *data) +{ + //freq_callback = callback; + //freq_callback_data = data; +} +static void tef665x_set_output(const char *output) +{ +} + +static radio_band_t tef665x_get_band(void) +{ + _debug("band", current_band); + return current_band; +} + +static void tef665x_set_band(radio_band_t band) +{ + uint fd; + int ret = i2c_init(I2C_DEV, _open, &fd); + + _debug("i2c_init ret value", ret); + + if(band == BAND_FM){ + current_band = band; + FM_tune_to(fd, eAR_TuningAction_Preset, current_fm_frequency / 10000); + } else { + current_band = band; + AM_tune_to(fd, eAR_TuningAction_Preset, current_am_frequency / 1000); + } + + i2c_init(I2C_DEV, _close, &fd); + + _debug("band", current_band); +} + +static uint32_t tef665x_get_frequency(void) +{ + if(current_band == BAND_FM){ + return current_fm_frequency; + } else { + return current_am_frequency; + } +} + +static void tef665x_set_frequency(uint32_t frequency) +{ + uint fd, f; + int ret = i2c_init(I2C_DEV, _open, &fd); + + _debug("i2c_init ret value", ret); + + if(!present) + return; + + if(scanning) + return; + + if(current_band == BAND_FM) { + if(frequency < known_fm_band_plans[fm_bandplan].min || + frequency > known_fm_band_plans[fm_bandplan].max ) { + _debug("invalid FM frequency", frequency); + return; + } + } else { + if(frequency < known_am_band_plans[am_bandplan].min || + frequency > known_am_band_plans[am_bandplan].max ) { + _debug("invalid AM frequency", frequency); + return; + } + } + + //tef665x_scan_stop(); + + if(current_band == BAND_FM){ + current_fm_frequency = frequency; + _debug("frequency set to FM :", frequency); + FM_tune_to(fd, eAR_TuningAction_Preset, frequency / 10000); + } else { + current_am_frequency = frequency; + _debug("frequency set to AM :", frequency); + AM_tune_to(fd, eAR_TuningAction_Preset, frequency / 1000); + } + + + + //freq_callback(current_frequency, freq_callback_data); + + i2c_init(I2C_DEV, _close, &fd); +} + +static int tef665x_band_supported(radio_band_t band) +{ + if(band == BAND_FM || band == BAND_AM) + return 1; + return 0; +} + +static uint32_t tef665x_get_min_frequency(radio_band_t band) +{ + if(band == BAND_FM) { + return known_fm_band_plans[fm_bandplan].min; + } else { + return known_am_band_plans[am_bandplan].min; + } +} + +static uint32_t tef665x_get_max_frequency(radio_band_t band) +{ + if(band == BAND_FM) { + return known_fm_band_plans[fm_bandplan].max; + } else { + return known_am_band_plans[am_bandplan].max; + } +} + +static uint32_t tef665x_get_frequency_step(radio_band_t band) +{ + uint32_t ret = 0; + + switch (band) { + case BAND_AM: + ret = known_am_band_plans[am_bandplan].step; + break; + case BAND_FM: + ret = known_fm_band_plans[fm_bandplan].step; + break; + default: + break; + } + return ret; +} +radio_impl_ops_t tef665x_impl_ops = { + .name = "TEF665x", + .init = tef665x_init, + .start = tef665x_start, + .stop = tef665x_stop, + .set_output = tef665x_set_output, + .get_frequency = tef665x_get_frequency, + .set_frequency = tef665x_set_frequency, + .set_frequency_callback = tef665x_set_frequency_callback, + .get_band = tef665x_get_band, + .set_band = tef665x_set_band, + .band_supported = tef665x_band_supported, + .get_min_frequency = tef665x_get_min_frequency, + .get_max_frequency = tef665x_get_max_frequency, + .get_frequency_step = tef665x_get_frequency_step, + /*.scan_start = tef665x_scan_start, + .scan_stop = tef665x_scan_stop, + .get_stereo_mode = tef665x_get_stereo_mode, + .set_stereo_mode = tef665x_set_stereo_mode, + .get_rds_info = tef665x_get_rds_info*/ +}; diff --git a/binding/radio_impl_tef665x.h b/binding/radio_impl_tef665x.h new file mode 100644 index 0000000..a95fd99 --- /dev/null +++ b/binding/radio_impl_tef665x.h @@ -0,0 +1,23 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _RADIO_IMPL_TEF665X_H +#define _RADIO_IMPL_TEF665X_H + +#include "radio_impl.h" + +extern radio_impl_ops_t tef665x_impl_ops; + + +#endif /* _RADIO_IMPL_TEF665X_H */ + diff --git a/binding/tef665x.h b/binding/tef665x.h new file mode 100644 index 0000000..add145b --- /dev/null +++ b/binding/tef665x.h @@ -0,0 +1,375 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef TEF665X_H +#define TEF665X_H + +typedef uint8_t u8; +typedef uint16_t ushort; +typedef uint32_t uint; + +typedef enum +{ +_close = 0, +_open +} I2C_STATE; + +typedef enum +{ + TEF665X_MODULE_FM = 0x20, //32 + TEF665X_MODULE_AM = 0x21, //31 + TEF665X_MODULE_AUDIO = 0x30, //48 + TEF665X_MODULE_APPL = 0x40 //64 +} TEF665x_MODULE; + +enum { + TEF6657_CMD_tune = 0, + TEF6657_CMD_open = 1, + TEF6657_CMD_close = 2, + TEF6657_CMD_am = 3, + TEF6657_CMD_fm = 4, + TEF6657_CMD_GETamSTAUS = 5, + TEF6657_CMD_GETfmSTAUS = 6, + TEF6657_CMD_GEToirtSTAUS +}; + +enum +{ + RADIO_BOOT_STATE = 0, + RADIO_IDLE_STATE, + RADIO_STANBDY_STATE, + RADIO_FM_STATE, + RADIO_AM_STATE + +}; + +typedef enum +{ + TEF665X_Cmd_Set_OperationMode = 0x01, + TEF665X_Cmd_Set_GPIO = 0x03, + TEF665X_Cmd_Set_ReferenceClock = 0x04, + TEF665X_Cmd_Activate = 0x05, + + TEF665X_Cmd_Get_Operation_Status = 0x80, //128, + TEF665X_Cmd_Get_GPIO_Status = 0x81, //129, + TEF665X_Cmd_Get_Identification = 0x82, //130, + TEF665X_Cmd_Get_LastWrite = 0x83, //131 +} TEF665x_APPL_COMMAND; + +typedef enum +{ + TEF665X_Cmd_Tune_To = 0x01, + TEF665X_Cmd_Set_Tune_Options =0x02, + TEF665X_Cmd_Set_Bandwidth =0x0A, //10, + TEF665X_Cmd_Set_RFAGC =0x0B, //11, + TEF665X_Cmd_Set_Antenna =0x0C, //12, + + TEF665X_Cmd_Set_MphSuppression =0x14, //20, + TEF665X_Cmd_Set_NoiseBlanker =0x17, //23, + TEF665X_Cmd_Set_NoiseBlanker_Audio =0x18, //24, + + TEF665X_Cmd_Set_DigitalRadio =0x1E, //30, + TEF665X_Cmd_Set_Deemphasis =0x1F, //31, + + TEF665X_Cmd_Set_LevelStep = 0x26, //38, + TEF665X_Cmd_Set_LevelOffset = 0x27, //39, + + TEF665X_Cmd_Set_Softmute_Time =0x28, //40, + TEF665X_Cmd_Set_Softmute_Mod = 0x29, //41, + TEF665X_Cmd_Set_Softmute_Level =0x2A, //42, + TEF665X_Cmd_Set_Softmute_Noise =0x2B, //43, + TEF665X_Cmd_Set_Softmute_Mph =0x2C, //44, + TEF665X_Cmd_Set_Softmute_Max =0x2D, //45, + + TEF665X_Cmd_Set_Highcut_Time =0x32, //50, + TEF665X_Cmd_Set_Highcut_Mod = 0x33, //51, + TEF665X_Cmd_Set_Highcut_Level =0x34, //52, + TEF665X_Cmd_Set_Highcut_Noise = 0x35, //53, + TEF665X_Cmd_Set_Highcut_Mph =0x36, //54, + TEF665X_Cmd_Set_Highcut_Max =0x37, //55, + TEF665X_Cmd_Set_Highcut_Min =0x38, //56, + TEF665X_Cmd_Set_Lowcut_Min =0x3A, //58, + + TEF665X_Cmd_Set_Stereo_Time =0x3C, //60, + TEF665X_Cmd_Set_Stereo_Mod =0x3D, //61, + TEF665X_Cmd_Set_Stereo_Level =0x3E, //62, + TEF665X_Cmd_Set_Stereo_Noise = 0x3F, //63, + TEF665X_Cmd_Set_Stereo_Mph =0x40, //64, + TEF665X_Cmd_Set_Stereo_Max = 0x41, //65, + TEF665X_Cmd_Set_Stereo_Min = 0x42, //66, + + TEF665X_Cmd_Set_Scaler = 0x50, //80, + TEF665X_Cmd_Set_RDS = 0x51, //81, + TEF665X_Cmd_Set_QualityStatus = 0x52, //82, + TEF665X_Cmd_Set_DR_Blend = 0x53, //83, + TEF665X_Cmd_Set_DR_Options = 0x54, //84, + TEF665X_Cmd_Set_Specials = 0x55, //85, + + TEF665X_Cmd_Get_Quality_Status = 0x80, //128, + TEF665X_Cmd_Get_Quality_Data = 0x81, //129, + TEF665X_Cmd_Get_RDS_Status = 0x82, //130, + TEF665X_Cmd_Get_RDS_Data = 0x83, //131, + TEF665X_Cmd_Get_AGC = 0x84, //132, + TEF665X_Cmd_Get_Signal_Status = 0x85, //133, + TEF665X_Cmd_Get_Processing_Status = 0x86, //134, + TEF665X_Cmd_Get_Interface_Status = 0x87, //135, + + TEF665X_Cmd_Set_Output_signal_i2s = 0x21, //33, + TEF665X_Cmd_Set_Output_signal_dac = 0x80, //128, + TEF665X_Cmd_Set_Output_source_aRadio = 0x04, //4, + TEF665X_Cmd_Set_Output_source_dInput = 0x20, //32, + TEF665X_Cmd_Set_Output_source_aProcessor = 0xe0, //224, + TEF665X_Cmd_Set_Output_source_SinWave = 0xf0, //240, + } TEF665x_RADIO_COMMAND; + +typedef enum +{ + TEF665X_Cmd_Set_Volume = 0x0A, //10, + TEF665X_Cmd_Set_Mute = 0x0B, //11, + TEF665X_Cmd_Set_Input = 0x0C, //12, + TEF665X_Cmd_Set_Output_Source = 0x0D, //13, + + TEF665X_Cmd_Set_Ana_Out = 0x15, //21, + TEF665X_Cmd_Set_Dig_IO = 0x16, //22, + TEF665X_Cmd_Set_Input_Scaler = 0x17, //23, + TEF665X_Cmd_Set_WaveGen = 0x18, //24 +} TEF665x_AUDIO_COMMAND; + +typedef enum +{ + TEF665X_AUDIO_CMD_22_SIGNAL_i2s1 = 0x21, //33, + TEF665X_AUDIO_CMD_22_MODE_voltage = 0x02, //2, + TEF665X_AUDIO_CMD_22_FORMAT_16 = 0x10, //16, + TEF665X_AUDIO_CMD_22_FORMAT_32 = 0x20, //32, + TEF665X_AUDIO_CMD_22_OPERATION_slave = 0, //0, + TEF665X_AUDIO_CMD_22_OPERATION_master = 0x0100,//256, + TEF665X_AUDIO_CMD_22_SAMPLERATE_48K = 0x12c0 //4800 +} TEF665x_AUDIO_CMD_22; + +typedef enum{ + eDevTEF665x_Power_on, + eDevTEF665x_Boot_state , + eDevTEF665x_Idle_state, + eDevTEF665x_Wait_Active, + eDevTEF665x_Active_state, + + eDevTEF665x_Not_Exist, + + eDevTEF665x_Last +}TEF665x_STATE; + +const u8 patchByteValues[]= +{ + 0xF0, 0x00, 0x38, 0x16, 0xD0, 0x80, 0x43, 0xB2, 0x38, 0x1D, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xC2, 0xF7, 0xF0, 0x00, 0x38, 0x4E, 0xD0, 0x80, + 0xF0, 0x00, 0x38, 0xF1, 0xD0, 0x80, 0xC4, 0xA2, 0x02, 0x0C, 0x60, 0x04, 0x90, 0x01, 0x39, 0x07, 0xD0, 0x80, 0xF0, 0x00, 0x38, 0xD3, 0xD0, 0x80, + 0xF0, 0x00, 0x39, 0x0E, 0xD2, 0x80, 0xF0, 0x00, 0x39, 0x12, 0xD0, 0x80, 0x40, 0x20, 0x39, 0x1E, 0xD0, 0x80, 0x9E, 0x30, 0x18, 0xF9, 0xD2, 0x80, + 0xF0, 0x00, 0x39, 0x20, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x23, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x38, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x3B, 0xD0, 0x80, + 0x00, 0x43, 0x39, 0x43, 0xD9, 0x80, 0xF0, 0x00, 0x39, 0x46, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x60, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x71, 0xD0, 0x80, + 0xF0, 0x00, 0x39, 0x7F, 0xD0, 0x80, 0xF0, 0x00, 0x39, 0x82, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x14, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0xD4, + 0xF0, 0x00, 0x70, 0x00, 0xA0, 0xDB, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x0C, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x12, 0xF0, 0x00, 0x70, 0x00, 0xA1, 0x2D, + 0xF0, 0x00, 0x20, 0x31, 0xD0, 0x80, 0x00, 0x7F, 0x60, 0x02, 0xE2, 0x00, 0xF0, 0x00, 0x0E, 0x22, 0x60, 0x0A, 0xF0, 0x00, 0x00, 0xFF, 0x60, 0x03, + 0xF0, 0x00, 0x01, 0x42, 0xD2, 0x80, 0x90, 0x03, 0x40, 0x02, 0xF0, 0x00, 0x90, 0x43, 0x01, 0x70, 0xD1, 0x80, 0xF0, 0x00, 0x01, 0x69, 0xD0, 0x80, + 0x0E, 0x69, 0x60, 0x0A, 0xA1, 0x60, 0x20, 0x23, 0x00, 0x01, 0x60, 0x01, 0xF0, 0x00, 0x70, 0x00, 0xF0, 0x00, 0xC4, 0xCB, 0x70, 0x00, 0xF0, 0x00, + 0xCA, 0x09, 0x30, 0x23, 0xF0, 0x00, 0xC2, 0xCB, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x23, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x50, 0x60, 0x08, + 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x09, 0x30, 0x00, 0x21, 0x80, 0x60, 0x01, 0xF0, 0x00, 0x40, 0x32, 0xF0, 0x00, 0x30, 0x11, 0x45, 0xF3, 0xF0, 0x00, + 0x30, 0x92, 0x2D, 0x30, 0x60, 0x04, 0x31, 0x13, 0x2D, 0x40, 0x60, 0x05, 0x31, 0x94, 0x7F, 0xFF, 0x60, 0x06, 0x32, 0x15, 0x0D, 0x61, 0x60, 0x0A, + 0x32, 0x96, 0x0D, 0x6B, 0x60, 0x0B, 0x33, 0x10, 0x0D, 0x50, 0x60, 0x01, 0x33, 0x90, 0x0D, 0x5C, 0x60, 0x02, 0x30, 0x21, 0x0D, 0x63, 0x60, 0x03, + 0x30, 0x31, 0x0D, 0x75, 0x60, 0x0C, 0x30, 0xA2, 0x8D, 0x00, 0x60, 0x01, 0x30, 0xB3, 0x01, 0x73, 0x60, 0x02, 0x30, 0x41, 0x00, 0x25, 0x60, 0x03, + 0x30, 0xC2, 0x40, 0x44, 0xF0, 0x00, 0x31, 0x43, 0x40, 0x35, 0xF0, 0x00, 0x31, 0xC4, 0x64, 0x00, 0x60, 0x06, 0x32, 0x45, 0x1F, 0x40, 0x60, 0x07, + 0x32, 0xC6, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x47, 0x1E, 0xBC, 0x60, 0x0D, 0x33, 0xC0, 0x01, 0x22, 0x60, 0x01, 0x34, 0x40, 0xFD, 0xEE, 0x60, 0x02, + 0x30, 0x51, 0x7B, 0x8F, 0x60, 0x03, 0x30, 0xD2, 0xC4, 0x29, 0x60, 0x04, 0x31, 0x51, 0x1E, 0xC2, 0x60, 0x0E, 0x32, 0x53, 0xFF, 0x0D, 0x60, 0x02, + 0x32, 0xD4, 0x7D, 0x2E, 0x60, 0x03, 0x30, 0x61, 0xC1, 0x9A, 0x60, 0x04, 0x30, 0xE2, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x61, 0x70, 0x00, 0xF0, 0x00, + 0x32, 0x63, 0x70, 0x00, 0xF0, 0x00, 0x32, 0xE4, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x03, 0x70, 0xD2, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x02, + 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x59, 0xF0, 0x00, 0x02, 0x15, 0xD0, 0x80, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x0F, 0xF0, 0x00, 0x05, 0x17, 0x60, 0x0E, + 0x23, 0xF6, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x21, 0x63, 0x41, 0xF5, 0x91, 0x8F, 0x21, 0xF8, 0x40, 0x74, 0xC3, 0xEF, 0x21, 0xE0, 0xF0, 0x00, + 0xC3, 0xA4, 0x33, 0xF7, 0xF0, 0x00, 0xD8, 0x5B, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x18, 0x70, 0x00, 0xF0, 0x00, 0x9F, 0xAF, 0x18, 0x00, 0xF0, 0x00, + 0x9F, 0x0F, 0x31, 0xF8, 0x90, 0x02, 0xF0, 0x00, 0x70, 0x00, 0x90, 0x28, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x22, 0x78, 0xF0, 0x00, + 0x16, 0xD3, 0x60, 0x09, 0xA0, 0x7F, 0x35, 0xF0, 0x1E, 0xBC, 0x60, 0x0D, 0xF0, 0x00, 0x0D, 0x61, 0x60, 0x08, 0xF0, 0x00, 0x03, 0xA5, 0xD2, 0x80, + 0xF0, 0x00, 0x1E, 0xC2, 0x60, 0x0D, 0xF0, 0x00, 0x0D, 0x6B, 0x60, 0x08, 0xF0, 0x00, 0x03, 0xA5, 0xD2, 0x80, 0xF0, 0x00, 0x21, 0x00, 0xF0, 0x00, + 0x83, 0x6D, 0x22, 0xF1, 0xF0, 0x00, 0xF0, 0x00, 0x23, 0x77, 0xF0, 0x00, 0x90, 0x41, 0x36, 0x70, 0xF0, 0x00, 0x9E, 0x79, 0x70, 0x00, 0x90, 0x01, + 0xF0, 0x00, 0x32, 0xF1, 0xD0, 0x08, 0x91, 0xC7, 0x33, 0x75, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0x70, 0xE6, 0x00, 0xF0, 0x00, 0x34, 0xF0, 0xE6, 0x00, + 0xF0, 0x00, 0x24, 0x74, 0xF0, 0x00, 0xF0, 0x00, 0x24, 0xF3, 0xF0, 0x00, 0x8C, 0x24, 0x26, 0xF2, 0x40, 0x16, 0x8A, 0x1B, 0x34, 0x74, 0x4F, 0xF5, + 0x82, 0xB7, 0x34, 0xF3, 0xF0, 0x00, 0xF0, 0x00, 0x20, 0x71, 0x90, 0x05, 0x83, 0x04, 0x70, 0x00, 0xF0, 0x00, 0x8E, 0x67, 0x70, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0x70, 0x00, 0x90, 0x02, 0xF0, 0x00, 0x36, 0xF6, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0xF0, 0x80, 0x06, 0x82, 0xAF, 0x70, 0x00, 0xF0, 0x00, + 0x82, 0x1B, 0x70, 0x00, 0xD0, 0x09, 0x8E, 0x5F, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x09, 0xF0, 0x00, 0x36, 0xF5, 0xF0, 0x00, + 0xF0, 0x00, 0x34, 0x70, 0xF0, 0x00, 0x40, 0x11, 0x27, 0x72, 0xA1, 0x03, 0x90, 0x8A, 0x20, 0xF3, 0xA1, 0x02, 0x8E, 0xD7, 0x37, 0x72, 0xF0, 0x00, + 0xF0, 0x00, 0x37, 0xF1, 0xE6, 0x00, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x22, 0x7A, 0xF0, 0x00, 0x16, 0xC3, 0x60, 0x09, 0xA0, 0x58, + 0xF0, 0x00, 0x18, 0x20, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0x70, 0xF0, 0x00, 0xF0, 0x00, 0x32, 0x7A, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x51, 0x60, 0x08, + 0x40, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x80, 0x70, 0x00, 0xF0, 0x00, 0x21, 0x06, 0x70, 0x00, 0xF0, 0x00, 0x37, 0x00, 0x70, 0x00, 0xF0, 0x00, + 0x37, 0x80, 0x40, 0x15, 0xF0, 0x00, 0x36, 0x83, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x05, 0x0D, 0x61, 0x60, 0x09, 0x32, 0x86, 0x0D, 0x6B, 0x60, 0x0A, + 0x32, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x32, 0x90, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x90, 0x70, 0x00, 0xF0, 0x00, + 0x34, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x90, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x10, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x90, 0x70, 0x00, 0xF0, 0x00, + 0x32, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x32, 0xA0, 0x70, 0x00, 0xF0, 0x00, 0x33, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x33, 0xA0, 0x70, 0x00, 0xF0, 0x00, + 0x34, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x34, 0xA0, 0x70, 0x00, 0xF0, 0x00, 0x31, 0x20, 0x70, 0x00, 0xF0, 0x00, 0x31, 0xA0, 0x70, 0x00, 0xF0, 0x00, + 0x82, 0x00, 0x0D, 0x30, 0x60, 0x0A, 0x0D, 0x40, 0x60, 0x0B, 0xC0, 0x10, 0xF0, 0x00, 0x10, 0x20, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x0C, 0xC0, 0x10, + 0xF0, 0x00, 0x10, 0x30, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0xC0, 0xD0, 0x08, 0xF0, 0x00, 0x0D, 0x75, 0x60, 0x0F, 0xF0, 0x00, 0x05, 0x63, 0x60, 0x0E, + 0x24, 0xF7, 0x05, 0x1D, 0x60, 0x0D, 0x25, 0x76, 0x70, 0x00, 0xF0, 0x00, 0x91, 0xC7, 0x20, 0xE8, 0x40, 0x15, 0x91, 0x8F, 0x21, 0xE9, 0xD4, 0x09, + 0xC3, 0xEF, 0x20, 0x00, 0x40, 0x12, 0x9F, 0xBE, 0x20, 0x11, 0x58, 0x03, 0xA0, 0x80, 0x35, 0x77, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, + 0xF0, 0x00, 0x21, 0xF5, 0xF0, 0x00, 0xA0, 0xCA, 0x22, 0x54, 0xF0, 0x00, 0xCC, 0x09, 0x05, 0x17, 0x60, 0x0C, 0x83, 0x2C, 0x70, 0x00, 0xF0, 0x00, + 0x8A, 0x61, 0x70, 0x00, 0xF0, 0x00, 0xAE, 0x48, 0x22, 0x45, 0xA0, 0xCB, 0xA2, 0x28, 0x20, 0x78, 0xF0, 0x00, 0xF0, 0x00, 0x35, 0xF0, 0xF0, 0x00, + 0xF0, 0x00, 0x18, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x78, 0xF0, 0x00, 0x16, 0xE3, 0x60, 0x09, 0xA0, 0x27, 0x89, 0x01, 0x23, 0xF4, 0xF0, 0x00, + 0xF0, 0x00, 0x20, 0xF2, 0xF0, 0x00, 0x82, 0x61, 0x21, 0x73, 0xF0, 0x00, 0xA0, 0x50, 0x36, 0x70, 0xF0, 0x00, 0xA0, 0x58, 0x23, 0x72, 0xE1, 0x40, + 0xA8, 0x01, 0x22, 0xF3, 0xF0, 0x00, 0x90, 0x49, 0x22, 0x75, 0xE0, 0x40, 0x80, 0x61, 0x70, 0x00, 0xF0, 0x00, 0x8A, 0x51, 0x33, 0xF1, 0xF0, 0x00, + 0xA0, 0x58, 0x70, 0x00, 0xF0, 0x00, 0xAF, 0x48, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x34, 0x70, 0xD0, 0x08, 0x82, 0x00, 0x0D, 0x75, 0x60, 0x08, + 0x90, 0x09, 0x0D, 0x00, 0x60, 0x09, 0xF0, 0x00, 0x35, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x33, 0x80, 0xC0, 0x28, 0xF0, 0x00, 0x10, 0x10, 0xF0, 0x00, + 0xF0, 0x00, 0x34, 0x81, 0xD0, 0x08, 0x82, 0x49, 0x0D, 0x75, 0x60, 0x08, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFD, 0x04, 0x00, 0x60, 0x00, 0xA0, 0xB1, + 0x8E, 0xC0, 0x40, 0x00, 0x60, 0x05, 0x60, 0x00, 0x60, 0x05, 0xE6, 0x00, 0xC8, 0x1B, 0x70, 0x00, 0xF0, 0x00, 0xD8, 0xDB, 0x0D, 0x51, 0x60, 0x08, + 0x83, 0x5B, 0x70, 0x00, 0xF0, 0x00, 0x9E, 0xBA, 0x30, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x30, 0x84, 0xD4, 0x09, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xAF, + 0xF0, 0x00, 0x0D, 0x75, 0x60, 0x08, 0xF0, 0x00, 0x0D, 0x51, 0x60, 0x09, 0xF0, 0x00, 0x24, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0x27, 0x94, 0xD0, 0x08, + 0xA0, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xC0, 0x0E, 0xA0, 0x09, 0x00, 0x11, 0x08, 0x00, + 0xA0, 0x09, 0x70, 0x00, 0xF0, 0x00, 0xA4, 0x08, 0x70, 0x00, 0xD0, 0x08, 0xA0, 0x03, 0x70, 0x00, 0xF0, 0x00, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x00, + 0x00, 0x11, 0x08, 0x00, 0xC0, 0x26, 0xA0, 0x09, 0x00, 0x11, 0x08, 0x00, 0xA0, 0x09, 0x70, 0x00, 0xF0, 0x00, 0xA4, 0x08, 0x70, 0x00, 0xD0, 0x08, + 0xF0, 0x00, 0x1D, 0x01, 0x60, 0x08, 0xF0, 0x00, 0x0A, 0x2C, 0x60, 0x00, 0xF0, 0x00, 0x01, 0x1A, 0x60, 0x01, 0x31, 0x00, 0x70, 0x00, 0xF0, 0x00, + 0x31, 0x81, 0x70, 0x00, 0xD0, 0x08, 0x10, 0x00, 0x60, 0x03, 0xA0, 0x93, 0x30, 0x23, 0x07, 0x73, 0xD2, 0x80, 0xF0, 0x00, 0x07, 0xC6, 0xD0, 0x80, + 0x40, 0xE0, 0x00, 0x1F, 0x60, 0x01, 0x13, 0xD5, 0x60, 0x07, 0xA0, 0x06, 0x13, 0xFB, 0x60, 0x06, 0xF0, 0x00, 0x90, 0x40, 0x0D, 0x28, 0xD2, 0x80, + 0x14, 0x05, 0x60, 0x06, 0xF0, 0x00, 0xF0, 0x00, 0x0D, 0x28, 0xD2, 0x80, 0x14, 0x0F, 0x60, 0x06, 0xF0, 0x00, 0xF0, 0x00, 0x0D, 0x28, 0xD0, 0x80, + 0xD7, 0xCA, 0x00, 0xFF, 0x60, 0x04, 0x81, 0xD7, 0x0C, 0xF7, 0x60, 0x09, 0xD0, 0x56, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x76, 0x30, 0x17, 0xF0, 0x00, + 0xD0, 0xF6, 0x40, 0x83, 0xF0, 0x00, 0xC1, 0xA4, 0x20, 0x19, 0xF0, 0x00, 0x82, 0xF6, 0x70, 0x00, 0xF0, 0x00, 0xC1, 0x80, 0x20, 0x17, 0xA0, 0x81, + 0xC3, 0xE7, 0x70, 0x00, 0xF0, 0x00, 0xC5, 0xC7, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0xB1, 0xD0, 0x80, 0x40, 0x00, 0x70, 0x00, 0xAF, 0xF0, + 0x41, 0xF1, 0x40, 0x40, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0xB2, 0xD0, 0x80, 0x40, 0x71, 0x10, 0xB2, 0xD2, 0x80, 0xF0, 0x00, 0x10, 0x81, 0xD0, 0x80, + 0xF0, 0x00, 0x0B, 0xC9, 0x60, 0x08, 0xF0, 0x00, 0x1D, 0x8D, 0xD2, 0x80, 0xF0, 0x00, 0x16, 0xD5, 0xD0, 0x80, 0xF0, 0x00, 0x0B, 0xC9, 0x60, 0x08, + 0xF0, 0x00, 0x1D, 0x8F, 0xD2, 0x80, 0xF0, 0x00, 0x16, 0xDA, 0xD0, 0x80, 0xF0, 0x00, 0x0B, 0x60, 0x60, 0x0E, 0xF0, 0x00, 0x00, 0x04, 0x60, 0x03, + 0xF0, 0x00, 0x3F, 0xFC, 0x60, 0x04, 0x32, 0x63, 0x80, 0x08, 0x60, 0x05, 0x32, 0xE4, 0x19, 0x9A, 0x60, 0x06, 0x33, 0x65, 0x70, 0x00, 0xF0, 0x00, + 0x31, 0xE6, 0x70, 0x00, 0xD0, 0x08, 0x83, 0x6D, 0x0C, 0x35, 0x60, 0x08, 0x40, 0x60, 0x39, 0x36, 0x60, 0x01, 0x41, 0xE2, 0x21, 0x96, 0x60, 0x03, + 0x33, 0x00, 0x41, 0x44, 0xF0, 0x00, 0x33, 0x81, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x02, 0x70, 0x00, 0xF0, 0x00, 0x34, 0x83, 0x70, 0x00, 0xF0, 0x00, + 0x35, 0x04, 0x70, 0x00, 0xF0, 0x00, 0x35, 0x85, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x70, 0x00, 0xAF, 0x54, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0x99, + 0xF0, 0x00, 0x70, 0x00, 0xAF, 0x92, 0xF0, 0x00, 0x0C, 0x51, 0xD2, 0x80, 0xF0, 0x00, 0x21, 0xA0, 0xD0, 0x80, 0xF0, 0x00, 0x05, 0x2E, 0xD2, 0x80, + 0xF0, 0x00, 0x70, 0x00, 0xA0, 0x01, 0xF0, 0x00, 0x21, 0xB7, 0xD0, 0x80, 0xF0, 0x00, 0x20, 0xF0, 0xD2, 0x80, 0x90, 0x02, 0x27, 0xDF, 0xD2, 0x80, + 0x9E, 0x69, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x07, 0x00, 0xD1, 0x80, 0xF0, 0x00, 0x23, 0x20, 0xD0, 0x80, 0x17, 0x0B, 0x60, 0x0C, 0xA0, 0x41, + 0x00, 0x40, 0x40, 0x05, 0xF0, 0x00, 0x00, 0x41, 0x24, 0x3F, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xAE, 0xDD, 0xF0, 0x00, 0x0C, 0x8D, 0x60, 0x08, + 0xF0, 0x00, 0x26, 0x0A, 0xD0, 0x80, 0x83, 0xFF, 0x0D, 0x83, 0x60, 0x08, 0xF0, 0x00, 0x01, 0xF4, 0x60, 0x00, 0xF0, 0x00, 0x03, 0xB1, 0x60, 0x01, + 0x10, 0x00, 0x03, 0xB2, 0x60, 0x02, 0x10, 0x01, 0x04, 0x0E, 0x60, 0x00, 0x10, 0x02, 0x04, 0x0F, 0x60, 0x01, 0x10, 0x00, 0x04, 0x5C, 0x60, 0x02, + 0x10, 0x01, 0x04, 0x5D, 0x60, 0x00, 0x10, 0x02, 0x13, 0x80, 0x60, 0x01, 0x10, 0x00, 0x0D, 0x8E, 0x60, 0x09, 0x10, 0x01, 0x02, 0xEE, 0x60, 0x00, + 0x10, 0x07, 0x43, 0x06, 0x60, 0x01, 0x10, 0x10, 0x04, 0x69, 0x60, 0x02, 0x10, 0x11, 0x44, 0x87, 0x60, 0x00, 0x10, 0x12, 0x05, 0xE3, 0x60, 0x01, + 0x10, 0x10, 0x46, 0x08, 0x60, 0x02, 0x10, 0x11, 0x06, 0xAE, 0x60, 0x00, 0x10, 0x12, 0x0D, 0x8C, 0x60, 0x08, 0x10, 0x10, 0x9E, 0x3C, 0x60, 0x00, + 0x10, 0x17, 0x0D, 0x82, 0x60, 0x09, 0x10, 0x00, 0x70, 0x00, 0xF0, 0x00, 0x10, 0x07, 0x70, 0x00, 0xF0, 0x00, 0x10, 0x17, 0x70, 0x00, 0xD0, 0x08, + 0x0D, 0x83, 0x60, 0x08, 0xA0, 0x24, 0xF0, 0x00, 0x00, 0x02, 0xA0, 0x23, 0x90, 0x82, 0x70, 0x00, 0xF0, 0x00, 0x82, 0x8A, 0x70, 0x00, 0x90, 0x03, + 0x90, 0x8A, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFB, 0x82, 0xBF, 0x70, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x01, 0x99, 0xD2, 0x80, + 0xF0, 0x00, 0x0D, 0x82, 0x60, 0x08, 0xF0, 0x00, 0x26, 0xC1, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x02, 0xA0, 0x1A, 0x90, 0x82, 0x70, 0x00, 0xF0, 0x00, + 0x82, 0x8A, 0x70, 0x00, 0x90, 0x03, 0x90, 0x8A, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x8F, 0xFB, 0x82, 0x80, 0x70, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x0D, 0x8E, 0x60, 0x0D, 0xF0, 0x00, 0x3F, 0xFF, 0x60, 0x02, 0xF0, 0x00, 0x00, 0x51, 0xA0, 0x11, + 0xC2, 0x53, 0x70, 0x00, 0xF0, 0x00, 0x8E, 0xC4, 0x70, 0x00, 0x90, 0x01, 0xF0, 0x00, 0x70, 0x00, 0x97, 0xFC, 0xD4, 0x8F, 0x01, 0x99, 0xD2, 0x80, + 0x40, 0x05, 0x0D, 0x8C, 0x60, 0x0D, 0x40, 0x17, 0x3F, 0xFF, 0x60, 0x02, 0x9F, 0x7D, 0x00, 0x51, 0xA0, 0x0A, 0xC2, 0x53, 0x70, 0x00, 0xF0, 0x00, + 0x82, 0xC4, 0x27, 0x1C, 0xD1, 0x80, 0xF0, 0x00, 0x70, 0x00, 0x97, 0xFC, 0x91, 0x46, 0x27, 0x20, 0xD0, 0x80, 0xF0, 0x00, 0x29, 0x15, 0xD2, 0x80, + 0xF0, 0x00, 0x39, 0x86, 0xD2, 0x80, 0xF0, 0x00, 0x28, 0x88, 0xD0, 0x80, 0x01, 0x52, 0x60, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x28, 0xDC, 0xD2, 0x80, + 0xF0, 0x00, 0x28, 0xD5, 0xD0, 0x80, 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08, 0xF0, 0x00, 0x16, 0xC3, 0x60, 0x08, 0xF0, 0x00, 0x00, 0x9A, 0x60, 0x00, + 0xF0, 0x00, 0x02, 0xE3, 0x60, 0x00, 0x10, 0x00, 0x04, 0xF4, 0x60, 0x00, 0x10, 0x00, 0x06, 0xFF, 0x60, 0x00, 0x10, 0x00, 0x09, 0x07, 0x60, 0x00, + 0x10, 0x00, 0x0B, 0x10, 0x60, 0x00, 0x10, 0x00, 0x0D, 0x1F, 0x60, 0x00, 0x10, 0x00, 0x0F, 0x65, 0x60, 0x00, 0x10, 0x00, 0x0F, 0x65, 0x60, 0x00, + 0x10, 0x00, 0x0D, 0x1F, 0x60, 0x00, 0x10, 0x00, 0x0B, 0x10, 0x60, 0x00, 0x10, 0x00, 0x09, 0x07, 0x60, 0x00, 0x10, 0x00, 0x06, 0xFF, 0x60, 0x00, + 0x10, 0x00, 0x04, 0xF4, 0x60, 0x00, 0x10, 0x00, 0x02, 0xE3, 0x60, 0x00, 0x10, 0x00, 0x00, 0x9A, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x16, 0xD3, 0x60, 0x08, 0xF0, 0x00, 0xFF, 0x93, 0x60, 0x00, 0xF0, 0x00, 0xFE, 0x37, 0x60, 0x00, + 0x10, 0x00, 0xFD, 0xD9, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x9F, 0x60, 0x00, 0x10, 0x00, 0x03, 0x85, 0x60, 0x00, 0x10, 0x00, 0x0D, 0x6B, 0x60, 0x00, + 0x10, 0x00, 0x16, 0x84, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x49, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x49, 0x60, 0x00, 0x10, 0x00, 0x16, 0x84, 0x60, 0x00, + 0x10, 0x00, 0x0D, 0x6B, 0x60, 0x00, 0x10, 0x00, 0x03, 0x85, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x9F, 0x60, 0x00, 0x10, 0x00, 0xFD, 0xD9, 0x60, 0x00, + 0x10, 0x00, 0xFE, 0x37, 0x60, 0x00, 0x10, 0x00, 0xFF, 0x93, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0x16, 0xE3, 0x60, 0x08, 0xF0, 0x00, 0x00, 0x64, 0x60, 0x00, 0xF0, 0x00, 0xFF, 0xA8, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA6, 0x60, 0x00, + 0x10, 0x00, 0xFF, 0xDF, 0x60, 0x00, 0x10, 0x00, 0x00, 0x01, 0x60, 0x00, 0x10, 0x00, 0x01, 0x28, 0x60, 0x00, 0x10, 0x00, 0x01, 0x2F, 0x60, 0x00, + 0x10, 0x00, 0xFD, 0x23, 0x60, 0x00, 0x10, 0x00, 0xFD, 0xA1, 0x60, 0x00, 0x10, 0x00, 0x03, 0x89, 0x60, 0x00, 0x10, 0x00, 0x02, 0x54, 0x60, 0x00, + 0x10, 0x00, 0x0E, 0xA2, 0x60, 0x00, 0x10, 0x00, 0x0C, 0x47, 0x60, 0x00, 0x10, 0x00, 0xF9, 0x42, 0x60, 0x00, 0x10, 0x00, 0xFB, 0xE1, 0x60, 0x00, + 0x10, 0x00, 0x00, 0x8C, 0x60, 0x00, 0x10, 0x00, 0xFE, 0x7D, 0x60, 0x00, 0x10, 0x00, 0x02, 0x54, 0x60, 0x00, 0x10, 0x00, 0x03, 0x89, 0x60, 0x00, + 0x10, 0x00, 0xFD, 0xA1, 0x60, 0x00, 0x10, 0x00, 0xFD, 0x23, 0x60, 0x00, 0x10, 0x00, 0x01, 0x2F, 0x60, 0x00, 0x10, 0x00, 0x01, 0x28, 0x60, 0x00, + 0x10, 0x00, 0x00, 0x01, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xDF, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA6, 0x60, 0x00, 0x10, 0x00, 0xFF, 0xA8, 0x60, 0x00, + 0x10, 0x00, 0x00, 0x64, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x17, 0x0B, 0x60, 0x08, + 0xF0, 0x00, 0x00, 0x03, 0x60, 0x00, 0xF0, 0x00, 0x54, 0xC0, 0x60, 0x00, 0x10, 0x00, 0x00, 0x05, 0x60, 0x00, 0x10, 0x00, 0x00, 0x05, 0x60, 0x00, + 0x10, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x10, 0x00, 0x00, 0x0F, 0x60, 0x00, 0x10, 0x00, 0x09, 0xC0, 0x60, 0x00, 0x10, 0x00, 0x0A, 0x20, 0x60, 0x00, + 0x10, 0x00, 0x1D, 0x40, 0x60, 0x00, 0x10, 0x00, 0x1E, 0x60, 0x60, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x10, 0x00, 0xF0, 0x00, + 0xF0, 0x00, 0x70, 0x00, 0xD0, 0x08 +}; + +unsigned char lutByteValues[]= +{ + /* + 0x40, 0x13, 0x41, 0x68, 0x41, 0xC1, 0x42, 0x14, + 0x47, 0xC5, 0x4D, 0x83, 0x4E, 0x49, 0x4E, 0x53, + 0x4F, 0x92, 0x4F, 0xEA, 0x50, 0x80, 0x56, 0x60, + 0x56, 0xD4, 0x56, 0xD9, 0x61, 0x9F, 0x61, 0xB6, + 0x64, 0x3B, 0x66, 0x09, 0x67, 0x0B, 0x67, 0x1A, + 0x68, 0x87, 0x68, 0xD4 + */ + 0x80, 0x17, 0x80, 0x45, 0x80, 0x96, 0x81, 0x5B, + 0x82, 0xD6, 0x88, 0x0B, 0x88, 0x10, 0x88, 0xDB, + 0x89, 0x48, 0x8B, 0x0A, 0x8B, 0x12, 0x8B, 0x13, + 0x8B, 0x21, 0x8B, 0x26, 0x8C, 0x6F, 0x94, 0xD0, + 0x95, 0x20, 0x95, 0x33, 0x95, 0x6F, 0x95, 0xA8, + 0x95, 0xAC, 0x95, 0xC3, 0x95, 0xE1, 0x97, 0xC9, + 0x97, 0xF6, 0x98, 0x8D, 0x99, 0x00, 0x9A, 0x00, + 0x9E, 0x73, 0xA0, 0x12, 0xA1, 0x03, 0xA2, 0xF0, + 0xA3, 0x0D, 0xA3, 0x4C, 0xA3, 0x52, 0xA3, 0xED, + 0xA8, 0x31, 0xAB, 0x01, 0xAB, 0x1F, 0xAB, 0x4C, + 0xAC, 0x76, 0xAC, 0x88, 0xAD, 0xB0, 0xAD, 0xB7, + 0xB0, 0xE2, 0xB1, 0x01, 0xB1, 0x0B, 0xB1, 0x35, + 0xB1, 0x3B, 0xB1, 0x97, 0xB3, 0x03 +}; + +const uint patchSize = sizeof(patchByteValues); +const u8 *pPatchBytes = &patchByteValues[0]; + +const uint lutSize = sizeof(lutByteValues); +const u8 *pLutBytes = &lutByteValues[0]; + +static const u8 init_para[] = { +//Set the Band related API settings... +11, 0x20,0x0A,0x01,0x00,0x01,0x09,0x38,0x05,0xDC,0x04,0xB0,//FM_BandWidth Auto, FM_Set_Bandwidth (1, 1, 2360, 1500, 1200) +5, 0x20,0x14,0x01,0x00,0x01,//FM_MphSuppression, FM_Set_MphSuppression (1, 1) +7, 0x20,0x17,0x01,0x00,0x01,0x04,0xB0,//FM_NoiseBlanker, FM_Set_NoiseBlanker (1, 1, 1200) + +//Set all Weaksignal API settings (LevelOffset)... +//Set the SoftMute API settings... +9, 0x20,0x2A,0x01,0x00,0x03,0x00,0x64,0x00,0xFA,//FM_SmlMode, FM_Set_SoftMute_Level (1, 3, 100, 250) +11, 0x20,0x28,0x01,0x00,0x3C,0x00,0x78,0x00,0x0A,0x00,0x14,//FM_SmSlowAttack,FM_Set_SoftMute_Time (1, 60, 120, 10, 20) +9, 0x20,0x2C,0x01,0x00,0x03,0x01,0x90,0x03,0xE8,//FM_Smm,FM_Set_SoftMute_Mph (1, 3, 400, 1000) +9, 0x20,0x2B,0x01,0x00,0x03,0x01,0x90,0x03,0xE8,//FM_Smn,FM_Set_SoftMute_Noise (1, 3, 400, 1000) +7, 0x20,0x2D,0x01,0x00,0x01,0x00,0x64,//FM_SmMaximum,FM_Set_SoftMute_Max (1, 1, 100) + +//Set the HighCut API settings... +9, 0x20,0x34,0x01,0x00,0x01,0x01,0xF4,0x00,0xC8,//FM_HclMode,FM_Set_HighCut_Level (1, 1, 500, 200) +11, 0x20,0x32,0x01,0x00,0x3C,0x00,0x78,0x00,0x14,0x00,0x14,//FM_HcSlowAttack,FM_Set_HighCut_Time (1, 60, 120, 20, 20) +11, 0x20,0x33,0x01,0x00,0x01,0x01,0x90,0x00,0xC8,0x03,0x20,//FM_Hco,FM_Set_HighCut_Mod (1, 1, 400, 200, 800) +9, 0x20,0x36,0x01,0x00,0x01,0x00,0x64,0x00,0x64,//FM_Hcm,FM_Set_HighCut_Mph (1, 1, 100, 100) +9, 0x20,0x35,0x01,0x00,0x01,0x00,0x64,0x00,0x64,//FM_Hcn,FM_Set_HighCut_Noise (1, 1, 100, 100) +7, 0x20,0x38,0x01,0x00,0x01,0x3A,0x98,//FM_HcMinimum,FM_Set_HighCut_Min (1, 1, 15000) +7, 0x20,0x3A,0x01,0x00,0x01,0x00,0x64,//FM_HcLowCutMinimum,FM_Set_LowCut_Min (1, 1, 100) +7, 0x20,0x37,0x01,0x00,0x01,0x05,0xDC,//FM_HcMaximum,FM_Set_HighCut_Max (1, 1, 1500) + +//Set the Stereo API settings... +9, 0x20,0x3E,0x01,0x00,0x01,0x01,0xF4,0x00,0xFA,//FM_StlMode,FM_Set_Stereo_Level (1, 1, 500, 250) +11, 0x20,0x3C,0x01,0x00,0x3C,0x00,0x78,0x00,0x0A,0x00,0x14,//FM_StSlowAttack,FM_Set_Stereo_Time (1, 60, 120, 10, 20) +11, 0x20,0x3D,0x01,0x00,0x01,0x00,0xC8,0x00,0xC8,0x03,0xE8,//FM_Sto,FM_Set_Stereo_Mod (1, 1, 200, 200, 1000) +9, 0x20,0x40,0x01,0x00,0x01,0x00,0x64,0x00,0x64,//FM_Stm,FM_Set_Stereo_Mph (1, 1, 100, 100) +9, 0x20,0x3F,0x01,0x00,0x01,0x00,0x64,0x00,0x64,//FM_Stn,FM_Set_Stereo_Noise (1, 1, 100, 100) + +//Set the Audio and Application related API settings... +9, 0x40,0x03,0x01,0x00,0x00,0x00,0x21,0x00,0x03,//AM_GPIO 0 Feature +9, 0x40,0x03,0x01,0x00,0x01,0x00,0x21,0x00,0x00,//AM_GPIO 1 Feature +9, 0x40,0x03,0x01,0x00,0x02,0x00,0x21,0x00,0x00,//AM_GPIO 2 Feature +9, 0x40,0x03,0x01,0x00,0x00,0x00,0x20,0x00,0x03,// FM_GPIO 0 Feature +9, 0x40,0x03,0x01,0x00,0x01,0x00,0x20,0x00,0x00,//FM_GPIO 1 Feature +9, 0x40,0x03,0x01,0x00,0x02,0x00,0x20,0x00,0x00,//FM_GPIO 2 Feature +13, 0x30,0x16,0x01,0x00,0x21,0x00,0x00,0x00,0x20,0x00,0x00,0x11,0x3A,//Dig_IO_IIS_SD_1 Mode +//5, 0x30,0x0B,0x01,0x00,0x00,//Mute +//5, 0x30,0x0A,0x01,0xFF,0xf0,//Volume +7, 0x30,0x0D,0x01,0x00,0x80,0x00,0xE0,//Audio Output Source DAC L/R +}; + +typedef enum +{ + eAR_TuningAction_Standby = 0, + eAR_TuningAction_Preset = 1, /*!< Tune to new program with short mute time */ + eAR_TuningAction_Search = 2, /*!< Tune to new program and stay muted */ + eAR_TuningAction_AF_Update = 3, /*!< Tune to alternative frequency, store quality and tune back with inaudible mute */ + eAR_TuningAction_Jump = 4, /*!< Tune to alternative frequency with short inaudible mute */ + eAR_TuningAction_Check = 5, /*!< Tune to alternative frequency and stay muted */ + eAR_TuningAction_End = 7 /*!< Release the mute of a Search/Check action (frequency is ignored) */ +} AR_TuningAction_t, *pAR_TuningAction_t; +#endif -- cgit 1.2.3-korg