Editing GRAndWalkthrough

Jump to navigation Jump to search

Warning: You are not logged in. Your IP address will be publicly visible if you make any edits. If you log in or create an account, your edits will be attributed to your username, along with other benefits.

The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.

Latest revision Your text
Line 6: Line 6:


* Open Android Studio
* Open Android Studio
** File > New> New Project
** File <s>&gt; New</s>&gt; New Project
** Give it a name and a company domain
** Give it a name and a company domain
** Select the type -- probably Phone and Tablet
** Select the type -- probably Phone and Tablet
** And the API level is "API 21: Android 5.0 (Lollipop)"
** And the API level is &quot;API 21: Android 5.0 (Lollipop)&quot;
** Select a Blank Activity
** Select a Blank Activity
** Give the main activity a name (e.g., GrTemplate or stick with MainActivity)
** Give the main activity a name (e.g., GrTemplate or stick with MainActivity)
Line 16: Line 16:
* Open [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/AndroidManifest.xml AndroidManifest.xml] (under '''GrTemplate/app/main''' or '''manifests''' depending on your Android Studio view)
* Open [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/AndroidManifest.xml AndroidManifest.xml] (under '''GrTemplate/app/main''' or '''manifests''' depending on your Android Studio view)


* Add necessary permissions. Put this before the <application> start tag.
'''''' Add necessary permissions. Put this before the <application> start tag.


* Necessary permissions (for preferences, volk config, gnuradio config, and USRP firmware/FPGA binaries)
''''''* Necessary permissions (for preferences, volk config, gnuradio config, and USRP firmware/FPGA binaries)


<pre>  
<pre>   
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
   </pre>
   </pre>
* You will need access to the Internet interface for ControlPort and ZMQ
''''''* You will need access to the Internet interface for ControlPort and ZMQ


<pre>  <uses-permission android:name="android.permission.INTERNET"/> </pre>
<pre>  </pre>
* For talking to the audio input or output
''''''* For talking to the audio input or output


<pre>   <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"/>
<pre>
   <uses-permission android:name="android.permission.RECORD_AUDIO"/>
    
  <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
   </pre>
   </pre>
== Setup the JNI ==
== Setup the JNI ==


* Create a new '''jni''' directory.
* Create a new '''jni''' directory.
** app > src >main > Right Click> New > Directory> 'jni'
** app &gt; src &gt;main <s>&gt; Right Click</s>&gt; New <s>&gt; Directory</s>&gt; 'jni'
** This makes a folder app/src/main/jni
** This makes a folder app/src/main/jni
* Add the Android makefiles we provide
* Add the Android makefiles we provide
** [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/GrAndroid.mk GrAndroid.mk]: This declares and allows us to pull in all of the GNU Radio dependencies for building the JNI library.
** [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/GrAndroid.mk GrAndroid.mk]: This declares and allows us to pull in all of the GNU Radio dependencies for building the JNI library.
*** Note that it assumes we've put the [http://gnuradio.org/data/android/grandroid.tar.gz dependencies] into /opt/grandroid.
*** Note that it assumes we've put the [http://gnuradio.org/data/android/grandroid.tar.gz dependencies] into /opt/grandroid.
**** If not, change that up top in the "GRLIBPATH" variable.
**** If not, change that up top in the &quot;GRLIBPATH&quot; variable.
*** This creates:
*** This creates:
**** GR_WHOLE_STATIC_LIBRARIES: libUHD
**** GR_WHOLE_STATIC_LIBRARIES: libUHD
Line 62: Line 58:


