Простая эмуляция USB клавиатуры при помощи PIC18F2550 в CarPC на базе Android

в 19:33, , рубрики: android, carpc, diy или сделай сам, pic, usb, микроконтроллер, периферия, Программинг микроконтроллеров, метки: , , , ,

Здравствуйте, уважаемые участники Habrahanr.

При том, что Хабр — портал, ориентированный на программистов, обратил внимание, что последнее время появляется много статей о программировании микроконтроллеров и создании девайсов на их базе. Решил поделиться одной своей разработкой. В прошлом я много писал для МК, даже работал разработчиком ПО и схемотехники в одной из фирм, а до этого программил на АСМе под Z80 и i8080. Сейчас, во взрослой жизни, в основном пишу на PHP/MySQL для собственных интернет-проектов и к программированию МК не возвращался очень давно. Назвать полноценным программистом я себя не могу, т.к. освоить, например, OOP так и не смог, но немного пишу на С по мере надобности.

Некоторое время назад у меня возникла задача создать эмулятор USB клавиатуры для CarPC проекта. Использоваться она должна была в магнитоле Becker BE2580, устанавливаемой на автомобили немецкого производства 2000-х годов. Эмулятор должен был опрашивать штатные кнопки магнитолы и генерировать нажатия на виртуальной USB клавиатуре, подключенной к материнской плате CarPC на базе Android. Что из этого получилось, под катом.

Вкратце о самом CarPC: изначально мне в голову пришла крамольная идея воткнуть в машину новомодную магнитолу на базе Android со съёмной передней панелью-планшетом, которую недавно начали выпускать китайские производители. Однако товарищи по автосообществу отговорили меня от этой идеи, призывая не нарушать классический облик салона автомобиля и дизайн, задуманный производителем. В результате, в магнитолу была встроена материнская плата от медиаплеера Iconbit Toucan Nano, установил я её на место кассетной лентопротяжки. При этом отметил как быстро развивается прогресс: решил ради интереса проверить кассетник, но дома не нашлось ни одной кассеты.

Toucan Nano — идеальный кандидат для использования в CarPC, при цене около 100 долл (в РФ) у него есть TV выход (композит), компонент (субтрактивный с выделенным синхросигналом), правда, отсутствует, к сожалению, RGB, который был нужен для вывода изображения на дисплей в самой магнитоле. Есть HDMI, USB хост (2 порта). Ещё в ядро оказались вкомпилированными поддержка чипа PL2303 (USB2COM конвертер, т.е. RS232) — что позволило подключить внешний GPS приёмник, а также поддержка WiFi свистков на чипе Ralink (я использовал Dlink DWA-140). Плата была установлена в магнитолу, сигнал с ТВ выхода подан на RGB входы штатного монитора магнитолы при помощи самостоятельно собранного конвертора TV -> RGB на базе TDA8362. В магнитоле предусмотрен коммутатор видео-сигнала, таким образом, весь родной функционал магнитолы был сохранён. Выглядит это примерно вот так:

Простая эмуляция USB клавиатуры при помощи PIC18F2550 в CarPC на базе Android

Красным цветом показано то, что размещено вторым этажом (под платой). С Toucan Nano в комплекте идёт пульт, работающий в паре с радио-свистком. В пульте реализована интересная технология Fly Mouse: мышь реагирует на встроенный в пульт акселерометр, таким образом, просто наклоняя пульт, передвигаешь мышку по экрану девайса, получается что-то вроде указки. Однако, в машине пользоваться этим мне показалось неудобно и глупо: это ведь всё-таки магнитола, а не комп! Поэтому было принято решение собрать эмулятор клавиатуры магнитолы, который бы подключался к порту USB и вёл себя как стандартная PC клавиатура, при этом опрашивая кнопки магнитолы. По сути, решение это универсально и может использоваться с любой ОС: не секрет, что многие системы CarPC строятся на платформах Intel.

Так случилось, что у меня на тот момент не было опыта работы с микроконтроллерами PIC, в молодости я программил для Atmel, но этот опыт на сегодня был уже не актуален, т.к. прошло лет 10 и о моих любимых AT89c2051 сейчас, наверное, уже никто не помнит. Писались программы тогда строго на АСМе, т.к. на С это просто было бы сложнее, у 2051 всего 2К ПЗУ. В те годы PIC тоже существовал, но мы отказались от его использования, т.к. средства разработки были слишком дороги, а для 2051 я тогда разрабатывал эмулятор ПЗУ самостоятельно на базе i51 с внешней ПЗУшкой, имевшего тот же instruction set что и Atmel 89c2051. Сейчас, поняв, что мне придётся пройти этот путь фактически заново, я собрался духом и засел за литературу. Думаю, опыт потому и будет полезен читателям, что всё расписываю по шагам, в развитии.

