{"id":21008,"date":"2015-12-11T12:02:52","date_gmt":"2015-12-11T11:02:52","guid":{"rendered":"https:\/\/www.inovex.de\/\/?p=1219"},"modified":"2022-12-01T12:14:53","modified_gmt":"2022-12-01T11:14:53","slug":"android-sensor-integration-part-2-sensor-readings","status":"publish","type":"post","link":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/","title":{"rendered":"Android Sensor Integration Part 2: Sensor Readings"},"content":{"rendered":"<p>In the second part of our four part series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder. If you haven&#8217;t done so go check part one for the <a href=\"https:\/\/www.inovex.de\/\/android-sensor-integration-part-1-sensor-stack-and-kernel-module\/\" target=\"_blank\" rel=\"noopener\">basics of the Android sensor stack and kernel module integration<\/a>. Otherwise jump right in!<!--more--><\/p>\n<div style=\"background-color: #0079ff; color: white; padding: 1em;\">Disclaimer: The integration described here was implemented for the Pandaboard ES Rev B3 with a Linaro Android 4.4.4 and the ultrasonic range sensor SRF02 connected on an I2C bus. The full source code is <a style=\"color: white; text-decoration: underline;\" href=\"https:\/\/github.com\/Allegra42\/android-srf02\" target=\"_blank\" rel=\"noopener\">available on Github<\/a>. However this is written as a guideline for any standard sensor integration into Android. It should be considered work in progress with several ugly details that I know have to be fixed. And they will be in the future \u2013 probably. Only the files I really had to change have been uploaded.<\/div>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_79_2 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\"><p class=\"ez-toc-title\" style=\"cursor:inherit\"><\/p>\n<\/div><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Entries-for-the-sysfs-%E2%80%93-control-the-ranging\" >Entries for the sysfs \u2013 control the ranging<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Queues-and-Input-events-%E2%80%93-performing-the-readings\" >Queues and Input events \u2013 performing the\u00a0readings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Android-tired-Sensor-needs-to-sleep\" >Android tired, Sensor needs to sleep<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Clean-up\" >Clean up<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Stay-tuned\" >Stay tuned<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#Sources-Parts-1-and-2\" >Sources (Parts 1 and 2)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#The-Whole-Story\" >The Whole Story<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Entries-for-the-sysfs-%E2%80%93-control-the-ranging\"><\/span>Entries for the sysfs \u2013 control the ranging<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Finally we can start to implement sensor readings. We&#8217;ll begin by\u00a0creating\u00a0a file in sysfs as an interface to the userspace. To interact with the sensor\u00a0we need two access functions: The first one for writing access to enable\u00a0or disable the readings\u00a0and the other one for reading access as a way to get the results.<\/p>\n<p>Let&#8217;s take a\u00a0look at the function which handles writing access to the corresponding sysfs entry. As mentioned\u00a0this function\u00a0will allow us to\u00a0enable or disable readings. To do so\u00a0we read from the standard input. For better evaluation the input is converted to a long. If the detected input value is greater than 0, a delayed workqueue for performing the repeated measurements is created. If it isn&#8217;t\u00a0the\u00a0existing queue is destroyed to end this periodic action.\u00a0What exactly is happening here\u00a0will be discussed\u00a0in the next chapter.<\/p>\n<pre class=\"lang:c decode:true\">static ssize_t srf02_store_values_cyclic (struct device *dev, struct device_attribute *attr, const char *buf, size_t size) {\r\n\r\nunsigned long value;\r\n\r\nint ret;\r\n\r\nvalue = simple_strtoul (buf, NULL, 10);\r\n\r\nif (value &gt; 0) {\r\n\r\n    dev_static = dev;\r\n\r\n    my_wq = create_workqueue(\"my_workqueue\");\r\n\r\n    if (my_wq) {\r\n\r\n        work = (my_work_t *) kmalloc (sizeof (my_work_t), GFP_KERNEL);\r\n\r\n        if (work) {\r\n\r\n            INIT_DELAYED_WORK ((struct delayed_work *) work, workq_fn);\r\n\r\n            ret = queue_delayed_work(my_wq, (struct delayed_work *) work, msecs_to_jiffies(100));\r\n\r\n        }\r\n\r\n    }\r\n\r\n    value_nonstop = 0;\r\n\r\n}\r\n\r\nif (value == 0) {\r\n\r\n    cancel_delayed_work((struct delayed_work *)work);\r\n\r\n    value_nonstop = -1; \/\/ for disabling -\r\n\r\n}\r\n\r\nreturn size;\r\n\r\n}<\/pre>\n<p>With <span class=\"lang:c decode:true crayon-inline\">srf02_get_values_cyclic ()<\/span>\u00a0we implement a function to\u00a0read\u00a0the results from our file after reading range data from our sensor.<\/p>\n<p>To connect the file name in the sysfs with these access functions and set up a proper rights management, we define a device attribute with name, rights, getter- and setter-functions. The name, <span class=\"lang:c decode:true crayon-inline\">value_now<\/span>, appears in the sysfs as a file we can interact with.<\/p>\n<p>For each file we create for access, a special role of the driver must be registered in the attribute structure.<\/p>\n<pre class=\"lang:c decode:true\">static DEVICE_ATTR (value_now, 0644, srf02_get_values_cyclic, srf02_store_values_cyclic);\r\n\r\nstatic const struct attribute *srf02_attrs[] = {\r\n\r\n    &amp;dev_attr_value_now.attr,\r\n\r\n    &amp;dev_attr_srf02value.attr,\r\n\r\n    NULL,\r\n\r\n};\r\n\r\nstatic const struct attribute_group srf02_attr_group = {\r\n\r\n    .attrs = srf02_attrs,\r\n\r\n};<\/pre>\n<p>From a debugging console we\u00a0can now\u00a0test enabling and disabling the readings\u00a0with<\/p>\n<p><span class=\"lang:sh decode:true crayon-inline\">echo 1 &gt; \/sys\/bus\/i2c\/devices\/i2c-4\/4-0070\/value_now<\/span>. This\u00a0command writes a \u201c1\u201c to the sysfs entry <span style=\"color: #000000;\">we have named above<\/span>. At this path, i2c-4 means our device is connected at the i2c bus number 4. The folder 4-0070 holds\u00a0all accessible files for the device at i2c bus 4 with the address 0x70.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Queues-and-Input-events-%E2%80%93-performing-the-readings\"><\/span>Queues and Input events \u2013 performing the\u00a0readings<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>So why are we choosing delayed workqueues?\u00a0We want to have a mechanism for the readings\u00a0that runs periodically in a defined interval without blocking the CPU\u00a0in between two cycles. Delayed workqueues provide just that. We only have\u00a0to define a function for them which defines the task that should be repeated.<\/p>\n<p>The delayed workqueue is created, as shown\u00a0in the code snipped above, by setting up a queue with\u00a0<span class=\"lang:c decode:true crayon-inline\">create_workqueue()<\/span>. Then we allocate storage for the work structure and initialize the delayed work with the structure and the function to perform using <span class=\"lang:c decode:true crayon-inline\">INIT_DELAYED_WORK()<\/span>. There is a difference between the functions for setting up and destroying workqueues and delayed workqueues, it won&#8217;t work if you mix them.<\/p>\n<p>At the end we writeour work structure (<span class=\"lang:c decode:true crayon-inline\">my_work_t *work<\/span>) to\u00a0the created queue (<span class=\"lang:c decode:true crayon-inline \">workqueue_struct my_wq<\/span>), which contains a reference to the work function (<span class=\"lang:c decode:true crayon-inline\">workq_fn<\/span>) and set a delay for starting this task.\u00a0With the same function, the work function writes itself back into the queue before it ends.<\/p>\n<p>The work function is responsible for the reading\u00a0itself. Therefore we file our device as an I2C slave and start the activity by\u00a0sending the command for getting the results in centimeters to the command register of\u00a0the client. The ranging of the\u00a0SRF02 ultrasonic sensor takes\u00a0up to 66 milliseconds, so just to be sure we will wait 100 ms. Then we are able to read the value from registers 2 and 3 as high and low bytes.<\/p>\n<pre class=\"lang:c decode:true\">void workq_fn (struct delayed_work *work) {\r\n\r\n    int ret = 0;\r\n\r\n    s32 i2cRet = 0;\r\n\r\n    int value_reg1 = 0;\r\n\r\n    int value_reg2 = 0;\r\n\r\n    struct i2c_client *client = to_i2c_client(dev_static);\r\n\r\n    \/\/write to command register that result shall be in cm\r\n\r\n    i2cRet = i2c_smbus_write_byte_data (client, CMD_COMMAND_REG, CMD_RESULT_IN_CM);\r\n\r\n    msleep(100);\r\n\r\n    \/\/Reading result\r\n\r\n    value_reg1 = i2c_smbus_read_byte_data (client, CMD_RANGE_HIGH_BYTE);\r\n\r\n    value_reg2 = i2c_smbus_read_byte_data (client, CMD_RANGE_LOW_BYTE);\r\n\r\n    value_nonstop = (value_reg1 * 256) + value_reg2;\r\n\r\n    input_event(srf02_input_dev, EV_ABS, ABS_DISTANCE, value_nonstop);\r\n\r\n    input_sync(srf02_input_dev);\r\n\r\n    queue_delayed_work(my_wq, (struct delayed_work *)work, msecs_to_jiffies(100));\r\n\r\n}<\/pre>\n<p>Above\u00a0we initialized the input subsystem we&#8217;ll use to generate input events for the HAL driver. Here in the <span class=\"lang:c decode:true crayon-inline\">workq_fn<\/span>\u00a0function we finally\u00a0produce these\u00a0events.<\/p>\n<p>Reporting a new input event is easy: With the <span class=\"lang:c decode:true crayon-inline\">input_event()<\/span>\u00a0function we specify the device that generates the event, name the type of the event as well as\u00a0the event code and transfer the result of the ranging as the\u00a0value of the event. For a proximity sensor we use <span class=\"lang:c decode:true crayon-inline \">EV_ABS<\/span>\u00a0as event type which is intended for describing absolute events and <span class=\"lang:c decode:true crayon-inline\">ABS_DISTANCE<\/span>\u00a0 as event code that is used to characterize a distance between the sensor and its interaction surface. With the <span class=\"lang:c decode:true crayon-inline \">input_sync()<\/span>\u00a0 function we tell the receiver that this report is complete. To test whether\u00a0input events with our label are generated, we run <span class=\"lang:sh decode:true crayon-inline\">adb getevent<\/span>.<\/p>\n<p>With the input subsystem we already have a mechanism to receive the results, but e.g for debugging we implement the function for reading access to the sysfs. That means we are able to read out sensor&#8217;s results with <span class=\"lang:sh decode:true crayon-inline\">cat \/sys\/bus\/i2c\/devices\/i2c-4\/4-0070\/value_now<\/span>.<\/p>\n<p>In the kernel module we just take the result and place it in the buffer that was given as an argument. A value less than 0 means that\u00a0reading\u00a0is disabled.<\/p>\n<pre class=\"lang:c decode:true\">static ssize_t srf02_get_values_cyclic (struct device *dev,\r\n\r\nstruct device_attribute *attr, char *buf) {\r\n\r\n    return sprintf (buf, \"%d \\n\", value_nonstop);\r\n\r\n}<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Android-tired-Sensor-needs-to-sleep\"><\/span>Android tired, Sensor needs to sleep<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><a href=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg.png\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-1238 size-medium alignright\" src=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-300x169.png\" alt=\"\" width=\"300\" height=\"169\" srcset=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-300x169.png 300w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-1024x576.png 1024w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-768x432.png 768w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-1536x864.png 1536w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-400x225.png 400w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-720x406.png 720w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg-360x203.png 360w, https:\/\/www.inovex.de\/wp-content\/uploads\/2015\/12\/sleepdroid-small-bg.png 1920w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Because Android is a mobile platform, saving energy is quite\u00a0important, so\u00a0the system\u00a0switches to a suspended state as often\u00a0as possible. Our\u00a0kernel module will\u00a0support this behavior by stopping the readings\u00a0while sleeping. To\u00a0support the Android autosleep mechanism we need to expand the <span class=\"lang:sh decode:true crayon-inline \">srf02_priv<\/span>\u00a0structure with an entry for an <span class=\"lang:sh decode:true crayon-inline \">early_suspend<\/span>\u00a0 structure. This handler is filled in the <span class=\"lang:c decode:true crayon-inline\">probe()<\/span>\u00a0function and holds references to the functions that will\u00a0be called for suspend and resume. Then we register the handler with <span class=\"lang:c decode:true crayon-inline \">register_early_suspend()<\/span>\u00a0.<\/p>\n<pre class=\"lang:c decode:true\">struct srf02_priv {\r\n\r\n    struct i2c_client *client;\r\n\r\n    #ifdef CONFIG_EARLYSUSPEND\r\n\r\n    struct early_suspend es_handler;\r\n\r\n    #endif\r\n\r\n};\r\n\r\nstatic int srf02_i2c_probe (struct i2c_client *client, const struct i2c_device_id *id) {\r\n\r\n    \/\/ ...\r\n\r\n    #ifdef CONFIG_EARLYSUSPEND\r\n\r\n    srf02_p-&gt;es_handler.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;\r\n\r\n    srf02_p-&gt;es_handler.suspend = srf02_early_suspend;\r\n\r\n    srf02_p-&gt;es_handler.resume = srf02_later_resume;\r\n\r\n    srf02_p-&gt;es_handler.data = (void *)client;\r\n\r\n    register_early_suspend(&amp;srf02_p-&gt;es_handler);\r\n\r\n    #endif\r\n\r\n    \/\/ ...\r\n\r\n}\r\n\r\n<\/pre>\n<p>The functions for suspend and resume themselves\u00a0are very simple for the proximity sensor because it is not necessary to save any state of the device. So the idea is to cancel the workqueue and with it the measurement when the device goes\u00a0into suspend mode. And when\u00a0resuming we recreate the queue with our worker function to perform the ranging as if the suspension\u00a0had never happened.<\/p>\n<pre class=\"lang:c decode:true \">#ifdef CONFIG_HAS_EARLYSUSPEND\r\n\r\nstatic void srf02_early_suspend (struct early_suspend *suspend) {\r\n\r\n    struct srf02_priv *srf02_p;\r\n\r\n    if (suspend-&gt;data) {\r\n\r\n        srf02_p = i2c_get_clientdata((struct i2c_client *) suspend-&gt;data);\r\n\r\n        cancel_delayed_work ((struct delayed_work *)work);\r\n\r\n    }\r\n\r\n}\r\n\r\nstatic void srf02_later_resume (struct early_suspend *suspend) {\r\n\r\n    struct srf02_priv *srf02_p;\r\n\r\n    if (suspend-&gt;data) {\r\n\r\n        srf02_p = i2c_get_clientdata ((struct i2c_client *) suspend-&gt;data);\r\n\r\n        my_wq = create_workqueue(\"my_workqueue\");\r\n\r\n        if (my_wq) {\r\n\r\n            work = (my_work_t *) kmalloc (sizeof (my_work_t), GFP_KERNEL);\r\n\r\n            if (work) {\r\n\r\n                INIT_DELAYED_WORK ((struct delayed_work *) work, workq_fn);\r\n\r\n                queue_delayed_work(my_wq, (struct delayed_work *) work, msecs_to_jiffies(100));\r\n\r\n            }\r\n\r\n        }\r\n\r\n    }\r\n\r\n}\r\n\r\n#else\r\n\r\nstatic void srf02_early_suspend (struct early_suspend *suspend) { }\r\n\r\nstatic void srf02_later_resume (struct early_suspend *suspend) { }\r\n\r\n#endif<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Clean-up\"><\/span>Clean up<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Now we are nearly done with the kernel module for the SRF02 sensor and will just take a short look at the clean up process. Everything we create or register in the <span class=\"lang:c decode:true crayon-inline\">module_init()<\/span>\u00a0method must be destroyed or unregistered in the <span class=\"lang:c decode:true crayon-inline\">module_exit()<\/span>\u00a0method in reversed order to avoid memory leaks. That&#8217;s the same pattern the jump marks in the init-method itself work, if anything fails there. In the same\u00a0way the <span class=\"lang:c decode:true crayon-inline \">srf02_i2c_remove()<\/span>\u00a0function cleans up everything generated in the <span class=\"lang:c decode:true crayon-inline \">probe()<\/span>\u00a0function.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Stay-tuned\"><\/span>Stay tuned<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Half way through!\u00a0In the next two parts (due next week) we will get to know HAL and how it interacts with our kernel module and the framework. Until then head over to our website to learn more about <a href=\"https:\/\/www.inovex.de\/en\/our-services\/mobile\/internet-of-things-smart-devices\/\" target=\"_blank\" rel=\"noopener\">embedded development and the IoT<\/a>.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Sources-Parts-1-and-2\"><\/span>Sources (Parts 1 and 2)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<ul>\n<li><a href=\"https:\/\/source.android.com\/devices\/sensors\/index.html\" target=\"_blank\" rel=\"noopener\">https:\/\/source.android.com\/devices\/sensors\/index.html<\/a><\/li>\n<li><a href=\"http:\/\/www.makelinux.net\/ldd3\/\" target=\"_blank\" rel=\"noopener\">http:\/\/www.makelinux.net\/ldd3\/<\/a><\/li>\n<li><a href=\"https:\/\/www.kernel.org\/doc\/Documentation\/input\/input-programming.txt\" target=\"_blank\" rel=\"noopener\">https:\/\/www.kernel.org\/doc\/Documentation\/input\/input-programming.txt<\/a><\/li>\n<li><a href=\"https:\/\/gitlab.inovex.de\/inovex-embedded-marsboard\/marsboard-lcd\/raw\/master\/Master_Thesis_Dahmen_299580.pdf\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.inovex.de\/inovex-embedded-marsboard\/marsboard-lcd\/raw\/master\/Master_Thesis_Dahmen_299580.pdf<\/a><\/li>\n<li><a href=\"http:\/\/developer.android.com\/guide\/components\/services.html\" target=\"_blank\" rel=\"noopener\">http:\/\/developer.android.com\/guide\/components\/services.html<\/a><\/li>\n<li><a href=\"http:\/\/www.tldp.org\/LDP\/lkmpg\/2.4\/html\/\" target=\"_blank\" rel=\"noopener\">http:\/\/www.tldp.org\/LDP\/lkmpg\/2.4\/html\/<\/a><\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"The-Whole-Story\"><\/span>The Whole Story<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<ul>\n<li><a href=\"https:\/\/www.inovex.de\/\/android-sensor-integration-part-1-sensor-stack-and-kernel-module\/\" target=\"_blank\" rel=\"noopener\">Part 1:\u00a0Sensor Stack and Kernel Module<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/\/android-sensor-integration-part-2-sensor-readings\/\">Part 2: Sensor Readings<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/\/android-sensor-integration-part-3-hal\/\">Part 3: HAL<\/a><\/li>\n<li><a href=\"https:\/\/www.inovex.de\/\/android-sensor-integration-part-4-the-android-sensor-framework\/\">Part 4: The Android Sensor Framework<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In the second part of our four part series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder. If you haven&#8217;t done so go check part one for the basics of the Android sensor stack and kernel module integration. Otherwise jump right in!<\/p>\n","protected":false},"author":35,"featured_media":13054,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"ep_exclude_from_search":false,"footnotes":""},"tags":[74],"service":[712],"coauthors":[{"id":35,"display_name":"Anna-Lena Marx","user_nicename":"amarx"}],"class_list":["post-21008","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","tag-iot","service-internet-of-things-iot"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Android Sensor Integration Part 2: Sensor Readings - inovex GmbH<\/title>\n<meta name=\"description\" content=\"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Android Sensor Integration Part 2: Sensor Readings - inovex GmbH\" \/>\n<meta property=\"og:description\" content=\"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\" \/>\n<meta property=\"og:site_name\" content=\"inovex GmbH\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/inovexde\" \/>\n<meta property=\"article:published_time\" content=\"2015-12-11T11:02:52+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-12-01T11:14:53+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2300\" \/>\n\t<meta property=\"og:image:height\" content=\"876\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Anna-Lena Marx\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting-1024x390.jpg\" \/>\n<meta name=\"twitter:creator\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:site\" content=\"@inovexgmbh\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Anna-Lena Marx\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"9\u00a0Minuten\" \/>\n\t<meta name=\"twitter:label3\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data3\" content=\"Anna-Lena Marx\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\"},\"author\":{\"name\":\"Anna-Lena Marx\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b7d6fd8c3ec8972f3b14f0205e25d022\"},\"headline\":\"Android Sensor Integration Part 2: Sensor Readings\",\"datePublished\":\"2015-12-11T11:02:52+00:00\",\"dateModified\":\"2022-12-01T11:14:53+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\"},\"wordCount\":1315,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg\",\"keywords\":[\"IoT\"],\"articleSection\":[\"Applications\",\"English Content\",\"General\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\",\"url\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\",\"name\":\"Android Sensor Integration Part 2: Sensor Readings - inovex GmbH\",\"isPartOf\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg\",\"datePublished\":\"2015-12-11T11:02:52+00:00\",\"dateModified\":\"2022-12-01T11:14:53+00:00\",\"description\":\"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg\",\"width\":2300,\"height\":876,\"caption\":\"Porting an Android Embedded Setup\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.inovex.de\/de\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Android Sensor Integration Part 2: Sensor Readings\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.inovex.de\/de\/#website\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"name\":\"inovex GmbH\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.inovex.de\/de\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.inovex.de\/de\/#organization\",\"name\":\"inovex GmbH\",\"url\":\"https:\/\/www.inovex.de\/de\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"contentUrl\":\"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png\",\"width\":1921,\"height\":1081,\"caption\":\"inovex GmbH\"},\"image\":{\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/inovexde\",\"https:\/\/x.com\/inovexgmbh\",\"https:\/\/www.instagram.com\/inovexlife\/\",\"https:\/\/www.linkedin.com\/company\/inovex\",\"https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b7d6fd8c3ec8972f3b14f0205e25d022\",\"name\":\"Anna-Lena Marx\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/a8cfb531252ec2ef604ef3033c45111b\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/44ab0d3916e62a17054b8e4cea92702db304b9dcb6dd28fb9915484c1830409b?s=96&d=retro&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/44ab0d3916e62a17054b8e4cea92702db304b9dcb6dd28fb9915484c1830409b?s=96&d=retro&r=g\",\"caption\":\"Anna-Lena Marx\"},\"url\":\"https:\/\/www.inovex.de\/de\/blog\/author\/amarx\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Android Sensor Integration Part 2: Sensor Readings - inovex GmbH","description":"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/","og_locale":"de_DE","og_type":"article","og_title":"Android Sensor Integration Part 2: Sensor Readings - inovex GmbH","og_description":"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.","og_url":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/","og_site_name":"inovex GmbH","article_publisher":"https:\/\/www.facebook.com\/inovexde","article_published_time":"2015-12-11T11:02:52+00:00","article_modified_time":"2022-12-01T11:14:53+00:00","og_image":[{"width":2300,"height":876,"url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg","type":"image\/jpeg"}],"author":"Anna-Lena Marx","twitter_card":"summary_large_image","twitter_image":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting-1024x390.jpg","twitter_creator":"@inovexgmbh","twitter_site":"@inovexgmbh","twitter_misc":{"Verfasst von":"Anna-Lena Marx","Gesch\u00e4tzte Lesezeit":"9\u00a0Minuten","Written by":"Anna-Lena Marx"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#article","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/"},"author":{"name":"Anna-Lena Marx","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b7d6fd8c3ec8972f3b14f0205e25d022"},"headline":"Android Sensor Integration Part 2: Sensor Readings","datePublished":"2015-12-11T11:02:52+00:00","dateModified":"2022-12-01T11:14:53+00:00","mainEntityOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/"},"wordCount":1315,"commentCount":4,"publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg","keywords":["IoT"],"articleSection":["Applications","English Content","General"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/","url":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/","name":"Android Sensor Integration Part 2: Sensor Readings - inovex GmbH","isPartOf":{"@id":"https:\/\/www.inovex.de\/de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage"},"image":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage"},"thumbnailUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg","datePublished":"2015-12-11T11:02:52+00:00","dateModified":"2022-12-01T11:14:53+00:00","description":"In the second part of our series on Android Sensor Integration we will have a look at how to actually get readings from our SRF02 Ultrasonic Range finder.","breadcrumb":{"@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#primaryimage","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2017\/06\/android-embedded-porting.jpg","width":2300,"height":876,"caption":"Porting an Android Embedded Setup"},{"@type":"BreadcrumbList","@id":"https:\/\/www.inovex.de\/de\/blog\/android-sensor-integration-part-2-sensor-readings\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.inovex.de\/de\/"},{"@type":"ListItem","position":2,"name":"Android Sensor Integration Part 2: Sensor Readings"}]},{"@type":"WebSite","@id":"https:\/\/www.inovex.de\/de\/#website","url":"https:\/\/www.inovex.de\/de\/","name":"inovex GmbH","description":"","publisher":{"@id":"https:\/\/www.inovex.de\/de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.inovex.de\/de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/www.inovex.de\/de\/#organization","name":"inovex GmbH","url":"https:\/\/www.inovex.de\/de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/","url":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","contentUrl":"https:\/\/www.inovex.de\/wp-content\/uploads\/2021\/03\/inovex-logo-16-9-1.png","width":1921,"height":1081,"caption":"inovex GmbH"},"image":{"@id":"https:\/\/www.inovex.de\/de\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/inovexde","https:\/\/x.com\/inovexgmbh","https:\/\/www.instagram.com\/inovexlife\/","https:\/\/www.linkedin.com\/company\/inovex","https:\/\/www.youtube.com\/channel\/UC7r66GT14hROB_RQsQBAQUQ"]},{"@type":"Person","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/b7d6fd8c3ec8972f3b14f0205e25d022","name":"Anna-Lena Marx","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/www.inovex.de\/de\/#\/schema\/person\/image\/a8cfb531252ec2ef604ef3033c45111b","url":"https:\/\/secure.gravatar.com\/avatar\/44ab0d3916e62a17054b8e4cea92702db304b9dcb6dd28fb9915484c1830409b?s=96&d=retro&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/44ab0d3916e62a17054b8e4cea92702db304b9dcb6dd28fb9915484c1830409b?s=96&d=retro&r=g","caption":"Anna-Lena Marx"},"url":"https:\/\/www.inovex.de\/de\/blog\/author\/amarx\/"}]}},"_links":{"self":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21008","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/users\/35"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/comments?post=21008"}],"version-history":[{"count":2,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21008\/revisions"}],"predecessor-version":[{"id":33805,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/posts\/21008\/revisions\/33805"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media\/13054"}],"wp:attachment":[{"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/media?parent=21008"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/tags?post=21008"},{"taxonomy":"service","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/service?post=21008"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.inovex.de\/de\/wp-json\/wp\/v2\/coauthors?post=21008"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}