android安卓月光宝盒项目源码技术讲解

月光宝盒游戏机大家都了解,但是里面开发流程指导的人比较少,去年本人有幸接到过这样一个项目,研发月光宝盒游戏机。 在过去几年这边积累了非常多的模拟器开发资源。下面是淘宝上一款月光宝盒机器,实际上目前有几个大厂在做,淘宝上爆款一看就了解,我的客户机器比这个还要大一些,需要投币。

android安卓月光宝盒项目源码技术讲解_第1张图片

 

可以在网盘下载,app体验:https://pan.baidu.com/s/1c2BdnPY 

软件分为2个部分:输入装置+游戏机APP+输出装置。这样就组成一个游戏机系统。

输入装置: 这里主要是按键摇杆, 客户的按键是通过串口实现的,需要我自己去读串口发到我的APP中。

而且客户为了怕设备被破解,串口通信还加了密,真是坑爹啊。

 

游戏机APP:这里使用的是我 这边街机pro专业版游戏机模拟器,支持拳皇97 98等8000多个游戏。 通过修改,去掉游戏机里面触摸按键,介入上面说的游戏按键。

 

输出装置:输出装置就是显示器和声音。这些都是走的安卓系统通用api。不需要特殊处理。

 

 

这里先贴出串口处理的部分代码:,一般来说摇杆按键走的串口,一般需要经过加密,不然太容易破解了:别人可能盗走你的游戏主板去硬件山寨出一个跟你一模一样的东西。所以这就要涉及加密了。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "SerialPort.h"
#include "miyao.h"

#include "android/log.h"
static const char *TAG="serial_port";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO,  TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
#define IsLock 1

//下函数由叶先生实现

/*需要在JNI中实现如下函数功能函数

函数功能:将OStar_msg结构加密后转化成字节。
函数目的:(用于java层调用后获得返回字节结果,java层将直接写入到串口。)
char * MsgToByte(OStar_msg msg)


函数功能:将字节添加到缓冲区。 若成功返回1,若缓冲区满返回0
函数目的:(用于java层从串口获得字节后调用它将字节保存到缓冲区)
int MsgCacheOffer(char * byte)


函数功能:将从缓冲区取出24个有效数据返回,若无返回NULL。(函数需要校验 直到成功取出正确数据)
函数目的:(用于java层调用后,直接从串口取出正确数据)
OStar_msg MsgPoll()

*/

//下函数由softboy实现

/*
需要在JNI中实现 Java 层接口函数:

函数功能:将java层函数数据转化成 OStar_msg
函数目的:调用MsgToByte转成成字节返回给java。用于发送。调用 MsgToByte();
JNIEXPORT jbyteArray JNICALL Java_org_winplus_serial_utils_SerialPort_msg2byte
  (JNIEnv *env, jobject thiz,jint msg1,jint msg2,jint msg3)

函数功能:将java层从串口读出的字节调用MsgCacheOffer 写入到缓冲区
函数目的:java层串口读取字节 ,调用 MsgCacheOffer();
JNIEXPORT jbyteArray JNICALL Java_org_winplus_serial_utils_SerialPort_msg2cache
  (JNIEnv *env, jobject thiz,jbyteArray bytes)

函数功能:将java层从串口读出的字节调用MsgCacheOffer 写入到缓冲区
函数目的:java串口读取有效数据 ,调用 MsgPoll()
JNIEXPORT jobject JNICALL Java_org_winplus_serial_utils_SerialPort_msg2java
  (JNIEnv *env, jobject thiz)

*/

