Mediensystem für Toyota Prius (Restayl)



Dies ist der erste (einführende) Artikel in der Reihe, wie ich das Mediensystem des Autos fertigstellen werde. Das Projekt selbst, die Zeit, wie alle anderen - nein, also, liebe Leser, bitte haben Sie etwas Geduld, denn ich verspreche oft nicht, Artikel zu nieten.

Es begann alles damit, dass ich einen Prius bekam.

Und das erste, was mir aufgefallen ist - Probleme beim Aktualisieren der Navigation. Folgendes ist sehr selten, aber an einigen Stellen sind die erforderlichen Funktionen des Geräts mit dem Namen "Multifunktionsdisplay" (in der Regel Personen - der Kopf) vorhanden. Und dies vor dem Hintergrund einer Vielzahl chinesischer Radios mit Android an Bord und vielen Annehmlichkeiten. Ihre Installation an einem regelmäßigen Ort impliziert jedoch den Entzug solcher "Brötchen" wie das Diagramm der Energieverteilung und Klimatisierung.

Die Idee war geboren, den Android-Radio-Recorder irgendwie enger mit dem Auto zu verbinden, als die chinesischen Brüder vermuten lassen. Über diesen Artikel

Ausgangssituation


So An Bord befindet sich ein 7-Zoll-Display mit einem resistiven Touchscreen, der mit den anderen Elektronikleitungen TX + und TX- verbunden ist. Und diese Paare aus dem Kopf gehen bis zu 3. In diesem Schema heißt dieses Wunder AVC-LAN und sieht folgendermaßen aus:



Teil 1: Nach innen schauen


Wie Sie sehen, steht der Kopf in der Netzwerkunterbrechung, zwischen dem Router und der weiteren Kette des Radio-Recorders, des Verstärkers (er ist von mir getrennt) und einem separaten Kanal folgt die Kommunikation mit der Navigationseinheit. An einem anderen Ort hängt die Parkhauseinheit, die in meinen Schemata nicht erwähnt wird. Nun ja, ich beschloss, die Intimität bis in bessere Zeiten zu verschieben. Außerdem ist der Parkplatz eher ein Spiel, als wirklich notwendig.

Wenn wir alles Unnötige entfernen, werden wir über das folgende Blockdiagramm der Geräte informiert:



Reflexionen


Es wurde angenommen, dass die Navigationseinheit durch etwas Anderes ersetzt werden sollte, aber es verblasste, als ich tiefer herausfand, wie sie mit meinem Kopf kommunizieren. Neben AVC-LAN sind diese Module auch über die GVIF-Leitung (Gigabit Video InterFace) miteinander verbunden, und genau dieses Gesicht des Konverterherstellers kann versehentlich knacken, wenn ich auch einen GVIF-Videokonverter für mehr als 100 US-Dollar kaufe es mag schwierig sein, aber ... “- es klang in meinem Kopf nach dem Motiv eines berühmten Liedes, und mir gefiel die Entscheidung nicht.

Online-Lösungen mit der Installation des chinesischen Radios anstelle des Funkempfängers. Es hat mir nicht gefallen, dass die beiden Anzeigen - unzumutbare Redundanz. IMHO

Lösung


Die folgende Entscheidung wurde geboren: den ganzen Kopf zu ersetzen und den Android-Radio-Recorder zu verfeinern, nachdem er sich mit dem Prius angefreundet hatte, wofür:

  1. Entwickeln Sie einen USB <-> AVC-LAN-Hardwarekonverter
  2. Entwickle dazu Firmware, damit es sich als USB-HID verbindet.
  3. Um es zusammengesetzt zu machen, so dass eine der Funktionen als herkömmliche Hardwaretastatur erkannt wird (mit dem Ziel, als systemeigene Steuerung über die Schaltflächen des Bedienfelds zu dienen)
  4. Entwickeln Sie eine Android-Anwendung mit ähnlichen Funktionen wie Priusovsky
  5. Verhandeln Sie die hintere Kamera
  6. Mechanische Aufgaben lösen (Installation an einem normalen Ort)

Dabei bietet es sich an, eine weitere Anwendung für Android zu entwickeln - ein gewöhnlicher Sniffer, so dass es günstiger wäre, die Pakete über AVC-LAN rückgängig zu machen. Zur gleichen Zeit und Praxis.

Dies alles sollte folgendermaßen aussehen:



