{"id":382683,"date":"2024-06-29T04:25:33","date_gmt":"2024-06-29T04:25:33","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=382683"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=382683","title":{"rendered":"<span>APRS. AFSK modulator from Flipper Zero<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>There is such an interesting data transfer protocol &#8212; APRS.\u00a0A lot has already been told about him on the Internet. There will be no in-depth theoretical material here. This article will describe how to create your own &#171;pocket&#187; AFSK modulator.\u00a0In the following articles there will be instructions for going on the air and for creating a simple demodulator. This will allow you to accept APRS packages and display the information on the display right on the street.  Everything will be implemented for Flipper Zero.\u00a0If you don&#8217;t have this gadget yet, then don&#8217;t worry and try everything on the great and terrible Arduino.\u00a0It is very interesting to send information at a distance &#171;with your own hands&#187;.<\/p>\n<p><strong>We will not build a &#171;bicycle&#187;, we will only train &#171;crutches&#187;<\/strong><\/p>\n<p>The Internet has everything.\u00a0And the implementation of AFSK modulators also exists.\u00a0Only under FZ (Flipper Zero) not yet.\u00a0This gadget is good compared to my favorite Arduino Nano. For example, the fact that it is a complete device in a case with a display and buttons. Thus, the source code with an open license will be taken and modified taking into account the features of FZ.\u00a0Here I would like to appeal to more experienced readers. Who are well versed in FreeRTOS. After all, it is she who &#171;spins&#187; on FZ.\u00a0The original source codes are intended for Arduino. Multitasking is not used there. When developing for Flipper, I encountered an exit from important functions to interrupts. The solution was found. But I&#8217;m sure it can be implemented better. Please tell us in the comments how to do it right.<\/p>\n<p><strong>&#171;If someone wants to develop an application, I&#8217;m in business&#187; [Gluti. \/\/ Rick and Morty. &#8212; Season 4. &#8212; 2 series.]<\/strong><\/p>\n<p>You will need to figure out how to create applications for Flipper Zero.\u00a0This is created for version 0.83.1.\u00a0<a href=\"https:\/\/github.com\/flipperdevices\/flipperzero-firmware\/releases\/tag\/0.83.1\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/flipperdevices\/flipperzero-firmware\/releases\/tag\/0.83.1<\/a>.<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b95\/1de\/78b\/b951de78ba646f15db029f783d45f258.png\" alt=\"fig. 1.\u00a0Screenshot of the firmware version of the device from the experiment\" title=\"fig. 1.\u00a0Screenshot of the firmware version of the device from the experiment\" width=\"512\" height=\"256\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b95\/1de\/78b\/b951de78ba646f15db029f783d45f258.png\"\/><\/p>\n<div><figcaption>fig. 1.\u00a0Screenshot of the firmware version of the device from the experiment<\/figcaption><\/div>\n<\/figure>\n<p>Here, too, we will not dwell in detail. Because everything is already well described in other articles. I will give examples and give links that I used myself.\u00a0(Many thanks to the authors of these articles for their work done for us!):<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/amperka.ru\/blogs\/projects\/flipper-zero-app-programming-tutorial\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/amperka.ru\/blogs\/projects\/flipper-zero-app-programming-tutorial<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/yakovlev.me\/hello-flipper-zero\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/yakovlev.me\/hello-flipper-zero\/<\/u><\/a><\/p>\n<\/li>\n<\/ol>\n<p>In the article on the second link there is a good example of the implementation of timer triggering. If you use <code>furi_delay_ms(tx_delay);<\/code>, you will not be able to exit the application at the moment of pause.\u00a0It&#8217;s not very convenient. Especially when there are pauses of three minutes. So, timers are necessary. \u00a0Thus, the memory allocation\/deallocation template from the first article has been improved. This is due to the use of a timer.\u00a0(As it seemed to me, the second article will be easier to understand. especially for readers who have not yet gone beyond Arduino).\u00a0<\/p>\n<p><strong>A good template with memory allocation\/release for future applications<\/strong><\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/good_template\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/good_template<\/u><\/a><\/p>\n<p>Download, unzip and put the directory\u00a0 \/good_template to the catalog\u00a0flipperzero-firmware\/applications_user.\u00a0Further commands .\/fit fap_good_template and .\/fbt fap_deploy.  And the app on the device.<\/p>\n<p>Everyone says that the most difficult thing is the icon. And it&#8217;s true.\u00a0In the repository, you can take my APRS icon.\u00a0Build firmware. \u0415ransfer to the device. Here is a demonstration:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac31c5ae851501c53a139b\" data-style=\"\" id=\"64ac31c5ae851501c53a139b\" width=\"\"><\/div>\n<p><strong>About transferring a project from one debugging board to another device<\/strong><\/p>\n<p>When I found out about APRS, I wanted to repeat the success. I came across a project on the Internet that I found very interesting.\u00a0Here is this project:\u00a0<a href=\"https:\/\/github.com\/handiko\/Arduino-APRS\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/handiko\/Arduino-APRS<\/u><\/a>. Let&#8217;s use a good template. And we will transfer the functions from the repository of the Github user with the nickname Handiko to it. We will be grateful to him for his great work done.\u00a0It&#8217;s better to start with test firmware. So that I can use examples to point out the FreeRTOS feature.<\/p>\n<p><strong>Single tone test 1200 hz<\/strong><\/p>\n<p>In an infinite loop , it is called\u00a0<code>set_nada(_1200);<\/code>,  which causes\u00a0<code>set_nada_1200(void);<\/code>. In the second function, one of the outputs is turned off and off.\u00a0For FZ, the use of GPIO is described in the first article. Then our function <code>set_nada(_1200);<\/code> takes the form:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzApp* app) {     app->output_value = true;     furi_hal_gpio_write(app->output_pin, app->output_value);     furi_delay_us(tc1200);     app->output_value = false;     furi_hal_gpio_write(app->output_pin, app->output_value);     furi_delay_us(tc1200); }<\/code><\/pre>\n<p>In fact, the same as Handiko. But under the realities of FZ.\u00a0It&#8217;s a pity that it doesn&#8217;t work the way we would like it to:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac33a44ffc4801f3ecf74c\" data-style=\"\" id=\"64ac33a44ffc4801f3ecf74c\" width=\"\"><\/div>\n<p>The simplest buzzer is connected to the output. We hear his clicks in the background. Instead of 1200 Hz sound, the frequency is about 1 Hz.\u00a0These are the features of using FreeRTOS. It turns out an infinite loop in the FZ application is a little different than in Arduino.\u00a0Let&#8217;s rewrite the function\u00a0<code>void set_nada_1200(SingleToneTest1200HzApp* app)<\/code>. And it should be called not in an infinite loop, but before it:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzApp* app) {     uint32_t value = 5000;     while(value--){         app->output_value = true;         furi_hal_gpio_write(app->output_pin, app->output_value);         furi_delay_us(tc1200);         app->output_value = false;         furi_hal_gpio_write(app->output_pin, app->output_value);         furi_delay_us(tc1200);     } } <\/code><\/pre>\n<p>Result:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac33e365e33b4815393b86\" data-style=\"\" id=\"64ac33e365e33b4815393b86\" width=\"\"><\/div>\n<p>Problem again. Not so obvious this time. And it took me a couple of evenings after work to solve it. There are some signal distortions, they should not be.\u00a0This anomaly is visible very well on the waveform:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d0a\/0ff\/841\/d0a0ff841e0ff13eb0b35400aa28c2c9.png\" alt=\"fig. 2. Waveform of an anomaly in the signal\" title=\"fig. 2. Waveform of an anomaly in the signal\" width=\"1560\" height=\"877\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d0a\/0ff\/841\/d0a0ff841e0ff13eb0b35400aa28c2c9.png\"\/><\/p>\n<div><figcaption>fig. 2. Waveform of an anomaly in the signal<\/figcaption><\/div>\n<\/figure>\n<p>If you leave it as it is and continue to transfer the code, then everything will look as it should.\u00a0It is very difficult to interpret the waveform of a modulated message. And the buzzer is generally a toy.\u00a0It is necessary to deal with this problem at this stage.\u00a0These are now the features of FreeRTOS that were mentioned at the very beginning. And which need to be rewritten more correctly. When looking for a solution, I came across this article\u00a0<a href=\"https:\/\/habr.com\/ru\/articles\/129445\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/129445\/<\/u><\/a>. Thanks to the kind person who wrote it.\u00a0Critical sections must be used. Moreover, suspending the scheduler did not help in any way. It was the use of the critical section, which is built on macros, that helped. The article says so. Suspending the scheduler only protects against other tasks. And we fall into an interrupt. Now the function takes the form:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzDraftApp* app) {     uint32_t value = 5000;     taskENTER_CRITICAL();       while(value--){           app->output_value = true;           furi_hal_gpio_write(app->output_pin, app->output_value);           furi_delay_us(tc1200);           app->output_value = false;           furi_hal_gpio_write(app->output_pin, app->output_value);           furi_delay_us(tc1200);       }     taskEXIT_CRITICAL(); } <\/code><\/pre>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac37a50fb60a020d710dfd\" data-style=\"\" id=\"64ac37a50fb60a020d710dfd\" width=\"\"><\/div>\n<p>Now everything is correct by ear and the oscillogram is in order.\u00a0Only one thing.\u00a0While the code is being executed in the critical section, nothing else can be done. For example, exit the application by pressing the back button. In our case, of course, the packages are not that big. You can wait, but the soul of an engineer requires an ideal. And the family of attention. So, the question to more experienced readers is: &#171;How to get rid of this &#171;crutch&#187;?&#187;<\/p>\n<p>Link to the sources of \u201cSingle tone test 1200 Hz\u201d (note that this code has not yet implemented access to the timer. But he is not needed here):<\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/Single_Tone_Test_1200_Hz_draft\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/Single_Tone_Test_1200_Hz_draft<\/u><\/a>\u00a0<\/p>\n<p>Handiko has some test firmware in the Arduino_APRS repository.\u00a0But I will not disassemble them. Because I didn&#8217;t encounter any serious problems. As the need to use critical sections. I will comment only on a couple of points.\u00a0Even before I started using critical sections, I didn&#8217;t pay enough attention to the anomaly on the waveform\u00a0(well, or by ear with a buzzer). And immediately implemented the APRS_Random_String test. To my surprise, this signal was decoded quite well by the computer\u00a0(how this can be done I will describe further).\u00a0Which was decoded in about one case out of 20. At the same time, I sinned on the variable &#171;baud_adj&#187;. Because I thought I had something wrong with the pulse duration.<\/p>\n<p>Then I found a solution and used the critical sections. But to my surprise, I couldn&#8217;t decode it. It seemed that the problem was the inability to use critical sections. And when switching from function to function, an interruption occurs. I tried to compare the original waveforms taken from Arduino with the signal from FZ.\u00a0And I spent one evening trying to write everything in one function\u00a0(looks scary. There are more than 3000 lines. But I wanted it to work).<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/633\/517\/f06\/633517f0676dfefa0a37141b6701f894.png\" alt=\"fig. 3. Example of abnormal programming\" title=\"fig. 3. Example of abnormal programming\" width=\"1560\" height=\"877\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/633\/517\/f06\/633517f0676dfefa0a37141b6701f894.png\"\/><\/p>\n<div><figcaption>fig. 3. Example of abnormal programming<\/figcaption><\/div>\n<\/figure>\n<p>And the mistake was in my inattention. In the source code of &#171;APRS_Random_String&#187; in the implementation <code>void send_string_len(const char *in_string, int len)<\/code> the <code>j+len<\/code>&#187; index is passed to the &#171;<code>send_char_NRZI(in_string[j + len], HIGH)<\/code> function. But in the source code &#171;APRS_Hello_world&#187; in the implementation of the same function, the line is passed with the index <code>j<\/code>. Thus, when ripping off someone else&#8217;s code, be careful \ud83d\ude42<\/p>\n<p><strong>APRS_Hello_world<\/strong><\/p>\n<p>In fact, it remains only to fill a good template with functions from the source of the same name. The only difference is in accessing GPIO. This imposes on us the need to pass the structure of our application in the form of a parameter to most functions. If you rewrite a &#171;good template&#187; in the image and likeness of the example from the second article, the code will be simplified. I&#8217;ll show the sources completely:<\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/APRS_hello_world_clean\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/APRS_hello_world_clean<\/u><\/a><\/p>\n<p><strong>AFSK Decoder<\/strong><\/p>\n<p>To check the health of the application, it is necessary to decode the message.\u00a0To do this, you can use AFSK1200 Decoder.\u00a0To get a signal to the laptop&#8217;s sound card, I used this connector:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/90b\/380\/f2c\/90b380f2c39f4067ae791fe7d9bae56f.png\" alt=\"Fig. 4. Pinout Jack 3.5 for connecting Flipper Zero to a computer\" title=\"Fig. 4. Pinout Jack 3.5 for connecting Flipper Zero to a computer\" width=\"697\" height=\"518\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/90b\/380\/f2c\/90b380f2c39f4067ae791fe7d9bae56f.png\"\/><\/p>\n<div><figcaption>Fig. 4. Pinout Jack 3.5 for connecting Flipper Zero to a computer<\/figcaption><\/div>\n<\/figure>\n<p>You will need to select the signal source in the INPUT window and press Start Decoder:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/36e\/3a7\/ce2\/36e3a7ce24eb4fae491822e6801b241d.png\" alt=\"fig. 5. Example of decoded messages\" title=\"fig. 5. Example of decoded messages\" width=\"1078\" height=\"543\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/36e\/3a7\/ce2\/36e3a7ce24eb4fae491822e6801b241d.png\"\/><\/p>\n<div><figcaption>fig. 5. Example of decoded messages<\/figcaption><\/div>\n<\/figure>\n<p>There are other programs that can decode such signals, for example, UISS\u00a0(instructions\u00a0<a href=\"https:\/\/r4uab.ru\/aprs-iss\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/r4uab.ru\/aprs-iss\/<\/u><\/a>\u00a0). With this program, I was even better at receiving real APRS signals.\u00a0Or GNU Radio\u00a0(instructions\u00a0<a href=\"https:\/\/github.com\/handiko\/gr-APRS\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/handiko\/gr-APRS<\/u><\/a> ). I used GNU RADIO in UBUNTU and this instruction.<\/p>\n<p><strong>Results<\/strong><\/p>\n<p>Now we have managed to create an AVS modulator with our own hands. And figure out how Flipper Zero apps work. We even connected Flipper Zero to the computer.\u00a0But to reveal the APRS data transmission protocol, we will need a transmitter.\u00a0For example, I don&#8217;t have an amateur radio and radio callout license yet. Thus, in one of the following articles we will go on the air in the PMR band (446-446.200 MHz). There is no license required. The power of the transmitter will also be the permitted 500 MW.\u00a0And then we&#8217;ll see how far it will be possible to send messages.<\/p>\n<p>Despite some success, I still ask more experienced readers to give answers to the questions that have arisen:<\/p>\n<ol>\n<li>\n<p>How to protect yourself from the peculiarities of FreeRTOS, so that important code does not interfere with interrupts?<\/p>\n<\/li>\n<li>\n<p>Is it possible to use APRS frequencies (144.800 MHz) for, for example, communication with other radio amateurs\u00a0(of course, having all the necessary permits, licenses, call signs, etc.)\u00a0like a WhatsApp chat (well, for example)?<\/p>\n<\/li>\n<li>\n<p>How, after all, can I get an amateur radio license and a call sign now? Maybe someone recently received?\u00a0<\/p>\n<\/li>\n<li>\n<p>What happens if you go on the air without a license and a call sign, for example, using the same Baofeng UV-5R?\u00a0And if you are careful with the power of 1 watt? (I&#8217;m curious)<\/p>\n<\/li>\n<li>\n<p>What will happen if you work in the PMR band (446-446.200 MHz), where a license is not required, but with a power of 1 watt?<\/p>\n<\/li>\n<\/ol>\n<p>Thank you for finishing reading. Write, if something does not work out, we will figure it out together.<\/p>\n<p>S. N.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/747152\/\"> https:\/\/habr.com\/ru\/articles\/747152\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>There is such an interesting data transfer protocol &#8212; APRS.\u00a0A lot has already been told about him on the Internet. There will be no in-depth theoretical material here. This article will describe how to create your own &#171;pocket&#187; AFSK modulator.\u00a0In the following articles there will be instructions for going on the air and for creating a simple demodulator. This will allow you to accept APRS packages and display the information on the display right on the street.  Everything will be implemented for Flipper Zero.\u00a0If you don&#8217;t have this gadget yet, then don&#8217;t worry and try everything on the great and terrible Arduino.\u00a0It is very interesting to send information at a distance &#171;with your own hands&#187;.<\/p>\n<p><strong>We will not build a &#171;bicycle&#187;, we will only train &#171;crutches&#187;<\/strong><\/p>\n<p>The Internet has everything.\u00a0And the implementation of AFSK modulators also exists.\u00a0Only under FZ (Flipper Zero) not yet.\u00a0This gadget is good compared to my favorite Arduino Nano. For example, the fact that it is a complete device in a case with a display and buttons. Thus, the source code with an open license will be taken and modified taking into account the features of FZ.\u00a0Here I would like to appeal to more experienced readers. Who are well versed in FreeRTOS. After all, it is she who &#171;spins&#187; on FZ.\u00a0The original source codes are intended for Arduino. Multitasking is not used there. When developing for Flipper, I encountered an exit from important functions to interrupts. The solution was found. But I&#8217;m sure it can be implemented better. Please tell us in the comments how to do it right.<\/p>\n<p><strong>&#171;If someone wants to develop an application, I&#8217;m in business&#187; [Gluti. \/\/ Rick and Morty. &#8212; Season 4. &#8212; 2 series.]<\/strong><\/p>\n<p>You will need to figure out how to create applications for Flipper Zero.\u00a0This is created for version 0.83.1.\u00a0<a href=\"https:\/\/github.com\/flipperdevices\/flipperzero-firmware\/releases\/tag\/0.83.1\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/flipperdevices\/flipperzero-firmware\/releases\/tag\/0.83.1<\/a>.<\/p>\n<figure class=\"\">\n<div><figcaption>fig. 1.\u00a0Screenshot of the firmware version of the device from the experiment<\/figcaption><\/div>\n<\/figure>\n<p>Here, too, we will not dwell in detail. Because everything is already well described in other articles. I will give examples and give links that I used myself.\u00a0(Many thanks to the authors of these articles for their work done for us!):<\/p>\n<ol>\n<li>\n<p><a href=\"https:\/\/amperka.ru\/blogs\/projects\/flipper-zero-app-programming-tutorial\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/amperka.ru\/blogs\/projects\/flipper-zero-app-programming-tutorial<\/u><\/a><\/p>\n<\/li>\n<li>\n<p><a href=\"https:\/\/yakovlev.me\/hello-flipper-zero\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/yakovlev.me\/hello-flipper-zero\/<\/u><\/a><\/p>\n<\/li>\n<\/ol>\n<p>In the article on the second link there is a good example of the implementation of timer triggering. If you use <code>furi_delay_ms(tx_delay);<\/code>, you will not be able to exit the application at the moment of pause.\u00a0It&#8217;s not very convenient. Especially when there are pauses of three minutes. So, timers are necessary. \u00a0Thus, the memory allocation\/deallocation template from the first article has been improved. This is due to the use of a timer.\u00a0(As it seemed to me, the second article will be easier to understand. especially for readers who have not yet gone beyond Arduino).\u00a0<\/p>\n<p><strong>A good template with memory allocation\/release for future applications<\/strong><\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/good_template\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/good_template<\/u><\/a><\/p>\n<p>Download, unzip and put the directory\u00a0 \/good_template to the catalog\u00a0flipperzero-firmware\/applications_user.\u00a0Further commands .\/fit fap_good_template and .\/fbt fap_deploy.  And the app on the device.<\/p>\n<p>Everyone says that the most difficult thing is the icon. And it&#8217;s true.\u00a0In the repository, you can take my APRS icon.\u00a0Build firmware. \u0415ransfer to the device. Here is a demonstration:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac31c5ae851501c53a139b\" data-style=\"\" id=\"64ac31c5ae851501c53a139b\" width=\"\"><\/div>\n<p><strong>About transferring a project from one debugging board to another device<\/strong><\/p>\n<p>When I found out about APRS, I wanted to repeat the success. I came across a project on the Internet that I found very interesting.\u00a0Here is this project:\u00a0<a href=\"https:\/\/github.com\/handiko\/Arduino-APRS\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/handiko\/Arduino-APRS<\/u><\/a>. Let&#8217;s use a good template. And we will transfer the functions from the repository of the Github user with the nickname Handiko to it. We will be grateful to him for his great work done.\u00a0It&#8217;s better to start with test firmware. So that I can use examples to point out the FreeRTOS feature.<\/p>\n<p><strong>Single tone test 1200 hz<\/strong><\/p>\n<p>In an infinite loop , it is called\u00a0<code>set_nada(_1200);<\/code>,  which causes\u00a0<code>set_nada_1200(void);<\/code>. In the second function, one of the outputs is turned off and off.\u00a0For FZ, the use of GPIO is described in the first article. Then our function <code>set_nada(_1200);<\/code> takes the form:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzApp* app) {     app->output_value = true;     furi_hal_gpio_write(app->output_pin, app->output_value);     furi_delay_us(tc1200);     app->output_value = false;     furi_hal_gpio_write(app->output_pin, app->output_value);     furi_delay_us(tc1200); }<\/code><\/pre>\n<p>In fact, the same as Handiko. But under the realities of FZ.\u00a0It&#8217;s a pity that it doesn&#8217;t work the way we would like it to:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac33a44ffc4801f3ecf74c\" data-style=\"\" id=\"64ac33a44ffc4801f3ecf74c\" width=\"\"><\/div>\n<p>The simplest buzzer is connected to the output. We hear his clicks in the background. Instead of 1200 Hz sound, the frequency is about 1 Hz.\u00a0These are the features of using FreeRTOS. It turns out an infinite loop in the FZ application is a little different than in Arduino.\u00a0Let&#8217;s rewrite the function\u00a0<code>void set_nada_1200(SingleToneTest1200HzApp* app)<\/code>. And it should be called not in an infinite loop, but before it:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzApp* app) {     uint32_t value = 5000;     while(value--){         app->output_value = true;         furi_hal_gpio_write(app->output_pin, app->output_value);         furi_delay_us(tc1200);         app->output_value = false;         furi_hal_gpio_write(app->output_pin, app->output_value);         furi_delay_us(tc1200);     } } <\/code><\/pre>\n<p>Result:<\/p>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac33e365e33b4815393b86\" data-style=\"\" id=\"64ac33e365e33b4815393b86\" width=\"\"><\/div>\n<p>Problem again. Not so obvious this time. And it took me a couple of evenings after work to solve it. There are some signal distortions, they should not be.\u00a0This anomaly is visible very well on the waveform:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>fig. 2. Waveform of an anomaly in the signal<\/figcaption><\/div>\n<\/figure>\n<p>If you leave it as it is and continue to transfer the code, then everything will look as it should.\u00a0It is very difficult to interpret the waveform of a modulated message. And the buzzer is generally a toy.\u00a0It is necessary to deal with this problem at this stage.\u00a0These are now the features of FreeRTOS that were mentioned at the very beginning. And which need to be rewritten more correctly. When looking for a solution, I came across this article\u00a0<a href=\"https:\/\/habr.com\/ru\/articles\/129445\/\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/habr.com\/ru\/articles\/129445\/<\/u><\/a>. Thanks to the kind person who wrote it.\u00a0Critical sections must be used. Moreover, suspending the scheduler did not help in any way. It was the use of the critical section, which is built on macros, that helped. The article says so. Suspending the scheduler only protects against other tasks. And we fall into an interrupt. Now the function takes the form:<\/p>\n<pre><code class=\"cpp\">void set_nada_1200(SingleToneTest1200HzDraftApp* app) {     uint32_t value = 5000;     taskENTER_CRITICAL();       while(value--){           app->output_value = true;           furi_hal_gpio_write(app->output_pin, app->output_value);           furi_delay_us(tc1200);           app->output_value = false;           furi_hal_gpio_write(app->output_pin, app->output_value);           furi_delay_us(tc1200);       }     taskEXIT_CRITICAL(); } <\/code><\/pre>\n<div class=\"tm-iframe_temp\" data-src=\"https:\/\/embedd.srv.habr.com\/iframe\/64ac37a50fb60a020d710dfd\" data-style=\"\" id=\"64ac37a50fb60a020d710dfd\" width=\"\"><\/div>\n<p>Now everything is correct by ear and the oscillogram is in order.\u00a0Only one thing.\u00a0While the code is being executed in the critical section, nothing else can be done. For example, exit the application by pressing the back button. In our case, of course, the packages are not that big. You can wait, but the soul of an engineer requires an ideal. And the family of attention. So, the question to more experienced readers is: &#171;How to get rid of this &#171;crutch&#187;?&#187;<\/p>\n<p>Link to the sources of \u201cSingle tone test 1200 Hz\u201d (note that this code has not yet implemented access to the timer. But he is not needed here):<\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/Single_Tone_Test_1200_Hz_draft\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/Single_Tone_Test_1200_Hz_draft<\/u><\/a>\u00a0<\/p>\n<p>Handiko has some test firmware in the Arduino_APRS repository.\u00a0But I will not disassemble them. Because I didn&#8217;t encounter any serious problems. As the need to use critical sections. I will comment only on a couple of points.\u00a0Even before I started using critical sections, I didn&#8217;t pay enough attention to the anomaly on the waveform\u00a0(well, or by ear with a buzzer). And immediately implemented the APRS_Random_String test. To my surprise, this signal was decoded quite well by the computer\u00a0(how this can be done I will describe further).\u00a0Which was decoded in about one case out of 20. At the same time, I sinned on the variable &#171;baud_adj&#187;. Because I thought I had something wrong with the pulse duration.<\/p>\n<p>Then I found a solution and used the critical sections. But to my surprise, I couldn&#8217;t decode it. It seemed that the problem was the inability to use critical sections. And when switching from function to function, an interruption occurs. I tried to compare the original waveforms taken from Arduino with the signal from FZ.\u00a0And I spent one evening trying to write everything in one function\u00a0(looks scary. There are more than 3000 lines. But I wanted it to work).<\/p>\n<figure class=\"full-width\">\n<div><figcaption>fig. 3. Example of abnormal programming<\/figcaption><\/div>\n<\/figure>\n<p>And the mistake was in my inattention. In the source code of &#171;APRS_Random_String&#187; in the implementation <code>void send_string_len(const char *in_string, int len)<\/code> the <code>j+len<\/code>&#187; index is passed to the &#171;<code>send_char_NRZI(in_string[j + len], HIGH)<\/code> function. But in the source code &#171;APRS_Hello_world&#187; in the implementation of the same function, the line is passed with the index <code>j<\/code>. Thus, when ripping off someone else&#8217;s code, be careful \ud83d\ude42<\/p>\n<p><strong>APRS_Hello_world<\/strong><\/p>\n<p>In fact, it remains only to fill a good template with functions from the source of the same name. The only difference is in accessing GPIO. This imposes on us the need to pass the structure of our application in the form of a parameter to most functions. If you rewrite a &#171;good template&#187; in the image and likeness of the example from the second article, the code will be simplified. I&#8217;ll show the sources completely:<\/p>\n<p><a href=\"https:\/\/github.com\/NSV47\/APRS_hello_world_clean\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/github.com\/NSV47\/APRS_hello_world_clean<\/u><\/a><\/p>\n<p><strong>AFSK Decoder<\/strong><\/p>\n<p>To check the health of the application, it is necessary to decode the message.\u00a0To do this, you can use AFSK1200 Decoder.\u00a0To get a signal to the laptop&#8217;s sound card, I used this connector:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>Fig. 4. Pinout Jack 3.5 for connecting Flipper Zero to a computer<\/figcaption><\/div>\n<\/figure>\n<p>You will need to select the signal source in<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-382683","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/382683","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=382683"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/382683\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=382683"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=382683"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=382683"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}