Oryginalne oprogramowanie mikrokontrolera PIC interfejsu Eiffel ma przypadłość taką, że niestety w niektórych grach nie działa fire joysticka podpiętego pod port 1 joysticka.
Problem jest dość szeroki, bo dotyczy wielu gier i to raczej dobrych i ważnych, np.:
- Gods
- Prehistorik
- Dizzy Yolkfolk
- Fred
Pewnie więcej jest takich gier, ale to przykłady pierwsze z brzegu.
Podobnie nie działa fire joysticka w programie testującym joystick i mysz od P.Putnika i jest tu ta sama sytuacja.
Zauważyłem, że we wszystkich tych przypadkach gdzie nie działa fire, działa jako fire prawy przycisk myszy.
W oryginalnym Atari prawy przycisk myszy (port 0) i przycisk fire joysticka (port 1) to fizycznie jest to samo, bo linie te są połączone.
W przypadku Eiffla nie mamy fizycznego połączenia tych dwóch rzeczy, bo mysz jest PS/2, a joystick ma swój własny port.
Problem wynika z tego, że w Atari odczyt danych joysticków, myszy i przycisków można robić na kilka sposobów. Odpowiada za to interfejs IKBD, który znajduje się w oryginalnej klawiaturze Atari i obsługuje zarówno klawiaturę, mysz i joysticki. Odczyt przycisku fire jak zauważyłem autorzy gier robią z wykorzystaniem różnych funkcji interfejsu IKBD i czasem odczytują się stany joyów razem z przyciskami, czasem osobno kierunki i osobno przyciski, czasem przycisk jako przycisk myszy itd., a tych procedur odczytu jest kilka różnych.
Emulacja interfejsu IKBD stworzona w Eifflu odczytuje przycisk joysticka tylko w wypadku kiedy jest to faktycznie fizycznie przycisk joysticka, a myszy gdy mamy takie dane z PS/2.
Wymyśliłem więc najpierw, że skoro prawy przycisk myszy działa jako fire w grach, to trzeba po naciśnięciu fire dodać go do przycisku myszy.
Pierwsze próby zrobiłem tak, że wstrzyknąłem się w kod obsługi PS/2 i tam dodałem ten fire podczas wciśnięcia przycisku. To zadziałało, ale fire działał tylko jeśli w tym samym czasie szła jakaś faktyczna transmisja danych z myszy, żeby było do czego ten fire dodać. Takie rozwiązanie było o tyle dobre, że to były tylko dwie instrukcje, a dokładnie tyle wolnej pamięci na kod zostało w PIC-u. Jednak trudno wyobrazić sobie granie w gry i jednoczesne szuranie cały czas nogą myszką, żeby cały czas szła jakaś transmisja do której będziemy dodawać przycisk fire:-)
Dlatego wymyśliłem, że fire trzeba wysyłać bezpośrednio po stronie transmisji danych do Atari i po prostu wysłać fake-dane myszy.
Mój kod działa tak, że jest uruchamiany w miejscu gdzie wysyłane są dane joysticka do Atari, bezpośrednio przed tymi danymi. Jeśli przycisk fire jest wciskany lub puszczany, to mój kod wyśle transmisję danych od fejkowej myszy, w których to danych zapisane jest wciśnięcie (lub puszczenie) prawego przycisku myszy oraz brak ruchu myszy, czyli dwa zerowe bajty dla kompletności transmisji.
W kodzie źródłowym Eiffla w procedurze zaczynającej się od etykiety SendAtariJoysticks dodałem swój kod (są to linie w pliku źródłowym od 1867 do 1881).
Kod ten sprawdza czy włączona jest obsługa myszy (konieczne, bo jak Atari wyłączyło całkowicie mysz, to nie spodziewa się danych od myszy, więc jak się takie dane pojawiają, to występują błędy).
Jeżeli mysz wyłączono, to następuje przeskok mojego kodu i nie wykonuje się nic. Jeżeli natomiast mysz jest włączona, to można dokonać transmisji fejkowych danych.
Dane fejkowe to trzy bajty: pierwszy nagłówkowy zawiera informacje że to dane od myszy i tam też stan prawego przycisku myszy. Dwa kolejne bajty są zerowe i oznaczają ruch myszy w osi x i y.
Poniżej ten mój fragment kodu, który tu opisuję:
;-----------------------------------------------------------------------------
; BEGIN Fake mouse data (right mouse button) - added by Mq (2023-10-07)
btfss Flags,MOUSE_ENABLE
goto Not_Fake_Mouse_Data; no authorization from Atari
movlw 0xF9; joy1 fire pressed
btfss JOY1,4
movlw 0xF8; joy1 fire released
call SerialTransmit_Host
movlw 0
call SerialTransmit_Host
movlw 0
call SerialTransmit_Host
Not_Fake_Mouse_Data
; END Fake mouse data
;-----------------------------------------------------------------------------
I to załatwia temat. Przetestowałem na około 30 grach, wymienione wyżej gry zachowują się poprawnie, program testowy P.Putnika też działa poprawnie.
Jest tylko jeden jeszcze szkopuł. Otóż, żeby to dodać, musiałem wyłączyć obsługę wyświetlacza LCD, a więc wersja firmware, którą tu prezentuję nie będzie wyświetlała nic na wyświetlaczu LCD jeśli ktoś ma taką wersję interfejsu Eiffel. Zrobiłem tak dlatego, że w pamięci na kod Eiffla zostało miejsce tylko na dwie instrukcje. Eiffel ma na początku kodu w liniach od 130 do 140 kilka flag dotyczących kompilacji, które pozwalają wyłączyć część kodu odpowiedzialną za niektóre funkcjonalności Eiffla. Ponieważ mój Eiffel nie posiada wyświetlacza LCD i nie przewiduję go używać, więc najprościej było zmienić jedną wartość odpowiedzialną za LCD z 1 na 0, co wyłącza całkowicie obsługę wyświetlacza LCD, za to zwalnia miejsce w pamięci na dodatkowy kod, który dopisałem, żeby obejść problem niedziałającego fire.
Tak na prawdę w PIC-u jest jeszcze miejsce, z tym że pamięć tego układu jest bankowana i żeby użyć pamięci wolnej w innych bankach, trzeba by pozmieniać trochę więcej w kodzie, bo trzeba te banki przełączać, żeby np. wykonywać skoki do procedur zapisanych w innych bankach. Ja nigdy wcześniej nie programowałem na PIC-e niczego, więc i tak sporo trudu kosztowało mnie to co już zrobiłem. Dla siebie jak pisałem nie potrzebuję LCD, jeśli okaże się, że to jest potrzebne, to w przyszłości spróbuję jeszcze poprawić to tak, żeby jednak zmieścił się ten kod obsługi wyświetlacza. Można to zrobić na dwa sposoby: albo skorzystać z bankowanej pamięci dodatkowej, która jeszcze jest wolna, albo znaleźć miejsca w kodzie, które dało by się zoptymalizować i zyskać miejsce na kilka instrukcji, bo tego miejsca brakuje chyba na jakieś chyba 8 instrukcji tylko.
Załączam całkowity kod źródłowy z moją poprawką oraz skompilowany wsad do PIC-a.