完成libhackrf.so的编译之后,我们的android程序就可以通过libhackrf.so控制hackrf了。物理连接上,可以通过OTG线连接android设备和hackrf。libhackrf.so是动态库,android应用层需要通过JNI调用动态库,本文已简单FFT做为例子说一下android如何使用hackrf。


HackrfTouch这个app,总体的功能是能够显示信号FFT谱线图,能够改变频率等参数。从流程上看,HackrfTouch需要初始化hackrf,接收IQ数据,处理IQ数据,显示谱线图。为了保证效率,初始化和接收处理IQ数据这些操作都在c语言实现,最终结果发送到java层展现出来。


JNI方面

1)将编译好的库导入工程

拷贝哦libhackrf.h、libhackrf.so和libusb1.0.so到工程目录,创建libusb1.0.mk和libhackrf.mk

libusb1.0.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := libusb1.0LOCAL_SRC_FILES := libusb1.0.so include $(PREBUILT_SHARED_LIBRARY)

libhackrf.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := libhackrfLOCAL_SRC_FILES := libhackrf.so include $(PREBUILT_SHARED_LIBRARY)include $(LOCAL_PATH)/libusb1.0.mk

通过libhackrf.mk即可将libhackrf连接到工程中。


2)初始化hackrf,注册接收函数。

JNI接口

JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_test(JNIEnv *env, jclass cls) {int result = HACKRF_SUCCESS;result = hackrf_init();if (result == HACKRF_SUCCESS) {return env->NewStringUTF("OK!");} else {return env->NewStringUTF("Error!");}}JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_init(JNIEnv *env, jobject thiz) {int result = HACKRF_SUCCESS;uint8_t board_id = BOARD_ID_INVALID;char pbuf[2048] = { 0 };result = hackrf_init();if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_init() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}result = hackrf_open(&device);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_open() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}result = hackrf_board_id_read(device, &board_id);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_board_id_read() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}sprintf(pbuf, "Board ID Number: %d (%s)\n", board_id,hackrf_board_id_name((hackrf_board_id) board_id));return env->NewStringUTF(pbuf);}JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_setSampleRateManual(JNIEnv *env, jobject thiz, jlong freq, jint divi) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_set_sample_rate_manual(device, freq, divi);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_set_sample_rate_manual() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_setVgaGain(JNIEnv *env, jobject thiz, jint vga) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_set_vga_gain(device, vga);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_set_vga_gain() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}/* * Class:     com_pagekpang_hackrftouch_HackRFTouch * Method:    setLnaGain * Signature: (I)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_setLnaGain(JNIEnv *env, jobject thiz, jint lna) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_set_lna_gain(device, lna);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_set_lna_gain() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}/* * Class:     com_pagekpang_hackrftouch_HackRFTouch * Method:    setFreq * Signature: (J)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_setFreq(JNIEnv *env, jobject thiz, jlong freq) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_set_freq(device, freq);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_set_freq() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}/* * Class:     com_pagekpang_hackrftouch_HackRFTouch * Method:    setAmpEnable * Signature: (Ljava/lang/Boolean;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_setAmpEnable(JNIEnv *env, jobject thiz, jint b) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_set_amp_enable(device, b == 0 ? false : true);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_set_amp_enable() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_startRX(JNIEnv *env, jobject thiz) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_start_rx(device, hackrf_rx_cb, env->NewGlobalRef(thiz));if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_start_rx() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}/* * Class:     com_pagekpang_hackrftouch_HackRFTouch * Method:    stopRX * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_pagekpang_hackrftouch_HackRFTouch_stopRX(JNIEnv *env, jobject thiz) {int result = HACKRF_SUCCESS;char pbuf[2048] = { 0 };result = hackrf_stop_rx(device);if (result != HACKRF_SUCCESS) {sprintf(pbuf, "hackrf_stop_rx() failed: %s (%d)\n",hackrf_error_name((hackrf_error) result), result);return env->NewStringUTF(pbuf);}return env->NewStringUTF("ok");}
java层与JNI接口的绑定

package com.pagekpang.hackrftouch;public class HackRFTouch {static {System.loadLibrary("usb1.0");System.loadLibrary("hackrf");System.loadLibrary("HackrfTouch");}public static native String test();private native String init();private native String setSampleRateManual(long freq, int divi);private native String setVgaGain(int g);private native String setLnaGain(int g);private native String setFreq(long freq);private native String setAmpEnable(int f);public native String startRX();public native String stopRX();public native float[] readRx();private String retString = "";private Boolean isOpen = false;private ReadRxThread mReadRxThread = null;public HackRFTouch() {// TODO Auto-generated constructor stubretString = init();if (!retString.contains("failed")) {isOpen = true;mReadRxThread = new ReadRxThread(this);}}class ReadRxThread extends Thread {HackRFTouch mThisHackRFTouch = null;public ReadRxThread(HackRFTouch t) {// TODO Auto-generated constructor stubmThisHackRFTouch = t;}@Overridepublic void run() {// TODO Auto-generated method stubsuper.run();while(true){mThisHackRFTouch.cb(mThisHackRFTouch.readRx());try {Thread.sleep(100);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}public Boolean isOpen() {return isOpen;}public String getLastError() {return retString;}public Boolean HsetSampleRateManual(long freq, int divi) {if (!isOpen) {return false;}retString = setSampleRateManual(freq, divi);if (retString.contains("failed")) {return false;} else {return true;}}public Boolean HsetLnaGain(int g) {if (!isOpen) {return false;}retString = setLnaGain(g);if (retString.contains("failed")) {return false;} else {return true;}}public Boolean HsetVgaGain(int g) {if (!isOpen) {return false;}retString = setVgaGain(g);if (retString.contains("failed")) {return false;} else {return true;}}public Boolean HsetFreq(long freq) {if (!isOpen) {return false;}retString = setFreq(freq);if (retString.contains("failed")) {return false;} else {return true;}}public Boolean HsetAmpEnable(int b) {if (!isOpen) {return false;}retString = setAmpEnable(b);if (retString.contains("failed")) {return false;} else {return true;}}public Boolean HstartRX() {if (!isOpen) {return false;}if (!isOpen) {retString = init();if (!retString.contains("failed")) {isOpen = true;mReadRxThread = new ReadRxThread(this);}else {return false;}}retString = startRX();if (retString.contains("failed")) {return false;} else {mReadRxThread.start();return true;}}public Boolean HstopRX() {if (!isOpen) {return false;}retString = stopRX();if (retString.contains("failed")) {return false;} else {return true;}}public interface HackrfEven {public void rx(float[] b);public float[] tx();}private HackrfEven mHackrfEven = null;public void HsetOnEvent(HackrfEven hackrfEven) {mHackrfEven = hackrfEven;}public void cb(float[] f) {if (mHackrfEven != null && f != null) {mHackrfEven.rx(f);}}}
最后调用这些函数,配置参数,完成初始化
if (!mHackRFTouch.HsetAmpEnable(1)) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();return;}if (!mHackRFTouch.HsetFreq((long) (977*1e5))) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();return;}if (!mHackRFTouch.HsetLnaGain(24)) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();return;}if (!mHackRFTouch.HsetSampleRateManual((long) 8e6, 4)) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();return;}if (!mHackRFTouch.HsetVgaGain(10)) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();return;}if (!mHackRFTouch.HstartRX()) {Toast.makeText(this, mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();}else {Toast.makeText(this, "启动成功\n"+mHackRFTouch.getLastError(), Toast.LENGTH_LONG).show();}

3)FFT运算

if (device != NULL) {float raw[1024];int dalen = transfer->valid_length;float realF, imagF, maxF;uint8_t *pbuf = transfer->buffer;while (dalen > 0 && runcount == 0) {complex* fdata = new complex [1024];complex* fout = new complex [1024];for (int i = 0; i < 2048; i += 2) {fdata[i / 2] = complex(meanN(&pbuf[i], 100), meanN(&pbuf[i + 1], 100));}FFT(fdata, fout, 10);//dft(fdata, 10, 0);//fout = fdata;maxF = 0.0;for (int i = 0; i < 1024; i++) {raw[i] = pow(pow(fout[i].real(), 2) + pow(fout[i].imag(), 2),0.5);if (maxF < raw[i]) {maxF = raw[i];}}for (int i = 0; i < 1024; i++) {raw[i] = raw[i] / maxF;}sendBuf(raw);//send(g_client, (char *)&raw, 4*1024, 0); //发送数据dalen -= 2048;pbuf += 2048;runcount = 2;}runcount--;//printf("E");} else {printf("O");}

因为Hackrf上送的数据量非常大, 基于性能考虑,使用runcount变量控制处理次数。


至此,问中提及的代码片可以在我的code中找到整体,android中使用OTG最主要还是权限问题,在移植libusb文章已经讲过解决方案,如果遇到libusb初始化失败,可以考虑一下这方面原因。



更多相关文章

  1. SQLite数据库(2):ANDROID工程中的使用
  2. Android之路之十一(SharedPreferences&SQLite数据库)
  3. 记android学习之路----android中对json数据的解析
  4. android中的search dialog
  5. Android(安卓)binder学习一:主要概念
  6. Android(安卓)Tween 动画 (渐变、缩放、位移、旋转)
  7. android sqlite批量插入数据速度慢解决方案
  8. android数据库操作出现的 android.database.sqlite.SQLiteConstr
  9. 剖析andriod联系人

随机推荐

  1. Android中几种数据结构使用
  2. android 隐藏键盘 ----- 断点记录
  3. 一 Android Camera框架
  4. XML解析各种方式比较
  5. 如何低成本打造品牌Android软件?
  6. Android(安卓)studio 43 文件存储到sdcar
  7. Android Retrofit框架的使用和个人见解
  8. 专题分纲目录 android 系统核心机制 bind
  9. 用VS2010开发Android应用的配置方法
  10. Android Touch事件传递机制引发的血案