zoukankan      html  css  js  c++  java
  • android之WIFI小车编程详述

    有了前几篇wifi模块eps8266的使用,单片机设置eps8266程序,android TCP客户端,现在就做一个wifi小车

    先上图

    小车是四个轮子的,每个轮子上都有电机驱动,前进后退的时候四个轮子同时前进和后退,转弯的时候,小车两边的轮子按反方向转。

    为了达到更好的操作效果(一直按下前进,小车前进,按下左右转小车左右转,松开左右转,小车继续前进。松开前进,小车停止。后退同理),在单片机程序里加入了前进或后退的标志位。先说明一下,,,,,,

    按下前进向单片机发送‘0’,按下后退向单片机发送‘1’,按下左转向单片机发送‘2’,按下右转向单片机发送‘3’,松开前进或后退向单片机发送‘5’,松开左转或右转向单片机发送‘6’,这样子发数据也是为了获得更好的操作体验

    前进 后退 左转 右转按钮是使用的setOnTouchListener方法,以便在按钮按下或松开时发送数据,

    就看一下前进代码

    我在前面声明了一下

    //前进,关于OnTouchListener的使用,,找度娘,我也是找的度娘,不要偷懒呦

     //前进
        private OnTouchListener forwordButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN://如果按下
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("0".getBytes());//发送0
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP://如果松开
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("5".getBytes());//发送‘5’
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
    //源码
    package com.wifi_Contrl;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    
    import android.annotation.SuppressLint;
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.MenuItem;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.View.OnTouchListener;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    
    @SuppressLint("ClickableViewAccessibility") public class MainActivity extends Activity {
    
        boolean isConnect=true;//连接还是断开
        Button connectButton;//定义连接按钮
        Button forwordButton;//定义前进按钮
        Button backButton;//定义后退按钮
        Button leftButton;//定义左转按钮
        Button righButton;//定义右转按钮
        EditText ipEditText;//定义ip输入框
        EditText portText;//定义端口输入框
        Socket socket = null;//定义socket
        private InputStream inputStream=null;//定义输入流
        private OutputStream outputStream=null;//定义输出流
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            
            connectButton = (Button) findViewById(R.id.btConnect);
            forwordButton = (Button) findViewById(R.id.btqianjin);
            backButton = (Button) findViewById(R.id.bthoutui);
            leftButton = (Button) findViewById(R.id.btzuozhuan);
            righButton = (Button) findViewById(R.id.btyuozhuan);
            ipEditText = (EditText) findViewById(R.id.etIP);
            portText = (EditText) findViewById(R.id.etPort);
            
            connectButton.setOnClickListener(connectButtonListener);
            forwordButton.setOnTouchListener(forwordButtonTouch);
            backButton.setOnTouchListener(backButtonTouch);
            leftButton.setOnTouchListener(leftButtonTouch);
            righButton.setOnTouchListener(righButtonTouch);
           
        }
        //连接
        private OnClickListener connectButtonListener = new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                if (isConnect == true) //标志位 = true表示连接
                {
                    isConnect = false;//置为false
                    connectButton.setText("断开");//按钮上显示--断开
                    //打开连接线程
                    Connect_Thread connect_Thread = new Connect_Thread();
                    connect_Thread.start();
                }
                else //标志位 = false表示退出连接
                {
                    isConnect = true;//置为true
                    connectButton.setText("连接");//按钮上显示连接
                    Toast.makeText(MainActivity.this,"已退出连接!", Toast.LENGTH_SHORT).show();
                    try 
                    {
                        socket.close();//关闭连接
                        socket=null;
                    } 
                    catch (IOException e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        };
        //前进
        private OnTouchListener forwordButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("0".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("5".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //后退
        private OnTouchListener backButtonTouch = new OnTouchListener() {
                
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    // TODO Auto-generated method stub
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        try 
                        {
                            //获取输出流
                            outputStream = socket.getOutputStream();
                            //发送数据
                            //outputStream.write(msgEditText.getText().toString().getBytes());
                            outputStream.write("1".getBytes());
                        } 
                        catch (Exception e) 
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        break;
                    case MotionEvent.ACTION_UP:
                        try 
                        {
                            //获取输出流
                            outputStream = socket.getOutputStream();
                            //发送数据
                            //outputStream.write(msgEditText.getText().toString().getBytes());
                            outputStream.write("5".getBytes());
                        } 
                        catch (Exception e) 
                        {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    default:
                        break;
                    }
                    return false;
                }
        };
        //左转
        private OnTouchListener leftButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("2".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("6".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //右转
        private OnTouchListener righButtonTouch = new OnTouchListener() {
            
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("3".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    try 
                    {
                        //获取输出流
                        outputStream = socket.getOutputStream();
                        //发送数据
                        //outputStream.write(msgEditText.getText().toString().getBytes());
                        outputStream.write("6".getBytes());
                    } 
                    catch (Exception e) 
                    {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                default:
                    break;
                }
                return false;
            }
        };
        //连接线程
        class Connect_Thread extends Thread//继承Thread
        {
            public void run()//重写run方法
            {
                try 
                {
                    if (socket == null) 
                    {
                        //用InetAddress方法获取ip地址
                        InetAddress ipAddress = InetAddress.getByName(ipEditText.getText().toString());
                        int port =Integer.valueOf(portText.getText().toString());//获取端口号 
                        socket = new Socket(ipAddress, port);//创建连接地址和端口    
                        if (socket !=null) {
                            runOnUiThread(new Runnable()
                            {
                                public void run() 
                                {    
                                    // TODO Auto-generated method stub
                                    Toast.makeText(MainActivity.this,"已成功连接!", Toast.LENGTH_SHORT).show();
                                }                        
                            });
                        }
                    }    
                } 
                catch (Exception e) 
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
    //布局源码,大神勿喷,小弟才入门android,所以关于布局还,,,,,
    <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/holo_purple"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        tools:context="com.wifi_Contrl.MainActivity" >
    
        <!-- IP地址 : -->
        <TextView
            android:id="@+id/tvIP"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="IP地址 :"
            android:textSize="23dp" 
            android:layout_x="0dp"
            android:layout_y="0dp"
            />
            
        <!-- 左转 -->
        <Button
            android:id="@+id/btzuozhuan"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_x="400dp"
            android:layout_y="118dp"
            android:text="左转" />
    
        <!-- 右转 -->
        <Button
            android:id="@+id/btyuozhuan"
            android:layout_width="wrap_content"
            android:layout_height="80dp"
            android:layout_x="520dp"
            android:layout_y="118dp"
            android:text="右转" />
    
        <!-- 后退 -->
    
        <Button
            android:id="@+id/bthoutui"
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:layout_x="105dp"
            android:layout_y="200dp"
            android:text="后退" />
    
        <!-- 前进 -->
        <Button
            android:id="@+id/btqianjin"
            android:layout_width="wrap_content"
            android:layout_height="90dp"
            android:layout_marginBottom="21dp"
            android:layout_x="105dp"
            android:layout_y="65dp"
            android:text="前进" />
        
        <!-- 连接 -->
        <Button
            android:id="@+id/btConnect"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:layout_marginBottom="21dp"
            android:layout_x="500dp"
            android:text="连接" />
    
        <!-- 端口号 : -->
        <TextView
            android:id="@+id/tvPort"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_x="280dp"
            android:layout_y="0dp"
            android:text="端口号 :"
            android:textSize="23dp" />
    
        <!-- 输入端口地址的文本控件 -->
        <EditText
            android:id="@+id/etPort"
            android:layout_width="70dp"
            android:layout_height="30dp"
            android:layout_x="380dp"
            android:layout_y="0dp"
            android:background="@android:color/white"
            android:ems="10"
            android:text="8080" />
    
        <!-- 输入ip地址的文本控件 -->
    
        <EditText
            android:id="@+id/etIP"
            android:layout_width="150dp"
            android:layout_height="30dp"
            android:layout_x="100dp"
            android:layout_y="0dp"
            android:background="@android:color/white"
            android:ems="10"
            android:text="192.168.4.1" >
    
            <requestFocus />
        </EditText>
    
    </AbsoluteLayout>

    再看单片机,因为学实时操作系统UCOSII的时候,写程序就养成了这样写程序习惯,如果对于这样

    #ifndef _USART_C_//如果没有定义_USART_C_
    #define _USART_ex_ extern
    #else
    #define _USART_ex_
    #endif

    _USART_ex_ unsigned char Usart_Receive[20];
    _USART_ex_ unsigned char Usart_Cnt;
    _USART_ex_ bit Usart_AT_flage;
    _USART_ex_ bit Command_Flag;
    _USART_ex_ unsigned char UsartData;
    _USART_ex_ void InitUART(void);//串口初始化
    _USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据
    _USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止

    其实这样写,有助于各个c文件之间调用变量。说一下

    #ifndef _USART_C_//如果没有定义_USART_C_
    #define _USART_ex_ extern//就定义_USART_ex_ 为extern
    #else//否则
    #define _USART_ex_就定义_USART_ex_为空
    #endif

    如果是自身文件编译由于我在USART.C文件的开头加上了#define _USART_C_所以,就定义_USART_C_为空

    即   unsigned char Usart_Receive[20];

    如果别的文件编译那么因为别的文件没有定义#define _USART_C_ 所以就定义_USART_ex_ 为extern

    extern  unsigned char Usart_Receive[20];

    对于extern  这应该不陌生吧,好了接着往下看,

    不好意思再啰嗦下,我把所有的.h文件全放在了一个.h文件中,这样在每个c文件的开头只需加上#include "include.h"就方便多了

    #define _MAIN_C_
    #include "include.h"
    
    sbit a1 = P1^0;//前左轮前进
    sbit a2 = P1^1;//前左轮后退
    sbit a3 = P1^2;//前右轮前进
    sbit a4 = P1^3;//前右轮后进
    sbit a5 = P1^4;//后左轮前进
    sbit a6 = P1^5;//后左轮后退
    sbit a7 = P1^6;//后右轮前进
    sbit a8 = P1^7;//后右轮后进
    
    bit forword_flag=0;
    bit back_flag=0;
    
    unsigned char CWMODE[]="AT+CWMODE=2
    "; //设置模块的工作的模式为AP模式
    unsigned char RST[]="AT+RST
    "; //重启模块使AT+CWMODE=2模式生效
    unsigned char CIPMUX[]="AT+CIPMUX=1
    "; //启动多连接
    unsigned char CIPSERVER[]="AT+CIPSERVER=1,8080
    ";//开启服务器模式,端口号8080
    
    
    void delay1s(void) //误差 -0.00000000024us
    {
     unsigned char a,b,c;
     for(c=95;c>0;c--)
    for(b=26;b>0;b--)
    for(a=185;a>0;a--);
    }
    
    //多连接AP模式
    void ManyConnect_AP()
    {
        P0=0x00;
        while(1)
        {
        UartSends(CWMODE);//返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x01;
        break;
        } 
        }
     }
        UartSends(RST);//返回一大溜,不用判断返回
    delay1s();
        delay1s();
        while(1)
        {
        UartSends(CIPMUX);//返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x03;
        break;
        } 
        }
     }
        while(1)
        {
        UartSends(CIPSERVER);//返回ok,多了也返回ok
        delay1s();
        if(Usart_AT_flage ==1)
        {
        if(strstr(Usart_Receive, "OK") )
        {
        Usart_AT_flage = 0;
        P0 = 0x07;
        break;
        } 
        }
     }
    }
    
    void main()
    {
        InitUART();
        while(1)
        {
        ManyConnect_AP();//多连接AP模式
    while(1)
        {
        //由于消息的开头是+IP 故做此判断
    if((Usart_Receive[0]=='+')&&(Usart_Receive[1]=='I')&&(Usart_Receive[2]=='P'))
        {
        if((Usart_Receive[3]=='D')&&(Usart_Receive[6]==','))
        {
        if(Usart_Receive[9]=='0')//前进
    {
    forword_flag = 1;//前进标志位置一
    back_flag = 0; //后退标志位置零
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后进
    /*sbit a1 = P1^0;//前左轮前进
    sbit a2 = P1^0;//前左轮后退
    sbit a3 = P1^1;//前右轮前进
    sbit a4 = P1^2;//前右轮后进
    sbit a5 = P1^3;//后左轮前进
    sbit a6 = P1^0;//后左轮后退
    sbit a7 = P1^0;//后右轮前进
    sbit a8 = P1^1;//后右轮后进*/
    
        }
    if(Usart_Receive[9]=='1')//后退
    {
    forword_flag = 0;//前进标志位置一
    back_flag = 1; //后退标志位置零
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后进
    }
    if(Usart_Receive[9]=='6')//左右转停止
    {
    if(forword_flag == 1 && back_flag == 0)//上一次按下的是前进,没松开
    {
        //前进
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后进
    }
    if(forword_flag == 0 && back_flag == 1)//上一次按下的是后退,没松开
    {
        //后退
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后进
    }
    if(forword_flag == 0 && back_flag == 0)//上一次松开了前进或后退
    {
        //停止
    a1 = 0;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 0;//后右轮后进
    }
        }
    if(Usart_Receive[9]=='2')//左转
    {
    a1 = 0;//前左轮前进
    a2 = 1;//前左轮后退
    a3 = 1;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 1;//后左轮后退
    a7 = 1;//后右轮前进
    a8 = 0;//后右轮后退
    }
    if(Usart_Receive[9]=='3')//右转
    {
    a1 = 1;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 1;//前右轮后进
    a5 = 1;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 1;//后右轮后退
    }
    if(Usart_Receive[9]=='5')//停止
    {
    forword_flag = 0;//前进标志位置零
    back_flag = 0; //后退标志位置零
    a1 = 0;//前左轮前进
    a2 = 0;//前左轮后退
    a3 = 0;//前右轮前进
    a4 = 0;//前右轮后进
    a5 = 0;//后左轮前进
    a6 = 0;//后左轮后退
    a7 = 0;//后右轮前进
    a8 = 0;//后右轮后进
    }
        }
        }
        }
        }
    }

    #define _USART_C_
    #include "include.h"
    unsigned char Usart_Receive[20]={0};
    unsigned char Usart_Cnt=0;
    bit Usart_AT_flage;
    bit flage;
    bit Command_Flag;
    void InitUART(void)
    {
        TMOD = 0x20;
        SCON = 0x50;
        TH1 = 0xFD;
        TL1 = TH1;
        PCON = 0x00;
        EA = 1;
        ES = 1;
        TR1 = 1;
    }
    
    void SendOneByte(unsigned char c)
    {
            SBUF = c;
            while(!TI);
            TI = 0;    
    }
    
    //串行口连续发送char型数组,遇到终止号/0(空格)将停止
    void UartSends(unsigned char *str)
    {
        while(*str!='')
        {
            SBUF=*str;
            while(!TI);//等待发送完成信号(TI=1)出现
            TI=0;
            str++;
        }
    }
    
    void UARTInterrupt(void) interrupt 4
    {
        RI=0;
        Usart_Receive[Usart_Cnt]=SBUF;//接收串口数据
        Usart_Cnt++;//
        //返回数据以回车结尾,有回车,而且数据个数大于2,说明接收到了数据
        if(Usart_Receive[Usart_Cnt-2]=='
    ' && Usart_Receive[Usart_Cnt-1]=='
    ' && Usart_Cnt >= 2)
        {
            Usart_Cnt = 0;//接收数据计数清零
            Usart_AT_flage = 1;//数据接收成功标志位
      }
        else if(Usart_Cnt > 20)//
        {
            Usart_Cnt = 0;
        }    
    }

     

    #ifndef __USART_H_
    #define __USART_H_
    
    
    #ifndef _USART_C_
    #define _USART_ex_ extern
    #else
    #define _USART_ex_
    #endif
    
    _USART_ex_ unsigned char Usart_Receive[20];
    _USART_ex_ unsigned char Usart_Cnt;
    _USART_ex_ bit Usart_AT_flage;
    _USART_ex_ bit Command_Flag;
    _USART_ex_ unsigned char UsartData;
    _USART_ex_ void InitUART(void);//串口初始化
    _USART_ex_ void SendOneByte(unsigned char c);//发送字节型数据
    _USART_ex_ void UartSends(unsigned char *str);//串行口连续发送char型数组,遇到终止号/0将停止
    #endif

    #include <REGX52.H>
    #include "USART.h"
    #include <string.h>

    下载好程序,接好线,等一会用手机连接就好了,连接成功会显示连接成功

    eps8266说是3.3v供电因为我手头没有降压模块也没有二极管所以就直接接的5v供电,不过没有烧,正常工作,就是摸上去有点热。其实程序还有点不够可靠,以后再改进

  • 相关阅读:
    【Mybatis源码解析】Mybatis的日志系统
    20200728
    【Mybatis源码解析】-Configuration
    【日志】怎么打印日志
    【OOM】几种常见的OOM异常
    树 [虚树, 动态规划]
    最大公约数 [动态规划]
    送分题 [组合计数]
    LCM [树状数组, HH的项链]
    AT1219 歴史の研究 [回滚莫队]
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/5220919.html
Copyright © 2011-2022 走看看