
Este es el primer artículo (introductorio) de la serie sobre cómo voy a refinar el sistema de medios del automóvil. El proyecto en sí está en proceso, no hay tiempo, como todos los demás, por lo tanto, queridos lectores, tengan paciencia, porque a menudo no prometo remachar artículos.
Todo comenzó con el hecho de que tenía un Prius.
Y lo primero que me llamó la atención fueron los problemas con la actualización de la navegación. Los siguientes son muy escasos, pero en algunos lugares las características necesarias de un dispositivo llamado "Pantalla multifunción" (en personas comunes: la cabeza). Y esto está en el contexto de una gran cantidad de radios chinas con Android a bordo y muchas comodidades. Pero su instalación en un lugar regular implica la privación de tales "bollos" como un diagrama de la distribución de energía y control climático.
La idea nació para conectar de alguna manera la radio de Android con el automóvil más de lo que sugieren los hermanos chinos. Sobre esto y el artículo.
Situación inicial
Entonces A bordo hay una pantalla de 7 pulgadas con una pantalla táctil resistiva, conectada a otros dispositivos electrónicos con líneas TX + y TX-. Y ya hay 3 de esos pares de la cabeza. En el circuito, este milagro se llama AVC-LAN, y se ve así:

Parte 1: mirar alrededor
Como puede ver, la cabeza está en la brecha de la red, entre el enrutador y la cadena adicional de la radio, el amplificador (lo tengo por separado), y una conexión a la unidad de navegación sigue un canal separado. En otro lugar, una unidad de estacionamiento de automóviles está colgando, no mencionada de ninguna manera en mis esquemas. Bueno, bueno ... decidí posponer la proximidad con él hasta tiempos mejores. Además, el estacionamiento es más una función del juego que una necesidad real.
Después de eliminar todo lo innecesario, obtenemos aproximadamente el siguiente diagrama de bloques de los dispositivos:

Reflexiones
Hubo una idea de simplemente reemplazar la unidad de navegación con algo Android, pero se extinguió cuando entendí más profundamente cómo se comunican con la cabeza. Además de AVC-LAN, estos módulos también están conectados por la línea GVIF (Gigabit Video InterFace), y esta misma cara de los fabricantes de convertidores puede romperse accidentalmente si también compro un convertidor de señal de video en GVIF por más de $ 100. "Vivir sin una cara es ser puede ser difícil, pero ... "- sonó en mi cabeza por el motivo de una canción famosa, y no me gustó la decisión.
Hubo soluciones en la red con la instalación de una radio china en lugar de un receptor de radio. Esto no me convenía porque las dos pantallas son redundancia irrazonable. En mi humilde opinión.
Solución
Nació la siguiente solución: reemplazar la cabeza completa y finalizar la radio de Android, haciendo amigos con el Prius, para lo cual:
- Diseño de convertidor de hardware USB <-> AVC-LAN
- Desarrolle firmware para que se conecte como un USB-HID.
- Hágalo compuesto para que una de las funciones se detecte como un teclado de hardware normal (para usarlo como control nativo desde los botones del panel)
- Desarrolle una aplicación de Android con una funcionalidad similar (o superior) a la nativa, Priusovsky
- Alinee la cámara trasera.
- Resolver problemas en la parte mecánica (instalación en un lugar regular)
En el proceso, será necesario desarrollar otra aplicación para Android: un sniffer ordinario, para que sea más conveniente revertir paquetes en AVC-LAN. Al mismo tiempo y práctica.
Debería verse así:

Como base de hardware, se decidió utilizar una tabla de entrenamiento en el SM32F103:

