
#include <stdio.h>
#include <string.h>
#include "STC12C5A60S2.h"

//! 服务器IP地址与端口号,注意,用户需要将此IP替换为
//! 自己服务器的公网IP地址
#define TCPIP_SERVER_IPADDR "115.171.51.103"
#define TCPIP_SERVER_PORT   "8088"

//! 串口发送与接收缓冲区大小
#define TTY_MAX_BUFFER_SIZE 256
//! 串口发送与接收缓冲区
char ttyBuffer[TTY_MAX_BUFFER_SIZE];

//! TCPIP发送与接收缓冲区大小
#define TCPIP_MAX_BUFFER_SIZE 256 
//! TCPIP发送与接收缓冲区
char tcpipBuffer[TCPIP_MAX_BUFFER_SIZE];

//! 串口0初始化函数, 此串口用作接收终端控制命令
//! 晶振频率：22.1184MHz
//! 串口0波特率：9600
void Uart0_Init(void)   //9600bps@22.1184MHz
{
  PCON |= 0x80;       //使能波特率倍速位SMOD
  SCON = 0x50;        //8位数据,可变波特率
  AUXR |= 0x40;       //定时器1时钟为Fosc,即1T
  AUXR &= 0xfe;       //串口1选择定时器1为波特率发生器
  TMOD &= 0x0f;       //清除定时器1模式位
  TMOD |= 0x20;       //设定定时器1为8位自动重装方式
  TL1 = 0x70;         //设定定时初值
  TH1 = 0x70;         //设定定时器重装值
  ET1 = 0;            //禁止定时器1中断
  TR1 = 1;            //启动定时器1
}

//! 串口0字符串输出函数
//! 参数说明：pString为字符串缓冲区首地址
void Uart0_PutString(char* pString)
{ 
  unsigned short i = 0; 
  while(pString[i]) 
  {     
    SBUF = pString[i++];
    while(!TI);
    TI = 0;
  }
}

//! 串口0字符串读取函数, 获取一行数据, 遇到换行符为止
//! 参数说明：pBuffer为缓冲区首地址, nBufferLen为缓冲区大小, nTimeOut为超时时间
//!          如果nTimeOut=0, 那么函数会阻塞, 直到缓冲区满或遇到换行符
unsigned short Uart0_GetALine(char* pBuffer, unsigned char nBufferLen, unsigned char nTimeOut)
{
  char ch = 0;
  unsigned int i = 0, j = 0, k = 0;

  k = 20000*nTimeOut;
  for(i = 0, j = 0; i < nBufferLen; i++)
  {
    while(1)
    {
      if(RI)
      {
        RI = 0;         //清除接收完成标志
        pBuffer[i] = SBUF;
        //! 回显给终端显示
        SBUF = pBuffer[i];
        while(!TI);
        TI = 0;
        if(pBuffer[i] == 0x0d)
        {  
          pBuffer[i] = 0x00;
          return i;
        }
        break;
      }
      else if(nTimeOut == 0)
        continue;
      else
        j++;

      if(j == k)
        break;
    }
  }

  return i;
}

//! 串口1初始化函数, 此串口用作控制GSM模块
//! 晶振频率：22.1184MHz
//! 串口1波特率：9600
void Uart1_Init(void)   //9600bps@22.1184MHz
{
  AUXR |= 0x08;  //使能波特率倍速位S2SMOD
  S2CON = 0x50;  //8位数据,可变波特率
  BRT = 0x70;    //设定独立波特率发生器重装值
  AUXR |= 0x04;  //独立波特率发生器时钟为Fosc,即1T
  AUXR |= 0x10;  //启动独立波特率发生器
}

//! 串口1字符串输出函数
//! 参数说明：pString为字符串缓冲区首地址
//! 备注：此函数一方面向串口1发送数据,
//!       另一方面也向串口0发送数据,
//!       目的是为了方便调试
void Uart1_PutString(char* pString)
{ 
  unsigned char i = 0;

  //! 向串口1写数据
  i = 0;
  while(pString[i])
  {     
    //! 向串口0写数据,目的是方便调试
    SBUF = pString[i];
    while(!TI);
    TI = 0;

    S2BUF = pString[i++];
    while(!(S2CON&S2TI));
    S2CON &= ~S2TI;
  }
}

