воскресенье, 23 февраля 2020 г.

"RealPad" DualShock(1,2) gamepad plugin for PCSX2 PS2 emulator

  Написал за несколько вечеров код работы (чтение/конфигурация) с игровыми контроллерами Sega, PlayStation1, PlayStation2 под микроконтроллер STM32F7, высунул данные через USB (HID устройство), можно пользоваться как обычным компьютерным геймпадом.

  Я использовал борд с микроконтроллером серии STM32F7  с сайта одного знакомого "электронщика": https://evaluationboard.ru .  В борде нет ни чего лишнего и имеется всё необходимое. Например, в нём распаян полностью рабочий программатор ST-Link V2 и установлена микросхема FTDI (USB to COM адаптер), оба они припаяны к хабу, от которого идёт наружу "принтерный" USB разъем. Получаем  отладку SWD, UART через 1 кабель и ни каких лишних девайсов/проводов. Остальные плюшки борда можно рассмотреть на сайте, при желании.

  Но этого оказалось недостаточно...

  Когда всё заработало, я подумал: а что если реализовать мечту "детства" и написать немного кода для некогда часто мной используемого эмулятора PlayStation2 "PCSX2"?

  Сделал fork pcsx2 проекта на github, разобравшись (со скрипом, т.к. API очень не интуитивно сделан и не документирован) в API эмулятора, накидал быстро код общения с моим хардварным интерфейсом к геймпадам и назвал проект "RealPad" по аналогии с другими плагинам. "Real" - тут важная часть названия, т.к. подключается настоящий геймпад и по-настоящему читается виртуальной PS2 без дополнительных алгоритмов обработки ввода.

  Это самая простая и самая нативная интеграция геймпада, что может быть ) Любая игра может как угодно пользоваться геймпадом - это и чтение данных ввода (любых, включая силу нажатия кнопок) и конфигурация геймпада и т.п.

  Вот что получилось:


  Ссылка на репозиторий: https://github.com/L-proger/pcsx2/tree/develop/RealPad

  Disclaimer: код пока что сырой, написан в скоростном режиме как proof of concept.  Предстоит его почистить, реализовать правильную выгрузку, поддержку нескольких геймпадов, починить косяк, когда игры не видят контроллер после загрузки быстрого сохранения (F3).  А ещё ввод с клавиатуры не работает, когда используется мой плагин, например, не могу использовать "быстрое сохранение" (F1), придётся разобраться что ещё от меня хочет эмулятор.

  В дальнейшем выложу и прошивку под STM32, как только её в порядок приведу )


среда, 2 октября 2019 г.

Run Stm32CubeMX & STM32CubeProgrammer applications with OpenJDK on Windows

Stm32CubeMX требует наличие установленного OracleJRE/JDK и при его отсутствии в системе ругается, что не может найти JRE версии 1.8.0_45 или выше. Кубу всё равно на то, что у меня в системе есть OpenJDK (ставил разные версии, добавлял в PATH, не помогало) и мне на пару секунд даже показалось, что придётся сдаться и поставить ещё и OracleJRE (чего я очень не хотел), но на самом деле сдаваться рано )

Сначала попробовал изменить требуюмую версию Java в инсталлере куба, но понял, что это не помогает. Потом нашёл и "поставил" именно 1.8.0_45 но OpenJRE а не OracleJRE - всё равно не помогло. Потом нашёл некий интересный путь C:\ProgramData\Oracle\Java\javapath ! В нём лежат 3 симлинка на java.exe, javaw.exe, jawaws.exe.

Тут я решил, что "вот оно", мне надо эти симлинки создать на соответствующие exe файлы из моей версии OpenJRE. И создал. И не помогло ) Куб при установке ругался всё тем же сообщением.

Теперь я решил запустить java.exe через мой симлинк и о чудо, java ругнулась, что в реестре не хватает ветки. Я поставил OracleJDK, экспортнул ветку, удалил OracleJDK, импортнул ветку и подправил пути на свои, вычистив лишние ветки/ключи.

И всё заработало !

Моя версия OpenJDK лежит по такому пути: C:\openjdk-12.0.2

А вот текст .reg файла, которым можно указанный выше путь зарегистрировать в реестре:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\12.0.2]

"JavaHome"="C:\\openjdk-12.0.2"
"RuntimeLib"="C:\\openjdk-12.0.2\\bin\\server\\jvm.dll"
"MicroVersion"="0"
"BuildNumber"="10"


Насчёт необходимости ключей "MicroVersion"="0", "BuildNumber"="10" я не разбирался. Может они не нужны (так выглядит), но OracleJRE их создаёт. Хз, решил, что лучше оставить. Кто знает что в будущем может поломаться из за их отсутствия.


ОБНОВЛЕНИЕ:

