first commit

This commit is contained in:
ethan.du 2021-01-22 16:21:57 +08:00
commit 9809fe4350
14 changed files with 986 additions and 0 deletions

91
README.md Normal file
View File

@ -0,0 +1,91 @@
## 编译
编译依赖cmake 2.8依赖的nats库仅支持cmake编译
```
sudo apt-get install cmake
```
编译方式GNU Make
```
make
```
## 打包方式
将samples改名为main和依赖的动态链接库如果有一起打成zip的压缩包,将压缩包上传到子设备驱动
```
cd samples
cp samples main
zip -r abc.zip main
```
## API参考文档
/**
* @brief 应用初始化
*
* @param void:
*
* @retval : 成功则返回APP_OK
*/
app_status app_common_init(void)
/**
* @brief 获取应用名称
*
* @param void:
*
* @retval : 成功则返回应用名称的字符串失败返回NULL
*/
char *app_get_name(void)
/**
* @brief 获取产品SN号的字符串
*
* @param void:
*
* @retval : 成功则返回产品SN号的字符串失败返回NULL
*/
char *app_get_productSN(void)
/**
* @brief 获取设备SN号的字符串
*
* @param void:
*
* @retval : 成功则返回设备SN号的字符串失败返回NULL
*/
char *app_get_deviceSN(void)
/**
* @brief 获取应用配置信息的字符串
*
* @param void:
*
* @retval : 成功则返回应用配置信息的字符串失败返回NULL
*/
char *app_get_info(void)
/**
* @brief 注册下行消息回调函数
*
* @param handle: 下行消息回调函数指针
*
* @retval : 成功则返回APP_OK
*/
app_status app_register_cb(msg_handler handle)
/**
* @brief 记录日志
*
* @param level: 日志等级分为DEBUG、INFO、WARNING、ERROR
* @param format: 日志记录格式
*
* @retval : void
*/
void log_write(log_level level, const char *format,...)

396
app/app.c Normal file
View File

@ -0,0 +1,396 @@
#include "app.h"
natsConnection *conn = NULL;
natsSubscription *sub = NULL;
static cJSON *app_config_json = NULL;
char *app_name = NULL;
char *app_productSN = NULL;
char *app_deviceSN = NULL;
char *app_info = NULL;
msg_handler cb = NULL;
char edge_router_subject[NATS_SUBJECT_MAX_LEN] = {0};
app_status nats_subscribe(const char *subject, natsMsgHandler cb, void *cbClosure)
{
app_status status = APP_OK;
natsConnection_Subscribe(&sub, conn, subject, cb, cbClosure);
natsConnection_Flush(conn);
return status;
}
app_status nats_publish(const char *topic, const char *str)
{
app_status status = APP_OK;
natsConnection_PublishString(conn, topic, str);
natsConnection_Flush(conn);
return status;
}
void log_print(const char *format,...)
{
va_list args;
va_start(args, format);
vprintf(format, args);
va_end(args);
fflush(stdout);
return;
}
void log_write(log_level level, const char *format,...)
{
if((level < LOG_DEBUG) || (level > LOG_ERROR))
{
return;
}
const char *log_lev[4] = {"debug", "info", "warn", "error"};
struct timeval stamp;
char *msg_str_rep = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == msg_str_rep)
{
return;
}
memset(msg_str_rep, 0, NATS_MSG_MAX_LEN);
gettimeofday(&stamp, NULL);
char *msg_str = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == msg_str)
{
APP_FREE(msg_str_rep);
return;
}
memset(msg_str, 0, NATS_MSG_MAX_LEN);
char *log_msg = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == log_msg)
{
APP_FREE(msg_str_rep);
APP_FREE(msg_str);
return;
}
memset(log_msg, 0, NATS_MSG_MAX_LEN);
va_list args;
va_start(args, format);
vsnprintf(msg_str, NATS_MSG_MAX_LEN, format, args);
va_end(args);
// 将json字段转换成字符串
replace_str(msg_str_rep, msg_str, "\"", "\\\"");
snprintf(log_msg, NATS_MSG_MAX_LEN, LOG_UPLOAD_FORMAT, app_get_name(), log_lev[level], msg_str_rep, stamp.tv_sec);
nats_publish(EDGE_LOG_UPLOAD_SUBJECT, log_msg);
APP_FREE(msg_str_rep);
APP_FREE(msg_str);
APP_FREE(log_msg);
return;
}
static void _parse_config(void)
{
if(NULL == app_config_json)
{
unsigned int file_len = 0;
FILE *fp;
file_len = calc_file_len(CONFIG_FILE_PATH);
char *driver_config_str_tmp = (char *)APP_MALLOC(file_len + 1);
if(NULL == driver_config_str_tmp)
{
log_write(LOG_ERROR, "file_str malloc fail!");
return;
}
memset(driver_config_str_tmp, 0, file_len + 1);
fp = fopen(CONFIG_FILE_PATH, "r");
if(NULL == fp)
{
log_write(LOG_ERROR, "cannot open file:%s", CONFIG_FILE_PATH);
return;
}
if(file_len != fread(driver_config_str_tmp, 1, file_len, fp))
{
log_write(LOG_ERROR, "fread file:%s fail!", CONFIG_FILE_PATH);
}
driver_config_str_tmp[file_len] = '\0';
fclose(fp);
log_print("driver_config_str_tmp:%s",driver_config_str_tmp);
app_config_json = cJSON_Parse(driver_config_str_tmp);
APP_FREE(driver_config_str_tmp);
/* parse appName */
cJSON *app_name_json = cJSON_GetObjectItem(app_config_json, "appName");
if(NULL == app_name_json)
{
log_write(LOG_ERROR, "parse appName fail!");
return;
}
int app_name_len = strlen(app_name_json->valuestring);
app_name = (char *)APP_MALLOC(app_name_len+1);
strncpy(app_name, app_name_json->valuestring, app_name_len);
app_name[app_name_len]='\0';
/* parse productSN */
cJSON *productSN_json = cJSON_GetObjectItem(app_config_json, "productSN");
if(NULL == productSN_json)
{
log_write(LOG_ERROR, "parse productSN fail!");
return;
}
int app_productSN_len = strlen(productSN_json->valuestring);
app_productSN = (char *)APP_MALLOC(app_productSN_len+1);
strncpy(app_productSN, productSN_json->valuestring, app_productSN_len);
app_productSN[app_productSN_len]='\0';
/* parse deviceSN */
cJSON *deviceSN_json = cJSON_GetObjectItem(app_config_json, "deviceSN");
if(NULL == deviceSN_json)
{
log_write(LOG_ERROR, "parse deviceSN fail!");
return;
}
int app_deviceSN_len = strlen(deviceSN_json->valuestring);
app_deviceSN = (char *)APP_MALLOC(app_deviceSN_len+1);
strncpy(app_deviceSN, deviceSN_json->valuestring, app_deviceSN_len);
app_deviceSN[app_deviceSN_len]='\0';
/* parse appInfo */
cJSON *appInfo_json = cJSON_GetObjectItem(app_config_json, "appInfo");
if(NULL == appInfo_json)
{
log_write(LOG_ERROR, "parse appInfo fail!");
return;
}
int app_info_len = strlen(cJSON_PrintUnformatted(appInfo_json));
app_info = (char *)APP_MALLOC(app_info_len+1);
strncpy(app_info, cJSON_PrintUnformatted(appInfo_json), app_info_len);
app_info[app_info_len]='\0';
}
return;
}
char *app_get_name()
{
if(NULL == app_name)
return NULL;
return app_name;
}
char *app_get_productSN()
{
if(NULL == app_productSN)
return NULL;
return app_productSN;
}
char *app_get_deviceSN()
{
if(NULL == app_deviceSN)
return NULL;
return app_deviceSN;
}
char *app_get_info()
{
if(NULL == app_info)
return NULL;
return app_info;
}
static void _handle_message(natsConnection *nc, natsSubscription *sub, natsMsg *msg, void *closure)
{
log_write(LOG_DEBUG, "Received msg: %s - %.*s", natsMsg_GetSubject(msg), natsMsg_GetDataLength(msg), natsMsg_GetData(msg));
cJSON *msg_json = cJSON_Parse(natsMsg_GetData(msg));
if (!msg_json)
{
log_write(LOG_ERROR, "_handle_message json parse error: [%s]",cJSON_GetErrorPtr());
goto end;
}
cJSON *topic = cJSON_GetObjectItem(msg_json, "topic");
if(NULL == topic)
{
log_write(LOG_ERROR, "cannot find topic, illegal msg");
cJSON_Delete(msg_json);
goto end;
}
log_write(LOG_DEBUG, "_handle_message topic:%s", topic->valuestring);
cJSON *msg_base64code = cJSON_GetObjectItem(msg_json, "payload");
if(NULL == msg_base64code)
{
log_write(LOG_ERROR, "cannot find payload, illegal msg");
cJSON_Delete(msg_json);
goto end;
}
log_write(LOG_DEBUG, "_handle_message msg_base64code:%s", msg_base64code->valuestring);
char *msg_base64decode = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == msg_base64decode)
{
log_write(LOG_ERROR, "msg_base64decode malloc fail!");
cJSON_Delete(msg_json);
goto end;
}
memset(msg_base64decode, 0, NATS_MSG_MAX_LEN);
base64_decode(msg_base64code->valuestring, strlen(msg_base64code->valuestring), msg_base64decode);
log_write(LOG_DEBUG, "_handle_message msg_base64decode:%s", msg_base64decode);
if(NULL != cb)
cb(topic->valuestring, msg_base64decode);
APP_FREE(msg_base64decode);
end:
natsMsg_Destroy(msg);
cJSON_Delete(msg_json);
return;
}
app_status app_register_cb(msg_handler handle)
{
app_status status = APP_OK;
char edge_app_subject[NATS_SUBJECT_MAX_LEN] = {0};
if((NULL == cb) && (NULL != handle))
cb = handle;
snprintf(edge_app_subject, NATS_SUBJECT_MAX_LEN, EDGE_APP_SUBJECT_FORMAT, app_get_name());
log_write(LOG_DEBUG, "edge_app_subject:%s",edge_app_subject);
status = nats_subscribe(edge_app_subject, _handle_message, NULL);
if(APP_OK != status)
{
log_write(LOG_ERROR, "edge_subscribe %s fail! status:%d", edge_app_subject, status);
return APP_PROTOCOL_ERROR;
}
return status;
}
app_status app_publish(const char *topic, const char *str)
{
app_status status = APP_OK;
if((NULL == topic) || (NULL == str))
{
return APP_INVALID_ARG;
}
char *normal_payload_base64 = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == normal_payload_base64)
{
log_write(LOG_ERROR, "normal_payload_base64 malloc fail!");
return APP_NO_MEMORY;
}
memset(normal_payload_base64, 0, NATS_MSG_MAX_LEN);
base64_encode(str, strlen(str), normal_payload_base64);
log_write(LOG_DEBUG, "dyn_reg_payload_base64:%s",normal_payload_base64);
char *normal_msg = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == normal_msg)
{
log_write(LOG_ERROR, "normal_msg malloc fail!");
APP_FREE(normal_payload_base64);
return APP_NO_MEMORY;
}
memset(normal_msg, 0, NATS_MSG_MAX_LEN);
snprintf(normal_msg, NATS_MSG_MAX_LEN, NORMAL_MSG_FORMAT, topic, normal_payload_base64, app_get_name());
log_write(LOG_DEBUG, "normal_msg:%s",normal_msg);
status = nats_publish(edge_router_subject, normal_msg);
APP_FREE(normal_payload_base64);
APP_FREE(normal_msg);
return status;
}
static void _handle_status_sync(union sigval v)
{
app_status status = APP_OK;
char *sync_msg = (char *)APP_MALLOC(NATS_MSG_MAX_LEN);
if(NULL == sync_msg)
{
log_write(LOG_ERROR, "sync_msg malloc fail!");
return;
}
memset(sync_msg, 0, NATS_MSG_MAX_LEN);
snprintf(sync_msg, NATS_MSG_MAX_LEN, STATUS_SYNC_FORMAT, app_get_name());
log_write(LOG_DEBUG, "sync_msg:%s",sync_msg);
status = nats_publish(EDGE_APP_STATUS_SUBJECT, sync_msg);
if(APP_OK != status)
{
log_write(LOG_ERROR, "publish sync msg fail!");
APP_FREE(sync_msg);
return;
}
APP_FREE(sync_msg);
return;
}
static void _fetch_online_status(void)
{
struct sigevent evp;
struct itimerspec ts;
timer_t timer;
int ret;
memset(&evp, 0, sizeof(evp));
evp.sigev_value.sival_ptr = &timer;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = _handle_status_sync;
evp.sigev_value.sival_int = 0;
ret = timer_create(CLOCK_REALTIME, &evp, &timer);
if(ret)
perror("timer_create");
ts.it_interval.tv_sec = 15;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 15;
ts.it_value.tv_nsec = 0;
ret = timer_settime(timer, 0, &ts, NULL);
if( ret )
perror("timer_settime");
return;
}
app_status app_common_init(void)
{
app_status status = APP_OK;
char *nats_server_url = NULL;
// nats server取IOTEDGE_NATS_ADDRESS环境或者本地host
nats_server_url = getenv("IOTEDGE_NATS_ADDRESS");
status = natsConnection_ConnectTo(&conn, nats_server_url != NULL?nats_server_url:NATS_SERVER_DEFAULT_URL);
if(APP_OK != status)
{
log_print("connect nats fail!\r\n");
return APP_PROTOCOL_ERROR;
}
_parse_config();
snprintf(edge_router_subject, NATS_SUBJECT_MAX_LEN, EDGE_ROUTER_SUBJECT_FORMAT, app_get_name());
log_print(LOG_DEBUG, "edge_router_subject:%s",edge_router_subject);
_fetch_online_status();
return APP_OK;
}

139
app/app.h Normal file
View File

@ -0,0 +1,139 @@
#ifndef _APP_H
#define _APP_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include "cJSON.h"
#include "nats.h"
#include "utils.h"
#define APP_MALLOC(s) malloc((s))
#define APP_CALLOC(c,s) calloc((c), (s))
#define APP_REALLOC(p, s) realloc((p), (s))
#define APP_FREE(p) free((p))
typedef enum
{
LOG_DEBUG = 0,
LOG_INFO,
LOG_WARN,
LOG_ERROR,
}log_level;
#define CONFIG_FILE_PATH "./etc/iotedge/config.json"
#define NATS_SERVER_DEFAULT_URL "tcp://127.0.0.1:4222"
//topic format
#define EDGE_APP_SUBJECT_FORMAT "edge.app.%s" //edge.app.appName
#define EDGE_ROUTER_SUBJECT_FORMAT "edge.router.%s" //edge.router.appName
#define EDGE_LOG_UPLOAD_SUBJECT "edge.log.upload" //log update
#define EDGE_APP_STATUS_SUBJECT "edge.app.status"
//payload firmat
#define NORMAL_MSG_FORMAT "{\"src\": \"app\",\"topic\": \"%s\",\"payload\": \"%s\",\"identity\": \"%s\"}"
#define STATUS_SYNC_FORMAT "{\"appName\": \"%s\"}"
#define LOG_UPLOAD_FORMAT "{\"module\": \"application_%s\",\"level\": \"%s\",\"message\": \"%s\",\"timestamp\": %ld}"
#define NATS_MSG_MAX_LEN 2048
#define NATS_SUBJECT_MAX_LEN 100
typedef enum
{
APP_OK = 0, ///< Success
APP_ERR, ///< Generic error
APP_PROTOCOL_ERROR, ///< Error when parsing a protocol message,
/// or not getting the expected message.
APP_IO_ERROR, ///< IO Error (network communication).
APP_LINE_TOO_LONG, ///< The protocol message read from the socket
/// does not fit in the read buffer.
APP_CONNECTION_CLOSED, ///< Operation on this connection failed because
/// the connection is closed.
APP_NO_SERVER, ///< Unable to connect, the server could not be
/// reached or is not running.
APP_STALE_CONNECTION, ///< The server closed our connection because it
/// did not receive PINGs at the expected interval.
APP_SECURE_CONNECTION_WANTED, ///< The client is configured to use TLS, but the
/// server is not.
APP_SECURE_CONNECTION_REQUIRED, ///< The server expects a TLS connection.
APP_CONNECTION_DISCONNECTED, ///< The connection was disconnected. Depending on
/// the configuration, the connection may reconnect.
APP_CONNECTION_AUTH_FAILED, ///< The connection failed due to authentication error.
APP_NOT_PERMITTED, ///< The action is not permitted.
APP_NOT_FOUND, ///< An action could not complete because something
/// was not found. So far, this is an internal error.
APP_ADDRESS_MISSING, ///< Incorrect URL. For instance no host specified in
/// the URL.
APP_INVALID_SUBJECT, ///< Invalid subject, for instance NULL or empty string.
APP_INVALID_ARG, ///< An invalid argument is passed to a function. For
/// instance passing NULL to an API that does not
/// accept this value.
APP_INVALID_SUBSCRIPTION, ///< The call to a subscription function fails because
/// the subscription has previously been closed.
APP_INVALID_TIMEOUT, ///< Timeout must be positive numbers.
APP_ILLEGAL_STATE, ///< An unexpected state, for instance calling
/// #natsSubscription_NextMsg() on an asynchronous
/// subscriber.
APP_SLOW_CONSUMER, ///< The maximum number of messages waiting to be
/// delivered has been reached. Messages are dropped.
APP_MAX_PAYLOAD, ///< Attempt to send a payload larger than the maximum
/// allowed by the NATS Server.
APP_MAX_DELIVERED_MSGS, ///< Attempt to receive more messages than allowed, for
/// instance because of #natsSubscription_AutoUnsubscribe().
APP_INSUFFICIENT_BUFFER, ///< A buffer is not large enough to accommodate the data.
APP_NO_MEMORY, ///< An operation could not complete because of insufficient
/// memory.
APP_SYS_ERROR, ///< Some system function returned an error.
APP_TIMEOUT, ///< An operation timed-out. For instance
/// #natsSubscription_NextMsg().
APP_FAILED_TO_INITIALIZE, ///< The library failed to initialize.
APP_NOT_INITIALIZED, ///< The library is not yet initialized.
APP_SSL_ERROR, ///< An SSL error occurred when trying to establish a
/// connection.
APP_NO_SERVER_SUPPORT, ///< The server does not support this action.
APP_NOT_YET_CONNECTED, ///< A connection could not be immediately established and
/// #natsOptions_SetRetryOnFailedConnect() specified
/// a connected callback. The connect is retried asynchronously.
APP_DRAINING, ///< A connection and/or subscription entered the draining mode.
/// Some operations will fail when in that mode.
APP_INVALID_QUEUE_NAME, ///< An invalid queue name was passed when creating a queue subscription.
} app_status;
typedef void (*msg_handler)(char *topic, char *payload);
char *app_get_name();
char *app_get_productSN();
char *app_get_deviceSN();
char *app_get_info();
app_status app_register_cb(msg_handler handle);
app_status app_publish(const char *topic, const char *str);
app_status app_common_init(void);
void log_write(log_level level, const char *format,...);
#endif

25
app/app.mk Normal file
View File

@ -0,0 +1,25 @@
include ../make.settings
CFLAGS = -g -Wall -O2 -D_GNU_SOURCE -std=c99
APP_LIB = libapp.a
INCLUDE_PATH = -I$(PWD)
INCLUDE = $(INCLUDE_PATH)/build/cjson $(INCLUDE_PATH)/build/nats
OBJS = ./app.o \
./utils.o \
all : $(APP_LIB) install
$(APP_LIB): $(OBJS)
$(AR) cr $@ $(OBJS)
$(OBJS):%o:%c
$(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE)
install:
mkdir -p $(PWD)/build/app
cp $(APP_LIB) $(PWD)/build/app
cp *.h $(PWD)/build/app
clean:
-$(RM) -r $(APP_LIB) $(OBJS)

180
app/utils.c Normal file
View File

@ -0,0 +1,180 @@
#include "utils.h"
// base64 转换表, 共64个
static const char base64_alphabet[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N',
'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '/'};
// 解码时使用
static const unsigned char base64_suffix_map[256] = {
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 253, 255,
255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 253, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255 };
static char cmove_bits(unsigned char src, unsigned lnum, unsigned rnum) {
src <<= lnum; // src = src << lnum;
src >>= rnum; // src = src >> rnum;
return src;
}
int base64_encode(const char *indata, int inlen, char *outdata) {
int ret = 0; // return value
if (indata == NULL || inlen == 0) {
return ret = -1;
}
int in_len = 0; // 源字符串长度, 如果in_len不是3的倍数, 那么需要补成3的倍数
int pad_num = 0; // 需要补齐的字符个数, 这样只有2, 1, 0(0的话不需要拼接, )
if (inlen % 3 != 0) {
pad_num = 3 - inlen % 3;
}
in_len = inlen + pad_num; // 拼接后的长度, 实际编码需要的长度(3的倍数)
char *p = outdata; // 定义指针指向传出data的首地址
//编码, 长度为调整后的长度, 3字节一组
int i = 0;
for (i = 0; i < in_len; i+=3) {
int value = *indata >> 2; // 将indata第一个字符向右移动2bit(丢弃2bit)
char c = base64_alphabet[value]; // 对应base64转换表的字符
*p = c; // 将对应字符(编码后字符)赋值给outdata第一字节
//处理最后一组(最后3字节)的数据
if (i == inlen + pad_num - 3 && pad_num != 0) {
if(pad_num == 1) {
*(p + 1) = base64_alphabet[(int)(cmove_bits(*indata, 6, 2) + cmove_bits(*(indata + 1), 0, 4))];
*(p + 2) = base64_alphabet[(int)cmove_bits(*(indata + 1), 4, 2)];
*(p + 3) = '=';
} else if (pad_num == 2) { // 编码后的数据要补两个 '='
*(p + 1) = base64_alphabet[(int)cmove_bits(*indata, 6, 2)];
*(p + 2) = '=';
*(p + 3) = '=';
}
} else { // 处理正常的3字节的数据
*(p + 1) = base64_alphabet[cmove_bits(*indata, 6, 2) + cmove_bits(*(indata + 1), 0, 4)];
*(p + 2) = base64_alphabet[cmove_bits(*(indata + 1), 4, 2) + cmove_bits(*(indata + 2), 0, 6)];
*(p + 3) = base64_alphabet[*(indata + 2) & 0x3f];
}
p += 4;
indata += 3;
}
return ret;
}
int base64_decode(const char *indata, int inlen, char *outdata) {
int ret = 0;
if (indata == NULL || inlen <= 0 || outdata == NULL) {
return ret = -1;
}
if (inlen % 4 != 0) { // 需要解码的数据不是4字节倍数
return ret = -2;
}
int t = 0, x = 0, y = 0, i = 0;
unsigned char c = 0;
int g = 3;
while (indata[x] != 0) {
// 需要解码的数据对应的ASCII值对应base64_suffix_map的值
c = base64_suffix_map[(unsigned int)indata[x++]];
if (c == 255) return -1;// 对应的值不在转码表中
if (c == 253) continue;// 对应的值是换行或者回车
if (c == 254) { c = 0; g--; }// 对应的值是'='
t = (t<<6) | c; // 将其依次放入一个int型中占3字节
if (++y == 4) {
outdata[i++] = (unsigned char)((t>>16)&0xff);
if (g > 1) outdata[i++] = (unsigned char)((t>>8)&0xff);
if (g > 2) outdata[i++] = (unsigned char)(t&0xff);
y = t = 0;
}
}
return ret;
}
int calc_file_len(const char *file_path)
{
FILE *fp;
fp = fopen(file_path, "r");
if(NULL == fp)
{
printf("cannot open file:%s\r\n",file_path);
return 0;
}
//计算文件大小,申请内存
fseek(fp,0L,SEEK_END);
int file_len = ftell(fp);
fclose(fp);
return file_len;
}
static int _count_string(char *data, char *key)
{
int count = 0;
int klen = strlen(key);
char *pos_start = data, *pos_end;
while (NULL != (pos_end = strstr(pos_start, key))) {
pos_start = pos_end + klen;
count++;
}
return count;
}
void replace_str(char *new_buf, char *data, char *rep, char *to)
{
int rep_len = strlen(rep);
int to_len = strlen(to);
int counts = _count_string(data, rep);
if(0 == counts)
{
strcpy(new_buf, data);
return;
}
char *pos_start = data, *pos_end, *pbuf = new_buf;
int copy_len;
while (NULL != (pos_end = strstr(pos_start, rep))) {
copy_len = pos_end - pos_start;
strncpy(pbuf, pos_start, copy_len);
pbuf += copy_len;
strcpy(pbuf, to);
pbuf += to_len;
pos_start = pos_end + rep_len;
}
strcpy(pbuf, pos_start);
return;
}

16
app/utils.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef _UTILS_H
#define _UTILS_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <time.h>
#include <stdarg.h>
#include <signal.h>
int base64_encode(const char *indata, int inlen, char *outdata);
int base64_decode(const char *indata, int inlen, char *outdata);
int calc_file_len(const char *file_path);
void replace_str(char *new_buf, char *data, char *rep, char *to);
#endif

BIN
deps/cJSON-1.7.7.tar.gz vendored Normal file

Binary file not shown.

3
deps/deps.cmake vendored Normal file
View File

@ -0,0 +1,3 @@
set(CMAKE_SYSTEM_NAME Linux)
#set(CMAKE_C_COMPILER /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc)
set(CMAKE_C_COMPILER gcc)

25
deps/deps.mk vendored Normal file
View File

@ -0,0 +1,25 @@
include ../make.settings
# 解压nats组件源码并完成编译和安装
LIB_NATS_TAR = $(PWD)/deps/nats.c-2.1.0
LIB_CJSON_TAR = $(PWD)/deps/cJSON-1.7.7
LIB_NATS_DIR = $(PWD)/build/nats
LIB_CJSON_DIR = $(PWD)/build/cjson
all :
tar xvfz $(LIB_NATS_TAR).tar.gz
mkdir -p $(LIB_NATS_DIR)
cd $(LIB_NATS_TAR) && cmake . -DCMAKE_TOOLCHAIN_FILE=../deps.cmake -DNATS_BUILD_WITH_TLS=OFF -DNATS_BUILD_STREAMING=OFF -DNATS_BUILD_NO_SPIN=ON && $(MAKE)
cp $(LIB_NATS_TAR)/src/libnats_static.a $(LIB_NATS_DIR)
cp $(LIB_NATS_TAR)/src/nats.h $(LIB_NATS_DIR)
cp $(LIB_NATS_TAR)/src/status.h $(LIB_NATS_DIR)
cp $(LIB_NATS_TAR)/src/version.h $(LIB_NATS_DIR)
mkdir -p $(LIB_CJSON_DIR)
tar xvfz $(LIB_CJSON_TAR).tar.gz
cd $(LIB_CJSON_TAR) && $(MAKE) clean && $(MAKE) CC=$(CC) AR=$(AR) static
cp $(LIB_CJSON_TAR)/libcjson.a $(LIB_CJSON_DIR)
cp $(LIB_CJSON_TAR)/cJSON.h $(LIB_CJSON_DIR)
clean :
rm -rf $(LIB_NATS_TAR)
rm -rf $(LIB_CJSON_TAR)

BIN
deps/nats.c-2.1.0.tar.gz vendored Normal file

Binary file not shown.

5
make.settings Normal file
View File

@ -0,0 +1,5 @@
#PLATFORM_TOOL = arm-linux-gnueabihf-
PLATFORM_TOOL =
CC := $(PLATFORM_TOOL)gcc
AR := $(PLATFORM_TOOL)ar
LD= $(PLATFORM_TOOL)ld

21
makefile Normal file
View File

@ -0,0 +1,21 @@
include make.settings
# default compile output
all :
$(MAKE) app_sdk_c
$(MAKE) -C samples -f samples.mk
# linkedge device access sdk
app_sdk_c :
$(MAKE) -C deps -f deps.mk
$(MAKE) -C app -f app.mk
# clean tempory compile resource
clean:
$(MAKE) -C deps -f deps.mk clean
$(MAKE) -C app -f app.mk clean
$(MAKE) -C samples -f samples.mk clean
-$(RM) -r ./build
-$(RM) -r ./deps/cJSON-1.7.7/
-$(RM) -r ./deps/nats.c-master/
.PHONY: deps app samples

69
samples/samples.c Normal file
View File

@ -0,0 +1,69 @@
#include "app.h"
void recvmsg_handler(char *topic, char *payload)
{
log_write(LOG_INFO, "receive topic:%s",topic);
log_write(LOG_INFO, "receive payload:%s",payload);
return;
}
int main(int argc, char **argv)
{
app_status status = APP_OK;
char topic_str[100] = {0};
struct timeval stamp;
char time_stamp[100] = {0};
cJSON *app_info = NULL;
//初始化获取产品、设备SN号信息
status = app_common_init();
if(APP_OK != status)
{
log_write(LOG_ERROR, "app_common_init fail");
goto end;
}
log_write(LOG_INFO, "productSN:%s, deviceSN:%s",app_get_productSN(),app_get_deviceSN());
log_write(LOG_INFO, "app info:%s",app_get_info());
//注册回调函数
status = app_register_cb(recvmsg_handler);
if(APP_OK != status)
{
log_write(LOG_ERROR, "app_register_cb fail");
goto end;
}
//获取应用配置信息
app_info = cJSON_Parse(app_get_info());
if (!app_info)
{
log_write(LOG_ERROR, "parse app info fail");
goto end;
}
/*
"topic":"/%s/%s/upload"
*/
cJSON *topic_format = cJSON_GetObjectItem(app_info, "topic");
snprintf(topic_str, 100, topic_format->valuestring, app_get_productSN(), app_get_deviceSN());
while(1)
{
sleep(5);
gettimeofday(&stamp, NULL);
memset(time_stamp, 0, 100);
snprintf(time_stamp, 100, "{\"timestamp\": \"%ld\"}", stamp.tv_sec);
log_write(LOG_INFO, "send message[%s]", time_stamp);
status = app_publish(topic_str, time_stamp);
if(APP_OK != status)
{
log_write(LOG_ERROR, "app_publish fail");
goto end;
}
}
end:
cJSON_Delete(app_info);
return status;
}

16
samples/samples.mk Normal file
View File

@ -0,0 +1,16 @@
include ../make.settings
CFLAGS = -g -Wall -O2 -lpthread
INCLUDE = -I../build/cjson -I../build/nats -I../build/app
LIBS = ../build/app/libapp.a ../build/nats/libnats_static.a ../build/cjson/libcjson.a
src = samples.c
target = samples
all : $(target)
$(target) :
$(CC) -o $(target) $(src) $(LIBS) $(INCLUDE) $(CFLAGS) -lrt
clean:
-$(RM) $(target) $(target).o