diff options
author | Ehsan Takalloo <ehsan.takalloo@gmail.com> | 2020-09-14 16:18:47 +0430 |
---|---|---|
committer | Ehsan Takalloo <ehsan.takalloo@gmail.com> | 2020-10-28 10:24:23 +0330 |
commit | d4fb6eb7a4648b74f930af667f9231226e4ce208 (patch) | |
tree | db267fab2460380f67fa5184c50e7fe9f84087fe | |
parent | 8958a8a3e98085c60c9cd803395be157e78e3565 (diff) |
Add support for tuning to alternative frequency
-Add a new verb for handling alternative frequency.
-Add a new structure (station_quality_t) and use it for sharing
quality parameters.
-Make tef665x implementations compatible with new structure.
-Update README.md file to cover new verbs.
Change-Id: Id78e3b9aa8896eca9ef44222657f21246de9914f
Signed-off-by: Ehsan Takalloo <ehsan.takalloo@gmail.com>
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | binding/radio-binding.c | 93 | ||||
-rw-r--r-- | binding/radio_impl.h | 31 | ||||
-rw-r--r-- | binding/radio_impl_tef665x.c | 260 |
4 files changed, 240 insertions, 146 deletions
@@ -22,6 +22,8 @@ respective audio stream. | scan_stop | stop scanning for station | | | stereo_mode | get/set stereo or mono mode | *Request:* {"value": "stereo" or "mono"} | | rds | get current RDS data | | +| quality | get station quality | | +| alternative_frequency | check an alternative frequency and retune | *Request:* {"value": 104900000} | ## Events diff --git a/binding/radio-binding.c b/binding/radio-binding.c index 45e8ecb..3b8561d 100644 --- a/binding/radio-binding.c +++ b/binding/radio-binding.c @@ -143,6 +143,97 @@ static void rds(afb_req_t request) afb_req_reply(request, ret_json, NULL, NULL); } +/* @brief Get quality information + * + * @param afb_req_t : an afb request structure + * + */ +static void quality(afb_req_t request) +{ + json_object *ret_json; + station_quality_t *quality_data; + + if (radio_impl_ops->get_quality_info == NULL) { + afb_req_reply(request, NULL, "failed", "Not supported"); + return; + } + + quality_data = radio_impl_ops->get_quality_info(); + ret_json=json_object_new_object(); + if(quality_data->af_update) + { + json_object_object_add(ret_json, "af_update", json_object_new_int((int) quality_data->af_update)); + } + if(quality_data->time_stamp){ + json_object_object_add(ret_json, "timestamp", json_object_new_int((int) quality_data->time_stamp)); + } + if(quality_data->rssi) + { + json_object_object_add(ret_json, "rssi", json_object_new_int((int) quality_data->rssi)); + } + if(quality_data->usn) + { + json_object_object_add(ret_json, "usn", json_object_new_int((int) quality_data->usn)); + } + if(quality_data->bandw) + { + json_object_object_add(ret_json, "bandwidth", json_object_new_int((int) quality_data->bandw)); + } + afb_req_reply(request, ret_json, NULL, NULL); + return; +} + +/* @brief Check alternative frequency + * + * @param afb_req_t : an afb request structure + * + */ +static void alternative_frequency(afb_req_t request) +{ + json_object *ret_json; + uint32_t alternative; + const char *value; + + if (radio_impl_ops->set_alternative_frequency == NULL) { + afb_req_reply(request, NULL, "failed", "Not supported"); + return; + } + + value = afb_req_value(request, "value"); + if(value) { + char *p; + radio_band_t band; + uint32_t min_frequency; + uint32_t max_frequency; + uint32_t step; + + alternative = (uint32_t) strtoul(value, &p, 10); + if(alternative && *p == '\0') { + band = radio_impl_ops->get_band(); + min_frequency = radio_impl_ops->get_min_frequency(band); + max_frequency = radio_impl_ops->get_max_frequency(band); + step = radio_impl_ops->get_frequency_step(band); + if(alternative < min_frequency || + alternative > max_frequency || + (alternative - min_frequency) % step) { + afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); + return; + } + radio_impl_ops->set_alternative_frequency(alternative); + ret_json = json_object_new_object(); + json_object_object_add(ret_json, "alternative", json_object_new_int((int32_t) alternative)); + afb_req_reply(request, ret_json, NULL, NULL); + } else { + afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); + return; + } + } + else { + afb_req_reply(request, NULL, "failed", "Invalid alternative frequency"); + return; + } +} + /* * @brief Get (and optionally set) frequency band * @@ -531,6 +622,8 @@ static const afb_verb_t verbs[]= { { .verb = "frequency", .session = AFB_SESSION_NONE, .callback = frequency, .info = "Get/Set frequency" }, { .verb = "band", .session = AFB_SESSION_NONE, .callback = band, .info = "Get/Set band" }, { .verb = "rds", .session = AFB_SESSION_NONE, .callback = rds, .info = "Get RDS information" }, + { .verb = "quality", .session = AFB_SESSION_NONE, .callback = quality, .info = "Get station quality information" }, + { .verb = "alternative_frequency", .session = AFB_SESSION_NONE, .callback = alternative_frequency, .info = "Check an alternative frequency" }, { .verb = "band_supported", .session = AFB_SESSION_NONE, .callback = band_supported, .info = "Check band support" }, { .verb = "frequency_range", .session = AFB_SESSION_NONE, .callback = frequency_range, .info = "Get frequency range" }, { .verb = "frequency_step", .session = AFB_SESSION_NONE, .callback = frequency_step, .info = "Get frequency step" }, diff --git a/binding/radio_impl.h b/binding/radio_impl.h index 2867d7f..8f1ee94 100644 --- a/binding/radio_impl.h +++ b/binding/radio_impl.h @@ -40,6 +40,34 @@ typedef enum { STEREO } radio_stereo_mode_t; +/* + * AF_update + * true if quality belongs to an alternative frequency + * + * time_stamp + * if time_stamp is zero, quality data won't be valid + * reliability depending on time stamp + * it takes some time after tuning to get valid quality data + * + * rssi + * (signed) + * level detector result(RF input level) + * + * usn + * FM ultrasonic noise detector (relative usn detector result) + * + * bandwidth + * IF bandwidth + */ +typedef struct +{ + bool af_update; + uint16_t time_stamp; + int16_t rssi; + uint16_t usn; + uint16_t bandw; +} station_quality_t; + typedef struct { char *name; @@ -86,6 +114,9 @@ typedef struct { char * (*get_rds_info)(void); + station_quality_t * (*get_quality_info)(void); + + void (*set_alternative_frequency)(uint32_t frequency); } radio_impl_ops_t; #endif /* _RADIO_IMPL_H */ diff --git a/binding/radio_impl_tef665x.c b/binding/radio_impl_tef665x.c index 17454b8..504f155 100644 --- a/binding/radio_impl_tef665x.c +++ b/binding/radio_impl_tef665x.c @@ -76,15 +76,6 @@ typedef struct { uint32_t step; } band_plan_t; -typedef struct -{ - int16_t level; - uint16_t usn; - uint16_t wam; - int16_t offset; - uint16_t bandw; -}sig_quality_t; - typedef struct{ radio_scan_callback_t callback; radio_scan_direction_t direction; @@ -104,7 +95,7 @@ typedef struct rds_data uint16_t PICode; uint8_t DI_Seg; uint8_t PTY_Code; - + uint8_t Year; uint8_t Month; uint8_t Day; @@ -124,6 +115,7 @@ 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; @@ -160,7 +152,6 @@ static void (*freq_callback)(uint32_t, void*); static void (*rds_callback) (void*); static void *freq_callback_data; -void Get_quality_status (sig_quality_t *); int tef665x_set_rds (uint32_t i2c_file_desc); #define DEBUG 0 @@ -184,6 +175,8 @@ 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; @@ -1630,108 +1623,6 @@ static int i2c_init(const char *i2c, int state, uint32_t *i2c_file_desc) return 0; } -/* -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. -*/ -void Get_quality_status(sig_quality_t *quality){ - - uint32_t i2c_file_desc=0; - int ret = i2c_init(I2C_DEV, _open, &i2c_file_desc); - - uint8_t data[14]; - int16_t level=0; - uint16_t usn=0; - uint16_t wam=0; - int16_t offset=0; - uint16_t bw=0; - - for (int looper=0;looper<1;looper++){ - 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)); - } - - - int status=((data[0]&0b00000011)<<8|data[1]); - if(status!=1000){ - AFB_ERROR("Data is not ready, try again; quality time stamp: %d",status); - looper--; - usleep(1000); - continue; - } - - level =(data[2] <<8|data[3] ); - usn =(data[4] <<8|data[5] ); - wam =(data[6] <<8|data[7] ); - offset =(data[8] <<8|data[9] ); - bw =(data[10]<<8|data[11]); - } - i2c_init(I2C_DEV, _close, &i2c_file_desc); - - quality->offset = offset; - quality->bandw = bw; - quality->level = level; - quality->wam = wam; - quality->usn = usn; - - - return; -} - static void tef665x_start(void) { int ret; @@ -1942,7 +1833,7 @@ void *scan_frequencies(scan_data_t* scan_data){ tef665x_search_frequency(new_freq); //wait 30 ms to make sure quality data is available - for(int i=0;i<30;i++) + for(int i=0;i<40;i++) { usleep(1000); @@ -1959,40 +1850,18 @@ void *scan_frequencies(scan_data_t* scan_data){ } //Get Quality of tuned frequeency - sig_quality_t quality; - Get_quality_status(&quality); + tef665x_get_quality_info();//Get_quality_status(); - if((quality.level >260 && quality.usn<100) || quality.bandw>1200) + if((quality.rssi >260 /*&& ->.usn<100/**/) || quality.bandw>1200) { - AFB_DEBUG("Quality is valid"); - AFB_INFO("level is: 0x%4X : %d",quality.level,quality.level); - AFB_INFO("usn is: 0x%4X : %d",quality.usn,quality.usn); - AFB_INFO("offset is: 0x%4X : %d",quality.offset,quality.offset); - AFB_INFO("wam is: 0x%4X : %d",quality.wam,quality.wam); - AFB_INFO("Bandwidth is: 0x%4X : %d",quality.bandw,quality.bandw); - - //Send + //Send frequency value if(scan_data->callback) { scan_data->callback(new_freq,NULL); } - else - { - AFB_DEBUG("callback is not valid"); - } - + break; } - else - { - AFB_DEBUG("Quality is not valid"); - AFB_ERROR("level is: 0x%4X : %d",quality.level,quality.level); - AFB_ERROR("usn is: 0x%4X %d",quality.usn,quality.usn); - AFB_ERROR("offset is: 0x%4X %d",quality.offset,quality.offset); - AFB_ERROR("wam is: 0x%4X %d",quality.wam,quality.wam); - AFB_ERROR("bandwidth is: 0x%4X %d",quality.bandw,quality.bandw); - } - usleep(100); } @@ -2022,11 +1891,97 @@ static char *tef665x_get_rds_info(void) } /* + * @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 + * + * @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 + * @param radio_scan_callback_t callback which is the callback for sending result of search to * station_found ecent subscribers * @return void */ @@ -2034,7 +1989,6 @@ 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); @@ -2086,7 +2040,6 @@ static void tef665x_scan_stop(void) } } - /* module 32 / 33 FM / AM cmd 133 Get_Signal_Status | status @@ -2257,6 +2210,19 @@ static uint32_t tef665x_get_frequency(void) } } +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; @@ -2411,5 +2377,7 @@ radio_impl_ops_t tef665x_impl_ops = { .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_rds_info = tef665x_get_rds_info, + .get_quality_info = tef665x_get_quality_info, + .set_alternative_frequency = tef665x_set_alternative_frequency }; |