static speed_t getBaudrate(jint baudrate)
{
	switch (baudrate)
	{
		case 0: return B0;
		case 50: return B50;
		case 75: return B75;
		case 110: return B110;
		case 134: return B134;
		case 150: return B150;
		case 200: return B200;
		case 300: return B300;
		case 600: return B600;
		case 1200: return B1200;
		case 1800: return B1800;
		case 2400: return B2400;
		case 4800: return B4800;
		case 9600: return B9600;
		case 19200: return B19200;
		case 38400: return B38400;
		case 57600: return B57600;
		case 115200: return B115200;
		case 230400: return B230400;
		case 460800: return B460800;
		case 500000: return B500000;
		case 576000: return B576000;
		case 921600: return B921600;
		case 1000000: return B1000000;
		case 1152000: return B1152000;
		case 1500000: return B1500000;
		case 2000000: return B2000000;
		case 2500000: return B2500000;
		case 3000000: return B3000000;
		case 3500000: return B3500000;
		case 4000000: return B4000000;
		default: return B9600;
	}
}

typedef unsigned long  u32;
typedef unsigned short u16;
typedef unsigned char  u8;

#define JIAOME_LEN 18 //加密长度

typedef struct CMD_group1
{
	u8 CMD;
	u8 rand1;
}CMD_group;

typedef struct OStar_msg1
{
	union
	{
		u8 tbyte[16];
		u16  tword[8];
		u32 tdword[4];
	}data;
	CMD_group CMD_g;
	struct
	{
		u8 xuliehao1;
		u8 xuliehao2;
		u8 verify;
		u8 Align[3];
	}verf;
}OStar_msg;


typedef union
{
	long d32;
	char d8[4];
}U32data;

long Big_Lit_chang_32(long dat)
{
	U32data a,b;
	a.d32=dat;
	b.d8[0]=a.d8[3];
	b.d8[1]=a.d8[2];
	b.d8[2]=a.d8[1];
	b.d8[3]=a.d8[0];
	return b.d32;   
}

typedef union
{
	unsigned short d16;
	unsigned char d8[2];
}U16data;

unsigned short Big_Lit_chang_16(unsigned short dat)
{
	U16data a,b;
	a.d16=dat;
	b.d8[0]=a.d8[1];
	b.d8[1]=a.d8[0];    
	return b.d16;
}

#define GetItemSum( XX )	(sizeof(XX)/sizeof(XX[0]))

