在100ask stm32mp157板子上运行超级玛丽

该文详细介绍了如何在100askSTM32MP157开发板上通过arm-NES-linux项目运行超级玛丽游戏。首先从Git仓库下载源码,然后修改源码以支持通过标准输入控制游戏。接着在Linux目录下编译并运行程序。文章指出存在颜色显示不正确、按键延迟和游戏无法通关等问题,并提供了部分源代码片段。
摘要由CSDN通过智能技术生成

在100ask stm32mp157板子上运行超级玛丽

一、下载arm-NES-linux

git clone https://gitee.com/ant1423/arm-NES-linux.git

二、修改源码支持标准输入控制

这一步主要修改源码根目录下的linux/joypad_input.cpp文件,要生成linux可用的程序,只需要在linux目录下面执行make命令即可,但是由于编译的是cpp文件,所以需要交叉编译工具链支持c++,文末直接给出代码

添加了一个新的函数以支持从标准输入获取输入事件,这里的映射关系是参考的上面手柄来设置的
在这里插入图片描述
设置一个T_JoypadInput结构体
在这里插入图片描述
最后在InitJoypadInput函数里注册就行了
在这里插入图片描述

三、 编译运行

编译只需要在arm-NES-linux/linux目录下执行make命令就行了,编译生成InfoNes文件,把它和游戏ROM拷贝到板子上,添加执行权限就可以运行
注意,如果myir的QT程序正在运行,需要关闭myir的QT程序

systemctp stop myir

关闭成功后即可执行InfoNes,如运行超级玛丽

./InfoNES Super_Mario.nes

在这里插入图片描述
效果如下图所示
在这里插入图片描述
按在串口输入H开始游戏,J是跳跃,K是攻击,AD是移动

四、问题

1、颜色显示的不正确,这里可能需要修改RGB格式
1、在按下按键的时候,延时设置的是500毫秒,在按键按下之后也没有上报松开事件,整体的体验不是很好
2、在通过第一关的时候,内核会报错,这里没有仔细调。无法进入下一关,并且无法重新启动游戏

joypad_input.cpp

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/ioctl.h>
#include <termios.h>
#include<sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>




#define JOYPAD_DEV "/dev/joypad"
#define USB_JS_DEV "/dev/input/js0"


typedef struct JoypadInput{
	int (*DevInit)(void);
	int (*DevExit)(void);
	int (*GetJoypad)(void);
	struct JoypadInput *ptNext;
	pthread_t tTreadID;     /* 子线程ID */
}T_JoypadInput, *PT_JoypadInput;

struct js_event {		
	unsigned int   time;      /* event timestamp in milliseconds */		
	unsigned short value;     /* value */		
	unsigned char  type;      /* event type */		
	unsigned char  number;    /* axis/button number */	
};

//全局变量通过互斥体访问
static unsigned char g_InputEvent;

static pthread_mutex_t g_tMutex  = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  g_tConVar = PTHREAD_COND_INITIALIZER;

static int joypad_fd;
static int USBjoypad_fd;

static PT_JoypadInput g_ptJoypadInputHead;

struct termios g_tStoredSettings;
struct termios g_tNewSettings;


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

	while (1)
	{
		//因为有阻塞所以没有输入时是休眠
		g_InputEvent = GetJoypad();
		//有数据时唤醒
		pthread_mutex_lock(&g_tMutex);
		/*  唤醒主线程 */
		pthread_cond_signal(&g_tConVar);
		pthread_mutex_unlock(&g_tMutex);
	}
}

static int RegisterJoypadInput(PT_JoypadInput ptJoypadInput)
{
	PT_JoypadInput tmp;
	if(ptJoypadInput->DevInit())
	{
		return -1;
	}
	//初始化成功创建子线程 将子项的GetInputEvent 传进来
	pthread_create(&ptJoypadInput->tTreadID, NULL, InputEventTreadFunction, (void*)ptJoypadInput->GetJoypad);
	if(! g_ptJoypadInputHead)
	{
		g_ptJoypadInputHead = ptJoypadInput;
	}
	else
	{
		tmp = g_ptJoypadInputHead;
		while(tmp->ptNext)
		{
			tmp = tmp->ptNext;
		}
		tmp->ptNext = ptJoypadInput;
	}
	ptJoypadInput->ptNext = NULL;
	return 0;
}

static int joypadGet(void)
{
	return read(joypad_fd, 0, 0);
}

static int joypadDevInit(void)
{
	joypad_fd = open(JOYPAD_DEV, O_RDONLY);
	if(-1 == joypad_fd)
	{
		printf("%s dev not found \r\n", JOYPAD_DEV);
		return -1;
	}
	return 0;
}

