Androidthings LED blink program with firemonkey


With Android Studio , the following code works with RaspberryPi3.
LED connected to BCM6 blinks correctly.

How to implement this code into C++Builder10.3 Project ?
=========================
#include <android_native_app_glue.h>
#include <pio/peripheral_manager_client.h>
#include <unistd.h> // sleep

void android_main(android_app* app) {
bool led;
APeripheralManagerClient* client = APeripheralManagerClient_new();
AGpio* gpio;
APeripheralManagerClient_openGpio(client, "BCM6", &gpio);
int result = AGpio_setDirection(gpio, AGPIO_DIRECTION_OUT_INITIALLY_LOW);

while (!app->destroyRequested)
{
led = !led;
AGpio_setValue(gpio, led);
sleep(1);
}
AGpio_delete(gpio);
APeripheralManagerClient_delete(client);
}
=========================

I tried the following code with C++Builder10.3 , however could not solve errors.
Is my approach fundamentally wrong ?

//---------------------------------------------------------------------------
#include <fmx.h>
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.Memo.hpp>
#include <FMX.ScrollBox.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>

#pragma hdrstop
#include <dlfcn.h>
#include "peripheral_Manager_client.h"
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"

TForm1 *Form1;
void *libhandle;
APeripheralManagerClient* client;
AGpio* gpio;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Label1->Text=TimeToStr(Now());
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
libhandle = dlopen("libandroidthings.so", RTLD_NOW);
*(APeripheralManagerClient**)(APeripheralManagerClient_new)
=(APeripheralManagerClient*)dlsym(libhandle,"APeripheralManagerClient_new");
client = APeripheralManagerClient_new();
APeripheralManagerClient_openGpio(client, "BCM6", &gpio);