/**
 * @func Uart1_GetString
 * @author SwanTech (2011/12/14)
 * @param pBuffer 缓冲区地址
 * @param nBufferLen 缓冲区长度
 * @param nTimeOut 读取返回数据的超时时间
 * @return unsigned short 成功: 返回接收到的字节数. 失败: 返回-1
 * @remark 注意nTimeOut超时时间从接收到第一个字符开始计数
 */
unsigned short Uart1_GetString(char* pBuffer, unsigned short nBufferLen, unsigned short nTimeOut)
{
  unsigned short i = 0, j = 0, k = 0;

  //! 此函数固定的超时时间,也就是说如果根本就
  //! 没有应答数据时,函数经过这个固定超时时间会返回
  const unsigned short nFixedTimeout = 65500;

  for(i = 0; (i < nFixedTimeout && k == 0); i++)
  {
    for(j = 0, k = 0; j < nTimeOut; j++)
    {
      if(S2CON & S2RI)
      {
        S2CON &= ~S2RI;
        pBuffer[k++] = S2BUF;

        SBUF = S2BUF; //! 向串口0写数据,目的是方便调试
        while(!TI);
        TI = 0;

        if(k == 1) //! 应答数据第一次到来,重新计算超时值
          j = 0;
        else if(k+1 == nBufferLen) //! 字符串缓冲区已满
          break;
      }
    }
  }
  pBuffer[k] = 0x00; //! 字符串必须以0x00结束

  return k;
}

void SwanTech_LogoDisplay(void)
{
  Uart0_PutString("\n\r+------------------------------+\n\r");
  Uart0_PutString("|      #鸿鹄电子科技#          |\n\r");
  Uart0_PutString("|  http://swantech.taobao.com  |\n\r");
  Uart0_PutString("+------------------------------+\n\r");
  Uart0_PutString("|     TCPIP功能测试程序        |\n\r");
  Uart0_PutString("|    适用平台:STC12C5A60S2     |\n\r");
  Uart0_PutString("+------------------------------+\n\r");

}
void SwanTech_CommandDisplay(void)
{
  Uart0_PutString("\n\r+------------------------------+\n\r");
  Uart0_PutString(" 1: 开启TCPIP网络功能\n\r");
  Uart0_PutString(" 2: 连接服务器\n\r");
  Uart0_PutString(" 3: 发送数据(仅发送)\n\r");
  Uart0_PutString(" 4: 发送数据并等待应答\n\r");
  Uart0_PutString(" 5: 断开与服务器之间的连接\n\r");
  Uart0_PutString(" 6: 关闭TCPIP网络功能\n\r");
  Uart0_PutString("+SwanTech>");
}

/**
 * @brief TCPIP协议栈配置
 * @author SwanTech (2011/12/12)
 * @param 
 */
char SwanTech_TCPIP_Config(void)
{
  //! 下面是配置过程
  //! AT
  Uart1_PutString("AT\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 60000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::AT Command Exec failed.\n\r");
    return -1;
  }

  //! ATE0 [关闭回显]
  Uart1_PutString("ATE0\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::AT Command Exec failed.\n\r");
    return -1;
  }

  //! AT+CIPSHUT [防止上次使用过程中没有关闭网络功能,尝试关闭网络功能]
  //! 注意,此条命令执行时间较长,大概2秒左右才可以关闭网络功能
  //! 所以等待应答的时间较长
  Uart1_PutString("AT+CIPSHUT\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "SHUT OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::关闭网络功能失败.\n\r");
    return -1;
  }

  //! AT+CIPMUX [设置为单连接模式]
  Uart1_PutString("AT+CIPMUX=0\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::设置为单连接模式失败.\n\r");
    return -1;
  }

  //! AT+CIPRXGET [配置为手动获取网络数据]
  Uart1_PutString("AT+CIPRXGET=1\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::配置为手动获取网络数据失败.\n\r");
    return -1;
  }
  
  //! AT+CIPQRCLOSE [配置为加速远程断开连接]
  Uart1_PutString("AT+CIPQRCLOSE=1\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::配置为加速远程断开连接失败.\n\r");
    return -1;
  }

  //! AT+CIPMODE [配置为非透明传输模式]
  Uart1_PutString("AT+CIPMODE=0\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Config::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Config::配置为非透明传输模式失败.\n\r");
    return -1;
  }

  return 0;
}