Pedido con AliExpress por $ 2.05.
O busque - spoilerQuizás el vendedor ya haya eliminado el lote, así que le doy la cadena mágica para buscar en Ali:
STM32F103C8T6 ARM STM32 Módulo mínimo de placa de desarrollo del sistema
Lo que me gusta de ella:
- Módulo de hardware USB (dispositivo) a bordo del procesador
- Pila USB adecuada del fabricante (a diferencia del Freescale-ovsky, no se recuerda por la noche).
- Puertos GPIO gratuitos que se pueden usar para conectar botones normales a los lados del monitor. Quizás esto ocultará los botones de hardware de la radio debajo del panel. No sé lo que ella será
- Y en él puedes colgar el convertidor AVC-LAN en niveles lógicos
Describiré más adelante en el orden de implementación, que se debe, en primer lugar, a mi conocimiento personal. Es decir Traté de darme cuenta de los lugares en los que no estaban al principio, al final dejando lo que ciertamente debería suceder.
En cualquier caso, se planean varios artículos en diferentes centros. El proyecto resulta ser mucho FullStack, desde la conexión de hardware hasta la aplicación de Android.
Parte 2: USB, HID, descriptores y todo para obtener un prototipo piloto
El primer paso era obtener un montón de dispositivos y teléfonos, y para que el dispositivo pudiera transferir el paquete al teléfono, y eso, para mostrarlo en la aplicación.
Como dijo Gagarin: ¡Vamos!
Dispositivo compuesto USB HID en STM32
Lo que decidí hacer fue adaptar el ejemplo ST de mis tareas y obtener un dispositivo USB que el host reconozca como parte del teclado y "otra cosa": el dispositivo HID RAW. El primero, como ya dije, está destinado al control nativo de Android, el segundo, para el intercambio directo de paquetes AVC-LAN con el programa en el dispositivo.
Basado en CubeMX de STM, y después de leer muchos artículos sobre cómo implementar HID personalizado, encontré una cosa desagradable en la red: el problema de la creación de dispositivos compuestos está prácticamente ausente o es muy escaso.
Los códigos fuente serán más tardeTodavía no subo los códigos fuente debido al hecho de que el proyecto ahora se está implementando en un modo de capacitación experimental. Si el proyecto se completa con éxito, asegúrese de arrastrarlos a Github y editar el artículo con un enlace a ellos.
En la forma en que se encuentran, no tiene sentido cargarlos: hay suficiente desorden en Internet sin mí.
USB, compuesto, HID
Solo unas pocas palabras sobre este tema. Se supone que está más o menos familiarizado con el estándar USB. Si no, es mejor familiarizarse primero y experimentar con ejemplos de CubeMX.
Entonces tenemos:
Ejemplo de implementación de pila y mouse USB STM. Allí hemos configurado algunos descriptores y un punto final funcional. Esto se suma a un par de 0x00 y 0x80 para controlar todo el dispositivo.
Para implementar mi proyecto, necesito que el punto final del teclado sea bidireccional (no sé por qué, es útil) y un par de puntos finales que se usarán para intercambiar datos con la segunda función, RAW. Añádelos.
Hacemos el punto bidireccional agregando el punto OUT al descriptor:
Descriptor de configuración.Al editar un descriptor, vigile los índices y tamaños.
(2c5cf968121f0d8fa43a6755c09e15ef3a317791):
0x07, USB_DESC_TYPE_ENDPOINT, HID_EPOUT_ADDR, 0x03, HID_EPOUT_SIZE, 0x00, HID_FS_BINTERVAL,
Y agregue un par de puntos más:
Descriptor de configuración(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,
Era un descriptor de configuración. Ahora el host estará seguro de que tenemos algún tipo de dispositivo HID compuesto, y puede enviar datos a todos estos puntos. Pero esto no es así.
Para hacer esto verdad:
1. Nuestro controlador tiene una pieza de memoria especialmente asignada que se sincroniza con módulos CAN y USB. Dado que el módulo USB participa de forma independiente en el proceso de recepción / transmisión de un paquete de datos, debe establecer almacenamientos intermedios en este fragmento de memoria para cada punto final individual:
USBD_LL_Init en el archivo 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);
Las direcciones de búfer son arbitrarias, si no se superponen.
Por alguna razón, la pila ST se escribe con la expectativa de que el dispositivo no tendrá más de un punto final bidireccional, por lo que modificaremos un poco la pila:
Transferencia
Cambie el nombre del procedimiento USBD_HID_SendReport a USBD_HID_SendReportEP, agregando un parámetro más: el número de punto final. Dejamos el procedimiento con el nombre anterior por compatibilidad con versiones anteriores, pero en el cuerpo llamamos USBD_HID_SendReportEP con una constante en forma de punto final. La solución aún no es la más estética, pero funcionará para el experimento, e incluso si permanece, no interferirá con un proyecto específico.
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); }
Ahora todo está listo para enviar datos, solo queda en el momento adecuado para llamar a esta función.
Finalizacion
En aras del orden, buscamos el proyecto y llamamos nuevamente a USBD_LL_CloseEP, pero para los puntos finales recién creados.
Recepción
Para que los puntos finales estén moralmente ajustados para funcionar, debe llamar a USBD_LL_PrepareReceive para ellos. Recomiendo al lector que revise la búsqueda del proyecto para esta línea y que adapte estas llamadas a sus necesidades.
Tengo esta sepia fea en mi código:
usbd_core.c USBD_LL_PrepareReceive(pdev, HID_EPOUT_ADDR+(epnum&0x7F)-1 , hhid->Report_buf, USBD_HID_OUTREPORT_BUF_SIZE);
Es decir Procedí del hecho de que los números de puntos finales van en una fila. Esto es malo, en mi humilde opinión. No lo hagas. Sin embargo, tampoco me gusta ST.
Todo lo que queda es ir al archivo usbd_hid.c, y específicamente a la función USBD_HID_DataOut, y asegurarse de que la llamada al controlador de datos recibido coincida con sus ideas personales sobre la belleza. No tuve éxito también, por lo que el código y la descripción serán largos e incomprensibles. Más fácil hacerlo tú mismo.
Informe
Todo, en este lugar tenemos un dispositivo compuesto que es capaz de intercambiar datos a través de dos puntos bidireccionales. En el último golpe, "callamos" la curiosidad del controlador HID, describiendo tal descriptor de informe:
__ALIGN_BEGIN static uint8_t HID_ReportDesc2[33] __ALIGN_END = { 0x06, 0x00, 0xff,
Este informe le dice al controlador HID: habrá unos 31 bytes de datos. No es necesario que descubras cuáles son, solo dáselos al programa que abrió este dispositivo. En un informe físico, el byte cero será igual al índice del informe (REPORT_ID (2)). En consecuencia, vendrá un total de 32 bytes.
E ingrese los datos al respecto en usbd-hid.c, función USBD_HID_Setup.:
usbd-hid.c switch (req->bRequest) { case USB_REQ_GET_DESCRIPTOR: if( req->wValue >> 8 == HID_REPORT_DESC) {
Más adelante en el programa:
- Montaje del convertidor de nivel lógico AVC-LAN y conexión a la placa. Análisis de la capa física de AVC-LAN, formas de onda reales.
- Procesando la interfaz a nivel del controlador y enviando paquetes con informes
- Interfaz de extremo a extremo e ingeniería inversa Prius. Sniffer de paquete (o mi primera aplicación de Android)
PS
- Decidí escribir un artículo porque me forzaron (casi), convenciéndome de que esto debería ser compartido. Incluso si no termino el proyecto, parte de la información más reciente puede ayudar a alguien, incluso de una manera "en bruto".
- Las críticas al proyecto son bienvenidas, ya que Yo mismo todavía no imagino completamente que funcionará.
- Críticas al artículo, diseño, presentación, especialmente porque Este es el primer artículo para el recurso. Con la continuación del trabajo, me gustaría expresar mis pensamientos en la forma habitual y digerible para los lectores.