summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--binding/CMakeLists.txt3
-rw-r--r--binding/radio-binding.c5
-rw-r--r--binding/radio_impl_tef665x.c1205
-rw-r--r--binding/radio_impl_tef665x.h23
-rw-r--r--binding/tef665x.h375
6 files changed, 1613 insertions, 1 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/i2c-dev.h>
+#include <stdarg.h>
+#include <error.h>
+#include <gst/gst.h>
+
+//#include <json-c/json.h>
+//#include <gst/gst.h>
+
+#include <afb/afb-binding.h>
+
+#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