Сначала я стал изучать интернет на тему микроконтроллеров с поддержкой USB и сразу же наткнулся на девайс от славной компании PIC, это был 18F2550. Заявленные его функции оказались очень неплохими: поддержка USB 2.0, 1К ОЗУ, полностью конфигурируемый USB порт, по сути, 2550 может стать любым USB девайсом. Плюс все стандартные фичи PIC. Эту микросхему можно приобрести в корпусе DIP28, что удобно для монтажа и распайки, да и цена совсем невысока. В стародавние времена микроконтроллеры шили программатором, сейчас стали популярны бутлоадеры. Смысл бутлоадера в том, что его достаточно записать в микроконтроллер всего один раз, после чего вы можете обращаться к нему какими-либо иными средствами (в нашем случае через USB порт), и обновлять прошивку девайса, не извлекая его из схемы. Продаются готовые киты с предпрошитыми микроконтроллерами и готовым софтом для заливки прошивок через бутлоадер, однако мне искать такой кит (вернее, ждать пока его пришлют) не хотелось. Поэтому я просто отправился в ближайший радиомагазин и купил чистый PIC18F2550.

Далее нужно было собрать программатор для заливки бутлоадера. Пошарив по инету, нашёл вот это:

products.foxdelta.com/art2003.htm

Софт использовал WinPic800. Про сам бутлоадер история отдельная. Грузится он с адреса 0x000, соответственно сама прога должна начинаться с адреса 0x800, что указывается в настройках компилятора. Находил несколько разных бутлоадеров, они льют прошивку в разных режимах (например, HID), соответственно, предназначены для разных IDE. USB Драйвер PIC для прошивающего компа тоже может использоваться разный, т.к. PIC «превращается» в разные USB девайсы. Мне постоянно попадались бутлоадеры для 18F4550, а его конфиг отличается и бутлоадер от него на моём МК не работал. В результате, я остановился на бутлоадере и загрузчике прошивки на базе PIC-овской демо-платы MCHPUSB. Сам бутлоадер пришлось немного доработать под мою схемотехнику (т.к. я разместил кнопку бутлоадера на другом пине микроконтроллера). Вообще, там оказалось много всяких разных параметров (например, тип кварцевого резонатора, умножитель частоты и много подобной ерунды). При неправильном указании этих параметров, девайс шьётся и даже мигает светодиодом по программе, но потом отказывается работать как USB девайс, выдавая мою «любимую» ошибку «USB устройство не опознано», т.к. частоты неправильные. С этой проблемой я провозился пару дней, пока окончательно не нашёл работоспособную конфигурацию. В итоге, мой бутлоадер рассчитан на кварц 4Mhz. Светодиод припаян на RA5, кнопка активации режима прошивки для бутлоадера — на RA3 (и с нее 1кОм на плюс), 26 нога на землю (для работы в режиме LVP). Для того, чтобы МК вошёл в режим бутлоадера, удерживая сброс, нажимаем указанную кнопку на RA3. Бит LVP (отключение режима низковольтной прошивки) перепрошить мне почему-то так и не удалось, ну и ладно. По идее он нужен для предохранения бутлоадера от перезаписи. Умножитель настроен на максимальную частоту 48 Mhz. К сожалению, если микроконтроллер используется в режиме USB, выше частоту поднять нельзя, т.к. частоты USB фиксированы, а у умножителя есть кратность, но это оказалось и не нужно.

В итоге, бутлоадер поправил, драйвера на комп от Microchip установил. В качестве основы программы сразу взял бесплатный пример от Bradley A. Minch, который выдаёт на виртуальную клавиатуру последовательно символы 'f', 'o', 'o', 'b', 'a', 'r'. Исходный код этой программы можно найти здесь:

code.google.com/p/picusb/source/browse/lab2_pickit2/lab2.asm?spec=svn69&r=69

