В предыдущей статье этой серии вы узнали о различных типах периферийных устройств ввода и вывода и подключений, которые можно использовать с Android Things. Затем вы можете расширить эти знания, чтобы написать новые классы, известные как драйверы, которые еще больше упрощают взаимодействие с периферийными устройствами. Эта статья будет посвящена типу драйверов, которые могут быть написаны для Android Things.
Драйверы пространства пользователя Android Things
Драйверы пользовательского пространства позволяют разработчикам внедрять новое оборудование в среду Android, позволяя им взаимодействовать с уже установленными API-интерфейсами Android. Хотя вы можете напрямую связываться с устройствами с помощью стандартных API ввода / вывода, написание собственного драйвера позволит вашему приложению поддерживать различные аппаратные профили и напрямую работать с ОС Android. Кроме того, ваш код будет более структурированным и будет легко поддерживать повторное использование кода.
В этой статье вы узнаете о трех основных категориях драйверов: драйверы GPS, драйверы устройств ввода человека (HID) и драйверы датчиков.
GPS-драйверы
Если вашему устройству требуется информация о местоположении, вы можете добавить устройство GPS в свое приложение. Зарегистрировав свое периферийное устройство GPS в UserDriverManager
, вы сможете внедрить данные о местоположении вашего устройства в платформу Android, что позволит использовать его для служб определения местоположения Android. Это объединит данные GPS с WiFi и любым другим источником местоположения, чтобы обеспечить более точные результаты данных для вашего приложения.
Как правило, ваши модули GPS будут подключаться к устройству Android Things через соединение UART. Мы не будем углубляться в UART в этом учебнике, но вы можете узнать все о том, как он работает для периферийных устройств, в предыдущем учебнике этой серии .
Для работы с вашим GPS-модулем вам необходимо создать новый Java-компонент для связи с вашим новым устройством. Мы назовем этот класс GpsDriverService
.
Чтобы зарегистрировать свой GPS-модуль в платформе Android для данных о местоположении, сначала необходимо создать объект GpsDriver
в вашем GpsDriverService
. Этот объект может быть зарегистрирован с помощью UserDriverManager
с помощью вызова registerGpsDriver()
.
01 02 03 04 05 06 07 08 09 10 11 |
private GpsDriver mDriver; @Override public void onCreate() { super.onCreate(); mDriver = new GpsDriver(); UserDriverManager manager = UserDriverManager.getManager(); manager.registerGpsDriver( mDriver ); } |
Как только ваш GPS-модуль получит данные о местоположении и отправит их на ваше устройство Android Things через последовательное соединение UART, вам потребуется проанализировать их и добавить в объект Location
.
Большинство модулей GPS возвращают данные о местоположении в формате NMEA , хотя анализ этих данных выходит за рамки данного руководства. Для вашего объекта Location есть четыре обязательных элемента данных: точность, время, широта и долгота. Вы также можете при желании указать высоту, направление и скорость (если устройство движется).
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 |
private Location parseLocationFromString(String gpsData) { Location result = new Location(LocationManager.GPS_PROVIDER); //parse gpsData //required result.setAccuracy( getAccuracyFromGpsData( gpsData ) ); result.setTime( getTimeFromGpsData( gpsData ) ); result.setLatitude( getLatitudeFromGpsData( gpsData ) ); result.setLongitude( getLongitudeFromGpsData( gpsData ) ); //optional result.setAltitude( getAltitudeFromGpsData( gpsData ) ); result.setBearing( getBearingFromGpsData( gpsData ) ); result.setSpeed( getSpeedFromGpsData( gpsData ) ); return result; } |
Заполнив объект Location
, вы можете передать его в GpsDriver
, вызвав reportLocation()
.
1 2 |
Location location = parseLocationFromString( rawGpsData ); mDriver.reportLocation( location ); |
После того, как ваш компонент создан, вам нужно будет создать его экземпляр, начать чтение данных и прослушивать обновления в вашем приложении.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
private LocationListener mLocationListener = new LocationListener() { @Override public void onLocationChanged(Location location) { Log.v(«Test», «Location update: » + location); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { Log.e(«Test», «onstatuschanged»); } @Override public void onProviderEnabled(String provider) { Log.e(«Test», «onproviderenabled»); } @Override public void onProviderDisabled(String provider) { Log.e(«Test», «onproviderdisabled»); } }; … mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE); // Create and start the GPS component mGpsDriver = new GpsDriverService(); mGpsDriver.register(); // Register for location updates mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, mLocationListener); |
Когда ваше приложение будет завершено, вам нужно будет отменить регистрацию драйвера и удалить прослушиватель местоположения.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 |
@Override protected void onDestroy() { super.onDestroy(); if (mGpsDriver != null) { mGpsDriver.unregister(); mLocationManager.removeUpdates(mLocationListener); try { mGpsDriver.close(); } catch (IOException e) { } } } |
Кроме того, вам необходимо убедиться, что ваше приложение имеет разрешение ACCESS_FINE_LOCATION
. Вы можете найти подробную информацию о том, что приложение имеет необходимые разрешения в этом руководстве .
-
Android M
Понимание разрешений в Android M
При первой работе с приложением, которое использует новое разрешение в Android Things, вам необходимо перезагрузить устройство после установки приложения, чтобы убедиться, что разрешение было предоставлено.
Драйверы устройств ввода человека
Платформа Android поставляется со встроенным конвейером для обработки ввода от пользовательских кнопок и событий движения, который используется для таких вещей, как мультимедийные кнопки, джойстики контроллера и нажатия клавиш клавиатуры. Создав InputDriver
, вы можете связать свои собственные человеческие взаимодействия со стандартным конвейером ввода Android, чтобы ваше устройство могло правильно реагировать на ваших пользователей.
Для простоты мы рассмотрим только события ввода кнопок и как связать их с платформой Android, хотя события движения обрабатываются очень похожим образом. Как и в последней части этого урока, мы будем игнорировать более конкретные детали реализации устройств ввода и сосредоточимся на привязке полученных событий к платформе Android.
События кнопки
Когда событие кнопки происходит от кнопки, подключенной к вашему устройству Android Things, вы захотите записать это и отправить через конвейер Android.
Первое, что вам нужно сделать, это создать объект InputDriver
в новом Service
и инициализировать его. Драйвер можно инициализировать с помощью компоновщика, который принимает тип ввода, имя для ввода, версию и код клавиши, который представляет кнопка.
01 02 03 04 05 06 07 08 09 10 11 12 |
private InputDriver mDriver; @Override public void onCreate() { super.onCreate(); mDriver = InputDriver.builder(InputDevice.SOURCE_CLASS_BUTTON) .setName(«ButtonInputDriver») .setVersion(1) .setKeys(new int[] {KeyEvent.KEYCODE_SPACE}) .build(); } |
Как только ваш InputDriver
инициализирован, вы можете зарегистрировать его в UserDriverManager
с помощью вызова registerInputDriver()
.
1 2 |
UserDriverManager manager = UserDriverManager.getManager(); manager.registerInputDriver(mDriver); |
Как только вы зарегистрируете свой InputDriver
, ваша служба драйверов может ожидать отправки ему событий из класса реализации вашей кнопки. Если ваша пользовательская кнопка нажата, вы можете уведомить службу и создать новый KeyEvent
, который можно поместить в конвейер ввода Android с помощью метода emit(KeyEvent)
. Этот метод возвращает значение true, если KeyEvent
может быть отправлено в платформу Android, и значение false, если возникает ошибка.
1 2 3 4 5 6 7 |
if( buttonPressed ) { KeyEvent[] events = new KeyEvent[] {new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)}; if (!mDriver.emit(events)) { //something went wrong } } |
Последнее, что вам нужно сделать, это InputDriver
объекта UserDriverManager
в UserDriverManager
когда ваше приложение завершит работу.
1 2 3 4 5 6 7 |
@Override public void onDestroy() { super.onDestroy(); UserDriverManager manager = UserDriverManager.getManager(); manager.unregisterInputDriver(mDriver); } |
Прослушивание входных событий
Теперь, когда вы можете отправлять события ввода кнопок в конвейер ввода Android, самое время их прослушать. Здесь вся работа по перенаправлению ваших новых событий кнопок в платформу Android окупается. В Activity вашего приложения вам просто нужно добавить метод, когда KeyEvent
не работает, и другой, когда KeyEvent
не работает. В этих методах вы можете проверить код ключа KeyEvent
и соответствующим образом обработать событие.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 |
@Override public boolean onKeyDown(int keyCode, KeyEvent event) { if( event.getKeyCode() == KeyEvent.KEYCODE_SPACE ) { //handle it } return true; } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return true; } |
Драйверы датчиков
Некоторые из наиболее распространенных компонентов, которые вы будете использовать с платой Android Things, — это датчики. Поскольку Android имеет довольно надежную сенсорную структуру, имеет смысл только то, что мы хотели бы иметь возможность добавлять данные из наших внешних компонентов в этот конвейер.
Для начала вам нужно создать новый класс Java, который взаимодействует с вашим аппаратным датчиком. Этот класс должен будет расширить UserSensorDriver
и реализовать метод read()
. Кроме того, если ваш датчик поддерживает режимы пониженного энергопотребления или спящего режима, вы можете переопределить метод setEnabled()
и действовать соответственно.
Следующий фрагмент кода представляет собой версию класса с заглушками, которая считывает данные через периферийный API ввода-вывода для получения значений данных X, Y и Z и возврата нового UserSensorReading
. Если данные в данный момент недоступны, ваш класс может выдать новое IOException
.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class ExampleSensorComponent extends UserSensorDriver { float x, y, z; @Override public UserSensorReading read() throws IOException{ try { // Read data from the sensor hardware and return it x = getXValueFromHardware(); y = getYValueFromHardware(); z = getZValueFromHardware(); return new UserSensorReading(new float[]{x, y, z}); } catch (Exception e) { // Error occurred reading the sensor hardware throw new IOException(«Unable to read sensor»); } } //Used if supporting low power/sleep mode @Override public void setEnabled(boolean enabled) throws IOException { super.setEnabled(enabled); } } |
Как только класс вашего компонента создан, вы можете создать новый Service
который будет создавать его экземпляр, а также создать новый объект UserSensor
и присоединить его к конвейеру датчика Android.
Есть два типа датчиков, которые вы можете добавить к этому конвейеру. Первыми являются предопределенные типы, такие как гироскопы, акселерометры, свет и близость, и они могут быть добавлены в конвейер следующим образом:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
private ExampleSensorComponent mExampleSensor; private UserSensor mSensor; private SensorManager mSensorManager; @Override public void onCreate() { super.onCreate(); mExampleSensor = new ExampleSensorComponent(); mSensor = UserSensor.builder() .setName(«ExampleSensorComponent») .setVendor(«VendorName») .setType(Sensor.TYPE_ACCELEROMETER) .setDriver(mExampleSensor) .build(); UserDriverManager manager = UserDriverManager.getManager(); // Register the new driver with the framework manager.registerSensor(mSensor); mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mSensorManager.registerDynamicSensorCallback(new SensorCallback()); } private class SensorCallback extends SensorManager.DynamicSensorCallback { @Override public void onDynamicSensorConnected(Sensor sensor) { //Sensor connected mSensorManager.registerListener(SensorDriverService.this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } @Override public void onDynamicSensorDisconnected(Sensor sensor) { //Sensor disconnected mSensorManager.unregisterListener(SensorDriverService.this); } } |
Вы заметите, что SensorManager.DynamicSensorCallback
используется в приведенном выше примере. Это уведомляет ваше приложение, когда датчик доступен для платформы, так как регистрация может занять некоторое время, чтобы платформа не пыталась считывать данные с недоступного устройства.
Второй тип — пользовательский , который охватывает все, что еще не поддерживается в Android. Некоторые примеры включают уровни pH воды, скорость ветра, обнаружение движения или что-либо еще, что вы можете измерить с помощью нового оборудования.
setType()
параметр setCustomType()
, вы можете добавить имя вашего устройства и режим отчетов, чтобы контролировать, как оно будет срабатывать в конвейере.
1 2 3 4 5 6 7 8 9 |
mSensor = UserSensor.builder() .setName(«ExampleSensorComponent») .setVendor(«VendorName») .setType(Sensor.TYPE_ACCELEROMETER) .setCustomType(Sensor.TYPE_DEVICE_PRIVATE_BASE, «com.tutsplus.examplesensor», Sensor.REPORTING_MODE_ON_CHANGE) .setDriver(mExampleSensor) .build(); |
Наконец, когда ваше приложение завершит работу, вам нужно будет UserDriverManager
регистрацию нового компонента в UserDriverManager
.
1 2 3 4 5 6 |
@Override public void onDestroy() { super.onDestroy(); UserDriverManager manager = UserDriverManager.getManager(); manager.unregisterSensor(mSensor); } |
Вывод
Из этого руководства вы узнали, как использовать компоненты, созданные с использованием API периферийного ввода-вывода, и связывать их с соответствующими платформами Android для использования в приложениях Android Things.
На данный момент в этой серии у вас есть все инструменты, необходимые для создания более глубоких проектов Android Things. Помимо написания собственных драйверов, вы можете найти написанные драйверы и внедрить их в свой собственный проект. Вы можете найти источник этих драйверов в репозитории Android Things GitHub или ознакомиться с некоторыми рабочими примерами с использованием этих драйверов .
В следующей статье этой серии мы пойдем на шаг дальше и создадим полноценный проект Android Things, который берет изображения с Raspberry Pi и загружает их в Firebase. А пока посмотрите другие наши учебники по разработке приложений для Android здесь, на Envato Tuts +!
-
Android SDK
Что нового в Firebase? Обновления с саммита разработчиков Firebase
-
Android SDK
Firebase для Android: Хранение файлов
-
Android M
Понимание разрешений в Android M
-
Android
Введение в Android вещи
Исходная ссылка:http://blog.csdn.net/k_linux_man/article/details/7023824
Воспроизведено указать источник, автор: K_Linux_Man
Платформа разработки: farsight s5pc100-a
Ядро: linux2.6.29
Соответствие среды: введение в сообщение в блоге
Среда разработки: Ubuntu, Eclipse
Прежде всего выделите основные моменты:
1. При написании драйвера для Android вы должны сначала заполнить драйвер Linux, потому что драйвер Android фактически завершает уровень HAL (уровень абстракции оборудования) на основе драйвера Linux, если вы хотите протестировать , Вы должны написать программу на Java для тестирования вашего драйвера.
2. Корневая файловая система Android — это версия eclair_2.1. Я выложу для всех готовую корневую файловую систему. Я хочу сказать, что базовое ядро Android по-прежнему является ядром Linux, только с некоторыми изменениями. Готовый образ ядра linux выложу всем. Android создал набор корневой файловой системы, что и сделал сам Android. По сути, андроид просто создал набор корневой файловой системы.
Предполагается, что драйвер Linux готов для всех. На моей плате четыре источника света, я управляю четырьмя источниками света через ioctl, учитывая разные параметры, загораю разные огни.
Код драйвера Linux варьируется от платформы к платформе, поэтому код не закрепляется.
Это драйвер, который я написал для тестирования драйвера Linux, код выглядит следующим образом:
- #include<stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<fcntl.h>
- #include<string.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<sys/ioctl.h>
- #defineLED_ON_IO(‘k’,1)
- #defineLED_OFF_IO(‘k’,2)
- intmain()
- {
- inti=0;
- intdev_fd;
- dev_fd=open(«/dev/led»,O_RDWR);
- if(dev_fd==-1){
- printf(«Cann’topenfile/dev/ledn»);
- exit(1);
- }
- while(1)
- {
- ioctl(dev_fd,LED_ON,1);
- sleep(1);
- ioctl(dev_fd,LED_OFF,1);
- sleep(1);
- ioctl(dev_fd,LED_ON,2);
- sleep(1);
- ioctl(dev_fd,LED_OFF,2);
- sleep(1);
- ioctl(dev_fd,LED_ON,3);
- sleep(1);
- ioctl(dev_fd,LED_OFF,3);
- sleep(1);
- ioctl(dev_fd,LED_ON,4);
- sleep(1);
- ioctl(dev_fd,LED_OFF,4);
- sleep(1);
- }
- return0;
- }
Теперь начните упаковывать драйвер Linux в драйвер Android.
Сначала расскажите о трех важных структурах, используемых драйвером Android.
struct hw_module_t;
struct hw_device_t;
struct hw_module_methods_t;
Объявление структуры в исходном коде Android.
- typedefstructhw_module_t{
- uint32_ttag;
- uint16_tversion_major;
- uint16_tversion_minor;
- constchar*id;
- constchar*name;
- constchar*author;
- consthw_module_methods_t*methods;
- void*dso;
- uint32_treserved[32-7];
- }hw_module_t;
- typedefstructhw_device_t{
- uint32_ttag;
- uint32_tversion;
- structhw_module_t*module;
- uint32_treserved[12];
- int(*close)(structhw_device_t*device);
- }hw_device_t;
- typedefstructhw_module_methods_t{
- int(*open)(conststructhw_module_t*module,constchar*id,
- structhw_device_t**device);
- }hw_module_methods_t;
Мы часто используем эти три структуры.
Структура каталогов драйвера Android:
led
|— hal
||—-jni
||—— Android.mk
| |—-com_farsgiht_server_ledServer.cpp
||—-stub
||—- include
|||——led.h
||——module
||——Android.mk
||——led.c
|— linux_drv
Во-первых, нам нужно написать заглушку (агент). Агент означает, что для вашего уникального устройства вы можете найти агента, который сделает это за вас. Он первым работает с драйвером linux. слой.
Напишите файл заголовка, назовите led.h
Код выглядит следующим образом;
- #include<hardware/hardware.h>
- #include<fcntl.h>
- #include<errno.h>
- #include<cutils/log.h>
- #include<cutils/atomic.h>
- #defineLED_HARDWARE_MODULE_ID»led»
- structled_module_t{
- structhw_module_tcommon;
- };
- structled_control_device_t{
- structhw_device_tcommon;
- int(*set_on)(structled_control_device_t*dev,intarg);
- int(*set_off)(structled_control_device_t*dev,intarg);
- };
- structled_control_context_t{
- structled_control_device_tdevice;
- };
struct hw_module_t sturct hw_device_t Эти две структуры нельзя использовать напрямую, поэтому они инкапсулируются (наследуются).
led_module_t наследует hw_module_t
led_control_device_t наследует hw_device_t
led_control_context_t наследует led_control_device_t
В структуре led_control_device_t есть объявление указателей на функции, потому что эти указатели на функции будут назначены в коде позади
написать led.c
Код выглядит следующим образом:
- #defineLOG_TAG»LedStub»
- #include<hardware/hardware.h>
- #include<fcntl.h>
- #include<errno.h>
- #include<cutils/log.h>
- #include<cutils/atomic.h>
- #include<sys/ioctl.h>
- #include»../include/led.h»
- #defineLED_ON_IO(‘k’,1)
- #defineLED_OFF_IO(‘k’,2)
- intfd;
- staticintled_set_on(structled_control_device_t*dev,intarg)
- {
- LOGI(«led_set_on»);
- ioctl(fd,LED_ON,arg);
- return0;
- }
- staticintled_set_off(structled_control_device_t*dev,intarg)
- {
- LOGI(«led_set_off»);
- ioctl(fd,LED_OFF,arg);
- return0;
- }
- staticintled_device_close(structhw_device_t*device)
- {
- structled_control_context_t*context=(structled_control_context_t*)device;
- if(context)free(context);
- close(fd);
- return0;
- }
- staticintled_device_open(conststructhw_module_t*module,constchar*name,
- structhw_device_t**device)
- {
- structled_control_context_t*context;
- LOGD(«led_device_open»);
- context=(structled_control_context_t*)malloc(sizeof(*context));
- memset(context,0,sizeof(*context));
- context->device.common.tag=HARDWARE_DEVICE_TAG;
- context->device.common.version=0;
- context->device.common.module=module;
- context->device.common.close=led_device_close;
- context->device.set_on=led_set_on;
- context->device.set_off=led_set_off;
- *device=(structhw_device_t*)&(context->device);
- if((fd=open(«/dev/led»,O_RDWR))==-1)
- {
- LOGI(«ERROR:open»);
- }else{
- LOGI(«openleddeviceokn»);
- }
- return0;
- }
- staticstructhw_module_methods_tled_module_methods={
- open:led_device_open
- };
- conststructled_module_tHAL_MODULE_INFO_SYM={
- common:{
- tag:HARDWARE_MODULE_TAG,
- version_major:1,
- version_minor:0,
- id:LED_HARDWARE_MODULE_ID,
- name:«led_stub»,
- author:«K_Linux_Man»,
- methods:&led_module_methods,
- },
- };
Сначала посмотрите на struct led_module_t HAL_MODULE_INFO_SYM. Имя этой структуры должно совпадать с этим именем, иначе система не сможет найти структуру led_module_t.
Затем присвойте значение члену структуры hw_module_t в led_module_t. Самым важным является назначение двух членов id и методов. Идентификатор должен быть назначен, потому что функция позже находит hw_module_t по номеру идентификатора. После назначения методов можно вызывать верхний джни.
Затем посмотрите только на один член в структуре методов, указатель открытой функции, и назначьте указатель функции на функцию led_device_open. Основная реализация этой функции — выделить пространство структуры led_control_context_t. И присваивайте значения членам. Обратите внимание, что модулям members и close в hw_device_t должны быть присвоены значения.
Назначение указателя функции:
context->device.set_on = led_set_on;
context->device.set_off = led_set_off;
Цель следующего предложения заключается в том, что переданному указателю устройства присваивается новое значение, пока эта функция вызывается, переданный во втором указателе будет иметь значение ( Указатель второго уровня изменяет точку указателя первого уровня, вы можете прочитать сообщения блога int * p и int ** p, которые я написал).
*device = (struct hw_device_t *)&(context->device);
Затем откройте файл устройства и получите fd
led_set_on (); ioctl вызывается внутри;
led_set_off (); ioctl вызывается внутри;
Затем напишите jni. . com_farsight_server_ledServer.cpp файл
Код файла:
- #defineLOG_TAG»ledService»
- #include»utils/Log.h»
- #include<stdlib.h>
- #include<string.h>
- #include<unistd.h>
- #include<assert.h>
- #include<jni.h>
- #include»../stub/include/led.h»
- staticled_control_device_t*sLedDevice=NULL;
- staticjintled_set_on(JNIEnv*env,jobjectthiz,jintarg)
- {
- if(sLedDevice){
- LOGI(«led_set_on»);
- sLedDevice->set_on(sLedDevice,(int)arg);
- }else{
- LOGI(«sLedDeviceisNULL»);
- };
- return0;
- }
- staticjintled_set_off(JNIEnv*env,jobjectthiz,jintarg)
- {
- if(sLedDevice){
- LOGI(«led_set_off»);
- sLedDevice->set_off(sLedDevice,(int)arg);
- }else{
- LOGI(«sLedDeviceisnull»);
- }
- return0;
- }
- staticinlineintled_control_open(conststructhw_module_t*module,
- structled_control_device_t**device)
- {
- LOGI(«led_control_open»);
- returnmodule->methods->open(module,LED_HARDWARE_MODULE_ID,
- (structhw_device_t**)device);
- }
- staticjintled_init(JNIEnv*env,jclassclazz)
- {
- led_module_tconst*module;
- LOGI(«led_init»);
- if(hw_get_module(LED_HARDWARE_MODULE_ID,(consthw_module_t**)&module)==0){
- LOGI(«getModuleOK»);
- if(led_control_open(&module->common,&sLedDevice)!=0){
- LOGI(«led_initerror»);
- return-1;
- }
- }
- LOGI(«led_initsuccess»);
- return0;
- }
- staticconstJNINativeMethodgMethods[]={
- {«_init»,«()Z»,(void*)led_init},
- {«_set_on»,«(I)I»,(void*)led_set_on},
- {«_set_off»,«(I)I»,(void*)led_set_off},
- };
- staticintregisterMethods(JNIEnv*env){
- staticconstchar*constkClassName=
- «com/farsight/server/ledService»;
- jclassclazz;
- clazz=env->FindClass(kClassName);
- if(clazz==NULL){
- LOGE(«Can’tfindclass%sn»,kClassName);
- return-1;
- }
- if(env->RegisterNatives(clazz,gMethods,
- sizeof(gMethods)/sizeof(gMethods[0]))!=JNI_OK)
- {
- LOGE(«failedregisteringmethodsfor%sn»,kClassName);
- return-1;
- }
- return0;
- }
- jintJNI_OnLoad(JavaVM*vm,void*reserved){
- JNIEnv*env=NULL;
- jintresult=-1;
- LOGI(«JNI_onLoad»);
- if(vm->GetEnv((void**)&env,JNI_VERSION_1_4)!=JNI_OK){
- LOGE(«ERROR:jni_onload()n»);
- gotofail;
- }
- assert(env!=NULL);
- if(registerMethods(env)!=0){
- LOGE(«ERROR:registerMethod()n»);
- gotofail;
- }
- result=JNI_VERSION_1_4;
- fail:
- returnresult;
- }
При первой загрузке файла библиотеки jni в jni сначала вызовите функцию JNI_OnLoad, и пусть указатель env получит допустимое значение с помощью системной функции GetEnv. Затем вызовите функцию registerMethods, которая сама определяет функцию.
static const char * const kClassName = «com / farsight / server / ledService»; Имя класса согласуется с соответствующим пакетом, разработанным в Eclipse. Но точки заменены подчеркиваниями.
Затем найдите соответствующий класс и затем зарегистрируйте функцию Native в системе (Native Interface — это функция собственного интерфейса). В списке функций gMethods _init вызывается, когда платформа верхнего уровня загружает библиотеку. При вызове _init вызывается соответствующая функция led_init, () Z означает, что параметр функции led_init пуст, а возврат пуст. Вот собственно отображение функции. Java-функция, используемая на верхнем уровне, соответствует здесь функции c.
Аналогично, остальную часть _set_on _set_off повторять не нужно.
Когда вызывается функция led_init (), как система находит соответствующую заглушку (то есть как найти структуру hw_module_t)? Основная функция — hw_get_module. Эта функция использует номер идентификатора первого параметра, чтобы найти заглушку, соответствующую номеру идентификатора, который уже существует в системе (то есть структурной переменной led_module_t HAL_MODULE_INFO_SYM). Второй параметр — переданный вторичный указатель. Пусть модуль получит допустимое значение,
Затем вызовите led_control_open. Эта функция является встроенной функцией. Затем функция вызывает методы в HAL_MODULE_INFO_SYM. В методах открыт элемент, который фактически вызывает led.c (заглушку). В функции led_device_open указатель sLedDevice является глобальной переменной.После вызова этой функции sLedDevice получает адрес hw_deive_t (sLedDevice указывает на hw_device_t).
Первоначально указатель не имеет значения, но, передав вторичный указатель, вы можете заставить нулевой указатель получить допустимое значение. Вы можете обратиться к моему сообщению в блоге int * p и int * * p, вам будет полезно понять указатель второго уровня, чтобы изменить указатель первого уровня. Поскольку hw_module_t и hw_device_t в заглушке могут быть получены на уровне jni, вызвать функции в заглушке не проблема.
Следующим шагом является реализация уровня инфраструктуры, а служба на уровне framew вызывает jni. Служба на уровне фреймворка разрабатывается под eclipse.
Имя файла: ledService.java
код:
- packagecom.farsight.server;
- importandroid.util.Log;
- publicclassledService{
- static{
- Log.i(«ledService»,«LoadNativeserviceLIB»);
- System.loadLibrary(«led_runtime»);
- }
- publicledService(){
- Log.i(«JavaService»,«doinitNativeCall»);
- _init();
- }
- publicbooleanset_on(intarg){
- if(0==_set_on(arg)){
- returntrue;
- }else{
- returnfalse;
- }
- }
- publicbooleanset_off(intarg){
- if(0==_set_off(arg)){
- returntrue;
- }else{
- returnfalse;
- }
- }
- privatestaticnativeboolean_init();
- privatestaticnativeint_set_on(intarg);
- privatestaticnativeint_set_off(intarg);
- }
private static native boolean _init();
private static native int _set_on(int arg);
private static native int _set_off(int arg);
Три функции здесь являются функциями интерфейса собственного интерфейса, объявленными в jni.
При объявлении объекта ledService будет загружена статическая библиотека функций. По умолчанию соответствующая библиотека загружается в папку / system / lib. Дело в том, что led_runtime опущено. Предыдущая библиотека и суффикс .so.
Таким образом, мы можем добиться успеха при вызове jni, иначе он потерпит неудачу.
Остальное — объявить объект ledService в приложении, а затем вызвать set_on и set_off в объекте. Вы можете написать приложение, чтобы протестировать его самостоятельно.
Ниже приведен снимок экрана одного из моих проектов:
Поскольку он разработан для платы разработки M0, будут скриншоты температуры, влажности и RFID-карты.
Адрес для загрузки источника:http://download.csdn.net/detail/k_linux_man/3865567
Корневая файловая система Android, загрузка ядра zIamge;http://download.csdn.net/detail/k_linux_man/3865826
I’m assuming you mean drivers for the Linux kernel used by Android? I’m fairly sure most of the Android system interfaces with the Linux kernel to access hardware. For example, it relies on the framebuffer device for display, which is powered by a Linux framebuffer driver.
In this case, you need to root your device to get the proper privileges. Next, you need to determine the version of the Linux kernel, then obtain a copy of it.
There’s a lot of documentations on kernel development, and plenty of code to look through, but it’s not an easy task, and you probably won’t want to do it. If you have all of the necessary knowledge of the hardware, it might be a possibility.
edit: Ah, here; this might help you a bit: http://source.android.com/porting/display_drivers.html (there should be more information on other drivers from there on.)
Доброго времени суток, уважаемые форумчане.
Столкнулись с такой проблемой: есть некое устройство, успешно работающее с ОС Windows и Linux (под эти ОС есть драйверы), но теперь потребовалась работа под Android. Сейчас пытаемся работать с этим устройством через систему команд СОМ-порта, но это очень не удобно, к тому же малейшее изменение формата команды может потребовать изменения приложения. Мы под Android никогда ничего не разрабатывали, поэтому есть значительные трудности.
Для начала хотелось бы понять, как вообще должен выглядеть драйвер, и как приложение к этому драйверу должно обращаться. Например, в Windows можно использовать dll-библиотеку, подключая ее к приложению и импортируя методы, или можно использовать СОМ-объекты…
А как это обычно выглядит под Android?
Заранее спасибо!
__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь
If you are talking about a commercial phone and an existing piece of hardware, you are presumably talking about something connected via usb (or else bluetooth or wifi, etc). For these you can perhaps use the appropriate userspace api. For example, on phones/tablets that support usb host there is a host api which lets you access a device somewhat like you would with libusb, though there are limitations.
You should of course be able to get the source to the kernel for any device running a linux kernel; that’s in the kernel license. Many vendors are unfortunately slow to make the releases — the glaring problem with source releases is with a bunch of off-label tablets based on chipsets whose manufacturer apparently does not supply kernel and toolchain sources to the device manufacturers, leading to a hand-me-down license violation.
But returning to commercial hardware, typically (in the tradition of Tivo) having the kernel sources doesn’t mean that the device will allow you to install the compiled result, or that the bootloader will be willing to execute it even if you manage to flash it. Fortunately some of the phone manufacturers are getting better about offering developers and power users ways to unlock the bootloader of personal or test devices — devices sold by Google itself being the leading example.
If you are talking about a commercial phone and an existing piece of hardware, you are presumably talking about something connected via usb (or else bluetooth or wifi, etc). For these you can perhaps use the appropriate userspace api. For example, on phones/tablets that support usb host there is a host api which lets you access a device somewhat like you would with libusb, though there are limitations.
You should of course be able to get the source to the kernel for any device running a linux kernel; that’s in the kernel license. Many vendors are unfortunately slow to make the releases — the glaring problem with source releases is with a bunch of off-label tablets based on chipsets whose manufacturer apparently does not supply kernel and toolchain sources to the device manufacturers, leading to a hand-me-down license violation.
But returning to commercial hardware, typically (in the tradition of Tivo) having the kernel sources doesn’t mean that the device will allow you to install the compiled result, or that the bootloader will be willing to execute it even if you manage to flash it. Fortunately some of the phone manufacturers are getting better about offering developers and power users ways to unlock the bootloader of personal or test devices — devices sold by Google itself being the leading example.
Первое, что вам нужно для этого, — это полное понимание аппаратной архитектуры устройства.
Эта система основана на nVIDIA Tegra 3, и ЖК-панель будет напрямую подключена к ее графической подсистеме.
Первым делом вам следует обратиться к Техническому справочному руководству по Tegra. Если судить по другим SoC ARM, которые я видел, будет 8000-10000 страниц, и они будут доступны только под соглашением о неразглашении, особенно те части, которые относятся к графической подсистеме.
Далее вам потребуется полное понимание того, как дисплеи обрабатываются в Linux. Вы хотите реализовать простой фреймбуфер или использовать 2D- и 3D-функции Tegra?
Также будет драйвер подсветки ЖК-панели — контроллер для которого, скорее всего, будет подвешен на одну из шин I2C Tegra.
Создание базового драйвера фреймбуфера для Linux должно быть довольно простым, поскольку на самом деле он мало что делает.