#define	R_PUSH_BUFF_INT(_NAME, XXX)	do{\
	_NAME ## _flag ++; _NAME ## _buff[_NAME ## _in] = XXX;	\
	if(_NAME ## _in >= GetItemSum(_NAME ## _buff)-1) _NAME ## _in = 0;	\
	else _NAME ## _in++;}while(0)

#define	R_POP_BUFF_INT(_NAME, XXX) do{	\
	XXX = _NAME ## _buff[_NAME ## _out];	\
		_NAME ## _flag --;	\
	if(_NAME ## _out >= GetItemSum(_NAME ## _buff) -1)	_NAME ## _out =0; \
	else _NAME ## _out++;}while(0)

#define MAX_BUFF 512

u32 USART_rece_in=0;
u32 USART_rece_out=0;
u32 USART_rece_flag=0;
u8  USART_rece_buff[MAX_BUFF];

u32 usart_err=0;
int MsgCacheOffer(char *byte,int len)
{   
	int i = 0;
	for (i=0;i=MAX_BUFF)
		{
			usart_err++;
			LOGD("jni MsgCacheOffer called errors:%d",usart_err);
			return 0;   
		}
		R_PUSH_BUFF_INT(USART_rece,(byte[i]&0xff));
	}
	return len;
}

void OutdataToBuff(u8 *dat,u32 len)
{
	u8 i;
	for (i=0;iGetStringUTFChars(env, path, &iscopy);
		LOGD("Opening serial port %s with flags 0x%x", path_utf, O_RDWR | flags);
		fd = open(path_utf, O_RDWR | flags);
		LOGD("open() fd = %d", fd);
		(*env)->ReleaseStringUTFChars(env, path, path_utf);
		if (fd == -1)
		{
			/* Throw an exception */
			LOGE("Cannot open port");
			/* TODO: throw an exception */
			return NULL;
		}
	}

	/* Configure device */
	{
		struct termios cfg;
		LOGD("Configuring serial port");
		if (tcgetattr(fd, &cfg))
		{
			LOGE("tcgetattr() failed");
			close(fd);
			/* TODO: throw an exception */
			return NULL;
		}

		cfmakeraw(&cfg);
		cfsetispeed(&cfg, speed);
		cfsetospeed(&cfg, speed);

		if (tcsetattr(fd, TCSANOW, &cfg))
		{
			LOGE("tcsetattr() failed");
			close(fd);
			/* TODO: throw an exception */
			return NULL;
		}
	}
	static_fd = fd;

	/* Create a corresponding file descriptor */
	{
		jclass cFileDescriptor = (*env)->FindClass(env, "java/io/FileDescriptor");
		jmethodID iFileDescriptor = (*env)->GetMethodID(env, cFileDescriptor, "", "()V");
		jfieldID descriptorID = (*env)->GetFieldID(env, cFileDescriptor, "descriptor", "I");
		mFileDescriptor = (*env)->NewObject(env, cFileDescriptor, iFileDescriptor);
		(*env)->SetIntField(env, mFileDescriptor, descriptorID, (jint)fd);
	}

	dpclazz_key= (*env)->FindClass(env,"org/winplus/serial/utils/SerialPort");
	if (dpclazz_key==0)
	{
		LOGD("find class error");
		return;
	}
	method_key = (*env)->GetStaticMethodID(env,dpclazz_key,"onKey","(III)V");
	if (method_key==0)
	{
		LOGD("find onKeyValue error");
		return;
	}


	return mFileDescriptor;
}

/*
 * Class:     cedric_serial_SerialPort
 * Method:    close
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_org_winplus_serial_utils_SerialPort_close
(JNIEnv *env, jobject thiz)
{
	jclass SerialPortClass = (*env)->GetObjectClass(env, thiz);
	jclass FileDescriptorClass = (*env)->FindClass(env, "java/io/FileDescriptor");

	jfieldID mFdID = (*env)->GetFieldID(env, SerialPortClass, "mFd", "Ljava/io/FileDescriptor;");
	jfieldID descriptorID = (*env)->GetFieldID(env, FileDescriptorClass, "descriptor", "I");

	jobject mFd = (*env)->GetObjectField(env, thiz, mFdID);
	jint descriptor = (*env)->GetIntField(env, mFd, descriptorID);
	static_fd = -1;
	inited = -1;
	LOGD("close(fd = %d)", descriptor);
	close(descriptor);
}

JNIEXPORT void  JNICALL Java_org_winplus_serial_utils_SerialPort_msg2cache
(JNIEnv *env, jobject thiz,jbyteArray pcmData,jint len){
	jbyte *pcm;
	jboolean isCopy = 0;
	pcm = (*env)->GetByteArrayElements(env,pcmData, 0);
	int ret = MsgCacheOffer(pcm,len);
	//LOGD("jni msg2cache len:%d",ret);
	(*env)->ReleaseByteArrayElements(env,pcmData, pcm, JNI_ABORT);
}

int PortSend(int fdcom, char *data, int datalen) 
{ 
	return write(fdcom, data, datalen);
} 

enum CMD_2android //stm发给android
{
	CMD_OStar_Key = 0xA1,
	CMD_OStar_TuiB = 0x5f,
	CMD_OStar_GetInfo = 0x12,
	CMD_OStar_ErrorInfo = 0x11,
	CMD_OStar_ShakeHand = 0x23,
	CMD_OStar_BackFlsh,
	CMD_OStar_BackOK,
};

enum CMD_2STM32	//android发给stm
{
	CMD2STM32_tuiBi,
	CMD2STM32_tuiCP,
	CMD2STM32_GetMacInfo,
	CMD2STM32_ResetSTM,
	CMD2STM32_ShakeHand,
	CMD2STM32_Ask_ShakeHand,
	CMD2STM32_AskFlsh,
	CMD2STM32_SaveOneFlsh,
	CMD2STM32_TuiBPinit,
	CMD2STM32_end = 0xff
};


const u32 MaskBits[32]
={
	0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,
	(0x1UL<<8), (0x1UL<<9), (0x1UL<<10), (0x1UL<<11),
	(0x1UL<<12), (0x1UL<<13), (0x1UL<<14), (0x1UL<<15),
	(0x1UL<<16), (0x1UL<<17), (0x1UL<<18), (0x1UL<<19),
	(0x1UL<<20), (0x1UL<<21), (0x1UL<<22), (0x1UL<<23),
	(0x1UL<<24), (0x1UL<<25), (0x1UL<<26), (0x1UL<<27),
	(0x1UL<<28), (0x1UL<<29), (0x1UL<<30), (0x1UL<<31),
};


#define KeyDowndelay 1
#define KeyUpdelay   1
#define MAX_SLAVE 2




	int OTHER_KEY_START = 15;

	int FUNC_KEY_START = 20;

	enum
	{
		MenuKey_None,
		MenuKey_Down,
		MenuKey_OK,
		MenuKey_SGame,
		MenuKey_Right,
		MenuKey_Left,
		MenuKey_No,
		MenuKey_Up,
		MenuKey_Count,
	};

	u8 meun_key_flag=0Xff;
	u8 meun_key=0Xff;

	#define MenuKeyDownDelay 1
	#define MenuKeyUpDelay 3

	u8 meunkeydelay[8];
	void DealMeunKey(JNIEnv *env, jobject thiz)
	{
		u8 i,newflag,oldflag;
		for (i=0;iMenuKeyDownDelay)
					{
						meunkeydelay[i]=0;
						meun_key_flag&=~MaskBits[i];
						//有键按下
					 LOGD("jni DealMeunKey 1 CMD_OStar_Key down:%d ",i);
					 (*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,i+FUNC_KEY_START,1,0);

					}
				} else
				{
					if (meunkeydelay[i]>MenuKeyUpDelay)
					{
						meunkeydelay[i]=0;
						meun_key_flag|=MaskBits[i];
						//按键弹起
						 LOGD("jni DealMeunKey 1 CMD_OStar_Key down:%d ",i);
					    (*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,i+FUNC_KEY_START,0,0);
					}
				}
			} else
			{
				meunkeydelay[i]=0;
			}
		}
	}




enum
{
	play_start,
	play_button3,
	play_button1,
	play_button2,
	play_right,
	play_left,
	play_down,
	play_up,
	play_button4,
	play_button5,
	play_button6,
	play_cnt,
};



u16 orgKeyflag[MAX_SLAVE] ={ 0xffff, 0xffff};
u16 doKeyflag[MAX_SLAVE] = { 0xffff, 0xffff};
u16 Key_delay[MAX_SLAVE][play_cnt] = { 0, 0};

void Do_Key(JNIEnv *env, jobject thiz)
{
	int i, id, orgflag, doflag;
	for (id = 0; id KeyDowndelay)
					{
						Key_delay[id][i] = 0;
						doKeyflag[id] &= ~MaskBits[i];
						//按键按下
						LOGD("jni Do_Key 1 CMD_OStar_Key down:%d ,player is:%d",i,id);
						(*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,i,1,id);
					}
				} else
				{
					if (Key_delay[id][i]>KeyUpdelay)
					{
						Key_delay[id][i] = 0;
						doKeyflag[id] |= MaskBits[i];
						//按键弹起
						LOGD("jni Do_Key 1 CMD_OStar_Key up:%d ,player is:%d",i);
						(*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,i,0,id);
					}
				}
			} else
			{
				Key_delay[id][i] = 0;
			}
		}
	}
}

//投币数
int ToubiCnt[MAX_SLAVE]={0,0};

void dealMsg(OStar_msg  msg,JNIEnv *env, jobject thiz){
	unsigned int i=0;
	jclass dpclazz;jmethodID method;    
	LOGD("jni dealMsg called get msg,cmd:%d,errors:%d",msg.CMD_g.CMD,usart_err);
	OStar_msg data;
	int id=0;
	switch (msg.CMD_g.CMD)
	{
		case CMD_OStar_ShakeHand:
			inited = 0;
			memset((unsigned char* )&data,0,sizeof(data));
			data.data.tdword[0]=msg.data.tdword[0];
			data.CMD_g.CMD=CMD2STM32_ShakeHand;
			MsgToByteAndWrite(data,static_fd);
			LOGD("jni dealMsg  CMD_OStar_ShakeHand static_fd %d",static_fd);
			break;
		case CMD_OStar_Key:
			orgKeyflag[0]=msg.data.tbyte[0];
			orgKeyflag[1]=msg.data.tbyte[1];

			if (msg.data.tbyte[6]&MaskBits[0])orgKeyflag[0]|=MaskBits[8];
			else orgKeyflag[0]&=~MaskBits[8];

			if (msg.data.tbyte[6]&MaskBits[1])orgKeyflag[1]|=MaskBits[8];
			else orgKeyflag[1]&=~MaskBits[8];
			if (msg.data.tbyte[6]&MaskBits[2])orgKeyflag[0]|=MaskBits[9];
			else orgKeyflag[0]&=~MaskBits[9];
			if (msg.data.tbyte[6]&MaskBits[3])orgKeyflag[0]|=MaskBits[10];
			else orgKeyflag[0]&=~MaskBits[10];
			if (msg.data.tbyte[6]&MaskBits[4])orgKeyflag[1]|=MaskBits[9];
			else orgKeyflag[1]&=~MaskBits[9];
			if (msg.data.tbyte[6]&MaskBits[5])orgKeyflag[1]|=MaskBits[10];
			else orgKeyflag[1]&=~MaskBits[10];
			Do_Key(env,thiz);

			for (id=0;id0)
				{
					//正在投币中
					ToubiCnt[id]+=msg.data.tbyte[7+id];
					LOGD("jni dealMsg  coin player: %d , total:%d ,add:%d",id,ToubiCnt[id],msg.data.tbyte[7+id]);
					(*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,OTHER_KEY_START,msg.data.tbyte[7+id],id);
				}
			}
			meun_key = msg.data.tbyte[13];
			DealMeunKey(env,thiz);
			break;
		case CMD_OStar_GetInfo:
			LOGD("jni dealMsg  CMD_OStar_GetInfo 0 %d",msg.data.tdword[0]);
			LOGD("jni dealMsg  CMD_OStar_GetInfo 1 %d",msg.data.tdword[1]);
			LOGD("jni dealMsg  CMD_OStar_GetInfo 2 %d",msg.data.tdword[2]);
			LOGD("jni dealMsg  CMD_OStar_GetInfo 3 %d",msg.data.tdword[3]);
			break;

		case CMD_OStar_ErrorInfo:

			for (id=0;idCallStaticVoidMethod(env,dpclazz_key,method_key,OTHER_KEY_START+1,0,0);
				} else
				{
					//清除投币固障
					(*env)->CallStaticVoidMethod(env,dpclazz_key,method_key,OTHER_KEY_START+2,0,0);
				}

			}
			break;
	}
}

JNIEXPORT jobject JNICALL Java_org_winplus_serial_utils_SerialPort_msg2java
(JNIEnv *env, jobject thiz){
	MsgPoll(env,thiz);
}

JNIEXPORT jint JNICALL Java_org_winplus_serial_utils_SerialPort_msginit
(JNIEnv *env, jobject thiz){
	OStar_msg  data;
	memset((unsigned char* )&data,0,sizeof(data));
	if (inited == 0)
	{
		LOGD("jni msginit called CMD2STM32_GetMacInfo");    
		data.CMD_g.CMD=CMD2STM32_GetMacInfo;
		MsgToByteAndWrite(data,static_fd);
		inited = 1; 
	} else if (inited == -1)
	{
		LOGD("jni msginit called CMD2STM32_Ask_ShakeHand");
		data.CMD_g.CMD = CMD2STM32_Ask_ShakeHand;
		MsgToByteAndWrite(data,static_fd);
	} else if (inited == 1)
	{
	}
	//LOGD("jni msginit called %d:",inited);
	return inited;
}

 

 

 

你可能感兴趣的:(源码分享)