1 /*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <jni.h>
18 #include "fmr.h"
19
20 #ifdef LOG_TAG
21 #undef LOG_TAG
22 #endif
23 #define LOG_TAG "FMLIB_JNI"
24
25 static int g_idx = -1;
26 extern struct fmr_ds fmr_data;
27
openDev(JNIEnv * env,jobject thiz)28 jboolean openDev(JNIEnv *env, jobject thiz)
29 {
30 int ret = 0;
31
32 ret = FMR_open_dev(g_idx); // if success, then ret = 0; else ret < 0
33
34 LOGD("%s, [ret=%d]\n", __func__, ret);
35 return ret?JNI_FALSE:JNI_TRUE;
36 }
37
closeDev(JNIEnv * env,jobject thiz)38 jboolean closeDev(JNIEnv *env, jobject thiz)
39 {
40 int ret = 0;
41
42 ret = FMR_close_dev(g_idx);
43
44 LOGD("%s, [ret=%d]\n", __func__, ret);
45 return ret?JNI_FALSE:JNI_TRUE;
46 }
47
powerUp(JNIEnv * env,jobject thiz,jfloat freq)48 jboolean powerUp(JNIEnv *env, jobject thiz, jfloat freq)
49 {
50 int ret = 0;
51 int tmp_freq;
52
53 LOGI("%s, [freq=%d]\n", __func__, (int)freq);
54 tmp_freq = (int)(freq * 10); //Eg, 87.5 * 10 --> 875
55 ret = FMR_pwr_up(g_idx, tmp_freq);
56
57 LOGD("%s, [ret=%d]\n", __func__, ret);
58 return ret?JNI_FALSE:JNI_TRUE;
59 }
60
powerDown(JNIEnv * env,jobject thiz,jint type)61 jboolean powerDown(JNIEnv *env, jobject thiz, jint type)
62 {
63 int ret = 0;
64
65 ret = FMR_pwr_down(g_idx, type);
66
67 LOGD("%s, [ret=%d]\n", __func__, ret);
68 return ret?JNI_FALSE:JNI_TRUE;
69 }
70
tune(JNIEnv * env,jobject thiz,jfloat freq)71 jboolean tune(JNIEnv *env, jobject thiz, jfloat freq)
72 {
73 int ret = 0;
74 int tmp_freq;
75
76 tmp_freq = (int)(freq * 10); //Eg, 87.5 * 10 --> 875
77 ret = FMR_tune(g_idx, tmp_freq);
78
79 LOGD("%s, [ret=%d]\n", __func__, ret);
80 return ret?JNI_FALSE:JNI_TRUE;
81 }
82
seek(JNIEnv * env,jobject thiz,jfloat freq,jboolean isUp)83 jfloat seek(JNIEnv *env, jobject thiz, jfloat freq, jboolean isUp) //jboolean isUp;
84 {
85 int ret = 0;
86 int tmp_freq;
87 int ret_freq;
88 float val;
89
90 tmp_freq = (int)(freq * 100); //Eg, 87.55 * 100 --> 8755
91 ret = FMR_set_mute(g_idx, 1);
92 if (ret) {
93 LOGE("%s, error, [ret=%d]\n", __func__, ret);
94 }
95 LOGD("%s, [mute] [ret=%d]\n", __func__, ret);
96
97 ret = FMR_seek(g_idx, tmp_freq, (int)isUp, &ret_freq);
98 if (ret) {
99 ret_freq = tmp_freq; //seek error, so use original freq
100 }
101
102 LOGD("%s, [freq=%d] [ret=%d]\n", __func__, ret_freq, ret);
103
104 val = (float)ret_freq/100; //Eg, 8755 / 100 --> 87.55
105
106 return val;
107 }
108
autoScan(JNIEnv * env,jobject thiz)109 jshortArray autoScan(JNIEnv *env, jobject thiz)
110 {
111 #define FM_SCAN_CH_SIZE_MAX 200
112 int ret = 0;
113 jshortArray scanChlarray;
114 int chl_cnt = FM_SCAN_CH_SIZE_MAX;
115 uint16_t ScanTBL[FM_SCAN_CH_SIZE_MAX];
116
117 LOGI("%s, [tbl=%p]\n", __func__, ScanTBL);
118 FMR_Pre_Search(g_idx);
119 ret = FMR_scan(g_idx, ScanTBL, &chl_cnt);
120 if (ret < 0) {
121 LOGE("scan failed!\n");
122 scanChlarray = NULL;
123 goto out;
124 }
125 if (chl_cnt > 0) {
126 scanChlarray = env->NewShortArray(chl_cnt);
127 env->SetShortArrayRegion(scanChlarray, 0, chl_cnt, (const jshort*)&ScanTBL[0]);
128 } else {
129 LOGE("cnt error, [cnt=%d]\n", chl_cnt);
130 scanChlarray = NULL;
131 }
132 FMR_Restore_Search(g_idx);
133
134 if (fmr_data.scan_stop == fm_true) {
135 ret = FMR_tune(g_idx, fmr_data.cur_freq);
136 LOGI("scan stop!!! tune ret=%d",ret);
137 scanChlarray = NULL;
138 ret = -1;
139 }
140
141 out:
142 LOGD("%s, [cnt=%d] [ret=%d]\n", __func__, chl_cnt, ret);
143 return scanChlarray;
144 }
145
readRds(JNIEnv * env,jobject thiz)146 jshort readRds(JNIEnv *env, jobject thiz)
147 {
148 int ret = 0;
149 uint16_t status = 0;
150
151 ret = FMR_read_rds_data(g_idx, &status);
152
153 if (ret) {
154 //LOGE("%s,status = 0,[ret=%d]\n", __func__, ret);
155 status = 0; //there's no event or some error happened
156 }
157
158 return status;
159 }
160
getPs(JNIEnv * env,jobject thiz)161 jbyteArray getPs(JNIEnv *env, jobject thiz)
162 {
163 int ret = 0;
164 jbyteArray PSname;
165 uint8_t *ps = NULL;
166 int ps_len = 0;
167
168 ret = FMR_get_ps(g_idx, &ps, &ps_len);
169 if (ret) {
170 LOGE("%s, error, [ret=%d]\n", __func__, ret);
171 return NULL;
172 }
173 PSname = env->NewByteArray(ps_len);
174 env->SetByteArrayRegion(PSname, 0, ps_len, (const jbyte*)ps);
175 LOGD("%s, [ret=%d]\n", __func__, ret);
176 return PSname;
177 }
178
getLrText(JNIEnv * env,jobject thiz)179 jbyteArray getLrText(JNIEnv *env, jobject thiz)
180 {
181 int ret = 0;
182 jbyteArray LastRadioText;
183 uint8_t *rt = NULL;
184 int rt_len = 0;
185
186 ret = FMR_get_rt(g_idx, &rt, &rt_len);
187 if (ret) {
188 LOGE("%s, error, [ret=%d]\n", __func__, ret);
189 return NULL;
190 }
191 LastRadioText = env->NewByteArray(rt_len);
192 env->SetByteArrayRegion(LastRadioText, 0, rt_len, (const jbyte*)rt);
193 LOGD("%s, [ret=%d]\n", __func__, ret);
194 return LastRadioText;
195 }
196
activeAf(JNIEnv * env,jobject thiz)197 jshort activeAf(JNIEnv *env, jobject thiz)
198 {
199 int ret = 0;
200 jshort ret_freq = 0;
201
202 ret = FMR_active_af(g_idx, (uint16_t*)&ret_freq);
203 if (ret) {
204 LOGE("%s, error, [ret=%d]\n", __func__, ret);
205 return 0;
206 }
207 LOGD("%s, [ret=%d]\n", __func__, ret);
208 return ret_freq;
209 }
210
getAFList(JNIEnv * env,jobject thiz)211 jshortArray getAFList(JNIEnv *env, jobject thiz)
212 {
213 int ret = 0;
214 jshortArray AFList;
215 char *af = NULL;
216 int af_len = 0;
217
218 //ret = FMR_get_af(g_idx, &af, &af_len); // If need, we should implemate this API
219 if (ret) {
220 LOGE("%s, error, [ret=%d]\n", __func__, ret);
221 return NULL;
222 }
223 AFList = env->NewShortArray(af_len);
224 env->SetShortArrayRegion(AFList, 0, af_len, (const jshort*)af);
225 LOGD("%s, [ret=%d]\n", __func__, ret);
226 return AFList;
227 }
228
setRds(JNIEnv * env,jobject thiz,jboolean rdson)229 jint setRds(JNIEnv *env, jobject thiz, jboolean rdson)
230 {
231 int ret = 0;
232 int onoff = -1;
233
234 if (rdson == JNI_TRUE) {
235 onoff = FMR_RDS_ON;
236 } else {
237 onoff = FMR_RDS_OFF;
238 }
239 ret = FMR_turn_on_off_rds(g_idx, onoff);
240 if (ret) {
241 LOGE("%s, error, [ret=%d]\n", __func__, ret);
242 }
243 LOGD("%s, [onoff=%d] [ret=%d]\n", __func__, onoff, ret);
244 return ret?JNI_FALSE:JNI_TRUE;
245 }
246
stopScan(JNIEnv * env,jobject thiz)247 jboolean stopScan(JNIEnv *env, jobject thiz)
248 {
249 int ret = 0;
250
251 ret = FMR_stop_scan(g_idx);
252 if (ret) {
253 LOGE("%s, error, [ret=%d]\n", __func__, ret);
254 }
255 LOGD("%s, [ret=%d]\n", __func__, ret);
256 return ret?JNI_FALSE:JNI_TRUE;
257 }
258
setMute(JNIEnv * env,jobject thiz,jboolean mute)259 jint setMute(JNIEnv *env, jobject thiz, jboolean mute)
260 {
261 int ret = 0;
262
263 ret = FMR_set_mute(g_idx, (int)mute);
264 if (ret) {
265 LOGE("%s, error, [ret=%d]\n", __func__, ret);
266 }
267 LOGD("%s, [mute=%d] [ret=%d]\n", __func__, (int)mute, ret);
268 return ret?JNI_FALSE:JNI_TRUE;
269 }
270
271 /******************************************
272 * Inquiry if RDS is support in driver.
273 * Parameter:
274 * None
275 *Return Value:
276 * 1: support
277 * 0: NOT support
278 * -1: error
279 ******************************************/
isRdsSupport(JNIEnv * env,jobject thiz)280 jint isRdsSupport(JNIEnv *env, jobject thiz)
281 {
282 int ret = 0;
283 int supt = -1;
284
285 ret = FMR_is_rdsrx_support(g_idx, &supt);
286 if (ret) {
287 LOGE("%s, error, [ret=%d]\n", __func__, ret);
288 }
289 LOGD("%s, [supt=%d] [ret=%d]\n", __func__, supt, ret);
290 return supt;
291 }
292
293 /******************************************
294 * SwitchAntenna
295 * Parameter:
296 * antenna:
297 0 : switch to long antenna
298 1: switch to short antenna
299 *Return Value:
300 * 0: Success
301 * 1: Failed
302 * 2: Not support
303 ******************************************/
switchAntenna(JNIEnv * env,jobject thiz,jint antenna)304 jint switchAntenna(JNIEnv *env, jobject thiz, jint antenna)
305 {
306 int ret = 0;
307 jint jret = 0;
308 int ana = -1;
309
310 if (0 == antenna) {
311 ana = FM_LONG_ANA;
312 } else if (1 == antenna) {
313 ana = FM_SHORT_ANA;
314 } else {
315 LOGE("%s:fail, para error\n", __func__);
316 jret = JNI_FALSE;
317 goto out;
318 }
319 ret = FMR_ana_switch(g_idx, ana);
320 if (ret == -ERR_UNSUPT_SHORTANA) {
321 LOGW("Not support switchAntenna\n");
322 jret = 2;
323 } else if (ret) {
324 LOGE("switchAntenna(), error\n");
325 jret = 1;
326 } else {
327 jret = 0;
328 }
329 out:
330 LOGD("%s: [antenna=%d] [ret=%d]\n", __func__, ana, ret);
331 return jret;
332 }
333
334 static const char *classPathNameRx = "com/android/fmradio/FmNative";
335
336 static JNINativeMethod methodsRx[] = {
337 {"openDev", "()Z", (void*)openDev }, //1
338 {"closeDev", "()Z", (void*)closeDev }, //2
339 {"powerUp", "(F)Z", (void*)powerUp }, //3
340 {"powerDown", "(I)Z", (void*)powerDown }, //4
341 {"tune", "(F)Z", (void*)tune }, //5
342 {"seek", "(FZ)F", (void*)seek }, //6
343 {"autoScan", "()[S", (void*)autoScan }, //7
344 {"stopScan", "()Z", (void*)stopScan }, //8
345 {"setRds", "(Z)I", (void*)setRds }, //10
346 {"readRds", "()S", (void*)readRds }, //11 will pending here for get event status
347 {"getPs", "()[B", (void*)getPs }, //12
348 {"getLrText", "()[B", (void*)getLrText}, //13
349 {"activeAf", "()S", (void*)activeAf}, //14
350 {"setMute", "(Z)I", (void*)setMute}, //15
351 {"isRdsSupport", "()I", (void*)isRdsSupport}, //16
352 {"switchAntenna", "(I)I", (void*)switchAntenna}, //17
353 };
354
355 /*
356 * Register several native methods for one class.
357 */
registerNativeMethods(JNIEnv * env,const char * className,JNINativeMethod * gMethods,int numMethods)358 static jint registerNativeMethods(JNIEnv* env, const char* className,
359 JNINativeMethod* gMethods, int numMethods)
360 {
361 jclass clazz;
362
363 clazz = env->FindClass(className);
364 if (env->ExceptionCheck()) {
365 env->ExceptionDescribe();
366 env->ExceptionClear();
367 }
368 if (clazz == NULL) {
369 LOGE("Native registration unable to find class '%s'", className);
370 return JNI_FALSE;
371 }
372 if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
373 LOGE("RegisterNatives failed for '%s'", className);
374 return JNI_FALSE;
375 }
376
377 LOGD("%s, success\n", __func__);
378 return JNI_TRUE;
379 }
380
381 /*
382 * Register native methods for all classes we know about.
383 *
384 * returns JNI_TRUE on success.
385 */
registerNatives(JNIEnv * env)386 static jint registerNatives(JNIEnv* env)
387 {
388 jint ret = JNI_FALSE;
389
390 if (registerNativeMethods(env, classPathNameRx,methodsRx,
391 sizeof(methodsRx) / sizeof(methodsRx[0]))) {
392 ret = JNI_TRUE;
393 }
394
395 LOGD("%s, done\n", __func__);
396 return ret;
397 }
398
399 // ----------------------------------------------------------------------------
400
401 /*
402 * This is called by the VM when the shared library is first loaded.
403 */
404
405 typedef union {
406 JNIEnv* env;
407 void* venv;
408 } UnionJNIEnvToVoid;
409
JNI_OnLoad(JavaVM * vm,void * reserved)410 jint JNI_OnLoad(JavaVM* vm, void* reserved)
411 {
412 UnionJNIEnvToVoid uenv;
413 uenv.venv = NULL;
414 jint result = -1;
415 JNIEnv* env = NULL;
416
417 LOGI("JNI_OnLoad");
418
419 if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
420 LOGE("ERROR: GetEnv failed");
421 goto fail;
422 }
423 env = uenv.env;
424
425 if (registerNatives(env) != JNI_TRUE) {
426 LOGE("ERROR: registerNatives failed");
427 goto fail;
428 }
429
430 if ((g_idx = FMR_init()) < 0) {
431 goto fail;
432 }
433 result = JNI_VERSION_1_4;
434
435 fail:
436 return result;
437 }
438
439