How I Hacked my Car Part 6: Nothing to it but to Doom it.

If you haven’t read the earlier parts, please do so.
如果您还没有阅读前面的部分,请阅读。

The background 背景⌗

There is a long standing tradition among hardware hackers and tinkerers. Once a platform is hacked, once a gadget is tinkered with, once a device is understood there will always be someone who asks a certain, specific question. And that question is: “Can it run Doom?
硬件黑客和修补匠之间有着悠久的传统。一旦一个平台被黑客入侵,一旦一个小工具被修补,一旦一个设备被理解,总会有人提出一个特定的问题。这个问题是:“它能运行《毁灭战士》吗?

Doom (1993) 厄运 (1993) ⌗

Doom (1993) is a first person shooter made by id Software which was originally made for MS-DOS. Doom was one of the games that helped define the first person shooter genre. It was in fact so defining that one of the early terms for first person shooter games was “Doom clones”.
Doom (1993) 是由 id Software 制作的第一人称射击游戏,最初是为 MS-DOS 制作的。Doom 是帮助定义第一人称射击游戏类型的游戏之一。事实上,它是如此明确,以至于第一人称射击游戏的早期术语之一是“Doom clones”。

Doom was also made in a time where computers were very weak, at least compared to today. A time where CPUs were measured in megahertz instead of gigaherz, and memory was defined in megabytes instead of gigabytes.
《毁灭战士》也是在计算机非常薄弱的时代制作的,至少与今天相比是这样。CPU 以兆赫兹而不是千兆赫兹为单位,内存以兆字节而不是千兆字节来定义。

Due to the concept of linear time, it was limited to the technology of its day. Because of these limitations Doom was written to be highly optimized and portable. In the end, it ran very well on these relatively weak machines.
由于线性时间的概念,它仅限于当时的技术。由于这些限制,Doom 被编写为高度优化和可移植。最后,它在这些相对较弱的机器上运行得很好。

In late 1997, the source code for Doom was released.
1997年末,《毁灭战士》的源代码发布。

This combination of an open source, impressive, but still easy-to-run game made the perfect storm of an app that can be ported to nearly anything with a screen.
这款开源、令人印象深刻但仍然易于运行的游戏的结合造就了一款可以移植到几乎任何带有屏幕的应用程序的完美风暴。

And because the internet is the internet, memes eventually formed around the idea that nearly any gadget or gizmo can run Doom. Whether it be running on a thermostatan oscilloscopea desk phone, or even a pregnancy test.
因为互联网就是互联网,模因最终围绕着几乎任何小工具或小玩意儿都可以运行《毁灭战士》的想法而形成。无论是在恒温器、示波器、桌面电话上运行,还是在验孕棒上运行。

Because I am but a humble hacker on the internet desperate for that sweet, sweet internet clout. I of course had to port Doom to my hacked car.
因为我只是互联网上一个不起眼的黑客,渴望那种甜蜜的、甜蜜的互联网影响力。当然,我不得不将《毁灭战士》移植到我被黑的汽车上。

The port 端口⌗

Using the information that can be found in part 3. I set up the QTCreator IDE for DAudio2 development and used my DAudio2 Gui Template Application as a starter template.
使用第 3 部分中的信息。我为 DAudio2 开发设置了 QTCreator IDE,并使用我的 DAudio2 Gui 模板应用程序作为入门模板。

There are many flavors of Doom and Doom look-alikes, and many ports of those that can be used as a starting ground for new ports. I decided to go with doomgeneric, a version of Doom specifically made to be easily portable.
《毁灭战士》和《毁灭战士》的相似性有很多种,其中许多端口可以用作新端口的起点。我决定选择doomgeneric,这是Doom的一个版本,专门设计为易于携带。

doomgeneric claimed all I had to do was create a doomgeneric_myPlatform.cpp file and implement 5 simple functions and just like that, Doom would be ported.
doomgeneric 声称我所要做的就是创建一个 doomgeneric_myPlatform.cpp 文件并实现 5 个简单的函数,就这样,Doom 就会被移植。

“All I had to do” Joke #5
“我所要做的”笑话 #5 ⌗

