aboutsummaryrefslogtreecommitdiffstats
path: root/binding/radio_impl_tef665x.c
diff options
context:
space:
mode:
Diffstat (limited to 'binding/radio_impl_tef665x.c')
-rw-r--r--binding/radio_impl_tef665x.c2405
1 files changed, 0 insertions, 2405 deletions
diff --git a/binding/radio_impl_tef665x.c b/binding/radio_impl_tef665x.c
deleted file mode 100644
index 3abcc00..0000000
--- a/binding/radio_impl_tef665x.c
+++ /dev/null
@@ -1,2405 +0,0 @@
-/*
- * 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 set stereo_mode verb.
- - 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.
- - use Interupt for getting RDS data
-*/
-#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 <linux/i2c.h>
-#include <stdarg.h>
-#include <error.h>
-#include <gst/gst.h>
-#include <time.h>
-//#include <json-c/json.h>
-//#include <gst/gst.h>
-
-#include <afb/afb-binding.h>
-
-#include <pthread.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) ((uint8_t)((a) >> 8))
-#define Low_16bto8b(a) ((uint8_t)(a))
-#define Convert8bto16b(a) ((uint16_t)(((uint16_t)(*(a))) << 8 |((uint16_t)(*(a+1)))))
-
-#define GST_PIPELINE_LEN 256
-
-const uint8_t tef665x_patch_cmdTab1[] = {3, 0x1c,0x00,0x00};
-const uint8_t tef665x_patch_cmdTab2[] = {3, 0x1c,0x00,0x74};
-const uint8_t tef665x_patch_cmdTab3[] = {3, 0x1c,0x00,0x75};
-
-
-typedef struct {
- char *name;
- uint32_t min;
- uint32_t max;
- uint32_t step;
-} band_plan_t;
-
-typedef struct{
- radio_scan_callback_t callback;
- radio_scan_direction_t direction;
- void* data;
-}scan_data_t;
-typedef struct rds_data
-{
- bool Text_Changed;
- bool TrafficAnnouncement;
- bool TrafficProgram;
- bool Music_Speech;
-
- uint32_t Alternative_Freq[25];
- uint8_t Alternative_Freq_Counter;
- uint8_t Num_AlterFreq;
-
- uint16_t PICode;
- uint8_t DI_Seg;
- uint8_t PTY_Code;
-
- uint8_t Year;
- uint8_t Month;
- uint8_t Day;
- uint8_t Hour;
- uint8_t Min;
-
- uint8_t PTYN_Size;
- uint8_t raw_data[12];
-
- char PS_Name[16];
- char RT[128];
- char PTYN[16];
-} rds_data_t;
-
-//thread for handling RDS and Mutex
-pthread_t rds_thread;
-rds_data_t RDS_Message;
-pthread_mutex_t RDS_Mutex;
-
-station_quality_t quality;
-
-//Threads for handling Scan
-pthread_t scan_thread;
-
-pthread_mutex_t scan_mutex;
-
-char _Temp[64]={0};
-
-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 = 9000 }
-};
-
-static unsigned int fm_bandplan = 2;
-static unsigned int am_bandplan = 0;
-static bool corking;
-static bool present;
-static bool initialized;
-static bool scanning;
-
-// stream state
-static GstElement *pipeline;
-static bool running;
-
-
-uint32_t AlterFreqOffset=0;
-
-static void (*freq_callback)(uint32_t, void*);
-static void (*rds_callback) (void*);
-static void *freq_callback_data;
-
-int tef665x_set_rds (uint32_t i2c_file_desc);
-#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 uint32_t file_desc;
-
-static radio_band_t current_band;
-static uint32_t current_am_frequency;
-static uint32_t current_fm_frequency;
-
-static void tef665x_scan_stop (void);
-static void tef665x_set_frequency (uint32_t);
-static void tef665x_search_frequency (uint32_t);
-
-static uint32_t tef665x_get_min_frequency (radio_band_t);
-static uint32_t tef665x_get_max_frequency (radio_band_t);
-static uint32_t tef665x_get_frequency_step (radio_band_t);
-
-static station_quality_t *tef665x_get_quality_info (void);
-
-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, uint8_t cmd, int len, ...)
-{
- int i, ret;
- uint8_t buf[TEF665x_CMD_LEN_MAX];
- uint16_t 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, uint8_t cmd, uint8_t *receive, int len)
-{
- uint8_t temp;
- uint8_t 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);
- if(temp==0)
- AFB_ERROR("Error Number: %d: %s",errno,strerror(errno));
- 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 ,uint8_t *status)
-{
- uint8_t 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 uint8_t *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 uint8_t *bytes, uint16_t size)
-{
- uint8_t buf[25]; //the size which we break the data into, is 24 bytes.
- int ret, i;
-
- uint16_t num = size / 24;
- uint16_t 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(uint32_t i2c_file_desc, uint16_t frequency_high, uint16_t frequency_low, uint16_t type)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Set_ReferenceClock,
- 9,
- frequency_high, frequency_low, type);
-}
-
-static int appl_set_referenceClock(uint32_t i2c_file_desc, uint32_t frequency, bool is_ext_clk) //0x3d 0x900
-{
- return tef665x_appl_set_referenceClock(i2c_file_desc,(uint16_t)(frequency >> 16), (uint16_t)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(uint32_t i2c_file_desc ,uint16_t mode)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_APPL,
- TEF665X_Cmd_Activate,
- 5,
- mode);
-}
-
-static int appl_activate(uint32_t 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(uint8_t i2c_file_desc, uint16_t signal, uint16_t mode, uint16_t format, uint16_t operation, uint16_t samplerate)
-{
- int ret = tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_AUDIO,
- TEF665X_Cmd_Set_Dig_IO,
- 13,
- 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(uint32_t i2c_file_desc, uint16_t signal,uint16_t 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(uint32_t i2c_file_desc, uint8_t signal, uint8_t 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(uint32_t i2c_file_desc)
-{
- int i;
- int r;
- const uint8_t *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;
- }
- }
-
- //Initiate RDS
- tef665x_set_rds(i2c_file_desc);
-
- _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 (uint32_t i2c_file_desc, bool fm, uint16_t mode,uint16_t 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(uint32_t i2c_file_desc, AR_TuningAction_t mode, uint16_t frequency)
-{
- int ret = tef665x_radio_tune_to(i2c_file_desc, 1, (uint16_t)mode, frequency);
- _debug("return value", ret);
- return ret;
-}
-
-static int AM_tune_to(uint32_t i2c_file_desc, AR_TuningAction_t mode,uint16_t frequency)
-{
- int ret = tef665x_radio_tune_to(i2c_file_desc, 0, (uint16_t)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(uint32_t i2c_file_desc, uint16_t 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(uint32_t i2c_file_desc, uint16_t 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)
-{
- uint8_t 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(uint32_t 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(uint32_t i2c_file_desc, int vol)
-{
- return tef665x_audio_set_volume(i2c_file_desc, (uint16_t)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(uint32_t i2c_file_desc, uint16_t 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(uint32_t i2c_file_desc, bool OnOff)
-{
- tef665x_audio_set_operationMode(i2c_file_desc, OnOff? 0 : 1);//standby mode = 1
-}
-
-static void radio_modeSwitch(uint32_t i2c_file_desc, bool mode_switch, AR_TuningAction_t mode, uint16_t frequency)
-{
-
- if(mode_switch) //FM
- {
- FM_tune_to(i2c_file_desc, mode, frequency);
- }
- else //AM
- {
- AM_tune_to(i2c_file_desc, mode, frequency);
- }
-}
-
-/*
-module 32 FM
-cmd 81 Set_RDS
-
-index
-1 mode
- [ 15:0 ]
- RDS operation mode
- 0 = OFF
- 1 = decoder mode (default), output of RDS groupe data (Block A, B, C, D)
- from get_rds_status, get_rds_data FM cmd 130/131
-
-2 restart
- [ 15:0 ]
- RDS decoder restart
- 0 = no control
- 1 = manual restart, starlooking for new RDS data immidiately
- 2 = automatic restart after tuning (default)
- 3 = flush, empty RDS output buffer.
-
-3 interface
- [ 15:0 ]
- 0 = no pin interface.
- 2 = data available status output; active low (GPIO feature 'DAVN')
- 4 = legecy 2-wire demodulator data and clock output ('RDDA' and 'RDCL')
-*/
-int tef665x_set_rds(uint32_t i2c_file_desc)
-{
- return tef665x_set_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Set_RDS,
- 9,//Total Bytes to be sent
- TEF665X_Cmd_Set_RDS_mode, // default
- TEF665X_Cmd_Set_RDS_autorestart, // restart after tune
- 0x002 // no interface
- );
-}
-
-
-/*
- * @brief Adding Alternative Frequencies to RDS Data Structure
- *
- * @param uint8_t* : raw data of alternative frequency (Group 0A of RDS)
- * @param rds_data_t* : Pointer to RDS Data Structure
- * @return void
- */
-void Extract_Alt_Freqs(uint8_t* buf,rds_data_t *Rds_STU)
-{
- for(int Buffer_Index=6;Buffer_Index<8;Buffer_Index++)
- {
- if(buf[Buffer_Index]>204){
- if(250>buf[Buffer_Index]&&buf[Buffer_Index]>224)
- {
- Rds_STU->Num_AlterFreq=buf[Buffer_Index]-224;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- AlterFreqOffset=87500000;
- }
- else if(buf[Buffer_Index]==205)
- {
- AFB_ERROR("Filler Code");
- }
- else if(buf[Buffer_Index]==224)
- {
- AFB_ERROR("No AF Exists");
- }
- else if(buf[Buffer_Index]==250)
- {
- AFB_ERROR("An LF/MF Frequency Follows");
- AlterFreqOffset=144000;
- }
- else if(buf[Buffer_Index]>250)
- {
- AFB_WARNING("Alternative Frequency Not Assigned");
- }
- }
- else if(buf[Buffer_Index]>0)
- {
- if(AlterFreqOffset == 87500000)
- {
- Rds_STU->Alternative_Freq[Rds_STU->Alternative_Freq_Counter]=
- buf[Buffer_Index] * 100000 + AlterFreqOffset;
-
- Rds_STU->Alternative_Freq_Counter++;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- }
- else if(AlterFreqOffset == 144000)
- {
- Rds_STU->Alternative_Freq[Rds_STU->Alternative_Freq_Counter]=
- ((uint32_t)buf[Buffer_Index]) * 9000 + AlterFreqOffset;
-
- Rds_STU->Alternative_Freq_Counter++;
-
- if(Rds_STU->Alternative_Freq_Counter == Rds_STU->Num_AlterFreq)
- {
- Rds_STU->Alternative_Freq_Counter = 0;
- }
- }
- else
- {
- AFB_WARNING("Alternative Frequency is not defined");
- }
- }
- else
- {
- AFB_ERROR("Alternative Frequency- Not to be used");
- }
- }
-}
-
-/*
- * @brief Checking rds error code (determined by decoder)
- *
- * 0 : no error; block data was received with matching data and syndrome
- * 1 : small error; possible 1 bit reception error detected; data is corrected
- * 2 : large error; theoretical correctable error detected; data is corrected
- * 3 : uncorrectable error; no data correction possible
- *
- * @param Errors : Error Code of blocks A,B,C and D of RDS
- * @return void
- */
-void Check_RDS_Error(uint8_t Errors[])
-{
- for (int i=0;i<4;i++){
- if(Errors[i]==1){
- AFB_WARNING("RDS Block %d Reception Error; small error; possible 1 bit reception error detected; data is corrected",i+1);
- }
- else if(Errors[i]==2){
- AFB_WARNING("RDS Block %d Reception Error; large error; theoretical correctable error detected; data is corrected",i+1);
- }
- else if(Errors[i]==3){
- AFB_ERROR("RDS Block %d Reception Error; uncorrectable error; no data correction possible",i+1);
- }
- }
-}
-
-/*
- * @brief Getting rds_data_t and Process its raw_data
- *
- * @param rds_data_t * : Pointer to latest RDS Data Structure
- */
-void *Process_RDS_Words(void* rds_words){
- pthread_detach(pthread_self());
-
- rds_data_t *Rds_STU = rds_words;
- uint8_t *raw_data = Rds_STU->raw_data;
- int8_t group_Ver = -1;
- uint8_t GType0 = 0;
- bool DI_Seg = 0;
- bool M_S = 0;
- bool TA = 0;
-
- //Parse 1st Section
- bool DataAvailable = (raw_data[0] >> 7) & 1;
- bool DataLoss = (raw_data[0] >> 6) & 1 == 1;
- bool DataAvailType = (raw_data[0] >> 5) & 1 == 0;
- bool GroupType = (raw_data[0] >> 4) & 1;
- bool SyncStatus = (raw_data[0] >> 1) & 1;
-
- //Parse Last Section(Error Codes)
- uint8_t Error_A = raw_data[10] >> 6;
- uint8_t Error_B = raw_data[10] >> 4 & 3;
- uint8_t Error_C = raw_data[10] >> 2 & 3;
- uint8_t Error_D = raw_data[10] & 3;
- uint8_t Errors[]={Error_A,Error_B,Error_C,Error_D};
-
- //Inform user about Error Blocks Status Codes
- Check_RDS_Error(Errors);
-
- if(Error_A==0){
- //Bytes 2 and 3 are inside Block A
- //raw_data[2]and raw_data[3] Contains PI Code
- Rds_STU->PICode=Convert8bto16b(&raw_data[2]);
- }
- else{
- AFB_ERROR("Error_A=%d",Error_A);
- }
-
- bool GTypeVer=GType0;
- uint16_t GType=raw_data[4]>>4;
- //Bytes 4 and 5 are inside Block B
- if(Error_B==0){
- GTypeVer=raw_data[4]>>3 & 1;
- GType=raw_data[4]>>4;
- Rds_STU->TrafficProgram=raw_data[4]>>2&1;
- Rds_STU->PTY_Code= (raw_data[4] & 3) << 3 | raw_data[5] >> 5;
- }
-
- //Position Of Character
- uint8_t CharPos=0;
-
- //Extract Data based on Group Type values
- switch (GType)
- {
- case 0:
- {
- if(Error_B==0)
- {
- CharPos = raw_data[5] & 3;
-
- Rds_STU->TrafficAnnouncement = raw_data[5] >> 4 & 1;
- Rds_STU->Music_Speech = raw_data[5] >> 3 & 1;
- Rds_STU->DI_Seg = (raw_data[5] >> 2 & 1) * (2 ^ (3 - CharPos));
- }
-
- if(Error_C==0)
- {
- //Group Type 0A
- if (GType==0)
- {
- Extract_Alt_Freqs(raw_data,Rds_STU);
- }
-
- //Group Type 0B
- else
- {
- Rds_STU->PICode=Convert8bto16b(&raw_data[6]);
- }
- }
-
- if(Error_D == 0 && Error_B == 0)
- {
- if(raw_data[8] != 0x7f)
- {
- Rds_STU->PS_Name[CharPos*2] = raw_data[8];
- }
- else
- {
- Rds_STU->PS_Name[CharPos*2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f)
- {
- Rds_STU->PS_Name[CharPos*2+1] = raw_data[9];
- }
- else
- {
- Rds_STU->PS_Name[CharPos*2+1] = (char)'\0';
- }
- }
- }
- break;
- case 1:
- {
- //Group Type 1A
- if(GTypeVer == 0)
- {
- if(Error_D == 0)
- {
- Rds_STU->Day = raw_data[8] >> 3;
- Rds_STU->Hour = raw_data[8] >> 3;
- Rds_STU->Min = ((raw_data[8] & 7) << 2) | (raw_data[9] >> 6) ;
- }
- }
- }
- break;
- case 2:
- {
- //Group Type 2A:
- if(GTypeVer == 0)
- {
- uint8_t Text_pos = raw_data[5] & 15;
-
- if(Error_B == 0 && Error_C == 0)
- {
-
- if(raw_data[6] !=0x7f && raw_data[6] != '\n')
- {
- Rds_STU->RT[Text_pos*4] = raw_data[6];
- }
- else{
- Rds_STU->RT[Text_pos*4] = (char)'\0';
- }
- if(raw_data[7]!=0x7f&&raw_data[7]!='\n')
- {
- Rds_STU->RT[Text_pos*4+1] = raw_data[7];
- }
- else
- {
- Rds_STU->RT[Text_pos*4+1] = (char)'\0';
- }
- }
- if(Error_B == 0 && Error_D == 0)
- {
- if(raw_data[8] != 0x7f && raw_data[8] != '\n')
- {
- Rds_STU->RT[Text_pos*4+2] = raw_data[8];
- }
- else{
- Rds_STU->RT[Text_pos*4+2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f && raw_data[9] != '\n')
- {
- Rds_STU->RT[Text_pos*4+3] = raw_data[9];
- }
- else
- {
- Rds_STU->RT[Text_pos*4+3] = (char)'\0';
- }
- }
- }
-
- //Group Type 2B:
- else{
- if(Error_B==0 && Error_D==0)
- {
- //Clear All Radio Text if flag was changed
- if(raw_data[5] >> 4 & 1 != Rds_STU->Text_Changed)
- {
- memcpy(Rds_STU->RT, _Temp , 64);
- }
-
- uint8_t Text_pos = raw_data[5] & 15;
- if(raw_data[8] != 0x7f && raw_data[8] != '\n')
- {
-
- Rds_STU->RT[Text_pos*2] = raw_data[8];
- }
- else{
- Rds_STU->RT[Text_pos*2] = (char)'\0';
- }
- if(raw_data[9] != 0x7f && raw_data[9] != '\n')
- {
- Rds_STU->RT[Text_pos*2+1] = raw_data[9];
- }
- else
- {
- Rds_STU->RT[Text_pos*2+1] = (char)'\0';
- }
- }
- }
- }
- break;
- case 4:
- {
- //Group Type 4A
- if(GTypeVer == 0)
- {
- if(Error_B == 0 && Error_C == 0 && Error_D == 0)
- {
- //Following caclulations are based on RDS Standard
- uint32_t Modified_Julian_Day = ((raw_data[5] & 3) << 15) | (raw_data[6] << 7) | (raw_data[7]>>1);
- int y2 = (int)((((double)Modified_Julian_Day)-15078.2)/365.25);
- int m2 = (int)((((double)Modified_Julian_Day)-14956.1-((double)y2*365.25))/30.6001);
- int d2 = (double)Modified_Julian_Day-14956-(int)(y2*365.25)-(int)(m2*30.6001);
- int k = 0;
-
- if(m2 == 14 || m2 == 15)
- {
- k = 1;
- }
-
- Rds_STU->Day = d2;
- Rds_STU->Month = m2 - 1 + k * 12;
- Rds_STU->Year = y2 + k;
-
- uint8_t UTCHour = ((raw_data[7] & 1) << 4) | (raw_data[8] >> 4);
- uint8_t UTCMinute = ((raw_data[8] & 15) << 2) | (raw_data[9] >> 6);
-
- //Check Negative Offset
- bool NegOff = raw_data[9] & 32;
- uint8_t LocTimeOff = raw_data[9] & 31;
-
- if(!NegOff)
- {
- Rds_STU->Min = UTCMinute + LocTimeOff % 2;
- while(UTCMinute > 60)
- {
- UTCHour++;
- UTCMinute = UTCMinute - 60;
- }
-
- Rds_STU->Hour = UTCHour + LocTimeOff / 2;
- while(Rds_STU->Hour > 24){
- Rds_STU->Hour = Rds_STU->Hour - 24;
- }
-
-
- }
- else{
- Rds_STU->Min = UTCMinute + LocTimeOff % 2;
- while(UTCMinute < 0)
- {
- UTCHour--;
- UTCMinute = UTCMinute + 60;
- }
- Rds_STU->Hour = UTCHour + LocTimeOff / 2;
- while(Rds_STU->Hour<0)
- {
- Rds_STU->Hour = Rds_STU->Hour + 24;
-
- }
- }
- }
- }
- //Group Type 4B
- else
- {
- AFB_WARNING("Groupe Type 4B are not supported yet");
- }
- }
- case 8:
- {
- AFB_WARNING("Groupe Type 8A and 8B are not supported yet");
-
- }
- case 10:
- {
- AFB_WARNING("Groupe Type 10A and 10B are not supported yet");
- /*
- if(Error_B == 0){
- uint8_t pos = 0;
- pos=(raw_data[5] & 1) * 4;
-
- if(Error_C == 0){
- Rds_STU->PTYN[pos] = raw_data[6];
- Rds_STU->PTYN[pos+1] = raw_data[7];
- Rds_STU->PTYN_Size = pos + 2;
- }
- if(Error_D == 0){
- Rds_STU->PTYN[pos+2] = raw_data[8];
- Rds_STU->PTYN[pos+3] = raw_data[9];
- Rds_STU->PTYN_Size = pos + 4;
- }
- }
- /**/
- }
- break;
- default:
- AFB_ERROR("Unsupported Group %d",GType);
- break;
- }
-
- if(!DataAvailable)
- {
- AFB_ERROR("RDS Data is not available");
- }
-
- if(DataLoss)
- {
- AFB_ERROR("previous data was not read, replaced by newer data");
- }
-
- if(GroupType == 0)
- {
- group_Ver = 0;
- }
- else
- {
- group_Ver = 1;
- }
-
- if(!SyncStatus)
- {
- AFB_ERROR(" RDS decoder not synchronized; no RDS data found");
- }
-
- if(GroupType != GTypeVer)
- {
- AFB_ERROR("Version is not Correct?");
- }
-}
-
-/*
-module 32 FM
-cmd 131 get RDS data
-
-index
-1 status
- [ 15:0 ]
- FM RDS reception status.
- [15] = dta availableflag
- 0 = no data
- 1 = data available
- [14] = data loss flag
- 0 = no data loss
- 1 = previose data not read, replaced by newer data.
- [13] = data available type
- 0 = group data; continuos operation.
- 1 = first PI data;data with PI code following decoder sync.
- [12] = groupe type.
- 0 = type A; A-B-C-D group (with PI code in the block A)
- 1 = type B; A-B-C'-D group (with PI code in the block A and C')
- [ 8:0 ] reserved
-
-2 A_Block
- [ 15:0 ] = A block data
-
-3 B_Block
- [ 15:0 ] = B block data
-
-4 C_Block
- [ 15:0 ] = C block data
-
-5 D_Block
- [ 15:0 ] = D block data
-
-6 dec error
- [ 15:0 ]
- error code determined by decoder
- [ 15:14 ] = A block error
- [ 13:12 ] = B block error
- [ 11:10 ] = C block error
- [ 9:8 ] = D block error
- 0 = no error found
- 1 = small error, correctable. data is corrected.
- 2 = larg error, correctable. data is corrected.
- 3 = uncorrectable error.
- [ 7:0 ] = reserved.
-*/
-/*
- * @brief Get RDS Data fron Tef-665
- *
- * Getting RDS Data From I2C and Calling a thread to process raw data
- *
- * @param i2c_file_desc : I2C File Descriptor
- * @param Rds_STU : RDS Data Structure
- *
- */
-int tef665x_get_rds_data(uint32_t i2c_file_desc, rds_data_t *Rds_STU)
-{
-
- int ret;
- uint8_t buf[12];
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_RDS_Data,
- buf, sizeof(buf));
-
- if(ret == 1) {
- memcpy(Rds_STU->raw_data,buf,12);
- pthread_t t0;
- pthread_create(&t0, NULL,Process_RDS_Words ,(void *) (Rds_STU));
- }
- return ret;
-}
-
-void Clear_RDS_Data(rds_data_t *Rds_STU){
-
- Rds_STU-> Text_Changed=0;
- Rds_STU-> TrafficAnnouncement=0;
- Rds_STU-> TrafficProgram=0;
- Rds_STU-> Music_Speech=0;
-
- Rds_STU-> DI_Seg=0;
- Rds_STU-> PTY_Code=0;
- Rds_STU-> Num_AlterFreq=0;
- Rds_STU->PTYN_Size=0;
-
- Rds_STU-> Day=0;
- Rds_STU-> Month=0;
- Rds_STU-> Year=0;
-
- Rds_STU-> Hour=0;
- Rds_STU-> Min=0;
-
- /*memcpy(Rds_STU->Alternative_Freq,_Temp,25);/**/
- for(uint8_t i=0;i<25;i++){
- Rds_STU->Alternative_Freq[i]=0;
- }
- memcpy(Rds_STU-> PS_Name,_Temp,8);
- Rds_STU-> PS_Name[0]='\0';
- memcpy(Rds_STU-> RT,_Temp,64);
- Rds_STU-> RT[0]='\0';
- memcpy(Rds_STU-> PTYN,_Temp,8);
- Rds_STU-> PTYN[0]='\0';
-
- Rds_STU-> PICode=0;
- Rds_STU->Alternative_Freq_Counter=0;
- Rds_STU->PTYN_Size=0;
-}
-
-//Check if RDS is available
-int tef665x_get_rds_status(uint32_t i2c_file_desc, uint16_t *status)
-{
- int ret = 0;
- uint8_t buf[2];
-
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_RDS_Status,
- buf, sizeof(buf));
-
- if(ret == 1){
- status[0] =buf[0];
- status[1] =buf[1];
- }
-
- return ret;
-}
-
-static int tef665x_wait_active(uint32_t 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, 35))//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, uint32_t *i2c_file_desc)
-{
- int fd = 0, 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(!initialized)
- 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;
- }
- }
-
-/*
- * @brief Send_Rds_Result to rds subscribers
- *
- * @param rds_data_t : a rds message structure
- * @return The JsonObject of rds info
- */
-void *Send_Rds_Result(rds_data_t* RDS_Message){
- //Kill the thread when it was over
- pthread_detach(pthread_self());
-
- json_object *ret_json;
- json_object *Alternative_Freqs;
-
-
- ret_json = json_object_new_object();
- Alternative_Freqs=json_object_new_array();
-
-
-
- for(uint8_t af=0 ; af<25 ; af++)
- {
- if(RDS_Message->Alternative_Freq[af]!=NULL&&RDS_Message->Alternative_Freq[af]!=0)
- {
- json_object_array_add(Alternative_Freqs,json_object_new_int(RDS_Message->Alternative_Freq[af]));
- }
- }
-
- //Prepare JSon Object
- json_object_object_add(ret_json, "name" , json_object_new_string(RDS_Message->PS_Name));
- json_object_object_add(ret_json, "radiotext" , json_object_new_string(RDS_Message->RT));
- json_object_object_add(ret_json, "alternatives" , (Alternative_Freqs));
- json_object_object_add(ret_json, "minute" , json_object_new_int (RDS_Message->Min));
- json_object_object_add(ret_json, "hour" , json_object_new_int (RDS_Message->Hour));
- json_object_object_add(ret_json, "day" , json_object_new_int (RDS_Message->Day));
- json_object_object_add(ret_json, "month" , json_object_new_int (RDS_Message->Month));
- json_object_object_add(ret_json, "year" , json_object_new_int (RDS_Message->Year));
- json_object_object_add(ret_json, "pi" , json_object_new_int (RDS_Message->PICode));
- json_object_object_add(ret_json, "pty" , json_object_new_int (RDS_Message->PTY_Code));
- json_object_object_add(ret_json, "ta" , json_object_new_int (RDS_Message->TrafficAnnouncement));
- json_object_object_add(ret_json, "tp" , json_object_new_int (RDS_Message->TrafficProgram));
- json_object_object_add(ret_json, "ms" , json_object_new_int (RDS_Message->Music_Speech));
-
- //Send JsonObject to rds Subscribers
- if(rds_callback){
- rds_callback(ret_json);
- }
-
- return ret_json;
-}
-
-/*
- * @brief Create an infinit Loop to get RDS Packets and Send them to subscribers
- *
- * RDS data will be available every 85 ms;
- * Currently availability of RDS is checkes by tef665x_get_rds_status function
- *
- * @param rds_data_t : a rds message structure
- * @return The JsonObject of latest rds info
- */
-void *Get_RDS_Packets(rds_data_t *StuRDS){
- pthread_detach(pthread_self());
- uint32_t fd = 0;
-
- int ret = i2c_init(I2C_DEV, _open, &fd);
- uint8_t status[2];
-
- ret=tef665x_get_rds_status(fd, status);
-
- if(ret==1){
- if(status[0]>7){
- //RDS must update all the time, except the times we are scanning or changing frequency
- //when scanning or changing frequncy, we unlock RDS_Mutex and it will end this thread
- for (int ref_cnt=0; pthread_mutex_trylock(&RDS_Mutex) != 0;ref_cnt++){
- //Get New RDS Data
- tef665x_get_rds_data(fd,StuRDS);
-
- //Send RDS Data after rexeiving 22 Packets
- if(ref_cnt%22==0){
- pthread_t t0;
- pthread_create(&t0, NULL,Send_Rds_Result ,(void *) (&RDS_Message));
- }
-
- //Wait for 85ms before reading available rds data
- usleep(85000);
- }
- pthread_mutex_unlock (&RDS_Mutex);
- }
-
- else{
- AFB_ERROR("RDS is Not Valid0");
- }
- }
-
- else{
- AFB_ERROR("RDS is Not Valid1");
- }
- i2c_init(I2C_DEV, _close, &fd);
-}
-
-/*
- * @brief Free Allocated Memory for Scan Thread and Unlock Scan Mutex
- *
- * @param scan_data : scan_data_t contains direction of search and callback
- * for station_found event
- */
-static void scan_cleanup_handler(void *scan_data)
-{
- pthread_mutex_unlock(&scan_mutex);
- free(scan_data);
- scanning=false;
-}
-
-/*
- * @brief Create a loop to scan from current frequency to find a valid frequency
- *
- * If found a valid frequency, send station_found to subscribers and break the loop;
- * If the direction was forward and reach the maximum frequency, Search Must continue
- * from minimum frequency
- * If the direction was backward and reach the minimum frequency, Search Must continue
- * from maximum frequency
- * If no valid frequency found, scan will stop at the begining point
- * If stop_scan called, scan_mutex will be unlocked and thread must be stopped
- *
- * @param scan_data : scan_data_t contains direction of search and callback
- * for station_found event
- */
-void *scan_frequencies(scan_data_t* scan_data){
- pthread_cleanup_push(scan_cleanup_handler, (void *)scan_data);
-
- //Kill the thread when it was over
- pthread_detach(pthread_self());
-
- //Set Scan Flag
- scanning=true;
-
- //"Unlock Mutex" Flag
- bool unlck_mtx = false;
- uint32_t new_freq = 0;
- uint32_t init_freq = 0;
-
- init_freq = current_band == BAND_FM ? current_fm_frequency : current_am_frequency;
-
- //First Mute Current Frequency
- tef665x_search_frequency(init_freq);
-
- //freq_step will be negative if direction was backward and positive if direction was forward
- uint32_t freq_step = tef665x_get_frequency_step(current_band) * (scan_data->direction==SCAN_FORWARD?1:-1);
-
- //Continue loop until reaching the initial frequency
- while(init_freq != new_freq)
- {
- //Check Status of scan_mutex
- unlck_mtx = pthread_mutex_trylock(&scan_mutex)==0;
-
- //break the loop if scan_mutex was unlocked
- if(unlck_mtx)
- {
- break;
- }
-
- if(current_band==BAND_FM)
- {
- new_freq = current_fm_frequency + freq_step;
-
- //Searching Step is 100 KHz
- //If frequency reached to initial point, the search must stop
- while (((new_freq/10000)%10)!=0 && init_freq != new_freq){
- new_freq = new_freq+freq_step;
- }
- }
- else
- {
- new_freq = current_am_frequency + freq_step;
- }
-
- //Set Freq to min when it was more than Max Value
- if(new_freq>tef665x_get_max_frequency(current_band))
- {
- new_freq=tef665x_get_min_frequency(current_band);
- }
-
- //Set Freq to max when it was less than Min Value
- if(new_freq<tef665x_get_min_frequency(current_band))
- {
- new_freq=tef665x_get_max_frequency(current_band);
- }
-
- //Tune to new frequency
- tef665x_search_frequency(new_freq);
-
- //wait 30 ms to make sure quality data is available
- for(int i=0;i<40;i++)
- {
- usleep(1000);
-
- //Check scan_mutex lock for handling stop_scan
- unlck_mtx=pthread_mutex_trylock(&scan_mutex)==0;
- if(unlck_mtx)
- {
- break;
- }
- }
- if(unlck_mtx)
- {
- break;
- }
-
- //Get Quality of tuned frequeency
- tef665x_get_quality_info();//Get_quality_status();
-
- if((quality.rssi >260 /*&& ->.usn<100/**/) || quality.bandw>1200)
- {
- //Send frequency value
- if(scan_data->callback)
- {
- scan_data->callback(new_freq,NULL);
- }
-
- break;
- }
- usleep(100);
- }
-
- //Calling last pthread_cleanup_push
- pthread_cleanup_pop(1);
-}
-
-/*
- * @brief Get latest RDS Info and send rds jsonObject as response
- *
- * @return: cast rds_json(json_object) to (char *) and return result as response
- */
-static char *tef665x_get_rds_info(void)
-{
- //If Getting RDS Result wasn't already started, Start it now
- if(pthread_mutex_trylock(&RDS_Mutex) == 0)
- {
- AFB_DEBUG("Create the thread.");
- pthread_create(&rds_thread, NULL,Get_RDS_Packets ,(void *) (&RDS_Message));
- }
-
- //Send latest available rds data
- json_object *rds_json=(json_object *)Send_Rds_Result(&RDS_Message);
-
- //Convert json_object to char* and send it as response
- return (char *)json_object_to_json_string(rds_json);
-}
-
-/*
- * @brief Get latest quality Info and send quality parameters as response
- *
- * module 32/33 FM/AM
- * cmd 129 Get_Quality_Data
- *
- * index
- * 1 status
- * [ 15:0 ]
- * quality detector status
- * [15] = AF_update flag
- * 0 = continuous quality data with time stamp
- * 1 = AF_Update sampled data
- * [14:10] = reserved
- * 0 = no data loss
- * 1 = previose data not read, replaced by newer data.
- * [9:0] = quality time stamp
- * 0 = tuning is in progress, no quality data available
- * 1 … 320 (* 0.1 ms) = 0.1 … 32 ms after tuning,
- * quality data available, reliability depending on time stamp
- * 1000 = > 32 ms after tuning
- * quality data continuously updated
- *
- * 2 level
- * [ 15:0 ] (signed)
- * level detector result
- * -200 … 1200 (0.1 * dBuV) = -20 … 120 dBuV RF input level
- * actual range and accuracy is limited by noise and agc
- *
- * 3 usn
- * [ 15:0 ] = noise detector
- * FM ultrasonic noise detector
- * 0 … 1000 (*0.1 %) = 0 … 100% relative usn detector result
- *
- * 4 wam
- * [ 15:0 ] = radio frequency offset
- * FM ‘wideband-AM’ multipath detector
- * 0 … 1000 (*0.1 %) = 0 … 100% relative wam detector result
- *
- * 5 offset
- * [ 15:0 ] (signed) = radio frequency offset
- * -1200 … 1200 (*0.1 kHz) = -120 kHz … 120 kHz radio frequency error
- * actual range and accuracy is limited by noise and bandwidth
- *
- * 6 bandwidth
- * [ 15:0 ] = IF bandwidth
- * FM 560 … 3110 [*0.1 kHz] = IF bandwidth 56 … 311 kHz; narrow … wide
- * AM 30 … 80 [*0.1 kHz] = IF bandwidth 3 … 8 kHz; narrow … wide
- *
- * 7 modulation
- * [ 15:0 ] = modulation detector
- * FM 0 … 1000 [*0.1 %] = 0 … 100% modulation = 0 … 75 kHz FM dev.
- *
- * @return: cast station_quality_t pointer as response
- *
- */
-
-static station_quality_t *tef665x_get_quality_info(void)
-{
- uint32_t i2c_file_desc=0;
- uint8_t data[14];
-
- int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc);
- if(current_band==BAND_FM)
- {
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_Quality_Data,
- data, sizeof(data));
- }
- else
- {
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_AM,
- TEF665X_Cmd_Get_Quality_Data,
- data, sizeof(data));
- }
- i2c_init(I2C_DEV, _close, &i2c_file_desc);
-
- quality.af_update = data[0]&0b10000000;
- quality.time_stamp = ((data[0]&0b00000011)<<8 | data[1]);
- quality.rssi = (data[2] << 8 | data[3] );
- quality.usn = (data[4] << 8 | data[5] );
- quality.bandw = (data[10]<< 8 | data[11]);
-
- return &quality;
-}
-
-/*
- * @brief Start Scan
- *
- * @param radio_scan_direction_t direction which is the scan direction and can be
- * SCAN_FORWARD or SCAN_BACKWARD
- * @param radio_scan_callback_t callback which is the callback for sending result of search to
- * station_found ecent subscribers
- * @return void
- */
-static void tef665x_scan_start(radio_scan_direction_t direction,
- radio_scan_callback_t callback,
- void *data)
-{
- //Stop RDS if enabled
- pthread_mutex_unlock (&RDS_Mutex);
-
- //Stop current scan:
- if(scanning)
- {
- tef665x_scan_stop();
- }
-
- scan_data_t *inputs;
-
- //Clean RDS Message since frequency will change
- Clear_RDS_Data(&RDS_Message);
- usleep(10000);
-
- AFB_DEBUG("check Mutex Condition");
-
- //check if is there any activated search
- if(pthread_mutex_trylock(&scan_mutex)==0&&!scanning)
- {
- AFB_DEBUG("Start Scanning...");
-
- inputs=malloc(sizeof(*inputs));
- if(!inputs)
- return -ENOMEM;
-
- inputs->direction= direction;
- inputs->callback= callback;
- inputs->data=data;
-
- pthread_create(&scan_thread, NULL,scan_frequencies ,(void *) inputs);
- }
-}
-
-/*
- * @brief Stop Scan
- *
- * By unlocking scan_mutex, Scan thread will be stopped safely and update scanning flag
- *
- * @return void
- */
-static void tef665x_scan_stop(void)
-{
- pthread_mutex_unlock(&scan_mutex);
- while(scanning)
- {
- usleep(100);
- AFB_DEBUG(" Wait for unlocking scan Thread");
- }
-}
-
-/*
-module 32 / 33 FM / AM
-cmd 133 Get_Signal_Status | status
-index
-1 status
- [ 15:0 ] = Radio signal information
- [15] = 0 : mono signal
- [15] = 1 : FM stereo signal (stereo pilot detected)
-
- [14] = 0 : analog signal
- [14] = 1 : digital signal (blend input activated by digital processor or control)
- (TEF6659 only)
-*/
-radio_stereo_mode_t tef665x_get_stereo_mode(void)
-{
- uint32_t i2c_file_desc = 0;
- int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc);
- uint8_t data[2];
- if(current_band==BAND_FM){
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_FM,
- TEF665X_Cmd_Get_Signal_Status,
- data, sizeof(data));
- }
- else{
- ret = tef665x_get_cmd(i2c_file_desc, TEF665X_MODULE_AM,
- TEF665X_Cmd_Get_Signal_Status,
- data, sizeof(data));
- }
- i2c_init(I2C_DEV, _close, &i2c_file_desc);
- return data[0]>>7 ==1 ? STEREO:MONO;
-}
-
-static void tef665x_stop(void)
-{
- int ret;
- GstEvent *event;
- audio_set_mute(file_desc, 1);
-
- if(initialized && 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_probe()
-{
- int rc;
-
- if(present)
- return 0;
-
- rc = i2c_init(I2C_DEV, _open, &file_desc);
- if(rc < 0) {
- AFB_NOTICE("tef665x not present");
- return -1;
- }
- _debug("file_desc= ", file_desc);
-
- rc = appl_get_identification(file_desc);
- if(rc != 1){
- AFB_ERROR("no tef665x!");
- return -1;
- }
-
- present = true;
- return 0;
-}
-
-static int tef665x_init()
-{
- char gst_pipeline_str[GST_PIPELINE_LEN];
- int rc;
-
- if(!present)
- return -1;
-
- if(initialized)
- return 0;
-
- current_am_frequency = known_am_band_plans[am_bandplan].min;
- current_fm_frequency = known_fm_band_plans[fm_bandplan].min;
-
- 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 device=hw:1,0 ! audioconvert ! audioresample ! audio/x-raw, rate=48000, channels=2 \
- ! pipewiresink stream-properties=\"p,media.role=Multimedia\"");
-
- 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
- rc = gst_element_set_state(pipeline, GST_STATE_PAUSED);
- _debug("gst_element_set_state to pause (at the begining)", rc);
-
- rc = gst_bus_add_watch(gst_element_get_bus(pipeline), (GstBusFunc) handle_message, NULL);
- _debug("gst_bus_add_watch rc", rc);
-
- //Initialize Mutex Lock for Scan and RDS
- pthread_mutex_init(&scan_mutex, NULL);
- pthread_mutex_init (&RDS_Mutex, NULL);
-
- initialized = true;
-
- tef665x_start();
- 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_rds_callback(radio_rds_callback_t callback)
-{
- rds_callback = callback;
-
-}
-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)
-{
- uint32_t fd = 0;
- 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_alternative_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
- int ret = i2c_init(I2C_DEV, _open, &fd);
-
- if(current_band == BAND_FM)
- {
- FM_tune_to(fd, eAR_TuningAction_AF_Update, frequency / 10000);
- }
-
- i2c_init(I2C_DEV, _close, &fd);
-}
-
-static void tef665x_set_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
-
- if(!initialized)
- 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;
- }
- }
-
- int ret = i2c_init(I2C_DEV, _open, &fd);
-
- 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);
- }
- i2c_init(I2C_DEV, _close, &fd);
-
- //Send Frequency data to subscribers
- if(freq_callback)
- {
- freq_callback(frequency, freq_callback_data);
- }
-
- //Start RDS if the band was FM
- if(current_band==BAND_FM){
- //Unlock Mutex
- pthread_mutex_unlock (&RDS_Mutex);
-
- //Clean RDS Message
- Clear_RDS_Data(&RDS_Message);
-
- //Wait to make sure rds thread is finished
- usleep(300000);
-
- //Restart RDS
- tef665x_get_rds_info();
- }
-}
-
-/*
- * @brief Tune to a frequency in search mode
- *
- * Tune to new program and stay muted
- * Sending new frequency to subscribers
- *
- * @param uint32_t which is the frequecy to be tuned
- * @return void
- */
-static void tef665x_search_frequency(uint32_t frequency)
-{
- uint32_t fd = 0;
- int ret = i2c_init(I2C_DEV, _open, &fd);
- if(current_band == BAND_FM)
- {
- current_fm_frequency = frequency;
- _debug("frequency set to FM :", frequency);
- FM_tune_to(fd, eAR_TuningAction_Search, frequency / 10000);
-
- }
- else
- {
- current_am_frequency = frequency;
- _debug("frequency set to AM :", frequency);
- AM_tune_to(fd, eAR_TuningAction_Search, frequency / 1000);
- }
- i2c_init(I2C_DEV, _close, &fd);
-
- //Send Frequency data to subscribers
- if(freq_callback)
- {
- freq_callback(frequency, freq_callback_data);
- }
-}
-
-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",
- .probe = tef665x_probe,
- .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,
- .set_rds_callback=tef665x_set_rds_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,
- .get_quality_info = tef665x_get_quality_info,
- .set_alternative_frequency = tef665x_set_alternative_frequency
-};