/**
 * @brief 连接服务器
 * @author SwanTech (2011/12/12)
 * @param 
 */
char SwanTech_TCPIP_Connect(void)
{
  //! AT+CIPSTART [准备连接服务器]
  sprintf(ttyBuffer, "AT+CIPSTART=\"TCP\",\"%s\",%s\x0D\x0A", TCPIP_SERVER_IPADDR, TCPIP_SERVER_PORT);
  Uart1_PutString(ttyBuffer);
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Connect::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Connect::准备连接服务器失败.\n\r");
    return -1;
  }

  //! 判断是否连接已经建立
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Connect::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "CONNECT OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Connect::连接服务器失败.\n\r");
    return -1;
  }

  return 0;
}

/**
 * @brief 断开与服务器的连接
 * @author SwanTech (2011/12/12)
 * @param 
 */
char SwanTech_TCPIP_DisConnect(void)
{
  //! AT+CIPCLOSE [断开连接]
  sprintf(ttyBuffer, "AT+CIPCLOSE=1\x0D\x0A");
  Uart1_PutString(ttyBuffer);
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_DisConnect::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "CLOSE OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_DisConnect::断开连接失败.\n\r");
    return -1;
  }

  return 0;
}

/**
 * @brief 关闭网络功能
 * @author SwanTech (2011/12/12)
 * @param 
 */
char SwanTech_TCPIP_NETShut(void)
{
  //! AT+CIPSHUT [关闭网络功能]
  sprintf(ttyBuffer, "AT+CIPSHUT\x0D\x0A");
  Uart1_PutString(ttyBuffer);
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_NETShut::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "SHUT OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_NETShut::关闭网络功能失败.\n\r");
    return -1;
  }

  return 0;
}

/**
 * @brief SIM900_TCPIP数据发送函数
 * @author SwanTech (2011/12/12)
 * @param pBuffer: 数据缓冲区地址
 * @param nBufferLen: 数据长度
 */
short SwanTech_TCPIP_Send(char* pBuffer, unsigned short nBufferLen)
{
  //! 请求发送数据
  //! AT+CIPSEND
  sprintf(ttyBuffer, "AT+CIPSEND=%d\x0D\x0A", nBufferLen);
  Uart1_PutString(ttyBuffer);
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Send::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, ">") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Send::请求发送数据失败.\n\r");
    return -1;
  }

  //! 发送数据
  Uart1_PutString(pBuffer);
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 1000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Send::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "SEND OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Send::发送数据失败.\n\r");
    return -1;
  }

  return nBufferLen;
}

/**
 * @brief SIM900_TCPIP数据接收函数
 * @author SwanTech (2011/12/12)
 * @param pBuffer: 数据缓冲区地址
 * @param nBufferLen: 缓冲区大小
 */
short SwanTech_TCPIP_Recv(char* pBuffer, unsigned short nBufferLen)
{
  //! 判断应答数据到来标志[+CIPRXGET:1]
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 10000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Recv::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "+CIPRXGET:1") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Recv::获取应答数据标志失败.\n\r");
    return -1;
  }

  //! 读取应答数据
  Uart1_PutString("AT+CIPRXGET=2,128\x0D\x0A");
  if(Uart1_GetString(ttyBuffer, TTY_MAX_BUFFER_SIZE, 30000) == 0)
  {
    Uart0_PutString("SwanTech_TCPIP_Recv::Uart1_GetString::failed.\n\r");
    return -1;
  }
  if(strstr(ttyBuffer, "OK") == NULL) //! 没有找到命令成功执行的结果,函数返回,否则命令执行成功
  {
    Uart0_PutString("SwanTech_TCPIP_Recv::读取应答数据失败.\n\r");
    return -1;
  }

  return 1;
}