Yeah it wasn’t that simple, but also it wasn’t not that simple. Like how many programming projects end up, there were a number of roadblocks and difficulties I hit along the way.
是的,事情没那么简单,但也不是那么简单。就像许多编程项目最终完成一样,我在此过程中遇到了许多障碍和困难。

But for now, back to the start:
但现在,回到开头:

There were 5/6 functions I needed to/could implement:
我需要/可以实现 5/6 个功能:

Function Description
DG_Init Platform-specific initialization (Creating window, allocating buffers, etc..)
特定于平台的初始化(创建窗口、分配缓冲区等)
DG_DrawFrame Draw the frame from the framebuffer to the window
将帧从帧缓冲区绘制到窗口
DG_SleepMs Sleeping in milliseconds
以毫秒为单位的睡眠
DG_GetTicksMs Getting the ticks that passed since the launch in milliseconds
获取自启动以来经过的刻度(以毫秒为单位)
DG_GetKey Provide keyboard inputs to Doom
为 Doom 提供键盘输入
DG_SetWindowTitle Set the window title (Not applicable in this case)
设置窗口标题(本例不适用)

doomgeneric helpfully had a few example ports. One of them being an X11/xlib port. The port had pretty generic implementations of DG_SleepMs(), DG_GetTicksMs(), and some nice helper methods to make DG_GetKey() easier. I decided to copy these for my port.
Doomgeneric 提供了一些示例端口。其中之一是 X11/xlib 端口。该端口具有非常通用的 DG_SleepMs()、DG_GetTicksMs() 实现,以及一些不错的辅助方法,使 DG_GetKey() 更容易。我决定为我的端口复制这些。

This left 3 functions to implement, DG_Init(), DG_DrawFrame(), and some DG_GetKey() logic.
这留下了 3 个函数要实现,DG_Init()、DG_DrawFrame() 和一些 DG_GetKey() 逻辑。

I created my doomgeneric_daudio.cpp file and started with the initialization logic.
我创建了我的doomgeneric_daudio.cpp文件,并从初始化逻辑开始。

Startup 创业公司 ⌗

To keep things simple I created my main() function in this file and copied over the code to initialize my TestGuiApplication from my template code. I also renamed all of my “Test” placeholder texts with “Doom”.
为了简单起见,我在此文件中创建了我的 main() 函数,并复制了代码以从我的模板代码初始化我的 TestGuiApplication。我还用“Doom”重命名了我所有的“测试”占位符文本。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

At this point I decided I didn’t need a seperate DG_Init() function to initialize things when I have a main() function. I removed it and moved the couple of things that were in there into main(). Following the instructions in doomgeneric’s Readme.md, I added a call to doomgeneric_Create();
在这一点上,我决定当我有一个 main() 函数时,我不需要一个单独的 DG_Init() 函数来初始化东西。我删除了它并将其中的几个东西移动到 main() 中。按照 doomgeneric Readme.md 中的说明,我添加了对 doomgeneric_Create() 的调用;
How I Hacked my Car Part 6: Nothing to it but to Doom it.

There were a couple of complications I had while creating this main() function, even with how simple it was. The main one was the argument handling.
在创建这个 main() 函数时,我遇到了一些复杂问题,即使它很简单。最主要的是参数处理。

DAudio2 GUI applications work a little weird. They can’t be just started from a command line like in most linux distributions. Their launching is handled by a window manager called Helix, and the format of the arguments is standardized to allow for launching specific AppViews or AppServices in the application.
DAudio2 GUI 应用程序的工作有点奇怪。它们不能像大多数 linux 发行版那样从命令行启动。它们的启动由名为 Helix 的窗口管理器处理,参数的格式是标准化的,以允许在应用程序中启动特定的 AppView 或 AppServices。

Because of this I couldn’t just pass along the normal arguments into doomgeneric_Create() as it could have unintended side effects. Because this was a silly little demo I simply hard-coded my own arguments and passed those along.
正因为如此,我不能只是将正常的参数传递到 doomgeneric_Create() 中,因为它可能会产生意想不到的副作用。因为这是一个愚蠢的小演示,我只是硬编码了我自己的论点并传递了它们。

