1 /*
2  * Copyright (C) 2015-2018 Alibaba Group Holding Limited
3  */
4 
5 #ifndef __OTA_COAP_C_H__
6 #define __OTA_COAP_C_H__
7 #if (OTA_SIGNAL_CHANNEL) == 2
8 
9 #include "iotx_ota_internal.h"
10 
11 /* OSC, OTA signal channel */
12 
13 /* Specify the maximum characters of version */
14 #define OSC_COAP_URI_MAX_LEN (135) /* IoTx CoAP uri maximal length */
15 
16 typedef struct {
17     void *coap;
18     const char *product_key;
19     const char *device_name;
20     ota_cb_fpt cb;
21     void *context;
22 } otacoap_Struct_t, *otacoap_Struct_pt;
23 
24 static otacoap_Struct_pt h_osc_coap = NULL;
25 
otacoap_response_handler(void * arg,void * p_response)26 static void otacoap_response_handler(void *arg, void *p_response)
27 {
28     int len = 0;
29     unsigned char *p_payload = NULL;
30     iotx_coap_resp_code_t resp_code;
31     IOT_CoAP_GetMessageCode(p_response, &resp_code);
32     IOT_CoAP_GetMessagePayload(p_response, &p_payload, &len);
33     OTA_LOG_DEBUG("CoAP response code = %d", resp_code);
34     OTA_LOG_DEBUG("[CoAP msg_len=%d, msg=%s\r\n", len, p_payload);
35 
36     if ((NULL != h_osc_coap) && (NULL != p_payload)) {
37         h_osc_coap->cb(h_osc_coap->context, (const char *)p_payload,
38                        (uint32_t)len);
39     }
40 }
41 
42 /* Generate topic name according to @ota_topic_type, @product_key, @device_name
43  */
44 /* and then copy to @buf. */
45 /* 0, successful; -1, failed */
otacoap_GenTopicName(char * buf,size_t buf_len,const char * ota_topic_type,const char * product_key,const char * device_name)46 static int otacoap_GenTopicName(char *buf, size_t buf_len,
47                                 const char *ota_topic_type,
48                                 const char *product_key,
49                                 const char *device_name)
50 {
51     int ret;
52 
53     ret = OTA_SNPRINTF(buf, buf_len, "/topic/ota/device/%s/%s/%s",
54                        ota_topic_type, product_key, device_name);
55 
56     if (ret >= buf_len) {
57         return -1;
58     }
59 
60     if (ret < 0) {
61         OTA_LOG_ERROR("snprintf failed");
62         return -1;
63     }
64 
65     return 0;
66 }
67 
68 /* report progress of OTA */
otacoap_Publish(otacoap_Struct_pt handle,const char * topic_type,const char * msg)69 static int otacoap_Publish(otacoap_Struct_pt handle, const char *topic_type,
70                            const char *msg)
71 {
72     int ret;
73     char uri[IOTX_URI_MAX_LEN + 1] = { 0 };
74     iotx_message_t message;
75     message.p_payload = (unsigned char *)msg;
76     message.payload_len = (unsigned short)strlen(msg);
77     message.resp_callback = otacoap_response_handler;
78     message.msg_type = IOTX_MESSAGE_CON;
79     message.content_type = IOTX_CONTENT_TYPE_JSON;
80 
81     /* topic name: /topic/ota/device/${topic_type}/${productKey}/${deviceName}
82      */
83     ret = otacoap_GenTopicName(uri, OSC_COAP_URI_MAX_LEN, topic_type,
84                                handle->product_key, handle->device_name);
85     if (ret < 0) {
86         OTA_LOG_ERROR("generate topic name failed");
87         return -1;
88     }
89 
90     ret = IOT_CoAP_SendMessage(handle->coap, (char *)uri, &message);
91     if (ret != IOTX_SUCCESS) {
92         OTA_LOG_ERROR("send CoAP msg failed%d", ret);
93         return -1;
94     }
95 
96     return 0;
97 }
98 
osc_Init(const char * product_key,const char * device_name,void * ch_signal,ota_cb_fpt cb,void * context)99 void *osc_Init(const char *product_key, const char *device_name,
100                void *ch_signal, ota_cb_fpt cb, void *context)
101 {
102     otacoap_Struct_pt h_osc = NULL;
103 
104     h_osc = OTA_MALLOC(sizeof(otacoap_Struct_t));
105     if (h_osc == NULL) {
106         OTA_LOG_ERROR("allocate for h_osc failed");
107         return NULL;
108     }
109 
110     memset(h_osc, 0, sizeof(otacoap_Struct_t));
111 
112     h_osc->coap = ch_signal;
113     h_osc->product_key = product_key;
114     h_osc->device_name = device_name;
115     h_osc->cb = cb;
116     h_osc->context = context;
117 
118     h_osc_coap = h_osc;
119 
120     return h_osc;
121 }
122 
osc_Deinit(void * handle)123 int osc_Deinit(void *handle)
124 {
125     if (NULL != handle) {
126         OTA_FREE(handle);
127     }
128 
129     return 0;
130 }
131 
132 /* report progress of OTA */
osc_ReportProgress(void * handle,const char * msg)133 int osc_ReportProgress(void *handle, const char *msg)
134 {
135     return otacoap_Publish(handle, "progress", msg);
136 }
137 
138 /* report version of OTA firmware */
osc_ReportVersion(void * handle,const char * msg)139 int osc_ReportVersion(void *handle, const char *msg)
140 {
141     static int state = 0;
142     int ret;
143 
144     if (0 == state) { /* report version in initial state */
145         ret = otacoap_Publish(handle, "inform", msg);
146         if (0 != ret) {
147             return ret;
148         }
149         state = 1;
150     }
151 
152     /* request new firmware after initial state */
153     return otacoap_Publish(handle, "request", msg);
154 }
155 
156 #endif /* #if (OTA_SIGNAL_CHANNEL) == 2 */
157 #endif
158