STM32CubeProgrammer не захотел работать с хаком, описаным выше. Как оказалось, CubeProgrammer использует JavaFX, которого нет в официальной сборке OpenJDK. Почему-то за преемлимое время мне не удалось установить OpenJFX поверх OpenJDK, потому я пошёл другим путём и скачал OpenJDK сразу собранный вместе с OpenJFX.

Скачать можно вот по этой ссылке:  https://bell-sw.com/pages/java-13/

Архив с этим билдом JDK я распаковал в корень диска C

А вот контент .reg файла, регистрирующего установку этой версии JDK:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JDK]
"CurrentVersion"="13.0.0"

[HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\JDK\10.0.2]
"JavaHome"="C:\\bellsoft-jdk13-windows-amd64\\jdk-13"


Здесь можно заметить, что ветка реестра содержит версию 10.0.2, а не 13.0.0.  Это важно, т.к. по этому имени STM32CubeProgrammer проверяет версию java, которая должна быть 1.8.0 - 10.99.99.  Приходится таким путём обманывать STM32CubeProgrammer, если хочется иметь в системе свежую версию JDK.

понедельник, 2 сентября 2019 г.

Как собирать С++ приложения в Windows C# кодом

Понадобилось тут собрать С++ Qmake приложение под Windows используя cl компилятор из под C# приложения. При этом хотелось не запускать это C# приложение из под VisualStudio comand prompt, а разрулить всё прямо в коде.

Обычно, для сборки приложения в консоли студийным компилятором, необходимо открыть VisualStudio command prompt и делать сборку там, либо вручную вызвать vcvars64.bat или vcvarsall.bat для настройки окружения, но  тут есть 2 проблемы: 1. Как найти этот bat файл, 2. Как его запустить внутри C# приложения так, что бы он правильно настроил environment variables.

Решение:
1. Найти все VisualStudio >= 2017 можно при помощи приложения vswhere, которое ставится с VisualStudio installer
2. Находим VisualStudio при помощи vswhere, находим vcvars64.bat, выполняем bat файл, забирая себе его environment в текстовом виде, парсим и применяем в своё приложение.

//Find vswhere path
var programFilesDir = Environment.GetEnvironmentVariable("ProgramFiles(x86)");
var vsInstallationDir = Path.Combine(programFilesDir, @"Microsoft Visual Studio", "Installer");
var vsWherePath = Path.Combine(vsInstallationDir, "vswhere.exe");

//Find latest VisualStudio installation directory
var vsWhereResult = SystemProcess.Execute(vsWherePath, "-latest -property installationPath");
var vsInstallPath = vsWhereResult.outBuffer[0];

//Import VisualStudio environment
var vsEnvBatchFile = Path.Combine(vsInstallPath, @"VC\Auxiliary\Build\vcvars64.bat");
var vsEnvResult = SystemProcess.Execute("cmd", $"/C \"{vsEnvBatchFile}\" > nul 2>&1 && set");
Regex envVariableRegex = new Regex("^([^=]+)=(.*)");
foreach(var str in vsEnvResult.outBuffer) {
 var match = envVariableRegex.Match(str);
 if (match.Success) {
  System.Environment.SetEnvironmentVariable(match.Groups[1].Value, match.Groups[2].Value);
 }
}
В коде вообще нет ни каких проверок, потестил просто как proof of concept. SystemProcess - мой мини враппер над System.Diagnostics.Process, запускает процесс и возвращает массив строк stdout, stderr и exit code. По хорошему надо делать не совсем так, необходимо применить лишь diff переменных окружения, но в моей задаче это было не нужно. А дальше просто собираем своё Qmake приложение:
//run qmake
SystemProcess.Execute(@"C:\Qt\5.13.0\msvc2019_64_custom\bin\qmake.exe", proFileDir + " -spec win32-msvc \"CONFIG += release\"");
//run nmake
SystemProcess.Execute("nmake");

воскресенье, 6 мая 2018 г.

Попиливаю процедурную генерацию геометрии

  Для всякого моего домашнего прототипирования в Unity часто хочется быстро, "вот прям тут", не переключаясь в другую софтину,  сгенерировать визуализацию какой-нибудь занятной штуковины, например, 2D функции или же 3D объекта. Сейчас вот использую для визуализации линз оптической системы. Чаще всего это нужно "вот прям тут", т.к.  модели параметрические (те же линзы) и на каждое изменение параметров лезть в пакет 3D моделирования и править геометрию - пустая трата времени.

  Использовать готовые решения (даже не искал, знаю только о плагине Houdini для Unity) я, конечно же, не хочу. Так веселее, да и вообще это как отдых ) В большинстве случаев нода процессинга геометрии пишется просто и потому процесс не напряжен, а результат радует.

  Сегодня почти допилил L-System, стараясь косить под Houdini )


  Осталось немного доделать Context matching.

  А вот и хорошая книга по L-системам: The algorithmic beauty of plants






