【Gokit】从0开始实现智能插座(PCB、源码等开源)
本帖最后由 Genius 于 2016-8-29 15:06 编辑【开源硬件】机智云智能硬件创新大赛http://club.gizwits.com/thread-2646-1-1.html
原创**:如需转载,请注明来源:http://club.gizwits.com/thread-3029-1-1.html
原贴名称:基于 公版APP 机智云插座 从0开始 代码实现G
首先要感谢机智云给了我们这样一个可以实现想法的平台,如果没有机智云,我要实现这个功能,需要请做APP的同事做一款APP,还要请做云平台的同事做一个平台,自己还要云阿里注册一个账号购买一个云服务。如果把这些加起来,要请这个同事吃饭,那个同事吃饭,现实我的这个想法起码要超过1万元。在深圳会展中心了解到机智云后,这几天工作任务少,就进入这个平台学习了几天,打算从公版APP入手,为什么会选择智能云插座作为体验机智云平台呢?插座是生活中的必须品,需求还是很强的,当然还有智能灯也是。我自己的一个应用场景,现在广东天气这么热我每天晚上睡觉需要开空调,如果一直开着,到了早上会觉得有点冷,特别是有小孩的家庭。所以我希望到了凌晨3点之后关闭空调,同时又能自动打开风扇,让空气流通起来,我相信还是有很多朋友有跟我一样的想法,如果有,那就跟我一起解决生活中需要解决的问题吧,让想法照进现实。//-------------------------------------------{
共四大分部
第一部分:修改公版APP
第二部分:修改GOKIT MCU源码
第三部分:用GOKIT开发板验证功能
第四部分:用公模插座外壳做自己的智能插座
//--------------------------------------------}
第一部分
安装APP编译环境,这里只使用了安卓的环境,这一块我也不是很熟悉,从百度上了解到的。
五步搞定Android开发环境部署
//-----------------------------------------------------
第一步:安装JDKhttp://www.oracle.com/technetwork/java/javase/downloads/index.html
http://images.cnitblog.com/blog/50387/201410/191139466851148.png
JDK默认安装成功后,会在系统目录下出现两个文件夹,一个代表jdk,一个代表jre。
JDK的全称是Java SE Development Kit,也就是Java 开发工具箱。SE表示标准版。JDK是Java的核心,包含了Java的运行环境(Java Runtime Environment),一堆Java工具和给开发者开发应用程序时调用的Java类库
我们可以打开jdk的安装目录下的Bin目录,里面有许多后缀名为exe的可执行程序,这些都是JDK包含的工具。通过第二步讲到的配置JDK的变量环境,我们可以方便地调用这些工具及它们的命令。
http://images.cnitblog.com/blog/50387/201410/191141099825300.png
JDK包含的基本工具主要有:
javac:Java编译器,将源代码转成字节码。
jar:打包工具,将相关的类文件打包成一个文件。
javadoc:文档生成器,从源码注释中提取文档。
jdb:debugger,调试查错工具。
java:运行编译后的java程序。
//-----------------------------------------------------
第二步:配置Windows上JDK的变量环境
很多刚学java开发的人按照网上的教程可以很轻松配置好Windows上JDK的变量环境,但是为什么要这么配置并没有多想。
我们平时打开一个应用程序,一般是通过桌面的应用程序图标双击或单击系统开始菜单中应用程序的菜单链接,无论是桌面的快捷图标还是菜单链接都包含了应用程序的安装位置信息,打开它们的时候系统会按照这些位置信息找到安装目录然后启动程序
http://images.cnitblog.com/blog/50387/201410/191141424357718.png
知道了一个应用程序的安装目录位置,我们也可以通过命令行工具打开,如QQ的位置为:C:\Program Files (x86)\Tencent\QQ\QQProtect\Bin,QQ的应用程序名为为QQProtect.exe,那么我们打开命令行工具,然后进入到“C:\Program Files (x86)\Tencent\QQ\QQProtect\Bin”目录,再输入“QQProtect”,即可运行qq。
http://images.cnitblog.com/blog/50387/201410/191142031548889.png
如果我们希望打开命令行工具后,直接输入“QQProtect”就能启动qq程序,而不是每次都进入qq的安装目录再启动,这个时候可以通过配置系统环境变量Path来实现。右击“我的电脑”,选择“属性”,在打开窗口中点击左边的“高级系统设置”,出现“系统属性”窗口,在“高级”选项卡下面点击“环境变量”。
http://images.cnitblog.com/blog/50387/201410/191142544042565.png
编辑系统变量名“Path”,在“Path”变量(字符串内容)的后面追加qq的安装目录:;C:\Program Files (x86)\Tencent\QQ\QQProtect\Bin 注意追加的时候要在目录字符串的前面加个英文的分号;,英文分号是用来区分Path里面不同的路径。
http://images.cnitblog.com/blog/50387/201410/191143356696192.png
确定保存后,再回到命令窗口,不管在任何目录下,你只要输入qqprotect的命令,qq就会启动
http://images.cnitblog.com/blog/50387/201410/191144028577785.png
通过启动qq的例子,我们总结下:当要求系统启动一个应用程序时,系统会先在当前目录下查找,如果没有则在系统变量Path指定的路径去查找。前面我们说了JDK包含了一堆开发工具,这些开发工具都在JDK的安装目录下,为了方便使用这些开发工具,我们有必要把JDK的安装目录设置了系统变量。这就是为什么在Windows安装了JDK后需要设置JDK的bin目录为系统环境变量的原因。
为了配置JDK的系统变量环境,我们需要设置三个系统变量,分别是JAVA_HOME,Path和CLASSPATH。下面是这三个变量的设置防范。
JAVA_HOME
先设置这个系统变量名称,变量值为JDK在你电脑上的安装路径:C:\Program Files\Java\jdk1.8.0_20。创建好后则可以利用%JAVA_HOME%作为JDK安装目录的统一引用路径。
Path
PATH属性已存在,可直接编辑,在原来变量后追加:;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin 。
CLASSPATH
设置系统变量名为:CLASSPATH变量值为:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar 。
注意变量值字符串前面有一个"."表示当前目录,设置CLASSPATH 的目的,在于告诉Java执行环境,在哪些目录下可以找到您所要执行的Java程序所需要的类或者包。
配置环境变量其实还是经常看得到的。特别是一些大型软件
//----------------------------------------------------------
第三步: 下载安装Eclipse
Eclipse为Java应用程序及Android开发的IDE(集成开发环境)。Eclipse不需要安装,下载后把解压包解压后,剪切eclipse文件夹到你想安装的地方,打开时设置你的工作目录即可。
Eclipse的版本有多个,这里选择下载Eclipse IDE for Java EE Developers这个版本。
http://images.cnitblog.com/blog/50387/201410/191145119987863.png
//----------------------------------------------
第一部分:修改公版APP
第二部分:修改GOKIT MCU源码
第三部分:用GOKIT开发板验证功能
第四部分:用公模插座外壳做自己的智能插座
前面三个部分都有了。现在是要做最后的一个部分。根据公模外壳,画原理图,设计PCB,打样,焊接元器件,调试程序。出样品。这些过程。
前面几个步骤都做完了,但我自己还不能真正使用智能云插座去操作开与关。前面都是过程。最后实物需要第四部分完成。
如果看到这里,你产生了和我一样的想法,制作出实物来。那么我们可以一起去做。
我们就可以共同拥有它了。
外壳选择
PROTOCOL.h
#ifndef _PROTOCOL_H
#define _PROTOCOL_H
#include <stdio.h>
#include <stdbool.h>
#include <stm32f10x.h>
#define SoftAp_Mode 0x01
#define AirLink_Mode 0x02
#define MAX_P0_LEN 128 //p0数据最大长度
#define MAX_PACKAGE_LEN (MAX_P0_LEN*2) //数据缓冲区最大长度
#define MAX_RINGBUFFER_LEN MAX_PACKAGE_LEN//环形缓冲区最大长度
#define Max_UartBuf MAX_PACKAGE_LEN//串口数据缓冲区最大长度
#define PROTOCOL_DEBUG //调试通信数据信息宏开关
#define DEBUG //系统运行调试信息
#define Send_MaxTime 300
#define Send_MaxNum 3
#define PRO_VER "00000004"
#define P0_VER "00000004"
#define HARD_VER "02030100"
#define SOFT_VER "02030003"
#define PRODUCT_KEY "8a2d232e861e4de1843b7b827debe57d"//宠物屋PRODUCT_KEY717c14293174447eb27c90e084e46344
__packed typedef struct
{
uint8_t Message_Buf; //串口接收缓冲区
uint8_t Message_Len; //接受到的数据长度
} UART_HandleTypeDef;
/*命令码*/
typedef enum
{
Pro_W2D_GetDeviceInfo_Cmd = 0x01,
Pro_D2W__GetDeviceInfo_Ack_Cmd = 0x02,
Pro_W2D_P0_Cmd = 0x03,
Pro_D2W_P0_Ack_Cmd = 0x04,
Pro_D2W_P0_Cmd = 0x05,
Pro_W2D_P0_Ack_Cmd = 0x06,
Pro_W2D_Heartbeat_Cmd = 0x07,
Pro_D2W_heartbeatAck_Cmd = 0x08,
Pro_D2W_ControlWifi_Config_Cmd = 0x09,
Pro_W2D_ControlWifi_Config_Ack_Cmd = 0x0A,
Pro_D2W_ResetWifi_Cmd = 0x0B,
Pro_W2D_ResetWifi_Ack_Cmd = 0x0C,
Pro_W2D_ReportWifiStatus_Cmd = 0x0D,
Pro_D2W_ReportWifiStatus_Ack_Cmd = 0x0E,
Pro_W2D_ReportMCUReset_Cmd = 0x0F,
Pro_D2W_ReportMCUReset_Ack_Cmd = 0x10,
Pro_W2D_ErrorPackage_Cmd = 0x11,
Pro_D2W_ErrorPackage_Ack_Cmd = 0x12,
/*7.28*/
Pro_Get_Network_Time_Cmd =0x17,//获取网络时间
Pro_Get_Network_Time_Ack_Cmd =0x18,//回复获取网络时间
} Pro_CmdTypeDef;
typedef enum
{
SetLED_OnOff = 0x01,
SetLED_Color = 0x02,
SetLED_R = 0x04,
SetLED_G = 0x08,
SetLED_B = 0x10,
SetMotor = 0x20,
} Attr_FlagsTypeDef;
typedef enum
{
LED_OnOff = 0x00,
LED_OnOn = 0x01,
Time_OnOff = 0x00,
Time_OnOn = 0x02,
Week_OnOff = 0x00,
Week_OnOn = 0x04,
} LED_ColorTypeDef;
/************************************
* 重发机制结构体
**************************************/
__packed typedef struct
{
uint32_t SendTime;//重发的系统时间
uint8_t SendNum;//重发次数
uint8_t Flag;//1,表示有需要等待的ACK;0,表示无需要等待的ACK
uint16_t ResendBufLen;
uint8_t Cmd_Buff;//重发数据缓冲区
} Pro_Wait_AckTypeDef;
/************************************
* 协议标准头
**************************************/
__packed typedef struct
{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
} Pro_HeadPartTypeDef;
/************************************
* 4.1WiFi模组请求设备信息
**************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint8_t Pro_ver;
uint8_t P0_ver;
uint8_t Hard_ver;
uint8_t Soft_ver;
uint8_t Product_Key;
uint16_t Binable_Time;
uint8_t Sum;
} Pro_M2W_ReturnInfoTypeDef;
/************************************
* 协议通用数据帧(4.2、4.4、4.6、4.9、4.10)
************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint8_t Sum;
} Pro_CommonCmdTypeDef;
/************************************
* 4.3 设备MCU通知WiFi模组进入配置模式
**************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint8_t Config_Method;
uint8_t Sum;
} Pro_D2W_ConfigWifiTypeDef;
/************************************
* WiFi模组工作状态
************************************/
#define Wifi_SoftAPMode (uint8_t)(1<<0) //SoftAP
#define Wifi_StationMode (uint8_t)(1<<1) //Station
#define Wifi_ConfigMode (uint8_t)(1<<2) //
#define Wifi_BindingMode (uint8_t)(1<<3) //
#define Wifi_ConnRouter (uint8_t)(1<<4) //
#define Wifi_ConnClouds (uint8_t)(1<<5) //Connect OK
/************************************
* 4.5 WiFi模组向MCU通知WiFi模组工作状态的变化
************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint16_t Wifi_Status;
uint8_t Sum;
} Pro_W2D_WifiStatusTypeDef;
/************************************
* 4.13获取网络时间
************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint32_t other;
uint8_t Sum;
} Pro_W2D_GetTimeTypeDef;
/************************************
* 非法报文类型
************************************/
typedef enum
{
Error_AckSum = 0x01, //校验错误
Error_Cmd = 0x02, //命令码错误
Error_Other= 0x03, //其他
} Error_PacketsTypeDef;
/************************************
* 4.7 非法消息通知
************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
Error_PacketsTypeDef Error_Packets;
uint8_t Sum;
} Pro_ErrorCmdTypeDef;
/************************************
* P0 command 命令码
************************************/
typedef enum
{
P0_W2D_Control_Devce_Action = 0x01,
P0_W2D_ReadDevStatus_Action = 0x02,
P0_D2W_ReadDevStatus_Action_ACK = 0x03,
P0_D2W_ReportDevStatus_Action = 0X04,
} P0_ActionTypeDef;
/************************************
* P0报文标准头
**************************************/
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
P0_ActionTypeDef Action;
} Pro_HeadPartP0CmdTypeDef;
short exchangeBytes(short value);
uint8_t CheckSum( uint8_t *buf, int packLen );
void GizWits_init(uint8_t P0_Len);
void GizWits_D2WResetCmd(void);
void GizWits_D2WGetCmd(void);//获取网络时间
void GizWits_D2WConfigCmd(uint8_t WiFi_Mode);
void GizWits_DevStatusUpgrade(uint8_t *P0_Buff, uint32_t Time, uint8_t flag);
void GizWits_WiFiStatueHandle(uint16_t wifiStatue);
u8 GizWits_MessageHandle(u8 * Message_Buf, u8 Length_buf);
#endif /*_PROTOCOL_H*/
/*****************************************************
* Function Name: GizWits_ControlDeviceHandle
* Description : Analy P0 Package根据数据有效位标志,进行控制
4.10 WiFi模组控制MCU
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ActionBit(1B)__attrFlags(1B)__attrValue(6B)__CheckSum(1B)
0xFFFF 0x000D 0x03 0x## 0x0000 0x01 标志位 控制值 0x##
MCU 回通用消息帧:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x04 0x## 0x0000 0x##
Bit0~5:LED_ONOFF, LED_Color, R,G,B, Motor_speed
WirteTypeDef_t{
uint8_t Attr_Flags; //信息位 是否有效的标志
uint8_t LED_Cmd;
uint8_t LED_R;
uint8_t LED_G;
uint8_t LED_B;
MOTOR_T Motor;
}
依靠接收的数据帧,存储到WirteTypeDef,再更改设备状态
*****************************************************/
void GizWits_ControlDeviceHandle()//WiFi模组控制MCU
{
//标志位 0位开关 共1个字节
if( (WirteTypeDef.Attr_Flags & (1<<0)) == (1<<0))//低位第0位ONOFF是否设置标志位7位
{
if((WirteTypeDef.LED_Cmd &(1<<0))== 0)
{
LED_RGB_Control(0,0,0);
LED_OFF(LED1);
ReadTypeDef.LED_Cmd &= ~(1<<0);//存储状态LED_OnOff a&=~(1<<i);//将a的bit i清0
printf("LED OFF \r\n");
}
if((WirteTypeDef.LED_Cmd &(1<<0))== (1<<0))
{
ReadTypeDef.LED_Cmd |= (1<<0);//LED_OnOn a|=1<<i;//将a的bit i置1
LED_ON(LED1);
LED_RGB_Control(254,0,0);//默认打开时,是红色
printf("LED ON \r\n");
}
}
//标志位是否启用定时器
if( (WirteTypeDef.Attr_Flags & (1<<1)) == (1<<1))//低位第1位Time_OnOff
{
if((WirteTypeDef.LED_Cmd & (1<<1))== 0)
{
//LED_RGB_Control(0,0,0);
LED_OFF(LED2);
ReadTypeDef.LED_Cmd &= ~(1<<1);//存储状态LED_OnOff a&=~(1<<i);//将a的bit i清0
printf("Time_OnOff OFF \r\n");
}
if((WirteTypeDef.LED_Cmd & (1<<1)) == (1<<1))
{
ReadTypeDef.LED_Cmd |= (1<<1);//LED_OnOn a|=1<<i;//将a的bit i置1
LED_ON(LED2);
//LED_RGB_Control(254,254,0);//
printf("Time_OnOff ON \r\n");
}
}
//标志位是否启用倒计时
if( (WirteTypeDef.Attr_Flags & (1<<2)) == (1<<2))
{
if((WirteTypeDef.LED_Cmd & (1<<2))== 0)
{
//LED_RGB_Control(0,0,0);
LED_OFF(LED3);
ReadTypeDef.LED_Cmd &= ~(1<<2);//存储状态LED_OnOff a&=~(1<<i);//将a的bit i清0
printf("Count_Down_OnOff OFF \r\n");
TIM_Cmd(TIM4,DISABLE);//失能TIMx外设
time_min = 0;
time_sec = 0;
min_flag = 0;
}
if((WirteTypeDef.LED_Cmd & (1<<2)) == (1<<2))
{
ReadTypeDef.LED_Cmd |= (1<<2);//LED_OnOn a|=1<<i;//将a的bit i置1
LED_ON(LED3);
//LED_RGB_Control(254,254,254);//
printf("Count_Down_OnOff ON \r\n");
CountDown_Minute_time=exchangeBytes(ReadTypeDef.CountDown_Minute);//重新给当前设置的值给倒计时
if(CountDown_Minute_time!=0)
{
TIM_Cmd(TIM4, ENABLE);//使能TIMx外设
}
}
}
//标志位是否重复星期
if( (WirteTypeDef.Attr_Flags & (1<<3)) == (1<<3))
{
ReadTypeDef.Week_Repeat=WirteTypeDef.Week_Repeat;
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
}
//标志位定时开机 注:时间以分钟为单位1小时=60分钟=0x3c 存储的是16进制
if( (WirteTypeDef.Attr_Flags & (1<<4)) == (1<<4))
{
printf("Time_On_Minute ON = %d \r\n",exchangeBytes(WirteTypeDef.Time_On_Minute));
if(exchangeBytes(WirteTypeDef.Time_On_Minute)<1441)
{
ReadTypeDef.Time_On_Minute=WirteTypeDef.Time_On_Minute;
CountDown_Time_On_Minute=exchangeBytes(ReadTypeDef.Time_On_Minute);//存储的是高低位改变过的
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
}
}
//标志位定时关机
if( (WirteTypeDef.Attr_Flags & (1<<5)) == (1<<5))
{
printf("Time_On_Minute OFF = %d \r\n",exchangeBytes(WirteTypeDef.Time_Off_Minute));
if(exchangeBytes(WirteTypeDef.Time_Off_Minute)<1441)
{
ReadTypeDef.Time_Off_Minute=WirteTypeDef.Time_Off_Minute;
CountDown_Time_Off_Minute=exchangeBytes(ReadTypeDef.Time_Off_Minute);//存储的是高低位改变过的
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
}
}
//标志位倒计时
if( (WirteTypeDef.Attr_Flags & (1<<6)) == (1<<6))
{
printf("CountDown_Minute T = %d \r\n",exchangeBytes(WirteTypeDef.CountDown_Minute));
if(exchangeBytes(WirteTypeDef.CountDown_Minute)<1441)
{
ReadTypeDef.CountDown_Minute=WirteTypeDef.CountDown_Minute;
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
CountDown_Minute_time=exchangeBytes(ReadTypeDef.CountDown_Minute);//当前设置的值给倒计时
if(((ReadTypeDef.LED_Cmd & (1<<2)) == (1<<2))&&(CountDown_Minute_time!=0))
{
time_min = 0;
time_sec = 0;
min_flag = 0;
TIM_Cmd(TIM4, ENABLE);//使能TIMx外设
}
}
}
}
/*****************************************************
* Function Name: GizWits_GatherSensorData();
* Description : Gather Sensor Data
* Input : None
* Output : None
* Return : None
* Attention : None
*****************************************************/
void GizWits_GatherSensorData(void)
{
// ReadTypeDef.Infrared = IR_Handle();
// DHT11_Read_Data(&curTem, &curHum);
// ReadTypeDef.Temperature = (curTem + lastTem) /2;
// ReadTypeDef.Humidity = (curHum + lastHum)/2;
// ReadTypeDef.Temperature = ReadTypeDef.Temperature + 13;//Temperature Data Correction//根据协议,矫正数据
// lastTem = curTem;
// lastHum = curHum;
}
/*****************************************************
* Function Name: KEY_Handle
* Description : Key processing function
* KEY1 短按 : None
* KEY1 长按 : None
* KEY2 短按 : SoftAP方式配置WiFi模组
* KEY2 长按 : AirLink方式配置WiFi模组
* 4.13获取网络时间
__packed typedef struct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint32_t other;
uint8_t Sum;
} Pro_W2D_GetTimeTypeDef;
*****************************************************/
void KEY_Handle(void)
{
uint8_t Key_return =0;
Key_return = ReadKeyValue();
if(Key_return & KEY_UP)
{
if(Key_return & PRESS_KEY1)//短按K1
{
#ifdef PROTOCOL_DEBUG
printf("KEY1 PRESS\r\n");
#endif
GizWits_D2WGetCmd();
}
if(Key_return & PRESS_KEY2)//短按K2
{
#ifdef PROTOCOL_DEBUG
printf("KEY2 PRESS ,Soft AP mode\r\n");
#endif
//Soft AP mode, RGB red
LED_RGB_Control(255, 0, 0);
GizWits_D2WConfigCmd(SoftAp_Mode);
NetConfigureFlag = 1;
}
}
if(Key_return & KEY_LONG)
{
if(Key_return & PRESS_KEY1)//长按K1
{
#ifdef PROTOCOL_DEBUG
printf("KEY1 PRESS LONG ,Wifi Reset\r\n");
#endif
GizWits_D2WResetCmd();//解绑WIFI
}
if(Key_return & PRESS_KEY2)//长按K2
{
//AirLink mode, RGB Green
#ifdef PROTOCOL_DEBUG
printf("KEY2 PRESS LONG ,AirLink mode\r\n");
#endif
LED_RGB_Control(0, 128, 0);
GizWits_D2WConfigCmd(AirLink_Mode);//进入AirLink_Mode模式
NetConfigureFlag = 1;
}
}
}
/*****************************************************
* Function Name: GizWits_WiFiStatueHandle
* Description : Callback function , Judge Wifi statue
* Input : None
* Output : None
* Return : Bit , Attr_Flags
* Attention :
*****************************************************/
void GizWits_WiFiStatueHandle(uint16_t wifiStatue)
{
if(((wifiStatue & Wifi_ConnClouds) == Wifi_ConnClouds) && (NetConfigureFlag == 1))
{
printf("W2M->Wifi_ConnClouds\r\n");
NetConfigureFlag = 0;
LED_RGB_Control(0,0,0);
}
}
/************* (C) COPYRIGHT 2011 STMicroelectronics ****END OF FILE***/
第四步:下载安装Android SDK
配置了JDK变量环境,安装好了Eclipse,这个时候如果只是开发普通的JAVA应用程序,那么Java的开发环境已经准备好了。我们要通过Eclipse来开发Android应用程序,那么我们需要下载Android SDK(Software Development Kit)和在Eclipse安装ADT插件,这个插件能让Eclipse和Android SDK关联起来。
Android SDK提供了开发Android应用程序所需的API库和构建、测试和调试Android应用程序所需的开发工具。
打开http://developer.android.com/sdk/index.html,我们发现google提供了集成了Eclipse的Android Developer Tools,因为我们这次是已经下载了Eclipse,所以我们选择单独下载Android SDK。
http://images.cnitblog.com/blog/50387/201410/200909055582129.jpg
下载后双击安装,指定Android SDK的安装目录,为了方便使用Android SDK包含的开发工具,我们在系统环境变量中的Path设置Android SDK的安装目录下的tools目录。
在Android SDK的安装目录下,双击“SDK Manager.exe”,打开Android SDK Manager,Android SDK Manage负责下载或更新不同版本的SDK包,我们看到默认安装的Android SDK Manager只安装了一个版本的sdk tools。
http://images.cnitblog.com/blog/50387/201410/191145438577396.png
打开Android SDK Manager,它会获取可安装的sdk版本,但是国内有墙,有时候会出现获取失败的情况。
http://images.cnitblog.com/blog/50387/201410/191146045912796.png
//这里要注意了,正常的网络我们是不能下载的,这里要翻墙才能正常下载。
我们可以下载 离线包安装。没有安装的是不能编译的。这一步是必须要做的,文件蛮大。刚开始我没有怎么理解,网上下载了一个几十MB的,根本没有。
将Android SDK Manage上的https请求改成http请求
打开Android SDK Manager,在Tools下的 Options 里面,有一项 Force https://..sources to be fetched using http://... 将这一项勾选上,就可以了。
http://images.cnitblog.com/blog/50387/201410/191147281387703.png
再打开Android SDK Manager.exe,正常情况下就可以下载Android的各个版本的sdk了。你只需要选择想要安装或更新的安装包安装即可。这里是比较耗时的过程,还会出现下载失败的情况,失败的安装包只需要重新选择后再安装就可以了。
http://images.cnitblog.com/blog/50387/201410/191147476856332.png
如果通过更改DNS也无法下载Android SDK,还有两个方法,第一个是自备梯子FQ,第二个是从这个网站上下载,下载的地址是:http://www.androiddevtools.cn/
//----------------------------------------------------
第五步:为Eclipse安装ADT插件
前面我们已经配置好了java的开发环境,安装了开发Android的IDE,下载安装了Android SDK,但是Eclipse还没有和Android SDK进行关联,也就是它们现在是互相独立的,就好比**和**分开了。为了使得Android应用的创建,运行和调试更加方便快捷,Android的开发团队专门针对Eclipse IDE定制了一个插件:Android Development Tools(ADT)。
下面是在线安装ADT的方法:
启动Eclipse,点击 Help菜单 -> Install New Software… ?,点击弹出对话框中的Add… 按钮。
http://images.cnitblog.com/blog/50387/201410/191148291238673.png
然后在弹出的对话框中的Location中输入:http://dl-ssl.google.com/android/eclipse/,Name可以输入ADT,点击“OK”按钮
http://images.cnitblog.com/blog/50387/201410/191148418108763.png
安装好后会要求你重启Eclipse,Eclipse会根据目录的位置智能地和它相同目录下Android sdk进行关联,如果你还没有通过sdk manager工具安装Android任何版本的的sdk,它会提醒立刻安装它们。
http://images.cnitblog.com/blog/50387/201410/191150000914250.png
在弹出的对话框选择要安装的工具,然后下一步就可以了http://images.cnitblog.com/blog/50387/201410/191149032942535.png
如果Eclipse没有自动关联Android sdk的安装目录,那么你可以在打开的Eclipse选择 Window -> Preferences ,在弹出面板中就会看到Android设置项,填上安装的SDK路径,则会出现刚才在SDK中安装的各平台包,按OK完成配置。
http://images.cnitblog.com/blog/50387/201410/191150132018510.png
到这里,我们在windows上的Android上的开发环境搭建就完成了,这时候,你用Eclipse的File——》New——》Project...新建一个项目的时候,就会看到建立Android项目的选项了。 http://images.cnitblog.com/blog/50387/201410/191150281858698.png
//-----------------------------------------------------------------
上面安装方法都是从网上找的。这里方便学习大家我转进来。
首先大家下载公版APP智能云插座的源代码 然后导入,再修改成与自己关联的。每个APP要包含自己的APPID PRODUCT_KEYAPP_SECRET,如果用我的APP是连接不上你的硬件产品的。https://git.oschina.net/dantang/Gizwits-SmartSocket_Android
解压之后把源码文件夹放到workspace文件夹里目录每个人安装路径不一样,结果也不一样,我的是C:\Users\JIPINZN\workspace导入刚下载的APP源码项目然后双击Existing Projectts into Workspace如果看到下面打抅,说明是有效的。可以导入
导入进来之后,第一步是要修改成自己的APPID PRODUCT_KEYAPP_SECRET
/** * app配置参数. * * @author Lien */public class Configs { /**设备名字符显示长度. */ public staticfinal int DEVICE_NAME_KEEP_LENGTH = 8; /**设定是否为debug版本. */ public staticfinal boolean DEBUG = true; /**设定AppID,参数为机智云官网中查看产品信息得到的AppID. */ public staticfinal String APPID = "a932138570e24574890c4032d20bb319"; /**指定该app对应设备的product_key,如果设定了过滤,会过滤出该peoduct_key对应的设备. */ public staticfinal String PRODUCT_KEY = "8a2d232e461e4de1843b7b827debe57d"; /**设定日志打印级别. */ public staticfinal XPGWifiLogLevel LOG_LEVEL = XPGWifiLogLevel.XPGWifiLogLevelAll; /**日志保存文件名. */ public staticfinal String LOG_FILE_NAME = "BassApp.log"; /** 产品密钥 */ public staticfinal String APP_SECRET = "532a1c88bb7f4dc2a13381791a666890";
}把自己的APPIDPRODUCT_KEYAPP_SECRET输入到里面这三个信息在机智云后台上找得到http://site.gizwits.com/zh-cn/developer/product 点机智云硬件接入,添加新应用
这样生成的APP,就可以连接到自己的硬件开发板上了。
上面主要是了解配置安卓编译环境,和修改APP几个主要的参数。下面我们要了解的是硬件。智能云插座是怎样工作的。MCU代码主要是机智云给出的。我只是在上面 把一个通用的代码变为配合公版APP智能云插座就能工作的一个过程。
首先下载GOKIT开发板代码http://site.gizwits.com/zh-cn/de ... hardware?type=GoKit
我这里使用的是版本号: 2.3.2更新时间: 2016.1.04 12:20
在我们去修改MCU代码之前,我想解释下这个插座的功能,虽然大家都知道,但我还是要结合APP讲一下操作过程
1.在我们拿到开发板,或者是智能云插座硬件时,第一步是连接WIFI网络。
按下开发板的KEY2键,用长按AIRLINK连接方式,绿灯长亮,说明是这个配置模式
这时,我们可以USB连接电脑,用串口工作查看打印出来的信息
//------------------------------------------
KEY2 PRESS LONG ,AirLink mode
MCU : ff ff069 27002 38
GAgentToMCU: ff ff05a 2700 36
ACK: SUCCESS! ...
Time:2016-7-29 16:51:27-5
GAgentToMCU: ff ff07d 75006e 9d
MCU : ff ff05e 7500 88
W2D_WifiStatusStruct.Wifi_Status=3590Time:2016-7-29 16:51:28-5
//------------------------------------------
KEY2 PRESS LONG ,AirLink mode 说明我们进行了长按操作并进入了AirLink mode
MCU : ff ff069 27002 38 前面是打印当前发数据时的系统时间 协议分析大家还是很容易理解的。
APP已经配置成功了。
这时我们看串口打印出来的信息
GAgentToMCU: ff ff07d 8c006 3a e0
MCU : ff ff05e 8c00 9f
GAgent就是WIFI模块,它向MCU发送了命令码为0X0D的WIFI状态变化指令。 6 3a 就是当前WIFI模块的状态,可以查协议得知具体是什么状态
按协议,MCU是要回复一个通用状态帧
W2M->Wifi_ConnClouds 打印出WIFI配置结束,
是下面这个函数里。
void GizWits_WiFiStatueHandle(uint16_t wifiStatue) { if(((wifiStatue & Wifi_ConnClouds) == Wifi_ConnClouds) && (NetConfigureFlag == 1)){printf("W2M->Wifi_ConnClouds\r\n");NetConfigureFlag = 0;LED_RGB_Control(0,0,0);}}如果WIFI连接到了网络。我们会发送一条获取网络时间的命令给WIFI,因为我们插座有一个定时 开与关的功能,只要获取一次就可以了,MCU自带RTC功能,时钟可以自己走。 MCU : ff ff05 17200 1e 申请获取网络时间GAgentToMCU: ff ff0 10 182007 e07 1d 116 28 57 9b 1c a0 22获取到的网络时间如果当前WIFI没有连接上路由,获取到的时间是1970年的。Time:2016-7-29 17:6:39-5这是解析出来显示的时间 年月日 ,时分秒 最后重要的是星期 因为我们APP里面要设置星期几执行开关功能。没有选中的星期几,不能执行开关动作。 year : month : day : hour : minute : second : 这里是RTC时钟显示的时间。APP上有一个是预约功能,一个是定时开关功能。我们使用的是两套计时方法。互相独立。上面解释的是一个APP登入的过程。MCU需要获取的数据协议里面的一些心跳,我们不用关心。
main.c
/**
**************************************
*
* @file main.c
* @author Gizwtis
* @version V2.3
* @date 2015-07-06
*
* @brief 机智云 只为智能硬件而生
* Gizwits Smart Cloudfor Smart Products
* 链接|增值|开放|中立|安全|自有|自由|生态
* www.gizwits.com
* APP打开,会发一条CMD03查询当前的状态命令ff ff0639002 14
回复 MCU : ff ff0 10490030000000000 20
ff ff0 104 230032 10 3c0000000 88
如果没有收到会等待查询很久,最后提示断开连
WIFI状态改变,会把时间信息给MCU,同时MCU打开自己的RTC进行时钟,没有网络的情况下,都能正常执行预约和定时开关
**************************************/
/* Includes ------------------------------------------------------------------*/
#include "gokit.h"
#include "rtc.h"
/*Global Variable*/
extern _calendar_obj calendar; //日历结构体
extern Pro_W2D_GetTimeTypeDef Pro_W2D_GetTimeStruct;//获取网络时间结构体
uint16_ttime_min;//分钟计时
uint32_ttime_sec;//秒种计时
uint8_t min_flag;//分钟到标志
uint16_t CountDown_Minute_time; //定时器存的时间当前剩余时间
uint16_t CountDown_Time_On_Minute; //存储定时开的时间
uint16_t CountDown_Time_Off_Minute; //存储定时关的时间
uint32_t ReportTimeCount = 0;//没用到
uint8_tgaterSensorFlag = 0; //MCU收集外设信息标志,每隔1s被TIM3中断函数置位一次
uint8_tSet_LedStatus = 0; //枚举量 方式更改等颜色,这种方式下更改IoE中颜色、或者开闭灯,无效。
uint8_tNetConfigureFlag = 0;//是否 打印WiFi配置结果 的标志
uint8_tcurTem = 0, curHum = 0;//DHT11数据
uint8_tlastTem = 0,lastHum = 0;
//注意是head指向了读区域,tail指向了写区域
//typedef struct {
// size_t rb_capacity;//缓冲区容量
// char*rb_head;//用于读出的指针
// char*rb_tail;//用于写入的指针
// charrb_buff;//缓冲区实体
//}RingBuffer;
extern RingBuffer u_ring_buff;
uint8_t p0Flag = 0;//WiFi控制设备命令,主要是CMD0X03已经下达的标志
WirteTypeDef_t WirteTypeDef; //WiFi发来的数据 MCU要接收 WIFI发过来的数据
ReadTypeDef_t ReadTypeDef; //WiFi要读取的数据 MCU要发送发给WIFI的数据 接收到的数据如果是U16以上要exchangeBytes函数转换
/**
* @briefMain program.
* @paramNone
* @retval None
*/
int main(void)
{
uint8_t p0_control_buf;//存储控制命令
SystemInit(); //开始初始化
HW_Init();
Printf_SystemRccClocks();
SW_Init();
while(1)
{
KEY_Handle(); //处理按键
GizWits_MessageHandle(p0_control_buf, sizeof(WirteTypeDef_t));//如果是控制命令,则把控制信息 放到p0_ctl_buf中
if(p0Flag == 1)//控制命令已经下达标志
{
//控制信息 转存到WirteTypeDef
memcpy((uint8_t *)&WirteTypeDef, p0_control_buf, sizeof(WirteTypeDef_t));
//靠WirteTypeDef来解析控制命令,控制设备
GizWits_ControlDeviceHandle();
//GizWits_DevStatusUpgrade(uint8_t *P0_Buff, uint32_t Time, uint8_t flag)
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);//flag=1,立即汇报
p0Flag =0;
}
//此标志每隔1s被TIM3中断函数置位一次
if(gaterSensorFlag != 0)
{
if((ReadTypeDef.LED_Cmd & (1<<1)) == (1<<1))//如果打开了定时功能才进入
{
if((ReadTypeDef.Week_Repeat & ( 1<<(calendar.week-1)))==( 1<<(calendar.week-1)))//先判断星期是否是设置的。然后判断小时,分钟
{
printf("t=%d",((calendar.hour*60)+calendar.min));
if(CountDown_Time_On_Minute==((calendar.hour*60)+calendar.min))//如果设置的小时数与现在的小时数相同 16进制表示
{
LED_RGB_Control(254,0,0);//默认打开时,是红色
}
if(CountDown_Time_Off_Minute==((calendar.hour*60)+calendar.min))
{
LED_RGB_Control(0,0,0);//关灯
}
}
}
GizWits_GatherSensorData(); //没有用到
gaterSensorFlag = 0;
}
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 0);//更新数据等待定时上报
//-----------------------------{
if(min_flag)//如果启用了预约功能
{
min_flag=0;
CountDown_Minute_time--;
if(CountDown_Minute_time<=0)//减到0
{
TIM_Cmd(TIM4,DISABLE);//失能TIMx外设
time_min = 0;
time_sec = 0;
CountDown_Minute_time = 0;
if((ReadTypeDef.LED_Cmd &(1<<0))== 0)
{
LED_RGB_Control(254,0,0);//打开时,是红色
LED_ON(LED1);
ReadTypeDef.LED_Cmd |= (1<<0);//LED_OnOn a|=1<<i;//将a的bit i置1如果以前是关的,现在要开
printf("TIME LED ON \r\n");
}
else if((ReadTypeDef.LED_Cmd &(1<<0))== (1<<0))
{
ReadTypeDef.LED_Cmd &= ~(1<<0);//存储状态LED_OnOff a&=~(1<<i);//将a的bit i清0如果以前是开的,现在要关
LED_OFF(LED1);
LED_RGB_Control(0,0,0);
printf("TIME LED OFF \r\n");
}
LED_OFF(LED3);
ReadTypeDef.LED_Cmd &= ~(1<<2);//预约时间已经到了,就要关闭预约开关
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
}
ReadTypeDef.CountDown_Minute=exchangeBytes(CountDown_Minute_time);
GizWits_DevStatusUpgrade((uint8_t *)&ReadTypeDef, 10*60*1000, 1);
}
//-----------------------------}
}
}
/** @addtogroup GizWits_HW_Init
* @{
*/
void HW_Init(void)
{
Delay_Init(72);
UARTx_Init();
RGB_KEY_GPIO_Init();
RGB_LED_Init();
LED_GPIO_Init();
KEY_GPIO_Init();
TIM3_Int_Init(7199,9); //ms interrupt
TIM4_Int_Init(10000,7199);//产生1s的定时TIM4_Int_Init(10000,7199);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
Motor_Init();
DHT11_Init();
IR_Init();
RTC_Init(); //RTC初始化
}
/** @addtogroup GizWits_SW_Init
* @{
*/
void SW_Init()
{
ReadTypeDef.LED_Cmd = 0;
ReadTypeDef.Week_Repeat = 0;
ReadTypeDef.Time_On_Minute = 0;
ReadTypeDef.Time_Off_Minute = 0;
ReadTypeDef.CountDown_Minute = 0;
GizWits_init(sizeof(ReadTypeDef_t));
printf("Gokit Init Ok ...\r\n");
}
/** @addtogroup Printf_SystemRccClocks
* @{
*/
void Printf_SystemRccClocks(void)
{
uint8_t SYSCLKSource;
RCC_ClocksTypeDefSystemRCC_Clocks;
printf("System start...\r\n");
SYSCLKSource = RCC_GetSYSCLKSource();
if(SYSCLKSource==0x04)
printf("SYSCLKSource is HSE\r\n");
else if(SYSCLKSource==0x00)
printf("SYSCLKSource is HSI\r\n");
else if(SYSCLKSource==0x08)
printf("SYSCLKSource is PL!\r\n");
RCC_GetClocksFreq(&SystemRCC_Clocks);
printf("SYS clock =%dMHz \r\n",(uint32_t)SystemRCC_Clocks.SYSCLK_Frequency/1000000);
printf("HCLK clock =%dMHz \r\n",(uint32_t)SystemRCC_Clocks.HCLK_Frequency/1000000);
printf("PCLK1 clock =%dMHz \r\n",(uint32_t)SystemRCC_Clocks.PCLK1_Frequency/1000000);
printf("PCLK2_clock =%dMHz \r\n",(uint32_t)SystemRCC_Clocks.PCLK2_Frequency/1000000);
printf("SADCCLK_Frequencyclock =%dMHz \r\n",(uint32_t)SystemRCC_Clocks.ADCCLK_Frequency/1000000);
}
gokit.h
#ifndef _GOKIT_H
#define _GOKIT_H
#include "stm32f10x.h"
#include "Hal_key/Hal_key.h"
#include "Hal_led/Hal_led.h"
#include "Hal_motor/Hal_motor.h"
#include "Hal_rgb_led/Hal_rgb_led.h"
#include "Hal_temp_hum/Hal_temp_hum.h"
#include "Hal_infrared/Hal_infrared.h"
#include "Hal_Usart/hal_uart.h"
#include "ringbuffer.h"
#include "Protocol.h"
#include <string.h>
//__packed typedef struct
//{
// uint8_t LED_Cmd;
// uint8_t LED_R;
// uint8_t LED_G;
// uint8_t LED_B;
// MOTOR_T Motor;
// uint8_t Infrared;
// uint8_t Temperature;
// uint8_t Humidity;
// uint8_t Alert;
// uint8_t Fault;
//}ReadTypeDef_t; //发送 发给WIFI的数据
__packed typedef struct //把里的数据返回给APP
{
uint8_t LED_Cmd;//开关,是否启用定时器
uint8_t Week_Repeat;//每周重复
uint16_t Time_On_Minute;//定时开机
uint16_t Time_Off_Minute; //定时 关机
uint16_t CountDown_Minute;//倒计时
uint16_t Power_Consumption;//能耗
}ReadTypeDef_t; //发送 发给WIFI的数据dev_status
//__packed typedef struct
//{
// uint8_t Attr_Flags;//信息位 是否有效的标志位
// uint8_t LED_Cmd;
// uint8_t LED_R;
// uint8_t LED_G;
// uint8_t LED_B;
// MOTOR_T Motor;
//
//}WirteTypeDef_t;
__packed typedef struct
{
uint8_t Attr_Flags;//信息位 是否有效的标志位
uint8_t LED_Cmd;
uint8_t Week_Repeat;//每周重复
uint16_t Time_On_Minute;//定时开机
uint16_t Time_Off_Minute; //定时 关机
uint16_t CountDown_Minute;//倒计时
uint16_t Power_Consumption;//能耗
}WirteTypeDef_t;//接收 WIFI发过来的数据
void HW_Init(void);
void Printf_SystemRccClocks(void);
void GizWits_GatherSensorData(void);
void GizWits_ControlDeviceHandle(void);
void SW_Init(void);
void KEY_Handle(void);
//void GizWits_WiFiStatueHandle(uint16_t wifiStatue);
#endif
Protocol.c 这个文件和MAIN.C是主要实现文件
/**
**************************************
*
* @file Protocol.c
* @author Gizwtis
* @version V2.3
* @date 2015-07-06
*
* @brief 机智云.只为智能硬件而生
* Gizwits Smart Cloudfor Smart Products
* 链接|增值ֵ|开放|中立|安全|自有|自由|生态
* www.gizwits.com
*
**************************************/
#include "stdio.h"
#include "stdbool.h"
#include "string.h"
#include "ringbuffer.h"
#include "Protocol.h"
#include "stm32f10x_usart.h"
#include "Hal_Usart/hal_uart.h"
#include "Hal_rgb_led/Hal_rgb_led.h"
#include "rtc.h"
extern uint16_t time_num; //预约用的定时时间
extern uint16_t min_num; //记录了多少分钟了
extern uint8_t dis_flag; //远程控制标志
Pro_W2D_GetTimeTypeDef Pro_W2D_GetTimeStruct;//获取网络时间结构体
//环形缓冲区
RingBuffer u_ring_buff;
//串口接收信息
//__packed typedef struct
//{
// uint8_t Message_Buf; //串口接收缓冲区
// uint8_t Message_Len; //接受到的数据长度
//} UART_HandleTypeDef;
UART_HandleTypeDef UART_HandleStruct;
//MCU设备信息
//__packed typedef struct
//{
// Pro_HeadPartTypeDef Pro_HeadPart;
// uint8_t Pro_ver;
// uint8_t P0_ver;
// uint8_t Hard_ver;
// uint8_t Soft_ver;
// uint8_t Product_Key;
// uint16_t Binable_Time;
// uint8_t Sum;
//} Pro_M2W_ReturnInfoTypeDef;
Pro_M2W_ReturnInfoTypeDef Pro_M2W_ReturnInfoStruct;
/*通用协议帧{
Pro_HeadPartTypeDef{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
uint8_t Sum;
}*/
Pro_CommonCmdTypeDef Pro_CommonCmdStruct;
/*重发机制结构体
uint32_t SendTime; //重发时记录的时间戳
uint8_t SendNum; //重发次数
uint8_t Flag; //1、作为需要等待WiFi应答的标志!!!!!
//2、这个标志位也限制MCU上报数据!!!!!
// 只要此标志置位,暂停上报
// 复位标志,则重新允许上报
uint16_t ResendBufLen;//长度
uint8_t Cmd_Buff; //重发数据缓冲区
*/
Pro_Wait_AckTypeDef Wait_AckStruct;
/*带ActionBit时的P0命令报文头
只有4.8WiFi读MCU 4.10WiFi控MCU的报文带ActionBit
Pro_HeadPartTypeDef{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
P0_ActionTypeDef Action;
*/
Pro_HeadPartP0CmdTypeDef Pro_HeadPartP0Cmd;
/*
Pro_HeadPartTypeDef{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
uint16_t Wifi_Status;
uint8_t Sum;
*/
Pro_W2D_WifiStatusTypeDef Pro_W2D_WifiStatusStruct;
/*由发送发给出,回复方原样返回即可*/
Pro_Wait_AckTypeDef Wait_AckStruct;
uint8_t SN; //程序中的SN,瞎写的,看来不影响报文通信
//ReadTypeDef是WiFi读设备时,读取的数据
//ReadTypeDef值存放至此数组
uint8_t g_DevStatus;
uint8_t g_P0DataLen;
uint32_t SystemTimeCount;//系统时间计数 TIM3 1毫秒级中断
uint32_t Last_ReportTime;//用来记录"上一次上报Dev状态"的时间戳
uint32_t Last_Report_10_Time;//用来记录"每隔十分钟,定期上报Dev状态"的时间戳。此标志处理的不当bug
uint8_t timeoutFlag = 0;//Read error package , timeoutFlag 1//没用到
/*环形缓冲区,全局变量*/
uint8_t packageFlag = 0;
uint16_t dataLen = 0;
uint16_t count = 0;
uint8_t tmp_buf = {0};
uint8_t lastValue = 0;
uint8_t curValue = 0;
//以Pro_开头,表示协议处理函数
static uint8_t GizWits_W2D_AckCmdHandle(void);
static void Pro_W2D_GetMcuInfo(void);
static void Pro_W2D_CommonCmdHandle(void);
static void Pro_W2D_WifiStatusHandle(void);
static void Pro_W2D_GetTimeHandle(void);//获取网络时间函数
static void Pr0_W2D_RequestResetDeviceHandle(void);
static void Pro_W2D_ReadDevStatusHandle(void);
static void Pro_D2W_ReportDevStatusHandle(void);
static void Pro_UART_SendBuf(uint8_t *Buf, uint16_t PackLen, uint8_t Tag);
static uint8_t GizWits_W2D_AckCmdHandle(void);
static void Pro_W2D_ErrorCmdHandle(Error_PacketsTypeDef errorType);
static uint8_t Pro_GetFrame(void);
static uint8_t GizWits_D2W_Resend_AckCmdHandle(void);
extern uint8_t p0Flag ;//WiFi控制命令【4.10】已经下达的标志
/************************ 重发机制 ******************************
* Wait_AckStruct.Flag 是需要等待WiFi应答的标志
* Wait_AckStruct当中,保存了需要重发的报文
************************************************************/
static uint8_t GizWits_D2W_Resend_AckCmdHandle(void)
{
if(Wait_AckStruct.Flag == 1)
{
/*重发次数小于两次*/
if(Wait_AckStruct.SendNum < Send_MaxNum)
{
if((SystemTimeCount - Wait_AckStruct.SendTime) > Send_MaxTime)//到达重发时间
{
Pro_UART_SendBuf((uint8_t *)&Wait_AckStruct.Cmd_Buff, Wait_AckStruct.ResendBufLen, 0);
#ifdef DEBUG
printf("Send again\r\n");
#endif
Wait_AckStruct.SendTime = SystemTimeCount;//赋值新的系统时间
Wait_AckStruct.SendNum++;//重发次数加1
return 2;
}
}
/*重发两次,不再发送此报文*/
else
{
memset(&Wait_AckStruct, 0, sizeof(Wait_AckStruct)); //Wait_AckStruct.Flag = 0;收到Ack或重发了两次时,清空此Flag位
return 1;
}
}
return 0;
}
/************************** 判断ACK **************************
* 需要等待Ack的地方:
* MCU主动上报信息后
* MCU通知WiFi模块配网后
* MCU通知WiFi模块重启后
**********************************************************/
static uint8_t GizWits_W2D_AckCmdHandle(void)
{
Pro_HeadPartTypeDef * Wait_Ack_HeadPart = (Pro_HeadPartTypeDef *)Wait_AckStruct.Cmd_Buff;
Pro_HeadPartTypeDef * Recv_HeadPart = (Pro_HeadPartTypeDef *)UART_HandleStruct.Message_Buf;
if(Wait_AckStruct.Flag == 1)
{
/*判断收到的报文命令码和报文序号,是否是需要等到的ACK*/
/*Ack信息的Cmd字段,总是比发送方的Cmd字段多1*/
if((Wait_Ack_HeadPart->Cmd == (Recv_HeadPart->Cmd - 1)) && (Wait_Ack_HeadPart->SN == Recv_HeadPart->SN))
{
memset(&Wait_AckStruct, 0, sizeof(Wait_AckStruct)); //Wait_AckStruct.Flag = 0;收到Ack或重发了两次时,清空此Flag位
return 0; //允许重新reprot //检查Ack成功,返回0
}
}
return 1;
}
/*****************************************************
* Function Name: UART_SendBuf
* Description : 向串口发送数据帧
* Input : buf:数据起始地址;
packLen:数据长度;
tag=0,不等待ACK;tag=1,等待ACK;
需要等待Ack的地方:
MCU主动上报信息后
MCU通知WiFi模块配网后
MCU通知WiFi模块重启后
需要等待ACK时,Wait_AckStruct.Flag 置位
若等待ACK,按照协议失败重发3次;数据区出现FF,在其后增加55
*****************************************************/
static void Pro_UART_SendBuf(uint8_t *Buf, uint16_t PackLen, uint8_t Tag)
{
uint16_t i;
for(i=0; i<PackLen; i++)
{
UART2_Send_DATA(Buf);
if(i >=2 && Buf == 0xFF)
{
UART2_Send_DATA(0x55);
}
}
//需要实现重发的报文 当等不到Ack时重发
if(Tag == 1)
{
Wait_AckStruct.SendTime = SystemTimeCount;
Wait_AckStruct.SendNum = 0;
Wait_AckStruct.Flag = 1;//这里添加Wait标志
memcpy(Wait_AckStruct.Cmd_Buff, Buf, PackLen);//把发送的数据Buf,备份到Ack
}
}
/*****************************************************
* Function Name: exchangeBytes 大 小端转换
* Description : 模拟的htons 或者 ntohs,如果系统支字节序更改可直接替换成系统函数
* Input : value
* Output : None
* Return : 更改过字节序的short数值
* Attention : 从WIFI接收过来的数据 要转换,发送回去给WIFI也要再转换回去
*****************************************************/
short exchangeBytes(short value)
{
short tmp_value;
uint8_t *index_1, *index_2;
index_1 = (uint8_t *)&tmp_value;
index_2 = (uint8_t *)&value;
*index_1 = *(index_2+1);
*(index_1+1) = *index_2;
return tmp_value;
}
/*****************************************************
* Function Name: CheckSum
* Description : 校验和算法
* Input : buf:数据起始地址; packLen:数据长度;
* Output : None
* Return : 校验码
* Attention : None
*****************************************************/
uint8_t CheckSum( uint8_t *buf, int packLen )
{
int i;
uint8_t sum;
if(buf == NULL || packLen <= 0) return 0;
sum = 0;
for(i=2; i<packLen-1; i++)
sum += buf;
return sum;
}
void GizWits_init(uint8_t P0_Len)
{
Pro_HeadPartP0CmdTypeDef *Pro_HeadPartP0Cmd = (Pro_HeadPartP0CmdTypeDef *)g_DevStatus;
if(P0_Len > MAX_P0_LEN)
{
printf("Warning P0_Len out of range\r\n");
while(1);
}
rb_new(&u_ring_buff);//New Ring buff
memset((uint8_t *)&g_DevStatus, 0, MAX_P0_LEN);
memset(&Pro_M2W_ReturnInfoStruct, 0, sizeof(Pro_M2W_ReturnInfoStruct));
Pro_M2W_ReturnInfoStruct.Pro_HeadPart.Head = 0xFF;
Pro_M2W_ReturnInfoStruct.Pro_HeadPart.Head = 0xFF;
Pro_M2W_ReturnInfoStruct.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_M2W_ReturnInfoStruct) - 4);
Pro_M2W_ReturnInfoStruct.Pro_HeadPart.Cmd = Pro_D2W__GetDeviceInfo_Ack_Cmd;
memcpy(Pro_M2W_ReturnInfoStruct.Pro_ver, PRO_VER, strlen(PRO_VER));
memcpy(Pro_M2W_ReturnInfoStruct.P0_ver, P0_VER, strlen(P0_VER));
memcpy(Pro_M2W_ReturnInfoStruct.Hard_ver, HARD_VER, strlen(HARD_VER));
memcpy(Pro_M2W_ReturnInfoStruct.Soft_ver, SOFT_VER, strlen(SOFT_VER));
memcpy(Pro_M2W_ReturnInfoStruct.Product_Key, PRODUCT_KEY, strlen(PRODUCT_KEY));
Pro_M2W_ReturnInfoStruct.Binable_Time = exchangeBytes(0);
g_P0DataLen = P0_Len;
Pro_HeadPartP0Cmd->Pro_HeadPart.Head = 0xFF;
Pro_HeadPartP0Cmd->Pro_HeadPart.Head = 0xFF;
Pro_HeadPartP0Cmd->Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_HeadPartP0CmdTypeDef) - 4);
Pro_HeadPartP0Cmd->Pro_HeadPart.Cmd = 0x0;
Pro_HeadPartP0Cmd->Pro_HeadPart.SN = 0;
Pro_HeadPartP0Cmd->Pro_HeadPart.Flags = 0x0;
Pro_HeadPartP0Cmd->Pro_HeadPart.Flags = 0x0;
}
/*****************************************************
* Function Name: Pro_GetFrame
* Description :抓取一个包
* Input : None
* Output : New package
* Return : 0 : Find new package ; 1 : Error
* Attention : Data adhering
*****************************************************/
static uint8_t Pro_GetFrame()
{
if(rb_can_read(&u_ring_buff) >= 1)
{
if(packageFlag ==0)
{
rb_read(&u_ring_buff, &curValue, 1);
if((lastValue == 0xFF)&&(curValue == 0xFF))
{
tmp_buf = 0xFF;
tmp_buf = 0xFF;
count = 2;
return 1;
}
if((lastValue == 0xFF)&&(curValue == 0x55))
{
lastValue = curValue;
return 1;
}
tmp_buf = curValue;
count ++ ;
lastValue = curValue;
if(count ==4)
{
dataLen = tmp_buf*256+tmp_buf;
}
if(count ==(dataLen + 4))
{
//把rb的数据,拷贝到UART_HandleStruct
memcpy(UART_HandleStruct.Message_Buf, tmp_buf, dataLen + 4);
UART_HandleStruct.Message_Len = dataLen + 4;
#ifdef PROTOCOL_DEBUG
printf("GAgentToMCU: ");
for(uint8_t i=0; i<dataLen+4; i++)
{
printf("%2x ", UART_HandleStruct.Message_Buf);
}
printf("\r\n");
#endif
memset(tmp_buf, 0, (dataLen + 4));
packageFlag = 1;
lastValue = curValue =0;
return 0;
}
}
}
return 1;
}
/*****************************************************
* Function Name: MessageHandle
* Description :
* 信息处理机制
* 如果收到的是WiFi控制MCU命令【4.10】,把数据存储到Message_Buf
用到
//__packed typedef struct
//{
// uint8_t Head;
// uint16_t Len;
// uint8_t Cmd;
// uint8_t SN;
// uint8_t Flags;
//} Pro_HeadPartTypeDef;
*****************************************************/
u8 GizWits_MessageHandle(u8 * Message_Buf, u8 Length_buf)
{
uint8_t ret = 0;
Pro_HeadPartTypeDef *Recv_HeadPart = NULL;
/*抓取一包*/
Pro_GetFrame();//完成时:packageFlag = 1;数据保存到 UART_HandleStruct
memset(&Recv_HeadPart, 0, sizeof(Recv_HeadPart));
//重发机制 这里有bug 应该是等待Ack失败后才重发
//可以根据ret来判断。。。0_0
//这里只要需要等待Ack就重发,错!
GizWits_D2W_Resend_AckCmdHandle();//if(Wait_AckStruct.Flag == 1) 重发,bug
if(packageFlag)
{
/*验证校验码*//*计算数据帧的校验码,并与数据帧中的校验码,进行比对*/
if(CheckSum(UART_HandleStruct.Message_Buf, UART_HandleStruct.Message_Len) != UART_HandleStruct.Message_Buf)
{
Pro_W2D_ErrorCmdHandle(Error_AckSum);
packageFlag = 0;
return 1;
}
/*判断ACK*///ret没用到
ret = GizWits_W2D_AckCmdHandle(); //if(Wait_AckStruct.Flag == 1) 判断
#ifdef DEBUG
if(ret == 0)
{
printf("ACK: SUCCESS! ...\r\n");
}
#endif
Recv_HeadPart = (Pro_HeadPartTypeDef *)UART_HandleStruct.Message_Buf;
switch (Recv_HeadPart->Cmd)
{
//4.1 WiFi模组请求信息 Cmd=0x01
case Pro_W2D_GetDeviceInfo_Cmd:
Pro_W2D_GetMcuInfo();
break;
//4.8WiFi读取MCU. Cmd=0x03
//4.10 WiFi控制MCU. Cmd=0x03
case Pro_W2D_P0_Cmd:
{
switch(UART_HandleStruct.Message_Buf)//标准报头后紧跟一个action(1B)
{
//4.10 WiFi控制MCU. Cmd=0x03 ActionBit=0x01
case P0_W2D_Control_Devce_Action:
{
Pro_W2D_CommonCmdHandle();//回复通用协议帧
//储存ActionBit之后的信息
memcpy(Message_Buf, UART_HandleStruct.Message_Buf+sizeof(Pro_HeadPartP0CmdTypeDef), Length_buf);
p0Flag = 1;//main()里,依靠此标志,和WriteTypeDef来控制更改设备状态
break;
}
//4.8 WiFi读取MCU. Cmd=0x03 ActionBit=0x02
case P0_W2D_ReadDevStatus_Action:
Pro_W2D_ReadDevStatusHandle();
break;
default:
break;
}
}
break;
case Pro_W2D_P0_Ack_Cmd:
break;
//4.2 WiFi模组与设备MCU的心跳 Cmd=0x07
case Pro_W2D_Heartbeat_Cmd:
Pro_W2D_CommonCmdHandle();
break;
//4.3Cmd=0x09+1设备MCU通知WiFi模组进入配置模式,WiFi的回复
case Pro_W2D_ControlWifi_Config_Ack_Cmd:
break;
case Pro_W2D_ResetWifi_Ack_Cmd:
break;
//4.5 WiFi模组向设备MCU通知WiFi模组工作状态 Cmd=0x0D
case Pro_W2D_ReportWifiStatus_Cmd:
Pro_W2D_WifiStatusHandle();
break;
//4.6 WiFi模组请求重启MCU Cmd=0x0F
case Pro_W2D_ReportMCUReset_Cmd:
Pr0_W2D_RequestResetDeviceHandle();
break;
case Pro_W2D_ErrorPackage_Cmd:
//Pro_W2D_ErrorCmdHandle(Error_AckSum);//bug
break;
case Pro_Get_Network_Time_Ack_Cmd://WIFI发来的获取网络时间
Pro_W2D_GetTimeHandle();
break;
default://4.7 非法消息通知
Pro_W2D_ErrorCmdHandle(Error_Cmd);
break;
}
memset(&UART_HandleStruct.Message_Buf, 0, UART_HandleStruct.Message_Len);
packageFlag = 0;
}
return 1;
} /*****************************************************
* Function Name: Pro_GetMcuInfo
* Description : WiFi模组请求设备信息
4.1 WiFi模组请求信息
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
WiFi发:
0xFFFF 0x0005 0x01 0x## 0x0000 0x##
MCU 回复:
0xFFFF 0x0047 0x02 0x## 0x0000 \
ProtocolVer(8V)__p0Ver(8B)__HardVer(8B)__SoftVer(8B)_ \
_ProductKey(32B)__BindableTimeOut(2B)_ \
_CheckSum(1B)
用到的数据:Pro_M2W_ReturnInfoStruct
*****************************************************/
static void Pro_W2D_GetMcuInfo(void)
{
memcpy(&Pro_CommonCmdStruct, UART_HandleStruct.Message_Buf, sizeof(Pro_CommonCmdStruct));
Pro_M2W_ReturnInfoStruct.Pro_HeadPart.SN = Pro_CommonCmdStruct.Pro_HeadPart.SN;//SN
Pro_M2W_ReturnInfoStruct.Sum = CheckSum((uint8_t *)&Pro_M2W_ReturnInfoStruct, sizeof(Pro_M2W_ReturnInfoStruct));
Pro_UART_SendBuf((uint8_t *)&Pro_M2W_ReturnInfoStruct,sizeof(Pro_M2W_ReturnInfoStruct), 0);
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i=0; i<sizeof(Pro_M2W_ReturnInfoStruct); i++)
{
printf("%2x ", *((uint8_t *)&Pro_M2W_ReturnInfoStruct + i));
}
printf("\r\n");
#endif
}
static void Pro_W2D_ReadDevStatusHandle(void)
{
Pro_D2W_ReportDevStatusHandle();
}
/*****************************************************
* Function Name: Pro_Pro_W2D_Heartbeat
MCU回复WiFi模组要用的 通用协议帧:
4.2 WiFi模组与设备MCU的心跳
4.5 WiFi模组向MCU汇报工作状态
4.6 WiFi模组请求重启MCU
4.7 WiFi模组通知MCU得到非法消息
4.10 WiFi模组控制更改MCU状态
都用此方法
然而
4.1 WiFi请求MCU系统信息,MCU要回复系统信息
4.3 MCU通知WiFi进入配网,WiFi发Ack
4.4 MCU通知WiFi重启,WiFi发Ack
4.8 WiFi读取MCU状态,MCU回复中要有设备信息和ActionBit位
4.9 MCU主动上报,WiFi发应答Ack
不用此法
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 Cmd 0x## 0x0000 0x##
MCU 回复:
0xFFFF 0x0005 Cmd+1 0x## 0x0000 0x##
*****************************************************/
static void Pro_W2D_CommonCmdHandle(void)
{
memcpy(&Pro_CommonCmdStruct, UART_HandleStruct.Message_Buf, sizeof(Pro_CommonCmdStruct));
Pro_CommonCmdStruct.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_CommonCmdTypeDef) - 4);
// 注意协议里规定 回复方Cmd+1 == 发送发Cmd
Pro_CommonCmdStruct.Pro_HeadPart.Cmd = Pro_CommonCmdStruct.Pro_HeadPart.Cmd + 1;
Pro_CommonCmdStruct.Sum = CheckSum((uint8_t *)&Pro_CommonCmdStruct, sizeof(Pro_CommonCmdStruct));
Pro_UART_SendBuf((uint8_t *)&Pro_CommonCmdStruct, sizeof(Pro_CommonCmdStruct), 0);
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);//打印系统时间
for(uint16_t i=0; i<sizeof(Pro_CommonCmdStruct); i++)
{
printf("%2x ", *((uint8_t *)&Pro_CommonCmdStruct + i));
}
printf("\r\n");
#endif
memset(&Pro_CommonCmdStruct, 0, sizeof(Pro_CommonCmdStruct));
}
/*****************************************************
* Function Name: Pro_W2D_WifiStatusHandle
* Description : 将WiFi的状态保存到 Pro_W2D_WifiStatusStruct中。并回复ACK
4.5 WiFi模组向设备MCU通知WiFi模组工作状态
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__WiFiStatus(2B)__CheckSum(1B)
0xFFFF 0x0007 0x0D 0x## 0x0000 ... 0x##
MCU 回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x0E 0x## 0x0000 0x##
Pro_W2D_WifiStatusTypeDef Pro_W2D_WifiStatusStruct
{
Pro_HeadPartTypeDef Pro_HeadPart;
uint16_t Wifi_Status;
uint8_t Sum;
}
*****************************************************/
void (*callBackFunc)(uint16_t);//函数指针
static void Pro_W2D_WifiStatusHandle(void)
{
//将WiFi的状态保存到 Pro_W2D_WifiStatusStruct中
memcpy(&Pro_W2D_WifiStatusStruct, UART_HandleStruct.Message_Buf, sizeof(Pro_W2D_WifiStatusStruct));
//回复通用协议帧
Pro_W2D_CommonCmdHandle();
callBackFunc= GizWits_WiFiStatueHandle;
(*callBackFunc)(exchangeBytes(Pro_W2D_WifiStatusStruct.Wifi_Status));
printf("W2D_WifiStatusStruct.Wifi_Status=%d",Pro_W2D_WifiStatusStruct.Wifi_Status);
if((exchangeBytes(Pro_W2D_WifiStatusStruct.Wifi_Status) & (1<<4))==(1<<4))
{
GizWits_D2WGetCmd();
}
}
/********************************************
4.13获取网络时间解码,现在能得到当前时间信息
********************************************/
static void Pro_W2D_GetTimeHandle(void)
{
//把接收到WIFI的时间存在Pro_W2D_GetTimeStruct结构体中
memcpy(&Pro_W2D_GetTimeStruct,UART_HandleStruct.Message_Buf,sizeof(Pro_W2D_GetTimeStruct));
Pro_W2D_GetTimeStruct.year=exchangeBytes(Pro_W2D_GetTimeStruct.year);
printf("[%d] year : ", Pro_W2D_GetTimeStruct.year);
printf("[%d] month : ", Pro_W2D_GetTimeStruct.month);
printf("[%d] day : ", Pro_W2D_GetTimeStruct.day);
printf("[%d] hour : ", Pro_W2D_GetTimeStruct.hour);
printf("[%d] minute : ", Pro_W2D_GetTimeStruct.minute);
printf("[%d] second : ", Pro_W2D_GetTimeStruct.second);
printf("\r\n");
RTC_Set(Pro_W2D_GetTimeStruct.year,Pro_W2D_GetTimeStruct.month,Pro_W2D_GetTimeStruct.day,Pro_W2D_GetTimeStruct.hour,Pro_W2D_GetTimeStruct.minute,Pro_W2D_GetTimeStruct.second);
}
/*****************************************************
* Function Name: Pr0_W2D_RequestResetDeviceHandle
* Description : WiFi模组请求复位设备MCU,MCU回复ACK,并执行设备复位
4.6 WiFi模组请求重启MCU
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0007 0x0F 0x## 0x0000 0x##
MCU 回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x10 0x## 0x0000 0x##
*****************************************************/
void Pr0_W2D_RequestResetDeviceHandle(void)
{
Pro_W2D_CommonCmdHandle();//回复通用协议帧
uint32_t timeDelay = SystemTimeCount;
/*Wait 600ms*/
while((SystemTimeCount - timeDelay) <= 600)//Wait 600ms
printf("W2D_RequestResetDevice...\r\n");
printf("MCU Restart...\r\n");
/*******************MCU RESTART*******************/
__set_FAULTMASK(1);
NVIC_SystemReset();
/****************************************************/
}
/*****************************************************
* Function Name: Pro_W2D_ErrorCmdHandle
* Description : WiFi发送收到非法信息通知,设备MCU回复ACK,并执行相应的动作
4.7 非法消息通知
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ErrorCode(1B)__CheckSum(1B)
0xFFFF 0x0007 0x0F 0x## 0x0000 错误码 0x##
MCU 回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ErrorCode(1B)__CheckSum(1B)
0xFFFF 0x0005 0x10 0x## 0x0000 错误码 0x##
可见,通信协议中,对非法消息根本没做处理。。。原样返回而已
Pro_ErrorCmdTypeDef{
Pro_HeadPartTypeDef{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
Error_PacketsTypeDef Error_Packets;
uint8_t Sum;
}
Error_PacketsTypeDef{
Error_AckSum = 0x01, //校验错误
Error_Cmd = 0x02, //命令码错
Error_Other= 0x03, //其他
}
*****************************************************/
static void Pro_W2D_ErrorCmdHandle(Error_PacketsTypeDef errorType)
{
uint8_t i;
Pro_ErrorCmdTypeDef Pro_ErrorCmdStruct;
memcpy(&Pro_ErrorCmdStruct, UART_HandleStruct.Message_Buf, sizeof(Pro_ErrorCmdStruct));
Pro_ErrorCmdStruct.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_ErrorCmdStruct) - 4);
Pro_ErrorCmdStruct.Pro_HeadPart.Cmd = Pro_D2W_ErrorPackage_Ack_Cmd;
Pro_ErrorCmdStruct.Error_Packets = errorType;
Pro_ErrorCmdStruct.Sum = CheckSum((uint8_t *)&Pro_ErrorCmdStruct, sizeof(Pro_ErrorCmdStruct));
Pro_UART_SendBuf((uint8_t *)&Pro_ErrorCmdStruct, sizeof(Pro_ErrorCmdStruct), 0);
#ifdef PROTOCOL_DEBUG
printf(" MCU: ");
for(i = 0; i < sizeof(Pro_ErrorCmdStruct); i++)
{
printf("%2x ", *((uint8_t *)&Pro_ErrorCmdStruct + i));
}
printf("\r\n");
#endif
/*****************Gagent to MCU ,Error********************/
switch (Pro_ErrorCmdStruct.Error_Packets)
{
case Error_AckSum:
printf("W2D Error Command ->Error_AckSum\r\n");
break;
case Error_Cmd:
printf("W2D Error Command ->Error_Cmd\r\n");
break;
case Error_Other:
printf("W2D Error Command ->Error_Other\r\n");
break;
default:
break;
}
/****************************************************/
}
/*
4.8 WiFi模组读取设备当前状态
WiFi发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ActionBit(1B)__CheckSum(1B)
0xFFFF 0x0006 0x03 0x## 0x0000 0x02 0x##
MCU 回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ActionBit(1B)__DevStatus(11B)__CheckSum(1B)
0xFFFF 0x0011 0x04 0x## 0x0000 0x03 Bablabla 0x##
用到的数据g_DevStatus
也就是ReadTypeDef
*/
static void Pro_D2W_ReportDevStatusHandle(void)
{
Pro_HeadPartP0CmdTypeDef *Pro_HeadPartP0Cmd = (Pro_HeadPartP0CmdTypeDef *)g_DevStatus;
memcpy(Pro_HeadPartP0Cmd, UART_HandleStruct.Message_Buf, sizeof(Pro_HeadPartTypeDef));
Pro_HeadPartP0Cmd->Pro_HeadPart.Cmd = Pro_D2W_P0_Ack_Cmd;
Pro_HeadPartP0Cmd->Pro_HeadPart.Len = exchangeBytes((sizeof(Pro_HeadPartP0CmdTypeDef)+g_P0DataLen+1) - 4);
Pro_HeadPartP0Cmd->Action = P0_D2W_ReadDevStatus_Action_ACK;
//加上校验和
g_DevStatus = CheckSum(g_DevStatus, sizeof(Pro_HeadPartP0CmdTypeDef)+g_P0DataLen+1);
Pro_UART_SendBuf((uint8_t *)Pro_HeadPartP0Cmd, sizeof(Pro_HeadPartP0CmdTypeDef)+g_P0DataLen+1, 0);
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i=0; i<(sizeof(Pro_HeadPartP0CmdTypeDef)+g_P0DataLen+1); i++)
{
printf("%2x ", *((uint8_t *)Pro_HeadPartP0Cmd + i));
}
printf("\r\n");
#endif
}
/*
4.4 设备MCU重置WiFi模组
MCU发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x0B 0x## 0x0000 0x##
WiFi回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x0C 0x## 0x0000 0x##
Pro_CommonCmdTypeDef {
Pro_HeadPartTypeDef {
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
uint8_t Sum;
}
*/
void GizWits_D2WResetCmd(void)
{
Pro_CommonCmdTypeDef Pro_D2WReset;
Pro_D2WReset.Pro_HeadPart.Head = 0xFF;
Pro_D2WReset.Pro_HeadPart.Head = 0xFF;
Pro_D2WReset.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_CommonCmdTypeDef) - 4);
Pro_D2WReset.Pro_HeadPart.Cmd = Pro_D2W_ResetWifi_Cmd;//0x0B
Pro_D2WReset.Pro_HeadPart.SN = SN++;
Pro_D2WReset.Pro_HeadPart.Flags = 0x00;
Pro_D2WReset.Pro_HeadPart.Flags = 0x00;
Pro_D2WReset.Sum = CheckSum((uint8_t *)&Pro_D2WReset, sizeof(Pro_CommonCmdTypeDef));
Pro_UART_SendBuf((uint8_t *)&Pro_D2WReset, sizeof(Pro_CommonCmdTypeDef), 1);//tag=1,需要等待WiFi应答的Ack
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i=0; i<sizeof(Pro_CommonCmdTypeDef); i++)
{
printf("%2x ", *((uint8_t *)&Pro_D2WReset + i));
}
printf("\r\n");
#endif
}
/*
4.3 设备MCU通知WiFi模组进入配置模式
MCU发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ConfigMethod(1B)__CheckSum(1B)
0xFFFF 0x0006 0x09 0x## 0x0000 SoftAp/AirLink 0x##
WiFi回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x0A 0x## 0x0000 0x##
用到了
Pro_D2W_ConfigWifiTypeDef{
Pro_HeadPartTypeDef{
uint8_t Head;
uint16_t Len;
uint8_t Cmd;
uint8_t SN;
uint8_t Flags;
}
uint8_t Config_Method;
uint8_t Sum;
}
*/
void GizWits_D2WConfigCmd(uint8_t WiFi_Mode)
{
Pro_D2W_ConfigWifiTypeDef Pro_D2WConfigWiFiMode;
Pro_D2WConfigWiFiMode.Pro_HeadPart.Head = 0xFF;
Pro_D2WConfigWiFiMode.Pro_HeadPart.Head = 0xFF;
Pro_D2WConfigWiFiMode.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_D2W_ConfigWifiTypeDef) - 4);
Pro_D2WConfigWiFiMode.Pro_HeadPart.Cmd = Pro_D2W_ControlWifi_Config_Cmd;
Pro_D2WConfigWiFiMode.Pro_HeadPart.SN = SN++;
Pro_D2WConfigWiFiMode.Pro_HeadPart.Flags = 0x00;
Pro_D2WConfigWiFiMode.Pro_HeadPart.Flags = 0x00;
Pro_D2WConfigWiFiMode.Config_Method = WiFi_Mode;
Pro_D2WConfigWiFiMode.Sum = CheckSum((uint8_t *)&Pro_D2WConfigWiFiMode, sizeof(Pro_D2W_ConfigWifiTypeDef));
Pro_UART_SendBuf((uint8_t *)&Pro_D2WConfigWiFiMode, sizeof(Pro_D2W_ConfigWifiTypeDef), 1);
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i=0; i<sizeof(Pro_D2W_ConfigWifiTypeDef); i++)
{
printf("%2x ", *((uint8_t *)&Pro_D2WConfigWiFiMode + i));
}
printf("\r\n");
#endif
}
/*
发获取网络时间 的命令 现在还没有得到 CMD 0X17 0X18
*/
void GizWits_D2WGetCmd(void)
{
Pro_CommonCmdTypeDef Pro_D2WGet;
Pro_D2WGet.Pro_HeadPart.Head = 0xFF;
Pro_D2WGet.Pro_HeadPart.Head = 0xFF;
Pro_D2WGet.Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_CommonCmdTypeDef) - 4);
Pro_D2WGet.Pro_HeadPart.Cmd = Pro_Get_Network_Time_Cmd;//0x17
Pro_D2WGet.Pro_HeadPart.SN = SN++;
Pro_D2WGet.Pro_HeadPart.Flags = 0x00;
Pro_D2WGet.Pro_HeadPart.Flags = 0x00;
Pro_D2WGet.Sum = CheckSum((uint8_t *)&Pro_D2WGet, sizeof(Pro_CommonCmdTypeDef));
Pro_UART_SendBuf((uint8_t *)&Pro_D2WGet, sizeof(Pro_CommonCmdTypeDef), 1);//tag=1,需要等待WiFi应答的Ack
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i=0; i<sizeof(Pro_CommonCmdTypeDef); i++)
{
printf("%2x ", *((uint8_t *)&Pro_D2WGet + i));
}
printf("\r\n");
#endif
}
/*
4.9 MCU主动上报当前状态
flag=1,立即上报
MCU发:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__ActionBit(1B)__DevStatus(11B)__CheckSum(1B)
0xFFFF 0x0011 0x05 0x## 0x0000 0x04 Bablabla 0x##
WiFi回复:
Header(2B)__LEN(2B)__CMD(1B)__sn(1B)__falg(2B)__CheckSum(1B)
0xFFFF 0x0005 0x06 0x## 0x0000 0x##
g_DevStatus就是ReadType的拷贝
*/
//10分钟定期上报
//Wifi控制时,上报频率不受限制
//用户更改Status时,上报频率 小于 2秒一次
void GizWits_DevStatusUpgrade(uint8_t *P0_Buff, uint32_t Time, uint8_t flag)
{
uint8_t Report_Flag = 0;
Pro_HeadPartP0CmdTypeDef *Pro_HeadPartP0Cmd = (Pro_HeadPartP0CmdTypeDef *)g_DevStatus;
//Wait_AckStruct.Flag这个标志位也限制MCU上报数据
//只要此标志置位,暂停上报
//复位标志,则重新允许上报
if(Wait_AckStruct.Flag == 1)
{
return;
}
if(flag == 1)
{
Report_Flag = 1;
goto Report;
}
if((2 * 1000) < (SystemTimeCount - Last_ReportTime))//SystemTimeCount TIM3毫秒级中断过去了(2 * 1000)进入到 这里
{
// 比较要上报的信息P0_Buff=ReadTypeDef,与原设备信息g_DevStatus
if(memcmp(g_DevStatus + sizeof(Pro_HeadPartP0CmdTypeDef), P0_Buff, g_P0DataLen) != 0)
{
Report_Flag = 1;
}
}
// Bug: Last_Report_10_Time从来没初始化 ,从0时间开始
//Time 当前输入的定时时间
if(Time < (SystemTimeCount-Last_Report_10_Time))
{
printf("Last_Report_10_Time");
Report_Flag = 1;
Last_Report_10_Time = SystemTimeCount;
}
Report:
if(Report_Flag == 1)
{
//就是这一句,把ReadTypeDef的值给了g_DevStatus
memcpy(g_DevStatus + sizeof(Pro_HeadPartP0CmdTypeDef), P0_Buff, g_P0DataLen);
Pro_HeadPartP0Cmd->Pro_HeadPart.Len = exchangeBytes(sizeof(Pro_HeadPartP0CmdTypeDef) + 1 + g_P0DataLen - 4);
Pro_HeadPartP0Cmd->Pro_HeadPart.Cmd = Pro_D2W_P0_Cmd;
Pro_HeadPartP0Cmd->Pro_HeadPart.SN = SN++;
Pro_HeadPartP0Cmd->Action = P0_D2W_ReportDevStatus_Action;
g_DevStatus = CheckSum(g_DevStatus, sizeof(Pro_HeadPartP0CmdTypeDef) + g_P0DataLen + 1);
Pro_UART_SendBuf((uint8_t *)Pro_HeadPartP0Cmd, sizeof(Pro_HeadPartP0CmdTypeDef) + g_P0DataLen + 1, 1);//
Last_ReportTime = SystemTimeCount;
#ifdef DEBUG
printf("Report Sensor Data \r\n");
#endif
#ifdef PROTOCOL_DEBUG
printf("[%d] MCU : ", SystemTimeCount);
for(uint16_t i = 0; i < (sizeof(Pro_HeadPartP0CmdTypeDef) + g_P0DataLen + 1); i++)
{
printf("%2x ", g_DevStatus);
}
printf("\r\n");
#endif
}
return;
}
开发板测试数据
看样子楼主已经做好了?,不过空调定时这个功能,空调自身就有吧? 我这个没有,插座也可以应用到很多地方,定时充电,虽然手机有保护功能,但也有意外,我在用小K智能插座定时关空调,但他的APP反应慢。 智能插座MCU
完整源代码 请在这里下载 http://pan.baidu.com/s/1c20sgRe
文件夹说明
GAgent ---- 最新版本的GAgent ESP8266里运行的程序,如果你们是拿到机智云的开发板,就不用更新
Gizwits-SmartSocket_Android---- 开源的公版智能云插座APP,修改里面三个参数就可以绑定自己的设备了
智能云插座基于公版stm32_V2.3.2 ---- 这个就是我修改的源码
GoKitV2.1硬件开发板------机智云开发板的原理图
微信宠物屋 for GoKit 2 STM V03010100 增加了点中文注释,也不是很全。主要是机智云给出的注释太少了,机智云把代码都好了,居然还差一点注释。增加了理解代码的时间。
原代码下载http://site.gizwits.com/zh-cn/developer/resource/hardware?type=GoKit
注释完整代码下载http://pan.baidu.com/s/1b779P8