static int joypadDevExit(void)
{
	close(joypad_fd);
	return 0;
}

static T_JoypadInput joypadInput = {
	joypadDevInit,
	joypadDevExit,
	joypadGet,
};

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 js_event e;
	if(0 < read (USBjoypad_fd, &e, sizeof(e)))
	{
		if(0x2 == e.type)
		{
			/*
			上:
			value:0x8001 type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x8001 == e.value && 0x5 == e.number)
			{
				joypad |= 1<<4;
			}
			
			/*下:
			value:0x7fff type:0x2 number:0x5
			value:0x0 type:0x2 number:0x5
			*/
			if(0x7fff == e.value && 0x5 == e.number)
			{
				joypad |= 1<<5;
			}
			//松开
			if(0x0 == e.value && 0x5 == e.number)
			{
				joypad &= ~(1<<4 | 1<<5);
			}
			
			/*左:
			value:0x8001 type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x8001 == e.value && 0x4 == e.number)
			{
				joypad |= 1<<6;
			}
			
			/*右:
			value:0x7fff type:0x2 number:0x4
			value:0x0 type:0x2 number:0x4
			*/
			if(0x7fff == e.value && 0x4 == e.number)
			{
				joypad |= 1<<7;
			}
			//松开
			if(0x0 == e.value && 0x4 == e.number)
			{
				joypad &= ~(1<<6 | 1<<7);
			}
		}

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

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

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

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

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

static int USBjoypadDevInit(void)
{
	USBjoypad_fd = open(USB_JS_DEV, O_RDONLY);
	if(-1 == USBjoypad_fd)
	{
		printf("%s dev not found \r\n", USB_JS_DEV);
		return -1;
	}
	return 0;
}

static int USBjoypadDevExit(void)
{
	close(USBjoypad_fd);
	return 0;
}

static T_JoypadInput usbJoypadInput = {
	USBjoypadDevInit,
	USBjoypadDevExit,
	USBjoypadGet,
};

/* 从标准输入获取输入 */
static int CmdJoypadGet(void)
{
	/**
	 * FC手柄 bit 键位对应关系 真实手柄中有一个定时器,处理 连A  连B 
	 * 0  1   2       3       4    5      6     7
	 * A  B   Select  Start  Up   Down   Left  Right
	 */
	//因为 USB 手柄每次只能读到一位键值 所以要有静态变量保存上一次的值

	/* 
		A --> Left
		S --> Down
		W --> Up
		D --> Right
		G --> Select
		H --> Start
		J --> A
		K --> B
	*/
	
	unsigned char joypad = 0;
	static unsigned char LastJoypad = 0;
	char c = 0;
	static char LastC = 0;
    int ret = 0;
	fd_set read_fds;
	FD_ZERO(&read_fds);
	FD_SET(STDIN_FILENO, &read_fds);
	struct timeval tTimeOut;
	tTimeOut.tv_usec = 500000; //500ms

    ret = select(1, &read_fds, NULL, NULL, &tTimeOut);
    if(ret <= 0)
    {
        printf("select timeout or error, ret = %d, errno:%d -> %s\r\n", ret, errno, strerror(errno));
        return 0;
    }

    if(FD_ISSET(0, &read_fds))
    {
        read(0, &c, 1);
    }
    else
    {
        printf("error ! invaild fd\n");
        return 0;
    }
    
	printf("Get Input From Cmd: %c\r\n", c);
    switch (c)
    {
        case 'A':
        case 'a':
            /* Left */
            joypad |= 1<<6;
            break;
        case 'S':
        case 's':
            /* Down */
            joypad |= 1<<5;
            break;

      	case 'D':
       	case 'd':
            /* Right */
            joypad |= 1<<7;
            break;
        case 'W':
        case 'w':
            /* Up */
            joypad |= 1<<4;
            break;
            
      	case 'J':
        case 'j':
            /* A */
            joypad |= 1<<0;
            break;
        case 'K':
        case 'k':
            /* B */
            joypad |= 1<<1;
      	case 'G':
        case 'g':
            /* Select */
            joypad |= 1<<2;
            break;
        case 'H':
        case 'h':
            /* Start */
            joypad |= 1<<3;
            break;    
            
        default:
            break;
    }

    printf("Get Input Data Return %u\r\n", joypad);
	LastJoypad = joypad;
	LastC = c;
    return joypad;
}

static int CmdJoypadDevInit(void)
{

	tcgetattr (0, &g_tStoredSettings);
	g_tNewSettings = g_tStoredSettings;
	g_tNewSettings.c_lflag &= (~ICANON);
	g_tNewSettings.c_cc[VTIME] = 0;
	g_tNewSettings.c_cc[VMIN] = 1;
	tcsetattr (0, TCSANOW, &g_tNewSettings);

	return 0;
}

static int CmdJoypadDevExit(void)
{
	tcsetattr (0, TCSANOW, &g_tStoredSettings); // 恢复终端参数
	return 0;
}

static T_JoypadInput CmdJoypadInput = {
	CmdJoypadDevInit,
	CmdJoypadDevExit,
	CmdJoypadGet,
};


int InitJoypadInput(void)
{
	int iErr = 0;
//	iErr = RegisterJoypadInput(&joypadInput);
//	iErr = RegisterJoypadInput(&usbJoypadInput);
	iErr = RegisterJoypadInput(&CmdJoypadInput);
	return iErr;
}

int GetJoypadInput(void)
{

	printf("get input sleep...\r\n");
	/* 休眠 */
	pthread_mutex_lock(&g_tMutex);
	pthread_cond_wait(&g_tConVar, &g_tMutex);	

	printf("wake up get data...\r\n");
	/* 被唤醒后,返回数据 */
	pthread_mutex_unlock(&g_tMutex);
	return g_InputEvent;
}
Qt技术是一套强大的跨平台应用程序开发框架,专注于使用C++语言来构建高性能、高可维护性的软件解决方案。自1991年首次推出以来,Qt因其卓越的跨平台能力、丰富的功能集、高效的开发工具和良好的社区支持而广受开发者欢迎。以下是对Qt技术的详细介绍: 核心特性 跨平台性: Qt设计的核心理念是“一次编写,到处运行”。它支持多种操作系统,包括但不限于Windows、macOS、Linux、Android和iOS。通过Qt,开发者可以使用同一套源代码,在不同平台上编译并生成原生外观与体验的应用程序,极大地提高了开发效率和产品一致性。 图形用户界面(GUI)开发: 提供了一个完整的GUI工具箱,包含各种控件(如按钮、文本框、滑块、列表视图等)、布局管理器、样式表支持、动画效果等,帮助开发者快速构建美观、功能丰富的桌面和移动应用界面。Qt Designer是一个可视化界面设计工具,允许通过拖放操作构建UI,所见即所得。 非GUI应用开发: 除了GUI程序,Qt同样适用于开发命令行工具、后台服务、嵌入式系统等非图形化应用。其底层API涵盖了文件处理、线程、网络通信、数据库访问等广泛的功能。 面向对象设计: Qt采用面向对象的设计原则,提供了高度模块化的类库,使得代码组织清晰、易于扩展和重用。它遵循MVC(模型-视图-控制器)模式,支持数据驱动的界面设计。 元对象系统与信号槽机制: Qt Meta-Object System(元对象系统)是Qt框架的一个重要特性,它引入了元对象编译器(moc),用于在编译时生成额外的代码以支持对象间通信、反射、动态属性绑定等高级功能。 Signal & Slot机制是Qt中实现对象间事件驱动通信的核心方式。信号代表对象状态变化或事件发生,槽则是响应这些信号的可调用实体。这种松耦合的通信方式简化了异步编程和事件处理。 QML与Qt Quick: QML是一种声明性语言,结合JavaScript,用于快速创建流畅、动态的用户界面。它与Qt Quick框架紧密集成,特别适合开发现代化、触屏友好的应用。 Qt Quick Controls和Qt Quick Dialogs提供了一系列预定义的QML组件,用于构建具有传统桌面风格或现代移动风格的界面元素。同时,Qt Quick也支持自定义控件开发。 多媒体支持: Qt Multimedia模块提供对音频、视频播放、录音、摄像头访问等功能的支持,使得开发多媒体应用程序变得简便。 网络功能: Qt Network模块封装了网络通信相关的API,包括HTTP、FTP、TCP/UDP套接字、SSL加密、DNS查询等,便于开发网络应用和服务。 国际化与本地化: Qt Linguist工具支持应用程序的多语言翻译和本地化工作,确保软件能适应全球市场。 开发工具与生态系统: Qt Creator是一款集成开发环境(IDE),集成了项目管理、代码编辑、调试、版本控制、QML预览等多种功能,为Qt开发提供了无缝的工作流程。 Qt拥有活跃的开发者社区、丰富的文档资源、示例代码库以及商业支持选项,为开发者的学习、问题解决和项目实施提供了坚实后盾。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值