======PyComPort программа на Python и драйвер UART_CLI через DMA====== Это краткое описание примера [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/PACK_Gen/Files/Examples/All_Boards/UART_CLI_Test|UART_CLI_Test]], в котором тестируется драйвер UART_CLI. В примере переключаются светодиоды по командам с компьютера, которые передаются программой-терминалом [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/Utils/pyComPort|pyComPort]] через UART в микроконтроллер. UART работает через DMA на прием и передачу для снижения нагрузки ядра. Терминал реализован на Python с использованием компонентов QT, предоставляемых проектом PySide2. Выбор обусловлен, [[https://ru.wikipedia.org/wiki/PySide|Википедия]]: PySide — привязка языка Python к инструментарию Qt, совместимая на уровне API с PyQt. В отличие от PyQt, PySide доступна для **свободного использования как в открытых, так и закрытых, в частности, коммерческих проектах**, поскольку лицензирована по **LGPL**. Кроме этого Python позволяет налету менять функционал программы, без необходимости пересобирать exe, подключать библиотеки и прочее и прочее. Это позволяет адаптировать терминал к различным потребностям в разных проектах работающих через UART. Да и в целом, Питон - это очень комфортная и простая экосистема для разработки. Использование компонентов Qt дает надежду, что тот же самый терминал заработает и на Linux. =====Краткая справка по реализации GUI для Python c PySide===== Это вариант под Windows, под Linux должно быть аналогично. - Установка Python - https://www.python.org/downloads/ * Скачать, установить: * выбрать "Add Python 3.8 to PATH", чтобы Питон был доступен из командной строки * {{python:pythonsetup_1.png}} * выбрать режим инсталляции Custom, оставить все галки активными. * {{python:pythonsetup_2.png}} * выбрать "Install for All Users" , при этом станет активна опция "Precompile standard library" * путь выбрать покороче, и чтобы доступ был без прав администратора. Например, "C:\Python38-32". * {{python:pythonsetup_3.png}} - Установить pySide2 * в окне Cmd(Win7) или PowerShell(Win10): > pip install PySide2 * (Опционально: обновить pip, если warning говорит, что есть новая версия): > python -m pip install --upgrade pip - Реализовать дизайн ui в QtDesigner, который находится здесь C:\Python38-32\Lib\site-packages\PySide2 * запускаем designer.exe * {{python:pyside2_qtdesignernew.png}} * дизайним форму * {{python:pyside2_qtdesign.png}} * сохраняем в папке проекта, где будем делать приложение. Например, MDR_Pack\Utils\pyComPort\PyComPort.ui. * {{python:pyside2_qt_save.png}} - Конвертируем дизайн из файла pyComPort.ui в питоновский формат pyComPort.py * в окне Cmd(Win7) или PowerShell(Win10): * переходим в директорию с pyComPort.ui: > cd C:\CODE\PACK\MDR_Pack\Utils * конвертируем: > pyside2-uic "PyComPort.ui" -o "PyComPort_ui.py" * в директории проекта появился файл PyComPort_ui.py - Пишем программу на Python для данного GUI. - Для COM порта необходимо поставить библиотеку: > pip install pyserial Полезные ссылки - примеры: * [[https://habr.com/ru/post/458536/|Habr: Python + Pyside2 или просто «Калькулятор»]] * [[https://www.youtube.com/watch?v=cK-hvG-Q9B0|YouTube: Как в Python писать программы с интерфейсом?]] * [[https://habr.com/ru/post/443326/|Habr: Python & Arduino. Просто, быстро и красиво]] Документация: * [[https://pythonhosted.org/pyserial/shortintro.html|pySerial]] * [[https://srinikom.github.io/pyside-docs/PySide/QtGui/index.html|Компоненты Qt]] Код программы на GitHub: [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/Utils/pyComPort|pyComPort]] ===== Драйвер UART_CLI ===== Иногда возникает необходимость поуправлять чем-нибудь с РС через COM-порт. Чтобы не писать каждый раз реализацию такой работы по UART, был реализован унифицированный драйвер, который в составе библиотеки MDR_Pack_V6 назван MDR_UART_CLI. В библиотеке уже есть подобный пример [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/PACK_Gen/Files/Examples/misc/UART_Commands|Пример приема команд по UART]], но потребовалось создать что-то менее ресурсоемкое и более масштабируемое. Поэтому в данном драйвере для передачи данных используется DMA. {{python:mdr_uart_cli.png}} Протокол обмена написан так, что обмен инициализирует всегда только мастер - РС. Он запускает на исполнение команду с набором параметров и ждет ответа-подтверждения от МК. Таким образом, обмен работает только как вопрос-ответ. UART микроконтроллера принимает и передает данные через DMA в блочном режиме (BReq). Первые два байта составляют заголовок. В этих байтах передается количество байт в данном сообщении (10 бит) и команда (6 бит). Эти поля позволяют завести 64 команды для управления и передавать для команды до 1023 параметров. Если длина сообщения имеет четное количество, то досылается дополнительный служебный нечетный байт. Этот байт необходим чтобы сработало событие Uart_TimeoutRx, по которому отслеживается окончание приема сообщения от РС. (Это последнее слово вычитывается DMA по SReq.) Прерывания по таймауту приема могут срабатывать несколько раз по мере передачи USB адаптером всего сообщения. Окончание приема сообщения отслеживается по сравнению длины в заголовке и фактически принятым количеством байт. Чтобы не тратить время на вход-выход в прерывание, наличие флага события Uart_TimeoutRx проверяется в функции запроса активной команды - MDR_CLI_GetCommand(). CLI_CMD_e MDR_CLI_GetCommand(uint8_t *lenAckParams, uint8_t **pCmdParams) Команда из заголовка возвращается как значение из перечисления CLI_CMD_e, которое должно быть задано в файле MDR_Config.h. Параметры к команде и их количество возвращаются в аргументах функции. Для экономии памяти и сохранения быстродействия, функция передает ссылку на внутренний DMA-буфер с принятыми данными, откуда начинаются параметры (т.е. начиная с InpData[2], т.к. первые два байта заняты заголовком.) Если длина в заголовке разошлась с фактической длиной сообщения, или если код команды не входит в перечисление CLI_CMD_e, то функция возвращает команду cliCMD_ERROR. Пользовательское приложение, которое использует драйвер UAR_CLI само должно решить, что делать в таком случае с данными. В примере ниже, в случае cliCMD_ERROR просто отсылаются обратно в РС, реализуя таким образом режим это (ECHO). На примере реализации управления светодиодами были добавлены следующие пользовательские команды: typedef enum { // Системные команды, зарезервированы cliCMD_NONE = 0, cliCMD_ERROR = 1, // Команды задаваемые пользователем под конкретный проект // В данном случае - это управление светодиодами и эхо cliCMD_LedShow, cliCMD_LedHide, cliCMD_LedOut, cliCMD_Echo, // Not for use - количество команд cliCMD_LEN } CLI_CMD_e; Если функция MDR_CLI_GetCommand() возвращает cliCMD_NONE, то это значит, что команд от РС не поступало, обрабатывать нечего. На каждую пришедшую команду от MDR_CLI_GetCommand() необходимо послать ответ функцией void MDR_CLI_SetResponse(CLI_CMD_e cmd, uint8_t lenAckParams); В поле cmd необходимо передать команду, на которую выдается ответ. А так-же задается количество данных в ответе. Сами данные ответа предлагается сразу писать в выходной буфер DMA, ссылку на который можно получить через вызов функции MDR_CLI_GetResponceBuf() аргумент pAckBuf. Размер буфера под параметры возвращается функцией. uint16_t MDR_CLI_GetResponceBuf(uint8_t **pAckBuf); Типовой цикл обработки команд: CLI_CMD_e cliCMD; uint8_t cliParamLen; uint8_t *pCliParams; while (1) { cliCMD = MDR_CLI_GetCommand(&cliParamLen, &pCliParams); switch (cliCMD) { case cliCMD_NONE: break; case cliCMD_LedShow: ... обработка команды MDR_CLI_SetResponse(cliCMD, 0); break; case cliCMD_LedHide: ... обработка команды MDR_CLI_SetResponse(cliCMD, 0); break; case cliCMD_LedOut: ... обработка команды MDR_CLI_SetResponse(cliCMD, 0); break; case cliCMD_Echo: case cliCMD_ERROR: default: // Send Echo MDR_CLI_SetResponse(cliCMD, cliParamLen); } } =====Проверка UART_CLI в связке с PyComPort===== Для проверки работы драйвера UART_CLI и терминала PyComPort была реализована программа [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/PACK_Gen/Files/Examples/All_Boards/UART_CLI_Test|UART_CLI_Test]] входящая в состав примеров MMR_Pack_v6. Пример проверялся на отладочной плате 1986ВЦ1Т при подключении к РС через USB COM-адаптер. Последовательность действий для запуска примера: * Установить Python и все библиотеки которые упоминались в разделе выше про питон. * Отладку подключить к РС (обычно через USB COM-адаптер) * Скачать проект [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/Utils/pyComPort|pyComPort]] * Терминал PyComPort запускается из командной строки из директории pyComPort: python PyComPort.py * Выбрать в терминале свой COM порт, если он не выбрался по умолчанию. Нажать Connect. * Проект [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/PACK_Gen/Files/Examples/All_Boards/UART_CLI_Test|UART_CLI_Test]] скомпилировать и прошить в МК Для управления светодиодами посылаем через питоновский терминал команды: {{python:pycomport_hdrlen.png}} На отладочной плате наблюдаем переключение светодиодов. =====Итого===== - В данной статье кратко дана инструкция для реализации GUI для Python через компоненты Qt (PySide2) - Разработка GUI не описана, для этого лучше смотреть видео по Qt на YouTube - Представлен унифицированный драйвер UART_CLI работающий через DMA. - Драйвер может использоваться в проектах для реализации управления от РС через COM-port. - Драйвер реализован в библиотеке под Keil - [[https://github.com/StartMilandr/MDR_Pack_v6|MDR_Pack_V6]] - Поддержка протокола с длиной сообщения и командой в заголовке реализована в программе-терминале [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/Utils/pyComPort|pyComPort]] - и опробована на проекте мигания светодиодами [[https://github.com/StartMilandr/MDR_Pack_v6/tree/master/PACK_Gen/Files/Examples/All_Boards/UART_CLI_Test|UART_CLI_Test]] Большой плюс в использовании Python в том, что протокол обмена можно поменять в любой момент. Например, можно ввести расчет CRC. Достаточно поправить один текстовый файл и не надо связываться с проприетарными IDE с замороченными лицензиями на использование. Но это наше первое знакомство с Python и возможно работа с потоками реализована не достаточно грамотно. Проект будет обновляться по мере освоения Python.