14 Star 18 Fork 5

HEKR_CLOUD / hekr-esp8266-sdk-ra

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
contribute
Sync branch
Cancel
Notice: Creating folder will generate an empty file .keep, because not support in Git
Loading...
README

#氦氪4.x嵌入式SDK应用手册 v1.1.4 by zejun.zhao@hekr.me 2016/3/30 11:03:38

##总体描述

  • 编写目的: 该文档旨在指导开发者快速上手氦氪4.x嵌入式SDK,进行对WIFI模块ESP8266的二次开发,熟悉目录结构、了解api接口各模块功能,以及编程中需注意的事项。

  • SDK开发者:基于esp8266硬件平台,采用Hekr配网模式、连接氦氪云进行开发的开发者群体。同时,开发者也无需关注网络重连及服务器重连机制,便于开发者进行二次应用开发。

  • api接口使用说明,请参考文档document\ra_embedded_api.chm

1. SDK目录


目录结构
├── app
| 	 └─ user
├── bin
|	 └─ upgrade
├── document
├── examples 
├── include
|	  └─ ra
├── ld
├── lib
└── tools
目录结构说明
  • app:用户工作区。用户在此目录下执行make编译操作,用户级代码及头文件均放在此目录下
    • user:用户级代码目录,SDK入口函数为ra_user_main(),在user_main.c
  • bin:二进制文件目录。该目录存放了编译生成的bin文件
    • upgrade:该子目录存放编译生成的支持云端升级(FOTA)的固件(如user1.binuser2.bin
  • document:文档目录
  • include:头文件目录,包含了用户可使用的API函数声明以及相关宏定义
    • ra:RA库头文件目录,开发者进行二次开发所需API函数、宏定义、类型定义均在此目录头文件中
  • examples:实例项目代码
    • Smart Plug : 智能插座项目
  • ld:SDK编译链接时所需文件,用户无需修改
  • lib:SDK编译链接时所需的库文件。
    • libra.a
  • tools:包含编译工具和烧录工具等,用户无需修改

2. 固件编译


  • app目录下,执行编译命令make,在bin\upgrade目录下生成用户固件1.bin

注:make编译前,可以根据flash大小来进行配置,配置文件为app\Makefile。默认为BOOT=new、APP=1、SPI_SPEED=40、SPI_MODE=QIO、SPI_SIZE_MAP=3,即flash map默认为3 = 2048KB(512K+512K)

固件编译时SPI_SIZE_MAP仅支持2/3/4,flash map对应表如下:

SPI_SIZE_MAP flash map
2 1024KB( 512KB+ 512KB)
3 2048KB( 512KB+ 512KB)
4 4096KB( 512KB+ 512KB)

3. 固件烧录


  • params_section_blank.bin用于擦除flash中的配置参数(如prodKey等)以及ra_set_parameter_string/ra_set_parameter_integer接口存入的参数。
  • 固件烧录地址取决于flash map,即SPI_SIZE_MAP

固件烧录时需要烧录下表中5个bin文件,烧录地址与SPI_SIZE_MAP对应表如下:

bin文件 2 3 4
boot_v1.5.bin 0x0 0x0 0x0
1.bin 0x1000 0x1000 0x1000
params_section_blank.bin 0x7D000 0x7D000 0x7D000
esp_init_data_default.bin 0xFC000 0x1FC000 0x3FC000
blank.bin 0xFE000 0x1FE000 0x3FE000

4. 用户代码入口


  • 用户代码入口函数为ra_user_main(),在app/user/user_main.c中。
  • 在进入函数ra_user_main()前,系统已经做了部分初始化,具体有:CPU频率为80MHz、wifi mode为STATION_MODE、设定uart0和uart1波特率为9600且打印终端为uart0

此外,在ra_user_main()中,需要执行一些函数完成对配置初始化,请参考以下代码:

#include <ra_parameter.h>
#include <ra_utils.h>
#include <ra_uart.h>

void ra_user_main(void)
{
	//必选
	ra_set_parameter_string("prodKey", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");	//prodKey设置
	ra_set_current_firmware_version("4.1.1.1");	//固件版本号设置,格式必须是"xx.xx.xx.xx"

	//可选
	ra_uart_set_terminal(RA_UART1); //设置打印终端,可将SDK内部调试信息输出
}

5. 功能模块


###5.1 打印终端配置

esp8266有两个串口(uart0和uart1),均可作为打印终端,调用ra_uart_set_terminal()os_printf的打印终端默认为uart0。

示例代码:(设置uart1为打印终端)

#include <ra_uart.h>

ra_uart_set_terminal(RA_UART1);
os_printf("hello world\n");

uart1输出:

hello world

注:ra_uart_set_terminal()设置后,SDK内部调试信息也会打印出来,如云端登陆流程的信息,方便开发者调试

串口相关属性配置可参考:5.5.1 UART操作接口

###5.2 用户参数存取接口

SDK提供K/V格式的存参接口。开发者可自定义Key,并可选择两种Value类型(int和string)。此外还提供了K/V的读取和删除接口。接口说明请参考ra_parameter.h

  • Key最大长度为32Byte,string类型的Value最大长度为64Byte。
  • 开发者请勿使用这三个Key,分别是ctrlKeybindKeytoken,Hekr云端登录机制有使用到它们。
  • 此接口旨在用于存储用户参数,不建议用于存放用户数据。用户数据请使用底层spi_flash_write()接口。

示例代码:

#include <ra_parameter.h>

int ret = -1;
char *key_1 = "key_1";
char *key_2 = "key_2";
ra_int32_t value_1 = 1000, value_int = 0;
char *value_2 = "12345678123456781234567812345678";
char value_str[64];

//store params
ra_set_parameter_integer(key_1, value_1);
ra_set_parameter_string(key_2, value_2);

//load params
ra_get_parameter_integer(key_1, &value_int);
ret = ra_get_parameter_string(key_2, value_str, 64);

os_printf("value_int = %d\n", value_int);
os_printf("ret = %d, value_str = %s\n", ret, value_str);

//delete key_2
ra_delete_parameter(key_2);
os_memset(value_str, 0, 64);
ret = ra_get_parameter_string(key_2, value_str, 64);
os_printf("ret = %d, value_str = %s\n", ret, value_str);

uart1输出:

value_int = 1000
ret = 32, value_str = 12345678123456781234567812345678
[log]ra_parameter.c:173: key_2 isn't exist //此为SDK内部打印

ret = -1, value_str =

###5.2 GPIO接口

#####5.2.1 逻辑引脚和物理引脚映射

SDK中gpio逻辑序号与esp8266的gpio物理序号一致。如gpio逻辑序号为12对应GPIO12,而它的引脚名称为MTDI_U

#####5.2.2 配置GPIO为输出

配置GPIO14引脚为输出,且输出高电平:

示例代码:

#include <ra_gpio.h>

ra_gpio_set_direction(14, RA_GPIO_DIRECTION_OUTPUT);
ra_gpio_output(14, 1);

#####5.2.3 配置GPIO为输入

配置GPIO13引脚为输入,且输出高电平:

示例代码:

#include <ra_gpio.h>

ra_gpio_set_direction(13, RA_GPIO_DIRECTION_INPUT);
ra_gpio_state_t state = ra_gpio_input(13);
os_printf("gpio13 = %d\n", state);

###5.3 按键接口

SDK中基于gpio封装了注册按键中断处理回调接口,输入参数包括gpio序号、gpio中断类型、长按时间阈值、短按处理函数指针以及长按处理函数指针。

示例代码:

按键管脚为序号为13的管脚,下降沿触发,长按阈值为3000ms,短按处理函数指针指向short_press_handler(),长按处理函数指针指向long_press_handler()

#include <ra_button.h>

void short_press_handler(void)
{
	os_printf("short press\n");
}

void long_press_handler(void)
{
	os_printf("long press\n");
}

void ra_user_main(void)
{
	ra_register_button_irq_handler(13, RA_GPIO_IRQ_TYPE_NEGEDGE, 3000, short_press_handler, long_press_handler);
}

gpio13电平拉低3s,则进入长按处理回调函数,打印long press;gpio13电平拉低短于3s,则进入短按处理回调函数,打印short press

  • 注:中断类型推荐使用下降沿触发RA_GPIO_IRQ_TYPE_NEGEDGE

###5.4 定时任务接口

SDK中定时接口是对底层api进行的二次封装,且增加了一些新特性,如查询定时任务剩余时间、查询定时任务是否可重复。

#####5.4.1 定时任务新建和启动

示例代码:

注册一个每隔2s重复执行的定时任务,每次执行打印输出hello world

#include <ra_timer.h>

void timer_callback(ra_timer_t timer, void *arg)
{
	os_printf("hello world\n");
}

void ra_user_main(void)
{
	ra_timer_t timer; 
	ra_timer_new(&timer);
	ra_timer_set_callback(timer, timer_callback, NULL);
	ra_timer_start(timer, 2000, ra_true);
}
  • 注:ra_timer_start()第三个参数值为ra_false时,定时任务不可重复

#####5.4.2 定时任务的停止与注销

ra_timer_stop():定时器停止工作,但不释放定时器timer。无需调用ra_timer_new()来新建定时器

ra_timer_delete():定时器停止工作,且释放定时器timer。

###5.5 UART接口

SDK可以设置UART0或者UART1作为串口输出,UART0的TXD、RXD管脚分别对应ESP8266的TXD、RXD引脚,UART1对应的TXD管脚为GPIO2。

  • 注:esp8266的串口接收中断仅对UART0有效,即ra_uart_recv_enable()只支持RA_UART0

#####5.5.1 UART属性设置

UART可设置的属性包括波特率、数据位、奇偶校验位、停止位。(注:底层esp8266暂不支持奇偶校验)。默认属性为960081

示例代码:

设置UART0波特率115200、数据位7,并从UART0重复输出hello world,同时注册串口接收回调函数。

#include <ra_timer.h>
#include <ra_uart.h>

void timer_callback(ra_timer_t timer, void *arg)
{
	char *string = "hello world";
	ra_uart_send_data(RA_UART0, string, os_strlen(string));
}

void uart_recv_cb(char *buf, ra_size_t len)
{
	os_printf("%s, len = %d\n", buf, len);
}

void ra_user_main(void)
{
	//设置UART0属性
	ra_uart_set_rate(RA_UART0, RA_UART_RATE_115200);
	ra_uart_set_data_bits(RA_UART0, RA_UART_DATA_BITS_7);

	//定时从UART0发送
	ra_timer_t timer;
	ra_timer_new(&timer);
	ra_timer_set_callback(timer, timer_callback, NULL);
	ra_timer_start(timer, 3000, 1);

	//设置UART0的数据接收回调函数
	ra_uart_register_recv_callback(RA_UART0, uart_recv_cb);
	//UART0接收中断使能
	ra_uart_recv_enable(RA_UART0);
}

#####5.5.2 UART通信配置

UART发送配置:

ra_uart_set_sending_queue_interval():用于设置串口数据发送队列间隔,默认为100ms。当发送数据帧太快,数据帧会缓存在队列中,然后以一定的间隔时间依次发送出去。

UART接收配置:

ra_uart_set_recv_timeout():设置串口接收中断超时时间,默认为100ms。UART中断接收数据,如果超时时间内没有再接收到数据,则进入串口接收回调函数。

ra_uart_set_recv_buffer_size_limit():设置串口接收回调触发长度,默认为256Byte。UART中断接收数据,当buffer长度达到设定值,则进入串口接收回调函数。

  • 进入串口回调函数的触发条件由上面两个函数设置的参数决定,满足其中一个条件即进入回调函数。

###5.6 设备状态接口

#####5.6.1 设备状态的读写操作

为了方便开发者对设备状态进行监控及控制,SDK中使用了设备状态机制。开发者可以根据设备当前实际状态,将对应的设备状态项item的值置为ra_true,待实际状态发生改变时,将该item置为ra_false。同时,开发者可在任意时候通过读取某item的值来判断设备是否处于该状态下。

typedef enum
{
	RA_DEVICE_STATE_WLAN_CONNECTED = 0, //路由器连接成功
	RA_DEVICE_STATE_WLAN_CONNECT_FAILED, //路由器连接失败
	RA_DEVICE_STATE_CLOUD_CONNECTED, //服务器连接成功
	RA_DEVICE_STATE_HEKR_CONFIG_RUNNING, //Hekr config模式下
	RA_DEVICE_STATE_AIRKISS_CONFIG_RUNNING, //airkiss config模式下
} ra_device_state_type_t;

ra_device_state_type_t枚举定义中包含了开发者可能用到的设备状态项,可以对它们进行store(设置)和load(读取)操作。

ra_device_state_store():设置某个设备状态项item的值。开发者须根据设备实际状态来设置对应item值。

ra_device_state_store(RA_DEVICE_STATE_WLAN_CONNECTED, ra_true); 
//设备连接路由器成功,设置item "RA_DEVICE_STATE_WLAN_CONNECTED"为ra_true。

ra_device_state_load():读取某个设备状态项item的值。根据该item值来判断设备当前状态,以便进行逻辑处理。

ra_device_state_load(RA_DEVICE_STATE_WLAN_CONNECTED); 
//根据返回值判断设备是否连接成功路由器,ra_true表示成功,ra_false表示失败。
  • 开发者在实际应用中,ra_device_state_type_t中已有的设备状态项的store操作已经在SDK实现,开发者只需通过load操作来获取设备状态。
  • 开发者可在ra_device_state_type_t枚举定义中添加其他设备状态项,它的storeload操作则自行实现。注:设备状态项请添加在已有项的后面
  • 所有设备状态项的初始值都是ra_false

#####5.6.2 设备状态改变时的回调函数

为方便开发者快速接入氦氪云端,SDK中提供了wifi连接及服务器登陆的接口,在此过程中,设备状态会出现多种变化(如路由器连接成功、路由器连接失败、服务器登陆成功、服务器登陆失败等)。SDK中提供了设备状态改变的回调函数,当设备状态改变时(如连接上路由器)开发者可以根据item的值来判断设备当前状态,进行分支操作。

示例代码:可参考5.8节的相关示例

为了不影响当前设备状态项,在ra_device_state_type_t枚举定义中后面添加一条设备状态 RA_DEVICE_STATE_DO_ACTION

#include <ra_device_state.h>
#include <ra_utils.h>

void device_state_changed_callback(ra_device_state_type_t item, ra_bool current_state)
{
	if (item == RA_DEVICE_STATE_DO_ACTION)
	{
		os_printf("RA_DEVICE_STATE_DO_ACTION. state = %d\n", current_state);
	}
}

void ra_user_main(void)
{
	ra_register_device_state_changed_callback(device_state_changed_callback);//注册设备状态改变时的回调函数

	if (ra_device_state_load(RA_DEVICE_STATE_DO_ACTION) == ra_false)
	{
		ra_device_state_store(RA_DEVICE_STATE_DO_ACTION, ra_true);
	}
}

uart1输出:

RA_DEVICE_STATE_DO_ACTION. state = 1

###5.7 wifi配网接口

  • 配网方式有:Hekr configairkiss config(暂不支持)

调用配网接口ra_start_wifi_config(RA_WIFI_CONFIG_TYPE_HEKR)即进入Hekr config模式,此时使用Hekr APP对设备进行一键配网,设备获取到ssid和password即进入配网处理回调函数中。

示例代码:

#include <ra_wifi.h>

void wifi_config_finish_callback(char *ssid, char *password)
{
	if ((ssid != NULL) && (password != NULL))
	{
		os_printf("wifi_config successed\n");
		os_printf("ssid = %s, password = %s\n", ssid, password);
		//配网成功,获取到ssid及password,接着连接路由器
	}
	else
	{
		os_printf("wifi_config failed\n");
		//配网失败
	}
}

void ra_user_main()
{
	os_printf("wifi_config start\n");
	ra_register_wifi_config_callback(wifi_config_finish_callback);//注册wifi config配网回调函数
	ra_start_wifi_config(RA_WIFI_CONFIG_TYPE_HEKR);//启动wifi config
}
  • 串口打印********hekr_config run********即表示进入配网模式。
  • 配网超时时间为5min,超时后也进入配网回调函数,此时ssid和password均为NULL。
  • 配网获取到的ssid和password未保存,用户可自行调用wifi_station_set_config()进行存储,避免重复配网。
  • 进行配网前,用户可以通过wifi_station_get_config(struct station_config *config)接口的config参数来判断是否需要进入配网模式。

###5.8 设备连接wifi及登陆服务器

设备须先连接上wifi路由器,然后进行登陆服务器操作。开发者可以使用hekr config一键配网获取ssid,也连接一个固定的ssid。以下示例配置固定的ssid。

示例代码:

#include <ra_wifi.h>
#include <ra_device_state.h>
#include <ra_utils.h>

void recv_cloud_msg_callback(char *buf, ra_uint16_t len)
{
	os_printf("buf = %s, len = %d\n", buf, len);
	//接收到云端数据
}

void device_state_changed_callback(ra_device_state_type_t item, ra_bool current_state)
{
	if (item == RA_DEVICE_STATE_WLAN_CONNECTED&&
		current_state == ra_true)
	{
		//路由器连接成功,接着登录服务器
		os_printf("wifi connect successed\n");
		ra_register_cloud_recv_callback(recv_cloud_msg_callback);//注册登录云端后,数据接收的回调函数
		ra_connect_to_cloud();//登录云端服务器
	}
	else if (item == RA_DEVICE_STATE_WLAN_CONNECT_FAILED&&
		current_state == ra_true)
	{
		os_printf("wifi connect failed\n");
	}
}

void ra_user_main(void)
{
	ra_register_device_state_changed_callback(device_state_changed_callback);//注册设备状态改变时的回调函数
	ra_connect_wifi("WDD_TEST", "56781234", NULL, 30 * 1000);
}
  • ra_connect_wifi()中第四个参数为wifi连接的超时时间,超时后设备停止wifi连接,并进入到设备状态改变的回调函数中,此时的item == RA_DEVICE_STATE_WLAN_CONNECT_FAILED && current_state == ra_true
  • 设备登陆服务器后就可以进行开发者自己的业务实现,同时,wifi连接异常及服务器连接异常处理开发者无需自行实现,SDK中集成了wifi重连及服务器重连机制。
  • 设备登陆服务器时需要prodKey(在HEKR console平台创建产品时生成,长度为32 Bytes),请在ra_user_main()中调用ra_set_parameter_string()来设置,如ra_set_parameter_string("prodKey", "12345678123456781234567812345678");

###5.9 UDP局域网接口

SDK局域网通信采用UDP协议,wifi模块端作为Server,监听固定端口,端口号为10000,APP端作为Client。

Client端的ip和port存在于UDP接收回调函数的参数ra_remote_info_t *中。

示例代码:

#include <ra_lan_comm.h>

//UDP数据接收回调函数中,ra_remote_info_t *remote是client端的ip和port
void lan_recv_cb(ra_remote_info_t *remote, char *data, ra_uint16_t size)
{
	os_printf("remote ip:%u:%u:%u:%u port:%u\n",
		remote->remote_ip[0],
		remote->remote_ip[1],
		remote->remote_ip[2],
		remote->remote_ip[3],
		remote->remote_port);

	os_printf("data = %s\n", data);
	ra_lan_comm_send(remote, data, size); //send data to remote
}

void ra_user_main()
{
	ra_lan_comm_register_recv_callback(lan_recv_cb); //注册UDP数据接收回调函数
	ra_lan_comm_server_start(); //启动UDP server,监听10000端口

	//连接wifi
	ra_connect_wifi("WDD_TEST", "56781234", NULL, 30 * 1000);
}

###5.10 OTA升级

esp8266的OTA升级方式将flash map分为A/B两个区,固件默认烧录到A区,OTA升级将新固件下载到B区,升级完成后系统重启从B区启动。再次升级时则固件下载至A分区,并从A分区启动,依次更替。

OTA升级指令(action为devUpgrade)是由云端主动下发,用户需要将指令中参数URL、MD5和固件类型提取出来,然后调用ra_start_dev_upgrade()启动OTA升级。用户在解析devUpgrade指令时可以不校验参数,ra_start_dev_upgrade()内部会进行校验,如果参数无误,则返回值为0,向云端回应devUpgradeResp时code为200;如果参数有误,则返回值为非0,向云端回应devUpgradeResp时code为非200(自行定义)。

注:如果代码中调用了ra_enable_cloud_data_parse()函数,则SDK内部集成了OTA升级,开发者无需调用OTA相关API来实现OTA升级。

示例代码:

void OTA_successful_callback(void)
{
	os_printf("OTA_successful!\n");

	//升级成功后,要执行ra_system_upgrade_reboot()重启完成升级
	ra_timer_t timer; 
	ra_timer_new(&timer);
	ra_timer_set_callback(timer, ra_system_upgrade_reboot, NULL);
	ra_timer_start(timer, 2*1000, ra_false);
}

void OTA_fail_callback(int error_code)
{
	os_printf("OTA_fail!\n");
}

void ra_user_main()
{
	int ret; 
	ra_register_dev_upgrade_success_callback(OTA_successful_callback); //注册OTA成功回调函数
	ra_register_dev_upgrade_failed_callback(OTA_fail_callback); //注册OTA失败回调函数
	ret = ra_start_dev_upgrade(dev_TID, URL, MD5, B); //启动模块OTA升级,OTA的固件类型为B
	if(ret == 0)
	{
		//上报devUpgradeResp,code为200
	}
	else
	{
		//上报devUpgradeResp,code为非200
	}
}
  • OTA升级成功后进入升级成功回调函数需调用ra_system_upgrade_reboot(),此时系统会重启,方可正常运行新版本固件。
  • OTA进度上报在SDK中集成了,无需用户单独编程。

###5.11 浮点打印的解决方案

由于esp8266 SDK并不支持浮点打印(包括printfsprintf),氦氪在此基础上移植了一种变通解决方案来支持浮点打印。为了区分原生api,支持浮点的api命名为c_printfc_sprintf,在#include <c_sprintf.h>中。

  • SDK中的cJSON也支持浮点。

6. 编码注意事项


  • include/ra目录下提供的api函数均是以ra_为前缀命名,是该SDK主推供开发者调用的API接口。由于该SDK本身是基于原生ESP8266 NON_RTOS SDK深度开发而来,故ESP8266底层API也对开发者开放可供调用,但我们不推荐开发者使用底层API,以免造成RA接口的失效。ra_前缀api使用说明请参考ra_embedded_api.chm文档。
  • 占用CPU时间超过500ms的函数不要在ra_user_main()直接调用,推荐在系统初始化完成后。可在入口函数中调用ra_register_system_init_done_callback()来注册系统初始化完成的回调函数。然后在回调函数中调用敏感api。
  • 敏感API均为网络相关API,有ra_disconnect_wifi()
  • 设备接收到云端的数据都是操作指令(如appSend、devUpgrade、devSendResp等)对应的JSON字符串,用户需要自行解析成JSON格式,SDK中已经集成了cJSON接口,请参考头文件cJSON.h。
修饰符说明
  • FUN_ATTRIBUTE:函数修饰符。函数前不加它,则上电启动时将函数代码从flash加载到iram;在函数前加上它,则在上电启动后函数被调用时才被加载到iram中。由于芯片iram空间有限,编码时请在函数前加上此修饰符,但不能给中断回调函数添加(定时器回调函数除外)。
  • RODATA_ATTRIBUTE:变量修饰符。在变量(包括数组)定义前添加它,它将被写入flash中,减少系统运行期间堆的占用,只在变量使用时从flash中读取到ram中。

Change Log

V1.0.2: SDK更新至v1.5.4.1 ,优化心跳机制

Empty file

About

嵌入式4.x固件开发SDK expand collapse
C
Cancel

Releases

No release

Contributors

All

Activities

Load More
can not load any more
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
C
1
https://gitee.com/HEKRCLOUD/hekr-esp8266-sdk-ra.git
git@gitee.com:HEKRCLOUD/hekr-esp8266-sdk-ra.git
HEKRCLOUD
hekr-esp8266-sdk-ra
hekr-esp8266-sdk-ra
master

Search

344bd9b3 5694891 D2dac590 5694891