понедельник, 22 января 2018 г.

PSY-Q SDK (Sony PlayStation1 SDK) на Windows 10 x64

Для тех, кто уже попробовал запускать программы из PSY-Q SDK, понятно, что этот древний софт ещё не мало проблем принесёт.

На удивление, компилятор ccpsx оказался 32-битным и спокойно работает в Windows10 x64, чего не скажешь о cpe2x.exe (конвертер .cpe в .exe) и psymake.exe (аналог make), они 16 битные, написаны под DOS, а в Windows x64 NTVDM выпилен, потому приложения запустить невозможно. Видел я, конечно, порты NTVDM под x64, но там встраивание в систему идёт через заднее место и мне это не нравится, тем более они все с жирными пометками "proof of concept".

Но кто сказал, что это конец? psymake как бы можно вообще выкинуть, заменить его обычным make, например из MinGW!  Я решил ради любви к прекрасному оставить таки имя этой утилиты таким, какое оно есть, потому переименовал PSYMAKE.EXE в _PSYMAKE.EXE, вдруг пригодится, а так же вместо него запилил BAT файл PSYMAKE.BAT
@echo off
"C:\Program Files\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin\mingw32-make.exe" %*

Теперь при вызове psymake на самом деле перевызывается mingw32-make.exe и всё параметры ему передаются через %*
А вот с cpe2x всё немного сложнее. Я видел его порт под x64, не из оригинальных исходников, а с нуля написанный. И снова у него были какие-то проблемы. Не тру это всё. Есть же рабочее решение, его просто нужно запустить...

DosBOX - вот кто придёт на помощь. Заменяем CPE2X.EXE на CPE2X.BAT вот примерно с таким контентом
@echo off
SET PSYQ_PATH=D:\L\PSOne\psyq
SET DOSBOX_EXE="C:\Program Files (x86)\DOSBox-0.74\DOSBox.exe"
SET SDL_VIDEODRIVER=dummy
REM cleanup CPE2X.EXE stdout file
copy /Y nul: CPE2XOUT.TXT > nul
REM execute CPE2X.EXE inside DOSBOX
%DOSBOX_EXE% -noconsole -c "MOUNT D 'D:\'" -c "D:" -c "cd %cd%" -c "%PSYQ_PATH%\bin\_CPE2X.EXE %* > CPE2XOUT.TXT" -c exit
REM print CPE2X.EXE stdout to console
type CPE2XOUT.TXT

Я тут свои реальные пути в системе оставил, ну да ладно.
Что там происходит:

1.
SET SDL_VIDEODRIVER=dummy
- т.к. DOSBOX написан с использованием SDL, то есть такой вот легальный путь запустить dosbox в headless режиме!

2.
copy /Y nul: CPE2XOUT.TXT > nul
- тут генерится/очищается файл, который будет содержать в себе выхлоп реального cpe2x.exe, нам же надо всё красиво сделать!

3. Вызываем DOSBOX!  Я монтирую реальный диск D в диск D внутри DOSBOX, так проще работать с путями. Потом переход в папку проекта: -c "cd %cd%"  тут важное уточнение: cd указывает на папку проекта, ибо я из неё запускаю данную команду, о том как это делается - напишу ниже. Дальше идёт запуск реального приложения
"%PSYQ_PATH%\bin\_CPE2X.EXE %* > CPE2XOUT.TXT"
с перенаправлением вывода в файл, чтоб потом этот файл запринтить хостовому приложению для красоты, типа я запустил настоящее приложение и увидел вывод.

4. Ну и принтим  в консоль вывод
type CPE2XOUT.TXT

С SDK вроде всё.

Далее внутри проекта прям рядом с сорцами и мейкфайлом я создаю ещё 1 bat файл build_console.bat
start "PSX Build Console" call "D:\L\PSOne\psyq\PSPATHS.BAT"
Он мне настраивает пути psy-q и оставляет окно консоли в котором я могу билдить проект! Это удобно!
Внутри окна консоли я просто вбиваю psymake и происходит магия! Всё отлично собирается и даже не видно, что я запускал dosbox!
Вот мой тестовый Makefile
.PHONY: all

all:main.c
  ccpsx -O3 -Xo$80010000 main.c -omain.cpe,main.sym,mem.map
  cpe2x main.cpe
После запуска psymake в этой консоли получаем вот такой красивый вывод:
D:\L\PSOne\projects\PS1Dev>psymake
ccpsx -O3 -Xo0010000 main.c -omain.cpe,main.sym,mem.map
cpe2x main.cpe
CPE2X Ver1.5
Copyright (C) 1994,1995 by Sony Computer Entertainment Inc.
convert from main.cpe to main.EXE for Japan area
pc0:0000881c  t_addr:00002710  t_size:00008800