*(int**)(AGpio_setDirection)=(int*)dlsym(libhandle,"AGpio_setDirection");
int result = AGpio_setDirection(gpio, AGPIO_DIRECTION_OUT_INITIALLY_LOW);
}

  • I gave up androidthings and succeeded in android lineage Ver16.
    konstakang.com/.../

    Mmap works fine under Firemonkey and Lineage OS is stable than Emteria OS.

    I succeeded with the following way.

    AnsiString command="su -c \"chmod 666 /dev/gpiomem\"";
    system(command.c_str()) ;


    mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
    gpio_map = mmap(
    NULL, //Any adddress in our space will do
    BLOCK_SIZE, //Map length
    PROT_READ | PROT_WRITE,// Enable reading & writting to mapped memory
    MAP_SHARED, //Shared with other processes
    mem_fd, //Fd to map
    MAP_GPIO //Offset to GPIO peripheral
    );

    The after are the same as the RaspberryPi programming.
    As well known gpio library outputs many errors , I had to write myself.

  • Simple instruction for C++Builder GPIO under Android.


    1. Download LineageOS 16.0 from Konstakang.com

    Rpi4
    konstakang.com/.../
    Rpi3
    konstakang.com/.../

    unzip and write img-file to microSD-card.

    2. Monitor Display resolution
    Confirm your display resolution and change the following files.
    /boot/resolution.txt

    /boot/config.txt
    hdmi_group=
    hdmi_mode=

    3. Boot Android Lineage16.0
    Change time setting and WiFi password.

    4. Root access and ADB setting
    Change to Developer options:
    Setting -> About tablet Raspberry Pi3 -> Click Build number sereral times slowly.

    Change root access , adb setting
    System->Developer options->Debugging
    -> Allow root access to Apps and ADB:
    -> Allow USB debugging:
    -> Allow ADB over network:
    -> Enable Local terminal:

    Check IP address
    Setting -> About tablet -> IP address

    5. Windows10 PC setup
    Open DOS-Prompt
    type > adb connect 192.168.1.xx <- android IP address.
    response > connected to 192.168.1.xx:5555

    6. Start C++Builder 10.3
    Make android new project and save all files.
    Overwrite with the following files.

    rpi.h

    //---------------------------------------------------------------------------
    #ifndef rpiH
    #define rpiH
    
    #include <System.Classes.hpp>
    #include <FMX.Controls.hpp>
    #include <FMX.Controls.Presentation.hpp>
    #include <FMX.ScrollBox.hpp>
    #include <FMX.StdCtrls.hpp>
    #include <FMX.Types.hpp>
    
    #include <cstdlib>     // std::system
    #include <sys/mman.h>  // mmap
    
    // Raspi2  Raspi3 model B
    // Board   ARM
    //         Pin  Num  board-pin
    #define    PIN3    2  
    #define    BCM2    2 // Pin3(SDA)
    
    #define    PIN5    3  
    #define    BCM3    3 // Pin5(SCL)
    
    #define    PIN7    4  
    #define    BCM4    4 // Pin7(GPCLK0)
    
    #define    PIN8   14  
    #define    BCM14  14 // Pin8(TXD)
    
    #define    PIN10  15
    #define    BCM15  15 // PIN9(RXD)
    
    #define    PIN11  17  
    #define    BCM17  17 // PIN11
    
    #define    PIN12  18 
    #define    BCM18  18 // PIN12
    
    #define    PIN13  27
    #define    BCM27  27 // PIN13
        
    #define    PIN15  22
    #define    BCM22  22 // PIN15
    
    #define    PIN16  23
    #define    BCM23  23 // PIN16
        
    #define    PIN18  24 
    #define    BCM24  24 // PIN18
    
    #define    PIN19  10
    #define    BCM10  10 // PIN19(MOSI)
        
    #define    PIN21   9 
    #define    BCM9    9 // PIN9(MISO)
    
    #define    PIN22  25 
    #define    BCM25  25 // PIN22
    
    #define    PIN23  11 
    #define    BCM11  11 // PIN23(SCLK)
    
    #define    PIN24   8 
    #define    BCM8    8 // PIN8(CE0)
        
    #define    PIN26   7 
    #define    BCM7    7 // PIN26(CE1)
    
    #define    PIN27   0 
    #define    BCM0    0 // PIN27(ID_SD)
    
    #define    PIN28   1 
    #define    BCM1    1 // PIN28(ID_SC)
    
    #define    PIN29   5 
    #define    BCM5    5 // PIN29
         
    #define    PIN31   6 
    #define    BCM6    6 // PIN31
    
    #define    PIN32  12  
    #define    BCM12  12 // PIN32(PWM0)
    
    #define    PIN33  13 
    #define    BCM13  13 // PIN33(PWM1)
        
    #define    PIN35  19 
    #define    BCM19  19 // PIN35(MISO)
    
    #define    PIN36  16 
    #define    BCM16  16 // PIN36
    
    #define    PIN37  26 
    #define    BCM26  26 // PIN37
    
    #define    PIN38  20 
    #define    BCM20  20// PIN38(MOSI)
        
    #define    PIN40  21 
    #define    BCM21  21// PIN40(SCLK)
    
    #define    INPUT       0
    #define    OUTPUT      1
    #define    PWM_OUTPUT  2
    #define    PUD_OFF     0
    #define    PUD_DOWN    1
    #define    PUD_UP      2
    #define    LOW         0
    #define    HIGH        1
    
    
    
    //        port name  addr    r/w  reset
    #define    GPSFSEL0  0x00 // r/w  0
    #define    GPSFSEL1  0x04 // r/w  0
    #define    GPSFSEL2  0x08 // r/w  0
    #define    GPSFSEL3  0x0C // r/w  0
    #define    GPSFSEL4  0x10 // r/w  0
    #define    GPSFSEL5  0x14 // r/w  0
        // reserve 0x18
    #define    GPSET0    0x1C //   w  0
    #define    GPSET1    0x20 //   w  0
        // reserve 24
    #define    GPCLR0    0x28 //   w  0
    #define    GPCLR1    0x2C //   w  0
        // reserve 30
    #define    GPLEV0    0x34 //   r  0
    #define    GPLEV1    0x35 //   r  0
    
    #define    GPPUD     0x94
    #define    GPPUDCLK0 0x98
    
    // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
    #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
    #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
    #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
    
    #define GPIO_SET *(gpio+7)  // GPSET0(0x1C) sets   bits which are 1 ignores bits which are 0,
    #define GPIO_CLR *(gpio+10) // GPCLR0(0x28) clears bits which are 1 ignores bits which are 0
    #define GPIO_GET *(gpio+13) // GPLEV0(0x34) read   bits
    
    //---------------------------------------------------------------------------
    class Trpi
    {
    protected:
    private:
    	int     mem_fd;              //  dev/gpiomem
    	void *gpio_map;              //  gpio mmap
    	volatile unsigned int *gpio;
    	AnsiString command;
    
    public:
    	int  init(unsigned int);
       void  pinMode(BYTE gpin,BYTE mode);
       void  digitalWrite(BYTE gpin,BYTE mode);    // Write output port
    	int  digitalRead(BYTE gpin);               // Read  input port
    	AnsiString msglog;
    
    	 Trpi();
    	 ~Trpi();
    
    };
    //---------------------------------------------------------------------------
    #endif
    

    rpi.cpp

    #include "rpi.h"
    
    #define    PAGE_SIZE  4096
    #define    BLOCK_SIZE 4096
    
    //---------------------------------------------------------------------------
     Trpi::Trpi()
    {
        mem_fd=NULL;
        gpio_map=MAP_FAILED;
    
        command="su -c \"chmod 666 /dev/gpiomem\"";
        std::system(command.c_str());
    }
    //---------------------------------------------------------------------------
     Trpi::~Trpi()
    { 
        if(gpio_map!=MAP_FAILED);
            munmap(gpio_map,PAGE_SIZE);
    }
    //---------------------------------------------------------------------------
    int  Trpi::init(unsigned int map_adrs)
    {
        int cnt;
        msglog="";
    
        for(cnt=1;cnt<=10;cnt++) // Try max 10 times
            {
            mem_fd = open("/dev/gpiomem", O_RDWR | O_SYNC);
            if(mem_fd > 0) break;
            std::system(command.c_str()) ; // retry to chmod 666 /dev/gpiomem
            Sleep(200);                    // 200ms sleep
            }
    
        if (mem_fd < 0)   { msglog=msglog+"gpio open(dev/gpiomem) failed \r\n";  return -1; }
        
            msglog=msglog+"gpio open( /dev/gpiomem ) success , try count = "+ IntToStr(cnt)+"\r\n";
            gpio_map = mmap(NULL,BLOCK_SIZE,PROT_READ | PROT_WRITE,MAP_SHARED, mem_fd,map_adrs );
        
        if(gpio_map<0) { msglog=msglog+"gpio mmap failed\r\n"; return -1; }
        
            gpio=(unsigned int *)gpio_map;
            msglog=msglog+"gpio mmap success , address= 0x"+ AnsiString::IntToHex((int)gpio_map,8)+"\r\n";
        
        return 0;
    }
    //---------------------------------------------------------------------------
    void  Trpi::pinMode(BYTE gpin,BYTE mode)
    {
        INP_GPIO(gpin);
        if(mode==OUTPUT)
            OUT_GPIO(gpin);
    }
    //---------------------------------------------------------------------------
    void  Trpi::digitalWrite(BYTE gpin,BYTE mode)
    {
       if(mode==HIGH)
            GPIO_SET = ( 1<<gpin );
        else
            GPIO_CLR = ( 1<<gpin );
    }
    //---------------------------------------------------------------------------
    int  Trpi::digitalRead(BYTE gpin)
    {
        return( (GPIO_GET & (1<<gpin)) ? 1 : 0);
    }
    //---------------------------------------------------------------------------
    
    
    

    unit1.h

    //---------------------------------------------------------------------------
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <System.Classes.hpp>
    #include <FMX.Controls.hpp>
    #include <FMX.Forms.hpp>
    #include <FMX.Controls.Presentation.hpp>
    #include <FMX.Memo.hpp>
    #include <FMX.ScrollBox.hpp>
    #include <FMX.StdCtrls.hpp>
    #include <FMX.Types.hpp>
    
    #include "rpi.h"
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// IDE で管理されるコンポーネント
    	TPanel *Panel1;
    	TMemo *Memo1;
    	TButton *Init;
    	TButton *LED_blink;
    	TButton *Exit;
    	TTimer *Timer1;
    	void __fastcall InitClick(TObject *Sender);
    	void __fastcall LED_blinkClick(TObject *Sender);
    	void __fastcall ExitClick(TObject *Sender);
    	void __fastcall FormCreate(TObject *Sender);
    	void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
    	void __fastcall Timer1Timer(TObject *Sender);
    private:	// ユーザー宣言
    
    	Trpi *rpi;
    	int   n;
    public:		// ユーザー宣言
    
    
    
    	__fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
    

    unit1.cpp

    //---------------------------------------------------------------------------
    #include <fmx.h>
    #pragma hdrstop
    
    #include "Unit1.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.fmx"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormCreate(TObject *Sender)
    {
        rpi=new Trpi;
    
        n=0;
        Timer1->Interval=1000; // ON/OFF Timer 1000ms
        Timer1->Enabled=false;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
    {
    	delete rpi;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::ExitClick(TObject *Sender)
    {
        delete rpi;
        Application->Terminate();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::InitClick(TObject *Sender)
    {
    #define    raspi3b   0x3f200000
    #define    raspi4b   0xfe200000
    
    int ret;
    
    	Memo1->Lines->Clear();
    	rpi->msglog="";
    	ret=rpi->init(raspi3b);         // Call gpio->mmap
    	Memo1->Lines->Add(rpi->msglog); // Display message
    
    	if(ret<0)
    	  Memo1->Lines->Add("gpio initialize failed\r\n");
    	else
    	  Memo1->Lines->Add("gpio initialized\r\n");
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::LED_blinkClick(TObject *Sender)
    {
    	Memo1->Lines->Clear();
    	rpi->pinMode(BCM11,OUTPUT);
    	Memo1->Lines->Add("SetPinMode : OUTPUT");
        n=0;
        Timer1->Enabled=true;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Timer1Timer(TObject *Sender)
    {
    n++;
    
    if (n%2==1)
       {
    	rpi->digitalWrite(BCM11,HIGH); // LED ON
    	Memo1->Lines->Add("LED ON ");
    	Memo1->GoToTextEnd();
       }
    else
       {
    	rpi->digitalWrite(BCM11,LOW); // LED OFF
    	Memo1->Lines->Add("LED OFF");
    	Memo1->GoToTextEnd();
       }
    
    if(n>=20)
       {
    	n=0;
    	Timer1->Enabled=false; // Stop Blinking
    	rpi->digitalWrite(BCM11,LOW);
    	Memo1->Lines->Add("LED OFF\r\n\r\n");
    	Memo1->Lines->Add("Click Start Button again");
    	Memo1->GoToTextEnd();
       }
    }
    //---------------------------------------------------------------------------
    

    unit1.fmx

    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 480
      ClientWidth = 640
      FormFactor.Width = 320
      FormFactor.Height = 480
      FormFactor.Devices = [Desktop]
      OnCreate = FormCreate
      OnClose = FormClose
      DesignerMasterStyle = 3
      object Panel1: TPanel
        Align = Top
        Size.Width = 640.000000000000000000
        Size.Height = 73.000000000000000000
        Size.PlatformDefault = False
        TabOrder = 0
        object Init: TButton
          Position.X = 24.000000000000000000
          Position.Y = 16.000000000000000000
          Size.Width = 105.000000000000000000
          Size.Height = 41.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 0
          Text = 'Init'
          OnClick = InitClick
        end
        object LED_blink: TButton
          Position.X = 152.000000000000000000
          Position.Y = 16.000000000000000000
          Size.Width = 121.000000000000000000
          Size.Height = 44.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 1
          Text = 'LED_blink'
          OnClick = LED_blinkClick
        end
        object Exit: TButton
          Position.X = 296.000000000000000000
          Position.Y = 16.000000000000000000
          Size.Width = 105.000000000000000000
          Size.Height = 41.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 2
          Text = 'Exit'
          OnClick = ExitClick
        end
      end
      object Memo1: TMemo
        Touch.InteractiveGestures = [Pan, LongTap, DoubleTap]
        DataDetectorTypes = []
        Align = Client
        Size.Width = 640.000000000000000000
        Size.Height = 407.000000000000000000
        Size.PlatformDefault = False
        TabOrder = 1
        Viewport.Width = 632.000000000000000000
        Viewport.Height = 399.000000000000000000
      end
      object Timer1: TTimer
        Enabled = False
        OnTimer = Timer1Timer
        Left = 456
        Top = 24
      end
    end