Als Hardware-Basis wurde beschlossen, eine Lernplatine für den SM32F103 zu verwenden:



Von AliExpress für $ 2,05 bestellt.

Oder suchen Sie - Spoiler
Möglicherweise wurde das Los bereits vom Verkäufer gelöscht.
Daher gebe ich die Suchzeichenfolge zur Suche nach Ali: STM32F103C8T6 ARM STM32 Minimum System Development Board-Modul

Was ich an ihr mag:

  • USB-Hardwaremodul (Device) an Bord des Prozessors
  • Angemessener USB-Stack vom Hersteller (im Gegensatz zu Freescale-Ovsky darf man sich nachts nicht erinnern).
  • Kostenlose GPIO-Anschlüsse, über die normale Tasten an den Seiten des Monitors angeschlossen werden können. Vielleicht können Sie dadurch die Hardware-Tasten des Radios unter dem Bedienfeld ausblenden. Ich weiß nicht was es sein wird
  • Und daran können Sie AVC-LAN-Konverter an logische Ebenen hängen

Weiter werde ich in der Reihenfolge der Umsetzung beschreiben, was vor allem auf mein persönliches Wissen zurückzuführen ist. Ie Ich versuchte, die Orte zu erkennen, an denen sie ganz am Anfang nicht dort waren, und endlich das verlassen, was sicherlich passieren würde.

In jedem Fall sind mehrere Artikel in verschiedenen Hubs geplant. Das Projekt erweist sich als sehr FullStack - von der Hardwareverbindung bis zur Android-Anwendung.

Teil 2: USB, HID, Griffe und alles, um einen Pilotprototyp zu erhalten


Als ersten Schritt wollte ich ein Bündel von Gerät und Telefon erhalten, damit das Gerät das Paket auf das Telefon übertragen kann, und dieses, um es in der Anwendung anzuzeigen.
Wie Gagarin sagte: Lass uns gehen!

USB-HID-Composite-Gerät an STM32


Was ich beschlossen habe, ist, ein Beispiel von ST an meine Aufgaben anzupassen und ein USB-Gerät zu erhalten, das vom Host als Kombination aus Tastatur und „etwas anderem“ erkannt wird - ein RAW-HID-Gerät. Der erste ist, wie gesagt, für die native Verwaltung von Android vorgesehen, der zweite - für den direkten Austausch von AVC-LAN-Paketen mit dem Programm auf dem Gerät.

Ich habe CubeMX von STM als Grundlage genommen und viele Artikel über die Implementierung eines benutzerdefinierten HIDs gelesen. Ich habe im Netzwerk eine unangenehme Sache gefunden: Es gibt praktisch keine oder nur sehr unzureichend geplante Erstellung von Verbundgeräten.

Quellcodes werden später sein
Исходные коды пока не выкладываю, по причине того, что проект сейчас реализуется в экспериментально-учебном режиме. Если проект будет успешно завершен — обязательно перетащу их на Github, и отредактирую статью ссылкой на оные.
В том виде, в котором они есть, выкладывать бессмысленно — бардака в интернете и без меня хватает.

USB, Composite, HID


Wörtlich ein paar Worte zu diesem Thema. Es wird davon ausgegangen, dass Sie mit dem USB-Standard mehr oder weniger vertraut sind. Wenn nicht, ist es besser, zuerst Beispiele von CubeMX zu lesen und mit ihnen zu experimentieren.

Wir haben also:

STM USB-Stack und ein Beispiel für eine Mausimplementierung. Dort haben wir einige Deskriptoren und einen funktionalen Endpunkt konfiguriert. Dies ist zusätzlich zu einem Paar von 0x00 und 0x80, um das Gerät vollständig zu steuern.

Um mein Projekt zu implementieren, ist es erforderlich, dass der Endpunkt der Tastatur bidirektional ist (ich weiß nicht warum, es ist praktisch) und ein weiteres Paar von Endpunkten, das zum Datenaustausch mit der zweiten, der RAW-Funktion verwendet wird. Fügen Sie sie hinzu.

Machen Sie den Punkt bidirektional, indem Sie den OUT-Punkt zum Deskriptor hinzufügen:

Konfigurations-Handle
При правке дескриптора следите за индексами и размерами.
(2c5cf968121f0d8fa43a6755c09e15ef3a317791):