понедельник, 8 января 2018 г.

Ретро задротство: запилил диски для PlayStation 1

Еле нашёл нормальные Jewel box-ы для дисков в Воронеже (не удивительно, время дисков уже прошло)! Китайцы же вообще обалдели, продают по цене от 140р за ОДНУ коробку!!! Ну да ладно, это как с биткоинами - главное вовремя закупиться ) Ах да, купил я эти коробки в классном магазинчике "Темп" на Плехановской, вот: https://goo.gl/maps/MUTooGEchcH2




Потом разобрался с размерами печати, запилил разметку в фотошопе и нагенерил кучу обложек, распечатал, вырезал, вставил в  диски и вот...



И вот




И вот




Сделал те же диски, что когда-то раньше и были у меня, но давно утеряны.

Ретро задротство: пишем простое приложение для PlayStation 1

Наконец дошли руки и я таки выполнил одно из древних желаний - написал хоть какой-то рабочий код для PlayStation1 !!

Буду иногда тут исследовать PS1 SDK (Psy-Q) https://github.com/L-proger/PS1Dev

Понял как выводится дефолтный текст (шрифт грузится из BIOS-а), очищается экран (можно просто очистить через GsClearDispArea или закинуть вместе с другими задачами через GsSortClear).

Курить ещё много чего надо, документация в SDK очень корявая и конечно же ни каких примеров в ней, благо есть демки в интернете, в них можно подсмотреть код )

Нашёл ещё крутейший эмулятор, no$psx:  http://problemkaputt.de/psx.htm  Он единственный (из всех что я видел) имеет дебаггер с breakpoint-ами и главное (для меня) умеет выводить в окно результат printf!!!  Дада, в ps1 был дебаг порт куда можно было принтить.

А вот и скрин (собрал диск .iso, запустил в эмуляторе, прожигать на болванку пока лень).





Если не извращаться и юзать всё как есть в SDK, то необходимо поставить Windows x86 (обязательно, в x64 не запускаются тулзы из SDK), не новее Windows 7.  Собственно, я и поставил Windows7 x86 в виртуалку, в ней и делаю сборку. Однако, программирую в своей хостовой OS Windows 10 в VisualStudio.  Открываю проект-папку, в json прописаны пути инклудов и вуаля,  годная IDE, комплит и OS в виртуалке только ради сборки.

понедельник, 25 сентября 2017 г.

STM32 HAL_SPI_TransmitReceive_DMA restart bug

  Захотелось мне перезапустить трансфер SPI прямо в колбэке HAL_SPI_TxRxCpltCallback. Казалось бы, из названия колбэка ясно, что вызывается он, когда и Tx и Rx полностью завершены и нет причин, почему в этом же колбэке нельзя запустить новый трансфер.

  А вот и есть: рукожопость.  Если внутри HAL_SPI_TxRxCpltCallback снова вызвать HAL_SPI_TransmitReceive_DMA, то трансфер никогда не завершится.

  А вот почему? Изначально не понятно, я же хорошо написал код, захендлил все Error code-ы библиотеки и если что-то не так, то я бы увидел в терминале ошибку и код автоматом бы мне вызвал breakpoint. Но всё вроде как ок, ошибок нет!

  Проверил под дебаггером - да,  HAL_SPI_TransmitReceive_DMA во второй раз возвращает HAL_OK! Статусы/регистры все сконфигурены корректно в SPI, стейт BUSY но прерываний нет... о_О

  Но не стоит недооценивать разработчиков HAL библиотеки, они те ещё рукожопы. Вспомнил я как несколько лет назад писал им в саппорт и уведомлял о баге, но конечно же его не починили )

Часть кода функции HAL_SPI_TransmitReceive_DMA:

/* Set the DMA AbortCpltCallback */
hspi->hdmarx->XferAbortCallback = NULL;
/* Enable the Rx DMA Stream/Channel  */
HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)hspi->pRxBuffPtr, hspi->RxXferCount);
/* Enable Rx DMA Request */
SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN);


  HAL_DMA_Start_IT возвращает код ошибки, который благополучно игнорируется! И кажется, что всё ОК )) А на самом деле HAL_SPI_TxRxCpltCallback  вызывается из прерывания RX DMA канала, а обработчик TX канала ещё не вызывался к этому моменту (он вызовется после RX канала).  И получается, что в колбэке RX DMA канала я перезапускаю передачу, которая не смогла запустить TX DMA канал  (он ещё не разлочен своим обработчиком прерывания) и потому всё висит.

  Это восхитительно.  Мало того, что TX прерывания ещё не было, но уже вызвался HAL_SPI_TxRxCpltCallback , так ещё и коды ошибок нагло игнорируются, вводя в глубочайшее заблуждение. Вот как так?  Железо у ST отличное, а код - говно...