aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEhsan Takalloo <ehsan.takalloo@gmail.com>2020-09-14 16:18:47 +0430
committerEhsan Takalloo <ehsan.takalloo@gmail.com>2020-10-28 10:24:23 +0330
commitd4fb6eb7a4648b74f930af667f9231226e4ce208 (patch)
treedb267fab2460380f67fa5184c50e7fe9f84087fe
parent8958a8a3e98085c60c9cd803395be157e78e3565 (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.md2
-rw-r--r--binding/radio-binding.c93
-rw-r--r--binding/radio_impl.h31
-rw-r--r--binding/radio_impl_tef665x.c260
4 files changed, 240 insertions, 146 deletions
diff --git a/README.md b/README.md
index 90184b7..79032ad 100644
--- a/README.md
+++ b/README.md
@@ -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
};