Скомпилировав программу, предварительно настроив кучу конфигурационных регистров PIC-а, я добился, что она начала печатать на компе в цикле строку foobar! Ура! В реальности всё это тоже случилось не за один день, но подробности я опускаю. И здесь меня постиг на секунду страх, что всё это чудо может не заработать на Iconbit, который может просто без объяснения причин игнорировать почти неделю моей работы — и я никогда не узнаю почему. Но, подключив девайс к Android материнке, я увидел, что всё заработало: тут же открылось окно поиска в котором побежали знакомые буковки foobar. Android на нажатие произвольных клавиш реагирует открытием именно окна поиска.

Далее требовалось доработать программу до моих нужд, в частности написать код, который будет считывать данные с самой магнитолы. Как это будет работать, я на тот момент не представлял. Думал, придётся подключаться к матрице магнитолы и считывать с неё. Обычно подобные устройства используют динамическое сканирование матрицы, когда по оси X «бежит» единичка, а по оси Y считывается информация. Т.е., скажем, 16 клавиш можно обработать 8 пинами (4 + 4). Чтобы параллельно считывать такую матрицу тоже понадобится 8 пинов, но настроенных на ввод. Однако, покопавшись на плате магнитолы, я обнаружил, что заботливые немцы выделили отдельный процессор для обработки всей клавиатуры, единственно, ручки энкодеров шли напрямую на центральный проц. В итоге, у проца клавиатуры магнитолы я нашёл выход, на котором появляются импульсы при нажатии любых клавиш магнитолы. Частота следования импульсов оказалась достаточно высокой и для начала я просто тупо подключил их к конвертеру на базе PL2303, т.е. просто подал на RS-232 порт и начал экспериментировать с настройками порта. В результате выяснилось, что осмысленные байты можно увидеть, настроив порт аж на 480 кбит. Для мне до сих пор загадка зачем немцам понадобилось данные с клавиатуры передавать на такой высокой скорости.

Для того чтобы написать программу для PIC, пришлось детально проанализировать характер импульсов клавиатурного процессора магнитолы. Для этого я купил осциллограф. В молодости, конечно, у меня были все эти приборы, но всё это осталось у родителей, а я уже 5 лет как переехал в Москву. Поэтому решил потихоньку собирать парк приборов: ведь к радиолюбительству возвращаюсь время от времени.

В итоге оказалось, что процессор перед каждой пачкой информации (которая состоит из 2 байт), выдаёт длинный импульс, который служит «пилотом», предупреждающим о начале передачи блока информации. Удивительным оказалось то, что длина этого блока (равно как и промежутки между байтами) меняются произвольным образом даже при нажатии одной и той же кнопки. Другая проблема оказалась в том, что PIC не мог программным путём надёжно читать данные на такой скорости. Ведь он должен ещё и успевать обслуживать шину USB! Если нажатие клавиши происходит в неподходящий момент, он её просто пропускает. Как я писал выше, частоту ядра я поднял до максимума при помощи умножителей, однако даже при такой настройке процессор работал на пределе и иногда пропускал биты, в результате вероятность правильного определения кнопок составляла около 70%, что недопустимо в автомобиле. Здесь я уже собрался с умом и подумал, что, наверное, есть второй сигнал (строб). Так и оказалось. Но изначально я его не нашёл потому, что импульсы на нём почему-то присутствуют постоянно, а было бы логично если бы они появлялись при нажатии кнопок. Видимо, процессор магнитолы опрашивает клавиатуру в непрерывном цикле и выдаёт импульс при передаче любого бита, даже если состояние клавиш не меняется. Т.е., просто шлёт нули если нет никакой активности. В общем, процессор стробирует каждый передаваемый бит, в результате их можно читать абсолютно чётко. Программу на PIC переписал, после чего всё стало работать стабильно и красиво. При нажатии кнопки формируется один код, при отпускании — другой. Таким образом можно было ещё реализовать режим удерживания кнопок, но я этого делать не стал, т.к. кнопок и так оказалось в изобилии.

Здесь я приведу выдержки из своей программы, те части, что написал именно я. Оригинал программы вы можете увидеть по приведённой выше ссылке. В программе у меня есть, разумеется, таблица, сопоставляющая считанные коды клавиш и USB коды, которые надо передавать в головной девайс. Сразу замечу, что комментарии я обычно пишу на английском (чтобы не терять время на переключение регистра). Если кому-то интересна полная версия программы, я без проблем могу выслать её. Полный текст не привожу здесь по соображениям соблюдения авторских прав. Также могу выслать и бутлоадер и программу для его прошивки, программу для заливки прошивок.

Перекодировка кнопок.