Pretty Pictures? 漂亮的图片?⌗

The next step was drawing frames onto the screen.
下一步是在屏幕上绘制框架。

After some research I found out I can use a QLabel to display a framebuffer through this process:
经过一番研究,我发现我可以使用QLabel通过这个过程显示帧缓冲区:

  1. Use the framebuffer to generate a QImage
    使用帧缓冲生成 QImage
  2. Use the QImage to make a QPixmap
    使用 QImage 制作 QPixmap
  3. Use the QPixmap as the QLabel’s background image
    使用 QPixmap 作为 QLabel 的背景图像

The buffer that doomgeneric writes to is called DG_ScreenBuffer. I made a field on my MainWindow called bufferQImage and set it up to reference DG_ScreenBuffer. I then used it to make a QPixmap which is used as the background image for my displayLabel.
doomgeneric 写入的缓冲区称为 DG_ScreenBuffer。我在 MainWindow 上创建了一个名为 bufferQImage 的字段,并将其设置为引用DG_ScreenBuffer。然后,我用它来制作一个QPixmap,它被用作displayLabel的背景图像。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

I also needed to update this QLabel whenever there was a new frame to render. I made a function called refreshDrawingBuffer which called the update function on my displayLabel. Based on my research this should cause the QLabel to redraw itself.
每当有新帧要渲染时,我还需要更新此 QLabel。我创建了一个名为 refreshDrawingBuffer 的函数,它调用了我的 displayLabel 上的更新函数。根据我的研究,这应该会导致 QLabel 重新绘制自己。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

I wired up the DG_DrawFrame() function to call the refreshDrawingBuffer() function and I set up a QTimer to repeatedly call the doomgeneric_Tick() function which should make the game run.
我连接了 DG_DrawFrame() 函数来调用 refreshDrawingBuffer() 函数,并设置了一个 QTimer 来重复调用 doomgeneric_Tick() 函数,这应该使游戏运行。

Did it work?
它起作用了吗?⌗

I should have now had the code needed to draw and run the Doom demo.
我现在应该已经拥有了绘制和运行 Doom 演示所需的代码。

In order to test this I needed to get a WAD file. WAD files are the Doom engine’s game data files. They contain the levels, maps, enemies, and textures used in the game. I found the original DOOM.WAD file and downloaded it to my flash drive.
为了测试这一点,我需要获取一个 WAD 文件。WAD文件是Doom引擎的游戏数据文件。它们包含游戏中使用的关卡、地图、敌人和纹理。我找到了原版《DOOM》。WAD 文件并将其下载到我的闪存驱动器。

In order for the Doom engine to load this WAD file I had to tell it where the file would be. I hardcoded a path in my arguments that tells Doom to read “/appdata/DOOM.WAD”.
为了让 Doom 引擎加载这个 WAD 文件,我必须告诉它文件在哪里。我在参数中硬编码了一条路径,告诉 Doom 读取“/appdata/DOOM。WAD“。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

I compiled the application and went into my car.
我编译了应用程序并进入了我的车。

In order for my app to be registered by Helix, I would have to add an .appconf file for it in the /etc/appmanager/appconf folder. I created a DAudio2Doom.appconf file with the following contents and copied it into the folder:
为了让我的应用程序被 Helix 注册,我必须在 /etc/appmanager/appconf 文件夹中为其添加一个 .appconf 文件。我创建了一个包含以下内容的 DAudio2Doom.appconf 文件并将其复制到文件夹中:

[Application]
Name=com.greenluigi1.doom
Exec=/appdata/DAudio2Doom

[DoomAppView]
# ComponentName : com.greenluigi1.doom.DoomAppView
Type=AppView

Then I ran the following to copy over my DAudio2Doom compiled binary, mark it as executable, reboot the system so it can read the new .appconf file, and finally start the application.
然后我运行以下命令来复制我的 DAudio2Doom 编译的二进制文件,将其标记为可执行文件,重新启动系统以便它可以读取新的 .appconf 文件,最后启动应用程序。

cp /run/media/B208-FF9A/DAudio2Doom /appdata

chmod +x /appdata/DAudio2Doom

reboot

appctl startAppView com.greenluigi1.doom.DoomAppView

After running the last command, the app launched and it quickly became apparently that it wasn’t working.
运行最后一个命令后,该应用程序启动,并且很快就明显无法正常工作。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

A completely blank screen was shown when I was expecting the first frame of Doom.
当我期待《毁灭战士》的第一帧时,出现了一个完全空白的屏幕。

Then the entire head unit rebooted…
然后整个主机重新启动……

Debugging on this platform is a bit difficult because of how Helix launches the apps. So my current method of debugging is putting logging statement everywhere.
由于 Helix 启动应用程序的方式,在此平台上进行调试有点困难。因此,我当前的调试方法是将日志记录语句放在任何地方。

So to figure out what went wrong, it was time to log everything.
因此,要弄清楚出了什么问题,是时候记录所有内容了。

I created a couple of methods to help with logging and then called them from Doom’s logging functions
我创建了几个方法来帮助日志记录,然后从 Doom 的日志记录函数中调用它们

void DG_Log(const char* logMessage)
{
    __android_log_print(ANDROID_LOG_DEBUG, "DAudio2Doom", logMessage);
}

int DG_Log_printf(const char *__restrict __format, ...)
{
    int result;
    va_list args;
    va_start(args, __format);
    result = __android_log_vprint(ANDROID_LOG_DEBUG, "DAudio2Doom", __format, args);
    va_end(args);

    return result;
}

int DG_Log_vprintf(const char *__restrict __format, va_list ap)
{
    return __android_log_vprint(ANDROID_LOG_DEBUG, "DAudio2Doom", __format, ap);
}

After running it again and extracting the logs, I found a couple of issues, like how I forgot to copy over the DOOM.WAD file. I also found out that when Doom encounters and error like not finding a valid WAD file, it calls the abort() function.
在再次运行并提取日志后,我发现了一些问题,比如我忘记复制《DOOM》了。WAD 文件。我还发现,当 Doom 遇到错误(例如找不到有效的 WAD 文件)时,它会调用 abort() 函数。

After the app aborted itself, the app watchdog in the head unit figured out that the app broke and restarted the head unit after a few seconds.
应用程序自行中止后,主机中的应用程序看门狗发现应用程序已损坏,并在几秒钟后重新启动了主机。

I disabled the abort() call and copied over the WAD file. I updated the binary, and started the app only to find another blank screen. It still could not find the WAD file. I tried a couple of things like changing the arguments (using “-iwad” instead of “-file”) but nothing worked. So, I updated the D_FindIWAD() function to just always return the hardcoded path “/appdata/DOOM.WAD”, which got rid of the error.
我禁用了 abort() 调用并复制了 WAD 文件。我更新了二进制文件,并启动了应用程序,却发现另一个空白屏幕。它仍然找不到 WAD 文件。我尝试了几件事,例如更改参数(使用“-iwad”而不是“-file”),但没有任何效果。因此,我更新了 D_FindIWAD() 函数,使其始终返回硬编码路径“/appdata/DOOM。WAD“,从而消除了错误。

But the blank screen remained. I was still missing something.
但是空白屏幕仍然存在。我仍然缺少一些东西。

I took an educated guess that something was wrong with the framebuffer or how I was reading it. The first thing I checked was the format of the framebuffer.
我有一个有根据的猜测,即帧缓冲或我阅读它的方式有问题。我检查的第一件事是帧缓冲区的格式。

Framebuffer Format 帧缓冲格式 ⌗

A framebuffer is a just a bunch of color data that forms an image. When storing color information you have to pick a format. The format dictates how much data each pixel takes up, what types of color information is stored, and what order are the colors stored in.
帧缓冲区只是形成图像的一堆颜色数据。存储颜色信息时,您必须选择一种格式。该格式决定了每个像素占用的数据量、存储的颜色信息类型以及颜色的存储顺序。

I was currently using QImage::Format_ARGB32 which meant QT was expecting the data to be stored in the following format:
我目前正在使用 QImage::Format_ARGB32,这意味着 QT 希望数据以以下格式存储:

  • Alpha (Transparency): 1 byte
    Alpha(透明度):1 字节
  • Red: 1 byte 红色:1 字节
  • Green 1 byte 绿色 1 字节
  • Blue 1 byte 蓝色 1 字节

Which makes a total of 4 bytes (Or 32 bits) of color data per pixel.
这使得每个像素总共有 4 个字节(或 32 位)的颜色数据。

But I wasn’t even sure if that was right, it was only a guess at the time.
但我甚至不确定这是否正确,当时这只是一个猜测。

So I looked at the examples provided by doomgeneric and saw a reference to the SDL format of RGB888.
因此,我查看了doomgeneal提供的示例,并看到了对RGB888的SDL格式的引用。

texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGB888, SDL_TEXTUREACCESS_TARGET, DOOMGENERIC_RESX, DOOMGENERIC_RESY);

I updated my code to use the QImage::Format_RGB888 format and ran it.
我更新了我的代码以使用 QImage::Format_RGB888 格式并运行了它。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

I could at least see there was something there. It was pretty recognizably the Doom start screen, just really mangled.
我至少能看到那里有什么东西。这是相当容易辨认的《毁灭战士》开始屏幕,只是真的被破坏了。

I cycled through a couple of other QImage::Formats but nothing appeared to work. I also looked through Doom’s code and it looked like each pixel should be ARGB, but as I saw before that didn’t work.
我循环浏览了其他几个 QImage::Formats,但似乎没有任何效果。我还查看了 Doom 的代码,看起来每个像素都应该是 ARGB,但正如我之前看到的,这不起作用。

In order to figure out the format for sure I added a “Dump” button which would dump the contents of the DG_ScreenBuffer to my flash drive.
为了确定格式,我添加了一个“转储”按钮,该按钮会将DG_ScreenBuffer的内容转储到我的闪存驱动器中。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

After loading up the app once again I dumped the framebuffer and use a tool called RAW pixels viewer to view the data.
再次加载应用程序后,我转储了帧缓冲区,并使用一个名为RAW像素查看器的工具来查看数据。

After fiddling with the parameters I eventually got a working image. The head unit was running doom the entire time, it just wasn’t displaying properly! It was also clearly running the game demo which means the game tick function was working correctly.
在摆弄参数后,我最终得到了一个工作图像。主机一直在运行厄运,只是没有正确显示!它显然也在运行游戏演示,这意味着游戏滴答声功能工作正常。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

The format of the image is BGRA, ignoring the alpha color channel.
图像的格式是 BGRA,忽略 alpha 颜色通道。

Here is it if we do not ignore the Alpha channel:
如果我们不忽略 Alpha 通道,就是这样:
How I Hacked my Car Part 6: Nothing to it but to Doom it.

Doom does not process any transparency data, so the alpha channel was always set to 0. This means my program was reading it as fully transparent. Which is why I had a blank screen on certain formats.
Doom 不处理任何透明度数据,因此 Alpha 通道始终设置为 0。这意味着我的程序是完全透明的。这就是为什么我在某些格式上有一个空白屏幕的原因。

It was displaying the image “correctly”, it was just that it was invisible. 😐
它“正确”地显示图像,只是它是不可见的。:|

With this information it was clear I had two issues with my code. One was the format, and the other was why the image was not updating on the screen.
有了这些信息,很明显我的代码有两个问题。一个是格式,另一个是为什么图像没有在屏幕上更新。

I set the format to be QImage::RGB32 which should read only the RGB and ignore the Alpha channel. The reason the format is not written as QImage::BGR32 is because the head unit uses little endian format. Effectively this means the channels are stored and read in reversed order, aka BGR instead of RGB which was exactly what I wanted.
我将格式设置为 QImage::RGB32,它应该只读取 RGB 而忽略 Alpha 通道。格式未写为 QImage::BGR32 的原因是主机使用小端格式。实际上,这意味着通道以相反的顺序存储和读取,即 BGR 而不是 RGB,这正是我想要的。

Next, I had to figure out why the image wasn’t updating on the screen. After a couple of hours of googling and testing various things, I figured out that the update call would not refresh the QLabel’s image unless the QPixmap itself was updated. I then changed the function to repeatedly set the QLabel’s Pixmap to the bufferQImage I made earlier.
接下来,我必须弄清楚为什么图像没有在屏幕上更新。经过几个小时的谷歌搜索和测试各种东西,我发现除非 QPixmap 本身更新,否则更新调用不会刷新 QLabel 的映像。然后,我更改了函数,将 QLabel 的 Pixmap 重复设置为我之前制作的 bufferQImage。
How I Hacked my Car Part 6: Nothing to it but to Doom it.

It is… Beautiful
是的。。。美丽⌗

After launching the new binary I was greeted with the beautiful sight of Doom running in my car.
在启动新的二进制文件后,我看到了 Doom 在我的车里奔跑的美丽景象。

Now I just needed to hook in some inputs and I would be playing in no time!
现在我只需要挂上一些输入,我很快就会玩!

The Fun Part – Inputs
有趣的部分 – 输入 ⌗

I decided that I would try to make this port as fun as possible by incorperating some of the inputs that are connected to the head unit instead of just hooking up a boring-old keyboard.
我决定通过合并一些连接到主机的输入来尝试使这个端口尽可能有趣,而不仅仅是连接一个无聊的旧键盘。

As mentioned in previous posts I found a plethora of header files in an older firmware update that gives me access to many APIs that interact with the vehicle. Unfortunately, these header files are no longer provided within the latest firmware updates. But luckily, Hyundai hasn’t really updated anything worthwhile so the old header files still work.
正如在之前的帖子中提到的,我在较旧的固件更新中发现了大量的头文件,这使我能够访问许多与车辆交互的 API。不幸的是,这些头文件不再在最新的固件更新中提供。但幸运的是,现代并没有真正更新任何有价值的东西,所以旧的头文件仍然有效。