* We've created the '''jni''' directory where our flowgraph lives.
* We've created the '''jni''' directory where our flowgraph lives.
* Add a new file to this directory: Right-Click -> New > New C/C++ Source File
* Add a new file to this directory: Right-Click -&gt; New &gt; New C/C++ Source File
** name this file fg.cpp and see the [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/fg.cpp flowgraph file] in the GrTemplate repo.
** name this file fg.cpp and see the [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/fg.cpp flowgraph file] in the GrTemplate repo.


<syntaxhighlight lang="c++">// Required
<pre>// Required
#include <jni.h>
#include  


// We'll likely want these
// We'll likely want these
#include <vector>
#include  
#include <string>
#include  


// Get any GNU Radio headers
// Get any GNU Radio headers
#include <gnuradio/top_block.h>
#include  
#include <gnuradio/blocks/null_source.h>
#include  
#include <gnuradio/blocks/throttle.h>
#include  
#include <gnuradio/blocks/null_sink.h>
#include  
// Other block headers next
// Other block headers next


Line 83: Line 79:
gr::top_block_sptr tb;
gr::top_block_sptr tb;


extern "C" {
extern &quot;C&quot; {


JNIEXPORT void JNICALL
JNIEXPORT void JNICALL
Line 89: Line 85:
                                                 jobject thiz)
                                                 jobject thiz)
{
{
   GR_INFO("fg", "FgInit Called");
   GR_INFO(&quot;fg&quot;, &quot;FgInit Called&quot;);


   // Declare our GNU Radio blocks
   // Declare our GNU Radio blocks
Line 97: Line 93:


   // Construct the objects for every block in the flwograph
   // Construct the objects for every block in the flwograph
   tb = gr::make_top_block("fg");
   tb = gr::make_top_block(&quot;fg&quot;);
   src = gr::blocks::null_source::make(sizeof(gr_complex));
   src = gr::blocks::null_source::make(sizeof(gr_complex));
   thr = gr::blocks::throttle::make(sizeof(gr_complex), 10000);
   thr = gr::blocks::throttle::make(sizeof(gr_complex), 10000);
Line 103: Line 99:


   // Connect up the flowgraph
   // Connect up the flowgraph
   tb->connect(src, 0, thr, 0);
   tb-&gt;connect(src, 0, thr, 0);
   tb->connect(thr, 0, snk, 0);
   tb-&gt;connect(thr, 0, snk, 0);
}
}


Line 111: Line 107:
                                                   jobject thiz)
                                                   jobject thiz)
{
{
   GR_INFO("fg", "FgStart Called");
   GR_INFO(&quot;fg&quot;, &quot;FgStart Called&quot;);
   tb->start();
   tb-&gt;start();
}
}


Line 119: Line 115:
                                                 jobject thiz)
                                                 jobject thiz)
{
{
   GR_INFO("fg", "FgStop Called");
   GR_INFO(&quot;fg&quot;, &quot;FgStop Called&quot;);
   tb->stop();
   tb-&gt;stop();
   tb->wait();
   tb-&gt;wait();
   GR_INFO("fg", "FgStop Exited");
   GR_INFO(&quot;fg&quot;, &quot;FgStop Exited&quot;);
}
}


Line 129: Line 125:
                                                 jobject thiz)
                                                 jobject thiz)
{
{
   return env->NewStringUTF(tb->edge_list().c_str());
   return env-&gt;NewStringUTF(tb-&gt;edge_list().c_str());
}
}


}</syntaxhighlight>
}</pre>
* This flowgraph is very simple and just creates the following flowgraph:
* This flowgraph is very simple and just creates the following flowgraph:
** <code>null_source -> throttle -> null_sink</code>
** <code>null_source -&gt; throttle -&gt; null_sink</code>
* There are four JNI functions declared here that we can use from our Java app:
* There are four JNI functions declared here that we can use from our Java app:
** FgInit: Where we ceate the blocks and construct the flowgraph.
** FgInit: Where we ceate the blocks and construct the flowgraph.
Line 147: Line 143:
* Add another C++ file called [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/settmp.cpp settmp.cpp] that looks like:
* Add another C++ file called [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/jni/settmp.cpp settmp.cpp] that looks like:


<syntaxhighlight lang="c++">
<pre>#include  
#include <jni.h>
#include  
#include <cstdlib>


extern "C" {
extern &quot;C&quot; {


JNIEXPORT void JNICALL
JNIEXPORT void JNICALL
Line 159: Line 154:
{
{
   const char *tmp_c;
   const char *tmp_c;
   tmp_c = env->GetStringUTFChars(tmpname, NULL);
   tmp_c = env-&gt;GetStringUTFChars(tmpname, NULL);
   setenv("TMP", tmp_c, 1);
   setenv(&quot;TMP&quot;, tmp_c, 1);
}
}


}</syntaxhighlight>
}</pre>
 
== Set up the MainActivity to call SetTMP ==
== Set up the MainActivity to call SetTMP ==


* In the [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/java/org/gnuradio/grtemplate/MainActivity.java main activity Java file], setup the JNI interface functions and call SetTMP in the onCreate function.
* In the [https://github.com/trondeau/GrTemplate/blob/master/app/src/main/java/org/gnuradio/grtemplate/MainActivity.java main activity Java file], setup the JNI interface functions and call SetTMP in the onCreate function.


* For access to the JNI call, put the following at the bottom of the activity class:
'''''' For access to the JNI call, put the following at the bottom of the activity class:


<pre>    public native void SetTMP(String tmpname);
<pre>    public native void SetTMP(String tmpname);


     static {
     static {
         System.loadLibrary("fg");
         System.loadLibrary(&quot;fg&quot;);
     }</pre>
     }</pre>
* The library name is 'fg' because that's what we put into the Android.mk file's LOCAL_MODULE value.
'''''' The library name is 'fg' because that's what we put into the Android.mk file's LOCAL_MODULE value.


* In the onCreate function, just add this line:
'''''' In the onCreate function, just add this line:


<pre>    @Override
<pre>    @Override
Line 188: Line 182:
         ....
         ....
     }</pre>
     }</pre>
* This uses Java to get information about the application's cache directory, which is unknown by us or by the C++ application. We get it through these Android calls, and then pass it to the C++ part, which will set the environmental variable TMP to this directory. GNU Radio knows to look at TMP when setting up the scheduler.
'''''' This uses Java to get information about the application's cache directory, which is unknown by us or by the C++ application. We get it through these Android calls, and then pass it to the C++ part, which will set the environmental variable TMP to this directory. GNU Radio knows to look at TMP when setting up the scheduler.


* Similarly, let's add the flowgraph control JNI function to the MainActivity class
* Similarly, let's add the flowgraph control JNI function to the MainActivity class
Line 196: Line 190:
     public native void FgStop();
     public native void FgStop();
     public native void FgRep();</pre>
     public native void FgRep();</pre>
* Then in the onCreate function, add the init and start functions after SetTMP:
'''''' Then in the onCreate function, add the init and start functions after SetTMP:


<pre>        FgInit();
<pre>        FgInit();
Line 208: Line 202:


* Tell Android Studio about the NDK:
* Tell Android Studio about the NDK:
** Under Gradle Scripts > local.properties
** Add a line fo the NDK:
** ndk.dir=/opt/ndk
** Or wherever you installed the NDK on your system.


* Next, we have to modify Gradle Scripts > "build.gradle (Module: app)" (Can also find this under the '''app''' directory).
'''''' Under Gradle Scripts &gt; local.properties
 
''''''* Add a line fo the NDK:
 
''''''* ndk.dir=/opt/ndk
 
'''''' Or wherever you installed the NDK on your system.
 
* Next, we have to modify Gradle Scripts &gt; &quot;build.gradle (Module: app)&quot; (Can also find this under the '''app''' directory).


* Here we will tell Android Studio not to try and do its own thing with the NDK but to run the command 'ndk-build' from the path directly. This makes sure that the build system uses our Android.mk file, which is important because we have a lot of libraries to install ourselves and there isn't a better way to do this in Android Studio.
'''''' Here we will tell Android Studio not to try and do its own thing with the NDK but to run the command 'ndk-build' from the path directly. This makes sure that the build system uses our Android.mk file, which is important because we have a lot of libraries to install ourselves and there isn't a better way to do this in Android Studio.


* Add the following lines just after the 'buildToolsVersion' line:
'''''' Add the following lines just after the 'buildToolsVersion' line:


<syntaxhighlight lang="Java">    // SETUP TO USE OUR OWN Android.mk FILE
<pre>    // SETUP TO USE OUR OWN Android.mk FILE
     sourceSets.main {
     sourceSets.main {
         jniLibs.srcDirs = ['src/main/libs']
         jniLibs.srcDirs = ['src/main/libs']
Line 231: Line 229:


     tasks.withType(JavaCompile) {
     tasks.withType(JavaCompile) {
         compileTask -> compileTask.dependsOn ndkBuild
         compileTask -&gt; compileTask.dependsOn ndkBuild
     }</syntaxhighlight>
     }</pre>
 
== Build the Project ==
== Build the Project ==


* If it complains about UTF-8 incompatibility, look down in the bottom right corner for the setting to click on and switch this project to UTF-8.
* If it complains about UTF-8 incompatibility, look down in the bottom right corner for the setting to click on and switch this project to UTF-8.


* Open up a terminal and go to the application's main directory, "AppName/app/src/main" and run the android update project command:
* Open up a terminal and go to the application's main directory, &quot;AppName/app/src/main&quot; and run the android update project command:


<pre>$ android update project -p . -s -t android-21</pre>
<pre>$ android update project -p . -s -t android-21</pre>
'''''' I am sure there is a way to do this within Android Studio itself, but I've yet to figure out how. (Note: Tools>Android>'Sync Project with Gradle Files')
'''''' I am sure there is a way to do this within Android Studio itself, but I've yet to figure out how. (Note: Tools&gt;Android&gt;'Sync Project with Gradle Files')


* Build the program: Build -> Make Project (or Ctrl + F9)
* Build the program: Build -&gt; Make Project (or Ctrl + F9)
* At this point, if everything was done correctly above, the build should end with "BUILD SUCCESSFUL" in the Messages tab at the bottom of the Android Studio interface.
* At this point, if everything was done correctly above, the build should end with &quot;BUILD SUCCESSFUL&quot; in the Messages tab at the bottom of the Android Studio interface.
* Build the project with the fg.cpp we wrote. It will take a few seconds for the ndk-build to run, and you'll likely see a handful of warnings about the Android LOG levels, which you can ignore (or help us fix them!). You should not get any errors.
* Build the project with the fg.cpp we wrote. It will take a few seconds for the ndk-build to run, and you'll likely see a handful of warnings about the Android LOG levels, which you can ignore (or help us fix them!). You should not get any errors.


Please note that all contributions to GNU Radio are considered to be released under the Creative Commons Attribution-ShareAlike (see GNU Radio:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To edit this page, please answer the question that appears below (more info):

Cancel Editing help (opens in new window)