unsigned char recode(long n) {

if (n==0x3550) return 'Q'; // <> REVERSE

if (n==0x1580) return 'U'; // up — 1
if (n==0x6aa0) return 'X'; // next — 2
if (n==0x2540) return 'D'; // down — 3
if (n==0x4a80) return 'Z'; // prev — 4
if (n==0x1570) return 'L'; // left — 5
if (n==0x0560) return 'R'; // right — 6

if (n==0x4520) return 'H'; // home
if (n==0x0ac0) return 'A'; // player
if (n==0x6500) return 'T'; // TEL ??
if (n==0x5530) return 'N'; // navi
if (n==0x7510) return 'S'; // settings
if (n==0x1b28) return 'B'; // back

if (n==0x4500) return 'E'; // enter
if (n==0x28e0) return 'M'; // (MAP) ??
if (n==0x1320) return 'O'; // notification area — REPEAT
if (n==0x0330) return 'F'; // search/find — CALL

return 0;
}

int remap(int n) {

// launcher
if (n=='S') return 0x3a; // F1 settings/menu
if (n=='F') return 0x3b; // F2
if (n=='O') return 0x3c; // F3 notification area

// programs
if (n=='H') return 0x3D; // F4 home
if (n=='A') return 0x3f; // F6 audio/player
if (n=='N') return 0x40; // F7 navi
if (n=='M') return 0x44; // F11 map
if (n=='T') return 0x45; // F12 tel

// player controls
if (n=='Z') return 0x3e; // F5 prev song
if (n=='X') return 0x43; // F10 next song

//cursor
if (n=='L') return 0x50; // left
if (n=='R') return 0x4f; // right
if (n=='U') return 0x52; // up
if (n=='D') return 0x51; // down

if (n=='E') return 0x28; // enter
if (n=='B') return 0x29; // ESC back

return 0x0;

}

Конфиги:

#pragma config DEBUG = OFF

// 1L 30000
#pragma config PLLDIV = 1 // PLL prescaler
//#pragma config CPUDIV = OSC3_PLL4 // sysclock postscaler — working
#pragma config CPUDIV = OSC1_PLL2 // sysclock postscaler
#pragma config USBDIV = 2 // usb clock comes from PLL div 2

// 1H 30001
// #pragma config FOSC = XTPLL_XT // low speed mode
#pragma config FOSC = HSPLL_HS // highspeed mode
#pragma config FCMEN = OFF // fail safe clock
#pragma config IESO = OFF // int/ext oscillator

// 2L 30002
#pragma config PWRT = OFF // power up timer
#pragma config BOR = OFF // brown out
#pragma config BORV = 0
#pragma config VREGEN = ON // usb voltage regulator

// 2H 30003
#pragma config WDT = OFF // watchdog
#pragma config WDTPS = 32768

// 3H 30005

#pragma config CCP2MX = ON // ccp2 mux
#pragma config PBADEN = OFF // portb a/d enable
#pragma config LPT1OSC = ON // low power timer 1 oscillator
#pragma config MCLRE = ON // MCLR pin enable

// 4L 30006
#pragma config STVREN = ON // stack full
#pragma config LVP = ON
#pragma config XINST = OFF // extended instructions

// 30008

//#pragma config ICPRT = OFF
#pragma config CP0 = OFF
#pragma config CP1 = OFF
#pragma config CP2 = OFF
#pragma config CP3 = OFF

// 30009

#pragma config CPB = OFF
#pragma config CPD = OFF

// 3000a

#pragma config WRT0 = OFF
#pragma config WRT1 = OFF
#pragma config WRT2 = OFF
#pragma config WRT3 = OFF

// 3000b
#pragma config WRTB = OFF
#pragma config WRTC = OFF
#pragma config WRTD = OFF

// 3000c

#pragma config EBTR0 = OFF
#pragma config EBTR1 = OFF
#pragma config EBTR2 = OFF
#pragma config EBTR3 = OFF

// 3000d

#pragma config EBTRB = OFF

//#define SHOW_ENUM_STATUS

#define LED PORTAbits.RA5
#define CAR PORTAbits.RA0 // keypad data line
#define EN1 PORTAbits.RA1
#define EN2 PORTAbits.RA2
#define SYN PORTAbits.RA3 // keypad strobe line

Часть конфигов переопределяется самим программатором при заливке бутлоадера.

Передача кода клавиши на USB интерфейс:

void SendKeyBuffer(void) {
unsigned char n;

for (n = 0; n<8; n++)
BD1I.address[n] = Key_buffer[n]; // copy Key_buffer to EP1 IN buffer
BD1I.bytecount = 0x08; // set the EP1 IN byte count to 8
BD1I.status = ((BD1I.status&0x40)^0x40)|0x88; // toggle the DATA01 bit of the EP1 IN status register and set the UOWN and DTS bits
}

int sendKey1(unsigned char c) {

int n;
long timeout=0;

for (n = 0; n<8; n++) Key_buffer[n] = 0x00; // clear key buffer

// ?? hang place 2

while ((BD1I.status&0x80)) {
// wait to see if UOWN bit of EP1 IN status register is clear, (i.e., PIC owns EP1 IN buffer)
timeout++;
if (timeout>250000) {
return 0;
}
ServiceUSB();
}

*(Key_buffer+2)=c;
SendKeyBuffer();

ServiceUSB();

return 1;
}

int sendKey(unsigned char c) {
if (sendKey1©) return (sendKey1(0x00));
return 0;
}

Подпрограммы чтения кнопок магнитолы. Для максимизации быстродействия
цикл не используется. Важен каждый такт.

char readByte() {

unsigned char b = 0;
// unsigned char i = 0;

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

while (SYN==0);
b = (b << 1) | CAR;
while (SYN==1);

return b;

}

int countZero() {

unsigned short i=1;
while (CAR==0 && i++);

return i/4;

}

int readCar() {

int i;
int d = 0;

unsigned char k;
unsigned char r;
unsigned long vl;

//#define analyzer
//#define dbg // debug mode

if (CAR==0) return 1;

#ifdef analyzer

for (i=0;i<110;i++) {
carbuff[i]=readByte();
carbuff[i+110]=ssd; // strobe data
}

for (i=0;i<221;i++) {
printHex(carbuff[i]);
}

crlf();
crlf();

return 1;

#endif // end analyzer

while (CAR==1); // short intro 1
while (CAR==0); // short intro 0
while (CAR==1); // long intro 1

vl = readByte() * 0x100 + readByte();

k = recode(vl);

#ifdef dbg
printDword(vl); // dbg
crlf(); // dbg
#endif

if (k!=0) {

#ifdef dbg
printChar(k); // dbg
crlf(); // dbg
#endif

#ifndef dbg
r=remap(k); // send actual keys we need
return sendKey®;
#endif

}

}

CAR — пин на который подключен сигнал с процессора клавиатуры магнитолы. SYN — сигнал строб с процессора клавиатуры магнитолы.

В процессе отладки я столкнулся с рядом проблем. В некоторых случаях микроконтроллер зависал и USB устройство просто пропадало. Протокол обмена USB очень непростой и вникать во все его нюансы было непросто. Путём проб и ошибок я нашёл проблемные места и добавил туда программный watchdog, который просто перезапускал процессор в случае зависания в этих местах. В итоге, я добился устойчивой бессбойной работы программы без зависаний с верностью определения нажатия клавиш 99%. USB порт в самом Toucan работает не очень хорошо, тем более, что я использовал USB разветвитель. Иногда даже «серьёзные» девайсы типа USB свистка мыши пропадают до следующей перезагрузки. Что уж говорить о моей самоделке. Однако, мне удалось добиться стабильности на уровне заводских USB девайсов.

Далее нужно было подключить энкодер. Я задумал направить данные с энкодера на эмуляцию кнопок «вверх» и «вниз», а нажатие ручки энкодера на клавишу Enter. Ну нажатие обрабатывает процессор, т.е. оно уже работает. Что касается энкодера, реализовать его чтение совсем несложно. Если его пины подключить к двум битам, он выдает последовательность 0, 1, 3, 2 (в двоичном коде 00 01 11 10). Двойку с тройкой меняем местами, получается 0 1 2 3. Далее, текущий результат из предыдущего вычитаем, если разность 1 или -3, то вращение в одну сторону, если -1 или 3, — в другую. Видел, что чтение энкодера реализуют какой-то таблицей, в общем, ничего это не нужно делать. Вот процедура:

int readEncoder() {

int k;
int enc;
int subb;
int res = 1;
static int enc1 = 0;
static int init = 0;

if (!init) { // prevent encoder key command sent on startup
init = 1;
enc1 = enc = EN1 + EN2 * 2;
if (enc==3 || enc==2) enc=enc ^ 1;
}

enc = EN1 + EN2 * 2;
if (enc==3 || enc==2) enc=enc ^ 1;

if (enc != enc1) {

subb = enc — enc1;
if (subb==1 || subb==-3) k='U';
if (subb==-1 || subb==3) k='D';

res = sendKey(remap(k)); // send up or down key command
}

enc1 = enc;

return res;

}

Теперь PowerAMP управляется чётко: ручка-энкодер и она же enter! Ручкой бегаем по папкам с музыкой, кнопкой входим в них и запускаем композиции. Мечта!

Добавлю, что коды, генерируемые виртуальной клавиатурой, это не коды ASCII и даже не коды клавиш Android (которые тоже отличаются от кодов ASCII). Это отдельные коды USB клавиатуры. Найти их можно в этой таблице:

www.win.tue.nl/~aeb/linux/kbd/scancodes-14.html

Соответственно, в Android есть специальный конфиг, который отвечает за обработку спец. клавиш. Конечно, мне надо было запускать и навигацию, и использовать кнопку Home и запускать плеер. Для этой цели нужно отредактировать файл keylayout, описание этих файлов есть здесь:

source.android.com/tech/input/key-layout-files.html

Вот мой конфиг:

key 1 BACK # ESC («AC» button)
key 59 MENU # F1 («BC» button)
#key 60 CAMERA # F2 («CALL» button)
key 61 NOTIFICATION # F3 («repeat» key on deck)
key 62 HOME # F4 («main» button)
key 63 MEDIA_PREVIOUS # F5 («4» button)
key 64 HEADSETHOOK # PLAY/PAUSE F6 («audio» button)
#key 65 INFO # F7 («navi» button)
key 66 VOLUME_UP # F8 ??
key 67 VOLUME_DOWN # F9 ??
key 200 HEADSETHOOK # hardware key # MEDIA_STOP not working
key 68 MEDIA_NEXT # F10 («6» button)
key 87 POWER # F11 ('map' key on deck)
#key 88 EMAIL # F12 («tel» button)

Разумеется, отредактировать этот файл можно только на рутованных устройствах.

Так получилось, что некоторые клавиши не работают после установки последнего обновления на Toucan Nano. Почему — мне так и не удалось выяснить. Например, перестала работать самая важная кнопка HOME. Поэтому я написал простой командный файлик, который у меня стартует при старте системы. Вот он:

#!/system/bin/sh
stty -F /dev/ttyUSB0 ispeed 4800
chmod 0777 /dev/ttyUSB0

sleep 20
am broadcast -a info.mapcam.droid.SERVICE_START # mapcam.info

while true

do

s=$(getevent -v0 -c1) # считываем одно событие из всех устройств ввода
# -v0 чтобы он не сыпал кучей ненужного мусора

s=$(echo $s | awk '{print $4}') #выделяем код клавиши

case $s in # выполняем нужную команду
0007003f) am start -a android.intent.action.MAIN -c android.intent.category.HOME -n com.maxmpz.audioplayer/.StartupActivity # AUDIO
# am start -a android.intent.action.MAIN -c android.intent.category.HOME -n com.maxmpz.audioplayer/.PlayListActivity # AUDIO
sleep 1
;;

00070040) am start -n ru.yandex.yandexmaps/.MapActivity # NAVI
sleep 1
;;

0007003d) am start -a android.intent.action.MAIN -c android.intent.category.HOME
sleep 1
;;

00070045) am start -a android.intent.action.MAIN -n com.speedsoftware.rootexplorer/.RootExplorer # TEL
sleep 1
;;

0007003b) am startservice -a «org.broeuschmeul.android.gps.usb.provider.nmea.intent.action.START_GPS_PROVIDER»
sleep 5
am broadcast -a info.mapcam.droid.SERVICE_START
# am start -n info.mapcam.droid/.SpeedometrActivity # CALL
sleep 1
;;
esac

done

Данный эмулятор уже почти в течение года успешно используется на машине. В планах сделать эмуляцию мыши, чтобы её можно было передвигать по экрану кнопками. Интегрировать тачскрин в систему я пока, к сожалению, так и не осилил. К сожалению, ряд программ (например Карты Рамблер) не управляются кнопками и требуют наличия тачскрина. Поэтому всё-таки для таких случаев в машине приходиться возить USB мышку.

О самом Android проекте я могу как-нибудь рассказать отдельно если это будет интересно.

Простая эмуляция USB клавиатуры при помощи PIC18F2550 в CarPC на базе Android

Автор: elgordo

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js