void SwanTech_CommandMonitor(void)
{
  unsigned char bFinishConfig = 0;
  unsigned char bFinishConnect = 0;
  char buffer[3] = {0};

  while(1)
  {
    Uart0_GetALine(buffer, 2, 0);
    //! 如果连续收到2个0x7F,那么认为是STC-ISP正在请求下载程序
    //! 这时候启动系统复位,从ISP监控程序重新引导
    if(buffer[0] == 0x7F && buffer[1] == 0x7F)
      IAP_CONTR = 0x60;
   
    Uart0_PutString("\n\r+------------------------------+\n\r");
    if(buffer[0] == '1')
    {
      if(SwanTech_TCPIP_Config() == -1)
      {  
        bFinishConfig = 0;  //! 配置失败的标志
        Uart0_PutString("\n\r+开启TCPIP网络功能失败!\n\r");
      }
      else
      {  
        bFinishConfig = 1;  //! 配置成功的标志
        Uart0_PutString("\n\r+开启TCPIP网络功能成功!\n\r");
      }
    }
    else if(buffer[0] == '2')
    {
      if(bFinishConfig == 0) //! 如果没有开启TCPIP网络功能,那么返回失败
        Uart0_PutString("\n\r+请先开启TCPIP网络功能!\n\r");
      else if(SwanTech_TCPIP_Connect() == -1)
      { 
        bFinishConnect = 0;  //! 连接失败的标志
        Uart0_PutString("\n\r+连接服务器失败!\n\r");
      }
      else
      {
        bFinishConnect = 1;  //! 连接成功的标志
        Uart0_PutString("\n\r+连接服务器成功!\n\r");
      }
    }
    else if(buffer[0] == '3')
    {
      strcpy(tcpipBuffer, "鸿鹄电子科技. Http://swantech.taobao.com/");
      if(bFinishConnect == 0) //! 如果成功连接到服务器,那么返回失败
        Uart0_PutString("\n\r+请先连接服务器!\n\r");
      else if(SwanTech_TCPIP_Send(tcpipBuffer, strlen(tcpipBuffer)) == -1)
        Uart0_PutString("\n\r+发送数据失败!\n\r");
      else
        Uart0_PutString("\n\r+发送数据成功!\n\r");
    }
    else if(buffer[0] == '4')
    {
      strcpy(tcpipBuffer, "鸿鹄电子科技. Http://swantech.taobao.com/");
      if(bFinishConnect == 0) //! 如果成功连接到服务器,那么返回失败
        Uart0_PutString("\n\r+请先连接服务器!\n\r");
      else
      {
        if(SwanTech_TCPIP_Send(tcpipBuffer, strlen(tcpipBuffer)) == -1)
          Uart0_PutString("\n\r+发送数据失败!\n\r");
        else
          Uart0_PutString("\n\r+发送数据成功!\n\r");

        Uart0_PutString("\n\r+等待服务器应答......\n\r");

        if(SwanTech_TCPIP_Recv(tcpipBuffer, TCPIP_MAX_BUFFER_SIZE) == -1)
          Uart0_PutString("\n\r+接收应答数据失败!\n\r");
        else
          Uart0_PutString("\n\r+接收应答数据成功!\n\r");
      }
    } 
    else if(buffer[0] == '5')
    {
      if(bFinishConnect == 0) 
        Uart0_PutString("\n\r+连接还没有建立,请先建立与服务器之间的连接!\n\r");
      else if(SwanTech_TCPIP_DisConnect() == -1)
        Uart0_PutString("\n\r+断开与服务器之间的连接失败!\n\r");
      else 
        Uart0_PutString("\n\r+断开与服务器之间的连接成功!\n\r");
    }
    else if(buffer[0] == '6')
    {
      if(SwanTech_TCPIP_NETShut() == -1)
        Uart0_PutString("\n\r+关闭TCPIP网络功能失败!\n\r");
      else 
        Uart0_PutString("\n\r+关闭TCPIP网络功能成功!\n\r");
    }

    SwanTech_CommandDisplay();
  }
}

void main(void)
{
  Uart0_Init();
  Uart1_Init();

  while(1)
  {
    if(RI)
    {
      RI = 0;
      SwanTech_LogoDisplay();
      SwanTech_CommandDisplay();
      break;
    }
  }

  while(1) SwanTech_CommandMonitor();

}