0x07,          /*bLength: Endpoint Descriptor size*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  HID_EPOUT_ADDR,     /*bEndpointAddress: Endpoint Address (IN)*/0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */0x00,
  HID_FS_BINTERVAL,  


Und noch ein paar Punkte hinzufügen:

Konfigurationsdeskriptor
(bc2bd583c98715e106fcb3ab07b266bc9221be36):

/* 59 */0x07,          /*bLength: Endpoint Descriptor size*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  HID_EPIN_ADDR2,     /*bEndpointAddress: Endpoint Address (IN)*/0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */0x00,
  HID_FS_BINTERVAL,          /*bInterval: Polling Interval (10 ms)*//* 66 */0x07,          /*bLength: Endpoint Descriptor size*/
  USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/
  HID_EPOUT_ADDR2,     /*bEndpointAddress: Endpoint Address (IN)*/0x03,          /*bmAttributes: Interrupt endpoint*/
  HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */0x00,
  HID_FS_BINTERVAL,          /*bInterval: Polling Interval (10 ms)*/


Es war ein Konfigurationsdeskriptor. Nun ist der Host sicher, dass wir eine Art zusammengesetztes HID-Gerät haben, und Daten können an alle diese Punkte gesendet werden. Dies ist jedoch noch nicht der Fall.
Damit dies wahr wird:

1. In unserem Controller befindet sich ein speziell ausgewählter Speicher, der mit den CAN- und USB-Modulen getaktet wird. Da das USB-Modul unabhängig in den Prozess des Empfangens / Sendens eines Datenpakets involviert ist, ist es erforderlich, diesem Puffer für jeden separat genommenen Endpunkt Puffer zuzuweisen:

USBD_LL_Init in der Datei usbd_conf.c
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x00 , PCD_SNG_BUF, 0x18);
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , 0x80 , PCD_SNG_BUF, 0x58);
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR , PCD_SNG_BUF, 0x100);
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR , PCD_SNG_BUF, 0x140);
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPOUT_ADDR2 , PCD_SNG_BUF, 0x180);
  HAL_PCDEx_PMAConfig((PCD_HandleTypeDef*)pdev->pData , HID_EPIN_ADDR2 , PCD_SNG_BUF, 0x1B0);


Pufferadressen sind beliebig, um sich nicht zu überlappen.

Aus irgendeinem Grund wird der ST-Stapel auf der Grundlage geschrieben, dass es im Gerät nicht mehr als einen bidirektionalen Endpunkt gibt. Daher verbessern wir den Stapel geringfügig:

Übertragung


Die Prozedur USBD_HID_SendReport wird in USBD_HID_SendReportEP umbenannt, wobei ein weiterer Parameter hinzugefügt wird - die Endpunktnummer. Die Prozedur mit dem alten Namen wird aus Gründen der Abwärtskompatibilität beibehalten. Im Rumpf wird jedoch USBD_HID_SendReportEP mit einer Konstante in Form eines Endpunkts aufgerufen. Die Entscheidung ist noch nicht die ästhetischste, aber sie wird für das Experiment herbeigeführt, und selbst wenn sie bleibt, wird sie ein bestimmtes Projekt nicht beeinträchtigen.

usbd_hid.c
uint8_t USBD_HID_SendReportEP (USBD_HandleTypeDef  *pdev, 
                                 uint8_t ep,
                                  uint8_t *report,
                                  uint16_t len)
{
 ... тело, бывшее раньше USBD_HID_SendReport
}
uint8_t USBD_HID_SendReport     (USBD_HandleTypeDef  *pdev, 
                                 uint8_t *report,
                                 uint16_t len)
{
  return USBD_HID_SendReportEP(pdev,HID_EPIN_ADDR,report,len);
}


Nun ist alles zum Senden von Daten bereit, es muss nur noch diese Funktion zum richtigen Zeitpunkt aufgerufen werden.

Fertig stellen


Wir durchsuchen die Bestellung nach dem Projekt und rufen USBD_LL_CloseEP erneut auf, jedoch für die neu erstellten Endpunkte.

Empfang


Damit die Endpunkte moralisch einwandfrei funktionieren, müssen Sie USBD_LL_PrepareReceive für sie aufrufen. Ich empfehle dem Leser, das Projekt nach dieser Linie zu durchsuchen und diese Herausforderungen an ihre Bedürfnisse anzupassen.

In meinem Code habe ich diesen hässlichen Tintenfisch bekommen:

