
Ceci est le premier article (d'introduction) de la série sur la façon dont je vais affiner le système multimédia de la voiture. Le projet lui-même est en cours, il n'y a pas de temps, comme tout le monde, donc, chers lecteurs, soyez patient, car souvent je ne promets pas de riveter des articles.
Tout a commencé avec le fait que j'avais une Prius.
Et la première chose qui a attiré mon attention a été les problèmes de mise à jour de la navigation. Les éléments suivants sont très maigres, mais à certains endroits, les fonctionnalités nécessaires d'un appareil appelé «écran multifonction» (chez les gens ordinaires - la tête). Et cela dans le contexte d'un grand nombre de radios chinoises avec Android à bord et de nombreuses commodités. Mais leur installation sur un lieu régulier implique la privation de tels "petits pains" comme schéma de répartition de l'énergie et du contrôle climatique.
L'idée est née de connecter d'une manière ou d'une autre la radio Android avec la voiture plus que ne le suggèrent les frères chinois. À propos de cela et de l'article.
Situation initiale
Alors. À bord, il y a environ un écran de 7 pouces avec un écran tactile résistif, connecté à d'autres appareils électroniques avec des lignes TX + et TX-. Et il y a déjà 3 paires de la tête. Dans le circuit, ce miracle s'appelle AVC-LAN, et ressemble à ceci:

Partie 1: Regarder autour de soi
Comme vous pouvez le voir, la tête est dans l'espace du réseau, entre le routeur et la chaîne supplémentaire de la radio, l'amplificateur (je l'ai séparément), et une connexion à l'unité de navigation suit un canal séparé. Quelque part ailleurs, un parking est suspendu, non mentionné en aucune façon dans mes projets. Eh bien, eh bien ... j'ai décidé de reporter la proximité avec elle jusqu'à des temps meilleurs. De plus, le stationnement est plus une fonction de jeu qu'un réel besoin.
Après avoir supprimé tous les éléments inutiles, nous obtenons approximativement le schéma fonctionnel des appareils suivant:

Réflexions
Il y avait une idée de simplement remplacer l'unité de navigation par quelque chose d'androïde, mais elle s'est éteinte lorsque j'ai compris plus profondément comment ils communiquent avec la tête. En plus d'AVC-LAN, ces modules sont également connectés par la ligne GVIF (Gigabit Video InterFace), et ce même visage des fabricants de convertisseurs peut accidentellement se fissurer si j'achète également un convertisseur de signal vidéo en GVIF pour plus de 100 $. «Vivre sans visage, c'est être cela peut être difficile, mais .. "- sonnait dans ma tête le motif d'une chanson célèbre, et je n'ai pas aimé la décision.
Il y avait des solutions sur le réseau avec l'installation d'une radio chinoise au lieu d'un récepteur radio. Cela ne me convenait pas car les deux écrans sont d'une redondance déraisonnable. À mon humble avis.
Solution
La solution suivante est née: remplacer la tête entière, et finaliser la radio Android, se faire des amis avec la Prius, pour laquelle:
- Convertisseur matériel USB <-> AVC-LAN
- Développez le firmware pour qu'il se connecte comme un USB-HID.
- Rendez-le composite de sorte qu'une des fonctions soit détectée comme un clavier matériel normal (afin de l'utiliser comme un contrôle natif à partir des boutons du panneau)
- Développer une application Android avec des fonctionnalités similaires (ou supérieures) à la native Priusovsky
- Alignez la caméra arrière
- Résoudre les problèmes de la partie mécanique (installation dans un endroit régulier)
Dans le processus, il sera nécessaire de développer une autre application pour Android - un renifleur ordinaire, afin qu'il soit plus pratique d'inverser les paquets sur AVC-LAN. En même temps et pratique.
Cela devrait ressembler à ceci:

Comme base matérielle, il a été décidé d'utiliser une carte de formation sur le SM32F103:

Commandé avec AliExpress pour 2,05 $.
Ou rechercher - spoilerPeut-être que le lot a déjà été supprimé par le vendeur, je donne donc la chaîne magique pour rechercher sur Ali:
STM32F103C8T6 ARM STM32 Module de carte de développement système minimum
Ce que j'aime chez elle:
- Module matériel USB (périphérique) à bord du processeur
- Pile USB adéquate du fabricant (contrairement au Freescale-ovsky, ne vous souvenez pas de la nuit).
- Ports GPIO gratuits qui peuvent être utilisés pour connecter des boutons normaux sur les côtés du moniteur. Peut-être que cela masquera les boutons matériels de la radio sous le panneau. Je ne sais pas ce qu'elle sera
- Et là-dessus, vous pouvez accrocher le convertisseur AVC-LAN en niveaux logiques
Je décrirai plus loin dans l'ordre de mise en œuvre, ce qui est dû tout d'abord à mes connaissances personnelles. C'est-à-dire J'ai essayé de réaliser les endroits où ils n'étaient pas au tout début, à la fin en laissant ce qui devait certainement arriver.
Dans tous les cas, plusieurs articles sont prévus dans différents hubs. Le projet s'avère être beaucoup FullStack - de la connexion matérielle à l'application Android.
Partie 2: USB, HID, descripteurs et tout pour obtenir un prototype pilote
La première étape, je voulais obtenir un tas d'appareils et de téléphones, et pour que l'appareil puisse transférer le paquet vers le téléphone, et cela - pour l'afficher dans l'application.
Comme l'a dit Gagarine: allons-y!
Périphérique composite USB HID sur STM32
Ce que j'ai décidé de faire était d'adapter l'exemple ST de mes tâches et d'obtenir un périphérique USB qui est reconnu par l'hôte comme faisant partie du clavier et «autre chose» - le périphérique RAW HID. Le premier, comme je l'ai déjà dit, est destiné au contrôle natif d'Android, le second - à l'échange direct de paquets AVC-LAN avec le programme sur l'appareil.
Basé sur CubeMX de STM, et après avoir lu de nombreux articles sur la façon d'implémenter un HID personnalisé, j'ai trouvé une chose désagréable sur le réseau: la question de la création d'appareils composites est pratiquement absente ou très rare.
Les codes sources seront plus tardJe ne télécharge pas encore les codes sources, car le projet est maintenant mis en œuvre en mode de formation expérimentale. Si le projet est terminé avec succès, assurez-vous de les faire glisser vers Github et de modifier l'article avec un lien vers eux.
Dans la forme sous laquelle ils se trouvent, cela n'a aucun sens de télécharger - il y a assez de dégâts sur Internet sans moi.
USB, composite, HID
Juste quelques mots à ce sujet. On suppose que vous connaissez plus ou moins la norme USB. Sinon, il est préférable de vous familiariser avec et de tester des exemples de CubeMX.
Nous avons donc:
Exemple d'implémentation d'une pile et d'une souris USB STM. Là, nous avons configuré certains descripteurs et un point de terminaison fonctionnel. Ceci s'ajoute à une paire de 0x00 et 0x80 pour contrôler l'ensemble du périphérique.
Pour mettre en œuvre mon projet, j'ai besoin que le point de terminaison du clavier soit bidirectionnel (je ne sais pas pourquoi - c'est utile) et quelques autres points de terminaison qui seront utilisés pour échanger des données avec la deuxième fonction - RAW -. Ajoutez-les.
Nous rendons le point bidirectionnel en ajoutant le point OUT au descripteur:
Descripteur de configuration.Lors de la modification d'un descripteur, gardez un œil sur les index et les tailles.
(2c5cf968121f0d8fa43a6755c09e15ef3a317791):
0x07, USB_DESC_TYPE_ENDPOINT, HID_EPOUT_ADDR, 0x03, HID_EPOUT_SIZE, 0x00, HID_FS_BINTERVAL,
Et ajoutez quelques points supplémentaires:
Descripteur de configuration(bc2bd583c98715e106fcb3ab07b266bc9221be36):
0x07, USB_DESC_TYPE_ENDPOINT, HID_EPIN_ADDR2, 0x03, HID_EPIN_SIZE, 0x00, HID_FS_BINTERVAL, 0x07, USB_DESC_TYPE_ENDPOINT, HID_EPOUT_ADDR2, 0x03, HID_EPOUT_SIZE, 0x00, HID_FS_BINTERVAL,
C'était un descripteur de configuration. Maintenant, l'hôte sera sûr que nous avons une sorte de périphérique HID composite, et vous pouvez envoyer des données à tous ces points. Mais ce n'est pas le cas.
Pour rendre cela vrai:
1. Notre contrôleur dispose d'une mémoire spécialement allouée qui est synchronisée avec les modules CAN et USB. Étant donné que le module USB est engagé indépendamment dans le processus de réception / transmission d'un paquet de données, vous devez définir des tampons dans cette pièce de mémoire pour chaque point de terminaison individuel:
USBD_LL_Init dans le fichier 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);
Les adresses de tampon sont arbitraires, si seulement elles ne se chevauchent pas.
Pour une raison quelconque, la pile ST est écrite dans l'espoir que le périphérique n'aura pas plus d'un point de terminaison bidirectionnel, nous allons donc modifier un peu la pile:
Transfert
Renommez la procédure USBD_HID_SendReport en USBD_HID_SendReportEP, en ajoutant un paramètre supplémentaire - le numéro du point de terminaison. Nous quittons la procédure avec l'ancien nom pour la compatibilité descendante, mais dans le corps, nous appelons USBD_HID_SendReportEP avec une constante sous la forme d'un point de terminaison. La solution n'est pas encore la plus esthétique, mais elle fonctionnera pour l'expérience, et même si elle reste, elle n'interférera pas avec un projet spécifique.
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); }
Maintenant que tout est prêt pour envoyer des données, il ne reste plus qu'au bon moment pour appeler cette fonction.
Finalisation
Pour des raisons d'ordre, nous recherchons le projet et appelons à nouveau USBD_LL_CloseEP, mais pour les points de terminaison nouvellement créés.
Réception
Pour que les points de terminaison soient moralement réglés pour fonctionner, vous devez appeler USBD_LL_PrepareReceive pour eux. Je recommande au lecteur de parcourir la recherche du projet pour cette ligne, et d'adapter ces appels à vos besoins.
J'ai cette moche seiche dans mon code:
usbd_core.c USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR+(epnum&0x7F)-1 , hhid->Report_buf, USBD_HID_OUTREPORT_BUF_SIZE);
C'est-à-dire Je suis parti du fait que le nombre de points finaux va dans une rangée. C'est mauvais, à mon humble avis. Ne le faites pas. Cependant, ne faites pas non plus comme ST.
Il ne reste plus qu'à accéder au fichier usbd_hid.c, et plus particulièrement à la fonction USBD_HID_DataOut, et de s'assurer que l'appel au gestionnaire de données reçu correspond à vos idées personnelles sur le beau. Je n'ai pas réussi non plus, donc le code et la description seront longs et incompréhensibles. Plus facile à faire vous-même.
Rapport
Tout, à cet endroit, nous avons obtenu un appareil composite capable d'échanger des données via deux points bidirectionnels. Au dernier coup, nous avons «fermé» la curiosité du conducteur HID, décrivant un tel descripteur de rapport:
__ALIGN_BEGIN static uint8_t HID_ReportDesc2[33] __ALIGN_END = { 0x06, 0x00, 0xff,
Ce rapport indique au pilote HID: il y aura environ 31 octets de données. Pas besoin de comprendre ce qu'ils sont - donnez-les simplement au programme qui a ouvert cet appareil. Dans un rapport physique, l'octet zéro sera égal à l'index de rapport (REPORT_ID (2)). En conséquence, un total de 32 octets viendra.
Et entrez les données à ce sujet dans usbd-hid.c, fonction USBD_HID_Setup.:
usbd-hid.c switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: if( req->wValue >> 8 == HID_REPORT_DESC) {
Plus loin dans le programme:
- Assemblage du convertisseur de niveau logique AVC-LAN et connexion à la carte. Analyse de la couche physique d'AVC-LAN, formes d'onde réelles.
- Traitement de l'interface au niveau du contrôleur et envoi de paquets avec des rapports
- Interface de bout en bout et reverse engineering Prius. Package Sniffer (ou ma première application Android)
PS
- J'ai décidé d'écrire un article parce que j'étais (presque) forcé, convaincu que cela devait être partagé. Même si je ne termine pas le projet, certaines des dernières informations peuvent aider quelqu'un, même de manière «brute».
- La critique du projet est la bienvenue, car Je n'imagine pas encore pleinement que cela fonctionnera.
- Critique de l'article, du design, de la présentation - surtout parce que Il s'agit du premier article de la ressource. Avec la poursuite du travail, je voudrais exprimer mes pensées sous la forme habituelle et digestible pour les lecteurs