All of our modern PCs, Smartphones, Tablets and other devices include more than just a screen, keyboard, mouse, memory, and storage. The devices We use include sensors for location, orientation, acceleration, ambient light, etc. My Samsung Slate Series 7 is a hybrid or "2 for 1" device that is both a desktop PC and a Tablet. It includes two cameras and accelerometer. Even if they don't include a GPS or other hardware sensor, our programs can use APIs to find the location from known Internet access points.  Some smartphones and tablets include two camera devices.  PCs for some time have had both a built-in microphone and a line-input jack. Different operating systems and hardware platforms provide different services:  Windows and Mac support menus, dialogs and mice, most include support for a canvas for low level drawing, a GPU (at least one or more) is available for higher performance 2D and 3D graphics, earlier versions of iOS did not provide a cut/copy/paste clipboard, server side systems may not provide a screen service, and there are many other services that we may or not have access to for C++ applications we build that need to run on different platforms.  What is a C++ developer supposed to do build applications that can run on a variety of systems and platforms?  The choices are varied and include using platform APIs, querying the hardware directly, adding conditional compilation to source code, and other methods.

Having access to a robust component framework that provides start-of-the-art components, classes and interfaces that do the work for you, greatly improves your ability to build applications for a wider arrange of systems.  C++Builder XE4 allows you to query for services, devices and sensors to know what your application can use.  FM, the component framework from Embarcadero Technologies, provides everything a C++ developer needs to query devices, count the number of sensors, and know which services are available for application use.  FM itself uses the same sensor, device and platform services to know how to initialize itself on each of the target platforms.  What sensors, device and services are supported for C++ application development? Let's take a look at each of the three in more detail.

Sensors

FM's support for sensors is organized into sensor categories:

  • Location

  • Environmental

  • Motion

  • Orientation

  • Mechanical

  • Electrical

  • Biometric

  • Light

  • Scanner


The sensor category definition in System.Sensors.hpp is:

TSensorCategory : unsigned char { Location, Environmental, Motion, Orientation, Mechanical, Electrical, Biometric, Light, Scanner }

For each sensor category there are many possible sensor types including:

  • TLocationSensorType : unsigned char { GPS, Static, Lookup, Triangulation, Broadcast, DeadReckoning, Other };

  • TEnvironmentalSensorType : unsigned char { Temperature, AtmosphericPressure, Humidity, WindSpeed, WindDirection };

  • TMotionSensorType : unsigned char { Accelerometer1D, Accelerometer2D, Accelerometer3D, MotionDetector, Gyrometer1D, Gyrometer2D, Gyrometer3D, Speedometer };

  • TOrientationSensorType : unsigned char { Compass1D, Compass2D, Compass3D, Inclinometer1D, Inclinometer2D, Inclinometer3D, Distance1D, Distance2D, Distance3D };

  • TElectricalSensorType : unsigned char { Voltage, Current, Capacitance, Resistance, Inductance, ElectricalPower, Potentiometer };

  • TMechanicalSensorType : unsigned char { BooleanSwitch, BooleanSwitchArray, MultiValueSwitch, Force, Scale, Pressure, Strain };

  • TBiometricSensorType : unsigned char { HumanPresence, HumanProximity, Touch };

  • TLightSensorType : unsigned char { AmbientLight };

  • TScannerSensorType : unsigned char { RFID, Barcode };


In your C++ code you can get a count of the identified sensors, sensor name, sensor category and type, sensor state and more.


    // get list of found sensors - if any
    TSensorManager::Current->Active = true;
    int NumberOfSensors = TSensorManager::Current->Count;
    Label2->Text = "Sensors: "+IntToStr(NumberOfSensors);
    Memo2->Lines->Clear();
    for (int i = 0; i < NumberOfSensors;i++) {
    Memo2->Lines->Add(IntToStr(i)+ ": "
    + TSensorManager::Current->Sensors[i]->Name
    + ". Category: "
    + System::Typinfo::GetEnumName(
    __delphirtti(TSensorCategory),TSensorManager::Current->Sensors[i]->Category)
    + ". State: "
    + System::Typinfo::GetEnumName(__delphirtti(TSensorState),
    TSensorManager::Current->Sensors[i]->State)
    );
    }
    TSensorManager::Current->Active = false;