usbd_core.c
USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR+(epnum&0x7F)-1 , hhid->Report_buf,
                          USBD_HID_OUTREPORT_BUF_SIZE);


Ie Ich ging davon aus, dass die Anzahl der Endpunkte in einer Reihe liegt. Das ist schlecht, IMHO. Mach das nicht Allerdings auch als ST nicht so.

Dann müssen Sie nur noch die Datei usbd_hid.c und speziell die Funktion USBD_HID_DataOut aufrufen und darauf achten, dass der Aufruf des empfangenen Datenhandlers Ihren persönlichen Vorstellungen von beauty entspricht. Ich habe es auch nicht wirklich getan, daher wird der Code und die Beschreibung lang und unverständlich sein. Einfacher, es selbst zu machen.

Bericht


An diesem Ort haben wir ein Composite-Gerät erhalten, das Daten über zwei bidirektionale Punkte austauschen kann. Der letzte Schliff besteht darin, die Neugier des HID-Treibers zu "stopfen" und einen solchen Berichtsdeskriptor zu beschreiben:

__ALIGN_BEGIN staticuint8_t HID_ReportDesc2[33]  __ALIGN_END =
{
    0x06, 0x00, 0xff,              // USAGE_PAGE (Vendor Defined Page 1)0x09, 0x01,                    // USAGE (Vendor Usage 1)0xa1, 0x01,                    // COLLECTION (Application)0x85, 0x01,                    //   REPORT_ID (1)0x15, 0x00,                    //   LOGICAL_MINIMUM (0)0x26, 0xff, 0x00,              //   LOGICAL_MAXIMUM (255)0x75, 0x08,                    //   REPORT_SIZE (8)0x95, 0x1f,                    //   REPORT_COUNT (31)0x09, 0x00,                    //   USAGE (Undefined)0x81, 0x00,                    //   INPUT (Data,Ary,Abs)0x85, 0x02,                    //   REPORT_ID (2)0x09, 0x01,                    //   USAGE (Vendor Usage 1)0x75, 0x08,                    //   REPORT_SIZE (8)0x95, 0x1f,                    //   REPORT_COUNT (31)0x91, 0x00,                    //   OUTPUT (Data,Ary,Abs)0xc0// END_COLLECTION
}; 

In diesem Bericht heißt es HID-Treiber: Es werden etwa 31 Byte Daten vorliegen. Sie müssen nicht herausfinden, wofür sie gedacht sind - geben Sie sie einfach dem Programm an, mit dem das Gerät geöffnet wurde. Im physischen Bericht entspricht das Null-Byte dem Berichtsindex (REPORT_ID (2)). Dementsprechend werden insgesamt 32 Bytes ankommen.

Und geben Sie die Daten darüber in die Funktion usbd-hid.c, USBD_HID_Setup ein:

usbd-hid.c
switch (req->bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR: 
      if( req->wValue >> 8 == HID_REPORT_DESC)
      {
// TODO: !!! Отдать нужный дескриптор, в зависимости от значения req->wIndex !!!
        THIDDescPtrLen * rep = (req->wIndex==1)?&HID_ReportDesc:&HID_ReportDesc2;
        len = MIN(rep->len , req->wLength);
        pbuf = rep->ptr;
      }

Weiter im Programm:


  1. Zusammenbau des AVC-LAN-Logikpegelumsetzers und Anschluss an die Karte. Analyse der physikalischen Schicht von AVC-LAN, reale Wellenformen.
  2. Verarbeitung der Schnittstelle auf Controller-Ebene und Senden von Paketen über Berichte
  3. End-to-End-Schnittstelle und Reverse Engineering Prius. Sniffer-Pakete (oder meine erste Android-Anwendung)

PS


  • Ich beschloss, den Artikel zu schreiben, weil ich (fast) gezwungen war, mich davon zu überzeugen, dass dieser geteilt werden sollte. Selbst wenn ich das Projekt nicht abschließe, kann eine bestimmte Menge aktueller Informationen jemandem sogar in „roher“ Form helfen.
  • Kritik am Projekt ist willkommen, weil Ich kann mir immer noch nicht ganz vorstellen, dass es klappen wird.
  • Kritik am Artikel, Design, Präsentation - vor allem seitdem Dies ist der erste Artikel für die Ressource. Während ich weiter arbeite, möchte ich meine Gedanken in einer vertrauten und bequemen Form für die Leser ausdrücken.

Jetzt auch beliebt: