使用F1C200S从零制作掌机之debian文件系统完善NES

一、模拟器源码

源码:https://files.cnblogs.com/files/twzy/arm-NES-linux-master.zip

二、文件系统

文件系统:debian bullseye

使用builtroot2018构建的文件系统,使用InfoNES模拟器存在bug,搞不定,所以放弃,改用debian。

三、编译

在debian文件系统下编译,在f1c200s开发板执行

解压源码进入Linux目录,不用做修改执行make编译。

编译后在f1c200s开发板执行,屏幕可见画面。

启动debian模拟器

mount_debian.sh

复制代码
#/bin/bash
cd rootfs
sudo mount --bind /dev dev/
sudo mount --bind /sys sys/
sudo mount --bind /proc proc/
sudo mount --bind /dev/pts dev/pts/
sudo cp /usr/bin/qemu-arm-static  usr/bin/
cd ..
sudo LC_ALL=C LANGUAGE=C LANG=C chroot rootfs

编译:

复制代码
cd /home/arm-NES-linux/linux && make

退出debian模拟器

unmount_debian.sh

复制代码
sudo rm rootfs/usr/bin/qemu-arm-static #删除之前拷贝的文件
cd rootfs
sudo umount   dev/pts/ # 一定要在/dev前面umount
sudo umount   dev/
sudo umount   sys/
sudo umount   proc/

四、适配遥控

builtroot制作的文件系统下调试驱动

在debian系统下使用:evtest命令

这里使用无线手柄:

在命令行执行:evtest,操作无线手柄可发现有按键事件上报。

修改NES模拟器源码linux目录下的joypad_input.cpp,使其适配自己的无线手柄。

修改一

复制代码
int InitJoypadInput(void)
{
	int iErr = 0;
	//iErr = RegisterJoypadInput(&joypadInput);
	iErr = RegisterJoypadInput(&usbJoypadInput);    // 只注册这个输入
	return iErr;
}

修改二

复制代码
static int USBjoypadGet(void)
{
	/**
	 * FC手柄 bit 键位对应关系 真实手柄中有一个定时器,处理 连A  连B 
	 * 0  1   2       3       4    5      6     7
	 * A  B   Select  Start  Up   Down   Left  Right
	 */
	//因为 USB 手柄每次只能读到一位键值 所以要有静态变量保存上一次的值
	static unsigned char joypad = 0;
	struct input_event e;
	if(0 < read (USBjoypad_fd, &e, sizeof(e)))
	{
		if(0x3 == e.type)
		{
			/*
			上:
			value:0x8001 type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(17 == e.code && -1 == e.value)
			{
				joypad |= 1<<4;
			}

			/*下:
			value:0x7fff type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(17 == e.code && 1 == e.value)
			{
				joypad |= 1<<5;
			}
			//松开
			if(17 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<4 | 1<<5);
			}
			
			/*左:
			value:0x8001 type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(16 == e.code && -1 == e.value)
			{
				joypad |= 1<<6;
			}
			
			/*右:
			value:0x7fff type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(16 == e.code && 1 == e.value)
			{
				joypad |= 1<<7;
			}
			//松开
			if(16 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<6 | 1<<7);
			}
		}

		if(0x1 == e.type)
		{
			/*选择:
			value:0x1 type:0x1 number:0xa
			value:0x0 type:0x1 number:0xa
			*/
			if(314 == e.code && 1 == e.value)
			{
				joypad |= 1<<2;
			}
			if(314 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<2);
			}
			
			/*开始
			value:0x1 type:0x1 number:0xb
			value:0x0 type:0x1 number:0xb
			*/
			if(315 == e.code && 1 == e.value)
			{
				joypad |= 1<<3;
			}
			if(315 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<3);
			}

			/*A
			value:0x1 type:0x1 number:0x0
			value:0x0 type:0x1 number:0x0
			*/
			if(304 == e.code && 1 == e.value)
			{
				joypad |= 1<<0;
			}
			if(304 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<0);
			}

			/*B
			value:0x1 type:0x1 number:0x1
			value:0x0 type:0x1 number:0x1
			*/
			if(305 == e.code && 1 == e.value)
			{
				joypad |= 1<<1;
			}
			if(305 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<1);
			}

			/*X
			value:0x1 type:0x1 number:0x3
			value:0x0 type:0x1 number:0x3
			*/
			if(307 == e.code && 1 == e.value)
			{
				joypad |= 1<<0;
			}
			if(307 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<0);
			}

			/*Y
			value:0x1 type:0x1 number:0x4
			value:0x0 type:0x1 number:0x4
		 	*/
		 	if(308 == e.code && 1 == e.value)
			{
				joypad |= 1<<1;
			}
			if(308 == e.code && 0 == e.value)
			{
				joypad &= ~(1<<1);
			}
		}
		return joypad;
	}
	return -1;
}

修改三

复制代码
static void *InputEventTreadFunction(void *pVoid)
{
	/* 定义函数指针 */
	int (*GetJoypad)(void);
	GetJoypad = (int (*)(void))pVoid;

	while (1)
	{
		//因为有阻塞所以没有输入时是休眠
		//g_InputEvent = GetJoypad();
		int data = GetJoypad();
		if (data == -1)
		{
			continue;
		}
		else
		{
			g_InputEvent = data;
		}

		//有数据时唤醒
		pthread_mutex_lock(&g_tMutex);
		//因为有阻塞所以没有输入时是休眠
		pthread_cond_signal(&g_tConVar);
		pthread_mutex_unlock(&g_tMutex);
	}
}

五、测试游戏是否可以正常玩耍

可以无声音畅玩了。

六、先解决debian系统下的语音播放

检查声卡

复制代码
cat /proc/asound/cards

默认声卡配置

vi /etc/asound.conf

复制代码
defaults.ctl.card 0
defaults.pcm.card 0
defaults.timer.card 0

amixer controls 用于查看音频系统提供的操作接口
amixer contents 用于查看接口配置参数
amixer cget + 接口函数
amixer cset + 接口函数 + 设置值

amixer cget numid=14,iface=MIXER,name='ADC Mixer Mic Capture Switch'
amixer cset numid=14,iface=MIXER,name='ADC Mixer Mic Capture Switch' on
打开之后才可以录音
arecord out.wav

root@wang-virtual-machine:~# arecord out.wav
Recording WAVE 'out.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
^CAborted by signal Interrupt...
root@wang-virtual-machine:~#
root@wang-virtual-machine:~#
root@wang-virtual-machine:~# aplay out.wav
Playing WAVE 'out.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
^CAborted by signal Interrupt...

七、解决NES模拟器的声音

启动游戏会出现乱七八糟的声音,也不知道对不对。在NES中是通过一些PCM的API操作音频的,具体的看代码吧。

八、mplayer播放音频

mplayer -ao alsa out.wav 特别慢有声音

mplayer -ao alsa test.wav

mplayer -ao alsa test.mp3

复制代码
root@wang-virtual-machine:/home# mplayer -ao alsa test.mp3
MPlayer 1.4 (Debian), built with gcc-10 (C) 2000-2019 MPlayer Team
do_connect: could not connect to socket
connect: No such file or directory
Failed to open LIRC support. You will not be able to use your remote control.

Playing test.mp3.
libavformat version 58.45.100 (external)
Audio only file format detected.
Load subtitles in ./
==========================================================================
Opening audio decoder: [mpg123] MPEG 1.0/2.0/2.5 layers I, II, III
AUDIO: 16000 Hz, 2 ch, s16le, 16.0 kbit/3.12% (ratio: 2000->64000)
Selected audio codec: [mpg123] afm: mpg123 (MPEG 1.0/2.0/2.5 layers I, II, III)
==========================================================================
AO: [alsa] 16000Hz 2ch s16le (2 bytes per sample)
Video: no video
Starting playback...
A:   3.1 (03.0) of 3.0 (03.0) 12.7%


Exiting... (End of file)

有办法去掉connect to socket吗?

是遥控器,通过配置去掉。

复制代码
vi /etc/mplayer/mplayer.conf
lirc=no

但依然还是很慢。能正常使用。

九、参考

https://zhuanlan.zhihu.com/p/670785159

相关推荐
Ha-gd8 分钟前
Linux基础开发工具一(yum/apt ,vim)
linux·服务器
charlie1145141911 小时前
内核深入学习3——分析ARM32和ARM64体系架构下的Linux内存区域示意图与页表的建立流程
linux·学习·架构·内存管理
Caron_xcb1 小时前
大数据——解决Matplotlib 字体不足问题(Linux\mac\windows)
大数据·linux·matplotlib
水水沝淼㵘2 小时前
嵌入式开发学习日志(数据结构--顺序结构单链表)Day19
linux·服务器·c语言·数据结构·学习·算法·排序算法
愚润求学2 小时前
【Linux】基础 IO(一)
linux·运维·服务器·开发语言·c++·笔记
大白的编程日记.2 小时前
【Linux学习笔记】理解一切皆文件实现原理和文件缓冲区
linux·笔记·学习
孞㐑¥3 小时前
Linux之进程控制
linux·开发语言·c++·经验分享·笔记
愚润求学3 小时前
【Linux】简单设计libc库
linux·运维·开发语言·c++·笔记
chennalC#c.h.JA Ptho3 小时前
Bodhi linux 系统详解
linux·经验分享·笔记·系统架构·系统安全
檀越剑指大厂3 小时前
T-BOX硬件方案深度解析:STM32与SD NAND Flash存储的完美搭配
stm32·单片机·嵌入式硬件