Once you know which sensors are available in your application you can chose to use the FM components and classes directly in your applications.  You can also query to ensure that a specific sensor is available for your application to use.  When you build your applications for Windows and Mac in C++Builder XE4 you'll have easy access to all of the sensors available on each of your target systems.

Devices

How many cameras do your PCs, Smartphones and Tablets have?  How many audio inputs does you application have access to?  You use use FM's support for device managers to be able to use them in your applications.  Each FM based application includes a default device manager.  The Device Manager interfaces will give you the device name, media type of the device (audio/video), the device state and other information about specific devices.  You can query and filter for specific device media types or iterate through the collection of devices to find the ones your application is looking for.


    TMediaType : unsigned char { Audio, Video };
    TCaptureDeviceState : unsigned char { Capturing, Stopped };
    TDevicePosition : unsigned char { dpUnspecified, dpFront, dpBack };
    TFlashMode : unsigned char { fmAutoFlash, fmFlashOff, fmFlashOn };
    TFocusMode : unsigned char { fmAutoFocus, fmContinuousAutoFocus, fmLocked };
    TTorchMode : unsigned char { tmModeOff, tmModeOn, tmModeAuto };
    TVideoCaptureQuality : unsigned char { vcPhotoQuality, vcHighQuality, vcMediumQuality, vcLowQuality };


The following C++ code snippet lists the audio and video capture devices available to your application.


    // get list of found devices - if any
    int NumberOfDevices = TCaptureDeviceManager::Current->Count;
    Label1->Text = "Devices: "+IntToStr(NumberOfDevices);
    Memo1->Lines->Clear();
    for (int i = 0; i < NumberOfDevices; i++) {
    Memo1->Lines->Add(IntToStr(i)+ ": "
    + TCaptureDeviceManager::Current->Devices[i]->Name
    + ". MediaType: "
    + System::Typinfo::GetEnumName(
    __delphirtti(TMediaType),
    TCaptureDeviceManager::Current->Devices[i]->MediaType)
    + ". State: "
    + System::Typinfo::GetEnumName(
    __delphirtti(TCaptureDeviceState),
    TCaptureDeviceManager::Current->Devices[i]->State)
    );
    }


The following C++ code snippet shows you how to support a system with one or two video cameras (like my Samsung Slate Series 7).


    // get count of number of video cameras devices - if any
    int NumberOfDevices = TCaptureDeviceManager::Current->Count;
    int NumberOfVideoDevices = 0;
    for (int i = 0; i Devices[i]->MediaType == TMediaType::Video) {
    NumberOfVideoDevices++;
    }
    CameraCountLabel->Text = "Cameras: "+IntToStr(NumberOfVideoDevices);
    if (NumberOfVideoDevices > 0) {
    VideoCamera1 = dynamic_cast(TCaptureDeviceManager::Current->GetDevicesByMediaType(TMediaType::Video)->Items[0]);
    if (VideoCamera1 != NULL) {
    VideoCamera1->OnSampleBufferReady = Camera1SampleBufferReady;
    }
    }
    if (NumberOfVideoDevices > 1) {
    VideoCamera2 = dynamic_cast(TCaptureDeviceManager::Current->GetDevicesByMediaType(TMediaType::Video)->Items[1]);
    if (VideoCamera2 != NULL) {
    VideoCamera2->OnSampleBufferReady = Camera2SampleBufferReady;
    }
    }


Platform Services

Each target platform comes with its support for different application and user interface paradigms.  These platform services can include, but are not limited to, the following types of services:

  • Application Service

  • Dialog Service

  • Canvas Service

  • Context Service

  • Locale Service

  • Clipboard Service

  • Cursor Service

  • Device Service

  • Drag and Drop Service

  • Hide App Service

  • Mouse Service

  • Screen Service

  • Style Service

  • Style HiRes Service

  • System Font Service

  • Text Service

  • Virtual Keyboard Service

  • Menu Service

  • Window Service

  • Window Border Service

  • Timer Service


In your C++ applications you can query whether a service is available on a target platform. If the service is available, use the native platform service or provide your own or a third party alternative.  For Windows and Mac development it is safe to assume that there is a mouse, menu, dialog and clipboard.  As your C++ applications move beyond the desktop, you may not have a dialog or menu service, but you can probably assume that there will be a virtual keyboard service.

Using the SupportsPlatformService method will return true or false if the service is available to your application.  The second method will return the service so that you can use it in your code.


    bool __fastcall SupportsPlatformService(const GUID &AServiceGUID);
    bool __fastcall SupportsPlatformService(const GUID &AServiceGUID, System::_di_IInterface &AService);


Here is a FM based C++ code snippet that lets you test to see if there is a virtual keyboard service available to your application and uses it:


    _di_IFMXVirtualKeyboardService KBDService;
    // if the platform supports the virtual keyboard
    if ((TPlatformServices::Current->SupportsPlatformService(
    __uuidof(IFMXVirtualKeyboardService)) &&
    (KBDService = TPlatformServices::Current->GetPlatformService(
    __uuidof(IFMXVirtualKeyboardService))))) {
    // Show the virtual keyboard
    KBDService->ShowVirtualKeyboard(Form4);
    }
    else {
    Edit1->Text = "No Virtual Keyboard Service Found!";
    }


Using Devices, Sensors and Platform Services in your Applications

I've written blog posts and created videos that show C++ developers how to work with sensors, devices and platform services.  Take a look at the following links for additional information.











As C++ developers move beyond the desktop, the same component framework will take you and your code to new platforms, devices, embedded applications and beyond.

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder. Design. Code. Compile. Deploy.

Start Free Trial   Free Delphi Community Edition   Free C++Builder Community Edition   Upgrade Today  

  • some code is a redundant but idea is clear code example on embarcadero blocking some sensors (AtmosphericPressure,Accelerometer3D,LinearAccelerometer3D,Light,GyroscopeRotationVector,GamerotationVector..) ....only beautiful thing a force to think,think....
  • Hello, I compile example (accelerometer and sensor info) from Embarcadero (RAD Studio) but why did not work (not sensor information) on my Samsung galaxy s5? /with modul system.sensor androi system not work or i thinking about I must write new code to example on RAD Studio/ delphifmandroid.blogspot.bg/.../blog-post.html www.embarcadero.com/.../android-ios-code-samples-xe5 example /*****************************/ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "uMain.h" // --------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.fmx" #pragma resource ("*.LgXhdpiPh.fmx", _PLAT_ANDROID) TAccelerometerForm *AccelerometerForm; // --------------------------------------------------------------------------- void __fastcall TAccelerometerForm::CreateIfExists(TSensorCategory ASensorCategory) { TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(ASensorCategory); lbAccelerationX->Text = GetSensorType(LSensorArray[3]); lbAccelerometerSensor->Data = LSensorArray[3]; } // --------------------------------------------------------------------------- String __fastcall TAccelerometerForm::GetSensorType(TCustomSensor *ASensor) { String Result = cND ; switch (ASensor->Category) { case TSensorCategory::Motion: Result = GetTypeNameMotion(static_cast(ASensor)->SensorType); break; default: ; } return Result; } // --------------------------------------------------------------------------- __fastcall TAccelerometerForm::TAccelerometerForm(TComponent* Owner) : TForm(Owner), cND("Not defined"), cForm(L" %s =\n%30s %3.5f \n") { } // --------------------------------------------------------------------------- void __fastcall TAccelerometerForm::FormCreate(TObject *Sender) { // start with no sensors lbAccelerationX->Visible = false; lbAccelerationY->Visible = false; lbAccelerationZ->Visible = false; lbAngleAccelX->Visible = false; lbAngleAccelY->Visible = false; lbAngleAccelZ->Visible = false; lbMotion->Visible = false; lbSpeed->Visible = false; FActiveSensor = NULL; TSensorManager::Current->Activate(); CreateIfExists(TSensorCategory::Motion); TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(TSensorCategory::Motion); FActiveSensor = (TCustomSensor*)LSensorArray[3]; #ifdef _WIN32 lbAccelerometerSensor->Text = "Simulator - no sensors"; swAccelerometerSensorActive->Enabled = False; #endif } // --------------------------------------------------------------------------- void __fastcall TAccelerometerForm::swAccelerometerSensorActiveSwitch (TObject *Sender) { // activate or deactivate the reading of the accelerometer sensor MotionSensor1->Active = swAccelerometerSensorActive->IsChecked; Timer1->Enabled = swAccelerometerSensorActive->IsChecked; if (Timer1->Enabled ) { Timer2->Enabled = false; lbAccelerationX->Visible = true; lbAccelerationY->Visible = true;lbAccelerationZ->Visible = true; TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(TSensorCategory::Motion); FActiveSensor = (TCustomSensor*)LSensorArray[3]; } else { Timer2->Enabled = true; Timer1->Enabled = false; lbAccelerationX->Visible = false; lbAccelerationY->Visible = false;lbAccelerationZ->Visible = false; TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(TSensorCategory::Motion); FActiveSensor = (TCustomSensor*)LSensorArray[3]; } } // --------------------------------------------------------------------------- void __fastcall TAccelerometerForm::Timer1Timer(TObject *Sender) { String ResultTextX, TY, TZ ; if (FActiveSensor != NULL) { switch (FActiveSensor->Category) { case TSensorCategory::Motion: ResultTextX = GetInfoAboutMotionX(FActiveSensor); TY = GetInfoAboutMotionY(FActiveSensor); TZ = GetInfoAboutMotionZ(FActiveSensor); break; } TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(TSensorCategory::Motion); TCustomMotionSensor * ls = static_cast(FActiveSensor); if (!ls->Started) ls->Start(); FActiveSensor = (TCustomSensor*)LSensorArray[0]; lbAccelerationX->Data = LSensorArray[0]; if (!ls->Started) ls->Start(); if (ls->AvailableProperties.Contains(TCustomMotionSensor::TProperty::AccelerationX)){ lbAccelerationX->Text = ResultTextX; lbAccelerationY->Text = TY; lbAccelerationZ->Text = TZ; } } } // --------------------------------------------------------------------------- String __fastcall TAccelerometerForm::GetTypeNameMotion(TMotionSensorType AType) { String Result = cND; switch (AType) { case TMotionSensorType::Accelerometer1D: Result = "Accelerometer1D"; break; case TMotionSensorType::Accelerometer2D: Result = "Accelerometer2D"; break; case TMotionSensorType::Accelerometer3D: Result = "Accelerometer3D"; break; case TMotionSensorType::MotionDetector: Result = "MotionDetector"; break; case TMotionSensorType::Gyrometer1D: Result = "Gyrometer1D"; break; case TMotionSensorType::Gyrometer2D: Result = "Gyrometer2D"; break; case TMotionSensorType::Gyrometer3D: Result = "Gyrometer3D"; break; case TMotionSensorType::Speedometer: Result = "Speedometer"; break; case TMotionSensorType::LinearAccelerometer3D: Result = "LinearAccelerometer3D"; break; case TMotionSensorType::GravityAccelerometer3D: Result = "GravityAccelerometer3D"; break; } return Result; } // --------------------------------------------------------------------------- String __fastcall TAccelerometerForm::GetInfoAboutMotionX(TCustomSensor *ASensor) { String LValuesX = ""; TCustomMotionSensor * ls = static_cast(ASensor); if (!ls->Started) ls->Start(); if (ls->AvailableProperties.Contains(TCustomMotionSensor::TProperty::AccelerationX)) LValuesX.sprintf(L"Acceleration X: %6.4f",ls->AccelerationX*10); return LValuesX; } // --------------------------------------------------------------------------- String __fastcall TAccelerometerForm::GetInfoAboutMotionY(TCustomSensor *ASensor) { String LValuesY = ""; TCustomMotionSensor * ls = static_cast(ASensor); if (!ls->Started) ls->Start(); if (ls->AvailableProperties.Contains(TCustomMotionSensor::TProperty::AccelerationY)) LValuesY.sprintf(L"Acceleration Y: %6.4f",ls->AccelerationY*10); return LValuesY; } // --------------------------------------------------------------------------- String __fastcall TAccelerometerForm::GetInfoAboutMotionZ(TCustomSensor *ASensor) { String LValuesZ = ""; TCustomMotionSensor * ls = static_cast(ASensor); if (!ls->Started) ls->Start(); if (ls->AvailableProperties.Contains(TCustomMotionSensor::TProperty::AccelerationZ)) LValuesZ.sprintf(L"Acceleration Z: %6.4f",ls->AccelerationZ*10); return LValuesZ; } // --------------------------------------------------------------------------- void __fastcall TAccelerometerForm::Timer2Timer(TObject *Sender) { String ResultText; if (FActiveSensor != NULL) { TSensorArray LSensorArray = TSensorManager::Current->GetSensorsByCategory(TSensorCategory::Motion); FActiveSensor = (TCustomSensor*)LSensorArray[3]; TCustomMotionSensor * ls = static_cast(FActiveSensor); if (!ls->Started) ls->Start(); } } //---------------------------------------------------------------------------