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
25static int g_idx = -1;
26extern struct fmr_ds fmr_data;
27
28jboolean 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
38jboolean 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
48jboolean 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
61jboolean 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
71jboolean 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
83jfloat 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
109jshortArray 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
141out:
142    LOGD("%s, [cnt=%d] [ret=%d]\n", __func__, chl_cnt, ret);
143    return scanChlarray;
144}
145
146jshort 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
161jbyteArray 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
179jbyteArray 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
197jshort 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
211jshortArray 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
229jint 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
247jboolean 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
259jint 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 ******************************************/
280jint 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 ******************************************/
304jint 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    }
329out:
330    LOGD("%s: [antenna=%d] [ret=%d]\n", __func__, ana, ret);
331    return jret;
332}
333
334static const char *classPathNameRx = "com/android/fmradio/FmNative";
335
336static 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 */
358static 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 */
386static 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
405typedef union {
406    JNIEnv* env;
407    void* venv;
408} UnionJNIEnvToVoid;
409
410jint 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
435fail:
436    return result;
437}
438
439