(Pst. Don’t tell Hyundai but you can still find the files in the latest Korean version of the firmware just click the dark blue button that has the “DN8” text. The update is even unencrypted so you can just extract the zip and the grab the system.img file directly. Do note that the update is older so your millage may vary if they work or not.)
(Pst. 不要告诉现代,但你仍然可以在最新的韩文版固件中找到文件,只需单击带有“DN8”文本的深蓝色按钮即可。该更新甚至是未加密的,因此您可以提取zip并直接获取system.img文件。请注意,更新较旧,因此您的里程可能会有所不同,无论它们是否有效。

I looked through many of the files and noted down some of them that could be used for inputs in the game. The following were ones that caught my eye:
我浏览了许多文件,并记下了其中一些可用于游戏输入的文件。以下是引起我注意的:

HChassis::getSteeringAngle(); // Or IHChassisListener::onSteeringAngleChanged();
HChassis::getAcceleratorPedalState(); // Or IHChassisListener::onAcceleratorPedalStateChanged();
HBody::isTurnSignalSwitchOn(); // Or IHBodyListener::onTurnSignalStateChanged()
IHModeChangeListener::onKeyEvent();
HSeat::isSeatBeltBuckleLatched();

I initially tried the IHChassisListener and IHBodyListener callback functions. Unfortunately I could not get them to work, so I went with checking the get() functions directly.
我最初尝试了 IHChassisListener 和 IHBodyListener 回调函数。不幸的是,我无法让它们工作,所以我直接检查了 get() 函数。

Using the Dump button I made earlier I hooked into each of the functions and checked to see if they worked.
使用我之前制作的“转储”按钮,我挂接到每个功能并检查它们是否有效。

Function Result
HChassis::getSteeringAngle()
HChassis::getSteeringAngle()
Received number between 0-6553.5 indicating steering wheel position.
收到 0-6553.5 之间的数字,指示方向盘位置。
HChassis::getAcceleratorPedalState()
HChassis::getAcceleratorPedalState()
Always returned 0. 始终返回 0。
HBody::isTurnSignalSwitchOn()
HBody::isTurnSignalSwitchOn()
Received seemingly random values with no bearing on the turn signal switches.
接收到看似随机的值,与转向信号开关无关。
IHModeChangeListener::onKeyEvent()
IHModeChangeListener::onKeyEvent()
Received key numbers indicating what button on the head unit or steering wheel was pressed and a state value indicating if it was pressed, released, long pressed, or long released.
接收指示主机或方向盘上按下哪个按钮的键号,以及指示是按下、松开、长按还是长松的状态值。
HSeat::isSeatBeltBuckleLatched()
HSeat::isSeatBeltBuckleLatched()
Recevied a True/False value if the specified seat belt buckle was latched.
如果锁定了指定的安全带扣,则接收到真/假值。

3/5 isn’t the best, but the ones that worked were the most important ones anyways.
3/5 不是最好的,但无论如何,有效的都是最重要的。

With this new information I mapped the following inputs to Doom:
有了这些新信息,我将以下输入映射到 Doom:

Vehicle Input Location 车辆输入位置 Vehicle Input 车辆输入 Doom Input 厄运输入
Steering Wheel 方向盘 Turning wheel Left 左转轮 Left Arrow Key 向左箭头键
Steering Wheel 方向盘 Turning wheel Right 向右转轮 Right Arrow Key 向右箭头键
Steering Wheel 方向盘 Seek Down Key (Which is actually the up key)
查找向下键(实际上是向上键)
Up Arrow Key 向上箭头键
Steering Wheel 方向盘 Seek Up Key (Which is actually the down key)
查找键(实际上是向下键)
Down Arrow Key 向下箭头键
Steering Wheel 方向盘 Mute Button 静音按钮 Use
Steering Wheel 方向盘 End Call Button 结束通话按钮 Fire
Head Unit 主机 Volume Knob Press 卷旋钮压力机 Enter
Head Unit 主机 Tune Knob Press 调谐旋钮按 Escape

I then hooked these inputs into Doom using the key queue which was provided in doomgeneric’s X11 example code.
然后,我使用 doomgeneric 的 X11 示例代码中提供的密钥队列将这些输入挂接到 Doom 中。

Can it run Doom? Yes It Can!
它能运行 Doom 吗?是的可以!⌗

And just like that I had a working installation of Doom running on my car.
就这样,我的车上运行着一个 Doom 的工作装置。

Is it perfect? No, first there is no audio and I will admit that the inputs are not the best. Some of the keys I used are also received by background applications and will do things like change the song if you are trying to move forward. As long as no media source is playing though (By pressing the volume knob in) it works well enough.
完美吗?不,首先没有音频,我承认输入不是最好的。我使用的一些键也被后台应用程序接收,如果您尝试继续前进,它们会做一些事情,例如更改歌曲。只要没有播放媒体源(通过按下音量旋钮),它就足够好用。

Oh, and the tires do move when turning the steering wheel, so it is best to not do any long playthroughs or you will grind your tires down. :p
哦,转动方向盘时轮胎确实会移动,所以最好不要进行任何长时间的游戏,否则你会磨坏轮胎。:p

But for the little demo it is, it sure is fun!
但对于这个小演示来说,它确实很有趣!

Source Code Release 源代码发布

The Future of My Car Hacking Adventures
我的汽车黑客冒险的未来 ⌗

I am no fortune teller and do not know what the future holds. But at least regarding my head unit, I have accomplished most of the things I wanted to do.
我不是算命先生,也不知道未来会怎样。但至少就我的主机而言,我已经完成了我想做的大部分事情。

I still have a couple of app ideas I may explore in the future and if new firmware updates are released I will try to crack those too.
我仍然有一些应用程序的想法,我可能会在未来探索,如果发布新的固件更新,我也会尝试破解它们。

But until then, I will be busy playing Doom.
但在那之前,我会忙于玩《毁灭战士》。

How I Hacked my Car Part 6: Nothing to it but to Doom it.

原文始发于Programming With Style:How I Hacked my Car Part 6: Nothing to it but to Doom it.

版权声明:admin 发表于 2024年6月9日 上午9:49。
转载请注明:How I Hacked my Car Part 6: Nothing to it but to Doom it. | CTF导航

相关文章