Change mbtk_source_v2
Change-Id: I0699762ab517b43060aad43fec0d87c2bfc1445d
diff --git a/mbtk/libmbtk_lib/Makefile b/mbtk/libmbtk_lib/Makefile
index 8183ffd..679250b 100755
--- a/mbtk/libmbtk_lib/Makefile
+++ b/mbtk/libmbtk_lib/Makefile
@@ -4,17 +4,31 @@
LOCAL_PATH=$(BUILD_ROOT)/libmbtk_lib
INC_DIR += \
- -I$(LOCAL_PATH)/inc
+ -I$(LOCAL_PATH)/audio \
+ -I$(LOCAL_PATH)/coap \
+ -I$(LOCAL_PATH)/common \
+ -I$(LOCAL_PATH)/ecall \
+ -I$(LOCAL_PATH)/fota \
+ -I$(LOCAL_PATH)/ftp \
+ -I$(LOCAL_PATH)/gnss \
+ -I$(LOCAL_PATH)/http \
+ -I$(LOCAL_PATH)/mqtt \
+ -I$(LOCAL_PATH)/mqtt/MQTTPacket \
+ -I$(LOCAL_PATH)/net \
+ -I$(LOCAL_PATH)/tcpip \
+ -I$(LOCAL_PATH)/ril
LIB_DIR +=
-LIBS += -llog -lubus -lubox -luci -lprop2uci -lrilutil -lblobmsg_json -ldl
+LIBS += -llog -lubus -lubox -luci -lprop2uci -lrilutil -lblobmsg_json -ldl -lcutils -laudio-apu -lssl -lcrypto
+ifeq ($(BUILD_LIB_TYPE), shared)
CFLAGS += -shared -Wl,-shared,-Bsymbolic
+endif
DEFINE += -DMBTK_NET_MONITOR_SUPPORT
-MY_FILES_PATH:=$(LOCAL_PATH)/src
+#MY_FILES_PATH:=$(LOCAL_PATH)/src
#ifeq ($(CONFIG_MBTK_QL_SUPPORT),y)
#MY_FILES_PATH += $(LOCAL_PATH)/ql
#endif
@@ -29,34 +43,108 @@
#MY_SRC_LIST := $(MY_SRC_LIST:$(LOCAL_PATH)/%=%)
#LOCAL_SRC_FILES += $(MY_SRC_LIST)
-LOCAL_SRC_FILES = src/ds_ASBuffer.cpp \
- src/ds_ASString.cpp \
- src/mbtk_at.c \
- src/mbtk_bs_position.c \
- src/mbtk_file.c \
- src/mbtk_list.c \
- src/mbtk_log.c \
- src/mbtk_map.c \
- src/mbtk_ntp.c \
- src/mbtk_queue.c \
- src/mbtk_str.c \
- src/mbtk_task.c \
- src/mbtk_utf.c \
- src/mbtk_utils.c \
- src/ringbuffer.c \
- src/mbtk_mtd.c \
- src/mbtk_device_info.c \
- src/mbtk_version.c \
- src/mbtk_gpio.c
+# common
+LOCAL_SRC_FILES = \
+ common/ds_ASBuffer.cpp \
+ common/ds_ASString.cpp \
+ common/mbtk_at.c \
+ common/mbtk_bs_position.c \
+ common/mbtk_file.c \
+ common/mbtk_list.c \
+ common/mbtk_log.c \
+ common/mbtk_map.c \
+ common/mbtk_ntp.c \
+ common/mbtk_queue.c \
+ common/mbtk_str.c \
+ common/mbtk_task.c \
+ common/mbtk_utf.c \
+ common/mbtk_utils.c \
+ common/ringbuffer.c \
+ common/mbtk_mtd.c \
+ common/mbtk_device_info.c \
+ common/mbtk_version.c \
+ common/mbtk_gpio.c \
+ common/mbtk_adc.c \
+ common/mbtk_debug.c
-ifeq ($(MBTK_DUMP_SUPPORT), y)
-LOCAL_SRC_FILES += src/mbtk_debug.c
-endif
+# audio
+LOCAL_SRC_FILES += \
+ audio/mbtk_audio.c \
+ audio/mbtk_audio_gain.c \
+ audio/mbtk_pcm_stream.c \
+ audio/mbtk_wav.c \
+ audio/mbtk_audio_ubus.c
+
+# coap
+LOCAL_SRC_FILES += \
+ coap/mbtk_coap.c \
+ coap/mbtk_coap_api.cpp \
+ coap/mbtk_coap_pdu.cpp
+
+# fota
+LOCAL_SRC_FILES += \
+ fota/mbtk_fota.c
+
+# gnss
+LOCAL_SRC_FILES += \
+ gnss/mbtk_gnss.c
+
+# net
+LOCAL_SRC_FILES += \
+ net/mbtk_dhcp.c \
+ net/mbtk_ifc.c \
+ net/mbtk_net_control.c \
+ net/mbtk_sock.c \
+ net/mbtk_sock2.c
+
+# ril
+LOCAL_SRC_FILES += \
+ ril/mbtk_info.c \
+ ril/mbtk_info_api.c \
+ ril/mbtk_pdu_sms.c
+
+# ftp
+LOCAL_SRC_FILES += \
+ ftp/mbtk_ftp.c \
+ ftp/mbtk_ftp_at.c
+
+# http
+LOCAL_SRC_FILES += \
+ http/mbtk_http.c \
+ http/mbtk_http_base.c \
+ http/mbtk_http_chunks.c
+
+# mqtt
+LOCAL_SRC_FILES += \
+ mqtt/mbtk_mqtt.c \
+ mqtt/MQTTClient.c \
+ mqtt/MQTTLinux.c \
+ mqtt/MQTTPacket/core_sha1.c \
+ mqtt/MQTTPacket/core_sha256.c \
+ mqtt/MQTTPacket/MQTTConnectClient.c \
+ mqtt/MQTTPacket/MQTTConnectServer.c \
+ mqtt/MQTTPacket/MQTTDeserializePublish.c \
+ mqtt/MQTTPacket/MQTTFormat.c \
+ mqtt/MQTTPacket/MQTTPacket.c \
+ mqtt/MQTTPacket/MQTTSerializePublish.c \
+ mqtt/MQTTPacket/MQTTSubscribeClient.c \
+ mqtt/MQTTPacket/MQTTSubscribeServer.c \
+ mqtt/MQTTPacket/MQTTUnsubscribeClient.c \
+ mqtt/MQTTPacket/MQTTUnsubscribeServer.c
+
+# tcpip
+LOCAL_SRC_FILES += \
+ tcpip/mbtk_tcpip_at.c
+
OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
$(info OBJS = $(OBJS))
+ifeq ($(BUILD_LIB_TYPE), shared)
dtarget := $(OUT_DIR)/lib/libmbtk_lib.so
+else
+dtarget := $(OUT_DIR)/lib/libmbtk_lib.a
+endif
all: $(dtarget)
diff --git a/mbtk/libmbtk_lib/audio/g711_pcm_convert.c b/mbtk/libmbtk_lib/audio/g711_pcm_convert.c
new file mode 100755
index 0000000..0927253
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/g711_pcm_convert.c
@@ -0,0 +1,351 @@
+#include "g711_pcm_convert.h"
+
+
+#define SIGN_BIT (0x80) /* Sign bit for a A-law byte. */
+#define QUANT_MASK (0xf) /* Quantization field mask. */
+#define NSEGS (8) /* Number of A-law segments. */
+#define SEG_SHIFT (4) /* Left shift for segment number. */
+#define SEG_MASK (0x70) /* Segment field mask. */
+#define BIAS (0x84) /* Bias for linear code. */
+
+
+static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF,
+ 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF
+ };
+
+/* copy from CCITT G.711 specifications */
+unsigned char _u2a[128] = { /* u- to A-law conversions */
+ 1, 1, 2, 2, 3, 3, 4, 4,
+ 5, 5, 6, 6, 7, 7, 8, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 27, 29, 31, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44,
+ 46, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62,
+ 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 74, 75, 76, 77, 78, 79,
+ 81, 82, 83, 84, 85, 86, 87, 88,
+ 89, 90, 91, 92, 93, 94, 95, 96,
+ 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112,
+ 113, 114, 115, 116, 117, 118, 119, 120,
+ 121, 122, 123, 124, 125, 126, 127, 128
+};
+
+unsigned char _a2u[128] = { /* A- to u-law conversions */
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 48, 49, 49,
+ 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72,
+ 73, 74, 75, 76, 77, 78, 79, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87,
+ 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103,
+ 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119,
+ 120, 121, 122, 123, 124, 125, 126, 127
+};
+
+
+static short search(short val, short* table, short size)
+{
+ short i;
+ for (i = 0; i < size; i++) {
+ if (val <= *table++) {
+ return (i);
+ }
+ }
+ return (size);
+}
+
+/**
+ * @brief Convert a 16-bit linear PCM value to 8-bit A-law
+ *
+ * linear2alaw() accepts an 16-bit integer and encodes it as A-law data.
+ *
+ * Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 0000000wxyza 000wxyz
+ * 0000001wxyza 001wxyz
+ * 000001wxyzab 010wxyz
+ * 00001wxyzabc 011wxyz
+ * 0001wxyzabcd 100wxyz
+ * 001wxyzabcde 101wxyz
+ * 01wxyzabcdef 110wxyz
+ * 1wxyzabcdefg 111wxyz
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char linear2alaw(short pcm_val) /* 2's complement (16-bit range) */
+{
+ short mask;
+ short seg;
+ unsigned char aval;
+
+ if (pcm_val >= 0) {
+ mask = 0xD5; /* sign (7th) bit = 1 */
+ } else {
+ mask = 0x55; /* sign bit = 0 */
+ pcm_val = -pcm_val - 8;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /* Combine the sign, segment, and quantization bits. */
+
+ if (seg >= 8) { /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ } else {
+ aval = seg << SEG_SHIFT;
+ if (seg < 2) {
+ aval |= (pcm_val >> 4) & QUANT_MASK;
+ } else {
+ aval |= (pcm_val >> (seg + 3)) & QUANT_MASK;
+ }
+ return (aval ^ mask);
+ }
+}
+
+/**
+ * @brief Convert an A-law value to 16-bit linear PCM
+ *
+ */
+short alaw2linear(unsigned char a_val)
+{
+ short t;
+ short seg;
+
+ a_val ^= 0x55;
+ t = (a_val & QUANT_MASK) << 4;
+ seg = ((unsigned)a_val & SEG_MASK) >> SEG_SHIFT;
+
+ switch (seg) {
+ case 0:
+ t += 8;
+ break;
+ case 1:
+ t += 0x108;
+ break;
+ default:
+ t += 0x108;
+ t <<= seg - 1;
+ }
+
+ return ((a_val & SIGN_BIT) ? t : -t);
+}
+
+/**
+ * @brief Convert a linear PCM value to u-law
+ *
+ * In order to simplify the encoding process, the original linear magnitude
+ * is biased by adding 33 which shifts the encoding range from (0 - 8158) to
+ * (33 - 8191). The result can be seen in the following encoding table:
+ *
+ * Biased Linear Input Code Compressed Code
+ * ------------------------ ---------------
+ * 00000001wxyza 000wxyz
+ * 0000001wxyzab 001wxyz
+ * 000001wxyzabc 010wxyz
+ * 00001wxyzabcd 011wxyz
+ * 0001wxyzabcde 100wxyz
+ * 001wxyzabcdef 101wxyz
+ * 01wxyzabcdefg 110wxyz
+ * 1wxyzabcdefgh 111wxyz
+ *
+ * Each biased linear code has a leading 1 which identifies the segment
+ * number. The value of the segment number is equal to 7 minus the number
+ * of leading 0's. The quantization interval is directly available as the
+ * four bits wxyz. * The trailing bits (a - h) are ignored.
+ *
+ * Ordinarily the complement of the resulting code word is used for
+ * transmission, and so the code word is complemented before it is returned.
+ *
+ * For further information see John C. Bellamy's Digital Telephony, 1982,
+ * John Wiley & Sons, pps 98-111 and 472-476.
+ */
+unsigned char linear2ulaw(int pcm_val) /* 2's complement (16-bit range) */
+{
+ short mask;
+ short seg;
+ unsigned char uval;
+
+ /* Get the sign and the magnitude of the value. */
+ if (pcm_val < 0) {
+ pcm_val = BIAS - pcm_val;
+ mask = 0x7F;
+ } else {
+ pcm_val += BIAS;
+ mask = 0xFF;
+ }
+
+ /* Convert the scaled magnitude to segment number. */
+ seg = search(pcm_val, seg_end, 8);
+
+ /*
+ * Combine the sign, segment, quantization bits;
+ * and complement the code word.
+ */
+ if (seg >= 8) { /* out of range, return maximum value. */
+ return (0x7F ^ mask);
+ } else {
+ uval = (seg << 4) | ((pcm_val >> (seg + 3)) & 0xF);
+ return (uval ^ mask);
+ }
+}
+
+/**
+ * @brief Convert a u-law value to 16-bit linear PCM
+ *
+ * First, a biased linear code is derived from the code word. An unbiased
+ * output can then be obtained by subtracting 33 from the biased code.
+ *
+ * Note that this function expects to be passed the complement of the
+ * original code word. This is in keeping with ISDN conventions.
+ */
+int ulaw2linear(unsigned char u_val)
+{
+ short t;
+
+ /* Complement to obtain normal u-law value. */
+ u_val = ~u_val;
+
+ /*
+ * Extract and bias the quantization bits. Then
+ * shift up by the segment number and subtract out the bias.
+ */
+ t = ((u_val & QUANT_MASK) << 3) + BIAS;
+ t <<= ((unsigned)u_val & SEG_MASK) >> SEG_SHIFT;
+
+ return ((u_val & SIGN_BIT) ? (BIAS - t) : (t - BIAS));
+}
+
+/**
+ * @brief A-law to u-law conversion
+ *
+ * @param aval A-law value
+ * @return unsigned char u-law value
+ */
+unsigned char alaw2ulaw(unsigned char aval)
+{
+ aval &= 0xff;
+ return ((aval & 0x80) ? (0xFF ^ _a2u[aval ^ 0xD5]) :
+ (0x7F ^ _a2u[aval ^ 0x55]));
+}
+
+/**
+ * @brief u-law to A-law conversion
+ *
+ * @param uval u-law value
+ * @return unsigned char A-law value
+ */
+unsigned char ulaw2alaw(unsigned char uval)
+{
+ uval &= 0xff;
+ return ((uval & 0x80) ? (0xD5 ^ (_u2a[0xFF ^ uval] - 1)) :
+ (0x55 ^ (_u2a[0x7F ^ uval] - 1)));
+}
+
+/**
+ * @brief pcm data encode to g711 data
+ *
+ * user should be responsible for pCodecbit memmory
+ *
+ * @param pCodecBits store g711 encoded data
+ * @param pBuffer pcm raw data
+ * @param BufferSize pcm data len
+ * @param type g711 data type
+ * @return int encode data length
+ */
+int G711EnCode(char* pCodecBits, char* pBuffer, int BufferSize, enum g711type type)
+{
+ int i;
+ unsigned char* codecbits = (unsigned char*)pCodecBits;
+ short* buffer = (short*)pBuffer;
+
+ if (pCodecBits == 0 || pBuffer == 0 || BufferSize <= 0) {
+ return -1;
+ }
+
+ if (type == G711ALAW) {
+ for (i = 0; i < BufferSize / 2; i++) {
+ codecbits[i] = linear2alaw(buffer[i]);
+ }
+ } else {
+ for (i = 0; i < BufferSize / 2; i++) {
+ codecbits[i] = linear2ulaw(buffer[i]);
+ }
+ }
+
+ return BufferSize / 2;
+}
+
+/**
+ * @brief g711 data decode to pcm data
+ *
+ * user should be responsible for pRawData memmory
+ *
+ * @param pRawData store uncoded pcm data
+ * @param pBuffer g711 encoded data
+ * @param BufferSize g711 data len
+ * @param type g711 data type
+ * @return int pcm data len
+ */
+int G711Decode(char* pRawData, char* pBuffer, int BufferSize, enum g711type type)
+{
+ int i;
+ short* out_data = (short*)pRawData;
+ unsigned char* buffer = (unsigned char*)pBuffer;
+
+ if (pRawData == 0 || pBuffer == 0 || BufferSize <= 0) {
+ return -1;
+ }
+
+ if (type == G711ALAW) {
+ for (i = 0; i < BufferSize; i++) {
+ out_data[i] = alaw2linear(buffer[i]);
+ }
+ } else {
+ for (i = 0; i < BufferSize; i++) {
+ out_data[i] = ulaw2linear(buffer[i]);
+ }
+ }
+
+ return BufferSize * 2;
+}
+
+/**
+ * @brief g711 u-law data and a-law data convert
+ *
+ * @param alawdata g711 a-law data
+ * @param ulawdata g711 u-lwa data
+ * @param datasize input data length
+ * @param type target g711 data type
+ * @return int sucess:1; failed:0
+ */
+int G711TypeChange(unsigned char* alawdata, unsigned char* ulawdata, int datasize, enum g711type type)
+{
+ int i;
+
+ if (alawdata == 0 || ulawdata == 0 || datasize <= 0) {
+ return 0;
+ }
+
+ if (type == G711ALAW) {
+ for (i = 0; i < datasize; i++) {
+ alawdata[i] = ulaw2alaw(ulawdata[i]);
+ }
+ } else {
+ for (i = 0; i < datasize; i++) {
+ ulawdata[i] = alaw2ulaw(alawdata[i]);
+ }
+ }
+ return 1;
+}
diff --git a/mbtk/libmbtk_lib/audio/g711_pcm_convert.h b/mbtk/libmbtk_lib/audio/g711_pcm_convert.h
new file mode 100755
index 0000000..688dcb4
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/g711_pcm_convert.h
@@ -0,0 +1,46 @@
+#ifndef G711_PCM_CONVERT_H_
+#define G711_PCM_CONVERT_H_
+
+enum g711type {
+ G711ALAW,
+ G711ULAW
+};
+
+/**
+ * @brief pcm data encode to g711 data
+ *
+ * user should be responsible for pCodecbit memmory
+ *
+ * @param pCodecBits store g711 encoded data
+ * @param pBuffer pcm raw data
+ * @param BufferSize pcm data len
+ * @param type g711 data type
+ * @return int encode data length
+ */
+int G711EnCode(char* pCodecBits, char* pBuffer, int BufferSize, enum g711type type);
+
+/**
+ * @brief g711 data decode to pcm data
+ *
+ * user should be responsible for pRawData memmory
+ *
+ * @param pRawData store uncoded pcm data
+ * @param pBuffer g711 encoded data
+ * @param BufferSize g711 data len
+ * @param type g711 data type
+ * @return int pcm data len
+ */
+int G711Decode(char* pRawData, char* pBuffer, int BufferSize, enum g711type type);
+
+/**
+ * @brief g711 u-law data and a-law data convert
+ *
+ * @param alawdata g711 a-law data
+ * @param ulawdata g711 u-lwa data
+ * @param datasize input data length
+ * @param type target g711 data type
+ * @return int sucess:1; failed:0
+ */
+int G711TypeChange(unsigned char* alawdata, unsigned char* ulawdata, int datasize, enum g711type type);
+
+#endif /* G711_PCM_CONVERT_H_ */
\ No newline at end of file
diff --git "a/mbtk/libmbtk_lib/audio/mbtk_audio \0502\051.c" "b/mbtk/libmbtk_lib/audio/mbtk_audio \0502\051.c"
new file mode 100755
index 0000000..2b9988a
--- /dev/null
+++ "b/mbtk/libmbtk_lib/audio/mbtk_audio \0502\051.c"
@@ -0,0 +1,1179 @@
+/**
+ * \file mbtk_audio.c
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: js.wang <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-03-31
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "mbtk_audio.h"
+
+/******************************************************************************\
+ * Macros / Defines
+\******************************************************************************/
+
+#ifndef UNUSEDPARAM
+#define UNUSEDPARAM(a) (void)(a)
+#endif
+
+#define AUDIO_UBUS_REQUEST_NAME "audio_if"
+#define mbtk_dtmf_UBUS_NAME "proslic_uBus" //Used by wake lock
+#define DTMFCODEID "dtmfcode"
+#define DTMFCODE_NOTIFICATION_NAME "audioif.dtmfcode"
+#define AUDIO_UBUS_VOLUME_SET "volume_set"
+#define AUDIO_UBUS_VOLUME_GET "volume_status"
+#define AUDIO_UBUS_MODE_SET "audio_mode_set"
+#define AUDIO_UBUS_PATH_ENABLE "audio_path_enable"
+#define AUDIO_UBUS_SWITCH_PCM "switch_pcm"
+#define AUDIO_UBUS_DSP_SET "config_dspgain"
+#define AUDIO_UBUS_LOOPBACK_EN "loopback_enable"
+#define AUDIO_UBUS_LOOPBACK_DIS "loopback_disable"
+#define AUDIO_UBUS_AUDIO_GAIN_SET "audio_gain_set"
+#define AUDIO_UBUS_AUDIO_REG_SET "audio_reg_set"
+
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+ #define mbtk_audio_log(...) mbtk_audio_log(__VA_ARGS__)
+#else
+ #define mbtk_audio_log(...)
+#endif
+
+typedef enum {
+ PARAM_INT_POLICY_0,
+ PARAM_INT_POLICY_1,
+ PARAM_INT_POLICY_2,
+ PARAM_INT_POLICY_3,
+ PARAM_INT_POLICY_MAX,
+} PARAM_INT_POLICY;
+
+#define FAILURE -1
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+#define FORMAT_PCM 1
+
+struct wav_header {
+ uint32_t riff_id;
+ uint32_t riff_sz;
+ uint32_t riff_fmt;
+ uint32_t fmt_id;
+ uint32_t fmt_sz;
+ uint16_t audio_format;
+ uint16_t num_channels;
+ uint32_t sample_rate;
+ uint32_t byte_rate; /* sample_rate * num_channels * bps / 8 */
+ uint16_t block_align; /* num_channels * bps / 8 */
+ uint16_t bits_per_sample;
+ uint32_t data_id;
+ uint32_t data_sz;
+};
+
+const struct blobmsg_policy int_policy[] ={
+ [PARAM_INT_POLICY_0] = {
+ .name = "param0",
+ .type = BLOBMSG_TYPE_INT32,
+ },
+};
+
+const struct blobmsg_policy dtmf_code_policy[] = {
+ [0] = {
+ .name = DTMFCODEID,
+ .type = BLOBMSG_TYPE_INT32,
+ },
+};
+
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout);
+static struct uloop_timeout mbtk_dtmf_add_subscribe_timeout_AudioIf =
+{
+ .cb = mbtk_dtmf_add_subscriber_AudioIf,
+};
+
+static struct blob_buf audio_cm_b;
+pthread_mutex_t mbtk_dtmf_mutex;
+int mbtk_dtmf_PMConstraintWorks;
+//For UBUS listening to RILD & audio_if
+struct mbtk_audio_ubus_db_t
+{
+ pthread_t dtmf_pthread;
+ mbtk_dtmf_cb dtmf_cb;
+ mbtk_volume_cb audio_volume_get_cb;
+ int work_state;
+ struct ubus_context *ctx;
+
+ /* Audio_If */
+ struct ubus_subscriber audioif_event;
+ uint32_t audioif_subscriber_id;
+ uint32_t audioif_request_id;
+};
+
+static struct mbtk_audio_ubus_db_t *mbtk_audio_ubus_db = NULL;
+
+#ifdef MBTK_YX_SUPPORT
+static struct ubus_context *audio_ctx = NULL;
+static uint32_t ubus_id_audio_if = 0;
+#endif
+
+static int record_fd = 0;
+
+#define AUDIO_FILE_DIR "/data"
+#define MBTK_AUD_DEMO_WAV "/data/demo.wav"
+
+int MBTK_wav_pcm16Le_set(int fd)
+{
+ struct wav_header hdr;
+
+ if (fd <= 0)
+ return -1;
+
+ memset(&hdr, 0, sizeof(struct wav_header));
+
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = 1;
+ hdr.sample_rate = 8000;
+ hdr.bits_per_sample = 16;
+ hdr.byte_rate = (8000 * 1 * hdr.bits_per_sample) / 8;
+ hdr.block_align = (hdr.bits_per_sample * 1) / 8;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+
+ hdr.riff_sz = hdr.data_sz + 44 - 8;
+ if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+int create_audio_dir(const char *dirname)
+{
+ DIR *p_dir;
+ int res = -1;
+
+ if(NULL == (p_dir = opendir((const char *)dirname)))
+ {
+ if(mkdir(dirname, 0777) == 0)
+ {
+ res = 0;
+ }
+ else
+ {
+ fprintf(stderr, "create audio dir error \n");
+ res = -1;
+ }
+ }
+ else
+ {
+ closedir(p_dir);
+ res = 0;
+ }
+ return res;
+}
+int mbtk_at_play(const char *args)
+{
+ int fd = 0;
+ int play_hdl = 0;
+ char databuf[1024];
+ int size;
+
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ // play_hdl = Ql_AudPlayer_Open(NULL, NULL);
+ play_hdl = mbtk_audio_open(0, 1, 8000, NULL);
+ if(0 == play_hdl)
+ printf("Ql_AudPlayer_Open fail\n");
+
+ fd = open(MBTK_AUD_DEMO_WAV, O_RDWR);
+ if (fd <= 0)
+ {
+ printf("file open error\n");
+ goto err;
+ }
+ memset(databuf, 0, sizeof(databuf));
+ while(0 < (size = read(fd, databuf, sizeof(databuf))))
+ {
+ if(-1 == mbtk_audio_play_stream(play_hdl, databuf, size))
+ break;
+ }
+ mbtk_audio_log("aplay Stream end \n");
+
+err:
+ if(fd > 0)
+ close(fd);
+ mbtk_audio_close(play_hdl);
+
+ return 0;
+}
+
+void record_cb_func(int cb_result, char* databuf, unsigned int len)
+{
+ int rc;
+
+ if(NULL != databuf && len > 0 && record_fd > 0)
+ {
+ //for debug:save into file
+ rc = write(record_fd, databuf, len);
+ if (rc < 0) {
+ printf("%s: error writing to file!\n", __FUNCTION__);
+ } else if (rc < len) {
+ printf("%s: wrote less the buffer size!\n", __FUNCTION__);
+ }
+ }
+}
+
+int mbtk_at_rec(const char *args)
+{
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ //hdl = Ql_AudRecorder_Open(NULL, record_cb_func);
+ void *record_hdl = mbtk_audio_open(1, 1, 8000, NULL);
+ if (record_hdl == NULL)
+ {
+ printf("AudRecorder open error\n");
+ return -1;
+ }
+
+ create_audio_dir(AUDIO_FILE_DIR);
+ record_fd = open(MBTK_AUD_DEMO_WAV, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if (record_fd <= 0)
+ {
+ printf("file open error\n");
+ goto err;
+ }
+
+ if(0 == MBTK_wav_pcm16Le_set(record_fd))// 设置格式,否则音频播放不了
+ {
+ if( 0 != mbtk_audio_record(record_hdl, record_cb_func, NULL))
+ {
+ printf("file write error\n");
+ close(record_fd);
+ record_fd = 0;
+ }
+ }
+ else
+ {
+ printf("arec set file header error\n");
+ close(record_fd);
+ record_fd = 0;
+ }
+
+ sleep(10);// 录音 10S
+err:
+ mbtk_audio_close(record_hdl);// 关闭录音
+ record_hdl = NULL;
+ if(record_fd > 0)
+ {
+ close(record_fd);
+ record_fd = 0;
+ }
+
+ return 0;
+}
+
+static void mbtk_ubus_complete_cb(struct ubus_request *req, int rc)
+{
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ if (req)
+ {
+ free(req);
+ req = NULL;
+ }
+ mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+ LOGI("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+ if(mbtk_audio_ubus_db->work_state)
+ mbtk_audio_ubus_db->work_state--;
+}
+/**
+ * @brief mbtk_audio_mode_set
+ *
+ * @details detailed description
+ *
+ * @param param
+ * "param0": UINT32
+ * typedef enum {
+ * AUDIO_MODE_INVALID = -2,
+ * AUDIO_MODE_CURRENT = -1,
+ * AUDIO_MODE_NORMAL = 0,
+ * AUDIO_MODE_RINGTONE = 1,
+ * AUDIO_MODE_IN_CALL = 2,
+ * AUDIO_MODE_IN_COMMUNICATION=3,
+ * AUDIO_MODE_IN_VT_CALL= 4,
+ * AUDIO_MODE_CNT,
+ * AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
+ * } audio_mode_
+ * @return return type
+ */
+void mbtk_audio_mode_set(int mode)
+{
+ int rc = 0;
+#ifndef MBTK_YX_SUPPORT
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", mode);
+ if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_MODE_SET,
+ audio_cm_b.head, NULL, NULL, 2 * 1000)) != UBUS_STATUS_OK)
+ {
+ printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_MODE_SET, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ }
+#else
+ static struct ubus_context *ctx;
+ ctx = ubus_connect(NULL);
+ if (!ctx) {
+ printf("Failed to connect to ubus\n");
+ return;
+ }
+
+ static struct blob_buf b;
+ uint32_t id;
+ int ret;
+ ret = ubus_lookup_id(ctx, AUDIO_UBUS_REQUEST_NAME, &id);
+ if (ret) {
+ printf("ubus_lookup_id() fail.\n");
+ return ret;
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "param0", mode);
+ if((ret = ubus_invoke(ctx, id, AUDIO_UBUS_MODE_SET, b.head, NULL, NULL, 0)) != UBUS_STATUS_OK) {
+ printf("ubus_invoke fail:%d.\n", ret);
+ } else {
+ printf("ubus_invoke success.\n");
+ }
+#endif
+}
+
+
+void mbtk_audio_path_enable(int mode)
+{
+ int rc = 0;
+#ifndef MBTK_YX_SUPPORT
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", mode);
+ if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_PATH_ENABLE,
+ audio_cm_b.head, NULL, NULL, 0)) != UBUS_STATUS_OK)
+ {
+ printf("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_PATH_ENABLE, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ }
+#else
+ static struct ubus_context *ctx;
+ ctx = ubus_connect(NULL);
+ if (!ctx) {
+ printf("Failed to connect to ubus\n");
+ return;
+ }
+
+ static struct blob_buf b;
+ uint32_t id;
+ int ret;
+ ret = ubus_lookup_id(ctx, AUDIO_UBUS_REQUEST_NAME, &id);
+ if (ret) {
+ printf("ubus_lookup_id() fail.\n");
+ return ret;
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "param0", mode);
+ if((ret = ubus_invoke(ctx, id, AUDIO_UBUS_PATH_ENABLE, b.head, NULL, NULL, 0)) != UBUS_STATUS_OK) {
+ printf("ubus_invoke fail:%d.\n", ret);
+ } else {
+ printf("ubus_invoke success.\n");
+ }
+
+#endif
+}
+
+
+/**
+ * @brief mbtk_audio_switch_pcm
+ *
+ * @details detailed description
+ *
+ * @param param
+ * "param0":UINT32 mode
+ * 0: Turn off MSA PCM
+ * 1: Turn on MSA PCM as NB PCM(i.e. 8KHz sample rate)
+ * 2: Turn on MSA PCM as WB PCM(i.e. 16KHz sample rate)
+ * @return return type
+ */
+void mbtk_audio_switch_pcm(int mode)
+{
+ int rc = 0;
+#ifndef MBTK_YX_SUPPORT
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", mode);
+ if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_SWITCH_PCM,
+ audio_cm_b.head, NULL, NULL, 0/*2 * 1000*/)) != UBUS_STATUS_OK)
+ {
+ printf("%s, ubus_invoke %s failed %s\n", __FUNCTION__, AUDIO_UBUS_SWITCH_PCM, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke success\n", __FUNCTION__);
+ }
+#else
+
+ static struct blob_buf b;
+ int ret;
+ if(audio_ctx == NULL || ubus_id_audio_if == 0) {
+ return;
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "param0", mode);
+ if((ret = ubus_invoke(audio_ctx, ubus_id_audio_if, AUDIO_UBUS_SWITCH_PCM, b.head, NULL, NULL, 2000)) != UBUS_STATUS_OK) {
+ printf("ubus_invoke fail:%d.\n", ret);
+ } else {
+ printf("ubus_invoke success.\n");
+ }
+
+#endif
+}
+
+int mbtk_audio_dsp_set(int type, int gain)
+{
+ LOGE("1type:%d, gain:%d\n", type, gain);
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ LOGE("mbtk_dtmf_ubus not init!\n");
+ return -1;
+ }
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ LOGE("leave %s: lack of memory\n", __FUNCTION__);
+ return -1;
+ }
+
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "type", type);
+ blobmsg_add_u32(&audio_cm_b, "gain", gain);
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_DSP_SET,
+ audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ LOGE("%s, ubus_invoke_async %s failed %s\n", __FUNCTION__, AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
+ return -1;
+ }
+ else
+ {
+ LOGE("%s: ubus_invoke_async success\n", __FUNCTION__);
+ mbtk_audio_ubus_db->work_state++;
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+ return 0;
+}
+/**
+ * @brief mbtk_audio_loopback_start
+ *
+ * @details detailed description
+ *
+ * @param param
+ * device: UINT32
+ * 0: earpiece
+ * 1: speaker
+ * 2: headset
+ * @return return type
+ */
+static void mbtk_audio_loopback_start(int device)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ LOGI("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ LOGI("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", device);
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_LOOPBACK_EN,
+ audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ LOGI("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ LOGI("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+}
+
+static void mbtk_audio_loopback_stop(void)
+{
+ int rc = 0;
+
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ blob_buf_init(&audio_cm_b, 0);
+
+ if ((rc = ubus_invoke(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_LOOPBACK_DIS,
+ audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
+ {
+ LOGI("%s, ubus_invoke volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ LOGI("%s: ubus_invoke success\n", __FUNCTION__);
+ }
+}
+
+int mbtk_at_loopback(int type)
+{
+ static mbtk_audio_client_handle_type audio_handle = 0;
+ int ret = 0;
+
+ LOGI("%s %d:%d", __FUNCTION__, __LINE__, type);
+ if(0 == type) // Stop
+ {
+ mbtk_audio_loopback_stop();
+ if(audio_handle)
+ {
+ mbtk_audio_ubus_client_deinit(audio_handle);
+ audio_handle = 0;
+ }
+ }
+ else // Start
+ {
+ if(NULL == mbtk_audio_ubus_db)
+ ret = mbtk_audio_ubus_client_init(&audio_handle, NULL);
+ if(ret)
+ {
+ return -1;
+ }
+ mbtk_audio_mode_set(0);
+ mbtk_audio_loopback_start(2);
+ }
+
+ return 0;
+}
+
+/***************************************************** \
+ * Retry mechanism to add subscriber for Audio_if
+\*****************************************************/
+static void mbtk_dtmf_add_subscriber_AudioIf(struct uloop_timeout *timeout)
+{
+ /* add subscriber for Audio_If */
+ if (ubus_lookup_id(mbtk_audio_ubus_db->ctx, DTMFCODE_NOTIFICATION_NAME, &mbtk_audio_ubus_db->audioif_subscriber_id))
+ {
+ printf("%s, Failed to look up %s\n", __FUNCTION__, DTMFCODE_NOTIFICATION_NAME);
+ uloop_timeout_set(timeout, 2000);
+ return;
+ }
+
+ ubus_subscribe(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event, mbtk_audio_ubus_db->audioif_subscriber_id);
+ mbtk_audio_log("Audio_If subscribe %s object ok\n", DTMFCODE_NOTIFICATION_NAME);
+ return;
+}
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBus_pmConstraint
+* Description: Lock/unlock system power management.
+* 0: unlock
+* 1: lock
+* Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBus_PMConstraint(int set)
+{
+ FILE *flk;
+ if (mbtk_dtmf_PMConstraintWorks != 0)
+ return; //wake_lock unavailable or not exist. Do nothing
+
+#ifdef PROSLIC_ENABLEFREERUN
+ mbtk_audio_log("%s(%d): %s\n", __FUNCTION__, set, set ? "no sleep" : "sleep after 7s");
+#else
+ mbtk_audio_log("%s(%d): free-run is disabled, no sleep\n", __FUNCTION__, set);
+#endif
+
+ /* Do Not check fopen success. It must be ok, if failed
+ ** (for any reason) better to crash for logging and recovery
+ */
+ flk = fopen("/sys/power/wake_lock", "w");
+ if(set)
+ {
+ fprintf(flk, mbtk_dtmf_UBUS_NAME);
+ }
+ else
+ {
+#ifdef PROSLIC_ENABLEFREERUN
+ /* Clear constraint but with TimeOut enough
+ ** Stay awake for (mbtk_dtmf_DIAL_TIMER + 1) seconds, wait for ringing timer expire
+ */
+ fprintf(flk, mbtk_dtmf_UBUS_NAME " 7000000000"/*nsec*/);
+#endif
+ }
+
+ fclose(flk);
+}
+
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBusInd_AudioIf_remove
+* Description: Handle upon Audio_if remove indication.
+* Returns:
+\*******************************************************************************/
+static void mbtk_dtmf_uBusInd_AudioIf_remove(struct ubus_context *ctx, struct ubus_subscriber *s,
+ uint32_t id)
+{
+ UNUSEDPARAM(ctx);
+ UNUSEDPARAM(s);
+ UNUSEDPARAM(id);
+
+ mbtk_audio_log("%s\n", __FUNCTION__);
+ uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 2000);
+}
+
+
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBusInd_AudioIf
+* Description: Handle upon Audio_If incoming indication.
+* Returns: 0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusInd_AudioIf(struct ubus_context *ctx, struct ubus_object *obj,
+ struct ubus_request_data *req, const char *method,
+ struct blob_attr *msg)
+{
+ UNUSEDPARAM(ctx);
+ UNUSEDPARAM(obj);
+ UNUSEDPARAM(req);
+ UNUSEDPARAM(method);
+
+ char DTMFCode = 0;
+ struct blob_attr *tb[1];
+ int rc = 0;
+
+ //Lock from mbtk_dtmf interrupt handler (mbtk_dtmf_MainLoop)
+ pthread_mutex_lock(&mbtk_dtmf_mutex);
+ mbtk_audio_log("==================================%s : Begin==================================\n", __FUNCTION__);
+ mbtk_dtmf_uBus_PMConstraint(1);
+
+ /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+ rc = blobmsg_parse(dtmf_code_policy, 1, tb, blob_data(msg), blob_len(msg));
+
+ if (rc < 0) {
+ printf("%s: parsing fail, rc = 0x%x\n", __FUNCTION__, rc);
+ }
+ else {
+ DTMFCode = (char)blobmsg_get_u32(tb[0]);
+ if(mbtk_audio_ubus_db->dtmf_cb)
+ mbtk_audio_ubus_db->dtmf_cb(DTMFCode);
+ mbtk_audio_log("%s got DTMF Code: Char[%c]=ASCII[0x%x]\n", __FUNCTION__, DTMFCode, DTMFCode);
+ }
+
+ mbtk_dtmf_uBus_PMConstraint(0);
+ mbtk_audio_log("==================================%s : End==================================", __FUNCTION__);
+ pthread_mutex_unlock(&mbtk_dtmf_mutex);
+
+ return rc;
+}
+
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBusRegisterNotifications
+* Description: Register UBUS notifications of RIL and Audio_If.
+* Returns: 0 on success
+\*******************************************************************************/
+static int mbtk_dtmf_uBusRegisterNotifications(void)
+{
+ int ret = 0;
+
+ /* register UBUS notifications of Audio_If */
+ ret = ubus_register_subscriber(mbtk_audio_ubus_db->ctx, &mbtk_audio_ubus_db->audioif_event);
+ if (ret)
+ {
+ printf("%s Failed to add audio_if watch handler: %s\n", __FUNCTION__, ubus_strerror(ret));
+ return -1;
+ }
+
+ /* specify callback to handle notifications */
+ mbtk_audio_ubus_db->audioif_event.remove_cb = mbtk_dtmf_uBusInd_AudioIf_remove;
+ mbtk_audio_ubus_db->audioif_event.cb = mbtk_dtmf_uBusInd_AudioIf;
+
+ /* add subscribe */
+ uloop_timeout_set(&mbtk_dtmf_add_subscribe_timeout_AudioIf, 0);
+
+ mbtk_audio_log("%s: Make use of DTMF detection in modem.\n", __FUNCTION__);
+
+ return 0;
+}
+
+void mbtk_switch_dtmf_detection_cb(struct ubus_request *req, int rc)
+{
+ if (req)
+ {
+ free(req);
+ req = NULL;
+ }
+ mbtk_audio_log("%s do nothing, rc=%d\n", __FUNCTION__, rc);
+}
+/**
+ * @brief mbtk_switch_dtmf_detection
+ *
+ * @details detailed description
+ *
+ * @param param
+ * “param0": UINT32 onoff
+ * 0: disbale Tx DTMF detection
+ * 1: enable Tx DTMF detection
+ * 2: disbale Rx DTMF detection
+ * 3: enable Rx DTMF detection
+ * @return return type
+ */
+void mbtk_switch_dtmf_detection(unsigned short on_off, unsigned short param1,
+ unsigned short param2, unsigned short param3)
+{
+#if PCM_CTRL_OVER_VCM
+ vcm_DTMFDetection(on_off, param1, param2, param3);
+#else
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ printf("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", on_off);
+ blobmsg_add_u32(&audio_cm_b, "param1", param1);
+ blobmsg_add_u32(&audio_cm_b, "param2", param2);
+ blobmsg_add_u32(&audio_cm_b, "param3", param3);
+
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, "dtmf_detection", audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ printf("%s, ubus_invoke dtmf_detection failed %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->complete_cb = mbtk_switch_dtmf_detection_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+#endif
+}
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBusInit
+* Description: Init UBUS context and register UBUS notifications of RIL.
+* Returns: 0 on success
+\*******************************************************************************/
+int mbtk_dtmf_uBusInit(void)
+{
+ int rc = 0;
+
+ uloop_init();
+
+ mbtk_audio_ubus_db->ctx = ubus_connect(NULL);
+ if (mbtk_audio_ubus_db->ctx == NULL)
+ {
+ printf(" %s Failed to connect to ubus\n", __FUNCTION__);
+ return -1;
+ }
+
+ ubus_add_uloop(mbtk_audio_ubus_db->ctx);
+
+ /* lookup fail if audio_if is not ready */
+ while(1)
+ {
+ rc = ubus_lookup_id(mbtk_audio_ubus_db->ctx, AUDIO_UBUS_REQUEST_NAME, &mbtk_audio_ubus_db->audioif_request_id);
+ if (0 != rc)
+ {
+ printf("%s, Failed to look up(%s), rc=%d\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME, rc);
+ usleep(600000); //600ms
+ }
+ else
+ break;
+ }
+ mbtk_audio_log("%s, ubus_lookup_id(%s) OK\n", __FUNCTION__, AUDIO_UBUS_REQUEST_NAME);
+
+ /* subscribe for RIL & audio_if notifications */
+ if (mbtk_dtmf_uBusRegisterNotifications() != 0)
+ return -1;
+
+ mbtk_audio_log("%s success!\n", __FUNCTION__);
+ return 0;
+}
+
+
+/*******************************************************************************\
+* Function: mbtk_dtmf_uBusRun
+* Description: Start running of UBUS.
+* Returns:
+\*******************************************************************************/
+static void mbtk_audio_ubus_thread(void* hdl)
+{
+ pthread_detach(pthread_self());
+ uloop_run();
+ mbtk_audio_log("%s exit!\n", __FUNCTION__);
+ pthread_exit(NULL);
+}
+
+int mbtk_audio_ubus_client_init(mbtk_audio_client_handle_type *ph_audio, mbtk_dtmf_cb cb)
+{
+#ifndef MBTK_YX_SUPPORT
+ // Set call handle.
+ if(ph_audio == NULL || mbtk_audio_ubus_db != NULL)
+ {
+ printf("ARG error or has inited.");
+ return -1;
+ }
+ mbtk_audio_ubus_db = malloc(sizeof(struct mbtk_audio_ubus_db_t));
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("malloc memory error\n");
+ }
+ memset(mbtk_audio_ubus_db, 0, sizeof(struct mbtk_audio_ubus_db_t));
+
+ mbtk_dtmf_PMConstraintWorks = access("/sys/power/wake_lock", R_OK | W_OK);
+ mbtk_dtmf_uBusInit();
+ mbtk_audio_ubus_db->dtmf_cb = cb;
+
+ mbtk_switch_dtmf_detection(3, 50, 4, 3);
+ pthread_create(&mbtk_audio_ubus_db->dtmf_pthread, NULL, (void *)mbtk_audio_ubus_thread, (void *)mbtk_audio_ubus_db);
+
+ *ph_audio = mbtk_audio_ubus_db;
+ LOGI("%s %d:%x", __FUNCTION__, __LINE__, mbtk_audio_ubus_db);
+#else
+ audio_ctx = ubus_connect(NULL);
+ if (!audio_ctx) {
+ printf("Failed to connect to ubus\n");
+ return -1;
+ }
+
+ int ret = ubus_lookup_id(audio_ctx, AUDIO_UBUS_REQUEST_NAME, &ubus_id_audio_if);
+ if (ret) {
+ printf("ubus_lookup_id() fail.\n");
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+int mbtk_audio_ubus_client_deinit(mbtk_audio_client_handle_type h_audio)
+{
+ int ret;
+#ifndef MBTK_YX_SUPPORT
+ struct mbtk_audio_ubus_db_t *audio_ubus = (struct mbtk_audio_ubus_db_t *)h_audio;
+
+ mbtk_audio_log("%s \n", __FUNCTION__);
+ if(h_audio == NULL || mbtk_audio_ubus_db == NULL)
+ {
+ printf("ARG error or not inited.");
+ return -1;
+ }
+ LOGI("%s %d:%x", __FUNCTION__, __LINE__, audio_ubus);
+ ret = pthread_cancel(audio_ubus->dtmf_pthread);
+ mbtk_audio_log("kill pthread : %d \n", ret);
+ pthread_join(audio_ubus->dtmf_pthread, NULL);
+ do{
+ ret = pthread_kill(audio_ubus->dtmf_pthread, 0);
+ mbtk_audio_log("kill pthread: %d \n", ret);
+ if(ret == ESRCH)
+ mbtk_audio_log("The specified thread does not exist or has terminated\n");
+ else if(ret == EINVAL)
+ mbtk_audio_log("Useless signal\n");
+ else
+ mbtk_audio_log("The thread exists\n");
+ usleep(100000);
+ }while(0 == ret);
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+
+ mbtk_switch_dtmf_detection(2, 0, 0, 0);
+ /*unregister uloop*/
+ /*thread will get here only if uloop stopped*/
+ ubus_free(mbtk_audio_ubus_db->ctx);
+ uloop_done();
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ free(h_audio);
+ mbtk_audio_ubus_db = NULL;
+#else
+ if(audio_ctx) {
+ ubus_free(audio_ctx);
+ audio_ctx = NULL;
+ }
+#endif
+ return 0;
+}
+
+/**********************************************************************\
+* Function: APP_Audio_VolumeSet
+* Description: This function is called to send command into audio_if.
+* unsigned int volume(0~100)
+* Returns: 0 on success
+\**********************************************************************/
+void mbtk_audio_ubus_volume_set(unsigned int volume)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(NULL == mbtk_audio_ubus_db)
+ {
+ printf("mbtk_dtmf_ubus not init!\n");
+ return;
+ }
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ printf("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "param0", volume);
+
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_VOLUME_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+}
+
+#define MBTK_AUDIO_GAIN_NUM 11
+void mbtk_audio_ubus_gain_set(mbtk_audio_gain_type_enum type, uint16 *gain, int gain_num)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ printf("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+ if((type == AUDIO_GAIN_TYPE_RX_CODECGAIN || type == AUDIO_GAIN_TYPE_RX_DSPGAIN)
+ && gain_num != MBTK_AUDIO_GAIN_NUM) {
+ printf("gain_num error:type = %d, gain_name = %d.\n", type, gain_num);
+ return;
+ }
+ if((type == AUDIO_GAIN_TYPE_TX_CODECGAIN || type == AUDIO_GAIN_TYPE_TX_DSPGAIN)
+ && gain_num != 1) {
+ printf("gain_num error:type = %d, gain_name = %d.\n", type, gain_num);
+ return;
+ }
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+
+ // Set RX
+ blobmsg_add_u16(&audio_cm_b, "volume_gain_type", type);
+ if(type == AUDIO_GAIN_TYPE_TX_CODECGAIN || type == AUDIO_GAIN_TYPE_TX_DSPGAIN) {
+ blobmsg_add_u16(&audio_cm_b, "volume_gain_0", gain[0]);
+ } else {
+ char name[20];
+ int i = 0;
+ // Set TX
+ for(; i < gain_num; i++) {
+ memset(name, 0x0, 20);
+ sprintf(name, "volume_gain_%d", i);
+ blobmsg_add_u16(&audio_cm_b, name, gain[i]);
+ }
+ }
+
+#if 1
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+#else
+ if ((rc = ubus_invoke(APP_ctx, APP_audio_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
+ {
+ printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ }
+ free(req);
+#endif
+}
+
+void mbtk_audio_ubus_reg_set(int reg_addr, int reg_value)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ printf("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+ blobmsg_add_u32(&audio_cm_b, "reg_addr", reg_addr);
+ blobmsg_add_u32(&audio_cm_b, "reg_value", reg_value);
+
+#if 1
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx, mbtk_audio_ubus_db->audioif_request_id, AUDIO_UBUS_AUDIO_REG_SET, audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+#else
+ if ((rc = ubus_invoke(APP_ctx, APP_audio_request_id, AUDIO_UBUS_AUDIO_GAIN_SET, audio_cm_b.head, NULL, 0, 0)) != UBUS_STATUS_OK)
+ {
+ printf("%s, ubus_invoke_async volume set failed: %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ printf("%s: ubus_invoke_async success\n", __FUNCTION__);
+ }
+ free(req);
+#endif
+}
+
+static void audio_volume_get_data_cb (struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ UNUSEDPARAM(req);
+ UNUSEDPARAM(type);
+ struct blob_attr *tb[1];
+ unsigned int volume = 888;
+ int rc = 0;
+
+ rc = blobmsg_parse(int_policy, 1, tb, blob_data(msg), blob_len(msg));
+ if (rc < 0)
+ {
+ printf("[%s] parsing blobmsg failed\n", __FUNCTION__);
+ return;
+ }
+
+ if(tb[0])
+ volume = blobmsg_get_u32(tb[0]);
+ if (mbtk_audio_ubus_db->audio_volume_get_cb)
+ mbtk_audio_ubus_db->audio_volume_get_cb(volume);
+ mbtk_audio_log("%s; volume:%d\n", __FUNCTION__, volume);
+}
+
+void mbtk_audio_ubus_volume_get(mbtk_volume_cb cb)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(NULL == mbtk_audio_ubus_db || NULL == cb)
+ {
+ printf("mbtk_dtmf_ubus not init or callback invalid!\n");
+ return;
+ }
+ mbtk_audio_ubus_db->audio_volume_get_cb = cb;
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ printf("leave %s: lack of memory\n", __FUNCTION__);
+ return;
+ }
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&audio_cm_b, 0);
+
+ if ((rc = ubus_invoke_async(mbtk_audio_ubus_db->ctx,
+ mbtk_audio_ubus_db->audioif_request_id,
+ AUDIO_UBUS_VOLUME_GET,
+ audio_cm_b.head, req)) != UBUS_STATUS_OK)
+ {
+ free(req);
+ printf("%s, ubus_invoke_async volume get failed %s\n", __FUNCTION__, ubus_strerror(rc));
+ }
+ else
+ {
+ mbtk_audio_log("%s: ubus_invoke_async success\n", __FUNCTION__);
+ req->data_cb = audio_volume_get_data_cb;
+ req->complete_cb = mbtk_ubus_complete_cb;
+ ubus_complete_request_async(mbtk_audio_ubus_db->ctx, req);
+ }
+}
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio.c b/mbtk/libmbtk_lib/audio/mbtk_audio.c
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio.c
@@ -0,0 +1 @@
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio_alsa.c b/mbtk/libmbtk_lib/audio/mbtk_audio_alsa.c
new file mode 100755
index 0000000..45ce873
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio_alsa.c
@@ -0,0 +1,876 @@
+/**
+ * \file mbtk_audio_alsa.c
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: js.wang <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2020-09-21
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+
+#include "audio_if_types.h"
+#include "audio_if_ubus.h"
+#include "audio_if_parameter.h"
+#include "audio_if.h"
+#include "audio_if_api.h"
+#include <unistd.h>
+#include <sys/stat.h>
+#include "audio_if_audio_hw_mrvl.h"
+#include "audio_hw_mrvl.h"
+#include <cutils/str_parms.h>
+#include "vcm.h"
+#include "voice_control.h"
+#include "mbtk_audio.h"
+
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+ #define mbtk_audio_log(...) printf(__VA_ARGS__)
+#else
+ #define mbtk_audio_log(...)
+#endif
+
+typedef int (*_play_callback)(int hdl, int result);
+
+#define FAILURE -1
+#define ID_RIFF 0x46464952
+#define ID_WAVE 0x45564157
+#define ID_FMT 0x20746d66
+#define ID_DATA 0x61746164
+#define FORMAT_PCM 1
+
+typedef enum {
+ AUD_PLAYER_ERROR = -1,
+ AUD_PLAYER_START = 0,
+ AUD_PLAYER_PAUSE,
+ AUD_PLAYER_RESUME,
+ AUD_PLAYER_NODATA, //Buff no data and play tread will sleep
+ AUD_PLAYER_LESSDATA, //Buff has less data
+ AUD_PLAYER_FINISHED,
+} Enum_AudPlayer_State;
+
+struct mopen_audio_t
+{
+ int device;
+ audio_hw_device_t *audio_ahw_dev_ubus;
+ struct audio_stream_in *stream_in;
+ struct audio_stream_out *stream_out;
+ int pcm_packet_size; //320:NB, 640:WB
+ int pipe_data;
+ int fd[2];
+ pthread_t pid;
+ mbtk_audio_state_enum state;
+ pthread_mutex_t _cond_mutex;
+ pthread_mutex_t _stream_mutex;
+ void *usrData;
+};
+struct record_cb_s
+{
+ mbtk_audio_record_cb_func _cb;
+ void *cb_data;
+};
+
+static struct mopen_audio_t *internal_hdl = NULL;
+
+static int dsp_rx_gain = 0xFF;
+static int dsp_tx_gain = 0xFF;
+
+int mbtk_wav_pcm16Le_check(int fd)
+{
+ printf("MBTK_wav_pcm16Le_check()----------strart5, fd:%d\n", fd);
+ struct wav_header hdr;
+
+ if (fd <= 0)
+ return -1;
+
+ if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr))
+ {
+ printf("\n%s: cannot read header\n", __FUNCTION__);
+ return -1;
+ }
+
+ printf("hdr.riff_id:%X, hdr.riff_fmt:%X, hdr.fmt_id:%X", hdr.riff_id, hdr.riff_fmt, hdr.fmt_id);
+
+ if ((hdr.riff_id != ID_RIFF)
+ || (hdr.riff_fmt != ID_WAVE)
+ || (hdr.fmt_id != ID_FMT))
+ {
+ printf("\n%s: is not a riff/wave file\n", __FUNCTION__);
+ return -1;
+ }
+
+ if ((hdr.audio_format != FORMAT_PCM) || (hdr.fmt_sz != 16)) {
+ printf("\n%s: is not pcm format\n", __FUNCTION__);
+ return -1;
+ }
+
+ if (hdr.bits_per_sample != 16) {
+ printf("\n%s: is not 16bit per sample\n", __FUNCTION__);
+ return -1;
+ }
+
+ printf("audio_format: %d,num_channels: %d,sample_rate: %d,byte_rate: %d,bits_per_sample: %d data_sz: %d\n",
+ hdr.audio_format, hdr.num_channels, hdr.sample_rate, hdr.byte_rate, hdr.bits_per_sample, hdr.data_sz);
+
+ return hdr.data_sz;
+}
+
+
+static void simulateOffhook(struct mopen_audio_t *aud_hdl, unsigned int onoff)
+{
+ unsigned int pcm_on;
+ unsigned int DTMFDetectiononoff;
+ unsigned int dialToneToOthersTones;
+ unsigned int dialTonesToOthersDialTones;
+ unsigned int dialVadDuration;
+
+ pcm_on = onoff;
+ //send the command of "AUDIOSTUB_PCMCTL"
+ aud_hdl->audio_ahw_dev_ubus->switch_pcm(aud_hdl->audio_ahw_dev_ubus, pcm_on);
+
+ DTMFDetectiononoff = onoff;
+ dialToneToOthersTones = 50;
+ dialTonesToOthersDialTones = 4;
+ dialVadDuration = 3;
+ //send the command of "AUDIOSTUB_DTMFDETECTIONCTL"
+ //vcm_DTMFDetection(1, 50, 4, 3);
+ vcm_DTMFDetection(DTMFDetectiononoff, dialToneToOthersTones, dialTonesToOthersDialTones, dialVadDuration);
+
+ return;
+}
+static int config_parameters(int in_out, int NBWB)
+{
+ unsigned int direction = 0xFF, type, srcdst, priority, dest;
+ char kvpair[128];
+ struct str_parms *param = NULL;
+ int data[5];
+ const char *key = NULL;
+ bool update_vcm = false;
+
+ direction = in_out;/* 0-play, 1-record */
+ type = NBWB; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
+ srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+ priority = 1;/* 0-Do not combine(override), 1-Combine */
+ dest = 1;/* 0-Near codec, 1-Near Vocoder */
+
+ memset(kvpair, 0x00, sizeof(kvpair));
+ sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
+ VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
+ VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
+
+ mbtk_audio_log("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
+
+ //extract the parameter and config from string
+ param = str_parms_create_str(kvpair);
+ if (!param) {
+ printf("%s: param create str is null!", __FUNCTION__);
+ return -1;
+ }
+
+ //set vcm configurations
+ key = VCM_CONFIG_DIRECTION;
+ if (str_parms_get_int(param, key, &data[0]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_TYPE;
+ if (str_parms_get_int(param, key, &data[1]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_SRC_DST;
+ if (str_parms_get_int(param, key, &data[2]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_PRIORITY;
+ if (str_parms_get_int(param, key, &data[3]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_DEST;
+ if (str_parms_get_int(param, key, &data[4]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+
+ //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
+
+ if (update_vcm) {
+ configure_vcm(data); /*TODO check if all inputs got all values successfully*/
+ }
+
+ return 0;
+}
+
+void mbtk_audio_set_status(void* hdl, mbtk_audio_state_enum _status)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ if (NULL == hdl || NULL == internal_hdl)
+ return 0;
+ pthread_mutex_lock(&pcxt->_cond_mutex);
+ pcxt->state = _status;
+ pthread_mutex_unlock(&pcxt->_cond_mutex);
+}
+
+
+int mbtk_audio_get_status(void* hdl)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ if (NULL == hdl || NULL == internal_hdl)
+ return 0;
+
+ return pcxt->state;
+}
+
+static void* mbtk_record_pthread(void* hdl)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ struct record_cb_s *_usrData = (struct record_cb_s *)pcxt->usrData;
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int len;
+
+ if (NULL == hdl)
+ return NULL;
+
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n", __FUNCTION__, bufsize);
+ return NULL;
+ }
+
+ mbtk_audio_set_status(hdl, AUDIO_RUNNING);
+
+ while (pcxt->state != AUDIO_STOP)
+ {
+ len = pcxt->stream_in->read(pcxt->stream_in, data, bufsize);
+ if (len < 0) {
+ printf("%s: error reading!\n", __FUNCTION__);
+ break;
+ }
+
+ if(dsp_tx_gain == 0xFF) {
+ if(!mbtk_dsp_gain_get(&dsp_rx_gain, &dsp_tx_gain)) {
+ vcm_config_dspgain(CONFIG_DSPGAIN_TX, dsp_tx_gain);
+ dsp_rx_gain = 0xFF;
+ }
+ }
+
+ if ((bufsize > 0) && (NULL != _usrData->_cb))
+ {
+ _usrData->_cb(2, data, bufsize);
+ }
+ }
+ pcxt->pid = 0;
+ if(pcxt->usrData)
+ {
+ free(pcxt->usrData);
+ pcxt->usrData = NULL;
+ }
+ free(data);
+ mbtk_audio_log("pcm pthread end-\n");
+ return NULL;
+}
+
+static void* mbtk_play_pthread(void* hdl)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int first_set = 0;
+ int ret = 0;
+ int rc;
+
+ pthread_detach(pthread_self());
+ if (NULL == hdl)
+ return NULL;
+
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+ pthread_exit(NULL);
+ }
+
+ while (pcxt->state != AUDIO_STOP && 0 != pcxt->pipe_data)
+ {
+ ret = read(pcxt->fd[0], data, bufsize);
+ // printf("%s:read : %d bytes\n", __FUNCTION__, ret);
+ if(ret == 0) {
+ mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret);
+ continue;
+ }
+ if(ret < 0) {
+ mbtk_audio_log("%s %d [%d]", __FUNCTION__, __LINE__, ret);
+ break;
+ }
+ if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+ {
+ first_set = 1;
+ mbtk_audio_set_status(hdl, AUDIO_RUNNING);
+ audio_play_cb(pcxt, AUD_PLAYER_RESUME);
+ }
+
+ pthread_mutex_lock(&pcxt->_stream_mutex);
+ pcxt->pipe_data -= ret;
+ pthread_mutex_unlock(&pcxt->_stream_mutex);
+ if(pcxt->pipe_data < 0)
+ pcxt->pipe_data = 0;
+ if(ret < pcxt->pcm_packet_size)
+ printf("pcm %d - %d\n", pcxt->pipe_data, ret);
+
+ rc = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+ if (rc < 0) {
+ printf("%s: error writing (child).\n", __FUNCTION__);
+ break;
+ } else if (rc < (signed int)pcxt->pcm_packet_size) {
+ printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, rc);
+ break;
+ }
+ }
+
+ if (pcxt->fd[0] != 0 && pcxt->fd[1] != 0)
+ {
+ close(pcxt->fd[0]);
+ close(pcxt->fd[1]);
+ pcxt->fd[0] = 0;
+ pcxt->fd[1] = 0;
+ /* printf("close pcxt->fd!\n"); */
+ }
+ if (audio_play_cb)
+ audio_play_cb(pcxt, AUD_PLAYER_FINISHED);
+ pcxt->pid = 0;
+// mbtk_audio_set_status(hdl, AUDIO_STOP);
+ mbtk_audio_set_status(hdl, AUDIO_OPEN);
+ free(data);
+ mbtk_audio_log("\n%s:exit!\n", __FUNCTION__);
+ pthread_exit(NULL);
+
+ return NULL;
+}
+
+static int audio_init_play_pthread(void* hdl)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+ int ret;
+
+ if (pcxt->fd[0] == 0 && pcxt->fd[1] == 0) {
+ if(pipe(pcxt->fd) == 0) {
+
+ pcxt->pipe_data = 0;
+ fcntl(pcxt->fd[0], F_SETFL, O_NONBLOCK);
+ fcntl(pcxt->fd[1], F_SETFL, O_NONBLOCK);
+ } else {
+ fprintf(stderr, "\n%d: create pipe error\n", __LINE__);
+ return -1;
+ }
+ }
+ if (pcxt->pid == 0) {
+ if (audio_play_cb)
+ audio_play_cb(pcxt, AUD_PLAYER_START);
+ mbtk_audio_set_status(pcxt, AUDIO_RUNNING);
+ ret = pthread_create(&pcxt->pid, NULL, mbtk_play_pthread, hdl);
+ if (ret != 0)
+ {
+ fprintf(stderr, "\n%s: Failed create pthread\n",__FUNCTION__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int mbtk_audio_play_wait_end(void* hdl)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+
+ if (NULL == hdl)
+ {
+ fprintf(stderr, "\n%s: intput invalid params\n",__FUNCTION__);
+ return -1;
+ }
+
+ if(pcxt->pid != 0)
+ {
+ do{
+ usleep(10000);
+ }
+ while(pcxt->state != AUDIO_STOP);
+ pcxt->pid = 0;
+ }
+
+ return 0;
+}
+
+static int audio_open_pcm(void *dev_hdl, int num_channels, int rate, int in_out)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+ int nb_wb;
+
+ //Support 8k/16k & mono wave file
+ if (((rate != 8000) && (rate != 16000))
+ || (num_channels != 1) ) {
+ printf("%s: error wave file:rate = %d, num_channels = %d!! \n",
+ __FUNCTION__,rate, num_channels);
+ return -1;
+ }
+
+ printf("%s: success open, rate = %d, num_channels = %d.\n",
+ __FUNCTION__, rate, num_channels);
+
+ if ((8000 == rate) && (1 == num_channels)) {
+ nb_wb = 0;//NB
+ pcxt->pcm_packet_size = PCM_NB_BUF_SIZE;
+ } else if ((16000 == rate) && (1 == num_channels)) {
+ nb_wb = 1;//WB
+ pcxt->pcm_packet_size = PCM_WB_BUF_SIZE;
+ }
+
+ //config playback parameters.
+ config_parameters(in_out, nb_wb);
+ pcxt->device = in_out;
+ return 0;
+}
+
+mbtk_audio_handle mbtk_audio_open(mbtk_audio_dev_enum dev, int flag, int rate, void *usrData)
+{
+ int value = 1;
+ struct mopen_audio_t *aud_hdl = NULL;
+ int ret;
+
+ // if (dev <= AUDIO_NULL || dev >= AUDIO_MAX)
+ // {
+ // printf("invaild PCM dev\n");
+ // return NULL;
+ // }
+ if(internal_hdl)
+ {
+ printf("Audio device inited\n");
+ return internal_hdl;
+ }
+ aud_hdl = (struct mopen_audio_t *) calloc(1, sizeof(struct mopen_audio_t));
+ if (!aud_hdl)
+ {
+ fprintf(stderr, "\n%s:Failed to allocate audio hdl!, errno=%d\n", __FUNCTION__, errno);
+ return NULL;
+ }
+ memset(aud_hdl, 0, sizeof(struct mopen_audio_t));
+
+ //init global variables
+ aud_hdl->audio_ahw_dev_ubus = audio_hal_install();
+ if (aud_hdl->audio_ahw_dev_ubus == NULL) {
+ printf("%s: audio_hal_install failed!\n", __FUNCTION__);
+ goto error;
+ }
+
+ if(1 == dev)
+ {
+ //send the command of "AUDIOSTUB_PCMCTL" and "AUDIOSTUB_DTMFDETECTIONCTL" to simulate telephone offhook.
+ // ASR Question #80497 Using it causes the recording to crash
+ // simulateOffhook(aud_hdl, 1);
+ //config playback parameters.
+ config_parameters(0, 0);
+ }
+ ret = audio_open_pcm(aud_hdl, flag, rate, dev);
+ if (ret)
+ {
+ printf("\n%s: pcm open error, errno=%d\n", __FUNCTION__, errno);
+ goto error;
+ }
+ if(1 == dev)
+ {
+ //open the audiostub_ctl, prepare for record and playback
+ VCMInit();
+ //open record stream
+ ret = aud_hdl->audio_ahw_dev_ubus->open_input_stream(aud_hdl->audio_ahw_dev_ubus, 0,
+ aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus),
+ NULL, &aud_hdl->stream_in, 0, 0, AUDIO_SOURCE_VOICE_CALL);
+ }
+ else
+ {
+ ret = aud_hdl->audio_ahw_dev_ubus->open_output_stream(aud_hdl->audio_ahw_dev_ubus, 0,
+ aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus),
+ AUDIO_OUTPUT_FLAG_DIRECT, NULL, &aud_hdl->stream_out, 0);
+ }
+
+ if (ret < 0) {
+ printf("%s: error opening output device. rc = %d\n", __FUNCTION__, ret);
+ goto error;
+ }
+ pthread_mutex_init(&aud_hdl->_cond_mutex, NULL);
+ pthread_mutex_init(&aud_hdl->_stream_mutex, NULL);
+ aud_hdl->usrData = usrData;
+ aud_hdl->state = AUDIO_OPEN;
+ /* printf("Mbtk_Audio_Open aud_hdl[%x][%x][%x]\n", aud_hdl, aud_hdl->_mixer_ctl, aud_hdl->_pcm); */
+ internal_hdl = aud_hdl;
+
+ return (void *)aud_hdl;
+
+error:
+ value = 0;
+ free(aud_hdl);
+ return NULL;
+}
+
+
+int mbtk_audio_play_stream_old(void *dev_hdl, const void *pData, int len)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == pcxt || NULL == internal_hdl)
+ return -1;
+
+ if (len > 1024) {
+ printf("audio play stream max size ( < 1024): %d\n", len);
+ return -2;
+ }
+
+ if (pcxt->state == AUDIO_STOP) {
+ return 0;
+ }
+ audio_init_play_pthread(pcxt);
+
+ pthread_mutex_lock(&pcxt->_stream_mutex);
+ pcxt->pipe_data += len;
+ pthread_mutex_unlock(&pcxt->_stream_mutex);
+ while(pcxt->state != AUDIO_STOP && (pcxt->pipe_data > 40960 || pcxt->fd[1] < 0 || pcxt->fd[1] == 0)) {
+ // printf("%s:wait %d %d\n", __FUNCTION__, pcxt->pipe_data, pcxt->fd[1]);
+ usleep(50000);
+ }
+
+ if(pcxt->fd[1] > 0) {
+ if (len != write(pcxt->fd[1], pData, len)) {
+ fprintf(stderr, "\n%s: pcm_write failed [%d %d]\n", __FUNCTION__, pcxt->fd[1], errno);
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+int mbtk_audio_play_stream(void *dev_hdl, const void *pData, int len)
+{
+// printf("%s,--len:%d\n", __func__, len);
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int first_set = 0;
+ int res = 0;
+ int ret = 0;
+ int read_size = 0;
+ char *p = (char *)pData;
+
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == dev_hdl || NULL == internal_hdl || pData == NULL)
+ return -1;
+
+ if(AUDIO_RUNNING == pcxt->state)
+ return -2;
+
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+ pthread_exit(NULL);
+ }
+
+ if(pcxt->state == AUDIO_OPEN)
+ {
+ mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+
+ }
+// if(bufsize > len )
+// {
+// bufsize = len;
+// }
+
+ while (pcxt->state != AUDIO_STOP)
+ {
+
+ memcpy(data,p+read_size, bufsize );
+ read_size += bufsize;
+
+ if(read_size > len)
+ {
+ // printf(">[%d]\n", read_size);
+ break;
+ }
+
+ while(AUDIO_PAUSE == pcxt->state)
+ {
+ usleep(80000);
+ }
+
+ if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+ {
+ first_set = 1;
+ mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+ }
+
+ ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+ if (ret < 0) {
+ printf("%s: error writing (child).\n", __FUNCTION__);
+ break;
+ } else if (ret < (signed int)pcxt->pcm_packet_size) {
+ printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+ break;
+ }
+
+ if(read_size == len)
+ {
+ // printf("=[%d]", read_size);
+ break;
+ }
+
+ }
+
+ if(pcxt->state != AUDIO_STOP)
+ {
+ mbtk_audio_set_status(dev_hdl, AUDIO_OPEN);
+ }
+
+ free(data);
+ return 0;
+
+}
+
+
+int mbtk_audio_play_file(void *dev_hdl, int file_fd, int offset)
+{
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int first_set = 0;
+ int file_data_sz = 0;
+ int res = 0;
+ int ret;
+
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+ _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+ if (NULL == dev_hdl || NULL == internal_hdl)
+ return -1;
+
+ if(AUDIO_RUNNING == pcxt->state)
+ return -2;
+
+ // file_data_sz = mbtk_wav_pcm16Le_check(file_fd);
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+ pthread_exit(NULL);
+ }
+ if(offset)
+ {
+ lseek(file_fd, offset, SEEK_SET);
+ }
+
+ mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+ int all_size = 0;
+
+ while (pcxt->state != AUDIO_STOP)
+ {
+ res = read(file_fd, data, bufsize);
+ // printf("%s:read : %d bytes\n", __FUNCTION__, res);
+ if(res == 0 || res < 0)
+ {
+ printf("read:[%d]", res);
+ break;
+ }
+
+ all_size += res;
+// if (file_data_sz < all_size || file_data_sz == all_size) {
+// printf("aplay size :%d - %d\n", file_data_sz, all_size);
+ // break;
+ // }
+
+ while(AUDIO_PAUSE == pcxt->state)
+ {
+ usleep(80000);
+ audio_play_cb(pcxt, AUD_PLAYER_PAUSE);
+ }
+
+ if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+ {
+ first_set = 1;
+ mbtk_audio_set_status(dev_hdl, AUDIO_RUNNING);
+ audio_play_cb(pcxt, AUD_PLAYER_RESUME);
+ }
+
+ ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+ if (ret < 0) {
+ printf("%s: error writing (child).\n", __FUNCTION__);
+ audio_play_cb(pcxt, AUD_PLAYER_ERROR);
+ break;
+ } else if (ret < (signed int)pcxt->pcm_packet_size) {
+ printf("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+ audio_play_cb(pcxt, AUD_PLAYER_LESSDATA);
+ break;
+ }
+
+ if(dsp_rx_gain == 0xFF) {
+ if(!mbtk_dsp_gain_get(&dsp_rx_gain, &dsp_tx_gain)) {
+ vcm_config_dspgain(CONFIG_DSPGAIN_RX, dsp_rx_gain);
+ dsp_tx_gain = 0xFF;
+ }
+ }
+ }
+ if (audio_play_cb)
+ audio_play_cb(pcxt, AUD_PLAYER_FINISHED);
+
+ printf("file_data_sz :%d - all_size: %d\n", file_data_sz, all_size);
+ mbtk_audio_set_status(dev_hdl, AUDIO_OPEN);
+ free(data);
+
+ return 0;
+}
+
+int mbtk_audio_record(void *dev_hdl, mbtk_audio_record_cb_func cb_func, void *cb_data)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+ int res = -1;
+ struct record_cb_s *_usrData = NULL;
+
+ if (NULL == pcxt || NULL == internal_hdl || NULL == cb_func)
+ return -1;
+
+ if(AUDIO_RUNNING == pcxt->state)
+ return -2;
+
+ _usrData = malloc(sizeof(struct record_cb_s));
+ _usrData->_cb = cb_func;
+ _usrData->cb_data = cb_data;
+ pcxt->usrData = (void *)_usrData;
+ res = pthread_create(&pcxt->pid, NULL, mbtk_record_pthread, dev_hdl);
+ if (res != 0)
+ {
+ if(pcxt->usrData)
+ {
+ free(pcxt->usrData);
+ pcxt->usrData = NULL;
+ }
+ fprintf(stderr, "\n%s: Failed to create pthread\n", __FUNCTION__);
+ }
+ // 防止重复录音
+ usleep(500);
+
+ return res;
+}
+
+int mbtk_audio_close(void *dev_hdl)
+{
+ printf("mbtk_audio_close()\n");
+ int value = 0;
+ struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == _hdl || NULL == internal_hdl )
+ {
+ printf("mbtk_audio_close() fail dev_hdl is NULL\n");
+ return -1;
+ }
+
+ mbtk_audio_set_status(_hdl, AUDIO_STOP);
+ if(0 == _hdl->device) {
+ while (_hdl->pid != 0) {
+ usleep(10000);
+ }
+
+ vcm_playback_drain(0);//wait for drain the AP audiostub queue.
+ usleep(80000);//delay 80ms until DSP play out its buffered data.
+ _hdl->stream_out->common.standby(&_hdl->stream_out->common);
+ _hdl->audio_ahw_dev_ubus->close_output_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_out);
+ } else {
+
+ while (_hdl->pid != 0) {
+ sleep(1);
+ }
+ _hdl->stream_in->common.standby(&_hdl->stream_in->common);
+ _hdl->audio_ahw_dev_ubus->close_input_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_in);
+ VCMDeinit();//close the fd of audiostub_ctl when exit the thread.
+ }
+
+ audio_hal_uninstall();
+ pthread_mutex_destroy(&_hdl->_cond_mutex);
+ pthread_mutex_destroy(&_hdl->_stream_mutex);
+ free(_hdl);
+ _hdl = NULL;
+ internal_hdl = NULL;
+
+ return 0;
+}
+
+int mbtk_audio_pause(void* dev_hdl)
+{
+ // struct pcm *_pcm = ((struct mopen_audio_t *)dev_hdl)->_pcm;
+
+ if (NULL == dev_hdl || NULL == internal_hdl)
+ return -1;
+
+ if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_RUNNING)
+ {
+ return -1;
+ }
+
+ // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 1))
+ // {
+ // printf("\n%s: cannot pause channel: errno =%d\n",__FUNCTION__,-errno);
+ // return -errno;
+ // }
+ mbtk_audio_set_status(dev_hdl, AUDIO_PAUSE);
+ return 0;
+}
+
+int mbtk_audio_resume(void* dev_hdl)
+{
+ if (NULL == dev_hdl || NULL == internal_hdl)
+ return -1;
+
+ if (((struct mopen_audio_t *)dev_hdl)->state != AUDIO_PAUSE)
+ {
+ return -1;
+ }
+
+ // if (ioctl(_pcm->fd, SNDRV_PCM_IOCTL_PAUSE, 0))
+ // {
+ // printf("\n%s: cannot Resume channel: errno =%d\n", __FUNCTION__, -errno);
+ // return -errno;
+ // }
+ mbtk_audio_set_status(dev_hdl, AUDIO_RESUME);
+ return 0;
+}
+
+int mbtk_audio_stop(void* dev_hdl)
+{
+ struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == dev_hdl || NULL == internal_hdl)
+ return -1;
+
+ // if (ioctl(_hdl->_pcm->fd, SNDRV_PCM_IOCTL_DROP))
+ // {
+ // printf("\n%s: cannot Resume channel: errno =%d\n",__FUNCTION__,-errno);
+ // return -errno;
+ // }
+
+ mbtk_audio_set_status(dev_hdl, AUDIO_STOP);
+ _hdl->pid = 0;
+
+ return 0;
+}
+
+mbtk_audio_state_enum mbtk_audio_state_get(void *hdl)
+{
+ return ((struct mopen_audio_t *)hdl)->state;
+}
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio_gain.c b/mbtk/libmbtk_lib/audio/mbtk_audio_gain.c
new file mode 100755
index 0000000..f0a961b
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio_gain.c
@@ -0,0 +1,156 @@
+/*
+* mbtk_audio_gain.c
+*
+* MBTK audio gain for nvm : /NVM/audio_gain.nvm.
+*
+*/
+/******************************************************************************
+
+ EDIT HISTORY FOR FILE
+
+ WHEN WHO WHAT,WHERE,WHY
+-------- -------- -------------------------------------------------------
+2024/3/1 LiuBin Initial version
+
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cutils/properties.h>
+
+#include "mbtk_log.h"
+#include "mbtk_str.h"
+#include "mbtk_audio_gain.h"
+
+void vcm_config_dspgain(unsigned int type, unsigned int gain);
+
+int mbtk_dsp_gain_set(CONFIG_DSPGAIN_Direction dir, int gain)
+{
+ if((gain < MBTK_AUDIO_GAIN_MIN || gain > MBTK_AUDIO_GAIN_MAX)
+ && gain != CONFIG_DSPGAIN_MUTE_ON && gain != CONFIG_DSPGAIN_MUTE_OFF) {
+ LOGE("DSP gain range: %d - %d or %d or %d", MBTK_AUDIO_GAIN_MIN, MBTK_AUDIO_GAIN_MAX,
+ CONFIG_DSPGAIN_MUTE_ON, CONFIG_DSPGAIN_MUTE_OFF);
+ return -1;
+ }
+
+ int fd = open(MBTK_AUDIO_GAIN_PATH, O_RDWR);
+ if(fd < 0) {
+ LOGE("Open file(%s) fail:%d", MBTK_AUDIO_GAIN_PATH, errno);
+ return -1;
+ }
+
+ if( -1 == lseek(fd, MBTK_AUDIO_GAIN_ADD_START, SEEK_SET)) {
+ LOGE("lseek(%d) fail:%d", MBTK_AUDIO_GAIN_ADD_START, errno);
+ goto fail;
+ }
+
+ ACMCodec_GainT gains[VC_HEAD_NUM];
+ int len;
+ memset(gains, 0x0, sizeof(gains));
+ if((len = read(fd, gains, sizeof(gains))) != sizeof(gains)) {
+ LOGE("read(%d/%d) fail:%d", len, sizeof(gains), errno);
+ goto fail;
+ }
+
+ int i = 0;
+ while(i < VC_HEAD_NUM) {
+ if(dir == CONFIG_DSPGAIN_RX) {
+ gains[i].Rx_DSPGain[AUDIOHAL_SPK_VOL_QTY] = (int16)(gain & 0xFFFF);
+ } else if(dir == CONFIG_DSPGAIN_TX) {
+ gains[i].Tx_DSPGain = (int16)(gain & 0xFFFF);
+ }/* else if(dir == CONFIG_DSPGAIN_SIDETONE) {
+ gains[i].Rx_DSPSideToneGain = gain;
+ }*/ else {
+ LOGE("Unknown direction : %d", dir);
+ goto fail;
+ }
+ i++;
+ }
+
+ if( -1 == lseek(fd, MBTK_AUDIO_GAIN_ADD_START, SEEK_SET)) {
+ LOGE("lseek(%d) fail:%d", MBTK_AUDIO_GAIN_ADD_START, errno);
+ goto fail;
+ }
+
+ if(write(fd, gains, sizeof(gains)) != sizeof(gains)) {
+ LOGE("write(%d) fail:%d", sizeof(gains), errno);
+ goto fail;
+ }
+
+ if(fsync(fd)) {
+ LOGE("fsync(%d) fail:%d", fd, errno);
+ goto fail;
+ }
+
+ close(fd);
+
+ LOGD("DSP gain NVM update success.");
+
+ char buff[10];
+ memset(buff, 0, 10);
+ snprintf(buff, 10, "%d", gain);
+ if(dir == CONFIG_DSPGAIN_RX) {
+ if(property_set("persist.mbtk.dsp_rx_gain", buff) == 0) {
+ // Set gain to DSP.
+ vcm_config_dspgain(dir, gain);
+ }
+ } else if(dir == CONFIG_DSPGAIN_TX) {
+ if(property_set("persist.mbtk.dsp_tx_gain", buff) == 0) {
+ // Set gain to DSP.
+ vcm_config_dspgain(dir, gain);
+ }
+ }else {
+ LOGE("Unknown direction : %d", dir);
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ close(fd);
+ return -1;
+}
+
+int mbtk_dsp_gain_get(int *rx_gain, int *tx_gain)
+{
+ if(rx_gain == NULL || tx_gain == NULL) {
+ LOGE("gain is NULL.");
+ return -1;
+ }
+
+ int fd = open(MBTK_AUDIO_GAIN_PATH, O_RDONLY);
+ if(fd < 0) {
+ LOGE("Open file(%s) fail:%d", MBTK_AUDIO_GAIN_PATH, errno);
+ return -1;
+ }
+
+ if( -1 == lseek(fd, MBTK_AUDIO_GAIN_ADD_START, SEEK_SET)) {
+ LOGE("lseek(%d) fail:%d", MBTK_AUDIO_GAIN_ADD_START, errno);
+ goto fail;
+ }
+
+ ACMCodec_GainT gains[VC_HEAD_NUM];
+ int len;
+ memset(gains, 0x0, sizeof(gains));
+ if((len = read(fd, gains, sizeof(gains))) != sizeof(gains)) {
+ LOGE("read(%d/%d) fail:%d", len, sizeof(gains), errno);
+ goto fail;
+ }
+
+ close(fd);
+
+ *rx_gain = gains[VC_HANDSFREE].Rx_DSPGain[AUDIOHAL_SPK_VOL_QTY];
+ *tx_gain = gains[VC_HANDSFREE].Tx_DSPGain;
+ return 0;
+fail:
+ close(fd);
+ return -1;
+}
+
+
+
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h b/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h
new file mode 100755
index 0000000..b4b3dc2
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio_internal.h
@@ -0,0 +1,55 @@
+/*
+* mbtk_audio_internal.h
+*
+* MBTK Audio internal header.
+*
+* Author : lb
+* Date : 2023/12/20 10:13:09
+*/
+#ifndef _MBTK_AUDIO_INTERNAL_H
+#define _MBTK_AUDIO_INTERNAL_H
+#include "mbtk_audio2.h"
+#include "audio_if_api.h"
+#include "audio_if_audio_hw_mrvl.h"
+
+typedef enum {
+ AUDIO_PLAY_STATE_STOP,
+ AUDIO_PLAY_STATE_RUNNING,
+ AUDIO_PLAY_STATE_PAUSE
+} audio_play_state_enum;
+
+typedef enum {
+ AUDIO_RECORDER_STATE_STOP,
+ AUDIO_RECORDER_STATE_RUNNING,
+ AUDIO_RECORDER_STATE_PAUSE
+} audio_recorder_state_enum;
+
+typedef struct {
+ struct audio_stream_out *stream_out;
+ char buff_remain[MBTK_PCM_WB_BUF_SIZE];
+ int buff_remain_len;
+} audio_play_info_t;
+
+typedef struct {
+ struct audio_stream_in *stream_in;
+ audio_recorder_state_enum state;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
+
+ mbtk_recorder_callback_func recorder_cb;
+} audio_recorder_info_t;
+
+typedef struct {
+ mbtk_audio_sample_rate_enum sample_rate;
+ int channel;
+ unsigned int playback_size;
+ audio_hw_device_t *audio_ahw_dev_ubus;
+
+ mbtk_audio_direction_enum direction;
+ union {
+ audio_play_info_t play;
+ audio_recorder_info_t recorder;
+ }info;
+} audio_inter_info_t;
+
+#endif /* _MBTK_AUDIO_INTERNAL_H */
diff --git a/mbtk/libmbtk_lib/audio/mbtk_audio_ubus.c b/mbtk/libmbtk_lib/audio/mbtk_audio_ubus.c
new file mode 100755
index 0000000..8ccc14e
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_audio_ubus.c
@@ -0,0 +1,258 @@
+/*
+* mbtk_audio_ubus.c
+*
+* MBTK audio ubus client API.
+*
+*/
+/******************************************************************************
+
+ EDIT HISTORY FOR FILE
+
+ WHEN WHO WHAT,WHERE,WHY
+-------- -------- -------------------------------------------------------
+2024/3/18 LiuBin Initial version
+
+******************************************************************************/
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "mbtk_audio_ubus.h"
+
+#define AUDIO_UBUS_TIMEOUT 5000 // 3s
+
+#define AUDIO_UBUS_REQUEST_NAME "audio_if"
+#define AUDIO_UBUS_VOLUME_SET "volume_set"
+#define AUDIO_UBUS_VOLUME_GET "volume_status"
+#define AUDIO_UBUS_MODE_SET "audio_mode_set"
+#define AUDIO_UBUS_PATH_ENABLE "audio_path_enable"
+#define AUDIO_UBUS_SWITCH_PCM "switch_pcm"
+#define AUDIO_UBUS_DSP_SET "config_dspgain"
+#define AUDIO_UBUS_LOOPBACK_EN "loopback_enable"
+#define AUDIO_UBUS_LOOPBACK_DIS "loopback_disable"
+#define AUDIO_UBUS_AUDIO_GAIN_SET "audio_gain_set"
+#define AUDIO_UBUS_AUDIO_REG_SET "audio_reg_set"
+
+static struct ubus_context *audio_ctx = NULL;
+static uint32_t ubus_id_audio_if = 0;
+
+static void ubus_complete_cb(struct ubus_request *req, int rc)
+{
+ if(audio_ctx == NULL) {
+ LOGE("MBTK audio ubus not inited.");
+ return;
+ }
+ if (req)
+ {
+ free(req);
+ req = NULL;
+ }
+
+ LOGD("ubus_complete_cb() , rc = %d", rc);
+}
+
+int mbtk_audio_ubus_init()
+{
+ if(audio_ctx) {
+ LOGE("MBTK audio ubus has inited.");
+ return -1;
+ }
+
+ audio_ctx = ubus_connect(NULL);
+ if (!audio_ctx) {
+ LOGE("Failed to connect to ubus.");
+ return -1;
+ }
+
+ int ret = ubus_lookup_id(audio_ctx, AUDIO_UBUS_REQUEST_NAME, &ubus_id_audio_if);
+ if (ret) {
+ LOGE("ubus_lookup_id() fail.");
+ return ret;
+ }
+ return 0;
+}
+
+int mbtk_audio_ubus_deinit()
+{
+ if(audio_ctx) {
+ ubus_free(audio_ctx);
+ audio_ctx = NULL;
+ ubus_id_audio_if = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief mbtk_audio_mode_set
+ *
+ * @details detailed description
+ *
+ * @param param
+ * "param0": UINT32
+ * typedef enum {
+ * AUDIO_MODE_INVALID = -2,
+ * AUDIO_MODE_CURRENT = -1,
+ * AUDIO_MODE_NORMAL = 0,
+ * AUDIO_MODE_RINGTONE = 1,
+ * AUDIO_MODE_IN_CALL = 2,
+ * AUDIO_MODE_IN_COMMUNICATION=3,
+ * AUDIO_MODE_IN_VT_CALL= 4,
+ * AUDIO_MODE_CNT,
+ * AUDIO_MODE_MAX = AUDIO_MODE_CNT-1,
+ * } audio_mode_
+ * @return return type
+ */
+int mbtk_audio_mode_set(int mode)
+{
+ if(audio_ctx == NULL || ubus_id_audio_if == 0) {
+ LOGE("MBTK audio ubus not inited.");
+ return -1;
+ }
+ static struct blob_buf b;
+ int ret;
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "param0", mode);
+ if((ret = ubus_invoke(audio_ctx, ubus_id_audio_if, AUDIO_UBUS_MODE_SET, b.head, NULL, NULL, AUDIO_UBUS_TIMEOUT)) != UBUS_STATUS_OK) {
+ LOGE("ubus_invoke fail:%d.\n", ret);
+ return -1;
+ } else {
+ LOGD("ubus_invoke success.\n");
+ return 0;
+ }
+}
+
+/**
+ * @brief mbtk_audio_loopback_start
+ *
+ * @details detailed description
+ *
+ * @param param
+ * device: UINT32
+ * 0: earpiece
+ * 1: speaker
+ * 2: headset
+ * @return return type
+ */
+int mbtk_audio_loopback_start(int device)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(audio_ctx == NULL || ubus_id_audio_if == 0) {
+ LOGE("MBTK audio ubus not inited.");
+ return -1;
+ }
+
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ LOGE("leave %s: lack of memory", __FUNCTION__);
+ return -1;
+ }
+ static struct blob_buf b;
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "param0", device);
+ if ((rc = ubus_invoke_async(audio_ctx,
+ ubus_id_audio_if,
+ AUDIO_UBUS_LOOPBACK_EN,
+ b.head, req)) != UBUS_STATUS_OK) {
+ free(req);
+ LOGE("ubus_invoke_async %s failed %s", AUDIO_UBUS_LOOPBACK_EN, ubus_strerror(rc));
+ return -1;
+ }
+ else
+ {
+ LOGD("ubus_invoke_async %s success", AUDIO_UBUS_LOOPBACK_EN);
+ req->complete_cb = ubus_complete_cb;
+ ubus_complete_request_async(audio_ctx, req);
+ return 0;
+ }
+}
+
+int mbtk_audio_loopback_stop()
+{
+ int rc = 0;
+
+ if(audio_ctx == NULL || ubus_id_audio_if == 0) {
+ LOGE("MBTK audio ubus not inited.");
+ return -1;
+ }
+ static struct blob_buf b;
+ blob_buf_init(&b, 0);
+ if ((rc = ubus_invoke(audio_ctx,
+ ubus_id_audio_if,
+ AUDIO_UBUS_LOOPBACK_DIS,
+ b.head, NULL, NULL, AUDIO_UBUS_TIMEOUT)) != UBUS_STATUS_OK)
+ {
+ LOGE("ubus_invoke %s failed %s", AUDIO_UBUS_LOOPBACK_DIS, ubus_strerror(rc));
+ return -1;
+ }
+ else
+ {
+ LOGD("ubus_invoke %s success", AUDIO_UBUS_LOOPBACK_DIS);
+ return 0;
+ }
+}
+
+/**
+ * @brief mbtk_audio_dsp_gain_set
+ *
+ * @details dsp gain set
+ *
+ * @param param
+ * type: 0:tx
+ * 0: tx
+ * 1: rx
+ * gain: -36~12 db
+
+ * @return return
+ */
+int mbtk_audio_dsp_gain_set(int type, int gain)
+{
+ int rc = 0;
+ struct ubus_request *req = NULL;
+
+ if(audio_ctx == NULL || ubus_id_audio_if == 0) {
+ LOGE("MBTK audio ubus not inited.");
+ return -1;
+ }
+
+ req = (struct ubus_request *)malloc(sizeof(struct ubus_request));
+ if (req == NULL)
+ {
+ LOGE("leave %s: lack of memory", __FUNCTION__);
+ return -1;
+ }
+ static struct blob_buf b;
+ memset(req, 0, sizeof(struct ubus_request));
+ blob_buf_init(&b, 0);
+ blobmsg_add_u32(&b, "type", type);
+ blobmsg_add_u32(&b, "gain", gain);
+ if ((rc = ubus_invoke_async(audio_ctx,
+ ubus_id_audio_if,
+ AUDIO_UBUS_DSP_SET,
+ b.head, req)) != UBUS_STATUS_OK) {
+ free(req);
+ LOGE("ubus_invoke_async %s failed %s", AUDIO_UBUS_DSP_SET, ubus_strerror(rc));
+ return -1;
+ }
+ else
+ {
+ LOGD("ubus_invoke_async %s success", AUDIO_UBUS_DSP_SET);
+ req->complete_cb = ubus_complete_cb;
+ ubus_complete_request_async(audio_ctx, req);
+ return 0;
+ }
+}
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_mp3.c b/mbtk/libmbtk_lib/audio/mbtk_mp3.c
new file mode 100755
index 0000000..8b13789
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_mp3.c
@@ -0,0 +1 @@
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_mp3_to_wav.c b/mbtk/libmbtk_lib/audio/mbtk_mp3_to_wav.c
new file mode 100755
index 0000000..cb95735
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_mp3_to_wav.c
@@ -0,0 +1,378 @@
+#include "mbtk_audio.h"
+#include "audio_if_types.h"
+#include "audio_if_ubus.h"
+#include "audio_if_parameter.h"
+#include "audio_if.h"
+#include "audio_if_api.h"
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include <string.h>
+//#include "audio_if_audio_hw_mrvl.h"
+//#include "utlEventHandler.h"
+//#include "udev_monitor.h"
+#include "audio_hw_mrvl.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <cutils/str_parms.h>
+#include "vcm.h"
+#include <libavutil/avutil.h>
+#include <libavutil/attributes.h>
+#include <libavutil/opt.h>
+#include <libavutil/mathematics.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/samplefmt.h>
+#include <libavutil/timestamp.h>
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+#include <libavutil/mathematics.h>
+#include <libswresample/swresample.h>
+//#include <libavutil/channel_layout.h>
+#include <libavutil/common.h>
+#include <libavformat/avio.h>
+#include <libavutil/file.h>
+#include <libswresample/swresample.h>
+#include <libavfilter/avfilter.h>
+
+
+extern int mbtk_audio_play_stream_old(void *dev_hdl, const void *pData, int len);
+extern int mbtk_audio_get_status(void* hdl);
+
+#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000
+
+/* the size may be modified because of different decoded sample number. */
+#define MGR_BUFFER_SIZE 1024
+
+//#define DEBUG_FFMPEG_PCM_STREAM
+
+/* needed by PCM stream */
+extern void* audio_hal_install(void);
+extern void audio_hal_uninstall(void);
+extern void configure_vcm(unsigned int data[]);
+extern void set_pcm_config(int role, int rate);
+extern int mrvl_hw_dev_config_pcm(struct audio_hw_device *dev, unsigned int pcm);
+
+
+typedef struct {
+ int videoindex;
+ int sndindex;
+ AVFormatContext* pFormatCtx;
+ AVCodecContext* sndCodecCtx;
+ AVCodec* sndCodec;
+ SwrContext *swr_ctx;
+ DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE * 2];
+ //DECLARE_ALIGNED(16,uint8_t,audio_buf) [AVCODEC_MAX_AUDIO_FRAME_SIZE];
+}AudioState;
+
+/******************************************************************************
+ * Globals
+ ******************************************************************************/
+/* needed by FFMPEG */
+extern int64_t av_get_default_channel_layout(int nb_channels);
+extern AVFrame *avcodec_alloc_frame(void);
+
+
+static int my_init_ffmpeg1(AudioState* is, char* filepath)
+{
+ is->sndindex = -1;
+
+ if(NULL == filepath)
+ {
+ printf("input file is NULL");
+ return -1;
+ }
+
+ avcodec_register_all();
+ avfilter_register_all();
+ av_register_all();
+
+ is->pFormatCtx = avformat_alloc_context();
+
+ if(avformat_open_input(&is->pFormatCtx, filepath, NULL, NULL)!=0)
+ return -1;
+
+ if(avformat_find_stream_info(is->pFormatCtx, NULL)<0)
+ return -1;
+
+ av_dump_format(is->pFormatCtx,0, 0, 0);
+
+ is->videoindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_VIDEO, is->videoindex, -1, NULL, 0);
+ is->sndindex = av_find_best_stream(is->pFormatCtx, AVMEDIA_TYPE_AUDIO,is->sndindex, is->videoindex, NULL, 0);
+
+ printf("videoindex=%d, sndindex=%d", is->videoindex, is->sndindex);
+
+ if(is->sndindex != -1)
+ {
+ is->sndCodecCtx = is->pFormatCtx->streams[is->sndindex]->codec;
+ is->sndCodec = avcodec_find_decoder(is->sndCodecCtx->codec_id);
+
+ if(is->sndCodec == NULL)
+ {
+ printf("Codec not found");
+ return -1;
+ }
+
+ if(avcodec_open2(is->sndCodecCtx, is->sndCodec, NULL) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int mbtk_audio_mp3_to_wav(const char *wavpath, char *mp3path)
+{
+ int in_channel_nb = 0;
+ int ret, rc;
+ int fd;
+ int size;
+ int len;
+ int file_data_size = 0;
+ int converted_nb_samples = 0;
+ int got_frame;
+ int index =0;
+ int i =0;
+ AVPacket *packet = av_mallocz(sizeof(AVPacket));
+ //AVFrame *frame = av_frame_alloc();
+ AVFrame *frame = avcodec_alloc_frame();
+ AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
+ uint8_t *out[] = { is->audio_buf };
+ //char buf[MGR_BUFFER_SIZE];
+
+ enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //输出采样格式16bit PCM
+
+ int out_channel_nb = 0;
+ struct wav_header header;
+
+
+#if 1
+ int sample_rate = 8000;
+ //int sample_rate = 16000;
+ //int sample_rate = 44100;
+
+ int out_sample_rate = sample_rate; //输出采样率
+ uint64_t out_ch_layout = AV_CH_LAYOUT_MONO; //输出的声道布局
+ //uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; //输出的声道布局
+
+#endif
+
+ fd = open(wavpath, O_WRONLY | O_CREAT); //wavpath
+
+ //leave enough room for header
+ lseek(fd, sizeof(struct wav_header), SEEK_SET);
+
+
+ //第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
+ if( (ret = my_init_ffmpeg1(is, mp3path)) != 0) //1.1 初始化ffmpeg
+ {
+ printf("my_init_ffmpeg error");
+ return -1;
+ }
+
+ while(av_read_frame(is->pFormatCtx, packet) >= 0) //1.2 循环读取mp3文件中的数据帧
+ {
+ if(packet->stream_index != is->sndindex)
+ continue;
+
+ if((ret = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
+ {
+ printf("file eof");
+ break;
+ }
+
+ if(got_frame <= 0) /* No data yet, get more frames */
+ continue;
+
+ //1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
+ if(NULL==is->swr_ctx)
+ {
+ if(is->swr_ctx != NULL)
+ swr_free(&is->swr_ctx);
+
+ //输入的声道个数
+ in_channel_nb = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+ //输出的声道个数
+ out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
+
+ printf("frame: input channel: channnels=%d, format=%d, sample_rate=%d, nb_samples=%d.\n",
+ in_channel_nb, frame->format, frame->sample_rate, frame->nb_samples);
+ printf("frame: out channel: channels=%d, format=%d, sample_rate=%d.\n", out_channel_nb, out_sample_fmt, out_sample_rate);
+
+ is->swr_ctx = swr_alloc_set_opts(NULL, out_ch_layout, out_sample_fmt, out_sample_rate, av_get_default_channel_layout(in_channel_nb), frame->format, frame->sample_rate, 0, NULL);
+
+
+ if(is->swr_ctx == NULL)
+ {
+ printf("swr_ctx == NULL");
+ }
+
+ swr_init(is->swr_ctx);
+ }
+
+ converted_nb_samples = swr_convert(is->swr_ctx, out, AVCODEC_MAX_AUDIO_FRAME_SIZE * 2, (const uint8_t **)frame->data, frame->nb_samples);
+
+ file_data_size += converted_nb_samples;
+
+ //1.5 数据格式转换完成后就写到文件中
+ //sample bit is 16bits = 2Bytes
+ size = converted_nb_samples*out_channel_nb*2;
+ write(fd, (char *)(is->audio_buf), size);
+
+ }
+
+ //sample bit is 16bits = 2Bytes
+ file_data_size *= (out_channel_nb*2);//(numSamples * wavFMT->numChannels * wavFMT->uiBitsPerSample) / 8
+
+ printf("file_data_size=%d, nb_samples=%d, converted_nb_samples=%d.\n", file_data_size, frame->nb_samples, converted_nb_samples);
+
+ //第2步添加上wav的头
+ //write header now all information is known
+ header.riff_id = ID_RIFF;
+ header.riff_sz = 0;
+ header.riff_fmt = ID_WAVE;
+ header.fmt_id = ID_FMT;
+ header.fmt_sz = 16;
+ header.audio_format = 1; //FORMAT_PCM;
+ header.num_channels = out_channel_nb; //Modem ONLY support mono recording
+ header.sample_rate = sample_rate; //44100, 8000, 16000
+ header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
+ header.byte_rate = (header.bits_per_sample / 8) * header.num_channels * header.sample_rate;
+ header.block_align = header.num_channels * (header.bits_per_sample / 8);
+ header.data_id = ID_DATA;
+
+ header.data_sz = file_data_size;
+ header.riff_sz = header.data_sz + sizeof(header) - 8;
+
+ lseek(fd, 0, SEEK_SET);
+ write(fd, &header, sizeof(struct wav_header));
+ printf("%s: sample_rate = %d, num_channels = %d!\n", __FUNCTION__, header.sample_rate, header.num_channels);
+
+ av_free_packet(packet);
+ av_free(frame);
+ avcodec_close(is->sndCodecCtx);
+ avformat_close_input(&is->pFormatCtx);
+
+ close(fd);
+
+ return 0;
+}
+
+
+int mbtk_audio_mp3_to_play(char *mp3path, int hdl, int sample_rate)
+{
+ int in_channel_nb = 0;
+ int ret, rc;
+ int size;
+ int len;
+ int file_data_size = 0;
+ int converted_nb_samples = 0;
+ int got_frame;
+ int index =0;
+ int i =0;
+ int audio_status =0;
+ AVPacket *packet = av_mallocz(sizeof(AVPacket));
+ //AVFrame *frame = av_frame_alloc();
+ AVFrame *frame = avcodec_alloc_frame();
+ AudioState* is = (AudioState*) av_mallocz(sizeof(AudioState));
+ uint8_t *out[] = { is->audio_buf };
+ //char buf[MGR_BUFFER_SIZE];
+
+ enum AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16; //输出采样格式16bit PCM
+
+ int out_channel_nb = 0;
+
+
+ if(sample_rate)
+ {
+ sample_rate = 16000;
+ }
+ else
+ {
+ sample_rate = 8000;
+ }
+// int sample_rate = 8000;
+ //int sample_rate = 16000;
+ //int sample_rate = 44100;
+
+ int out_sample_rate = sample_rate; //输出采样率
+ uint64_t out_ch_layout = AV_CH_LAYOUT_MONO; //输出的声道布局
+ //uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO; //输出的声道布局
+
+ //第1步初始化ffmpeg,并用ffmpeg解码,最后转为pcm格式
+ if( (ret = my_init_ffmpeg1(is, mp3path)) != 0) //1.1 初始化ffmpeg
+ {
+ printf("my_init_ffmpeg error");
+ return -1;
+ }
+
+ audio_status = mbtk_audio_get_status((void *)hdl);
+
+ while(av_read_frame(is->pFormatCtx, packet) >= 0 && ((audio_status==AUDIO_OPEN)|| (audio_status==AUDIO_RUNNING))) //1.2 循环读取mp3文件中的数据帧
+ {
+ if(packet->stream_index != is->sndindex)
+ continue;
+
+ if((ret = avcodec_decode_audio4(is->sndCodecCtx, frame, &got_frame, packet)) < 0) //1.3 解码数据帧
+ {
+ printf("file eof");
+ break;
+ }
+
+ if(got_frame <= 0) /* No data yet, get more frames */
+ continue;
+
+ //1.4下面将ffmpeg解码后的数据帧转为我们需要的数据(关于"需要的数据"下面有解释)
+ if(NULL==is->swr_ctx)
+ {
+ if(is->swr_ctx != NULL)
+ swr_free(&is->swr_ctx);
+
+ //输入的声道个数
+ in_channel_nb = av_get_channel_layout_nb_channels(frame->channel_layout);
+
+ //输出的声道个数
+ out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
+
+ printf("frame: input channel: channnels=%d, format=%d, sample_rate=%d, nb_samples=%d.\n",
+ in_channel_nb, frame->format, frame->sample_rate, frame->nb_samples);
+ printf("frame: out channel: channels=%d, format=%d, sample_rate=%d.\n", out_channel_nb, out_sample_fmt, out_sample_rate);
+
+ is->swr_ctx = swr_alloc_set_opts(NULL, out_ch_layout, out_sample_fmt, out_sample_rate, av_get_default_channel_layout(in_channel_nb), frame->format, frame->sample_rate, 0, NULL);
+
+
+ if(is->swr_ctx == NULL)
+ {
+ printf("swr_ctx == NULL");
+ }
+
+ swr_init(is->swr_ctx);
+ }
+
+ converted_nb_samples = swr_convert(is->swr_ctx, out, AVCODEC_MAX_AUDIO_FRAME_SIZE * 2, (const uint8_t **)frame->data, frame->nb_samples);
+
+ file_data_size += converted_nb_samples;
+
+ //1.5 数据格式转换完成后就写到文件中
+ //sample bit is 16bits = 2Bytes
+ size = converted_nb_samples*out_channel_nb*2;
+ mbtk_audio_play_stream((void *)hdl, (char *)(is->audio_buf), size);
+// mbtk_audio_play_stream_old((void *)hdl, (char *)(is->audio_buf), size);
+ audio_status = mbtk_audio_get_status((void *)hdl);
+
+ }
+
+
+ av_free_packet(packet);
+ av_free(frame);
+ avcodec_close(is->sndCodecCtx);
+ avformat_close_input(&is->pFormatCtx);
+
+ return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c b/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c
new file mode 100755
index 0000000..9f2336d
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_pcm_stream.c
@@ -0,0 +1,949 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "mbtk_log.h"
+#include "mbtk_audio_internal.h"
+#include "audio_if_audio_hw_mrvl.h"
+
+#define LOCK_FILE "/var/run/mbtk_audio.lock"
+#define AUDIO_DEBUG 0
+
+#define AUDIO_LOG(fmt, args ...) \
+ do{ \
+ if(AUDIO_DEBUG) {LOGD(fmt, ##args);} \
+ } while(0)
+
+extern void* audio_hal_install(void);
+extern void audio_hal_uninstall(void);
+extern void configure_vcm(unsigned int data[]);
+
+static audio_inter_info_t *audio_info = NULL;
+static pthread_t recorder_thread_play;
+
+static int lock_get() {
+ int fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd == -1) {
+ LOGE("Open(%s) fail:%d", LOCK_FILE, errno);
+ return -1;
+ }
+ // 尝试对文件进行加锁
+ struct flock fl;
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+ int ret = fcntl(fd, F_SETLK, &fl);
+ if (ret == -1) {
+ LOGE("Another instance is running, exiting...");
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ LOGD("Get file lock.");
+ return 0;
+}
+
+static int lock_free() {
+ int fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (fd == -1) {
+ LOGE("Open(%s) fail:%d", LOCK_FILE, errno);
+ return -1;
+ }
+ // 释放文件锁
+ struct flock fl;
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 1;
+ int ret = fcntl(fd, F_SETLK, &fl);
+ if (ret == -1) {
+ LOGE("Another instance is running, exiting...");
+ close(fd);
+ return -1;
+ }
+
+ LOGD("Free file lock.");
+ return 0;
+}
+
+static void audio_recorder_thread(void *arg)
+{
+ int rc, len, frames = 0;
+ char buff[MBTK_PCM_WB_BUF_SIZE];
+
+ audio_info->info.recorder.state = AUDIO_RECORDER_STATE_RUNNING;
+ pthread_mutex_init(&audio_info->info.recorder.mutex, NULL);
+ pthread_cond_init(&audio_info->info.recorder.cond, NULL);
+
+ while (TRUE) {
+ /* Playback loop */
+ pthread_mutex_lock(&audio_info->info.recorder.mutex);
+ if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_STOP) {
+ LOGD("Stop recorder...");
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ break;
+ } else if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ pthread_cond_wait(&audio_info->info.recorder.cond, &audio_info->info.recorder.mutex);
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ continue;
+ } else {
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ }
+
+ //record the needed format stream from the device.
+ //only read pcm stream, no send command.
+ len = audio_info->info.recorder.stream_in->read(audio_info->info.recorder.stream_in, buff,
+ audio_info->playback_size);
+ if (len <= 0) {
+ LOGE("%s: error reading!", __FUNCTION__);
+ goto thread_end;
+ }
+
+ AUDIO_LOG("Recorder data : len - %d", len);
+
+ if(audio_info->info.recorder.recorder_cb) {
+ audio_info->info.recorder.recorder_cb(buff, len);
+ }
+
+ LOGD("%s: No.%d frame playback.", __FUNCTION__, ++frames);
+ }
+
+
+thread_end:
+ pthread_mutex_destroy(&audio_info->info.recorder.mutex);
+ pthread_cond_destroy(&audio_info->info.recorder.cond);
+
+ audio_info->info.recorder.stream_in->common.standby(&audio_info->info.recorder.stream_in->common);
+ audio_info->audio_ahw_dev_ubus->close_input_stream(audio_info->audio_ahw_dev_ubus, audio_info->info.recorder.stream_in);
+ VCMDeinit();//close the fd of audiostub_ctl when exit the thread.
+ audio_info->info.recorder.stream_in = NULL;
+ LOGD("%s: finished pcm playback.", __FUNCTION__);
+
+ // Notify audio recorder data end.
+ if(audio_info->info.recorder.recorder_cb) {
+ audio_info->info.recorder.recorder_cb(NULL, 0);
+ }
+ return;
+}
+
+
+static int config_parameters(mbtk_audio_direction_enum direction, mbtk_audio_sample_rate_enum NBWB)
+{
+ unsigned int srcdst, priority, dest;
+ char kvpair[128];
+ struct str_parms *param = NULL;
+ int data[5];
+ const char *key = NULL;
+ bool update_vcm = false;
+
+ srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+ priority = 1;/* 0-Do not combine(override), 1-Combine */
+ dest = 1;/* 0-Near codec, 1-Near Vocoder */
+
+ if(direction == MBTK_AUDIO_DIRECTION_OUTPUT){//output
+ if(NBWB == MBTK_AUDIO_SAMPLE_RATE_8000)
+ audio_info->playback_size = MBTK_PCM_NB_BUF_SIZE;
+ else
+ audio_info->playback_size = MBTK_PCM_WB_BUF_SIZE;
+
+ LOGD("config playback parameters.");
+ }
+ else if(direction == MBTK_AUDIO_DIRECTION_INPUT){//input
+ if(NBWB == MBTK_AUDIO_SAMPLE_RATE_8000)
+ audio_info->playback_size = MBTK_PCM_NB_BUF_SIZE;
+ else
+ audio_info->playback_size = MBTK_PCM_WB_BUF_SIZE;
+
+ LOGD("config record parameters.");
+ }
+
+ memset(kvpair, 0x00, sizeof(kvpair));
+ sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
+ VCM_CONFIG_TYPE, NBWB, VCM_CONFIG_SRC_DST, srcdst,
+ VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
+
+ LOGD("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
+
+ //extract the parameter and config from string
+ param = str_parms_create_str(kvpair);
+ if (!param) {
+ LOGE("%s: param create str is null!", __FUNCTION__);
+ return -1;
+ }
+
+ //set vcm configurations
+ key = VCM_CONFIG_DIRECTION;
+ if (str_parms_get_int(param, key, &data[0]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_TYPE;
+ if (str_parms_get_int(param, key, &data[1]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_SRC_DST;
+ if (str_parms_get_int(param, key, &data[2]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_PRIORITY;
+ if (str_parms_get_int(param, key, &data[3]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_DEST;
+ if (str_parms_get_int(param, key, &data[4]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+
+ //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
+
+ if (update_vcm) {
+ configure_vcm(data); /*TODO check if all inputs got all values successfully*/
+ }
+
+ return 0;
+}
+
+int mbtk_audio_pcm_init()
+{
+ //mbtk_log_init("radio", "MBTK_AUDIO");
+ // Audio is running...
+ if(lock_get()) {
+ return -1;
+ }
+
+ if(audio_info) {
+ return 0;
+ }
+
+ audio_info = (audio_inter_info_t*)malloc(sizeof(audio_inter_info_t));
+ if(audio_info == NULL) {
+ LOGE("malloc() fail:%d", errno);
+ return -1;
+ }
+ memset(audio_info, 0x00, sizeof(audio_inter_info_t));
+
+ // Set default audio parameter.
+ audio_info->channel = 1;
+ audio_info->sample_rate = MBTK_AUDIO_SAMPLE_RATE_8000;
+ audio_info->playback_size = MBTK_PCM_NB_BUF_SIZE;
+
+ audio_info->audio_ahw_dev_ubus = audio_hal_install();
+ if (audio_info->audio_ahw_dev_ubus == NULL) {
+ LOGE("audio_hal_install() failed!");
+ goto init_fail;
+ }
+ return 0;
+init_fail:
+ free(audio_info);
+ audio_info = NULL;
+ return -1;
+}
+
+int mbtk_audio_pcm_sample_rate_set(mbtk_audio_sample_rate_enum sample_rate)
+{
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ audio_info->sample_rate = sample_rate;
+
+ return 0;
+}
+
+int mbtk_audio_pcm_play_start()
+{
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->audio_ahw_dev_ubus) {
+ LOGE("audio_info->audio_ahw_dev_ubus is NULL.");
+ return -1;
+ }
+
+ config_parameters(MBTK_AUDIO_DIRECTION_OUTPUT, audio_info->sample_rate);
+
+ int rc = audio_info->audio_ahw_dev_ubus->open_output_stream(audio_info->audio_ahw_dev_ubus, 0,
+ audio_info->audio_ahw_dev_ubus->get_supported_devices(audio_info->audio_ahw_dev_ubus),
+ AUDIO_OUTPUT_FLAG_DIRECT, NULL, &(audio_info->info.play.stream_out), 0);
+ if (rc < 0) {
+ LOGE("Open output device fail:%d", rc);
+ goto play_start_fail;
+ }
+
+ audio_info->direction = MBTK_AUDIO_DIRECTION_OUTPUT;
+ audio_info->info.play.buff_remain_len = 0;
+
+ return 0;
+play_start_fail:
+
+ return -1;
+}
+
+int mbtk_audio_pcm_play_data_send(const void* data,uint32 data_len)
+{
+ UNUSED(data);
+ UNUSED(data_len);
+
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->info.play.stream_out) {
+ LOGE("Output device not open.");
+ return -1;
+ }
+
+ uint32 index = 0;
+ // There are remaining data from the previous package。
+ if(audio_info->info.play.buff_remain_len > 0) {
+ // Too less for one package.
+ if(data_len + audio_info->info.play.buff_remain_len < audio_info->playback_size) {
+ AUDIO_LOG("Save remain data : len - %d", data_len);
+ memcpy(audio_info->info.play.buff_remain + audio_info->info.play.buff_remain_len, data, data_len);
+ audio_info->info.play.buff_remain_len += data_len;
+ return data_len;
+ } else {
+ AUDIO_LOG("Write remain data : %d + %d", audio_info->info.play.buff_remain_len, audio_info->playback_size - audio_info->info.play.buff_remain_len);
+ memcpy(audio_info->info.play.buff_remain + audio_info->info.play.buff_remain_len, data, audio_info->playback_size - audio_info->info.play.buff_remain_len);
+
+ int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, audio_info->info.play.buff_remain, audio_info->playback_size);
+ if (rc < 0) {
+ LOGE("%s: error writing (child).", __FUNCTION__);
+ goto send_fail;
+ } else if (rc < (signed int)audio_info->playback_size) {
+ LOGW("%s: wrote less than buffer size, rc=%d.", __FUNCTION__, rc);
+ index += rc;
+ goto send_fail;
+ }
+
+ index += (audio_info->playback_size - audio_info->info.play.buff_remain_len);
+ audio_info->info.play.buff_remain_len = 0;
+ }
+ }
+
+ while(data_len - index >= audio_info->playback_size) {
+ AUDIO_LOG("Package : %d -> %d", index, index + audio_info->playback_size - 1);
+ int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, (const char*)data + index, audio_info->playback_size);
+ if (rc < 0) {
+ LOGE("%s: error writing (child).", __FUNCTION__);
+ goto send_fail;
+ } else if (rc < (signed int)audio_info->playback_size) {
+ LOGW("%s: wrote less than buffer size, rc=%d.", __FUNCTION__, rc);
+ goto send_fail;
+ }
+
+ index += rc;
+ }
+
+ // Last package.( less then audio_info->playback_size)
+ // Save to buffer audio_info->play_buff_remain
+ if(data_len - index > 0) {
+ AUDIO_LOG("Save remain data : len - %d", data_len - index);
+ memcpy(audio_info->info.play.buff_remain, data + index, data_len - index);
+ audio_info->info.play.buff_remain_len = data_len - index;
+ }
+
+ return data_len;
+send_fail:
+ return -1;
+}
+
+int mbtk_audio_pcm_play_stop()
+{
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->info.play.stream_out) {
+ LOGE("Output device not open.");
+ return -1;
+ }
+
+ // Write last package.
+ if(audio_info->info.play.buff_remain_len > 0) {
+ char buf[MBTK_PCM_WB_BUF_SIZE];
+ memset(buf, 0x00, sizeof(buf));
+ memcpy(buf, audio_info->info.play.buff_remain, audio_info->info.play.buff_remain_len);
+
+ LOGD("len %d is smaller than needed %d, so fill the buffer with 0.", audio_info->info.play.buff_remain_len, audio_info->playback_size);
+
+ int rc = audio_info->info.play.stream_out->write(audio_info->info.play.stream_out, buf, audio_info->playback_size);
+ if (rc < 0) {
+ LOGE("%s: error writing (child).", __FUNCTION__);
+ //goto send_fail;
+ } else if (rc < (signed int)audio_info->playback_size) {
+ LOGW("%s: wrote less than buffer size, rc=%d.", __FUNCTION__, rc);
+ //goto send_fail;
+ }
+ audio_info->info.play.buff_remain_len = 0;
+ }
+
+ vcm_playback_drain(0);//wait for drain the AP audiostub queue.
+ usleep(80000);//delay 80ms until DSP play out its buffered data.
+ audio_info->info.play.stream_out->common.standby(&(audio_info->info.play.stream_out->common));
+ audio_info->audio_ahw_dev_ubus->close_output_stream(audio_info->audio_ahw_dev_ubus, audio_info->info.play.stream_out);
+
+ audio_info->info.play.stream_out = NULL;
+ return 0;
+}
+
+
+int mbtk_audio_pcm_recorder_start(mbtk_recorder_callback_func recorder_cb)
+{
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ if(!audio_info->audio_ahw_dev_ubus) {
+ LOGE("audio_info->audio_ahw_dev_ubus is NULL.");
+ return -1;
+ }
+
+ if(audio_info->info.recorder.state != AUDIO_RECORDER_STATE_STOP) {
+ LOGW("Audio is recorder...");
+ return -1;
+ }
+
+ config_parameters(MBTK_AUDIO_DIRECTION_INPUT, audio_info->sample_rate);
+
+ VCMInit();
+
+ int rc = audio_info->audio_ahw_dev_ubus->open_input_stream(audio_info->audio_ahw_dev_ubus, 0,
+ audio_info->audio_ahw_dev_ubus->get_supported_devices(audio_info->audio_ahw_dev_ubus),
+ NULL, &(audio_info->info.recorder.stream_in), 0, 0, AUDIO_SOURCE_VOICE_CALL);
+ if (rc < 0) {
+ LOGE("Open input device fail:%d", rc);
+ goto recorder_start_fail;
+ }
+
+ audio_info->direction = MBTK_AUDIO_DIRECTION_INPUT;
+ audio_info->info.recorder.recorder_cb = recorder_cb;
+
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+ {
+ LOGE("pthread_attr_setdetachstate() fail.");
+ return -1;
+ }
+
+ if (pthread_create(&recorder_thread_play, NULL, (void *)&audio_recorder_thread, NULL) < 0) {
+ LOGE("%s: error creating thread_recorder!", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+recorder_start_fail:
+
+ return -1;
+}
+
+int mbtk_audio_pcm_recorder_pause()
+{
+ int result = 0;
+ pthread_mutex_lock(&audio_info->info.recorder.mutex);
+ if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
+ audio_info->info.recorder.state = AUDIO_RECORDER_STATE_PAUSE;
+ } else {
+ result = -1;
+ LOGW("Audio state : %d", audio_info->info.recorder.state);
+ }
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ return result;
+}
+
+int mbtk_audio_pcm_recorder_resume()
+{
+ int result = 0;
+ pthread_mutex_lock(&audio_info->info.recorder.mutex);
+ if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ audio_info->info.recorder.state = AUDIO_RECORDER_STATE_RUNNING;
+ pthread_cond_signal(&audio_info->info.recorder.cond);
+ } else {
+ result = -1;
+ LOGW("Audio state : %d", audio_info->info.recorder.state);
+ }
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ return result;
+}
+
+
+int mbtk_audio_pcm_recorder_stop()
+{
+ int result = 0;
+ pthread_mutex_lock(&audio_info->info.recorder.mutex);
+ if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE || audio_info->info.recorder.state == AUDIO_RECORDER_STATE_RUNNING) {
+ if(audio_info->info.recorder.state == AUDIO_RECORDER_STATE_PAUSE) {
+ pthread_cond_signal(&audio_info->info.recorder.cond);
+ }
+ audio_info->info.recorder.state = AUDIO_RECORDER_STATE_STOP;
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+
+ LOGD("Waitting recorder thread exit...");
+ if (pthread_join(recorder_thread_play, NULL)) {
+ LOGE("error join thread_recorder!");
+ // abort();
+ }
+ LOGD("Recorder thread exit success.");
+ } else {
+ pthread_mutex_unlock(&audio_info->info.recorder.mutex);
+ result = -1;
+ LOGW("Audio state : %d", audio_info->info.recorder.state);
+ }
+
+ return result;
+}
+
+int mbtk_audio_pcm_deinit()
+{
+ if(!audio_info) {
+ LOGE("Not inited.");
+ return -1;
+ }
+
+ audio_hal_uninstall();
+
+ if(lock_free()) {
+ return -1;
+ }
+
+ free(audio_info);
+ audio_info = NULL;
+ return 0;
+}
+
+
+typedef enum {
+ AUD_PLAYER_ERROR = -1,
+ AUD_PLAYER_START = 0,
+ AUD_PLAYER_PAUSE,
+ AUD_PLAYER_RESUME,
+ AUD_PLAYER_NODATA, //Buff no data and play tread will sleep
+ AUD_PLAYER_LESSDATA, //Buff has less data
+ AUD_PLAYER_FINISHED,
+} Enum_AudPlayer_State;
+
+struct mopen_audio_t
+{
+ int device;
+ audio_hw_device_t *audio_ahw_dev_ubus;
+ struct audio_stream_in *stream_in;
+ struct audio_stream_out *stream_out;
+ int pcm_packet_size; //320:NB, 640:WB
+ int pipe_data;
+ int fd[2];
+ pthread_t pid;
+ mbtk_audio_state_enum state;
+ pthread_mutex_t _cond_mutex;
+ pthread_mutex_t _stream_mutex;
+ void *usrData;
+};
+
+static struct mopen_audio_t *internal_hdl = NULL;
+typedef int (*_play_callback)(int hdl, int result);
+
+
+static int config_parameters_new(int in_out, int NBWB)
+{
+ unsigned int direction = 0xFF, type, srcdst, priority, dest;
+ char kvpair[128];
+ struct str_parms *param = NULL;
+ int data[5];
+ const char *key = NULL;
+ bool update_vcm = false;
+
+ direction = in_out;/* 0-play, 1-record */
+ type = NBWB; /* 0:PCM_NB_BUF_SIZE, 1:PCM_WB_BUF_SIZE */
+ srcdst = 1;/* 0-None, 1-Near end, 2-Far end, 3-Both ends */
+ priority = 1;/* 0-Do not combine(override), 1-Combine */
+ dest = 1;/* 0-Near codec, 1-Near Vocoder */
+
+ memset(kvpair, 0x00, sizeof(kvpair));
+ sprintf(kvpair, "%s=%d;%s=%d;%s=%d;%s=%d;%s=%d", VCM_CONFIG_DIRECTION, direction,
+ VCM_CONFIG_TYPE, type, VCM_CONFIG_SRC_DST, srcdst,
+ VCM_CONFIG_PRIORITY, priority, VCM_CONFIG_DEST, dest);
+
+ LOGD("%s: config information kvpair is %s.\n", __FUNCTION__, kvpair);
+
+ //extract the parameter and config from string
+ param = str_parms_create_str(kvpair);
+ if (!param) {
+ printf("%s: param create str is null!", __FUNCTION__);
+ return -1;
+ }
+
+ //set vcm configurations
+ key = VCM_CONFIG_DIRECTION;
+ if (str_parms_get_int(param, key, &data[0]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_TYPE;
+ if (str_parms_get_int(param, key, &data[1]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_SRC_DST;
+ if (str_parms_get_int(param, key, &data[2]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_PRIORITY;
+ if (str_parms_get_int(param, key, &data[3]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+ key = VCM_CONFIG_DEST;
+ if (str_parms_get_int(param, key, &data[4]) == 0) {
+ update_vcm = true;
+ str_parms_del(param, key);
+ }
+
+ //printf("Direction is %d, Type is %d, Src_Dst is %d, Priority is %d, Dest is %d. \n",data[0], data[1], data[2], data[3], data[4]);
+
+ if (update_vcm) {
+ configure_vcm(data); /*TODO check if all inputs got all values successfully*/
+ }
+
+ return 0;
+}
+
+static int audio_open_pcm_new(void *dev_hdl, int num_channels, int rate, int in_out)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+ int nb_wb;
+
+ //Support 8k/16k & mono wave file
+ if (((rate != 8000) && (rate != 16000))
+ || (num_channels != 1) ) {
+ LOGD("%s: error wave file:rate = %d, num_channels = %d!! \n",
+ __FUNCTION__,rate, num_channels);
+ return -1;
+ }
+
+ LOGD("%s: success open, rate = %d, num_channels = %d.\n",
+ __FUNCTION__, rate, num_channels);
+
+ if ((8000 == rate) && (1 == num_channels)) {
+ nb_wb = 0;//NB
+ pcxt->pcm_packet_size = 320;
+ } else if ((16000 == rate) && (1 == num_channels)) {
+ nb_wb = 1;//WB
+ pcxt->pcm_packet_size = 640;
+ }
+
+ //config playback parameters.
+ config_parameters_new(in_out, nb_wb);
+ pcxt->device = in_out;
+ return 0;
+}
+
+static void mbtk_audio_set_status_new(void* hdl, mbtk_audio_state_enum _status)
+{
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)hdl;
+ if (NULL == hdl || NULL == internal_hdl)
+ return 0;
+ pthread_mutex_lock(&pcxt->_cond_mutex);
+ pcxt->state = _status;
+ pthread_mutex_unlock(&pcxt->_cond_mutex);
+}
+
+mbtk_audio_handle mbtk_audio_open_new(mbtk_audio_dev_enum dev, int flag, int rate, void *usrData)
+{
+
+ int value = 1;
+ struct mopen_audio_t *aud_hdl = NULL;
+ int ret;
+
+ if(internal_hdl)
+ {
+ printf("Audio device inited\n");
+ return internal_hdl;
+ }
+
+ aud_hdl = (struct mopen_audio_t *) calloc(1, sizeof(struct mopen_audio_t));
+ if (!aud_hdl)
+ {
+ LOGD("\n%s:Failed to allocate audio hdl!, errno=%d\n", __FUNCTION__, errno);
+ return NULL;
+ }
+ memset(aud_hdl, 0, sizeof(struct mopen_audio_t));
+ LOGD("mbtk_audio_open() success aud_hdl:%p\n", aud_hdl);
+
+ //init global variables
+ aud_hdl->audio_ahw_dev_ubus = audio_hal_install();
+ if (aud_hdl->audio_ahw_dev_ubus == NULL) {
+ LOGD("%s: audio_hal_install failed!\n", __FUNCTION__);
+ goto error;
+ }
+
+ ret = audio_open_pcm_new(aud_hdl, flag, rate, dev);
+ if (ret)
+ {
+ LOGD("\n%s: pcm open error, errno=%d\n", __FUNCTION__, errno);
+ goto error;
+ }
+
+ ret = aud_hdl->audio_ahw_dev_ubus->open_output_stream(aud_hdl->audio_ahw_dev_ubus, 0,
+ aud_hdl->audio_ahw_dev_ubus->get_supported_devices(aud_hdl->audio_ahw_dev_ubus),
+ AUDIO_OUTPUT_FLAG_DIRECT, NULL, &aud_hdl->stream_out, 0);
+
+ if (ret < 0) {
+ LOGD("%s: error opening output device. rc = %d\n", __FUNCTION__, ret);
+ goto error;
+ }
+
+ pthread_mutex_init(&aud_hdl->_cond_mutex, NULL);
+ aud_hdl->usrData = usrData;
+ aud_hdl->state = AUDIO_OPEN;
+ /* printf("Mbtk_Audio_Open aud_hdl[%x][%x][%x]\n", aud_hdl, aud_hdl->_mixer_ctl, aud_hdl->_pcm); */
+ internal_hdl = aud_hdl;
+
+ LOGD("mbtk_audio_open() success aud_hdl:%p\n", aud_hdl);
+ return (void *)aud_hdl;
+
+error:
+ value = 0;
+ free(aud_hdl);
+ return NULL;
+}
+
+int mbtk_audio_play_file_new(void *dev_hdl, int file_fd, int offset)
+{
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int first_set = 0;
+ int file_data_sz = 0;
+ int res = 0;
+ int ret;
+
+ char cmd[128] = {0};
+ bool flay_flag = TRUE;
+ int i = 0;
+
+
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+ _play_callback audio_play_cb = (_play_callback)pcxt->usrData;
+ if (NULL == dev_hdl || NULL == internal_hdl)
+ return -1;
+
+
+ LOGD("mbtk_audio_play_file_new() dev_hdl:%p\n", dev_hdl);
+
+ if(AUDIO_RUNNING == pcxt->state)
+ return -2;
+
+ // file_data_sz = mbtk_wav_pcm16Le_check(file_fd);
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+ pthread_exit(NULL);
+ }
+ if(offset)
+ {
+ lseek(file_fd, offset, SEEK_SET);
+ }
+
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_RUNNING);
+ int all_size = 0;
+
+ // system("echo 1 >/sys/class/gpio/gpio19/value");
+ while (pcxt->state != AUDIO_STOP)
+ {
+ res = read(file_fd, data, bufsize);
+ // printf("%s:read : %d bytes\n", __FUNCTION__, res);
+ if(res == 0 || res < 0)
+ {
+ LOGD("read:[%d]", res);
+ break;
+ }
+
+ all_size += res;
+// if (file_data_sz < all_size || file_data_sz == all_size) {
+// printf("aplay size :%d - %d\n", file_data_sz, all_size);
+ // break;
+ // }
+
+ while(AUDIO_PAUSE == pcxt->state)
+ {
+ usleep(80000);
+ audio_play_cb(pcxt, AUD_PLAYER_PAUSE);
+ }
+
+ if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+ {
+ first_set = 1;
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_RUNNING);
+ audio_play_cb(pcxt, AUD_PLAYER_RESUME);
+ }
+
+ ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+ if (ret < 0) {
+ LOGD("%s: error writing (child).\n", __FUNCTION__);
+ audio_play_cb(pcxt, AUD_PLAYER_ERROR);
+ break;
+ } else if (ret < (signed int)pcxt->pcm_packet_size) {
+ LOGD("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+ audio_play_cb(pcxt, AUD_PLAYER_LESSDATA);
+ break;
+ }
+
+ }
+ if (audio_play_cb)
+ audio_play_cb(pcxt, AUD_PLAYER_FINISHED);
+
+ LOGD("file_data_sz :%d - all_size: %d\n", file_data_sz, all_size);
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_OPEN);
+ free(data);
+// system("echo 0 >/sys/class/gpio/gpio19/value");
+
+ return 0;
+}
+
+int mbtk_audio_play_stream_new(void *dev_hdl, const void *pData, int len, int gain )
+{
+ unsigned bufsize = 0;
+ char *data = NULL;
+ int first_set = 0;
+ int res = 0;
+ int ret = 0;
+ int read_size = 0;
+ char *p = (char *)pData;
+
+ char cmd[128] = {0};
+ bool flay_flag = TRUE;
+ int i = 0;
+
+ struct mopen_audio_t *pcxt = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == dev_hdl || NULL == internal_hdl || pData == NULL)
+ return -1;
+
+ LOGD("mbtk_audio_play_stream_new() dev_hdl:%p\n", dev_hdl);
+
+ if(AUDIO_RUNNING == pcxt->state)
+ return -2;
+
+ bufsize = pcxt->pcm_packet_size;
+ data = calloc(1, bufsize);
+ if (!data) {
+ fprintf(stderr, "\n%s:could not allocate %d bytes\n",__FUNCTION__,bufsize);
+ pthread_exit(NULL);
+ }
+
+ if(pcxt->state == AUDIO_OPEN)
+ {
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_RUNNING);
+
+ }
+
+ // system("echo 1 >/sys/class/gpio/gpio19/value");
+ while (pcxt->state != AUDIO_STOP)
+ {
+
+ memcpy(data,p+read_size, bufsize );
+ read_size += bufsize;
+
+ if(read_size > len)
+ {
+ // printf(">[%d]\n", read_size);
+ break;
+ }
+
+ while(AUDIO_PAUSE == pcxt->state)
+ {
+ usleep(80000);
+ }
+
+ if ((0 == first_set || AUDIO_RESUME == pcxt->state))
+ {
+ first_set = 1;
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_RUNNING);
+ }
+
+ ret = pcxt->stream_out->write(pcxt->stream_out, data, bufsize);
+ if (ret < 0) {
+ LOGD("%s: error writing (child).\n", __FUNCTION__);
+ break;
+ } else if (ret < (signed int)pcxt->pcm_packet_size) {
+ LOGD("%s: wrote less than buffer size, rc=%d.\n", __FUNCTION__, ret);
+ break;
+ }
+
+ if(read_size == len)
+ {
+ // printf("=[%d]", read_size);
+ break;
+ }
+
+ i++;
+ if(i == 3) // 该值可以自行调节
+ {
+ if(flay_flag && gain != 50)
+ {
+ sprintf(cmd, "ubus call audio_if config_dspgain \"{\'type\':1, \'gain\':%d}\"", gain);
+ system(cmd);
+
+ flay_flag = FALSE;
+ usleep(80000);
+ }
+ }
+
+ }
+
+ if(pcxt->state != AUDIO_STOP)
+ {
+ mbtk_audio_set_status_new(dev_hdl, AUDIO_OPEN);
+ }
+ // system("echo 0 >/sys/class/gpio/gpio19/value");
+ free(data);
+ return 0;
+}
+
+int mbtk_audio_close_new(void *dev_hdl)
+{
+ LOGD("mbtk_audio_close()\n");
+ int value = 0;
+ struct mopen_audio_t *_hdl = (struct mopen_audio_t *)dev_hdl;
+
+ if (NULL == _hdl || NULL == internal_hdl )
+ {
+ LOGD("mbtk_audio_close() fail dev_hdl is NULL\n");
+ return -1;
+ }
+
+ mbtk_audio_set_status_new(_hdl, AUDIO_STOP);
+
+ vcm_playback_drain(0);//wait for drain the AP audiostub queue.
+ usleep(80000);//delay 80ms until DSP play out its buffered data.
+ _hdl->stream_out->common.standby(&_hdl->stream_out->common);
+ _hdl->audio_ahw_dev_ubus->close_output_stream(_hdl->audio_ahw_dev_ubus, _hdl->stream_out);
+
+ audio_hal_uninstall();
+ pthread_mutex_destroy(&_hdl->_cond_mutex);
+ free(_hdl);
+ _hdl = NULL;
+ internal_hdl = NULL;
+
+ return 0;
+}
+
+void mbtk_audio_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_audio_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/audio/mbtk_wav.c b/mbtk/libmbtk_lib/audio/mbtk_wav.c
new file mode 100755
index 0000000..f2e104c
--- /dev/null
+++ b/mbtk/libmbtk_lib/audio/mbtk_wav.c
@@ -0,0 +1,409 @@
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "mbtk_log.h"
+#include "mbtk_audio_internal.h"
+
+#define WAV_PLAY_BUFF 2048
+
+typedef struct {
+ const unsigned char *pcm_data;
+ int data_size;
+} audio_buff_t;
+
+static int wav_play_fd = -1;
+static audio_play_state_enum play_state = AUDIO_PLAY_STATE_STOP;
+static pthread_cond_t play_cond;
+static pthread_mutex_t play_mutex;
+static pthread_t play_thread_play;
+
+static int wav_recorder_fd = -1;
+static struct wav_header recorder_header;
+static uint32 recorver_data_count = 0;
+
+static audio_buff_t audio_buff;
+
+static void audio_play_thread(void *arg)
+{
+ int rc, len, frames = 0;
+ char buf[WAV_PLAY_BUFF];
+
+ play_state = AUDIO_PLAY_STATE_RUNNING;
+ pthread_mutex_init(&play_mutex, NULL);
+ pthread_cond_init(&play_cond, NULL);
+
+ int data_send = 0;
+ while (TRUE) {
+ /* Playback loop */
+ pthread_mutex_lock(&play_mutex);
+ if(play_state == AUDIO_PLAY_STATE_STOP) {
+ LOGD("Stop play...");
+ pthread_mutex_unlock(&play_mutex);
+ break;
+ } else if(play_state == AUDIO_PLAY_STATE_PAUSE) {
+ pthread_cond_wait(&play_cond, &play_mutex);
+ pthread_mutex_unlock(&play_mutex);
+ continue;
+ } else {
+ pthread_mutex_unlock(&play_mutex);
+ }
+
+ memset(buf, 0x00, sizeof(buf));
+ if(wav_play_fd > 0) { // Play file.
+ len = read(wav_play_fd, buf, WAV_PLAY_BUFF);
+ if (len == -1) {
+ LOGE("%s: error reading from file", __FUNCTION__);
+ goto thread_end;
+ }
+
+ if (len == 0) {
+ /* reached EOF */
+ LOGE("%s: Read wav file end.", __FUNCTION__);
+ break;
+ }
+ } else { // Play buffer.
+ if(data_send >= audio_buff.data_size) {
+ /* reached EOF */
+ LOGE("%s: Read buffer end.", __FUNCTION__);
+ break;
+ }
+ if(audio_buff.data_size - data_send >= WAV_PLAY_BUFF) {
+ memcpy(buf, audio_buff.pcm_data + data_send, WAV_PLAY_BUFF);
+ len = WAV_PLAY_BUFF;
+ } else {
+ memcpy(buf, audio_buff.pcm_data + data_send, audio_buff.data_size - data_send);
+ len = audio_buff.data_size - data_send;
+ }
+ data_send += len;
+ }
+
+ if((rc = mbtk_audio_pcm_play_data_send(buf, len)) < len) {
+ LOGE("Send data %d/%d", rc, len);
+ goto thread_end;
+ }
+
+ LOGD("%s: No.%d frame playback", __FUNCTION__, ++frames);
+ }
+
+ play_state = AUDIO_PLAY_STATE_STOP;
+
+thread_end:
+ pthread_mutex_destroy(&play_mutex);
+ pthread_cond_destroy(&play_cond);
+ mbtk_audio_pcm_play_stop();
+
+ if(wav_play_fd > 0) {
+ if (close(wav_play_fd))
+ LOGE("%s: error closing file", __FUNCTION__);
+ }
+
+ wav_play_fd = -1;
+ LOGD("%s: finished pcm playback.", __FUNCTION__);
+ return;
+}
+
+static void audio_recorder_cb(void *data, uint32 data_len)
+{
+ if(data_len > 0) {
+ LOGD("Recorver data:%d, count:%d", data_len, recorver_data_count);
+ if (write(wav_recorder_fd, data, data_len) < data_len) {
+ LOGE("%s: error writing to file!", __FUNCTION__);
+ }
+ recorver_data_count += data_len;
+ } else {
+ LOGD("Recorver data end.");
+ recorder_header.data_sz = recorver_data_count;
+ recorder_header.riff_sz = recorder_header.data_sz + sizeof(recorder_header) - 8;
+ lseek(wav_recorder_fd, 0, SEEK_SET);
+ write(wav_recorder_fd, &recorder_header, sizeof(struct wav_header));
+
+ close(wav_recorder_fd);
+ wav_recorder_fd = -1;
+ }
+}
+
+int mbtk_audio_wav_init()
+{
+ //mbtk_log_init("radio", "MBTK_AUDIO");
+ return mbtk_audio_pcm_init();
+}
+
+int mbtk_audio_wav_play_start(const void *wav_file)
+{
+ struct stat st;
+ const char *path = (const char *)wav_file;
+ struct riff_wave_header riff_wave_header;
+ struct chunk_header chunk_header;
+ struct chunk_fmt chunk_fmt = {0};
+ unsigned int more_chunks = 1;
+
+ if(play_state != AUDIO_PLAY_STATE_STOP) {
+ LOGW("Audio is playing...");
+ return -1;
+ }
+
+ /* Check and open source file */
+ if (access(path, F_OK) || stat(path, &st)) {
+ LOGE("%s: error reading from file %s", __FUNCTION__, path);
+ return -1;
+ }
+
+ if (!st.st_size) {
+ LOGE("%s: empty file %s", __FUNCTION__, path);
+ return -1;
+ }
+
+ wav_play_fd = open(path, O_RDONLY);
+ if (wav_play_fd < 0) {
+ LOGE("%s: error opening file %s", __FUNCTION__, path);
+ return -1;
+ }
+
+ read(wav_play_fd, &riff_wave_header, sizeof(riff_wave_header));
+ if ((riff_wave_header.riff_id != ID_RIFF) || (riff_wave_header.wave_id != ID_WAVE)) {
+ LOGE("Error: '%s' is not a riff/wave file", path);
+ close(wav_play_fd);
+ return -1;
+ }
+
+ do {
+ read(wav_play_fd, &chunk_header, sizeof(chunk_header));
+
+ switch (chunk_header.id) {
+ case ID_FMT:
+ read(wav_play_fd, &chunk_fmt, sizeof(chunk_fmt));
+ /* If the format header is larger, skip the rest */
+ if (chunk_header.sz > sizeof(chunk_fmt))
+ lseek(wav_play_fd, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
+ break;
+ case ID_DATA:
+ /* Stop looking for chunks */
+ more_chunks = 0;
+ break;
+ default:
+ /* Unknown chunk, skip bytes */
+ lseek(wav_play_fd, chunk_header.sz, SEEK_CUR);
+ }
+ } while (more_chunks);
+
+ //Support 8k/16k & mono wave file
+ if (((chunk_fmt.sample_rate != 8000) && (chunk_fmt.sample_rate != 16000))
+ || (chunk_fmt.num_channels != 1) ) {
+ LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
+ __FUNCTION__,chunk_fmt.sample_rate, chunk_fmt.num_channels);
+ close(wav_play_fd);
+ return -1;
+ }
+
+ LOGE("%s: success open wave file:%s, sample_rate = %d, num_channels = %d.",
+ __FUNCTION__, path, chunk_fmt.sample_rate, chunk_fmt.num_channels);
+
+ if ((8000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
+ mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
+ } else if ((16000 == chunk_fmt.sample_rate) && (1 == chunk_fmt.num_channels)) {
+ mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
+ }
+
+ if (mbtk_audio_pcm_play_start()) {
+ LOGE("%s: error opening output device.", __FUNCTION__);
+ return -1;
+ }
+
+ LOGD("Start play wav file...");
+
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+ {
+ LOGE("pthread_attr_setdetachstate() fail.");
+ return -1;
+ }
+
+ if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
+ LOGE("%s: error creating thread_play!", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+int mbtk_audio_wav_stream_play_start(const unsigned char *pcm_data, int data_size, int sample_rate, int num_channels)
+{
+ if(play_state != AUDIO_PLAY_STATE_STOP) {
+ LOGW("Audio is playing...");
+ return -1;
+ }
+
+ //Support 8k/16k & mono wave file
+ if (((sample_rate != 8000) && (sample_rate != 16000))
+ || (num_channels != 1) ) {
+ LOGD("%s: error wave file:sample_rate = %d, num_channels = %d!!",
+ __FUNCTION__,sample_rate, num_channels);
+ return -1;
+ }
+
+ LOGE("%s: success open wave stream, sample_rate = %d, num_channels = %d.",
+ __FUNCTION__, sample_rate, num_channels);
+
+ if ((8000 == sample_rate) && (1 == num_channels)) {
+ mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_8000);
+ } else if ((16000 == sample_rate) && (1 == num_channels)) {
+ mbtk_audio_pcm_sample_rate_set(MBTK_AUDIO_SAMPLE_RATE_16000);
+ }
+
+ if (mbtk_audio_pcm_play_start()) {
+ LOGE("%s: error opening output device.", __FUNCTION__);
+ return -1;
+ }
+
+ audio_buff.pcm_data = pcm_data;
+ audio_buff.data_size = data_size;
+ LOGD("Start play wav stream...");
+
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+ {
+ LOGE("pthread_attr_setdetachstate() fail.");
+ return -1;
+ }
+
+ if (pthread_create(&play_thread_play, NULL, (void *)&audio_play_thread, NULL) < 0) {
+ LOGE("%s: error creating thread_play!", __FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int mbtk_audio_wav_play_pause()
+{
+ int result = 0;
+ pthread_mutex_lock(&play_mutex);
+ if(play_state == AUDIO_PLAY_STATE_RUNNING) {
+ play_state = AUDIO_PLAY_STATE_PAUSE;
+ } else {
+ // result = -1;
+ LOGW("Audio state : %d", play_state);
+ }
+ pthread_mutex_unlock(&play_mutex);
+ return result;
+}
+
+int mbtk_audio_wav_play_resume()
+{
+ int result = 0;
+ pthread_mutex_lock(&play_mutex);
+ if(play_state == AUDIO_PLAY_STATE_PAUSE) {
+ play_state = AUDIO_PLAY_STATE_RUNNING;
+ pthread_cond_signal(&play_cond);
+ } else {
+ // result = -1;
+ LOGW("Audio state : %d", play_state);
+ }
+ pthread_mutex_unlock(&play_mutex);
+ return result;
+}
+
+
+int mbtk_audio_wav_play_stop()
+{
+ int result = 0;
+ pthread_mutex_lock(&play_mutex);
+ if(play_state == AUDIO_PLAY_STATE_PAUSE || play_state == AUDIO_PLAY_STATE_RUNNING) {
+ if(play_state == AUDIO_PLAY_STATE_PAUSE) {
+ pthread_cond_signal(&play_cond);
+ }
+ play_state = AUDIO_PLAY_STATE_STOP;
+ pthread_mutex_unlock(&play_mutex);
+
+ LOGD("Waitting play thread exit...");
+ if (pthread_join(play_thread_play, NULL)) {
+ LOGE("error join thread_play!");
+ // abort();
+ }
+ LOGD("Play thread exit success.");
+ } else {
+ pthread_mutex_unlock(&play_mutex);
+ // result = -1;
+ LOGW("Audio state : %d", play_state);
+ }
+
+ return result;
+}
+
+int mbtk_audio_wav_recorder_start(const void *wav_file, mbtk_audio_sample_rate_enum sample_rate)
+{
+ int rc;
+ const char *path = (const char *)wav_file;
+
+ LOGD("wav_file is %s.", path);
+ if(wav_recorder_fd > 0) {
+ LOGW("Audio is recorder...");
+ }
+
+ memset(&recorder_header, 0x0, sizeof(struct wav_header));
+ recorder_header.riff_id = ID_RIFF;
+ recorder_header.riff_sz = 0;
+ recorder_header.riff_fmt = ID_WAVE;
+ recorder_header.fmt_id = ID_FMT;
+ recorder_header.fmt_sz = 16;
+ recorder_header.audio_format = 1; //FORMAT_PCM;
+ recorder_header.num_channels = 1; //Modem ONLY support mono recording
+ recorder_header.sample_rate = (sample_rate == MBTK_AUDIO_SAMPLE_RATE_8000 ? 8000 : 16000);
+ recorder_header.bits_per_sample = 16; //PCM_SAMPLEBITS_S16_LE;
+ recorder_header.byte_rate = (recorder_header.bits_per_sample / 8) * recorder_header.num_channels * recorder_header.sample_rate;
+ recorder_header.block_align = recorder_header.num_channels * (recorder_header.bits_per_sample / 8);
+ recorder_header.data_id = ID_DATA;
+
+ mbtk_audio_pcm_sample_rate_set(sample_rate);
+
+ wav_recorder_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+ if (wav_recorder_fd < 0) {
+ LOGE("%s: error opening file %s!", __FUNCTION__, path);
+ return -1;
+ }
+
+ //leave enough room for header
+ lseek(wav_recorder_fd, sizeof(struct wav_header), SEEK_SET);
+
+ recorver_data_count = 0;
+
+ return mbtk_audio_pcm_recorder_start(audio_recorder_cb);
+}
+
+int mbtk_audio_wav_recorder_pause()
+{
+ return mbtk_audio_pcm_recorder_pause();
+}
+
+int mbtk_audio_wav_recorder_resume()
+{
+ return mbtk_audio_pcm_recorder_resume();
+}
+
+
+int mbtk_audio_wav_recorder_stop()
+{
+ return mbtk_audio_pcm_recorder_stop();
+}
+
+int mbtk_audio_wav_deinit()
+{
+ if(play_state != AUDIO_PLAY_STATE_STOP) {
+ if(mbtk_audio_wav_play_stop()) {
+ LOGE("mbtk_audio_wav_play_stop() fail.");
+ }
+ }
+
+ if(wav_recorder_fd > 0) {
+ mbtk_audio_wav_recorder_stop();
+ }
+
+ return mbtk_audio_pcm_deinit();
+}
+
diff --git a/mbtk/libmbtk_lib/coap/mbtk_coap.c b/mbtk/libmbtk_lib/coap/mbtk_coap.c
new file mode 100755
index 0000000..226fd5c
--- /dev/null
+++ b/mbtk/libmbtk_lib/coap/mbtk_coap.c
@@ -0,0 +1,1385 @@
+/*************************************************************
+Description:
+ C file for L620 coap.
+Author:
+ LuoJian
+Date:
+ 2019/3/25 9:23:29
+*************************************************************/
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/in.h>
+#include <unistd.h>
+
+#include "mbtk_coap.h"
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_sock2.h"
+
+
+/*************************************************************
+ Variables:public
+*************************************************************/
+
+
+#define MBTK_ECOAP_TIMEOUT (15 * 1000)
+#define MBTK_ECOAP_WAIT_CLOSE_TIMEOUT (5 * 60 * 1000)
+#define MBTK_ECOAP_STACK_SIZE (12 * 1024) // task stack size
+
+#define ECOAPVER 1
+#define EOCAPTYPE 2
+#define ECOAPCODE 3
+#define ECOAPMSGID 4
+#define ECOAPTOKEN 5
+
+
+/*param--------------------*/
+// Point the first item.
+static mbtk_ecoap_package_s *mbtk_ecoap_head = NULL;
+static mbtk_ecoap_package_ver mbth_ecoap_package_ver={1,0,1,1};
+
+
+struct sockaddr_in serveraddr = {0};
+int socket_id;
+int addrlen;
+
+static mbtk_init_info *coap_init_info = NULL;
+static int coap_handle = -1;
+static bool coap_sock_inited = FALSE;
+static int coap_fd = -1;
+
+
+
+// Point the last item.
+static mbtk_ecoap_package_s *mbtk_ecoap_tail = NULL;
+static mbtk_ecoap_net_s mbtk_ecoap_net;
+static mbtk_ecoap_state_e mbtk_ecoap_state = MBTK_ECOAP_STATE_NON;
+
+//static uint16 mbtk_ecoap_curr_coap_id = 0;
+static char mbtk_ecoap_host[MBTK_ECOAP_NEW_MAX+1] = {'\0'};
+
+static int mbtk_ecoap_port;
+static int mbtk_ecoap_is_dtls;
+static mbtk_ecoap_opt_2 mbtk_ecoap_option_2;
+static mbtk_ecoap_opt_3 mbtk_ecoap_option_3;
+static int mbtk_ecoap_recv = -1;
+static int mbtk_ecoap_cur_time =0;
+
+/*func------------------------*/
+void mbtk_ecoap_option_add(mbtk_ecoap_option_s *option);
+int mbtk_ecoap_list_del(uint16 message_id,int optDel);
+
+
+#define HEXCHAR(x) ((x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F'))
+
+
+#if 1
+
+#define toupper(a) ((((a) >= 'a') && ((a) <= 'z')) ? ((a) - 'a' + 'A') : (a))
+
+void HexToStr(byte *pbDest, byte *pbSrc, int nLen)
+{
+ char ddl,ddh;
+ int i;
+
+ for (i=0; i<nLen; i++)
+ {
+ ddh = 48 + pbSrc[i] / 16;
+ ddl = 48 + pbSrc[i] % 16;
+ if (ddh > 57)
+ {
+ ddh = ddh + 7;
+ }
+ if (ddl > 57)
+ {
+ ddl = ddl + 7;
+ }
+ pbDest[i*2] = ddh;
+ pbDest[i*2+1] = ddl;
+ }
+ pbDest[nLen*2] = '\0';
+}
+
+uint8_t StrToHex(byte *pbDest, byte *pbSrc, int nLen)
+{
+ char h1,h2;
+ byte s1,s2;
+ uint8_t i;
+
+ for (i=0; i<nLen; i++)
+ {
+ h1 = pbSrc[2*i];
+ h2 = pbSrc[2*i+1];
+ s1 = toupper(h1) - 0x30;
+ if (s1 > 9)
+ {
+ s1 -= 7;
+ }
+ s2 = toupper(h2) - 0x30;
+ if (s2 > 9)
+ {
+ s2 -= 7;
+ }
+ pbDest[i] = s1*16 + s2;
+ //DS_MBTK_MSG1_HIGH("StrToHex:%.2X",pbDest[i]);
+ }
+ return i;
+}
+
+void coap_log(int is_ascii,const char* data,int len)
+{
+ if(len <= 0) {
+ return;
+ }
+
+ if(is_ascii) { // Is ASCII
+ int i = 0;
+ int count = len / 100 + 1;
+
+ // Has '\0'
+ if(len != strlen(data)) {
+ return;
+ }
+
+ while(i < count) {
+ printf("%s\n",data + i * 100);
+ i++;
+ }
+ } else { // Is hex
+ int index = 0;
+ int i = 0;
+ char buf_temp[100];
+ while(index % 16 == 0 && index < len) {
+ memset(buf_temp,0,100);
+ for(i = 0;i < 16 && index + i < len;i++) {
+ snprintf(buf_temp + i * 3,100 - i,"%.2x ",((char*)data)[index + i]);
+ }
+ index += 16;
+ printf("%s\n", buf_temp);
+ }
+ }
+}
+
+
+
+static void
+mbtk_ecoap_show_error
+(
+ int rsp_errno
+)
+{
+ char temp[50] = {0};
+ memset(temp, 0, 50);
+ snprintf(temp,50,"\r\n+MCOAPERROR:%d\r\n",rsp_errno);
+ printf("%s\n",temp);
+}
+
+int ecoap_recv_buffer(char * dest,const char* data,int len)
+{
+ if( len <= 0) {
+ return -1;
+ }
+ int buffer_len = 0;
+ char Payload[MBTK_ECOAP_DATA_MAX*2+1] ={'\0'};
+ int pud_lenth = mbtk_coap_get_pdu_Length();
+ int type = mbtk_ecoap_get_message_type();
+ char code[12];
+ memset(code,0x00,sizeof(code));
+ mbtk_ecoap_get_code(code);
+ uint16_t mesageId = coapGetRecvMessageID();
+ memset(Payload,0x00,MBTK_ECOAP_DATA_MAX*2+1);
+ snprintf(dest,MBTK_ECOAP_DATA_MAX,
+ "+COAPNMI:%d\r\nMessage Type:%d\r\nCode:\"%s\"\r\nMessage ID:%d\r\nPayload:",
+ pud_lenth,
+ type,
+ code,
+ mesageId);
+
+
+ int i = 0;
+ for(i = 0; i < len; i++)
+ {
+ if(data[i] == 0xFF && i> 3) //BUG 46397
+ {
+ LOGE("data[i] == 0xFF\n");
+ memcpy(Payload, data+i+1, len - i-1);
+ Payload[len-i -1]='\0';
+ break;
+ }
+ }
+
+ LOGE("len:%d, i :%d\n",len,i);
+ if(Payload[len-i -1] == '\0' )
+ {
+ LOGE("==\0-------------------\n");
+ // coap_log(-1,(char*)Payload,len - i-1);
+ }else{
+ LOGE("!=\0--------------------\n");
+ Payload[0]='\0';
+ }
+
+ buffer_len = strlen(dest) + strlen(Payload);
+ strcat(dest,Payload);
+ LOGE("2---------buffer_len:%d,coap_recv_buffer_dest:%s,Payload:%s\n",buffer_len,dest,Payload);
+ return buffer_len;
+}
+
+int mbtk_ecoap_get_message_type(void)
+{
+ switch(coapGetRecvType())
+ {
+ case COAP_CONFIRMABLE:
+ return 0;
+ break;
+
+ case COAP_NON_CONFIRMABLE:
+ return 1;
+ break;
+
+ case COAP_ACKNOWLEDGEMENT:
+ return 2;
+ break;
+
+ case COAP_RESET:
+ return 3;
+ break;
+ }
+ return 0;
+}
+
+void mbtk_ecoap_get_code(char *ptr)
+{
+ switch(coapGetRecvCode()) {
+ case COAP_EMPTY:
+ memcpy(ptr,"0.00",4);
+ break;
+ case COAP_GET:
+ memcpy(ptr,"0.01",4);
+ break;
+ case COAP_POST:
+ memcpy(ptr,"0.02",4);
+ break;
+ case COAP_PUT:
+ memcpy(ptr,"0.03",4);
+ break;
+ case COAP_DELETE:
+ memcpy(ptr,"0.04",4);
+ break;
+ case COAP_CREATED:
+ memcpy(ptr,"2.01",4);
+ break;
+ case COAP_DELETED:
+ memcpy(ptr,"2.02",4);
+ break;
+ case COAP_VALID:
+ memcpy(ptr,"2.03",4);
+ break;
+ case COAP_CHANGED:
+ memcpy(ptr,"2.04",4);
+ break;
+ case COAP_CONTENT:
+ memcpy(ptr,"2.05",4);
+ break;
+ case COAP_CONTINUE:
+ memcpy(ptr,"2.31",4);
+ break;
+ case COAP_BAD_REQUEST:
+ memcpy(ptr,"4.00",4);
+ break;
+ case COAP_UNAUTHORIZED:
+ memcpy(ptr,"4.01",4);
+ break;
+ case COAP_BAD_OPTION:
+ memcpy(ptr,"4.02",4);
+ break;
+ case COAP_FORBIDDEN:
+ memcpy(ptr,"4.03",4);
+ break;
+ case COAP_NOT_FOUND:
+ memcpy(ptr,"4.04",4);
+ break;
+ case COAP_METHOD_NOT_ALLOWED:
+ memcpy(ptr,"4.05",4);
+ break;
+ case COAP_NOT_ACCEPTABLE:
+ memcpy(ptr,"4.06",4);
+ break;
+ case COAP_PRECONDITION_FAILED:
+ memcpy(ptr,"4.12",4);
+ break;
+ case COAP_REQUEST_ENTITY_TOO_LARGE:
+ memcpy(ptr,"4.13",4);
+ break;
+ case COAP_UNSUPPORTED_CONTENT_FORMAT:
+ memcpy(ptr,"4.15",4);
+ break;
+ case COAP_INTERNAL_SERVER_ERROR:
+ memcpy(ptr,"5.00 ",4);
+ break;
+ case COAP_NOT_IMPLEMENTED:
+ memcpy(ptr,"5.01",4);
+ break;
+ case COAP_BAD_GATEWAY:
+ memcpy(ptr,"5.02",4);
+ break;
+ case COAP_SERVICE_UNAVAILABLE:
+ memcpy(ptr,"5.03",4);
+ break;
+ case COAP_GATEWAY_TIMEOUT:
+ memcpy(ptr,"5.04",4);
+ break;
+ case COAP_PROXYING_NOT_SUPPORTED:
+ memcpy(ptr,"5.05",4);
+ break;
+ default:
+ sprintf(ptr, "UndefCod%u",(unsigned)(coapGetRecvCode()));
+ }
+}
+
+
+static int
+mbtk_ecoap_is_open()
+{
+ if(mbtk_ecoap_state >= MBTK_ECOAP_STATE_OPENED)
+ return 0;
+
+ return -1;
+}
+
+
+static void mbtk_ecoap_reset()
+{
+ memset(&mbtk_ecoap_net,0x0,sizeof(mbtk_ecoap_net_s));
+ mbtk_ecoap_net.message_id = 1; //change mbtk_ecoap_net.message_id = 0;
+ memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));
+ memset(&mbth_ecoap_package_ver, 0x0,sizeof(mbtk_ecoap_package_ver));
+ mbth_ecoap_package_ver.version = 1;
+ mbth_ecoap_package_ver.type = 0;
+ mbth_ecoap_package_ver.code = 1;
+ mbth_ecoap_package_ver.message_id = 1;
+ mbtk_ecoap_recv = -1;
+
+ mbtk_ecoap_package_s *coap = mbtk_ecoap_head;
+ mbtk_ecoap_package_s *coap_next = NULL;
+ mbtk_ecoap_option_s * option_ptr = NULL;
+ mbtk_ecoap_option_s * option_ptr_next = NULL;
+
+ while(coap != NULL)
+ {
+ coap_next = coap->next;
+ if(coap->payload != NULL)
+ free(coap->payload);
+
+ if(coap->options != NULL)
+ {
+ option_ptr = coap->options;
+ while(option_ptr != NULL)
+ {
+ option_ptr_next = option_ptr->next;
+ free(option_ptr);
+ option_ptr = NULL;
+ option_ptr = option_ptr_next;
+ }
+
+ }
+
+ free(coap);
+ coap = NULL;
+ coap = coap_next;
+
+ }
+
+ mbtk_ecoap_head = mbtk_ecoap_tail = NULL;
+}
+
+
+static void mbtk_ecoap_close()
+{
+
+}
+
+
+
+
+
+mbtk_ecoap_package_s *mbtk_ecoap_get_by_msg_id(uint16 message_id)
+{
+ if(mbtk_ecoap_head == NULL)
+ {
+ }
+ else
+ {
+ mbtk_ecoap_package_s *coap_ptr = mbtk_ecoap_head;
+ while(coap_ptr != NULL)
+ {
+ if(coap_ptr->message_id == message_id)
+ {
+ return coap_ptr;;
+ }
+ coap_ptr = coap_ptr->next;
+ }
+ }
+ return NULL;
+}
+
+static void mbtk_ecoap_list_item_init(unsigned int sig,mbtk_ecoap_package_s *coap,uint16 message_id)
+{
+ switch(sig)
+ {
+ case ECOAPVER:
+ coap->version = message_id;
+ break;
+ case EOCAPTYPE:
+ coap->type = message_id;
+ break;
+ case ECOAPCODE:
+ coap->code = message_id;
+ break;
+ case ECOAPMSGID:
+ coap->message_id = message_id;
+ break;
+ case ECOAPTOKEN:
+ coap->token_len = message_id;
+ break;
+ default:
+ break;
+ }
+ coap->next = NULL; //change delete this code
+}
+
+
+mbtk_ecoap_package_s* mbtk_ecoap_list_add(uint16 message_id)
+{
+ LOGE("mbtk_ecoap_list_add-----memssage_id:%d\n",message_id);
+ if(mbtk_ecoap_head == NULL)
+ {
+ mbtk_ecoap_head = (mbtk_ecoap_package_s*)malloc(sizeof(mbtk_ecoap_package_s));
+ memset(mbtk_ecoap_head, 0,sizeof(mbtk_ecoap_package_s));
+ mbtk_ecoap_list_item_init(ECOAPMSGID,mbtk_ecoap_head,message_id);
+ mbtk_ecoap_tail = mbtk_ecoap_head;
+ return mbtk_ecoap_head;
+ }
+ else
+ {
+ mbtk_ecoap_package_s *coap_ptr = mbtk_ecoap_head;
+ while(coap_ptr != NULL)
+ {
+ if(coap_ptr->message_id == message_id)
+ {
+ printf("Coap %d exist.\n",message_id);
+ return NULL;
+ }
+ coap_ptr = coap_ptr->next;
+ }
+ mbtk_ecoap_tail->next = (mbtk_ecoap_package_s*)malloc(sizeof(mbtk_ecoap_package_s));
+ mbtk_ecoap_list_item_init(ECOAPMSGID,mbtk_ecoap_tail->next,message_id);
+ mbtk_ecoap_tail = mbtk_ecoap_tail->next;
+ return mbtk_ecoap_tail;
+ }
+}
+
+static void mbtk_ecoap_free(mbtk_ecoap_package_s *coap)
+{
+ if(coap != NULL)
+ {
+ if(coap->payload != NULL)
+ free(coap->payload);
+
+ if(coap->options != NULL)
+ {
+ mbtk_ecoap_option_s *option_ptr = coap->options;
+ while(option_ptr != NULL)
+ {
+ free(option_ptr);
+ option_ptr = option_ptr->next;
+ }
+ }
+
+ free(coap);
+ coap = NULL;
+ }
+}
+
+int mbtk_ecoap_list_del(uint16 message_id,int optDel)
+{
+ LOGE("mbtk_ecoap_list_del:message_id:%d\n",message_id);
+ if(mbtk_ecoap_head == NULL)
+ {
+ printf("mbtk_ecoap_head == NULL\n");
+ return -1;
+ }
+
+ mbtk_ecoap_recv = -1;
+ if(optDel)
+ {
+ memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));
+ memset(&mbtk_ecoap_option_3, 0x0, sizeof(mbtk_ecoap_opt_3));
+ memset(&mbth_ecoap_package_ver,0x0,sizeof(mbth_ecoap_package_ver));
+ mbth_ecoap_package_ver.version = 1;
+ mbth_ecoap_package_ver.type = 0;
+ mbth_ecoap_package_ver.code = 1;
+ mbth_ecoap_package_ver.message_id = 1;
+ }
+ mbtk_ecoap_package_s *coap = mbtk_ecoap_head;
+ if(mbtk_ecoap_head->message_id == message_id) // Is first item.
+ {
+ mbtk_ecoap_head = mbtk_ecoap_head->next;
+
+ mbtk_ecoap_free(coap);
+ return 0;
+ }
+ else // Not first item.
+ {
+ while(coap->next != NULL)
+ {
+ if(message_id == coap->next->message_id) // delete
+ {
+ mbtk_ecoap_package_s *coap_tmp = coap->next;
+ if(mbtk_ecoap_tail == coap_tmp)
+ {
+ mbtk_ecoap_tail = coap;
+ }
+ coap->next = coap_tmp->next;
+ mbtk_ecoap_free(coap_tmp);
+ return 0;;
+ }
+ coap = coap->next;
+ }
+ return -1;
+ }
+}
+
+void mbtk_ecoap_option_add(mbtk_ecoap_option_s *option)
+{
+ if(option != NULL)
+ {
+ switch(option->type)
+ {
+ case COAP_OPTION_IF_MATCH:
+ case COAP_OPTION_URI_HOST:
+ case COAP_OPTION_ETAG:
+ case COAP_OPTION_IF_NONE_MATCH:
+ case COAP_OPTION_LOCATION_PATH:
+ case COAP_OPTION_LOCATION_QUERY:
+ case COAP_OPTION_PROXY_URI:
+ case COAP_OPTION_PROXY_SCHEME:
+ case COAP_OPTION_URI_PORT:
+ case COAP_OPTION_ACCEPT:
+ case COAP_OPTION_SIZE2:
+ case COAP_OPTION_SIZE1:
+ {
+ break;
+ }
+ case COAP_OPTION_BLOCK2:
+ case COAP_OPTION_BLOCK1:
+ {
+ LOGE("option->opt.opt_block.number = %d\n",option->opt.opt_block.number);
+ if(option->opt.opt_block.number <= 0x0F)
+ {
+ uint8_t temp[1];
+ temp[0] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)
+ | ((option->opt.opt_block.more_flag << 3) & 0x08)
+ | (option->opt.opt_block.size & 0x07));
+ coapAddOption(option->type,1,temp);
+ }
+ else if(option->opt.opt_block.number <= 0x0FFF)
+ {
+ uint8_t temp[2];
+ temp[0] = (uint8_t)(option->opt.opt_block.number >> 4);
+ temp[1] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)
+ | ((option->opt.opt_block.more_flag << 3) & 0x08)
+ | (option->opt.opt_block.size & 0x07));
+ coapAddOption(option->type,2,temp);
+
+ }
+ else
+ {
+ uint8_t temp[3];
+ temp[0] = (uint8_t)(option->opt.opt_block.number >> 12);
+ temp[1] = (uint8_t)(option->opt.opt_block.number >> 4);
+ temp[2] = (uint8_t)(((option->opt.opt_block.number << 4) & 0xF0)
+ | ((option->opt.opt_block.more_flag << 3) & 0x08)
+ | (option->opt.opt_block.size & 0x07));
+ coapAddOption(option->type,3,temp);
+
+ }
+ break;
+ }
+ case COAP_OPTION_MAX_AGE:
+ {
+ uint8_t temp[1];
+ temp[0] = (uint8_t)option->opt.opt_int;
+ coapAddOption(option->type,1,temp);
+ break;
+ }
+ case COAP_OPTION_OBSERVE:
+ {
+ uint8_t temp[1];
+ temp[0] = (uint8_t)option->opt.opt_int;
+ coapAddOption(option->type,1,temp);
+ break;
+ }
+ case COAP_OPTION_URI_QUERY:
+ {
+ coapAddURIQuery((char*)option->opt.opt_str);
+ break;
+ }
+ case COAP_OPTION_URI_PATH:
+ {
+ coapSetURI((char*)option->opt.opt_str);
+ break;
+ }
+ case COAP_OPTION_CONTENT_FORMAT:
+ {
+ coapSetContentFormat(option->opt.opt_content_format);
+ break;
+ }
+ default:
+ printf("No such type:%s\n",option->type);
+ break;
+ }
+ }
+}
+
+static void mbtk_ecoap_set_option(mbtk_ecoap_package_s *coap,
+ mbtk_coap_option_type type,void *str,
+ int int0,int int1,int int2)
+{
+ if(coap != NULL)
+ {
+/* if(coap->options == NULL)
+ {
+ coap->options = (mbtk_ecoap_option_s*)malloc(sizeof(mbtk_ecoap_option_s));
+ memset(coap->options,0x0,sizeof(mbtk_ecoap_option_s));
+ coap->options->type = type;
+ coap->options->next = NULL;
+ }
+*/
+ mbtk_ecoap_option_s *option = coap->options;
+ while(option != NULL)
+ {
+ LOGE("1option != NULL\n");
+ if(option->type == type)
+ {
+ break;
+ }
+ option = option->next;
+ }
+
+ LOGE("----------------------\n");
+ if(option == NULL) // Now option
+ {
+ LOGE("option == NULL\n");
+ option = (mbtk_ecoap_option_s*)malloc(sizeof(mbtk_ecoap_option_s));
+ memset(option,0x0,sizeof(mbtk_ecoap_option_s));
+// option->type = type;
+
+ option->next = coap->options;
+ coap->options = option;
+ option->type = type;
+ }
+ else // Change option
+ {
+ // Do noting.
+ }
+
+ switch(type)
+ {
+ case COAP_OPTION_IF_MATCH:
+ case COAP_OPTION_URI_HOST:
+ case COAP_OPTION_ETAG:
+ case COAP_OPTION_IF_NONE_MATCH:
+ case COAP_OPTION_LOCATION_PATH:
+ case COAP_OPTION_URI_QUERY:
+ case COAP_OPTION_LOCATION_QUERY:
+ case COAP_OPTION_PROXY_URI:
+ case COAP_OPTION_PROXY_SCHEME:
+ case COAP_OPTION_URI_PATH:
+ {
+ memset(option->opt.opt_str,0x0,128);
+ memcpy(option->opt.opt_str,str,strlen((char*)str));
+ break;
+ }
+ case COAP_OPTION_OBSERVE:
+ case COAP_OPTION_MAX_AGE:
+ case COAP_OPTION_URI_PORT:
+ case COAP_OPTION_SIZE2:
+ case COAP_OPTION_SIZE1:
+ {
+ option->opt.opt_int = (int)int0;
+ break;
+ }
+ case COAP_OPTION_BLOCK2:
+ case COAP_OPTION_BLOCK1:
+ {
+ option->opt.opt_block.size = (mbtk_ecoap_option_block_e)int0;
+ option->opt.opt_block.number = (int)int1;
+ option->opt.opt_block.more_flag = (uint8)int2;
+ break;
+ }
+ case COAP_OPTION_CONTENT_FORMAT:
+ {
+ option->opt.opt_content_format = (mbtk_content_format_type)int0;
+ break;
+ }
+ case COAP_OPTION_ACCEPT:
+ {
+ option->opt.opt_content_format = (mbtk_content_format_type)int0;
+ break;
+ }
+ default:
+ printf("No such type:%s\n",type);
+ break;
+ }
+ }
+}
+
+
+static void mbtk_ecoap_send_ack(mbtk_coap_code_type code,
+ uint16_t message_id,uint8 token_len,uint8 *token)
+{
+ coapReset();
+ coapSetVersion(1);
+ coapSetType(COAP_ACKNOWLEDGEMENT);
+ coapSetMessageID(message_id);
+
+ if(code == COAP_POST || code == COAP_PUT)
+ coapSetCode(COAP_CHANGED);
+ else
+ coapSetCode(COAP_EMPTY);
+
+ if(token_len > 0)
+ {
+ coapSetToken(token, token_len);
+ }
+
+ uint8_t* pduPointer = coapGetPDUPointer();
+ int pduLen = coapGetPDULength();
+ int err;
+ int res = mbtk_sock_write(coap_handle, coap_fd, pduPointer, pduLen, 300, &err);
+ if(res != pduLen)
+ {
+ printf("Send ACK fail.[res:%d,pduLen:%d],err:%d\n",res,pduLen,err);
+ }
+ else
+ {
+ printf("Send ACK to server success.\n");
+ }
+}
+
+
+
+static int mbtk_ecoap_handle_sock_init(char *ip_addr, int port, bool is_support_ssl, bool ingnore_cert)
+{
+ mbtk_sock_info *sock_info = NULL;
+ int rc = 0;
+ int errno;
+
+ sock_info = (mbtk_sock_info *)malloc(sizeof(mbtk_sock_info));
+ if(sock_info == NULL)
+ {
+ rc = -1;
+ return rc;
+ }
+ memcpy(sock_info->address, ip_addr, strlen(ip_addr));
+ sock_info->port = port;
+ sock_info->is_support_ssl = is_support_ssl;
+ sock_info->ingnore_cert = ingnore_cert;
+ sock_info->type = MBTK_SOCK_UDP;
+
+ printf("host %s\nport %d\nis_support_ssl %d\ningnore_cert %d\n",sock_info->address,sock_info->port,sock_info->is_support_ssl,sock_info->ingnore_cert);
+
+ if(!coap_sock_inited)
+ {
+ coap_handle = mbtk_sock_init(coap_init_info);
+ if (coap_handle < 0 )
+ {
+ rc = -1;
+ return rc;
+ }
+ coap_sock_inited = TRUE;
+ }
+
+
+ coap_fd = mbtk_sock_open(coap_handle, sock_info, 3000, &errno);
+ if(coap_fd < 0)
+ {
+ printf("creat socket fail, errno:%d\n",errno);
+ rc = -1;
+ return rc;
+ }
+ mbtk_ecoap_state = MBTK_ECOAP_STATE_READY;
+ return rc;
+}
+
+
+
+int mbtk_ecoap_ecoap_send(mbtk_ecoap_package_s* coap)
+{
+ if(coap != NULL)
+ {
+ coapReset();
+ coapSetVersion(coap->version);
+ coapSetType(coap->type);
+ coapSetCode(coap->code);
+ coapSetMessageID(coap->message_id);
+
+ if(coap->token_len > 0)
+ {
+ coapSetToken(coap->token, coap->token_len);
+ }
+
+ mbtk_ecoap_option_s *option = coap->options;
+ while(option != NULL)
+ {
+ mbtk_ecoap_option_add(option);
+ option = option->next;
+ }
+
+ if(coap->payload_len > 0)
+ {
+ coapSetPayload((uint8_t*)coap->payload, coap->payload_len);
+ }
+
+ uint8_t *pduPointer = coapGetPDUPointer();
+ int pduLen = coapGetPDULength();
+ uint8_t pduPointer2[MBTK_ECOAP_DATA_MAX*2];
+ int err;
+ memset ( pduPointer2,0x00,MBTK_ECOAP_DATA_MAX*2 );
+ if((mbtk_ecoap_option_2.optlen + pduLen) > MBTK_ECOAP_DATA_MAX*2)
+ {
+ printf("This length is too long\n");
+ return -1;
+ }
+
+ LOGE("pduLen:%d, optlen:%d\n",pduLen ,mbtk_ecoap_option_2.optlen);
+ // printf("pduPointer:\n");
+ // coap_log(-1,(char*)pduPointer,pduLen);
+ int j=0,k=0;
+ LOGE("pduPointer-----------end\n");
+// int optflag = 0;
+ pduPointer2[0]= *pduPointer++;
+ pduPointer2[1]= *pduPointer++;
+ pduPointer2[2]= *pduPointer++;
+ pduPointer2[3]= *pduPointer++;
+ for(j = 0; j < mbtk_ecoap_option_2.optlen; j++)
+ {
+ pduPointer2[4+j] = mbtk_ecoap_option_2.optVal[j];
+ LOGE("j:%d, %X",j, mbtk_ecoap_option_2.optVal[j]);
+ k++;
+ }
+ int pduLen2 = 4;
+ while(pduLen > pduLen2 )
+ {
+ LOGE("\r\npduLen > pduLen2 \r\n");
+ LOGE("pduLen:%d,pduPointer:%X,k:%d\n",pduLen2,*pduPointer,k);
+ pduPointer2[pduLen2+k] = *pduPointer++;
+ pduLen2++;
+ }
+
+ pduLen += mbtk_ecoap_option_2.optlen;
+
+ printf("sendpdu:--------pduLen:%d\n",pduLen);
+ coap_log(FALSE,(char*)pduPointer2,pduLen);
+ int send_len = 0;
+
+ if((send_len = mbtk_sock_write(coap_handle, coap_fd, pduPointer2, pduLen, 300, &err)) != pduLen)
+// if((send_len = sendto(socket_id, pduPointer2, pduLen, 0, (struct sockaddr*)&serveraddr, addrlen)) != pduLen)
+ {
+ printf("coap_udp_sendto complate.[%d/%d]\n",send_len,pduLen);
+
+ coap->send_count++;
+ return -1;
+ }
+
+ if(coap->type != COAP_CONFIRMABLE)
+ {
+ mbtk_ecoap_list_del(coap->message_id,0);
+ }
+
+ }
+ return 0;
+}
+
+void mbtk_ecoap_recv_buffer(char * dest)
+{
+ int pud_lenth = mbtk_coap_get_pdu_Length();
+ int type = mbtk_ecoap_get_message_type();
+ char code[12];
+ memset(code,0x00,sizeof(code));
+ mbtk_ecoap_get_code(code);
+ uint16_t mesageId = coapGetRecvMessageID();
+ memset(dest,0x00,129);
+ snprintf(dest,128,
+ "+COAPNMI:%d\r\nMessage Type:%d\r\nCode:\"%s\"\r\nMessage ID:%d\r\nPayload:",
+ pud_lenth,
+ type,
+ code,
+ mesageId);
+
+ return 0;
+}
+
+
+static void mbtk_ecoap_recv_resolve(const void *data,uint16 data_len)
+{
+ if(coapCreateRecv((uint8_t*)data, data_len) <= 0)
+ {
+ printf("coapCreateRecv fail.\n");
+ }
+ else
+ {
+ LOGE("coapCreateRecv() success.\n");
+
+ uint8_t version = coapGetRecvVersion();
+ mbtk_coap_type type = coapGetRecvType();
+ mbtk_coap_code_type code = coapGetRecvCode();
+ uint16_t message_id = coapGetRecvMessageID();
+ int pud_lenth = mbtk_coap_get_pdu_Length();
+ LOGE("version:%d;type:%d\n",version,type);
+ LOGE("code:%d;message_id:%d,pud_lenth:%d\n",code,message_id,pud_lenth);
+
+ uint8 token_len = coapGetRecvTokenLength();
+ char token[9] = {0};
+ memcpy(token,coapGetRecvTokenPointer(),token_len);
+ LOGE("token[%d]:%s\n",token_len,token);
+
+ uint16 playload_len = coapGetRecvPayloadLength();
+ uint8 *playload = coapGetRecvPayloadPointer();
+// printf("----------------payload-----------------\n");
+// coap_log(0,(char*)playload,playload_len);
+// printf("--------------payload end----------------\n");
+
+
+ char buff_data[MBTK_ECOAP_DATA_MAX*2+1];
+ memset ( buff_data,0x00,MBTK_ECOAP_DATA_MAX*2+1 );
+ int buffer_len = ecoap_recv_buffer(buff_data, data, data_len);
+ printf("recv buff_len:%d\n",buffer_len);
+ printf("buf:\n%s\r\n",buff_data);
+
+ LOGE("type:%X\n",type);
+ if(type == COAP_CONFIRMABLE) // Should ACK
+ {
+ mbtk_ecoap_send_ack(code,message_id,token_len,(uint8*)token);
+ }
+ else if(type == COAP_NON_CONFIRMABLE)
+ {
+ // Do nothing.
+ }
+ else if(type == COAP_ACKNOWLEDGEMENT)
+ {
+ mbtk_ecoap_package_s * coap_send = mbtk_ecoap_get_by_msg_id(message_id);
+ if(coap_send != NULL)
+ {
+ int number;
+ uint8_t more_flag;
+ uint8_t size;
+ LOGE("Get message(%d) ack.\n",message_id);
+ if(coapGetRecvOptionBlock2(&number, &more_flag, &size))
+ {
+ LOGE("Block2 (size:%d; more_flag:%d; number:%d)\n",size,more_flag,number);
+ if(more_flag) // Has data no read.
+ {
+ coap_send->message_id = ++mbtk_ecoap_net.message_id ;
+ mbtk_ecoap_set_option(coap_send, COAP_OPTION_BLOCK2, NULL,
+ size,number + 1,0);
+
+ mbtk_ecoap_ecoap_send(coap_send);
+ }
+ else
+ {
+ mbtk_ecoap_list_del(message_id,0);
+ }
+ }
+ else
+ {
+ printf("coapGetRecvOptionBlock2() fail.\n");
+ mbtk_ecoap_list_del(message_id,0);
+ }
+ }
+ else
+ {
+ printf("Coap not match.\n");
+ }
+ }
+ else // COAP_RESET
+ {
+ printf("Coap type error.\n");
+ }
+ }
+ coapDeleteRecv();
+
+}
+
+
+static int ecoap_sig_recv_handle(void)
+{
+ LOGE("coap_sig_recv_handle----------start\n");
+
+ uint8_t buffer[MBTK_ECOAP_DATA_MAX*2+1];
+ memset ( buffer,0x00,MBTK_ECOAP_DATA_MAX*2+1 );
+ int ret=-1;
+ int err = -1;
+ while(TRUE)
+ {
+ ret = mbtk_sock_read(coap_handle, coap_fd, buffer, MBTK_ECOAP_DATA_MAX*2, 1000*10, &err);
+ if(ret <= 0)
+ {
+ printf("read fail, err:%d",err);
+ break;
+ }
+ printf("recv_from ret:%d\n",ret);
+ coap_log(FALSE,(char*)buffer,ret);
+ mbtk_ecoap_recv_resolve(buffer,ret);
+ }
+
+ return ret;
+}
+
+static int ecoap_sig_send_complete_handle(void )
+{
+ int ret=-1;
+ mbtk_ecoap_package_s *coap = mbtk_ecoap_get_by_msg_id(mbtk_ecoap_net.message_id);
+ if(coap == NULL)
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_MSG_ID);
+ return -1;
+ }
+
+ ret = mbtk_ecoap_ecoap_send(coap);
+
+ return ret;
+
+}
+
+static int mbtk_ecoap_open(int open);
+
+
+
+#endif
+
+
+/*************************************************************
+ Public Function Definitions
+*************************************************************/
+
+/*************************************************************
+ ip_addr: url
+ port
+
+*************************************************************/
+int mbtk_coap_ecoapnew_exec_cmd
+(
+ char *ip_addr,
+ int port,
+ bool is_support_ssl,
+ bool ingnore_cert
+)
+{
+ printf("mbtk_coap_ecoapnew_exec_cmd()------start1\n");
+ int ret = 0;
+ if( !ip_addr)
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_READY);
+ return -1;
+ }
+
+ ret = mbtk_ecoap_handle_sock_init(ip_addr, port, is_support_ssl, ingnore_cert);
+
+ return ret;
+}
+
+int mbtk_coap_ecoaprxmod_exec_cmd
+(
+ int mode
+)
+{
+ int result = 0;
+ int rx_mod = mode;
+
+ return result;
+}
+
+int mbtk_coap_ecoappr_exec_cmd
+(
+ int format
+)
+{
+ int result = 0;
+ uint16 ecoappr = format;
+ return result;
+}
+
+int mbtk_coap_ecoaprxget_exec_cmd
+(
+ int len
+)
+{
+ int result = 0;
+ int get_len = len;
+
+ return result;
+
+}
+
+int mbtk_coap_ecoapver_exec_cmd
+(
+ int version
+)
+{
+ int result = 0;
+ mbth_ecoap_package_ver.version = version;
+ return result;
+
+}
+
+int mbtk_coap_ecoaptype_exec_cmd
+(
+ mbtk_coap_type type
+)
+{
+ int result = 0;
+ mbth_ecoap_package_ver.type = type;
+
+ return result;
+
+}
+
+
+int mbtk_coap_ecoapcode_exec_cmd
+(
+ mbtk_coap_code_type code
+)
+{
+ int result = 0;
+ mbth_ecoap_package_ver.code = code;
+ LOGE("ver:%d,type:%d,code:%d,msg:%d\n",
+ mbth_ecoap_package_ver.version,
+ mbth_ecoap_package_ver.type,
+ mbth_ecoap_package_ver.code,
+ mbth_ecoap_package_ver.message_id);
+ return result;
+
+}
+
+int mbtk_coap_ecoaptoken_exec_cmd
+(
+ char *token_buf, int len
+)
+{
+ int result = 0;
+ uint16 token_length = len;
+ char * token = token_buf;
+ if(strlen(token) != token_length)
+ {
+ return -1;
+ }
+
+ mbth_ecoap_package_ver.token_len = token_length;
+ memcpy(mbth_ecoap_package_ver.token, token, strlen(token));
+
+ return result;
+}
+
+int mbtk_coap_ecoapmsgid_exec_cmd
+(
+ int msg_id
+)
+{
+ int result = 0;
+ mbth_ecoap_package_ver.message_id = msg_id;
+
+ return result;
+}
+
+int mbtk_coap_ecoapopt_exec_cmd
+(
+ char *value_buf, int buf_len
+)
+{
+ int result = 0;
+ int opt = buf_len;
+ char* value = value_buf;
+
+ if(value == NULL)
+ {
+ return -1;
+ }
+ if(opt != strlen(value))
+ {
+ return -1;
+ }
+
+ memset(&mbtk_ecoap_option_2, 0x0, sizeof(mbtk_ecoap_opt_2));
+ memset(&mbtk_ecoap_option_3, 0x0, sizeof(mbtk_ecoap_opt_3));
+
+ mbtk_ecoap_option_3.optlen = opt;
+ mbtk_ecoap_option_2.optlen = opt / 2;
+
+ if(mbtk_ecoap_option_2.optlen > 0)
+ {
+ memcpy(mbtk_ecoap_option_3.optVal, value, opt);
+ mbtk_ecoap_option_3.optVal[opt] = '\0';
+ StrToHex((byte*)mbtk_ecoap_option_2.optVal, (byte*)value, strlen(value));
+// printf("\r\nopt2---------option_len,option_data");
+// coap_log(FALSE,(char*)mbtk_ecoap_option_2.optVal,mbtk_ecoap_option_2.optlen);
+ }
+ return result;
+
+}
+
+int mbtk_coap_ecoapsend_exec_cmd
+(
+ int message_id, int Data_len, char *data
+)
+{
+ int data_len = Data_len;
+ char * send_data = NULL;
+ int err = -1;
+ if(data_len != 0 )
+ {
+ send_data = data;
+ }
+ int coap_id = message_id;
+
+ LOGE("send---------coap_id:%d,data_len:%d\n",coap_id,data_len);
+
+ if(mbtk_ecoap_state <= MBTK_ECOAP_STATE_CLOSING )
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_OPEN);
+ return -1;
+ }
+
+ if(coap_id != mbth_ecoap_package_ver.message_id)
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_MSG_ID);
+ return -1;
+ }
+
+ if(coap_id != mbtk_ecoap_net.message_id)
+ {
+ printf("send_cmd del message_id:%d\n",mbtk_ecoap_net.message_id);
+ mbtk_ecoap_list_del(mbtk_ecoap_net.message_id,-1);
+ }
+
+ if(send_data)
+ {
+ if(data_len != strlen(send_data) || data_len > 1024)
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_PAYLOAD_LENGTH);
+ return -1;
+ }
+ }
+
+ mbtk_ecoap_package_s *coap = mbtk_ecoap_get_by_msg_id(coap_id);
+ if( !coap)
+ {
+ mbtk_ecoap_net.message_id = mbth_ecoap_package_ver.message_id;
+ coap = mbtk_ecoap_list_add(mbtk_ecoap_net.message_id);
+ if(coap != NULL)
+ {
+ mbtk_ecoap_list_item_init(ECOAPVER,coap,mbth_ecoap_package_ver.version);
+ mbtk_ecoap_list_item_init(EOCAPTYPE,coap,mbth_ecoap_package_ver.type);
+ mbtk_ecoap_list_item_init(ECOAPCODE,coap,mbth_ecoap_package_ver.code);
+ if(mbth_ecoap_package_ver.token_len > 0)
+ {
+ coap->token_len = mbth_ecoap_package_ver.token_len;
+ memcpy(coap->token, mbth_ecoap_package_ver.token, strlen((char *)mbth_ecoap_package_ver.token));
+ }
+
+ if(data_len > 0)
+ {
+ coap->payload_len = data_len;
+ if(coap->payload != NULL)
+ {
+ free(coap->payload);
+ coap->payload = NULL;
+ }
+ coap->payload = (uint8*)malloc(data_len + 1);
+ memset(coap->payload,0x00,data_len + 1);
+ memcpy(coap->payload,send_data,data_len);
+ }
+
+ }
+ else{
+ printf("coap new error\n");
+ }
+
+ }
+ else
+ {
+ printf("coap is NULL\n");
+ }
+
+ mbtk_ecoap_recv = 0;
+ if(mbtk_ecoap_state < MBTK_ECOAP_STATE_READY)
+ {
+ printf("State[%d] error,not ready...\n",mbtk_ecoap_state);
+ return -1;
+ }
+
+ if( !ecoap_sig_send_complete_handle() )
+ {
+ ecoap_sig_recv_handle();
+ }
+
+ if(mbtk_sock_close(coap_handle, coap_fd,1000, &err)) {
+ return -1;
+ }
+
+ coap_fd = -1;
+ return 0;
+
+}
+
+int mbtk_coap_ecoapdel_exec_cmd( int del_id )
+{
+
+ int result = 0;
+ LOGE("del---------del_id:%d\n",del_id);
+ if(del_id != 1)
+ {
+ return -1;
+ }
+
+ if(mbtk_ecoap_state <= MBTK_ECOAP_STATE_CLOSING )
+ {
+ mbtk_ecoap_show_error(MBTK_ECOAP_ERR_NO_OPEN);
+ return -1;
+ }
+
+ LOGE("del---------del_id:%d\n",del_id);
+
+ return result;
+
+}
+
+int mbtk_coap_ecoapclose_exec_cmd( void )
+{
+ int result = 0;
+ if(!coap_sock_inited) {
+ LOGE("HTTP not inited.");
+ return -1;
+ }
+
+ int err = mbtk_sock_deinit(coap_handle);
+ if(err != MBTK_SOCK_SUCCESS) {
+ LOGE("mbtk_sock_deinit() fail.");
+ return -1;
+ }
+
+ coap_handle = -1;
+ coap_sock_inited = FALSE;
+ return 0;
+
+ return result;
+}
+
+void mbtk_coap_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_coap_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/coap/mbtk_coap_api.cpp b/mbtk/libmbtk_lib/coap/mbtk_coap_api.cpp
new file mode 100755
index 0000000..0a6dc19
--- /dev/null
+++ b/mbtk/libmbtk_lib/coap/mbtk_coap_api.cpp
@@ -0,0 +1,906 @@
+/*====*====*====*====*====*====*====*====*====*====*====*====*====*====*====*
+
+
+===========================================================================*/
+
+
+/*===========================================================================
+
+ INCLUDE FILES FOR MODULE
+
+===========================================================================*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "mbtk_coap_pdu.h"
+#include "mbtk_coap_api.h"
+
+/*===========================================================================
+
+ LOCAL DATA STRUCTURES
+
+===========================================================================*/
+//extern "C"
+//{
+
+static CoapPDU * g_CoapPDU = NULL;
+static CoapPDU * g_CoapRecvPointer = NULL;
+
+static void createCoapPDU()
+{
+ if(g_CoapPDU == NULL)
+ g_CoapPDU = new CoapPDU();
+}
+
+void coapReleaseCoapPUD()
+{
+ if(g_CoapPDU)
+ {
+ delete g_CoapPDU;
+ g_CoapPDU = NULL;
+ }
+}
+
+int coapReset()
+{
+ createCoapPDU();
+ return g_CoapPDU->reset();
+}
+
+int coapValidate()
+{
+ createCoapPDU();
+ return g_CoapPDU->validate();
+}
+
+
+uint8_t* coapGetPDUPointer()
+{
+ return g_CoapPDU->getPDUPointer();
+}
+
+void coapSetPDULength(int len)
+{
+ createCoapPDU();
+ g_CoapPDU->setPDULength(len);
+}
+
+int coapSetURI(char *uri)
+{
+ createCoapPDU();
+ return g_CoapPDU->setURI(uri);
+}
+
+int coapAddURIQuery(char *query)
+{
+ createCoapPDU();
+ return g_CoapPDU->addURIQuery(query);
+}
+
+int coapGetURI(char *dst, int dstlen, int *outLen)
+{
+ createCoapPDU();
+ return g_CoapPDU->getURI(dst, dstlen, outLen);
+}
+
+int coapSetVersion(uint8_t version)
+{
+ createCoapPDU();
+ return g_CoapPDU->setVersion(version);
+}
+
+uint8_t coapGetVersion()
+{
+ createCoapPDU();
+ return g_CoapPDU->getVersion();
+}
+
+void coapSetType(mbtk_coap_type mt)
+{
+ createCoapPDU();
+ g_CoapPDU->setType(mt);
+}
+
+mbtk_coap_type coapGetType()
+{
+ createCoapPDU();
+ return (mbtk_coap_type)g_CoapPDU->getType();
+}
+
+int GetTokenLength(uint8_t tokenLength)
+{
+ createCoapPDU();
+ return g_CoapPDU->setTokenLength(tokenLength);
+}
+
+int coapGetTokenLength()
+{
+ createCoapPDU();
+ return g_CoapPDU->getTokenLength();
+}
+
+uint8_t* coapGetTokenPointer()
+{
+ createCoapPDU();
+ return g_CoapPDU->getTokenPointer();
+}
+
+int coapSetToken(uint8_t *token, uint8_t tokenLength)
+{
+ createCoapPDU();
+ return g_CoapPDU->setToken(token, tokenLength) ;
+}
+
+void coapSetCode(mbtk_coap_code_type code)
+{
+ createCoapPDU();
+ g_CoapPDU->setCode(code);
+}
+
+mbtk_coap_code_type coapGetCode()
+{
+ createCoapPDU();
+ return (mbtk_coap_code_type)g_CoapPDU->getCode();
+}
+
+mbtk_coap_code_type coapHttpStatusToCode(int httpStatus)
+{
+ createCoapPDU();
+ return (mbtk_coap_code_type)g_CoapPDU->httpStatusToCode(httpStatus);
+}
+
+int coapSetMessageID(uint16_t messageID)
+{
+ createCoapPDU();
+ return g_CoapPDU->setMessageID(messageID);
+}
+
+uint16_t coapGetMessageID()
+{
+ createCoapPDU();
+ return g_CoapPDU->getMessageID();
+}
+
+/// Returns the length of the PDU.
+int coapGetPDULength()
+{
+ createCoapPDU();
+ return g_CoapPDU->getPDULength();
+}
+
+/// Return the number of options that the PDU has.
+int coapGetNumOptions()
+{
+ createCoapPDU();
+ return g_CoapPDU->getNumOptions();
+}
+
+//CoapOption* getOptions() {
+// return g_CoapPDU->getOptions();
+//}
+
+
+int coapAddOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue)
+{
+ createCoapPDU();
+ return g_CoapPDU->addOption(insertedOptionNumber, optionValueLength, optionValue);
+}
+
+uint8_t* coapMallocPayload(int len)
+{
+ createCoapPDU();
+ return g_CoapPDU->mallocPayload(len);
+}
+
+int coapSetPayload(uint8_t *payload, int len)
+{
+ createCoapPDU();
+ return g_CoapPDU->setPayload(payload, len);
+}
+
+/// Returns a pointer to the payload buffer.
+uint8_t* coapGetPayloadPointer()
+{
+ createCoapPDU();
+ return g_CoapPDU->getPayloadPointer();
+}
+
+/// Gets the length of the payload buffer.
+int coapGetPayloadLength()
+{
+ createCoapPDU();
+ return g_CoapPDU->getPayloadLength();
+}
+
+/// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated).
+uint8_t* coapGetPayloadCopy()
+{
+ createCoapPDU();
+ return g_CoapPDU->getPayloadCopy();
+}
+
+int coapSetContentFormat(mbtk_content_format_type format)
+{
+ createCoapPDU();
+ return g_CoapPDU->setContentFormat(format);
+}
+
+int coapHasOption(uint16_t optionNumber )
+{
+ createCoapPDU();
+ return g_CoapPDU->hasOption(optionNumber);
+}
+void coapDeleteRecv()
+{
+ if(g_CoapRecvPointer != NULL)
+ {
+ delete g_CoapRecvPointer;
+ g_CoapRecvPointer = NULL;
+ }
+
+}
+int coapCreateRecv(uint8_t *pdu, int pduLength)
+{
+ coapDeleteRecv();
+ g_CoapRecvPointer = new CoapPDU(pdu, pduLength, pduLength);
+ if(g_CoapRecvPointer != NULL)
+ {
+ if(g_CoapRecvPointer->validate())
+ return g_CoapRecvPointer->getPDULength();
+ else
+ {
+ coapDeleteRecv();
+ return 0;
+ }
+ }
+ else
+ return 0;
+
+}
+
+void coapPrintHuman(char * outBuffer)
+{
+ char type[20];
+ switch(g_CoapRecvPointer->getType())
+ {
+ case COAP_CONFIRMABLE:
+ strcpy(type, "Confirmable");
+ break;
+
+ case COAP_NON_CONFIRMABLE:
+ strcpy(type, "Non-Confirmable");
+ break;
+
+ case COAP_ACKNOWLEDGEMENT:
+ strcpy(type, "Acknowledgement");
+ break;
+
+ case COAP_RESET:
+ strcpy(type, "Reset");
+ break;
+ }
+ char code[30];
+ switch(g_CoapRecvPointer->getCode())
+ {
+ case COAP_EMPTY:
+ strcpy(code, "0.00 Empty");
+ break;
+ case COAP_GET:
+ strcpy(code, "0.01 GET");
+ break;
+ case COAP_POST:
+ strcpy(code, "0.02 POST");
+ break;
+ case COAP_PUT:
+ strcpy(code, "0.03 PUT");
+ break;
+ case COAP_DELETE:
+ strcpy(code, "0.04 DELETE");
+ break;
+ case COAP_CREATED:
+ strcpy(code, "2.01 Created");
+ break;
+ case COAP_DELETED:
+ strcpy(code, "2.02 Deleted");
+ break;
+ case COAP_VALID:
+ strcpy(code, "2.03 Valid");
+ break;
+ case COAP_CHANGED:
+ strcpy(code, "2.04 Changed");
+ break;
+ case COAP_CONTENT:
+ strcpy(code, "2.05 Content");
+ break;
+ case COAP_BAD_REQUEST:
+ strcpy(code, "4.00 Bad Request");
+ break;
+ case COAP_UNAUTHORIZED:
+ strcpy(code, "4.01 Unauthorized");
+ break;
+ case COAP_BAD_OPTION:
+ strcpy(code, "4.02 Bad Option");
+ break;
+ case COAP_FORBIDDEN:
+ strcpy(code, "4.03 Forbidden");
+ break;
+ case COAP_NOT_FOUND:
+ strcpy(code, "4.04 Not Found");
+ break;
+ case COAP_METHOD_NOT_ALLOWED:
+ strcpy(code, "4.05 Method Not Allowed");
+ break;
+ case COAP_NOT_ACCEPTABLE:
+ strcpy(type, "4.06 Not Acceptable");
+ break;
+ case COAP_PRECONDITION_FAILED:
+ strcpy(code, "4.12 Precondition Failed");
+ break;
+ case COAP_REQUEST_ENTITY_TOO_LARGE:
+ strcpy(code, "4.13 Request Entity Too Large");
+ break;
+ case COAP_UNSUPPORTED_CONTENT_FORMAT:
+ strcpy(code, "4.15 Unsupported Content-Format");
+ break;
+ case COAP_INTERNAL_SERVER_ERROR:
+ strcpy(code, "5.00 Internal Server Error");
+ break;
+ case COAP_NOT_IMPLEMENTED:
+ strcpy(code, "5.01 Not Implemented");
+ break;
+ case COAP_BAD_GATEWAY:
+ strcpy(code, "5.02 Bad Gateway");
+ break;
+ case COAP_SERVICE_UNAVAILABLE:
+ strcpy(code, "5.03 Service Unavailable");
+ break;
+ case COAP_GATEWAY_TIMEOUT:
+ strcpy(code, "5.04 Gateway Timeout");
+ break;
+ case COAP_PROXYING_NOT_SUPPORTED:
+ strcpy(code, "5.05 Proxying Not Supported");
+ break;
+ default:
+ {
+ sprintf(code, "Undefined Code %u", g_CoapRecvPointer->getCode());
+ }
+ }
+
+ sprintf(outBuffer,"PDU is %d bytes long\r\n"
+ "CoAP Version: %d\r\n"
+ "Message Type: %s\r\n"
+ "Code: %s\r\n"
+ "Message ID: %u\r\n",
+ g_CoapRecvPointer->getPDULength(),
+ g_CoapRecvPointer->getVersion(),
+ type,
+ code,
+ g_CoapRecvPointer->getMessageID());
+
+ // print token value
+ int tokenLength = g_CoapRecvPointer->getTokenLength();
+ uint8_t *tokenPointer = g_CoapRecvPointer->getPDUPointer()+COAP_HDR_SIZE;
+ if(tokenLength==0)
+ {
+ sprintf(outBuffer,"%sNo token\r\n",outBuffer);
+ }
+ else
+ {
+ sprintf(outBuffer,"%sToken of %d bytes.\r\n"
+ "Value: %s\r\n",
+ outBuffer,tokenLength, (char*)tokenPointer);
+ for(int j=0; j<tokenLength; j++)
+ {
+ sprintf(outBuffer,"%s%.2x",outBuffer, tokenPointer[j]);
+ }
+ }
+ // print options
+ CoapPDU::CoapOption* options = g_CoapRecvPointer->getOptions();
+ if(options==NULL)
+ {
+ sprintf(outBuffer,"\r\n%sNO options\r\n", outBuffer);
+ }
+
+ for(int i=0; i<g_CoapRecvPointer->getNumOptions(); i++)
+ {
+ char optionNumberBuffer[20];
+ switch(options[i].optionNumber)
+ {
+ case COAP_OPTION_IF_MATCH:
+ strcpy(optionNumberBuffer, "IF_MATCH");
+ break;
+ case COAP_OPTION_URI_HOST:
+ strcpy(optionNumberBuffer, "URI_HOST");
+ break;
+ case COAP_OPTION_ETAG:
+ strcpy(optionNumberBuffer, "ETAG");
+ break;
+ case COAP_OPTION_IF_NONE_MATCH:
+ strcpy(optionNumberBuffer, "IF_NONE_MATCH");
+ break;
+ case COAP_OPTION_OBSERVE:
+ strcpy(optionNumberBuffer, "OBSERVE");
+ break;
+ case COAP_OPTION_URI_PORT:
+ strcpy(optionNumberBuffer, "URI_PORT");
+ break;
+ case COAP_OPTION_LOCATION_PATH:
+ strcpy(optionNumberBuffer, "LOCATION_PATH");
+ break;
+ case COAP_OPTION_URI_PATH:
+ strcpy(optionNumberBuffer, "URI_PATH");
+ break;
+ case COAP_OPTION_CONTENT_FORMAT:
+ strcpy(optionNumberBuffer, "CONTENT_FORMAT");
+ break;
+ case COAP_OPTION_MAX_AGE:
+ strcpy(optionNumberBuffer, "MAX_AGE");
+ break;
+ case COAP_OPTION_URI_QUERY:
+ strcpy(optionNumberBuffer, "URI_QUERY");
+ break;
+ case COAP_OPTION_ACCEPT:
+ strcpy(optionNumberBuffer, "ACCEPT");
+ break;
+ case COAP_OPTION_LOCATION_QUERY:
+ strcpy(optionNumberBuffer, "LOCATION_QUERY");
+ break;
+ case COAP_OPTION_PROXY_URI:
+ strcpy(optionNumberBuffer, "PROXY_URI");
+ break;
+ case COAP_OPTION_PROXY_SCHEME:
+ strcpy(optionNumberBuffer, "PROXY_SCHEME");
+ break;
+ case COAP_OPTION_BLOCK1:
+ strcpy(optionNumberBuffer, "BLOCK1");
+ break;
+ case COAP_OPTION_BLOCK2:
+ strcpy(optionNumberBuffer, "BLOCK2");
+ break;
+ case COAP_OPTION_SIZE1:
+ strcpy(optionNumberBuffer, "SIZE1");
+ break;
+ case COAP_OPTION_SIZE2:
+ strcpy(optionNumberBuffer, "SIZE2");
+ break;
+ default:
+ sprintf(optionNumberBuffer, "Unknown option %u",(unsigned)options[i].optionNumber);
+ break;
+ }
+
+ /*char optionValue[options[i].optionValueLength + 1];
+ for(int j=0; j<options[i].optionValueLength; j++) {
+ char c = options[i].optionValuePointer[j];
+ if((c>='!'&&c<='~')||c==' ') {
+ sprintf(optionValue, "%s%c",optionValue,c);
+ } else {
+ sprintf(optionValue,"%s\\%.2d",optionValue,c);
+ }
+ }
+ sprintf(optionValue,"%s\"\r\n",optionValue);*/
+ sprintf(outBuffer,"\r\n%sOPTION (%d/%d)\r\n"
+ "Option number (delta): %hu (%hu)\r\n"
+ "Name: %s\r\n"
+ "Value length: %u\r\n"
+ "Value: \"%s",
+ outBuffer,
+ i + 1,g_CoapRecvPointer->getNumOptions(),
+ options[i].optionNumber,options[i].optionDelta,
+ optionNumberBuffer,
+ options[i].optionValueLength,
+ (char *)options[i].optionValuePointer);
+
+ }
+ if(options)
+ free(options);
+ // print payload
+ if(g_CoapRecvPointer->getPayloadLength() == 0)
+ {
+ sprintf(outBuffer,"%sNo payload\r\n", outBuffer);
+ }
+ else
+ {
+ sprintf(outBuffer, "%sPayload of %d bytes\r\n"
+ "Value: \"%s\"\r\n", outBuffer,
+ g_CoapRecvPointer->getPayloadLength(),
+ (char *)g_CoapRecvPointer->getPayloadPointer());
+ /*sprintf(outBuffer,"%sPayload of %d bytes\r\n", outBuffer,g_CoapRecvPointer->getPayloadLength());
+ sprintf(outBuffer, "%sValue: \"", outBuffer);
+ uint8_t* _payloadPointer = g_CoapRecvPointer->getPayloadPointer();
+ for(int j=0; j<g_CoapRecvPointer->getPayloadLength(); j++) {
+ char c = _payloadPointer[j];
+ if((c>='!'&&c<='~')||c==' ') {
+ sprintf(outBuffer, "%s%c", outBuffer,c);
+ } else {
+ sprintf(outBuffer, "%s\\%.2x",outBuffer,c);
+ }
+ }
+ sprintf(outBuffer, "%s\"\r\n", outBuffer);*/
+ }
+
+}
+
+void coapGetOptionValueById(uint16_t optionNumber, uint16_t * optionValueLength, uint8_t * optionValuePointer)
+{
+ if(g_CoapRecvPointer)
+ g_CoapRecvPointer->getOptionValueById(optionNumber, optionValueLength, optionValuePointer);
+}
+
+uint16_t coapGetRecvMessageID()
+{
+ return g_CoapRecvPointer->getMessageID();
+}
+
+mbtk_coap_type coapGetRecvType()
+{
+ return (mbtk_coap_type)g_CoapRecvPointer->getType();
+}
+
+mbtk_coap_code_type coapGetRecvCode()
+{
+ return (mbtk_coap_code_type)g_CoapRecvPointer->getCode();
+}
+
+int mbtk_coap_get_pdu_Length()
+{
+ return g_CoapRecvPointer->getPDULength();
+}
+
+
+int coapGetRecvTokenLength()
+{
+ return g_CoapRecvPointer->getTokenLength();
+}
+
+uint8_t* coapGetRecvTokenPointer()
+{
+ return g_CoapRecvPointer->getTokenPointer();
+}
+
+/// Returns a pointer to the payload buffer.
+uint8_t* coapGetRecvPayloadPointer()
+{
+ return g_CoapRecvPointer->getPayloadPointer();
+}
+
+/// Gets the length of the payload buffer.
+int coapGetRecvPayloadLength()
+{
+ return g_CoapRecvPointer->getPayloadLength();
+}
+
+uint8_t coapGetRecvVersion()
+{
+ return g_CoapRecvPointer->getVersion();
+}
+
+// Return If-Match length,or 0 if fail.
+uint16_t coapGetRecvOptionIfMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_IF_MATCH,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Uri-Host length,or 0 if fail.
+uint16_t coapGetRecvOptionUriHost(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_URI_HOST,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return ETag length,or 0 if fail.
+uint16_t coapGetRecvOptionETag(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_ETAG,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return If-None-Match length,or 0 if fail.
+uint16_t coapGetRecvOptionIfNoneMatch(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_IF_NONE_MATCH,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Location-Path length,or 0 if fail.
+uint16_t coapGetRecvOptionLocationPath(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_LOCATION_PATH,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Location-Query length,or 0 if fail.
+uint16_t coapGetRecvOptionLocationQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_LOCATION_QUERY,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Proxy-Uri length,or 0 if fail.
+uint16_t coapGetRecvOptionProxyUri(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_PROXY_URI,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Proxy-Scheme length,or 0 if fail.
+uint16_t coapGetRecvOptionProxyScheme(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_PROXY_SCHEME,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Uri-Path length,or 0 if fail.
+uint16_t coapGetRecvOptionUriPath(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_URI_PATH,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return Uri-Query length,or 0 if fail.
+uint16_t coapGetRecvOptionUriQuery(uint16_t *optionValueLength, uint8_t *optionValuePointer)
+{
+ *optionValueLength = 0;
+ coapGetOptionValueById(COAP_OPTION_URI_QUERY,optionValueLength,optionValuePointer);
+ return *optionValueLength;
+}
+
+// Return 1 if get Observe success,or 0 if fail.
+uint16_t coapGetRecvOptionObserve(uint16_t *observe)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_OBSERVE,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *observe = (uint16_t)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Max-Age success,or 0 if fail.
+uint16_t coapGetRecvOptionMaxAge(uint16_t *max_age)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_MAX_AGE,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *max_age = (uint16_t)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Uri-Port success,or 0 if fail.
+uint16_t coapGetRecvOptionUriPort(uint16_t *uri_port)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_URI_PORT,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *uri_port = (uint16_t)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Size2 success,or 0 if fail.
+uint16_t coapGetRecvOptionSize2(uint16_t *size2)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_SIZE2,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *size2 = (uint16_t)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Size1 success,or 0 if fail.
+uint16_t coapGetRecvOptionSize1(uint16_t *size1)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_SIZE1,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *size1 = (uint16_t)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Block2 success,or 0 if fail.
+uint16_t coapGetRecvOptionBlock2(uint32_t *number,uint8_t *more_flag,uint8_t *size)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_BLOCK2,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ if(buff_len == 1)
+ {
+ *size = (uint8_t)(buff[0] & 0x07);
+ *more_flag = (uint8_t)((buff[0] & 0x08) >> 3);
+ *number = (uint32_t)((buff[0] & 0xF0) >> 4);
+ }
+ else if(buff_len == 2)
+ {
+ *size = (uint8_t)(buff[1] & 0x07);
+ *more_flag = (uint8_t)((buff[1] & 0x08) >> 3);
+ *number = (uint32_t)(((buff[0] << 8) | (buff[1] & 0xF0)) >> 4);
+ }
+ else if(buff_len == 3)
+ {
+ *size = (uint8_t)(buff[2] & 0x07);
+ *more_flag = (uint8_t)((buff[2] & 0x08) >> 3);
+ *number = (uint32_t)(((buff[0] << 16) | (buff[1] << 8) | (buff[2] & 0xF0)) >> 4);
+ }
+ else
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Block1 success,or 0 if fail.
+uint16_t coapGetRecvOptionBlock1(uint32_t *number,uint8_t *more_flag,uint8_t *size)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_BLOCK1,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *size = (uint8_t)(buff[0] & 0x07);
+ *more_flag = (uint8_t)(buff[0] & 0x08);
+ if(buff_len == 1)
+ {
+ *number = (uint32_t)(buff[0] & 0xF0);
+ }
+ else if(buff_len == 2)
+ {
+ *number = (uint32_t)((buff[1] << 8) | (buff[0] & 0xF0));
+ }
+ else if(buff_len == 3)
+ {
+ *number = (uint32_t)((buff[2] << 16) | (buff[1] << 8) | (buff[0] & 0xF0));
+ }
+ else
+ {
+ return 0;
+ }
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Content-Format success,or 0 if fail.
+uint16_t coapGetRecvOptionContentFormat(mbtk_content_format_type *type)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_CONTENT_FORMAT,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *type = (mbtk_content_format_type)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+// Return 1 if get Accept success,or 0 if fail.
+uint16_t coapGetRecvOptionAccept(mbtk_content_format_type *type)
+{
+ uint8_t buff[10];
+ uint16_t buff_len = 0;
+ memset(buff,0x0,10);
+ coapGetOptionValueById(COAP_OPTION_ACCEPT,&buff_len,buff);
+ if(buff_len > 0)
+ {
+ *type = (mbtk_content_format_type)atoi((char*)buff);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+int coapPrintRecvPayload(char *out)
+{
+ // print payload
+ int payloadLength = g_CoapRecvPointer->getPayloadLength();
+ if(payloadLength==0)
+ {
+ return 0;
+ }
+ else
+ {
+ uint8_t* payloadPointer = g_CoapRecvPointer->getPayloadPointer();
+ sprintf(out,"%s:%d\r\n",out, payloadLength*2);
+ for(int j=0; j<payloadLength; j++)
+ {
+ sprintf(out,"%s%.2X",out,payloadPointer[j]);
+ }
+ sprintf(out,"%s\r\n",out);
+ return 1;
+ }
+}
+
+const char* coapPrintHumanByIndex(int index)
+{
+ if(index == 0)
+ {
+ createCoapPDU();
+ return g_CoapPDU->printHuman();
+ }
+ else if(index == 1)
+ return g_CoapRecvPointer->printHuman();
+ return NULL;
+}
+
+const char* coapPrintHexByIndex(int index)
+{
+ if(index == 0)
+ {
+ createCoapPDU();
+ return g_CoapPDU->printHex();
+ }
+ else if(index == 1)
+ return g_CoapRecvPointer->printHex();
+ return NULL;
+}
+
+//}
+
+
diff --git a/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.cpp b/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.cpp
new file mode 100755
index 0000000..c9f046d
--- /dev/null
+++ b/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.cpp
@@ -0,0 +1,2065 @@
+/*
+Copyright (c) 2013, Ashley Mills.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// version, 2 bits
+// type, 2 bits
+// 00 Confirmable
+// 01 Non-confirmable
+// 10 Acknowledgement
+// 11 Reset
+
+// token length, 4 bits
+// length of token in bytes (only 0 to 8 bytes allowed)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "mbtk_coap_pdu.h"
+
+//#include "mbtk_log.h"
+//#ifdef FEATURE_MBTK_ECOAP
+/// Memory-managed constructor. Buffer for PDU is dynamically sized and allocated by the object.
+/**
+ * When using this constructor, the CoapPDU class will allocate space for the PDU.
+ * Contrast this with the parameterized constructors, which allow the use of an external buffer.
+ *
+ * Note, the PDU container and space can be reused by issuing a CoapPDU::reset(). If the new PDU exceeds the
+ * space of the previously allocated memory, then further memory will be dynamically allocated.
+ *
+ * Deleting the object will free the Object container and all dynamically allocated memory.
+ *
+ * \note It would have been nice to use something like UDP_CORK or MSG_MORE, to allow separate buffers
+ * for token, options, and payload but these FLAGS aren't implemented for UDP in LwIP so stuck with one buffer for now.
+ *
+ * CoAP version defaults to 1.
+ *
+ * \sa CoapPDU::CoapPDU(uint8_t *pdu, int pduLength), CoapPDU::CoapPDU::(uint8_t *buffer, int bufferLength, int pduLength),
+ * CoapPDU:CoapPDU()~
+ *
+ */
+
+//#define printf(fmtstr) LOGD(fmtstr)
+//#define printf(fmtstr ,arg1) LOGD(fmtstr, arg1)
+//#define printf(fmtstr, arg1, arg2) LOGD(fmtstr , arg1, arg2)
+//#define printf(fmtstr, arg1, arg2, arg3) LOGD(fmtstr , arg1, arg2, arg3)
+
+/*
+void* operator new(unsigned int size, void* alloc, ds_appsrv_mem_e_type mem_type) throw()
+{
+// Do nothing
+ return alloc;
+}
+
+void operator delete(void* obj, void* alloc, ds_appsrv_mem_e_type mem_type) throw()
+{
+// Do nothing
+}
+
+*/
+
+CoapPDU::CoapPDU()
+{
+ // pdu
+ _pdu = (uint8_t*)calloc(4,sizeof(uint8_t));
+ _pduLength = 4;
+ _bufferLength = _pduLength;
+
+ //options
+ _numOptions = 0;
+ _maxAddedOptionNumber = 0;
+
+ // payload
+ _payloadPointer = NULL;
+ _payloadLength = 0;
+
+ _constructedFromBuffer = 0;
+
+ setVersion(1);
+}
+
+/// Construct object from external buffer that may be larger than actual PDU.
+/**
+ * This differs from CoapPDU::CoapPDU(uint8_t *pdu, int pduLength) in that the buffer may be larger
+ * than the actual CoAP PDU contained int the buffer. This is typically used when a large buffer is reused
+ * multiple times. Note that \b pduLength can be 0.
+ *
+ * If an actual CoAP PDU is passed in the buffer, \b pduLength should match its length. CoapPDU::validate() must
+ * be called to initiate the object before member functions can be used.
+ *
+ * A PDU constructed in this manner must be validated with CoapPDU::validate() before the member variables will be accessible.
+ *
+ * \warning The validation call parses the PDU structure to set some internal parameters. If you do
+ * not validate the PDU, then the behaviour of member access functions will be undefined.
+ *
+ * The buffer can be reused by issuing a CoapPDU::reset() but the class will not change the size of the buffer. If the
+ * newly constructed PDU exceeds the size of the buffer, the function called (for example CoapPDU::addOption) will fail.
+ *
+ * Deleting this object will only delete the Object container and will not delete the PDU buffer.
+ *
+ * \param buffer A buffer which either contains a CoAP PDU or is intended to be used to construct one.
+ * \param bufferLength The length of the buffer
+ * \param pduLength If the buffer contains a CoAP PDU, this specifies the length of the PDU within the buffer.
+ *
+ * \sa CoapPDU::CoapPDU(), CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
+ */
+CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
+{
+ printf("CoapPDU(),bufferLength:%d, pduLength;%d\n",bufferLength,pduLength);
+ // sanity
+ if(pduLength<4&&pduLength!=0)
+ {
+ printf("PDU cannot have a length less than 4");
+ }
+
+ // pdu
+ _pdu = buffer;
+ _bufferLength = bufferLength;
+ if(pduLength==0)
+ {
+ // this is actually a fresh pdu, header always exists
+ _pduLength = 4;
+ // make sure header is zeroed
+ _pdu[0] = 0x00;
+ _pdu[1] = 0x00;
+ _pdu[2] = 0x00;
+ _pdu[3] = 0x00;
+ setVersion(1);
+ }
+ else
+ {
+ _pduLength = pduLength;
+ }
+
+ _constructedFromBuffer = 1;
+
+ // options
+ _numOptions = 0;
+ _maxAddedOptionNumber = 0;
+
+ // payload
+ _payloadPointer = NULL;
+ _payloadLength = 0;
+}
+
+/// Reset CoapPDU container so it can be reused to build a new PDU.
+/**
+ * This resets the CoapPDU container, setting the pdu length, option count, etc back to zero. The
+ * PDU can then be populated as if it were newly constructed.
+ *
+ * Note that the space available will depend on how the CoapPDU was originally constructed:
+ * -# CoapPDU::CoapPDU()
+ *
+ * Available space initially be \b _pduLength. But further space will be allocated as needed on demand,
+ * limited only by the OS/environment.
+ *
+ * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
+ *
+ * Space is limited by the variable \b pduLength. The PDU cannot exceed \b pduLength bytes.
+ *
+ * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
+ *
+ * Space is limited by the variable \b bufferLength. The PDU cannot exceed \b bufferLength bytes.
+ *
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::reset()
+{
+ // pdu
+ memset(_pdu,0x00,_bufferLength);
+ // packet always has at least a header
+ _pduLength = 4;
+
+ // options
+ _numOptions = 0;
+ _maxAddedOptionNumber = 0;
+ // payload
+ _payloadPointer = NULL;
+ _payloadLength = 0;
+ content.clear();
+ return 0;
+}
+
+/// Validates a PDU constructed using an external buffer.
+/**
+ * When a CoapPDU is constructed using an external buffer, the programmer must call this function to
+ * check that the received PDU is a valid CoAP PDU.
+ *
+ * \warning The validation call parses the PDU structure to set some internal parameters. If you do
+ * not validate the PDU, then the behaviour of member access functions will be undefined.
+ *
+ * \return 1 if the PDU validates correctly, 0 if not. XXX maybe add some error codes
+ */
+int CoapPDU::validate()
+{
+ if(_pduLength<4)
+ {
+ printf("PDU has to be a minimum of 4 bytes. This: %d bytes",_pduLength);
+ return 0;
+ }
+
+ // check header
+ // 0 1 2 3
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // |Ver| T | TKL | Code | Message ID |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Token (if any, TKL bytes) ...
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // | Options (if any) ...
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // |1 1 1 1 1 1 1 1| Payload (if any) ...
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ // version must be 1
+ int version = getVersion();
+ if (version != 1)
+ {
+ printf("Invalid version: %d", version);
+ return 0;
+ }
+ printf("Version: %d", version);
+ printf("Type: %d", getType());
+
+ // token length must be between 0 and 8
+ int tokenLength = getTokenLength();
+ if(tokenLength<0||tokenLength>8)
+ {
+ printf("Invalid token length: %d",tokenLength);
+ return 0;
+ }
+ printf("Token length: %d",tokenLength);
+ // check total length
+ if((COAP_HDR_SIZE+tokenLength)>_pduLength)
+ {
+ printf("Token length would make pdu longer than actual length.");
+ return 0;
+ }
+
+ // check that code is valid
+ int code = getCode();
+ if(code<COAP_EMPTY ||
+ (code>COAP_LASTMETHOD&&code<COAP_CREATED) ||
+ (code>COAP_CONTENT&&code<COAP_CONTINUE) ||
+ (code>COAP_CONTINUE&&code<COAP_BAD_REQUEST) ||
+ (code>COAP_NOT_ACCEPTABLE&&code<COAP_PRECONDITION_FAILED) ||
+ (code==0x8E) ||
+ (code>COAP_UNSUPPORTED_CONTENT_FORMAT&&code<COAP_INTERNAL_SERVER_ERROR) ||
+ (code>COAP_PROXYING_NOT_SUPPORTED) )
+ {
+ printf("Invalid CoAP code: %d",code);
+ return 0;
+ }
+ printf("CoAP code: %d",code);
+
+ // token can be anything so nothing to check
+
+ // check that options all make sense
+ uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;
+ int totalLength = 0;
+
+ // first option occurs after token
+ int optionPos = COAP_HDR_SIZE + getTokenLength();
+
+ // may be 0 options
+ if(optionPos==_pduLength)
+ {
+ printf("No options. No payload.");
+ _numOptions = 0;
+ _payloadLength = 0;
+ return 1;
+ }
+
+ int bytesRemaining = _pduLength-optionPos;
+ int numOptions = 0;
+ uint8_t upperNibble = 0x00, lowerNibble = 0x00;
+
+ // walk over options and record information
+ while(1)
+ {
+ // check for payload marker
+ if(bytesRemaining>0)
+ {
+ uint8_t optionHeader = _pdu[optionPos];
+ if(optionHeader==0xFF)
+ {
+ // payload
+ if(bytesRemaining>1)
+ {
+ _payloadPointer = &_pdu[optionPos+1];
+ _payloadLength = (bytesRemaining-1);
+ _numOptions = numOptions;
+ printf("Payload found, length: %d",_payloadLength);
+ return 1;
+ }
+ // payload marker but no payload
+ _payloadPointer = NULL;
+ _payloadLength = 0;
+ printf("Payload marker but no payload.");
+ return 0;
+ }
+
+ // check that option delta and option length are valid values
+ upperNibble = (optionHeader & 0xF0) >> 4;
+ lowerNibble = (optionHeader & 0x0F);
+ if(upperNibble==0x0F||lowerNibble==0x0F)
+ {
+ printf("Expected option header or payload marker, got: 0x%x%x",upperNibble,lowerNibble);
+ return 0;
+ }
+ printf("Option header byte appears sane: 0x%x%x",upperNibble,lowerNibble);
+ }
+ else
+ {
+ printf("No more data. No payload.");
+ _payloadPointer = NULL;
+ _payloadLength = 0;
+ _numOptions = numOptions;
+ return 1;
+ }
+
+ // skip over option header byte
+ bytesRemaining--;
+
+ // check that there is enough space for the extended delta and length bytes (if any)
+ int headerBytesNeeded = computeExtraBytes(upperNibble);
+ printf("%d extra bytes needed for extended delta",headerBytesNeeded);
+ if(headerBytesNeeded>bytesRemaining)
+ {
+ printf("Not enough space for extended option delta, needed %d, have %d.",headerBytesNeeded,bytesRemaining);
+ return 0;
+ }
+ headerBytesNeeded += computeExtraBytes(lowerNibble);
+ if(headerBytesNeeded>bytesRemaining)
+ {
+ printf("Not enough space for extended option length, needed %d, have %d.",
+ (headerBytesNeeded-computeExtraBytes(upperNibble)),bytesRemaining);
+ return 0;
+ }
+ printf("Enough space for extended delta and length: %d, continuing.",headerBytesNeeded);
+
+ // extract option details
+ optionDelta = getOptionDelta(&_pdu[optionPos]);
+ optionNumber += optionDelta;
+ optionValueLength = getOptionValueLength(&_pdu[optionPos]);
+ printf("Got option: %d with length %d",optionNumber,optionValueLength);
+ // compute total length
+ totalLength = 1; // mandatory header
+ totalLength += computeExtraBytes(optionDelta);
+ totalLength += computeExtraBytes(optionValueLength);
+ totalLength += optionValueLength;
+ // check there is enough space
+ if(optionPos+totalLength>_pduLength)
+ {
+ printf("Not enough space for option payload, needed %d, have %d.",(totalLength-headerBytesNeeded-1),_pduLength-optionPos);
+ return 0;
+ }
+ printf("Enough space for option payload: %d %d",optionValueLength,(totalLength-headerBytesNeeded-1));
+
+ // recompute bytesRemaining
+ bytesRemaining -= totalLength;
+ bytesRemaining++; // correct for previous --
+
+ // move to next option
+ optionPos += totalLength;
+
+ // inc number of options XXX
+ numOptions++;
+ }
+
+ return 1;
+}
+
+/// Destructor. Does not free buffer if constructor passed an external buffer.
+/**
+ * The destructor acts differently, depending on how the object was initially constructed (from buffer or not):
+ *
+ * -# CoapPDU::CoapPDU()
+ *
+ * Complete object is destroyed.
+ *
+ * -# CoapPDU::CoapPDU(uint8_t *pdu, int pduLength)
+ *
+ * Only object container is destroyed. \b pdu is left intact.
+ *
+ * -# CoapPDU::CoapPDU(uint8_t *buffer, int bufferLength, int pduLength)
+ *
+ * Only object container is destroyed. \b pdu is left intact.
+ *
+ */
+CoapPDU::~CoapPDU()
+{
+ if(!_constructedFromBuffer)
+ {
+ free(_pdu);
+ }
+}
+
+/// Returns a pointer to the internal buffer.
+uint8_t* CoapPDU::getPDUPointer()
+{
+ return _pdu;
+}
+
+/// Set the PDU length to the length specified.
+/**
+ * This is used when re-using a PDU container before calling CoapPDU::validate() as it
+ * is not possible to deduce the length of a PDU since the payload has no length marker.
+ * \param len The length of the PDU
+ */
+void CoapPDU::setPDULength(int len)
+{
+ _pduLength = len;
+}
+
+/// Shorthand function for setting a resource URI.
+/**
+ * Calls CoapPDU::setURI(uri,strlen(uri).
+ */
+int CoapPDU::setURI(char *uri)
+{
+ return setURI(uri,strlen(uri));
+}
+
+/// Shorthand function for setting a resource URI.
+/**
+ * This will parse the supplied \b uri and construct enough URI_PATH and URI_QUERY options to encode it.
+ * The options are added to the PDU.
+ *
+ * At present only simple URI formatting is handled, only '/','?', and '&' separators, and no port or protocol specificaiton.
+ *
+ * The function will split on '/' and create URI_PATH elements until it either reaches the end of the string
+ * in which case it will stop or if it reaches '?' it will start splitting on '&' and create URI_QUERY elements
+ * until it reaches the end of the string.
+ *
+ * Here is an example:
+ *
+ * /a/b/c/d?x=1&y=2&z=3
+ *
+ * Will be broken into four URI_PATH elements "a", "b", "c", "d", and three URI_QUERY elements "x=1", "y=2", "z=3"
+ *
+ * TODO: Add protocol extraction, port extraction, and some malformity checking.
+ *
+ * \param uri The uri to parse.
+ * \param urilen The length of the uri to parse.
+ *
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setURI(char *uri, int urilen)
+{
+ // only '/', '?', '&' and ascii chars allowed
+
+ // sanitation
+ if(urilen<=0||uri==NULL)
+ {
+ printf("Null or zero-length uri passed.");
+ return 1;
+ }
+
+ // single character URI path (including '/' case)
+ if(urilen==1)
+ {
+ addOption(COAP_OPTION_URI_PATH,1,(uint8_t*)uri);
+ return 0;
+ }
+
+ // TODO, queries
+ // extract ? to mark where to stop processing path components
+ // and then process the query params
+
+ // local vars
+ char *startP=uri,*endP=NULL;
+ int oLen = 0;
+ char splitChar = '/';
+ int queryStageTriggered = 0;
+ uint16_t optionType = COAP_OPTION_URI_PATH;
+ while(1)
+ {
+ // stop at end of string or query
+ if(*startP==0x00||*(startP+1)==0x00)
+ {
+ break;
+ }
+
+ // ignore leading slash
+ if(*startP==splitChar)
+ {
+ printf("Skipping leading slash");
+ startP++;
+ }
+
+ // find next split point
+ endP = strchr(startP,splitChar);
+
+ // might not be another slash
+ if(endP==NULL)
+ {
+ printf("Ending out of slash");
+ // check if there is a ?
+ endP = strchr(startP,'?');
+ // done if no queries
+ if(endP==NULL)
+ {
+ endP = uri+urilen;
+ }
+ else
+ {
+ queryStageTriggered = 1;
+ }
+ }
+
+ // get length of segment
+ oLen = endP-startP;
+
+#ifdef DEBUG
+ char *b = (char*)malloc(oLen+1);
+ memcpy(b,startP,oLen);
+ b[oLen] = 0x00;
+ printf("Adding URI_PATH %s",b);
+ free(b);
+#endif
+
+ // add option
+ if(addOption(optionType,oLen,(uint8_t*)startP)!=0)
+ {
+ printf("Error adding option");
+ return 1;
+ }
+ startP = endP;
+
+ if(queryStageTriggered)
+ {
+ splitChar = '&';
+ optionType = COAP_OPTION_URI_QUERY;
+ startP++;
+ queryStageTriggered = false;
+ }
+ }
+
+ return 0;
+}
+
+/// Shorthand for adding a URI QUERY to the option list.
+/**
+ * Adds a new option to the CoAP PDU that encodes a URI_QUERY.
+ *
+ * \param query The uri query to encode.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::addURIQuery(char *query)
+{
+ return addOption(COAP_OPTION_URI_QUERY,strlen(query),(uint8_t*)query);
+}
+
+/// Concatenates any URI_PATH elements and URI_QUERY elements into a single string.
+/**
+ * Parses the PDU options and extracts all URI_PATH and URI_QUERY elements,
+ * concatenating them into a single string with slash and amphersand separators accordingly.
+ *
+ * The produced string will be NULL terminated.
+ *
+ * \param dst Buffer into which to copy the concatenated path elements.
+ * \param dstlen Length of buffer.
+ * \param outLen Pointer to integer, into which URI length will be placed.
+ *
+ * \return 0 on success, 1 on failure. \b outLen will contain the length of the concatenated elements.
+ */
+int CoapPDU::getURI(char *dst, int dstlen, int *outLen)
+{
+ if(outLen==NULL)
+ {
+ printf("Output length pointer is NULL");
+ return 1;
+ }
+
+ if(dst==NULL)
+ {
+ printf("NULL destination buffer");
+ *outLen = 0;
+ return 1;
+ }
+
+ // check destination space
+ if(dstlen<=0)
+ {
+ *dst = 0x00;
+ *outLen = 0;
+ printf("Destination buffer too small (0)!");
+ return 1;
+ }
+ // check option count
+ if(_numOptions==0)
+ {
+ *dst = 0x00;
+ *outLen = 0;
+ return 0;
+ }
+ // get options
+ CoapPDU::CoapOption *options = getOptions();
+ if(options==NULL)
+ {
+ *dst = 0x00;
+ *outLen = 0;
+ return 0;
+ }
+ // iterate over options to construct URI
+ CoapOption *o = NULL;
+ int bytesLeft = dstlen-1; // space for 0x00
+ int oLen = 0;
+ // add slash at beggining
+ if(bytesLeft>=1)
+ {
+ *dst = '/';
+ dst++;
+ bytesLeft--;
+ }
+ else
+ {
+ printf("No space for initial slash needed 1, got %d",bytesLeft);
+ free(options);
+ return 1;
+ }
+
+ char separator = '/';
+ int firstQuery = 1;
+
+ for(int i=0; i<_numOptions; i++)
+ {
+ o = &options[i];
+ oLen = o->optionValueLength;
+ if(o->optionNumber==COAP_OPTION_URI_PATH||o->optionNumber==COAP_OPTION_URI_QUERY)
+ {
+ // if the option is a query, change the separator to &
+ if(o->optionNumber==COAP_OPTION_URI_QUERY)
+ {
+ if(firstQuery)
+ {
+ // change previous '/' to a '?'
+ *(dst-1) = '?';
+ firstQuery = 0;
+ }
+ separator = '&';
+ }
+
+ // check space
+ if(oLen>bytesLeft)
+ {
+ printf("Destination buffer too small, needed %d, got %d",oLen,bytesLeft);
+ free(options);
+ return 1;
+ }
+
+ // case where single '/' exists
+ if(oLen==1&&o->optionValuePointer[0]=='/')
+ {
+ *dst = 0x00;
+ *outLen = 1;
+ free(options);
+ return 0;
+ }
+
+ // copy URI path or query component
+ memcpy(dst,o->optionValuePointer,oLen);
+
+ // adjust counters
+ dst += oLen;
+ bytesLeft -= oLen;
+
+ // add separator following (don't know at this point if another option is coming)
+ if(bytesLeft>=1)
+ {
+ *dst = separator;
+ dst++;
+ bytesLeft--;
+ }
+ else
+ {
+ printf("Ran out of space after processing option");
+ free(options);
+ return 1;
+ }
+ }
+ }
+
+ // remove terminating separator
+ dst--;
+ bytesLeft++;
+ // add null terminating byte (always space since reserved)
+ *dst = 0x00;
+ *outLen = (dstlen-1)-bytesLeft;
+ free(options);
+ return 0;
+}
+
+/// Sets the CoAP version.
+/**
+ * \param version CoAP version between 0 and 3.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setVersion(uint8_t version)
+{
+ if(version>3)
+ {
+ return 0;
+ }
+
+ _pdu[0] &= 0x3F;
+ _pdu[0] |= (version << 6);
+ return 1;
+}
+
+/**
+ * Gets the CoAP Version.
+ * @return The CoAP version between 0 and 3.
+ */
+uint8_t CoapPDU::getVersion()
+{
+ return (_pdu[0]&0xC0)>>6;
+}
+
+/**
+ * Sets the type of this CoAP PDU.
+ * \param mt The type, one of:
+ * - COAP_CONFIRMABLE
+ * - COAP_NON_CONFIRMABLE
+ * - COAP_ACKNOWLEDGEMENT
+ * - COAP_RESET.
+ */
+void CoapPDU::setType(int mt)
+{
+ _pdu[0] &= 0xCF;
+ _pdu[0] |= mt;
+}
+
+/// Returns the type of the PDU.
+int CoapPDU::getType()
+{
+ return (int)(_pdu[0]&0x30);
+}
+
+
+/// Set the token length.
+/**
+ * \param tokenLength The length of the token in bytes, between 0 and 8.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setTokenLength(uint8_t tokenLength)
+{
+ if(tokenLength>8)
+ return 1;
+
+ _pdu[0] &= 0xF0;
+ _pdu[0] |= tokenLength;
+ return 0;
+}
+
+/// Returns the token length.
+int CoapPDU::getTokenLength()
+{
+ return _pdu[0] & 0x0F;
+}
+
+/// Returns a pointer to the PDU token.
+uint8_t* CoapPDU::getTokenPointer()
+{
+ if(getTokenLength()==0)
+ {
+ return NULL;
+ }
+ return &_pdu[4];
+}
+
+/// Set the PDU token to the supplied byte sequence.
+/**
+ * This sets the PDU token to \b token and sets the token length to \b tokenLength.
+ * \param token A sequence of bytes representing the token.
+ * \param tokenLength The length of the byte sequence.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setToken(uint8_t *token, uint8_t tokenLength)
+{
+ printf("Setting token");
+ if(token==NULL)
+ {
+ printf("NULL pointer passed as token reference");
+ return 1;
+ }
+
+ if(tokenLength==0)
+ {
+ printf("Token has zero length");
+ return 1;
+ }
+
+ // if tokenLength has not changed, just copy the new value
+ uint8_t oldTokenLength = getTokenLength();
+ if(tokenLength==oldTokenLength)
+ {
+ memcpy((void*)&_pdu[4],token,tokenLength);
+ return 0;
+ }
+
+ // otherwise compute new length of PDU
+ uint8_t oldPDULength = _pduLength;
+ _pduLength -= oldTokenLength;
+ _pduLength += tokenLength;
+
+ // now, have to shift old memory around, but shift direction depends
+ // whether pdu is now bigger or smaller
+ if(_pduLength>oldPDULength)
+ {
+ // new PDU is bigger, need to allocate space for new PDU
+ if(!_constructedFromBuffer)
+ {
+ uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
+ if(newMemory==NULL)
+ {
+ // malloc failed
+ printf("Failed to allocate memory for token");
+ _pduLength = oldPDULength;
+ return 1;
+ }
+ _pdu = newMemory;
+ _bufferLength = _pduLength;
+ }
+ else
+ {
+ // constructed from buffer, check space
+ if(_pduLength>_bufferLength)
+ {
+ printf("Buffer too small to contain token, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
+ _pduLength = oldPDULength;
+ return 1;
+ }
+ }
+
+ // and then shift everything after token up to end of new PDU
+ // memory overlaps so do this manually so to avoid additional mallocs
+ int shiftOffset = _pduLength-oldPDULength;
+ int shiftAmount = _pduLength-tokenLength-COAP_HDR_SIZE; // everything after token
+ shiftPDUUp(shiftOffset,shiftAmount);
+
+ // now copy the token into the new space and set official token length
+ memcpy((void*)&_pdu[4],token,tokenLength);
+ setTokenLength(tokenLength);
+
+ // and return success
+ return 0;
+ }
+
+ // new PDU is smaller, copy the new token value over the old one
+ memcpy((void*)&_pdu[4],token,tokenLength);
+ // and shift everything after the new token down
+ int startLocation = COAP_HDR_SIZE+tokenLength;
+ int shiftOffset = oldPDULength-_pduLength;
+ int shiftAmount = oldPDULength-oldTokenLength-COAP_HDR_SIZE;
+ shiftPDUDown(startLocation,shiftOffset,shiftAmount);
+ // then reduce size of buffer
+ if(!_constructedFromBuffer)
+ {
+ uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
+ if(newMemory==NULL)
+ {
+ // malloc failed, PDU in inconsistent state
+ printf("Failed to shrink PDU for new token. PDU probably broken");
+ return 1;
+ }
+ _pdu = newMemory;
+ _bufferLength = _pduLength;
+ }
+
+ // and officially set the new tokenLength
+ setTokenLength(tokenLength);
+ return 0;
+}
+
+/// Sets the CoAP response code
+void CoapPDU::setCode(int code)
+{
+ _pdu[1] = code;
+ // there is a limited set of response codes
+}
+
+/// Gets the CoAP response code
+int CoapPDU::getCode()
+{
+ return (int)_pdu[1];
+}
+
+
+/// Converts a http status code as an integer, to a CoAP code.
+/**
+ * \param httpStatus the HTTP status code as an integer (e.g 200)
+ * \return The correct corresponding int on success,
+ * CoapPDU::COAP_UNDEFINED_CODE on failure.
+ */
+int CoapPDU::httpStatusToCode(int httpStatus)
+{
+ switch(httpStatus)
+ {
+ case 1:
+ return CoapPDU::COAP_GET;
+ case 2:
+ return CoapPDU::COAP_POST;
+ case 3:
+ return CoapPDU::COAP_PUT;
+ case 4:
+ return CoapPDU::COAP_DELETE;
+ case 201:
+ return CoapPDU::COAP_CREATED;
+ case 202:
+ return CoapPDU::COAP_DELETED;
+ case 203:
+ return CoapPDU::COAP_VALID;
+ case 204:
+ return CoapPDU::COAP_CHANGED;
+ case 205:
+ return CoapPDU::COAP_CONTENT;
+ case 400:
+ return CoapPDU::COAP_BAD_REQUEST;
+ case 401:
+ return CoapPDU::COAP_UNAUTHORIZED;
+ case 402:
+ return CoapPDU::COAP_BAD_OPTION;
+ case 403:
+ return CoapPDU::COAP_FORBIDDEN;
+ case 404:
+ return CoapPDU::COAP_NOT_FOUND;
+ case 405:
+ return CoapPDU::COAP_METHOD_NOT_ALLOWED;
+ case 406:
+ return CoapPDU::COAP_NOT_ACCEPTABLE;
+ case 412:
+ return CoapPDU::COAP_PRECONDITION_FAILED;
+ case 413:
+ return CoapPDU::COAP_REQUEST_ENTITY_TOO_LARGE;
+ case 415:
+ return CoapPDU::COAP_UNSUPPORTED_CONTENT_FORMAT;
+ case 500:
+ return CoapPDU::COAP_INTERNAL_SERVER_ERROR;
+ case 501:
+ return CoapPDU::COAP_NOT_IMPLEMENTED;
+ case 502:
+ return CoapPDU::COAP_BAD_GATEWAY;
+ case 503:
+ return CoapPDU::COAP_SERVICE_UNAVAILABLE;
+ case 504:
+ return CoapPDU::COAP_GATEWAY_TIMEOUT;
+ case 505:
+ return CoapPDU::COAP_PROXYING_NOT_SUPPORTED;
+ default:
+ return CoapPDU::COAP_UNDEFINED_CODE;
+ }
+}
+
+/// Set messageID to the supplied value.
+/**
+ * \param messageID A 16bit message id.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setMessageID(uint16_t messageID)
+{
+ // message ID is stored in network byte order
+ uint8_t *to = &_pdu[2];
+ endian_store16(to, messageID);
+ return 0;
+}
+
+/// Returns the 16 bit message ID of the PDU.
+uint16_t CoapPDU::getMessageID()
+{
+ // mesasge ID is stored in network byteorder
+ uint8_t *from = &_pdu[2];
+ uint16_t messageID = endian_load16(uint16_t, from);
+ return messageID;
+}
+
+/// Returns the length of the PDU.
+int CoapPDU::getPDULength()
+{
+ return _pduLength;
+}
+
+/// Return the number of options that the PDU has.
+int CoapPDU::getNumOptions()
+{
+ return _numOptions;
+}
+
+
+/**
+ * This returns the options as a sequence of structs.
+ */
+CoapPDU::CoapOption* CoapPDU::getOptions()
+{
+ printf("getOptions() called, %d options.",_numOptions);
+
+ uint16_t optionDelta =0, optionNumber = 0, optionValueLength = 0;
+ int totalLength = 0;
+
+ if(_numOptions==0)
+ {
+ return NULL;
+ }
+
+ // malloc space for options
+ CoapOption *options = (CoapOption*)malloc(_numOptions*sizeof(CoapOption));
+ if(options==NULL)
+ {
+ printf("Failed to allocate memory for options.");
+ return NULL;
+ }
+
+ // first option occurs after token
+ int optionPos = COAP_HDR_SIZE + getTokenLength();
+
+ // walk over options and record information
+ for(int i=0; i<_numOptions; i++)
+ {
+ // extract option details
+ optionDelta = getOptionDelta(&_pdu[optionPos]);
+ optionNumber += optionDelta;
+ optionValueLength = getOptionValueLength(&_pdu[optionPos]);
+ // compute total length
+ totalLength = 1; // mandatory header
+ totalLength += computeExtraBytes(optionDelta);
+ totalLength += computeExtraBytes(optionValueLength);
+ totalLength += optionValueLength;
+ // record option details
+ options[i].optionNumber = optionNumber;
+ options[i].optionDelta = optionDelta;
+ options[i].optionValueLength = optionValueLength;
+ options[i].totalLength = totalLength;
+ options[i].optionPointer = &_pdu[optionPos];
+ options[i].optionValuePointer = &_pdu[optionPos+totalLength-optionValueLength];
+ // move to next option
+ optionPos += totalLength;
+ }
+
+ return options;
+}
+
+/// Add an option to the PDU.
+/**
+ * Unlike other implementations, options can be added in any order, and in-memory manipulation will be
+ * performed to ensure the correct ordering of options (they use a delta encoding of option numbers).
+ * Re-ordering memory like this incurs a small performance cost, so if you care about this, then you
+ * might want to add options in ascending order of option number.
+ * \param optionNumber The number of the option, see the enum CoapPDU::Option for shorthand notations.
+ * \param optionLength The length of the option payload in bytes.
+ * \param optionValue A pointer to the byte sequence that is the option payload (bytes will be copied).
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::addOption(uint16_t insertedOptionNumber, uint16_t optionValueLength, uint8_t *optionValue)
+{
+ // this inserts the option in memory, and re-computes the deltas accordingly
+ // prevOption <-- insertionPosition
+ // nextOption
+
+ // find insertion location and previous option number
+ uint16_t prevOptionNumber = 0; // option number of option before insertion point
+ int insertionPosition = findInsertionPosition(insertedOptionNumber,&prevOptionNumber);
+ printf("inserting option at position %d, after option with number: %hu",insertionPosition,prevOptionNumber);
+
+ // compute option delta length
+ uint16_t optionDelta = insertedOptionNumber-prevOptionNumber;
+ uint8_t extraDeltaBytes = computeExtraBytes(optionDelta);
+
+ // compute option length length
+ uint16_t extraLengthBytes = computeExtraBytes(optionValueLength);
+
+ // compute total length of option
+ uint16_t optionLength = COAP_OPTION_HDR_BYTE + extraDeltaBytes + extraLengthBytes + optionValueLength;
+
+ // if this is at the end of the PDU, job is done, just malloc and insert
+ if(insertionPosition==_pduLength)
+ {
+ printf("Inserting at end of PDU");
+ // optionNumber must be biggest added
+ _maxAddedOptionNumber = insertedOptionNumber;
+
+ // set new PDU length and allocate space for extra option
+ int oldPDULength = _pduLength;
+ _pduLength += optionLength;
+ if(!_constructedFromBuffer)
+ {
+ uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
+ if(newMemory==NULL)
+ {
+ printf("Failed to allocate memory for option.");
+ _pduLength = oldPDULength;
+ // malloc failed
+ return 1;
+ }
+ _pdu = newMemory;
+ _bufferLength = _pduLength;
+ }
+ else
+ {
+ // constructed from buffer, check space
+ if(_pduLength>_bufferLength)
+ {
+ printf("Buffer too small for new option: needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
+ _pduLength = oldPDULength;
+ return 1;
+ }
+ }
+
+ // insert option at position
+ insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);
+ _numOptions++;
+ return 0;
+ }
+ // XXX could do 0xFF pdu payload case for changing of dynamically allocated application space SDUs < yeah, if you're insane
+
+ // the next option might (probably) needs it's delta changing
+ // I want to take this into account when allocating space for the new
+ // option, to avoid having to do two mallocs, first get info about this option
+ int nextOptionDelta = getOptionDelta(&_pdu[insertionPosition]);
+ int nextOptionNumber = prevOptionNumber + nextOptionDelta;
+ int nextOptionDeltaBytes = computeExtraBytes(nextOptionDelta);
+ printf("nextOptionDeltaBytes: %d",nextOptionDeltaBytes);
+ // recompute option delta, relative to inserted option
+ int newNextOptionDelta = nextOptionNumber-insertedOptionNumber;
+ int newNextOptionDeltaBytes = computeExtraBytes(newNextOptionDelta);
+ printf("newNextOptionDeltaBytes: %d",newNextOptionDeltaBytes);
+ // determine adjustment
+ int optionDeltaAdjustment = newNextOptionDeltaBytes-nextOptionDeltaBytes;
+
+ // create space for new option, including adjustment space for option delta
+ printf("Creating space");
+ int mallocLength = optionLength+optionDeltaAdjustment;
+ int oldPDULength = _pduLength;
+ _pduLength += mallocLength;
+
+ if(!_constructedFromBuffer)
+ {
+ uint8_t *newMemory = (uint8_t*)realloc(_pdu,_pduLength);
+ if(newMemory==NULL)
+ {
+ printf("Failed to allocate memory for option");
+ _pduLength = oldPDULength;
+ return 1;
+ }
+ _pdu = newMemory;
+ _bufferLength = _pduLength;
+ }
+ else
+ {
+ // constructed from buffer, check space
+ if(_pduLength>_bufferLength)
+ {
+ printf("Buffer too small to contain option, needed %d, got %d.",_pduLength-oldPDULength,_bufferLength-oldPDULength);
+ _pduLength = oldPDULength;
+ return 1;
+ }
+ }
+
+ // move remainder of PDU data up to create hole for new option
+ printf("Shifting PDU.");
+ shiftPDUUp(mallocLength,_pduLength-(insertionPosition+mallocLength));
+
+ // adjust option delta bytes of following option
+ // move the option header to the correct position
+ int nextHeaderPos = insertionPosition+mallocLength;
+ _pdu[nextHeaderPos-optionDeltaAdjustment] = _pdu[nextHeaderPos];
+ nextHeaderPos -= optionDeltaAdjustment;
+ // and set the new value
+ setOptionDelta(nextHeaderPos, newNextOptionDelta);
+
+ // new option shorter
+ // p p n n x x x x x
+ // p p n n x x x x x -
+ // p p - n n x x x x x
+ // p p - - n x x x x x
+ // p p o o n x x x x x
+
+ // new option longer
+ // p p n n x x x x x
+ // p p n n x x x x x - - -
+ // p p - - - n n x x x x x
+ // p p - - n n n x x x x x
+ // p p o o n n n x x x x x
+
+ // note, it can only ever be shorter or the same since if an option was inserted the delta got smaller
+ // but I'll leave that little comment in, just to show that it would work even if the delta got bigger
+
+ // now insert the new option into the gap
+ printf("Inserting new option...");
+ insertOption(insertionPosition,optionDelta,optionValueLength,optionValue);
+ printf("done\r\n");
+
+ // done, mark it with B!
+ _numOptions++;
+ return 0;
+}
+
+/// Allocate space for a payload.
+/**
+ * For dynamically constructed PDUs, this will allocate space for a payload in the object
+ * and return a pointer to it. If the PDU was constructed from a buffer, this doesn't
+ * malloc anything, it just changes the _pduLength and returns the payload pointer.
+ *
+ * \note The pointer returned points into the PDU buffer.
+ * \param len The length of the payload buffer to allocate.
+ * \return Either a pointer to the payload buffer, or NULL if there wasn't enough space / allocation failed.
+ */
+uint8_t* CoapPDU::mallocPayload(int len)
+{
+ printf("Entering mallocPayload");
+ // sanity checks
+ if(len==0)
+ {
+ printf("Cannot allocate a zero length payload");
+ return NULL;
+ }
+
+ // further sanity
+ if(len==_payloadLength)
+ {
+ printf("Space for payload of specified length already exists");
+ if(_payloadPointer==NULL)
+ {
+ printf("Garbage PDU. Payload length is %d, but existing _payloadPointer NULL",_payloadLength);
+ return NULL;
+ }
+ return _payloadPointer;
+ }
+
+ printf("_bufferLength: %d, _pduLength: %d, _payloadLength: %d",_bufferLength,_pduLength,_payloadLength);
+
+ // might be making payload bigger (including bigger than 0) or smaller
+ int markerSpace = 1;
+ int payloadSpace = len;
+ // is this a resizing?
+ if(_payloadLength!=0)
+ {
+ // marker already exists
+ markerSpace = 0;
+ // compute new payload length (can be negative if shrinking payload)
+ payloadSpace = len-_payloadLength;
+ }
+
+ // make space for payload (and payload marker if necessary)
+ int newLen = _pduLength+payloadSpace+markerSpace;
+ if(!_constructedFromBuffer)
+ {
+ uint8_t* newPDU = (uint8_t*)realloc(_pdu,newLen);
+ if(newPDU==NULL)
+ {
+ printf("Cannot allocate (or shrink) space for payload");
+ return NULL;
+ }
+ _pdu = newPDU;
+ _bufferLength = newLen;
+ }
+ else
+ {
+ // constructed from buffer, check space
+ printf("newLen: %d, _bufferLength: %d",newLen,_bufferLength);
+ if(newLen>_bufferLength)
+ {
+ printf("Buffer too small to contain desired payload, needed %d, got %d.",newLen-_pduLength,_bufferLength-_pduLength);
+ return NULL;
+ }
+ }
+
+ // deal with fresh allocation case separately
+ if(_payloadPointer==NULL)
+ {
+ // set payload marker
+ _pdu[_pduLength] = 0xFF;
+ // payload at end of old PDU
+ _payloadPointer = &_pdu[_pduLength+1];
+ _pduLength = newLen;
+ _payloadLength = len;
+ return _payloadPointer;
+ }
+
+ // otherwise, just adjust length of PDU
+ _pduLength = newLen;
+ _payloadLength = len;
+ printf("Leaving mallocPayload");
+ return _payloadPointer;
+}
+
+/// Set the payload to the byte sequence specified. Allocates memory in dynamic PDU if necessary.
+/**
+ * This will set the payload to \b payload. It will allocate memory in the case where the PDU was
+ * constructed without an external buffer.
+ *
+ * This will fail either if the fixed buffer isn't big enough, or if memory could not be allocated
+ * in the non-external-buffer case.
+ *
+ * \param payload Pointer to payload byte sequence.
+ * \param len Length of payload byte sequence.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setPayload(uint8_t *payload, int len)
+{
+ if(payload==NULL)
+ {
+ printf("NULL payload pointer.");
+ return 1;
+ }
+
+ uint8_t *payloadPointer = mallocPayload(len);
+ if(payloadPointer==NULL)
+ {
+ printf("Allocation of payload failed");
+ return 1;
+ }
+
+ // copy payload contents
+ memcpy(payloadPointer,payload,len);
+
+ return 0;
+}
+
+/// Returns a pointer to the payload buffer.
+uint8_t* CoapPDU::getPayloadPointer()
+{
+ return _payloadPointer;
+}
+
+/// Gets the length of the payload buffer.
+int CoapPDU::getPayloadLength()
+{
+ return _payloadLength;
+}
+
+/// Returns a pointer to a buffer which is a copy of the payload buffer (dynamically allocated).
+uint8_t* CoapPDU::getPayloadCopy()
+{
+ if(_payloadLength==0)
+ {
+ return NULL;
+ }
+
+ // malloc space for copy
+ uint8_t *payload = (uint8_t*)malloc(_payloadLength);
+ if(payload==NULL)
+ {
+ printf("Unable to allocate memory for payload");
+ return NULL;
+ }
+
+ // copy and return
+ memcpy(payload,_payloadPointer,_payloadLength);
+ return payload;
+}
+
+/// Shorthand for setting the content-format option.
+/**
+ * Sets the content-format to the specified value (adds an option).
+ * \param format The content format, one of:
+ *
+ * - COAP_CONTENT_FORMAT_TEXT_PLAIN
+ * - COAP_CONTENT_FORMAT_APP_LINK
+ * - COAP_CONTENT_FORMAT_APP_XML
+ * - COAP_CONTENT_FORMAT_APP_OCTET
+ * - COAP_CONTENT_FORMAT_APP_EXI
+ * - COAP_CONTENT_FORMAT_APP_JSON
+ *
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::setContentFormat(int format)
+{
+ if(format==0)
+ {
+ // minimal representation means null option value
+ if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,0,NULL)!=0)
+ {
+ printf("Error setting content format");
+ return 1;
+ }
+ return 0;
+ }
+
+ uint8_t c[2];
+
+ // just use 1 byte if can do it
+ //if((uint16_t)format <= 0xffu) {
+ if(1)
+ {
+ c[0] = format;
+ if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,1,c)!=0)
+ {
+ printf("Error setting content format");
+ return 1;
+ }
+ return 0;
+ }
+
+ uint8_t *to = c;
+ endian_store16(to, format);
+ if(addOption(CoapPDU::COAP_OPTION_CONTENT_FORMAT,2,c)!=0)
+ {
+ printf("Error setting content format");
+ return 1;
+ }
+ return 0;
+}
+
+// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
+// PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE
+
+/// Moves a block of bytes to end of PDU from given offset.
+/**
+ * This moves the block of bytes _pdu[_pduLength-1-shiftOffset-shiftAmount] ... _pdu[_pduLength-1-shiftOffset]
+ * to the end of the PDU.
+ * \param shiftOffset End of block to move, relative to end of PDU (-1).
+ * \param shiftAmount Length of block to move.
+ */
+void CoapPDU::shiftPDUUp(int shiftOffset, int shiftAmount)
+{
+ printf("shiftOffset: %d, shiftAmount: %d",shiftOffset,shiftAmount);
+ int destPointer = _pduLength-1;
+ int srcPointer = destPointer-shiftOffset;
+ while(shiftAmount--)
+ {
+ _pdu[destPointer] = _pdu[srcPointer];
+ destPointer--;
+ srcPointer--;
+ }
+}
+
+/// Moves a block of bytes down a specified number of steps.
+/**
+ * Moves the block of bytes _pdu[startLocation+shiftOffset] ... _pdu[startLocation+shiftOffset+shiftAmount]
+ * down to \b startLocation.
+ * \param startLocation Index where to shift the block to.
+ * \param shiftOffset Where the block starts, relative to start index.
+ * \param shiftAmount Length of block to shift.
+ */
+void CoapPDU::shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount)
+{
+ printf("startLocation: %d, shiftOffset: %d, shiftAmount: %d",startLocation,shiftOffset,shiftAmount);
+ int srcPointer = startLocation+shiftOffset;
+ while(shiftAmount--)
+ {
+ _pdu[startLocation] = _pdu[srcPointer];
+ startLocation++;
+ srcPointer++;
+ }
+}
+
+/// Gets the payload length of an option.
+/**
+ * \param option Pointer to location of option in PDU.
+ * \return The 16 bit option-payload length.
+ */
+uint16_t CoapPDU::getOptionValueLength(uint8_t *option)
+{
+ uint16_t delta = (option[0] & 0xF0) >> 4;
+ uint16_t length = (option[0] & 0x0F);
+ // no extra bytes
+ if(length<13)
+ {
+ return length;
+ }
+
+ // extra bytes skip header
+ int offset = 1;
+ // skip extra option delta bytes
+ if(delta==13)
+ {
+ offset++;
+ }
+ else if(delta==14)
+ {
+ offset+=2;
+ }
+
+ // process length
+ if(length==13)
+ {
+ return (option[offset]+13);
+ }
+ else
+ {
+ uint8_t *from = &option[offset];
+ uint16_t value = endian_load16(uint16_t, from);
+ return value+269;
+ }
+
+}
+
+/// Gets the delta of an option.
+/**
+ * \param option Pointer to location of option in PDU.
+ * \return The 16 bit delta.
+ */
+uint16_t CoapPDU::getOptionDelta(uint8_t *option)
+{
+ uint16_t delta = (option[0] & 0xF0) >> 4;
+ if(delta<13)
+ {
+ return delta;
+ }
+ else if(delta==13)
+ {
+ // single byte option delta
+ return (option[1]+13);
+ }
+ else if(delta==14)
+ {
+ uint8_t *from = &option[1];
+ uint16_t value = endian_load16(uint16_t, from);
+ return value+269;
+ }
+ else
+ {
+ // should only ever occur in payload marker
+ return delta;
+ }
+}
+
+/// Finds the insertion position in the current list of options for the specified option.
+/**
+ * \param optionNumber The option's number.
+ * \param prevOptionNumber A pointer to a uint16_t which will store the option number of the option previous
+ * to the insertion point.
+ * \return 0 on success, 1 on failure. \b prevOptionNumber will contain the option number of the option
+ * before the insertion position (for example 0 if no options have been inserted).
+ */
+int CoapPDU::findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber)
+{
+ // zero this for safety
+ *prevOptionNumber = 0x00;
+
+ printf("_pduLength: %d",_pduLength);
+
+ // if option is bigger than any currently stored, it goes at the end
+ // this includes the case that no option has yet been added
+ if( (optionNumber >= _maxAddedOptionNumber) || (_pduLength == (COAP_HDR_SIZE+getTokenLength())) )
+ {
+ *prevOptionNumber = _maxAddedOptionNumber;
+ return _pduLength;
+ }
+
+ // otherwise walk over the options
+ int optionPos = COAP_HDR_SIZE + getTokenLength();
+ uint16_t optionDelta = 0, optionValueLength = 0;
+ uint16_t currentOptionNumber = 0;
+ while(optionPos<_pduLength && _pdu[optionPos]!=0xFF)
+ {
+ optionDelta = getOptionDelta(&_pdu[optionPos]);
+ currentOptionNumber += optionDelta;
+ optionValueLength = getOptionValueLength(&_pdu[optionPos]);
+ // test if this is insertion position
+ if(currentOptionNumber>optionNumber)
+ {
+ return optionPos;
+ }
+ // keep track of the last valid option number
+ *prevOptionNumber = currentOptionNumber;
+ // move onto next option
+ optionPos += computeExtraBytes(optionDelta);
+ optionPos += computeExtraBytes(optionValueLength);
+ optionPos += optionValueLength;
+ optionPos++; // (for mandatory option header byte)
+ }
+ return optionPos;
+
+}
+
+/// CoAP uses a minimal-byte representation for length fields. This returns the number of bytes needed to represent a given length.
+int CoapPDU::computeExtraBytes(uint16_t n)
+{
+ if(n<13)
+ {
+ return 0;
+ }
+
+ if(n<269)
+ {
+ return 1;
+ }
+
+ return 2;
+}
+
+/// Set the option delta to the specified value.
+/**
+ * This assumes space has been made for the option delta.
+ * \param optionPosition The index of the option in the PDU.
+ * \param optionDelta The option delta value to set.
+ */
+void CoapPDU::setOptionDelta(int optionPosition, uint16_t optionDelta)
+{
+ int headerStart = optionPosition;
+ // clear the old option delta bytes
+ _pdu[headerStart] &= 0x0F;
+
+ // set the option delta bytes
+ if(optionDelta<13)
+ {
+ _pdu[headerStart] |= (optionDelta << 4);
+ }
+ else if(optionDelta<269)
+ {
+ // 1 extra byte
+ _pdu[headerStart] |= 0xD0; // 13 in first nibble
+ _pdu[++optionPosition] &= 0x00;
+ _pdu[optionPosition] |= (optionDelta-13);
+ }
+ else
+ {
+ // 2 extra bytes, network byte order uint16_t
+ _pdu[headerStart] |= 0xE0; // 14 in first nibble
+ optionDelta -= 269;
+ uint8_t *to = &_pdu[++optionPosition];
+ endian_store16(to, optionDelta);
+ }
+}
+
+/// Insert an option in-memory at the specified location.
+/**
+ * This assumes that there is enough space at the location specified.
+ * \param insertionPosition Position in the PDU where the option should be placed.
+ * \param optionDelta The delta value for the option.
+ * \param optionValueLength The length of the option value.
+ * \param optionValue A pointer to the sequence of bytes representing the option value.
+ * \return 0 on success, 1 on failure.
+ */
+int CoapPDU::insertOption(
+ int insertionPosition,
+ uint16_t optionDelta,
+ uint16_t optionValueLength,
+ uint8_t *optionValue)
+{
+
+ int headerStart = insertionPosition;
+
+ // clear old option header start
+ _pdu[headerStart] &= 0x00;
+
+ // set the option delta bytes
+ if(optionDelta<13)
+ {
+ _pdu[headerStart] |= (optionDelta << 4);
+ }
+ else if(optionDelta<269)
+ {
+ // 1 extra byte
+ _pdu[headerStart] |= 0xD0; // 13 in first nibble
+ _pdu[++insertionPosition] &= 0x00;
+ _pdu[insertionPosition] |= (optionDelta-13);
+ }
+ else
+ {
+ // 2 extra bytes, network byte order uint16_t
+ _pdu[headerStart] |= 0xE0; // 14 in first nibble
+ optionDelta -= 269;
+ uint8_t *to = &_pdu[++insertionPosition];
+ endian_store16(to, optionDelta);
+ insertionPosition += 1;
+ }
+
+ // set the option value length bytes
+ if(optionValueLength<13)
+ {
+ _pdu[headerStart] |= (optionValueLength & 0x000F);
+ }
+ else if(optionValueLength<269)
+ {
+ _pdu[headerStart] |= 0x0D; // 13 in second nibble
+ _pdu[++insertionPosition] &= 0x00;
+ _pdu[insertionPosition] |= (optionValueLength-13);
+ }
+ else
+ {
+ _pdu[headerStart] |= 0x0E; // 14 in second nibble
+ // this is in network byte order
+ printf("optionValueLength: %u",optionValueLength);
+ uint8_t *to = &_pdu[++insertionPosition];
+ optionValueLength -= 269;
+ endian_store16(to, optionValueLength);
+ insertionPosition += 1;
+ }
+
+ // and finally copy the option value itself
+ memcpy(&_pdu[++insertionPosition],optionValue,optionValueLength);
+
+ return 0;
+}
+
+void CoapPDU::getOptionValueById
+(
+ uint16_t optionNumber,
+ uint16_t *optionValueLength,
+ uint8_t *optionValuePointer
+)
+{
+ if(_numOptions == 0)
+ return;
+ CoapOption* options = getOptions();
+ int i = 0;
+ for(; i < _numOptions; i++)
+ {
+ if(options[i].optionNumber == optionNumber)
+ {
+ *optionValueLength = options[i].optionValueLength;
+ memcpy(optionValuePointer, options[i].optionValuePointer, options[i].optionValueLength);
+ }
+ }
+ free(options);
+}
+
+int CoapPDU::hasOption
+(
+ uint16_t optionNumber
+)
+{
+ int res = 0;
+ if(_numOptions == 0)
+ return res;
+ CoapOption* options = getOptions();
+ int i = 0;
+ for(; i < _numOptions; i++)
+ {
+ if(options[i].optionNumber == optionNumber)
+ {
+ res = 1;
+ break;
+ }
+ }
+ free(options);
+ return res;
+}
+
+const char *CoapPDU::printHuman()
+{
+ content.clear();
+ char temp1[128];
+
+ sprintf(temp1,"PDU is %d bytes long\r\n",_pduLength);
+ content.append(temp1);
+
+ sprintf(temp1,"CoAP Version: %d\r\n",getVersion());
+ content.append("Message Type: ");
+ switch(getType())
+ {
+ case COAP_CONFIRMABLE:
+ content.append("Confirmable");
+ break;
+
+ case COAP_NON_CONFIRMABLE:
+ content.append("Non-Confirmable");
+ break;
+
+ case COAP_ACKNOWLEDGEMENT:
+ content.append("Acknowledgement");
+ break;
+
+ case COAP_RESET:
+ content.append("Reset");
+ break;
+ }
+
+ sprintf(temp1,"\r\nToken length: %d\r\n",getTokenLength());
+ content.append(temp1);
+ content.append("Code: ");
+ switch(getCode())
+ {
+ case COAP_EMPTY:
+ content.append("0.00 Empty");
+ break;
+ case COAP_GET:
+ content.append("0.01 GET");
+ break;
+ case COAP_POST:
+ content.append("0.02 POST");
+ break;
+ case COAP_PUT:
+ content.append("0.03 PUT");
+ break;
+ case COAP_DELETE:
+ content.append("0.04 DELETE");
+ break;
+ case COAP_CREATED:
+ content.append("2.01 Created");
+ break;
+ case COAP_DELETED:
+ content.append("2.02 Deleted");
+ break;
+ case COAP_VALID:
+ content.append("2.03 Valid");
+ break;
+ case COAP_CHANGED:
+ content.append("2.04 Changed");
+ break;
+ case COAP_CONTENT:
+ content.append("2.05 Content");
+ break;
+ case COAP_CONTINUE:
+ content.append("2.31 Continue");
+ break;
+ case COAP_BAD_REQUEST:
+ content.append("4.00 Bad Request");
+ break;
+ case COAP_UNAUTHORIZED:
+ content.append("4.01 Unauthorized");
+ break;
+ case COAP_BAD_OPTION:
+ content.append("4.02 Bad Option");
+ break;
+ case COAP_FORBIDDEN:
+ content.append("4.03 Forbidden");
+ break;
+ case COAP_NOT_FOUND:
+ content.append("4.04 Not Found");
+ break;
+ case COAP_METHOD_NOT_ALLOWED:
+ content.append("4.05 Method Not Allowed");
+ break;
+ case COAP_NOT_ACCEPTABLE:
+ content.append("4.06 Not Acceptable");
+ break;
+ case COAP_PRECONDITION_FAILED:
+ content.append("4.12 Precondition Failed");
+ break;
+ case COAP_REQUEST_ENTITY_TOO_LARGE:
+ content.append("4.13 Request Entity Too Large");
+ break;
+ case COAP_UNSUPPORTED_CONTENT_FORMAT:
+ content.append("4.15 Unsupported Content-Format");
+ break;
+ case COAP_INTERNAL_SERVER_ERROR:
+ content.append("5.00 Internal Server Error");
+ break;
+ case COAP_NOT_IMPLEMENTED:
+ content.append("5.01 Not Implemented");
+ break;
+ case COAP_BAD_GATEWAY:
+ content.append("5.02 Bad Gateway");
+ break;
+ case COAP_SERVICE_UNAVAILABLE:
+ content.append("5.03 Service Unavailable");
+ break;
+ case COAP_GATEWAY_TIMEOUT:
+ content.append("5.04 Gateway Timeout");
+ break;
+ case COAP_PROXYING_NOT_SUPPORTED:
+ content.append("5.05 Proxying Not Supported");
+ break;
+ default:
+ sprintf(temp1, "Undefined Code %u",(unsigned)(getCode()));
+ content.append(temp1);
+
+ }
+
+ // print message ID
+ sprintf(temp1,"\r\nMessage ID: %u\r\n",getMessageID());
+ content.append(temp1);
+
+ // print token value
+ int tokenLength = getTokenLength();
+ uint8_t *tokenPointer = getPDUPointer()+COAP_HDR_SIZE;
+ if(tokenLength==0)
+ {
+ content.append("No token.\r\n");
+ }
+ else
+ {
+ //memset(temp1,0,50);
+ sprintf(temp1,"Token of %d bytes.\r\n",tokenLength);
+ content.append(temp1);
+ content.append("Value: 0x");
+ char temp2[5];
+ for(int j=0; j<tokenLength; j++)
+ {
+ sprintf(temp2,"%.2X",tokenPointer[j]);
+ content.append(temp2);
+ }
+ }
+
+ // print options
+ CoapPDU::CoapOption* options = getOptions();
+ if(options==NULL)
+ {
+ content.append("\r\nNO options");
+ }
+ else
+ {
+ //memset(temp1,0,50);
+ sprintf(temp1,"\r\n%d options:",_numOptions);
+ content.append(temp1);
+ }
+
+ for(int i=0; i<_numOptions; i++)
+ {
+ char optionTemp[128];
+ sprintf(optionTemp,"\r\nOPTION (%d/%d)\r\n"
+ "Option number (delta): %hu (%hu)\r\n"
+ "Name: "
+ ,i + 1,_numOptions,
+ options[i].optionNumber,options[i].optionDelta);
+ content.append(optionTemp);
+ boolean asString = FALSE;
+ switch(options[i].optionNumber)
+ {
+ case COAP_OPTION_IF_MATCH:
+ content.append("IF_MATCH");
+ break;
+ case COAP_OPTION_URI_HOST:
+ content.append("URI_HOST");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_ETAG:
+ content.append("ETAG");
+ break;
+ case COAP_OPTION_IF_NONE_MATCH:
+ content.append("IF_NONE_MATCH");
+ break;
+ case COAP_OPTION_OBSERVE:
+ content.append("OBSERVE");
+ break;
+ case COAP_OPTION_URI_PORT:
+ content.append("URI_PORT");
+ break;
+ case COAP_OPTION_LOCATION_PATH:
+ content.append("LOCATION_PATH");
+ break;
+ case COAP_OPTION_URI_PATH:
+ content.append("URI_PATH");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_CONTENT_FORMAT:
+ content.append("CONTENT_FORMAT");
+ break;
+ case COAP_OPTION_MAX_AGE:
+ content.append("MAX_AGE");
+ break;
+ case COAP_OPTION_URI_QUERY:
+ content.append("URI_QUERY");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_ACCEPT:
+ content.append("ACCEPT");
+ break;
+ case COAP_OPTION_LOCATION_QUERY:
+ content.append("LOCATION_QUERY");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_PROXY_URI:
+ content.append("PROXY_URI");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_PROXY_SCHEME:
+ content.append("PROXY_SCHEME");
+ asString = TRUE;
+ break;
+ case COAP_OPTION_BLOCK1:
+ content.append("BLOCK1");
+ break;
+ case COAP_OPTION_BLOCK2:
+ content.append("BLOCK2");
+ break;
+ case COAP_OPTION_SIZE1:
+ content.append("SIZE1");
+ break;
+ case COAP_OPTION_SIZE2:
+ content.append("SIZE2");
+ break;
+ default:
+ //memset(temp1,0,50);
+ sprintf(temp1,"Unknown option %u",(unsigned)options[i].optionNumber);
+ content.append(temp1);
+ break;
+ }
+ //memset(temp1,0,50);
+ sprintf(temp1,"\r\nValue length: %u\r\n",options[i].optionValueLength);
+ content.append(temp1);
+ if(asString)
+ {
+ content.append("Value: ");
+ }
+ else
+ {
+ content.append("Value: 0x");
+ }
+ char temp3[5];
+ for(int j=0; j<options[i].optionValueLength; j++)
+ {
+ if(asString)
+ {
+ char c = options[i].optionValuePointer[j];
+ if((c>='!'&&c<='~')||c==' ')
+ {
+ sprintf(temp3,"%c", c);
+ }
+ else
+ {
+ sprintf(temp3,"\\%.2d",c);
+ }
+ content.append(temp3);
+ }
+ else
+ {
+ sprintf(temp3,"%.2X",options[i].optionValuePointer[j]);
+ content.append(temp3);
+ }
+ }
+ }
+
+ // print payload
+ if(_payloadLength==0)
+ {
+ content.append("\r\nNo payload.\r\n");
+ }
+ else
+ {
+ //memset(temp1,0,50);
+ sprintf(temp1,"\r\nPayload of %d bytes\r\nValue: 0x",_payloadLength);
+ content.append(temp1);
+ char temp4[5];
+ for(int j=0; j<_payloadLength; j++)
+ {
+ sprintf(temp4,"%.2X",_payloadPointer[j]);
+ content.append(temp4);
+ }
+ content.append("\r\n");
+ }
+ if(options)
+ free(options);
+ return content.c_str();
+}
+
+const char * CoapPDU::printHex()
+{
+ content.clear();
+ char temp[5];
+ for(int i=0; i<_pduLength; i++)
+ {
+ sprintf(temp,"%.2X",_pdu[i]);
+ content.append(temp);
+ }
+ content.append("\r\n");
+ return content.c_str();
+}
+//#endif
diff --git a/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.h b/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.h
new file mode 100755
index 0000000..334301a
--- /dev/null
+++ b/mbtk/libmbtk_lib/coap/mbtk_coap_pdu.h
@@ -0,0 +1,288 @@
+
+#ifndef __MBTK_COAP_H__
+#define __MBTK_COAP_H__
+#include <stdint.h>
+//#include "ps_in.h"
+#include "ds_ASBuffer.h"
+#include "mbtk_type.h"
+
+#define COAP_HDR_SIZE 4
+#define COAP_OPTION_HDR_BYTE 1
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+//typedef unsigned long uint32_t;
+typedef unsigned long long uint64_t;
+
+/*
+enum ds_appsrv_mem_e_type { APPSRV_MEM };
+
+void* operator new(unsigned int size, void* alloc, ds_appsrv_mem_e_type mem_type) throw();
+void operator delete(void* obj, void* alloc, ds_appsrv_mem_e_type mem_type) throw();
+*/
+
+#define ps_ntohs(x) \
+ (((((uint16)(x) & 0x00FF) << 8) | (((uint16)(x) & 0xFF00) >> 8)))
+
+
+#define endian_be16(x) ps_ntohs(x)
+
+#define endian_load16(cast, from) ((cast)( \
+ (((uint16_t)((uint8_t*)(from))[0]) << 8) | \
+ (((uint16_t)((uint8_t*)(from))[1]) ) ))
+
+#define endian_load32(cast, from) ((cast)( \
+ (((uint32_t)((uint8_t*)(from))[0]) << 24) | \
+ (((uint32_t)((uint8_t*)(from))[1]) << 16) | \
+ (((uint32_t)((uint8_t*)(from))[2]) << 8) | \
+ (((uint32_t)((uint8_t*)(from))[3]) ) ))
+
+#define endian_load64(cast, from) ((cast)( \
+ (((uint64_t)((uint8_t*)(from))[0]) << 56) | \
+ (((uint64_t)((uint8_t*)(from))[1]) << 48) | \
+ (((uint64_t)((uint8_t*)(from))[2]) << 40) | \
+ (((uint64_t)((uint8_t*)(from))[3]) << 32) | \
+ (((uint64_t)((uint8_t*)(from))[4]) << 24) | \
+ (((uint64_t)((uint8_t*)(from))[5]) << 16) | \
+ (((uint64_t)((uint8_t*)(from))[6]) << 8) | \
+ (((uint64_t)((uint8_t*)(from))[7]) ) ))
+
+#define endian_store16(to, num) \
+ do { uint16_t val = endian_be16(num); memcpy(to, &val, 2); } while(0)
+
+// CoAP PDU format
+
+// 0 1 2 3
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |Ver| T | TKL | Code | Message ID |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Token (if any, TKL bytes) ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | Options (if any) ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |1 1 1 1 1 1 1 1| Payload (if any) ...
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+class CoapPDU
+{
+
+
+public:
+ /// CoAP message types. Note, values only work as enum.
+ enum Type
+ {
+ COAP_CONFIRMABLE=0x00,
+ COAP_NON_CONFIRMABLE=0x10,
+ COAP_ACKNOWLEDGEMENT=0x20,
+ COAP_RESET=0x30
+ };
+
+ // CoAP response codes.
+ enum Code
+ {
+ COAP_EMPTY=0x00,
+ COAP_GET,
+ COAP_POST,
+ COAP_PUT,
+ COAP_DELETE,
+ COAP_LASTMETHOD=0x1F,
+ COAP_CREATED=0x41,
+ COAP_DELETED,
+ COAP_VALID,
+ COAP_CHANGED,
+ COAP_CONTENT,
+ COAP_CONTINUE=0x5F,
+ COAP_BAD_REQUEST=0x80,
+ COAP_UNAUTHORIZED,
+ COAP_BAD_OPTION,
+ COAP_FORBIDDEN,
+ COAP_NOT_FOUND,
+ COAP_METHOD_NOT_ALLOWED,
+ COAP_NOT_ACCEPTABLE,
+ COAP_PRECONDITION_FAILED=0x8C,
+ COAP_REQUEST_ENTITY_TOO_LARGE=0x8D,
+ COAP_UNSUPPORTED_CONTENT_FORMAT=0x8F,
+ COAP_INTERNAL_SERVER_ERROR=0xA0,
+ COAP_NOT_IMPLEMENTED,
+ COAP_BAD_GATEWAY,
+ COAP_SERVICE_UNAVAILABLE,
+ COAP_GATEWAY_TIMEOUT,
+ COAP_PROXYING_NOT_SUPPORTED,
+ COAP_UNDEFINED_CODE=0xFF
+ };
+
+ /// CoAP option numbers.
+ enum Option
+ {
+ COAP_OPTION_IF_MATCH=1,
+ COAP_OPTION_URI_HOST=3,
+ COAP_OPTION_ETAG,
+ COAP_OPTION_IF_NONE_MATCH,
+ COAP_OPTION_OBSERVE,
+ COAP_OPTION_URI_PORT,
+ COAP_OPTION_LOCATION_PATH,
+ COAP_OPTION_URI_PATH=11,
+ COAP_OPTION_CONTENT_FORMAT,
+ COAP_OPTION_MAX_AGE=14,
+ COAP_OPTION_URI_QUERY,
+ COAP_OPTION_ACCEPT=17,
+ COAP_OPTION_LOCATION_QUERY=20,
+ COAP_OPTION_BLOCK2=23,
+ COAP_OPTION_BLOCK1=27,
+ COAP_OPTION_SIZE2,
+ COAP_OPTION_PROXY_URI=35,
+ COAP_OPTION_PROXY_SCHEME=39,
+ COAP_OPTION_SIZE1=60
+ };
+
+ /// CoAP content-formats.
+ enum ContentFormat
+ {
+ COAP_CONTENT_FORMAT_TEXT_PLAIN = 0,
+ COAP_CONTENT_FORMAT_APP_LINK = 40,
+ COAP_CONTENT_FORMAT_APP_XML,
+ COAP_CONTENT_FORMAT_APP_OCTET,
+ COAP_CONTENT_FORMAT_APP_EXI = 47,
+ COAP_CONTENT_FORMAT_APP_JSON = 50
+ };
+
+ /// Sequence of these is returned by CoapPDU::getOptions()
+ struct CoapOption
+ {
+ uint16_t optionDelta;
+ uint16_t optionNumber;
+ uint16_t optionValueLength;
+ int totalLength;
+ uint8_t *optionPointer;
+ uint8_t *optionValuePointer;
+ };
+
+ // construction and destruction
+ CoapPDU();
+ CoapPDU(uint8_t *buffer, int bufferLength, int pduLength);
+ ~CoapPDU();
+ int reset();
+ int validate();
+
+ // version
+ int setVersion(uint8_t version);
+ uint8_t getVersion();
+
+ // message type
+ void setType(int type);
+ int getType();
+
+ // tokens
+ int setTokenLength(uint8_t tokenLength);
+ int getTokenLength();
+ uint8_t* getTokenPointer();
+ int setToken(uint8_t *token, uint8_t tokenLength);
+
+ // message code
+ void setCode(int code);
+ int getCode();
+ int httpStatusToCode(int httpStatus);
+
+ // message ID
+ int setMessageID(uint16_t messageID);
+ uint16_t getMessageID();
+
+ // options
+ int addOption(uint16_t optionNumber, uint16_t optionLength, uint8_t *optionValue);
+ // gets a list of all options
+ CoapOption* getOptions();
+ int getNumOptions();
+ // shorthand helpers
+ int setURI(char *uri);
+ int setURI(char *uri, int urilen);
+ int getURI(char *dst, int dstlen, int *outLen);
+ int addURIQuery(char *query);
+
+ // content format helper
+ int setContentFormat(int format);
+
+ // payload
+ uint8_t* mallocPayload(int bytes);
+ int setPayload(uint8_t *value, int len);
+ uint8_t* getPayloadPointer();
+ int getPayloadLength();
+ uint8_t* getPayloadCopy();
+
+ // pdu
+ int getPDULength();
+ uint8_t* getPDUPointer();
+ void setPDULength(int len);
+ void getOptionValueById(uint16_t optionNumber, uint16_t *optionValueLength,uint8_t *optionValuePointer);
+ const char *printHuman();
+ const char * printHex();
+ int hasOption(uint16_t optionNumber);
+private:
+ // variables
+ uint8_t *_pdu;
+ int _pduLength;
+
+ int _constructedFromBuffer;
+ int _bufferLength;
+
+ uint8_t *_payloadPointer;
+ int _payloadLength;
+
+ int _numOptions;
+ uint16_t _maxAddedOptionNumber;
+ ASBuffer content;
+
+ // functions
+ void shiftPDUUp(int shiftOffset, int shiftAmount);
+ void shiftPDUDown(int startLocation, int shiftOffset, int shiftAmount);
+ uint8_t codeToValue(int c);
+
+ // option stuff
+ int findInsertionPosition(uint16_t optionNumber, uint16_t *prevOptionNumber);
+ int computeExtraBytes(uint16_t n);
+ int insertOption(int insertionPosition, uint16_t optionDelta, uint16_t optionValueLength, uint8_t *optionValue);
+ uint16_t getOptionDelta(uint8_t *option);
+ void setOptionDelta(int optionPosition, uint16_t optionDelta);
+ uint16_t getOptionValueLength(uint8_t *option);
+
+};
+
+/*
+#define COAP_CODE_EMPTY 0x00
+
+// method codes 0.01-0.31
+#define COAP_CODE_GET 0x01
+#define COAP_CODE_POST 0x02
+#define COAP_CODE_PUT 0x03
+#define COAP_CODE_DELETE 0x04
+
+// Response codes 2.00 - 5.31
+// 2.00 - 2.05
+#define COAP_CODE_CREATED 0x41
+#define COAP_CODE_DELETED 0x42
+#define COAP_CODE_VALID 0x43
+#define COAP_CODE_CHANGED 0x44
+#define COAP_CODE_CONTENT 0x45
+
+// 4.00 - 4.15
+#define COAP_CODE_BAD_REQUEST 0x80
+#define COAP_CODE_UNAUTHORIZED 0x81
+#define COAP_CODE_BAD_OPTION 0x82
+#define COAP_CODE_FORBIDDEN 0x83
+#define COAP_CODE_NOT_FOUND 0x84
+#define COAP_CODE_METHOD_NOT_ALLOWED 0x85
+#define COAP_CODE_NOT_ACCEPTABLE 0x86
+#define COAP_CODE_PRECONDITION_FAILED 0x8C
+#define COAP_CODE_REQUEST_ENTITY_TOO_LARGE 0x8D
+#define COAP_CODE_UNSUPPORTED_CONTENT_FORMAT 0x8F
+
+// 5.00 - 5.05
+#define COAP_CODE_INTERNAL_SERVER_ERROR 0xA0
+#define COAP_CODE_NOT_IMPLEMENTED 0xA1
+#define COAP_CODE_BAD_GATEWAY 0xA2
+#define COAP_CODE_SERVICE_UNAVAILABLE 0xA3
+#define COAP_CODE_GATEWAY_TIMEOUT 0xA4
+#define COAP_CODE_PROXYING_NOT_SUPPORTED 0xA5
+*/
+
+#endif
diff --git a/mbtk/libmbtk_lib/src/ds_ASBuffer.cpp b/mbtk/libmbtk_lib/common/ds_ASBuffer.cpp
similarity index 100%
rename from mbtk/libmbtk_lib/src/ds_ASBuffer.cpp
rename to mbtk/libmbtk_lib/common/ds_ASBuffer.cpp
diff --git a/mbtk/libmbtk_lib/src/ds_ASString.cpp b/mbtk/libmbtk_lib/common/ds_ASString.cpp
similarity index 100%
rename from mbtk/libmbtk_lib/src/ds_ASString.cpp
rename to mbtk/libmbtk_lib/common/ds_ASString.cpp
diff --git a/mbtk/libmbtk_lib/common/mbtk_adc.c b/mbtk/libmbtk_lib/common/mbtk_adc.c
new file mode 100755
index 0000000..55cce7c
--- /dev/null
+++ b/mbtk/libmbtk_lib/common/mbtk_adc.c
@@ -0,0 +1,102 @@
+/**
+ * \file mbtk_adc.c
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: js.wang <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-04-22
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_adc.h"
+
+int mbtk_adc_close(const char* adc_dev)
+{
+ int ret = 0;
+ int fd = 0;
+ char adc = '3';
+ //system("echo 3 > /sys/kernel/debug/adc");
+ if(adc_dev != NULL && !access(adc_dev, R_OK))
+ {
+ //LOGI("DEV:%s", ADC_DEVICE_803);
+ fd = open(adc_dev, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+
+ if(fd < 0) {
+ LOGE("[%s] file open error\n", __FUNCTION__);
+ return -2;
+ }
+ ret = write(fd, &adc, 1);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+ close(fd);
+ return 0;
+}
+
+int mbtk_adc_get(const char* adc_dev, mbtk_adc_enum channle)
+{
+ int ret = 0;
+ int fd = 0;
+ char adc_buf[24] = {0};
+ char *adc_value = NULL;
+ char adc =(channle == MBTK_ADC0 ? '0' : (channle == MBTK_ADC1 ? '1' : '2'));
+
+
+ if(adc_dev != NULL && !access(adc_dev, R_OK))
+ {
+ LOGI("[adc] DEV:%s", adc_dev);
+ fd = open(adc_dev, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices : %s", adc_dev ? adc_dev : "NULL");
+ return -1;
+ }
+
+ if(fd < 0) {
+ LOGE("[%s] file open error\n", __FUNCTION__);
+ return -2;
+ }
+ ret = write(fd, &adc, 1);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+ ret = read(fd, adc_buf, 24);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }else{
+ //LOGI("%s %d adc:%s\n", __FUNCTION__, __LINE__, adc_buf);
+ adc_value = strstr(adc_buf, "channel");
+ }
+ close(fd);
+ if(adc_value)
+ {
+ //LOGI("%s adc: %s\n", __FUNCTION__, adc_value);
+ }
+ else
+ return -2;
+
+ return atoi(&adc_value[9]);
+}
diff --git a/mbtk/libmbtk_lib/src/mbtk_alarm.c b/mbtk/libmbtk_lib/common/mbtk_alarm.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_alarm.c
rename to mbtk/libmbtk_lib/common/mbtk_alarm.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_at.c b/mbtk/libmbtk_lib/common/mbtk_at.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_at.c
rename to mbtk/libmbtk_lib/common/mbtk_at.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_bs_position.c b/mbtk/libmbtk_lib/common/mbtk_bs_position.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_bs_position.c
rename to mbtk/libmbtk_lib/common/mbtk_bs_position.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_debug.c b/mbtk/libmbtk_lib/common/mbtk_debug.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_debug.c
rename to mbtk/libmbtk_lib/common/mbtk_debug.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_device_info.c b/mbtk/libmbtk_lib/common/mbtk_device_info.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_device_info.c
rename to mbtk/libmbtk_lib/common/mbtk_device_info.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_file.c b/mbtk/libmbtk_lib/common/mbtk_file.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_file.c
rename to mbtk/libmbtk_lib/common/mbtk_file.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_gpio.c b/mbtk/libmbtk_lib/common/mbtk_gpio.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_gpio.c
rename to mbtk/libmbtk_lib/common/mbtk_gpio.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_list.c b/mbtk/libmbtk_lib/common/mbtk_list.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_list.c
rename to mbtk/libmbtk_lib/common/mbtk_list.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_log.c b/mbtk/libmbtk_lib/common/mbtk_log.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_log.c
rename to mbtk/libmbtk_lib/common/mbtk_log.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_map.c b/mbtk/libmbtk_lib/common/mbtk_map.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_map.c
rename to mbtk/libmbtk_lib/common/mbtk_map.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_mtd.c b/mbtk/libmbtk_lib/common/mbtk_mtd.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_mtd.c
rename to mbtk/libmbtk_lib/common/mbtk_mtd.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_ntp.c b/mbtk/libmbtk_lib/common/mbtk_ntp.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_ntp.c
rename to mbtk/libmbtk_lib/common/mbtk_ntp.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_queue.c b/mbtk/libmbtk_lib/common/mbtk_queue.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_queue.c
rename to mbtk/libmbtk_lib/common/mbtk_queue.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_str.c b/mbtk/libmbtk_lib/common/mbtk_str.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_str.c
rename to mbtk/libmbtk_lib/common/mbtk_str.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_task.c b/mbtk/libmbtk_lib/common/mbtk_task.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_task.c
rename to mbtk/libmbtk_lib/common/mbtk_task.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_utf.c b/mbtk/libmbtk_lib/common/mbtk_utf.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_utf.c
rename to mbtk/libmbtk_lib/common/mbtk_utf.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_utils.c b/mbtk/libmbtk_lib/common/mbtk_utils.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_utils.c
rename to mbtk/libmbtk_lib/common/mbtk_utils.c
diff --git a/mbtk/libmbtk_lib/src/mbtk_version.c b/mbtk/libmbtk_lib/common/mbtk_version.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/mbtk_version.c
rename to mbtk/libmbtk_lib/common/mbtk_version.c
diff --git a/mbtk/libmbtk_lib/src/ringbuffer.c b/mbtk/libmbtk_lib/common/ringbuffer.c
similarity index 100%
rename from mbtk/libmbtk_lib/src/ringbuffer.c
rename to mbtk/libmbtk_lib/common/ringbuffer.c
diff --git a/mbtk/libmbtk_lib/factory/gpio-define.h b/mbtk/libmbtk_lib/factory/gpio-define.h
new file mode 100755
index 0000000..36c497e
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/gpio-define.h
@@ -0,0 +1,133 @@
+/**
+ * \file gpio-define.h
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: Sniper <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-04-26
+ */
+
+#ifndef __GPIO_DEFINE_H__
+#define __GPIO_DEFINE_H__
+
+/*
+4组GPIO共128个GPIO,分别从GPIO_0到GPIO_127
+GPIO22位于0xd4019000这一组的BIT22
+
+GPIO0_BASE 0xD4019000
+GPIO1_BASE 0xD4019004
+GPIO2_BASE 0xD4019008
+GPIO3_BASE 0xD4019100
+ */
+/*
+MMC_CMD GPIO_41
+MMC_DATA0 GPIO_40
+MMC_DATA1 GPIO_39
+MMC_DATA2 GPIO_38
+MMC_DATA3 GPIO_37
+
+SD_DET GPIO_43
+WLAN_DAT3 GPIO_48
+
+
+*/
+#define GPIO_FUNC_MMC1_DAT3 0xD401E094
+#define GPIO_FUNC_MMC1_DAT2 0xD401E098
+#define GPIO_FUNC_MMC1_DAT1 0xD401E09C
+#define GPIO_FUNC_MMC1_DAT0 0xD401E0A0
+#define GPIO_FUNC_MMC1_CMD 0xD401E0A4
+#define GPIO_FUNC_MMC1_CLK 0xD401E0A8
+#define GPIO_FUNC_MMC1_CD 0xD401E0AC
+#define GPIO_FUNC_USB_ID 0xD401E0B0
+#define GPIO_FUNC_PRI_TDI 0xD401E0B4
+#define GPIO_FUNC_PRI_TMS 0xD401E0B8
+#define GPIO_FUNC_PRI_TCK 0xD401E0BC
+#define GPIO_FUNC_PRI_TDO 0xD401E0C0
+#define GPIO_FUNC_QSPI_VMODE_GPIO 0xD401E0C4
+#define GPIO_FUNC_VBUS_DRV 0xD401E0C8
+#define GPIO_FUNC_CLK_REQ 0xD401E0CC
+#define GPIO_FUNC_VCXO_REQ 0xD401E0D4
+#define GPIO_FUNC_VCXO_OUT 0xD401E0D8
+#define GPIO_FUNC_GPIO_00 0xD401E0DC
+#define GPIO_FUNC_GPIO_01 0xD401E0E0
+#define GPIO_FUNC_GPIO_02 0xD401E0E4
+#define GPIO_FUNC_GPIO_03 0xD401E0E8
+#define GPIO_FUNC_GPIO_04 0xD401E0EC
+#define GPIO_FUNC_GPIO_05 0xD401E0F0
+#define GPIO_FUNC_GPIO_06 0xD401E0F4
+#define GPIO_FUNC_GPIO_07 0xD401E0F8
+#define GPIO_FUNC_GPIO_08 0xD401E0FC
+#define GPIO_FUNC_GPIO_09 0xD401E100
+#define GPIO_FUNC_GPIO_10 0xD401E104
+#define GPIO_FUNC_GPIO_11 0xD401E108
+#define GPIO_FUNC_GPIO_12 0xD401E10C
+#define GPIO_FUNC_GPIO_13 0xD401E110
+#define GPIO_FUNC_GPIO_14 0xD401E114
+#define GPIO_FUNC_GPIO_15 0xD401E118
+#define GPIO_FUNC_GPIO_16 0xD401E11C
+#define GPIO_FUNC_GPIO_17 0xD401E120
+#define GPIO_FUNC_GPIO_18 0xD401E124
+#define GPIO_FUNC_GPIO_19 0xD401E128
+#define GPIO_FUNC_GPIO_20 0xD401E12C
+#define GPIO_FUNC_GPIO_21 0xD401E130
+#define GPIO_FUNC_GPIO_22 0xD401E134
+#define GPIO_FUNC_GPIO_23 0xD401E138
+#define GPIO_FUNC_GPIO_24 0xD401E13C
+#define GPIO_FUNC_GPIO_25 0xD401E140
+#define GPIO_FUNC_GPIO_26 0xD401E144
+#define GPIO_FUNC_GPIO_27 0xD401E148
+#define GPIO_FUNC_GPIO_28 0xD401E14C
+#define GPIO_FUNC_GPIO_29 0xD401E150
+#define GPIO_FUNC_GPIO_30 0xD401E154
+#define GPIO_FUNC_GPIO_31 0xD401E158
+#define GPIO_FUNC_GPIO_32 0xD401E15C
+#define GPIO_FUNC_GPIO_33 0xD401E160
+#define GPIO_FUNC_GPIO_34 0xD401E164
+#define GPIO_FUNC_GPIO_35 0xD401E168
+#define GPIO_FUNC_GPIO_36 0xD401E16C
+#define GPIO_FUNC_GPIO_49 0xD401E1A0
+#define GPIO_FUNC_GPIO_50 0xD401E1A4
+#define GPIO_FUNC_GPIO_51 0xD401E1A8
+#define GPIO_FUNC_GPIO_52 0xD401E1AC
+#define GPIO_FUNC_GPIO_53 0xD401E1B0
+#define GPIO_FUNC_GPIO_54 0xD401E1B4
+#define GPIO_FUNC_DVL_0 0xD401E2B4
+#define GPIO_FUNC_DVL_1 0xD401E2B8
+#define GPIO_FUNC_GPIO_69 0xD401E2BC
+#define GPIO_FUNC_GPIO_70 0xD401E2C0
+#define GPIO_FUNC_QSPI_DAT3 0xD401E2C4
+#define GPIO_FUNC_QSPI_DAT2 0xD401E2C8
+#define GPIO_FUNC_QSPI_DAT1 0xD401E2CC
+#define GPIO_FUNC_QSPI_DAT0 0xD401E2D0
+#define GPIO_FUNC_QSPI_CLK 0xD401E2D4
+#define GPIO_FUNC_QSPI_CS1 0xD401E2D8
+#define GPIO_FUNC_GPIO_77 0xD401E2DC
+#define GPIO_FUNC_GPIO_78 0xD401E2E0
+#define GPIO_FUNC_GPIO_79 0xD401E2E4
+#define GPIO_FUNC_GPIO_80 0xD401E2E8
+#define GPIO_FUNC_SDIO_DAT3 0xD401E2EC
+#define GPIO_FUNC_SDIO_DAT2 0xD401E2F0
+#define GPIO_FUNC_SDIO_DAT1 0xD401E2F4
+#define GPIO_FUNC_SDIO_DAT0 0xD401E2F8
+#define GPIO_FUNC_SDIO_CMD 0xD401E2FC
+#define GPIO_FUNC_SDIO_CLK 0xD401E300
+#define GPIO_FUNC_GPIO_60 0xD401E304
+#define GPIO_FUNC_USIM_UCLK 0xD401E320
+#define GPIO_FUNC_USIM_UIO 0xD401E324
+#define GPIO_FUNC_USIM_URSTn 0xD401E328
+
+
+#define GPIO0_BASE 0xD4019000
+#define GPIO1_BASE 0xD4019004
+#define GPIO2_BASE 0xD4019008
+#define GPIO3_BASE 0xD4019100
+
+struct gpio_register_function
+{
+ int reg;
+ int func_gpio; // 第 [func_gpio] 功能为 GPIO
+};
+
+
+#endif /*__GPIO_DEFINE_H__*/
diff --git a/mbtk/libmbtk_lib/factory/mbtk_adc.c b/mbtk/libmbtk_lib/factory/mbtk_adc.c
new file mode 100755
index 0000000..90a48e2
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_adc.c
@@ -0,0 +1,171 @@
+/**
+ * \file mbtk_adc.c
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: js.wang <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-04-22
+ */
+#include <fcntl.h>
+#include <stdint.h>
+#include <limits.h>
+#include <termios.h>
+#include <stdarg.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <sys/types.h>
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_adc.h"
+
+#define ADC_DEVICE_802 "/sys/devices/soc.0/d4000000.apb/pxa2xx-i2c.2/i2c-2/2-0030/pm802-bat/adc"
+#define ADC_DEVICE_803 "/sys/kernel/debug/adc"
+#define ADC_DEVICE_PMIC802 "/sys/devices/platform/asr-adc/pm80x_adc"
+#define ADC_DEVICE_AUX "/sys/devices/platform/asr-adc/aux_adc"
+
+int mbtk_adc_close(void)
+{
+ int ret = 0;
+ int fd = 0;
+ char adc = '3';
+ //system("echo 3 > /sys/kernel/debug/adc");
+ if(!access(ADC_DEVICE_803, R_OK))
+ {
+ //LOGI("DEV:%s", ADC_DEVICE_803);
+ fd = open(ADC_DEVICE_803, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+
+ if(fd < 0) {
+ LOGE("[%s] file open error\n", __FUNCTION__);
+ return -2;
+ }
+ ret = write(fd, &adc, 1);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+ close(fd);
+ return 0;
+}
+
+int mbtk_adc_get(mbtk_adc_enum channle)
+{
+ int ret = 0;
+ int fd = 0;
+ char adc_buf[24] = {0};
+ char *adc_value = NULL;
+ char adc =(channle == MBTK_ADC0 ? '0' : (channle == MBTK_ADC1 ? '1' : '2'));
+
+#if defined(MBTK_PROJECT_L508_X6)
+ switch(channle)
+ {
+ case MBTK_ADC0:
+ case MBTK_ADC1:
+ {
+ if(!access(ADC_DEVICE_PMIC802, R_OK))
+ {
+ LOGI("[adc] DEV:%s", ADC_DEVICE_PMIC802);
+ fd = open(ADC_DEVICE_PMIC802, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+ break;
+ }
+ case MBTK_ADC2:
+ {
+ if(!access(ADC_DEVICE_AUX, R_OK))
+ {
+ LOGI("[adc] DEV:%s", ADC_DEVICE_AUX);
+ fd = open(ADC_DEVICE_AUX, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+ break;
+ }
+ default:
+ {
+ LOGE("channle is error.");
+ return -1;
+ }
+ }
+#elif defined(MBTK_PROJECT_T108)
+ if(!access(ADC_DEVICE_AUX, R_OK))
+ {
+ LOGI("[adc] DEV:%s", ADC_DEVICE_AUX);
+ fd = open(ADC_DEVICE_AUX, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+#else
+#if 0
+ if(!access(ADC_DEVICE_802, R_OK)) {
+ //LOGI("DEV:%s", ADC_DEVICE_802);
+ fd = open(ADC_DEVICE_802, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ } else {
+ if(!access(ADC_DEVICE_803, R_OK)) {
+ //LOGI("DEV:%s", ADC_DEVICE_803);
+ fd = open(ADC_DEVICE_803, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ } else {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+ }
+#endif
+ if(!access(ADC_DEVICE_PMIC802, R_OK))
+ {
+ //LOGI("DEV:%s", ADC_DEVICE_803);
+ fd = open(ADC_DEVICE_PMIC802, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ }
+ else
+ {
+ LOGE("No found ADC devices.");
+ return -1;
+ }
+#endif
+
+ if(fd < 0) {
+ LOGE("[%s] file open error\n", __FUNCTION__);
+ return -2;
+ }
+ ret = write(fd, &adc, 1);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+ ret = read(fd, adc_buf, 24);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }else{
+ //LOGI("%s %d adc:%s\n", __FUNCTION__, __LINE__, adc_buf);
+ adc_value = strstr(adc_buf, "channel");
+ }
+ close(fd);
+ if(adc_value)
+ {
+ //LOGI("%s adc: %s\n", __FUNCTION__, adc_value);
+ }
+ else
+ return -2;
+
+ return atoi(&adc_value[9]);
+}
diff --git a/mbtk/libmbtk_lib/factory/mbtk_audio.c b/mbtk/libmbtk_lib/factory/mbtk_audio.c
new file mode 100755
index 0000000..fd0f640
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_audio.c
@@ -0,0 +1,77 @@
+#include "mbtk_log.h"
+#include "mbtk_audio2.h"
+#include "mbtk_audio_ubus.h"
+
+#define AUD_DEMO_WAV "/user_data/demo.wav"
+
+int mbtk_at_loopback(int type)
+{
+ LOGD("mbtk_at_loopback() : type - %d", type);
+ if(0 == type) // Stop
+ {
+ if(mbtk_audio_loopback_stop()) {
+ return -1;
+ }
+
+ mbtk_audio_ubus_deinit();
+ }
+ else // Start
+ {
+ mbtk_audio_ubus_init();
+
+ mbtk_audio_mode_set(0);
+ mbtk_audio_loopback_start(2);
+ }
+
+ return 0;
+}
+
+int mbtk_at_play(const char *args)
+{
+ int ret = 0;
+ if(mbtk_audio_wav_init()) {
+ LOGE("mbtk_audio_wav_init() fail.");
+ return -1;
+ }
+
+ if(mbtk_audio_wav_play_start(AUD_DEMO_WAV)) {
+ LOGE("mbtk_audio_wav_play_start() fail.");
+ ret = -1;
+ goto exit;
+ }
+
+ sleep(5);
+
+exit:
+ if(mbtk_audio_wav_deinit()) {
+ LOGE("mbtk_audio_wav_deinit() fail.");
+ return -1;
+ }
+
+ return ret;
+}
+
+int mbtk_at_rec(const char *args)
+{
+ int ret = 0;
+ if(mbtk_audio_wav_init()) {
+ LOGE("mbtk_audio_wav_init() fail.");
+ return -1;
+ }
+
+ if(mbtk_audio_wav_recorder_start(AUD_DEMO_WAV, MBTK_AUDIO_SAMPLE_RATE_8000)) {
+ LOGE("mbtk_audio_wav_recorder_start() fail.");
+ ret = -1;
+ goto exit;
+ }
+
+ sleep(5);
+
+exit:
+ if(mbtk_audio_wav_deinit()) {
+ LOGE("mbtk_audio_wav_deinit() fail.");
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/mbtk/libmbtk_lib/factory/mbtk_basic_at_wrapper.c b/mbtk/libmbtk_lib/factory/mbtk_basic_at_wrapper.c
new file mode 100755
index 0000000..8a96d24
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_basic_at_wrapper.c
@@ -0,0 +1,26 @@
+#include "mbtk_adc.h"
+#include "mbtk_log.h"
+
+int mbtk_at_adc(int value)
+{
+ if(0 != value && 1 != value && 2 != value){
+ return -1;
+ }
+
+#if (defined(MBTK_PROJECT_L508_X6) || defined(MBTK_PROJECT_T108))
+ //NULL
+#else
+ if(value == 2)
+ {
+ return mbtk_adc_close();
+ }
+#endif
+
+ return mbtk_adc_get((mbtk_adc_enum)value);
+}
+
+void mbtk_factory_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_factory_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/factory/mbtk_gpio.c b/mbtk/libmbtk_lib/factory/mbtk_gpio.c
new file mode 100755
index 0000000..7837453
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_gpio.c
@@ -0,0 +1,1999 @@
+/**
+ * \file gpio-test.c
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: Sniper <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-04-26
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/mount.h>
+#include "mbtk_log.h"
+#include <sys/mman.h>
+#include <ctype.h>
+#include <cutils/properties.h>
+#include "mbtk_gpio_def.h"
+#include "gpio-define.h"
+#include "mbtk_type.h"
+
+#define gpio_log(...) if(gpio_debug)printf(__VA_ARGS__)
+#define HWMAP_DEVICE "/dev/hwmap"
+#define PAGE_OFFS_BITS(pgsz) ((unsigned int)(pgsz)-1)
+#define PAGE_MASK_BITS(pgsz) (~PAGE_OFFS_BITS(pgsz))
+#define STR_MAX_LEN 220
+typedef enum {
+ MBTK_ADC0 = 0, /* ADC 0 */
+ MBTK_ADC1 /* ADC 1 */
+} mbtk_adc_enum;
+
+static int gpio_debug = 0;
+#define DEBUG_GPIO_TEST 1
+
+/**/
+#define GPIO_MAX_CURRENT (7<<10) //设置GPIO最大输出电流
+#define GPIO_STRONG_PULLUP (1<<3) //设置GPIO强上拉
+#define GPIO_PULLUP_ENABLE ((1<<15)|(1<<14)) //GPIO上拉
+#define GPIO_PULLDOWN_ENABLE ((1<<15)|1<<13) //GPIO下拉
+
+#define MBTK_GPIO_OUTPUT 1
+#define MBTK_GPIO_INPUT 0
+
+#if (defined(MBTK_PROJECT_L508_X6) || defined(MBTK_PROJECT_T108))
+struct gpio_register_function gpio_func_register[128] = {
+ {GPIO_FUNC_GPIO_00, 0},
+ {GPIO_FUNC_GPIO_01, 0},
+ {GPIO_FUNC_GPIO_02, 0},
+ {GPIO_FUNC_GPIO_03, 0},
+ {GPIO_FUNC_GPIO_04, 0},
+ {GPIO_FUNC_GPIO_05, 0},
+ {GPIO_FUNC_GPIO_06, 0},
+ {GPIO_FUNC_GPIO_07, 0},
+ {GPIO_FUNC_GPIO_08, 0},
+ {GPIO_FUNC_GPIO_09, 0},
+ {GPIO_FUNC_GPIO_10, 0},
+ {GPIO_FUNC_GPIO_11, 0},
+ {GPIO_FUNC_GPIO_12, 0},
+ {GPIO_FUNC_GPIO_13, 0},
+ {GPIO_FUNC_GPIO_14, 0},
+ {GPIO_FUNC_GPIO_15, 0},
+ {GPIO_FUNC_GPIO_16, 0},
+ {GPIO_FUNC_GPIO_17, 0},
+ {GPIO_FUNC_GPIO_18, 0},
+ {GPIO_FUNC_GPIO_19, 0},
+ {GPIO_FUNC_GPIO_20, 0},
+ {GPIO_FUNC_GPIO_21, 0},
+ {GPIO_FUNC_GPIO_22, 0},
+ {GPIO_FUNC_GPIO_23, 0},
+ {GPIO_FUNC_GPIO_24, 0},
+ {GPIO_FUNC_GPIO_25, 0},
+ {GPIO_FUNC_GPIO_26, 0},
+ {GPIO_FUNC_GPIO_27, 0},
+ {GPIO_FUNC_GPIO_28, 0},
+ {GPIO_FUNC_GPIO_29, 0},
+ {GPIO_FUNC_GPIO_30, 0},
+ {GPIO_FUNC_GPIO_31, 0},
+ {GPIO_FUNC_GPIO_32, 0},
+ {GPIO_FUNC_GPIO_33, 0},
+ {GPIO_FUNC_GPIO_34, 0},
+ {GPIO_FUNC_GPIO_35, 0},
+ {GPIO_FUNC_GPIO_36, 0},
+ {GPIO_FUNC_GPIO_37, 0}, // GPIO_37
+ {GPIO_FUNC_GPIO_38, 0}, // GPIO_38
+ {GPIO_FUNC_GPIO_39, 0}, // GPIO_39
+ {GPIO_FUNC_GPIO_40, 0}, // GPIO_40
+ {GPIO_FUNC_GPIO_41, 0}, //GPIO_41
+ {GPIO_FUNC_GPIO_42, 0}, //GPIO_42
+ {GPIO_FUNC_GPIO_43, 0}, //GPIO_43
+ {GPIO_FUNC_GPIO_44,0}, //GPIO_44
+ {GPIO_FUNC_GPIO_45,0}, //GPIO_45
+ {GPIO_FUNC_GPIO_46,0}, //GPIO_46
+ {GPIO_FUNC_GPIO_47,0}, //GPIO_47
+ {GPIO_FUNC_SDIO_DAT3, 1}, //GPIO_48
+ {GPIO_FUNC_GPIO_49, 0},
+ {GPIO_FUNC_GPIO_50, 0},
+ {GPIO_FUNC_GPIO_51, 0},
+ {GPIO_FUNC_GPIO_52, 0},
+ {GPIO_FUNC_GPIO_53, 0},
+ {GPIO_FUNC_GPIO_54, 0},
+ {GPIO_FUNC_SDIO_DAT2, 1}, //GPIO_55
+ {GPIO_FUNC_SDIO_DAT1, 1}, //GPIO_56
+ {GPIO_FUNC_SDIO_DAT0, 1}, //GPIO_57
+ {GPIO_FUNC_SDIO_CMD, 1}, //GPIO_58
+ {GPIO_FUNC_SDIO_CLK, 1}, //GPIO_59
+ {GPIO_FUNC_GPIO_60, 0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},
+ {GPIO_FUNC_DVL_0, 1},//GPIO_67
+ {GPIO_FUNC_DVL_1, 1},//GPIO_68
+ {GPIO_FUNC_GPIO_69, 0},
+ {GPIO_FUNC_GPIO_70, 0},
+ {GPIO_FUNC_QSPI_DAT3, 1}, //GPIO_71
+ {GPIO_FUNC_QSPI_DAT2, 1}, //GPIO_72
+ {GPIO_FUNC_QSPI_DAT1, 1}, //GPIO_73
+ {GPIO_FUNC_QSPI_DAT0, 1}, //GPIO_74
+ {GPIO_FUNC_QSPI_CLK, 1}, //GPIO_75
+ {GPIO_FUNC_QSPI_CS1, 1}, //GPIO_76
+ {GPIO_FUNC_GPIO_77, 0},
+ {GPIO_FUNC_GPIO_78, 0},
+ {GPIO_FUNC_GPIO_79, 0},
+ {GPIO_FUNC_GPIO_80, 0},
+ {GPIO_FUNC_USIM_UCLK, 1},//GPIO_81
+ {GPIO_FUNC_USIM_UIO, 1},//GPIO_82
+ {GPIO_FUNC_USIM_URSTn, 1},//GPIO_83
+
+ {GPIO_FUNC_MMC1_DAT3,5}, //GPIO_84
+ {GPIO_FUNC_MMC1_DAT2,5}, //GPIO_85
+ {GPIO_FUNC_MMC1_DAT1,5}, //GPIO_86
+ {GPIO_FUNC_MMC1_DAT0,5}, //GPIO_87
+ {GPIO_FUNC_MMC1_CMD,5}, //GPIO_88
+ {GPIO_FUNC_MMC1_CLK,5}, //GPIO_89
+ {GPIO_FUNC_MMC1_CD,1}, //GPIO_90
+ {0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},
+ {GPIO_FUNC_USB_ID, 1},//GPIO_99
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},
+ {GPIO_FUNC_PRI_TDI, 1}, //GPIO_117
+ {GPIO_FUNC_PRI_TMS, 1}, //GPIO_118
+ {GPIO_FUNC_PRI_TCK, 1}, //GPIO_119
+ {GPIO_FUNC_PRI_TDO, 1}, //GPIO_120
+ {GPIO_FUNC_QSPI_VMODE_GPIO, 1}, //GPIO_121
+ {GPIO_FUNC_VBUS_DRV, 1}, //GPIO_122
+ {GPIO_FUNC_CLK_REQ, 1}, //GPIO_123
+ {0,0},
+ {GPIO_FUNC_VCXO_REQ, 1}, //GPIO_125
+ {0,0}, //GPIO_126
+ {GPIO_FUNC_VCXO_OUT, 1}, //GPIO_127
+ {0,0},
+};
+
+#else
+struct gpio_register_function gpio_func_register[128] = {
+ {GPIO_FUNC_GPIO_00, 0},
+ {GPIO_FUNC_GPIO_01, 0},
+ {GPIO_FUNC_GPIO_02, 0},
+ {GPIO_FUNC_GPIO_03, 0},
+ {GPIO_FUNC_GPIO_04, 0},
+ {GPIO_FUNC_GPIO_05, 0},
+ {GPIO_FUNC_GPIO_06, 0},
+ {GPIO_FUNC_GPIO_07, 0},
+ {GPIO_FUNC_GPIO_08, 0},
+ {GPIO_FUNC_GPIO_09, 0},
+ {GPIO_FUNC_GPIO_10, 0},
+ {GPIO_FUNC_GPIO_11, 0},
+ {GPIO_FUNC_GPIO_12, 0},
+ {GPIO_FUNC_GPIO_13, 0},
+ {GPIO_FUNC_GPIO_14, 0},
+ {GPIO_FUNC_GPIO_15, 0},
+ {GPIO_FUNC_GPIO_16, 0},
+ {GPIO_FUNC_GPIO_17, 0},
+ {GPIO_FUNC_GPIO_18, 0},
+ {GPIO_FUNC_GPIO_19, 0},
+ {GPIO_FUNC_GPIO_20, 0},
+ {GPIO_FUNC_GPIO_21, 0},
+ {GPIO_FUNC_GPIO_22, 0},
+ {GPIO_FUNC_GPIO_23, 0},
+ {GPIO_FUNC_GPIO_24, 0},
+ {GPIO_FUNC_GPIO_25, 0},
+ {GPIO_FUNC_GPIO_26, 0},
+ {GPIO_FUNC_GPIO_27, 0},
+ {GPIO_FUNC_GPIO_28, 0},
+ {GPIO_FUNC_GPIO_29, 0},
+ {GPIO_FUNC_GPIO_30, 0},
+ {GPIO_FUNC_GPIO_31, 0},
+ {GPIO_FUNC_GPIO_32, 0},
+ {GPIO_FUNC_GPIO_33, 0},
+ {GPIO_FUNC_GPIO_34, 0},
+ {GPIO_FUNC_GPIO_35, 0},
+ {GPIO_FUNC_GPIO_36, 0},
+ {GPIO_FUNC_MMC1_DAT3, 5}, // GPIO_37
+ {GPIO_FUNC_MMC1_DAT2, 5}, // GPIO_38
+ {GPIO_FUNC_MMC1_DAT1, 5}, // GPIO_39
+ {GPIO_FUNC_MMC1_DAT0, 5}, // GPIO_40
+ {GPIO_FUNC_MMC1_CMD, 5}, //GPIO_41
+ {GPIO_FUNC_MMC1_CLK, 5}, //GPIO_42
+ {GPIO_FUNC_MMC1_CD , 1}, //GPIO_43
+ {0,0},{0,0},{0,0},{0,0},
+ {GPIO_FUNC_SDIO_DAT3, 1}, //GPIO_48
+ {GPIO_FUNC_GPIO_49, 0},
+ {GPIO_FUNC_GPIO_50, 0},
+ {GPIO_FUNC_GPIO_51, 0},
+ {GPIO_FUNC_GPIO_52, 0},
+ {GPIO_FUNC_GPIO_53, 0},
+ {GPIO_FUNC_GPIO_54, 0},
+ {GPIO_FUNC_SDIO_DAT2, 1}, //GPIO_55
+ {GPIO_FUNC_SDIO_DAT1, 1}, //GPIO_56
+ {GPIO_FUNC_SDIO_DAT0, 1}, //GPIO_57
+ {GPIO_FUNC_SDIO_CMD, 1}, //GPIO_58
+ {GPIO_FUNC_SDIO_CLK, 1}, //GPIO_59
+ {GPIO_FUNC_GPIO_60, 0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},
+ {GPIO_FUNC_DVL_0, 1},//GPIO_67
+ {GPIO_FUNC_DVL_1, 1},//GPIO_68
+ {GPIO_FUNC_GPIO_69, 0},
+ {GPIO_FUNC_GPIO_70, 0},
+ {GPIO_FUNC_QSPI_DAT3, 1}, //GPIO_71
+ {GPIO_FUNC_QSPI_DAT2, 1}, //GPIO_72
+ {GPIO_FUNC_QSPI_DAT1, 1}, //GPIO_73
+ {GPIO_FUNC_QSPI_DAT0, 1}, //GPIO_74
+ {GPIO_FUNC_QSPI_CLK, 1}, //GPIO_75
+ {GPIO_FUNC_QSPI_CS1, 1}, //GPIO_76
+ {GPIO_FUNC_GPIO_77, 0},
+ {GPIO_FUNC_GPIO_78, 0},
+ {GPIO_FUNC_GPIO_79, 0},
+ {GPIO_FUNC_GPIO_80, 0},
+ {GPIO_FUNC_USIM_UCLK, 1},//GPIO_81
+ {GPIO_FUNC_USIM_UIO, 1},//GPIO_82
+ {GPIO_FUNC_USIM_URSTn, 1},//GPIO_83
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},
+ {GPIO_FUNC_USB_ID, 1},//GPIO_99
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},{0,0},{0,0},{0,0},
+ {0,0},
+ {GPIO_FUNC_PRI_TDI, 1}, //GPIO_117
+ {GPIO_FUNC_PRI_TMS, 1}, //GPIO_118
+ {GPIO_FUNC_PRI_TCK, 1}, //GPIO_119
+ {GPIO_FUNC_PRI_TDO, 1}, //GPIO_120
+ {GPIO_FUNC_QSPI_VMODE_GPIO, 1}, //GPIO_121
+ {GPIO_FUNC_VBUS_DRV, 1}, //GPIO_122
+ {GPIO_FUNC_CLK_REQ, 1}, //GPIO_123
+ {0,0},
+ {GPIO_FUNC_VCXO_REQ, 1}, //GPIO_125
+ {GPIO_FUNC_VCXO_OUT, 1}, //GPIO_126
+ {0,0},
+};
+
+#endif
+
+static int mbtk_gpio_adc(channel)
+{
+ int ret = 0;
+
+ ret = mbtk_adc_get(channel);
+#if DEBUG_GPIO_TEST
+ printf("ADC_%d_value =%d\n", channel, ret);
+#endif
+ if(ret >= 500 ){ //TODO: 各项目高电平标准?
+ ret = 1;
+ }
+ else if (ret>=0 && ret<=480){
+ ret = 0;
+ }
+ else{
+ ret = -1;
+ }
+ return ret;
+}
+
+
+static int hwacc_register(int rw, unsigned int addr, unsigned int *data)
+{
+ int fid;
+ unsigned int pagesize, len, len_aligned;
+ unsigned int addr_aligned;
+ volatile unsigned int *pa;
+ void *vpa;
+
+ len = pagesize = sysconf(_SC_PAGESIZE);
+ if((fid = open(HWMAP_DEVICE, O_RDWR)) < 0)
+ {
+ printf("Failed to open %s\n", HWMAP_DEVICE);
+ exit(-1);
+ }
+
+ // Align the length so the mapped area is page-aligned and contains the requested area
+ addr_aligned = addr & PAGE_MASK_BITS(pagesize);
+ len_aligned =((addr + len - addr_aligned) + pagesize - 1) & PAGE_MASK_BITS(pagesize);
+
+ /* Notes on flags: MAP_PRIVATE results in copy on write; MAP_SHARED allows normal write */
+ /* MAP_SHARED required O_RDWR in open above, otherwise mmap fails with errno=EACCES */
+ /* Notes on prot: PROT_WRITE allows read and write; PROT_READ allows read only */
+ /* Notes on off: an unsigned 32-bit value, should be aligned to page size according to mmap manpage */
+ if((vpa = mmap(0, len_aligned, PROT_READ|PROT_WRITE, MAP_SHARED, fid, addr_aligned)) == MAP_FAILED)
+ {
+ printf("mmap failed (%d)\n", errno);
+ }
+ else
+ {
+ pa = (volatile unsigned int *)((unsigned char *)vpa + (addr & PAGE_OFFS_BITS(pagesize)));
+ if(rw == 0)
+ {
+ *data = *pa;
+ gpio_log("Value read from 0x%.8x via MVA=0x%p is 0x%.8x\n", addr, pa, *data);
+ }
+ else if(rw == 1)
+ {
+ *pa = *data;
+ gpio_log("Value %.8x written to 0x%.8x via MVA=0x%p\n", *data, addr, pa);
+#if defined(HWACC_DEBUG)
+ {
+ unsigned int val;
+ val = *pa;
+ printf("Value read from 0x%.8x via MVA=0x%p is 0x%.8x\n", addr, pa, val);
+ }
+#endif
+ }
+ munmap(vpa, len);
+ }
+
+ close(fid);
+ return 0;
+}
+/*
+设置GPIO 模式:第一步读GPIO22默认function
+root@OpenWrt:/# hwacc r 0xd401e134
+Option = r Addr = d401e134
+Value read from 0xd401e134 via MVA=0x0xb6fc3134 is 0x0000d040 //默认GPIO功能
+Bit0~bit2值对应上面表格各function,0代表GPIO功能
+ */
+static int gpio_register_read(int reg)
+{
+ int ret = -1;
+#if 0
+ FILE * fp;
+ // "/bin/hwacc r 0xd401e134";
+ char command[36] = {0};
+ char buffer[1024];
+ int i = 0;
+
+ sprintf(command, "/bin/hwacc r 0x%x", reg);
+ fp = popen(command, "r");
+ while(1)
+ {
+ if( fgets (buffer, sizeof(buffer), fp)!=NULL ) {
+ buffer[strlen(buffer) - 1] = 0;
+ // gpio_log("out [%d]: %s\n", strlen(buffer), buffer);
+ }else{
+ break;
+ }
+ i = strstr_n(buffer, "is");
+ if(i)
+ {
+ ret = str_to_hex(&buffer[i + 2]);
+ gpio_log("read 0x%x value:%s, %x\n", reg, &buffer[i + 2], ret);
+ }
+ }
+ pclose(fp);
+#else
+#ifndef MBTK_PROJECT_PN1803
+ usleep(50);
+#endif
+ hwacc_register(0, reg, &ret);
+#ifndef MBTK_PROJECT_PN1803
+ usleep(50);
+#endif
+#endif
+ return ret;
+}
+/*
+设置输入输出状态,设置PDR寄存器GPIO22为output
+root@OpenWrt:/# hwacc w 0xD401900c 0x00c03800
+Option = w Addr = d401900c Data=00c03800
+Value 00c03800 written to 0xd401900c via MVA=0x0xb6f9f00c
+ */
+static void gpio_register_write(int reg, int value)
+{
+#if 0
+ FILE * fp;
+ // "/bin/hwacc w 0xD401900c 0x00c03800"
+ char command[36] = {0};
+ char buffer[1024];
+
+ sprintf(command, "/bin/hwacc w 0x%x 0x%x", reg, value);
+ gpio_log("command: %s\n", command);
+ fp = popen(command, "r");
+ while(1)
+ {
+ if( fgets (buffer, sizeof(buffer), fp)!=NULL ) {
+ gpio_log("%s\n", buffer);
+ }else{
+ break;
+ }
+ }
+ pclose(fp);
+
+#else
+#ifndef MBTK_PROJECT_PN1803
+ usleep(50);
+#endif
+ hwacc_register(1, reg, &value);
+#ifndef MBTK_PROJECT_PN1803
+ usleep(50);
+#endif
+#endif
+}
+/*
+AF SEL<p>This field is used for alternate function selection for a pin.
+It selects between the eight possible alternate functions for the pin.
+Alternate function 0 is always the reset case.
+
+<p>0x0 = Alternate function 0 (primary function at reset)
+<p>0x1 = Alternate function 1
+<p>0x2 = Alternate function 2
+<p>0x3 = Alternate function 3
+<p>0x4 = Alternate function 4
+<p>0x5 = Alternate function 5
+<p>0x6 = Alternate function 6
+<p>0x7 = Alternate function 7
+ */
+static int gpio_register_set_func_0(int port)
+{
+ int ret;
+ struct gpio_register_function *reg = NULL;
+ if(port > 128)
+ return -1;
+ reg = &gpio_func_register[port];
+ if(0 == reg->reg)
+ return -1;
+ ret = gpio_register_read(reg->reg);
+ if((ret & 0x7) != reg->func_gpio)
+ {
+ //printf("Gpio set func [%d] [0x%x]!\n", reg->func_gpio, (ret & 0xfffffff8) | reg->func_gpio);
+ gpio_register_write(reg->reg, (ret & 0xfffffff8) | reg->func_gpio);
+ }
+ return 0;
+}
+/*
+设置GPIO 方向
+读取输入输出状态,读PDR寄存器:0x0c
+root@OpenWrt:/# hwacc r 0xD401900c
+Option = r Addr = d401900c
+Value read from 0xd401900c via MVA=0x0xb6f3900c is 0x00803800 //bit22为0,代表Input
+ */
+static void gpio_register_set_direction(int port, int dir)
+{
+ int ret;
+ int reg = 0xD4019000;
+
+ if(port > (32 - 1))
+ reg = 0xD4019004;
+ if(port > (32 * 2 - 1))
+ reg = 0xD4019008;
+ if(port > (32 * 3 - 1))
+ reg = 0xD4019100;
+
+ reg += 0x0c;
+ port = port % 0x20;
+ ret = gpio_register_read(reg);
+ //printf("[Direction] reg_value=%x\n", ret);
+ // 设置 输出 0 && 1
+ if(!(ret & (0x1 << port)) && dir)
+ {
+ gpio_register_write(reg, ret | (0x1 << port)); //set the gpio bit
+ //printf("[Direction out] reg_value=%x\n", gpio_register_read(reg));
+ }
+ // 设置 输入 1 && 0
+ if((ret & (0x1 << port)) && !dir)
+ {
+#if 1
+ gpio_register_write(reg, ret & (~(0x1 << port))); //clear the gpio bit,mbtk_tanggaoyou
+#else
+ gpio_register_write(reg, ret | !(0x1 << port)); //这是错误配置,实际没有任何作用,还是原来的值
+#endif
+ //printf("[Direction in] reg_value=%x\n", gpio_register_read(reg));
+ }
+}
+/*
+设置GPIO 输出电平
+
+读取电平状态,先读PLR寄存器:0x00
+root@OpenWrt:/# hwacc r 0xD4019000
+Option = r Addr = d4019000
+Value read from 0xd4019000 via MVA=0x0xb6f1c000 is 0x81e82a30
+对应下面具体BIT
+1000 0001 1110 1000 0010 1010 0011 0000 BIT22默认电平高
+
+设置输出高:设置PSR寄存器:0x18(只写寄存器)
+root@OpenWrt:/# hwacc w 0xD4019018 0x400000
+Option = w Addr = d4019018 Data=00400000
+Value 00400000 written to 0xd4019018 via MVA=0x0xb6f56018 //bit22写1,输出高
+
+设置输出低:设置PCR寄存器:0x24
+root@OpenWrt:/# hwacc w 0xD4019024 0x400000
+Option = w Addr = d4019024 Data=00400000
+Value 00400000 written to 0xd4019024 via MVA=0x0xb6faa024 //Bit22写1,GPIO22输出低
+
+ */
+static void gpio_register_set_value(int port, int value)
+{
+ int ret;
+ int reg = 0xD4019000;
+
+ if(port > (32 - 1))
+ reg = 0xD4019004;
+ if(port > (32 * 2 - 1))
+ reg = 0xD4019008;
+ if(port > (32 * 3 - 1))
+ reg = 0xD4019100;
+
+ if(value)
+ {
+ reg += 0x18;
+ }
+ else
+ reg += 0x24;
+
+ port = port % 0x20;
+ ret = gpio_register_read(reg);
+ //printf("[Value] reg_value=%x\n", gpio_register_read(0xD4019004));
+ // 设置 高电平 0 && 1
+ if(value)
+ {
+ gpio_register_write(reg, ret | (0x1 << port));
+ //printf("[Value high] reg_value=%x\n", gpio_register_read(0xD4019004));
+ return;
+ }
+ // 设置 低电平 1 && 0
+ if(!(ret & (0x1 << port)) && !value)
+ {
+ gpio_register_write(reg, ret | (0x1 << port));
+ //printf("[Value low] reg_value=%x\n", gpio_register_read(0xD4019004));
+ }
+}
+/*
+读取电平状态,先读PLR寄存器:0x00
+root@OpenWrt:/# hwacc r 0xD4019000
+Option = r Addr = d4019000
+Value read from 0xd4019000 via MVA=0x0xb6f1c000 is 0x81e82a30
+对应下面具体BIT
+1000 0001 1110 1000 0010 1010 0011 0000 BIT22默认电平高
+ */
+static int gpio_register_get_value(int port)
+{
+ int ret = -1;
+ int reg = 0xD4019000;
+
+ if(port > (32 - 1))
+ reg = 0xD4019004;
+ if(port > (32 * 2 - 1))
+ reg = 0xD4019008;
+ if(port > (32 * 3 - 1))
+ reg = 0xD4019100;
+ port = port % 0x20;
+ ret = gpio_register_read(reg);
+ if(ret & (0x1 << port))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+void gpio_debug_set(int enable)
+{
+ gpio_debug = enable;
+}
+
+
+
+#if defined(MBTK_PROJECT_PN1803)
+int gpio_register_test_out(int port, int value)
+{
+ int ret;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port);
+ ret = gpio_register_set_func_0(port); //设功能为GPIO
+ if(ret){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port, 1); //设方向为输出
+ ret = gpio_register_get_value(port);
+ //printf("gpio default value is : %d.\n", ret);
+
+
+ //[High]
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 1);
+ usleep(50);
+ valueh = gpio_register_get_value(port);
+ //printf("set high? %d\n",valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+ //usleep(10000);
+ for(i = 0; i <= 35; i++){
+ ret = mbtk_gpio_adc(0);
+ usleep(3000);
+ if(1 == ret){
+ break;
+ }
+ }
+ if(1 != ret){
+ ret=-1;
+ goto exit;
+ }
+ printf("******gpio should is high: %d.******\n", ret);
+
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 0); //输出低
+ usleep(50);
+ valuel = gpio_register_get_value(port);
+ //printf("set low? %d\n",valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+ //usleep(10000);
+ for(i = 0; i <= 35; i++){
+ ret = mbtk_gpio_adc(0);
+ usleep(3000);
+ if(0 == ret){
+ break;
+ }
+ }
+ printf("******gpio should is low: %d.******\n", ret);
+ if(0 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+exit:
+ //gpio_register_set_direction(port, 0); //设方向为输入
+ return ret;
+}
+
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+ int test_gpio[] = {
+ 56, 55, 58, 57, 48, 59, 12, 20, 5, 43, 21,
+ 49, 50, 27, 28, 26, 25, 16, 17, 15, 126, 125,
+ 4, 0, 3, 18, 7, 6, 1, 2, /*54,*/ 19, 13,
+ 32, 31, 23, 24, 22, /*122,*/ 33, 35, 36, 34, 14,
+ 99,/* 53,*/ 37, 38, 39, 40, 41, 42};
+
+ int i, j, ret, total, n = 0;
+ int *fail_io = (int *)arg;
+ total = (sizeof(test_gpio)/sizeof(int));
+ //printf("Start test gpio total: %d\n", total);
+
+ /* [1 all gpio set to low] */
+ for(j = 0; j < 6 ; j++){
+ for(i = 0; i < total; i++){
+ gpio_register_set_func_0(test_gpio[i]);
+ gpio_register_set_direction(test_gpio[i], 1);
+ gpio_register_set_value(test_gpio[i], 0);
+ }
+ //usleep(10000);
+ for(i = 0; i <= 35; i++){
+ ret = mbtk_gpio_adc(0);
+ usleep(3000);
+ if(0 == ret){
+ break;
+ }
+ }
+ printf("pre set ADC: %d, times: %d\n",ret, j);
+ if(0 == ret){
+ break;
+ }
+ }
+ if(0 != ret){
+ printf("Fail, please retest");
+ return -1;
+ }
+
+
+ /* [2 GPIOTEST] */
+ for(i = 0; i < total; i++){
+ ret = gpio_register_test_out(test_gpio[i], 0);
+ if(-1 == ret){
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio[i]);
+ fail_io[n] = test_gpio[i];
+ n++;
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio[i]);
+ }
+ }
+ mbtk_adc_close();
+ return n;
+}
+
+#elif defined(MBTK_PROJECT_L508)
+
+
+#define READ_GPIO_NUM 22
+
+#define DEBUG_GPIO_TEST 1
+
+mbtk_gpio_test_pin_and_gpio *p_test_gpio =NULL;
+mbtk_gpio_test_pin_and_gpio *p_gnss_gpio = NULL;
+int test_gpio_group_total_pin = 0;
+int gnss_gpio_group_total_pin = 0;
+
+int gpio_test_set_group_pin_to_low(mbtk_gpio_test_pin_and_gpio *p_pin_group_array, int total_num)
+{
+ int i;
+ int gpio_num = 0;
+ int ret = 0;
+
+ if(p_pin_group_array == NULL)
+ return -1;
+
+ for(i=0; i < total_num; i++)
+ {
+ gpio_num = p_pin_group_array[i].gpio_num;
+ ret += gpio_register_set_func_0(gpio_num);
+ gpio_register_set_direction(gpio_num, MBTK_GPIO_OUTPUT);
+ gpio_register_set_value(gpio_num, 0);
+ }
+ return ret;
+}
+
+
+int gpio_test_init(void)
+{
+ int i,j,ret;
+ int gpio_num = 0;
+
+
+
+
+ system("i2cset -y -f 2 0x31 0x12 0x46");
+ system("echo 53 > /sys/class/gpio/export"); //gnss uart rx
+ system("echo out > /sys/class/gpio/gpio53/direction");
+ system("echo 54 > /sys/class/gpio/export");//gnss uart tx
+ system("echo out > /sys/class/gpio/gpio54/direction");
+ system("echo 22 > /sys/class/gpio/export");//check pin
+
+ gpio_register_set_func_0(READ_GPIO_NUM);
+ gpio_register_set_direction(READ_GPIO_NUM, 1); //输出
+
+ usleep(500);
+/*
+ GPIO22默认是上拉,如果改成GPIO输入模式,其PIN脚电压是高电平,必须改成下拉后GPIO22才处于低电平状态,否则测试PIN拉低失败
+*/
+ gpio_register_set_direction(READ_GPIO_NUM, MBTK_GPIO_INPUT); //设置输入模式
+ gpio_register_write(GPIO_FUNC_GPIO_22,0xb040); //PULL DOWN
+
+
+ gpio_test_set_group_pin_to_low(p_gnss_gpio,gnss_gpio_group_total_pin); //set all gnss reserver pin to low
+
+
+ /* [1 all gpio set to low] */
+ for(j = 0; j < 6 ; j++){
+ gpio_test_set_group_pin_to_low(p_test_gpio,test_gpio_group_total_pin);
+
+ for(i = 0; i <= 5; i++){
+ ret = gpio_register_get_value(READ_GPIO_NUM);
+ if(0 == ret){
+ break;
+ }
+ usleep(3000);
+ }
+
+ if(0 == ret){
+ break;
+ }
+ }
+
+ if(0 != ret){
+ printf("[GPIOTEST]set all low Fail, please retest\n");
+ return -1;
+ }
+ printf("[GPIOTEST]pre set SUCCESS\n");
+ return 0;
+}
+
+int gpio_test(void* arg,int index,mbtk_gpio_test_pin_and_gpio *p_pin_group_array,int total)
+{
+ int ret,i;
+ int *fail_io = (int *)arg;
+ int failed_num = index;
+ int gpio_num = 0;
+ int pin_num = 0;
+ bool falied_flag = FALSE;
+
+ for(i = 0; i < total; i++){
+ gpio_num = p_pin_group_array[i].gpio_num;
+ pin_num = p_pin_group_array[i].pin_num;
+ falied_flag = FALSE;
+
+#if DEBUG_GPIO_TEST
+ ret = gpio_register_get_value(gpio_num);
+ printf("[GPIOTEST]pin_num%d default value= %d\n", pin_num, ret);
+#endif
+
+ //set high
+ gpio_register_set_value(gpio_num, 1);
+
+#if DEBUG_GPIO_TEST
+ ret = gpio_register_get_value(gpio_num);
+ printf("[GPIOTEST]pin_num%d set high= %d\n", pin_num, ret);
+#endif
+ //get
+ ret = gpio_register_get_value(READ_GPIO_NUM);
+ if(1 != ret){
+ printf("[GPIOTEST]pin%d test high failed\n", pin_num);
+ falied_flag = TRUE;
+ }else{
+ printf("[GPIOTEST]pin[%d] test high success\n", pin_num);
+ }
+
+ //set low
+ gpio_register_set_value(gpio_num, 0);
+#if DEBUG_GPIO_TEST
+ ret = gpio_register_get_value(gpio_num);
+ printf("[GPIOTEST]pin_num%d set low= %d\n", pin_num, ret);
+#endif
+ //get
+ ret = gpio_register_get_value(READ_GPIO_NUM);
+ if(0 != ret){
+ printf("[GPIOTEST]pin_num%d test low failed\n", pin_num);
+ falied_flag = TRUE;
+
+ }else{
+ printf("[GPIOTEST]pin_num%d test low success\n", pin_num);
+ }
+
+ if(falied_flag)
+ {
+ fail_io[failed_num] = p_pin_group_array[i].pin_num;
+#if DEBUG_GPIO_TEST
+ printf("[GPIOTEST]NO.%d pin_num%d failed %d\n",i,pin_num, failed_num);
+#endif
+ failed_num++;
+ }
+ }
+ return failed_num;
+}
+
+
+int mbtk_at_gpio(bool gnss_support,void* arg)
+{
+ int n = 0;
+ mbtk_gpio_test_pin_and_gpio test_gpio[] =
+ {
+ //{GPIO , PIN}
+ {0,100}, //RMII_RX-DV
+ {1,101}, //RMII_RXD0
+ {2,102},//RMII_RXD1
+ {3,103},//RMII_CLK
+ {6,104},//RMII_TXD0
+ {7,105},//RMII_TXD1
+ {15,106},//RMII_TX_EN
+ {16,109},//RMII_MDC
+ {17,110},//RMII_MDIO
+ {18,107},//RMII_INT
+ {99,16},//USB_ID
+ {34,9}, //SPI0_CS
+ {36,8},//SPI0_TXD
+ {35,7},//SPI0_RXD
+ {33,6},//SPI0_CLK
+ {14,51}, //NET_LIGHT
+ {13,49}, //STATUS LED
+ {12,50},//WAKE_IN
+ {49,55}, //I2C SCL
+ {50,56}, //I2C SDA
+ {19,53}, //USIM_DET
+ {43,48}, //SD_DET
+ {118,52}, //WAKE OUT
+ {120,54}, //FLIGHT MODE
+
+
+ {20,45}, //NORMAL GPIO
+ {59,122}, //SDIO_CLK
+ {56,117}, //SDIO_DATA1
+ {55,118},//SDIO_DATA2
+ {58,119},//SDIO_CMD
+ {48,120},//SDIO_DATA3
+ {57,121},//SDIO_DATA0
+ {5,84}, //NORMAL GPIO
+ {4,30},//NORMAL GPIO
+ {21,28}, //NORMAL GPIO
+ {23,69}, //UART_RING
+ {24,70}, //UART_DCD
+ {27,73}, //PCM_OUT
+ {28,74}, //PCM_IN
+ {26,75}, //PCM_SYNC
+ {25,76}, //PCM_CLK
+
+ {126,112},//NORMAL GPIO or pwm3
+ {117,123}, //PWM
+ {125,116}, //CLK_REQ
+
+ //{54,114}, //debug uart2, no need be tested
+ //{53,115}, //debug uart2, no need be tested
+
+ };
+
+ mbtk_gpio_test_pin_and_gpio GNSS_test_gpio[] = {
+ {54,114}, //GPS UTXD, UART1_TXD,L508LAN+L508CN(D)+L508EN+L508LEN+L508TLCN NOT CONNECTED
+ {53,115}, //GPS URXD,UART1-RXD,L508LAN+L508CN(D)+L508EN+L508LEN+L508TLCN NOT CONNECTED
+ {32,66}, //PIN66,host wake GPS, RTS, L508TLCN_V2+L508LEN_V2+L508EN_V2 NOT CONNECTED
+ {31,67}, //PIN67,GPS wake Host,CTS, L508TLCN_V2+L508LEN_V2+L508EN_V2 NOT CONNECTED
+ {123,42},//GPS_EN, L508TLCN_V2+L508LEN_V2+L508EN_V2 NOT CONNECTED
+ {122,35}, //32K OUT, L508TLCN_V2+L508LEN_V2+L508EN_V2 not connected
+ };
+ p_gnss_gpio = GNSS_test_gpio;
+ gnss_gpio_group_total_pin = (sizeof(GNSS_test_gpio)/sizeof(GNSS_test_gpio[0]));
+
+ p_test_gpio = test_gpio;
+ test_gpio_group_total_pin = (sizeof(test_gpio)/sizeof(test_gpio[0]));
+
+ if(!gnss_support)
+ n = test_gpio_group_total_pin+gnss_gpio_group_total_pin;
+ else
+ n = test_gpio_group_total_pin;
+
+ printf("[init] L508 XX GPIOTEST v1.3 total pin=%d\n",n);
+
+ n = gpio_test_init();
+ if(-1 == n)
+ {
+ goto gpiotest_finished;
+ }
+ n = 0;
+
+ n = gpio_test(arg,0,p_test_gpio,test_gpio_group_total_pin);
+
+ //if the module has gnss chip, don't test the gnss's pins
+ if(!gnss_support)
+ {
+ n = gpio_test(arg,n,p_gnss_gpio,gnss_gpio_group_total_pin);
+ }
+
+gpiotest_finished:
+ system("echo 53 > /sys/class/gpio/unexport"); //unexport gnss uart rx
+ system("echo 54 > /sys/class/gpio/unexport");//unexportgnss uart tx
+ system("echo 22 > /sys/class/gpio/unexport");//unexportcheck pin
+
+ printf("\n[GPIOTEST] Finished %d!!\n\n",n);
+ return n;
+}
+
+
+
+#elif defined(MBTK_PROJECT_L509)
+//测低
+static uint16 mbtk_gpio_test_all_low(mbtk_gpio_paired_info_struct *pin_array, uint16 MAX_pin_num)
+{
+ uint16 index = 0;
+ uint16 OUT_pin, Read_pin;
+ uint32 read_high_value;
+ uint32 read_low_value;
+ uint16 fail_num = 0;
+ //int res;
+
+ printf("[GPIOTEST][run test all pin low]\n");
+
+ for(index = 0; index < MAX_pin_num; index++){
+ OUT_pin = pin_array[index].output_gpio;
+ Read_pin = pin_array[index].input_gpio;
+
+ //输出低
+ gpio_register_set_direction(OUT_pin, 1);
+ gpio_register_set_value(OUT_pin, 0);
+
+ //输入脚设为输入
+ gpio_register_set_direction(Read_pin,0);
+ }
+
+ for(index = 0; index < MAX_pin_num; index++){
+ OUT_pin = pin_array[index].output_gpio;
+ Read_pin = pin_array[index].input_gpio;
+ read_low_value = gpio_register_get_value(Read_pin);
+
+ //结果检测
+ if(read_low_value != 0){
+ printf("[GPIOTEST][!Low Failed!]: GPIO%d PIN%d\n", Read_pin, pin_array[index].input_pin);
+ pin_array[index].mbtk_gpio_test_result = 1;
+ fail_num ++;
+ }
+#if DEBUG_GPIO_TEST
+ else{
+ printf("[GPIOTEST][-Low Success-]: GPIO%d \n", Read_pin);
+ }
+#endif
+ }
+ return fail_num;
+}
+
+
+//测高
+static uint16 mbtk_gpio_test_pin_high(mbtk_gpio_paired_info_struct *pin_array, uint16 MAX_pin_num)
+{
+ uint16 index = 0;
+ uint16 OUT_pin, Read_pin;
+ uint32 read_high_value;
+ uint32 read_low_value;
+ uint16 fail_num = 0;
+ int i = 0;
+
+ printf("[GPIOTEST][run test pin high]\n");
+
+ for(index = 0; index < MAX_pin_num; index++){
+ OUT_pin = pin_array[index].output_gpio;
+ Read_pin = pin_array[index].input_gpio;
+
+ //设高
+ gpio_register_set_direction(OUT_pin,1);
+ gpio_register_set_direction(Read_pin,0);
+ gpio_register_set_value(OUT_pin, 1);
+ usleep(10000);
+ read_high_value = gpio_register_get_value(Read_pin);
+#if DEBUG_GPIO_TEST
+ printf("[GPIOTEST][test_high]: PIN%d: get value =%d \n", pin_array[index].input_pin, read_high_value);
+#endif
+
+ //设高后重新设低
+ usleep(10000);
+ gpio_register_set_value(OUT_pin, 0);
+ usleep(10000);
+ for(i = 0; i < 10; i++){
+ read_low_value = gpio_register_get_value(Read_pin);
+ if(0 == read_low_value){
+ break;
+ }
+ usleep(20000);
+ }
+#if DEBUG_GPIO_TEST
+ printf("[GPIOTEST][test_low]: PIN%d: get value =%d \n", pin_array[index].input_pin, read_low_value);
+#endif
+ if(read_high_value != 1 || read_low_value != 0){
+ printf("[GPIOTEST][!High Failed!]: Gpio%d PIN%d\n", Read_pin,pin_array[index].input_pin);
+ pin_array[index].mbtk_gpio_test_result = 2;
+ fail_num ++;
+ }
+#if DEBUG_GPIO_TEST
+ else{
+ printf("[GPIOTEST][-High Success-]: Gpio%d \n", Read_pin);
+ }
+#endif
+ }
+ return fail_num;
+}
+
+
+static void gpio_test_init_test_gpio_mode(mbtk_gpio_paired_info_struct pin_array[], int MAX_pin_num)
+{
+ int index = 0;
+ int OUT_pin, Read_pin;
+
+ printf("[GPIOTEST] L509 GPIOTEST v2.2 --init\n");
+
+ gpio_register_set_func_0(125);
+ gpio_register_set_direction(125, 1);
+ gpio_register_set_value(125, 1); //RS2299开关的使能脚
+
+ system("i2cset -y -f 2 0x31 0x12 0x46"); //使能0x12地址的VLDO, 某组GPIO的供电
+
+ gpio_register_write(GPIO_FUNC_GPIO_53, 0xb040); //GPIO53 DTR set PULL DOWN
+
+ for(index = 0; index < MAX_pin_num; index++){
+ OUT_pin = pin_array[index].output_gpio;
+ Read_pin = pin_array[index].input_gpio;
+ pin_array[index].mbtk_gpio_test_result = 0; //init as passed
+ gpio_register_set_func_0(OUT_pin);
+ gpio_register_set_func_0(Read_pin);
+ gpio_register_set_value(OUT_pin, 0);
+ }
+
+#if DEBUG_GPIO_TEST
+ printf("[GPIOTEST]gpio_test_init_test_gpio_mode FINISH\n");
+#endif
+
+}
+
+
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+ int i, num;
+ int *fail_io = (int *)arg;
+ /*OPEN SWITCH */
+ uint16 test_fail_count = 0;
+ uint16 test_MAX_pin_num = 0;
+ char buf[STR_MAX_LEN];
+ //uint16 str_len = 0;
+ uint16 temp_len =0;
+ uint16 Out_pin;
+ uint16 in_pin;
+ //uint16 fail_print_num = 0;
+
+ mbtk_gpio_paired_info_struct test_pin_array[] ={
+ //output_pin, output_gpio, input_gpio, input_pin, test_result
+ {122, 16, 17, 121, 0}, /* RGMII/RMII_MD_CLK <---SW RS2299---> RGMII/RMII_MD_IO */
+
+ {78, 7, 2, 73, 0}, /* RGMII/RMII_TX_1 <---SW RS2299---> RGMII/RMII_RXD1 */
+ {77, 6, 1, 76, 0}, /* RGMII/RMII_TXD0 <---SW RS2299---> RGMII/RMII_RXD0 */
+ {81, 15, 3, 75, 0}, /* RGMII/RMII_TX_EN <---SW RS2299---> RGMII/RMII_CLK */
+ {74, 0, 18, 120, 0}, /* RGMII/RMII_RX_DV <---SW RS2299---> RGMII/RMII_INT */
+
+ {1, 117, 120, 2, 0}, /* WAKEUP_IN <---SW RS2299---> AP_READY */
+ {4, 118, 19, 13, 0}, /* FLIGHTMODE <---SW RS2299---> USIM_CD */
+ {5, 123, 126, 6, 0}, /* NET_MODE <---SW RS2299---> NET_STATUS */
+ {23, 43, 23, 62, 0}, /* MMC1_CD <---SW RS2299---> UART_RI */
+
+ {79, 4, 5, 82, 0}, /* RGMII_RX_2 <---SW RS2299---> RGMII_RX_3 */
+ {80, 13, 14, 84, 0}, /* RGMII_TX_2 <---SW RS2299---> RGMII_TX_3 */
+ {129, 48, 55, 130, 0}, /* WLAN_DAT3 <---SW RS2299---> WLAN_DAT2 */
+ {131, 56, 57, 132, 0}, /* WLAN_DAT1 <---SW RS2299---> WLAN_DAT0 */
+
+ {24, 28, 27, 25, 0}, /* PCM_IN <---SW RS2299---> PCM_OUT */
+ {26, 26, 25, 27, 0}, /* PCM_SYNC <---SW RS2299---> PCM_CLK */
+ {37, 34, 33, 40, 0}, /* SPI_CS <---SW RS2299---> SPI_CLK */
+ {38, 36, 35, 39, 0}, /* SPI_DOUT <---SW RS2299---> SPI_DIN */
+
+ {133, 59, 58, 134, 0}, /* WLAN_CLK/PCIE_RSTN <---SW RS2299---> WLAN_CMD/PCIE_WK */
+ {135, 21, 99, 139, 0}, /* WLAN_WAKE_HOST <---SW RS2299---> USB_ID */
+ {119, 20, 22, 136, 0}, /* RGMII/RMII_RST_N <---SW RS2299---> WLAN_EN */
+ {83, 12, 122, 118, 0}, /* RGMII_CLK_TX <---SW RS2299---> WLAN_SLP_CLK */
+
+ {41, 49, 50, 42, 0}, /* I2C_SCL <---SW RS2299---> I2C_SDA */
+ {143, 10, 11, 144, 0}, /* GRFC1 <---SW RS2299---> GRFC2 */
+ {64, 32, 31, 65, 0}, /* UART_CTS <---SW RS2299---> UART_RTS */
+ {63, 54, 53, 66, 0}, /* UART_DCD <---SW RS2299---> UART_DTR */
+ };
+
+
+ /* [1]初始化待测GPIO */
+ test_MAX_pin_num = sizeof(test_pin_array) / sizeof(test_pin_array[0]);
+ if(gnss_support){ //TODO: When the hardware does not have GNSS, do not test GPIO53, 54
+ //bad implement, need modify
+ test_MAX_pin_num = test_MAX_pin_num - 1;
+ }
+ gpio_test_init_test_gpio_mode(test_pin_array, test_MAX_pin_num);
+
+
+ /* [2]测试过程 */
+ test_fail_count = mbtk_gpio_test_all_low(test_pin_array, test_MAX_pin_num);
+
+ if(!test_fail_count){ //set all pin to low success
+ printf("[GPIOTEST]set all pin to low: success\n");
+ test_fail_count = mbtk_gpio_test_pin_high(&test_pin_array, test_MAX_pin_num);
+ }
+ else{
+ printf("[GPIOTEST]set all pin low: failed num=%d!!!\n", test_fail_count);
+ }
+
+
+ //memset(buf,0,STR_MAX_LEN);
+ /* [3]测试结果检测与上报 */
+ if(test_fail_count ){
+ //printf( "GPIOTEST Fail %02d PINs:\n", test_fail_count*2);
+ sprintf(buf, "GPIOTEST Fail %02d PINs:", test_fail_count * 2);
+ temp_len = strlen(buf);
+
+ num = 0;
+ for(i = 0; i < test_MAX_pin_num; i++){
+ if(test_pin_array[i].mbtk_gpio_test_result){
+ Out_pin = test_pin_array[i].output_pin;
+ in_pin = test_pin_array[i].input_pin;
+ fail_io[num++] = Out_pin;
+ fail_io[num++] = in_pin;
+ }
+ }
+ }
+
+ else{
+ printf(buf, "ALL GPIO TEST PASS\r\n");
+ }
+
+ printf("\n[GPIOTEST] Finished !!\n\n");
+ return test_fail_count * 2;
+}
+
+
+#elif defined(MBTK_PROJECT_L508_X6)
+int gpio_register_test_out_0(int port)
+{
+ int ret;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port);
+ ret = gpio_register_set_func_0(port); //设功能为GPIO
+ if(ret){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port, 1); //设方向为输出
+ //ret = gpio_register_get_value(port);
+ //printf("gpio default value is : %d.\n", ret);
+
+
+ //[High]
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 1);
+ usleep(50);
+ valueh = gpio_register_get_value(port);
+ //printf("set high? %d\n",valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+ usleep(5000);
+ for(i = 0; i <= 10; i++){
+ ret = mbtk_gpio_adc(0);
+ usleep(3000);
+ if(1 == ret){
+ break;
+ }
+ }
+ //printf("******gpio should is high: %d.******\n", ret);
+ if(1 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 0); //输出低
+ usleep(50);
+ valuel = gpio_register_get_value(port);
+ //printf("set low? %d\n",valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+ usleep(5000);
+ for(i = 0; i <= 10; i++){
+ ret = mbtk_gpio_adc(0);
+ usleep(3000);
+ if(0 == ret){
+ break;
+ }
+ }
+ printf("******gpio should is low: %d.******\n", ret);
+ if(0 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+exit:
+ gpio_register_set_value(port, 0);
+ //gpio_register_set_direction(port, 0); //设方向为输入
+ return ret;
+}
+
+int gpio_register_test_out_1(int port)
+{
+ int ret;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port);
+ ret = gpio_register_set_func_0(port); //设功能为GPIO
+ if(ret){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port, 1); //设方向为输出
+ //ret = gpio_register_get_value(port);
+ //printf("gpio default value is : %d.\n", ret);
+
+
+ //[High]
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 1);
+ usleep(50);
+ valueh = gpio_register_get_value(port);
+ //printf("set high? %d\n",valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+ usleep(5000);
+ for(i = 0; i <= 10; i++){
+ ret = mbtk_gpio_adc(1);
+ usleep(3000);
+ if(1 == ret){
+ break;
+ }
+ }
+ if(1 != ret){
+ ret=-1;
+ goto exit;
+ }
+ //printf("******gpio should is high: %d.******\n", ret);
+
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port, 0); //输出低
+ usleep(50);
+ valuel = gpio_register_get_value(port);
+ //printf("set low? %d\n",valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+ usleep(10000);
+ for(i = 0; i <= 10; i++){
+ ret = mbtk_gpio_adc(1);
+ usleep(3000);
+ if(0 == ret){
+ break;
+ }
+ }
+ //printf("******gpio should is low: %d.******\n", ret);
+ if(0 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+exit:
+ gpio_register_set_value(port, 0);
+ //error: no need set direction in gpio_register_set_direction(port, 0);
+ return ret;
+}
+
+
+int gpio_register_test_out_2(int port_in, int port_out)
+{
+ int ret_in;
+ int ret_out;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port_out);
+ ret_in = gpio_register_set_func_0(port_in); //设功能为GPIO
+ ret_out = gpio_register_set_func_0(port_out);
+ if((ret_in+ret_out)){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port_out, 1); //设方向为输出
+ gpio_register_set_direction(port_in, 0); //设方向为输入
+ //ret_in = gpio_register_get_value(port_in);
+ //printf("gpio default value is : %d.\n", ret_in);
+
+
+ //[High]
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port_out, 1);
+ usleep(50);
+ valueh = gpio_register_get_value(port_out);
+ //printf("set high? %d\n",valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+
+ usleep(5000);
+ for(i = 0; i <= 10; i++){
+ ret_in = gpio_register_get_value(port_in);
+ usleep(3000);
+ if(1 == ret_in){
+ break;
+ }
+ }
+ if(1 != ret_in){
+ ret_in=-1;
+ printf("get high failed! \n");
+ goto exit;
+ }
+ //printf("******gpio should is high: %d.******\n", ret_in);
+
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 10; i++){
+ gpio_register_set_value(port_out, 0); //输出低
+ usleep(50);
+ valuel = gpio_register_get_value(port_out);
+ //printf("set low? %d\n",valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+
+ usleep(5000);
+ for(i = 0; i <= 10; i++){
+ ret_in = gpio_register_get_value(port_in);
+ usleep(3000);
+ if(0 == ret_in){
+ break;
+ }
+ }
+ //printf("******gpio should is low: %d.******\n", ret_in);
+ if(0 != ret_in){
+ ret_in=-1;
+ printf("get low failed! \n");
+ goto exit;
+ }
+
+exit:
+ gpio_register_set_value(port_out, 0);
+ //gpio_register_set_direction(port_out, 0);
+ return ret_in;
+}
+
+
+static int gpio_test_init_test_gpio_mode(void )
+{
+ const int test_gpio_1[] = {
+ 40, 33, 34, 39, 99, 10, 11, 88, 87, 86, 85, 84, 89,
+ 56, 55, 58, 57, 48, 59, 10, 90, 20, 53, 19, 46, 127,
+ 49, 50, 32, 31, 6, 7
+ };
+
+ const int test_gpio_0[] = {
+ 8, 27, 28, 26, 25, 15, 1, 3, 0,
+ 37, 38,35, 36, 42, 41, 21, 22, 24, 23,
+ 54, 125, 18, 13, 14, 17, 16, 5, 4, 2, 12,
+ 43, 44, 45, 47, 117, 119
+ };
+ int i, j, ret_0, ret_1, total_1, total_0, n = 0;
+ total_0 = (sizeof(test_gpio_0)/sizeof(int));
+ total_1 = (sizeof(test_gpio_1)/sizeof(int));
+
+ //system("at at+gpsinit=0");
+ system("i2cset -y -f 2 0x32 0x0d 0x00");
+ system("i2cset -y -f 2 0x31 0x18 0x8f");
+ usleep(10000);
+
+ //printf("[init]gpio_test_init_test_gpio_mode FINISH\n");
+ /* [1 all gpio set to low] */
+ for(j = 0; j < 6 ; j++){
+ for(i = 0; i < total_0; i++){
+ gpio_register_set_func_0(test_gpio_0[i]);
+ gpio_register_set_direction(test_gpio_0[i], 1);
+ gpio_register_set_value(test_gpio_0[i], 0);
+ }
+ for(i = 0; i < total_1; i++){
+ gpio_register_set_func_0(test_gpio_1[i]);
+ gpio_register_set_direction(test_gpio_1[i], 1);
+ gpio_register_set_value(test_gpio_1[i], 0);
+ }
+
+ usleep(50000);
+ for(i = 0; i <= 10; i++){
+ ret_0 = mbtk_gpio_adc(0);
+ usleep(3000);
+ ret_1 = mbtk_gpio_adc(1);
+
+ if(ret_0 ==0 && ret_1 == 0){
+ break;
+ }
+ }
+ printf("pre set ADC0: %d, ADC1: %d, times: %d\n", ret_0, ret_1, j);
+ if(ret_0 ==0 && ret_1 == 0){
+ break;
+ }
+ }
+ if(!(ret_0 ==0 && ret_1 == 0)){
+
+ printf("Fail, please retest");
+ return -1;
+ }
+ gpio_register_set_value(119, 1);
+ gpio_register_set_value(117, 1);
+ return 0;
+}
+
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+ const int test_gpio_0[] = {
+ 35, 93,
+ 36, 94,
+ 42, 97,
+ 41, 98,
+ 21, 100,
+ 22, 101,
+ 24, 102,
+ 23, 103,
+ 54, 107,
+ 125, 108,
+ 18, 109,
+ 13, 114,
+ 14, 115,
+ 17, 116,
+ 16, 117,
+ 5, 119,
+ 4, 127,
+ 2, 120,
+ 12, 126,
+ 0, 90,
+ 27, 73,
+ 28, 74,
+ 26, 75,
+ 25, 76,
+ 15, 86,
+ 1, 88,
+ 3, 89,
+ 37, 91,
+ 38, 92,
+ 8, 72
+ };
+
+ const int test_gpio_1[] = {
+ 40, 6,
+ 33, 7,
+ 34, 8,
+ 39, 9,
+ 99, 16,
+ 56, 27,
+ 58, 29,
+ 55, 28,
+ 57, 30,
+ 48, 31,
+ 59, 32,
+ 20, 49,
+ 53, 50,
+ 19, 51,
+ 49, 55,
+ 50, 56,
+ 32, 66,
+ 31, 67,
+ 6, 68,
+ 11, 83,
+ 10, 84,
+ 7, 69,
+ 90, 48,
+ 46, 52,
+ 127, 54,
+ 88, 21,
+ 87, 22,
+ 86, 23,
+ 85, 24,
+ 84, 25,
+ 89, 26,
+ };
+
+ const int test_gpio_2[] = { //GPS组
+ 43, 53,
+ 47, 95,
+ 45, 71,
+ 44, 70,
+ };
+
+ int i, j, ret_0, ret_1, ret_2, total_1, total_0, total_2, n = 0;
+ int *fail_io = (int *)arg;
+ total_0 = (sizeof(test_gpio_0)/sizeof(int)); //GPIO+PIN
+ total_1 = (sizeof(test_gpio_1)/sizeof(int));
+ total_2 = (sizeof(test_gpio_2)/sizeof(int));
+ if(gnss_support == 1){
+ total_2 = total_2 - 4;
+ }
+ printf("L508-X6 Start test gpio V1.1\n");
+ /* [1 all gpio Init] */
+ gpio_test_init_test_gpio_mode();
+
+
+ /* [2 GPIOTEST] */
+ //Test 0
+ for(i = 0; i < total_0; i=i+2){
+ ret_0 = gpio_register_test_out_0(test_gpio_0[i]);
+ if(-1 == ret_0){
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio_0[i]);
+ fail_io[n] = test_gpio_0[i+1];
+ n++;
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio_0[i]);
+ }
+ }
+
+ //Test 1
+ for(i = 0; i < total_1; i=i+2){
+ ret_1 = gpio_register_test_out_1(test_gpio_1[i]);
+ if(-1 == ret_1){
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio_1[i]);
+ fail_io[n] = test_gpio_1[i+1];
+ n++;
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio_1[i]);
+ }
+ }
+
+ //Test 2
+ for(i = 0; i < total_2; i=i+4){
+ ret_2 = gpio_register_test_out_2(test_gpio_2[i], test_gpio_2[i+2]);
+ if(-1 == ret_2){
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio_2[i+2]);
+ fail_io[n] = test_gpio_2[i+3];
+ n++;
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio_2[i+2]);
+ }
+ }
+
+ mbtk_adc_close();
+ return n;
+}
+
+#elif 0//(MBTK_PROJECT_T108)
+int gpio_register_test_out(int port, int value)
+{
+ int ret;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port);
+ ret = gpio_register_set_func_0(port); //设功能为GPIO
+ if(ret){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port, 1); //设方向为输出
+ //ret = gpio_register_get_value(port);
+ //printf("gpio default value is: %d\n", ret);
+
+
+ //[High]
+ for(i = 0; i <= 9; i++){
+ gpio_register_set_value(port, 1);
+ usleep(50);
+ //valueh = gpio_register_get_value(port);
+ //printf("set high? %d\n", valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+
+ for(i = 0; i <= 35; i++){
+ ret = gpio_register_get_value(118);
+ if(1 == ret){
+ break;
+ }
+ usleep(3000);
+ }
+ printf("******gpio should is high: %d.******\n", ret);
+ if(1 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 9; i++){
+ gpio_register_set_value(port, 0); //输出低
+ usleep(50);
+ //valuel = gpio_register_get_value(port);
+ //printf("set low? %d\n", valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+
+ for(i = 0; i <= 35; i++){
+ ret = gpio_register_get_value(118);
+ if(0 == ret){
+ break;
+ }
+ usleep(3000);
+ }
+ //printf("******gpio should is low: %d.******\n", ret);
+ if(0 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+exit:
+ gpio_register_set_value(port, 0);
+ gpio_register_set_direction(port, 0); //设方向为输入
+ return ret;
+}
+
+int gpio_test_init_test_gpio_mode(void)
+{
+ const int test_gpio[] = {
+ 99,
+ 117,
+ 21,22,23,24,44,41,120,
+ 8,127,46,59,58,57,56,55,48,19,34,33,35,36,49,
+ 50,25,28,26,122,20,10,11,
+ 39,40,37,38,
+ 51,52,31,32,
+ };
+
+ int i, j, ret, total, n = 0;
+ total = (sizeof(test_gpio)/sizeof(int));
+ printf("[init]gpio_test_init_test_gpio_mode BEGIN\n");
+
+ /* [1 all gpio set to low] */
+ gpio_register_set_func_0(118);
+ gpio_register_set_direction(118, 0);
+ system("echo in > /sys/class/gpio/gpio118/direction");
+
+ for(j = 0; j < 6 ; j++){
+ for(i = 0; i < total; i++){
+ gpio_register_set_func_0(test_gpio[i]);
+ gpio_register_set_direction(test_gpio[i], 1);
+ gpio_register_set_value(test_gpio[i], 0);
+ //ret = gpio_register_get_value(test_gpio[i]);
+ //printf("[init]get gpio%d=%d\n", test_gpio[i], ret);
+ }
+
+ for(i = 0; i <= 35; i++){
+ ret = gpio_register_get_value(118);
+ printf("[init]get gpi118=%d\n", ret);
+ usleep(3000);
+ if(0 == (ret)){
+ break;
+ }
+ }
+
+ printf("pre set ADC: %d, times: %d\n",(ret), j);
+ if(0 == (ret)){
+ break;
+ }
+ }
+ if(0 != (ret)){
+ printf("!!!Set all low FAIL, please retest\n");
+ return -1;
+ }
+ return 0;
+}
+
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+
+ const int test_gpio[] = {
+ //GPIO PIN GPIO PIN GPIO PIN GPIO PIN
+ 99, 170, 117, 59, 21, 61, 22, 62,
+ 23, 144, 24, 147, 44, 5, 41, 159,
+ 120, 143, 8, 171, 127, 160, 46, 149,
+ 59, 19, 58, 18, 57, 20, 56, 21,
+ 55, 22, 48, 23, 19, 3, 34, 79,
+ 33, 80, 35, 78, 36, 77, 49, 43,
+ 50, 42, 25, 67, 28, 66, 26, 65,
+ 122, 169, 20, 152, 10, 74, 11, 73,
+ 39, 166, 40, 164, 37, 165, 38, 163,
+ 51, 58, 52, 60, 31, 57, 32, 56,
+ };
+
+ int i, n = 0, ret, total;
+ int *fail_io = (int *)arg;
+ int try_count = 0;
+ total = (sizeof(test_gpio)/sizeof(int));
+ printf("T108 Start test gpio V1.0, total gpio=%d\n", (total/2));
+
+ for(try_count; try_count < 4; try_count++){
+ n = 0;
+ /* [1 all gpio Init] */
+ gpio_test_init_test_gpio_mode();
+
+ /* [2 GPIOTEST] */
+ for(i = 0; i < total; i = i + 2){
+ ret = gpio_register_test_out(test_gpio[i], 0);
+ if(-1 == ret){
+ n++;
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio[i]);
+ if(try_count != 3){
+ printf(" ---TEST FAILED! RETRY!--- \n");
+ usleep(5000);
+ break;
+ }
+ fail_io[n - 1] = test_gpio[i+1];
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio[i]);
+ }
+ }
+ if(0 == n){
+ break;
+ }
+ }
+ return n;
+}
+
+
+#elif (MBTK_PROJECT_T108)
+static int gpio_test(int port)
+{
+ int ret;
+ int i;
+ int valueh = 0;
+ int valuel = 1;
+
+ //printf("Gpio port [%d] test start!\n", port);
+ ret = gpio_register_set_func_0(port);
+ if(ret){
+ printf("gpio_port can't support!\n");
+ return -1;
+ }
+ gpio_register_set_direction(port, 1);
+ //ret = gpio_register_get_value(port);
+ //printf("gpio default value is: %d\n", ret);
+
+
+ //[High]
+ for(i = 0; i <= 5; i++){
+ gpio_register_set_value(port, 1);
+ usleep(50);
+ //valueh = gpio_register_get_value(port);
+ //printf("set high? %d\n", valueh);
+ if(1 == valueh){
+ break;
+ }
+ }
+
+ for(i = 0; i <= 5; i++){
+ ret = gpio_register_get_value(118);
+ if(1 == ret){
+
+ break;
+ }
+ usleep(3000);
+ }
+ //printf("count=%d \n", i);
+ //printf("******gpio should is high: %d.******\n", ret);
+ if(1 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+ //[Low]
+ usleep(200);
+ for(i = 0; i <= 9; i++){
+ gpio_register_set_value(port, 0);
+ usleep(50);
+ //valuel = gpio_register_get_value(port);
+ //printf("set low? %d\n", valuel);
+ if(0 == valuel){
+ break;
+ }
+ }
+
+ for(i = 0; i <= 5; i++){
+ ret = gpio_register_get_value(118);
+ if(0 == ret){
+
+ break;
+ }
+ usleep(3000);
+ }
+ //printf("count=%d \n", i);
+ //printf("******gpio should is low: %d.******\n", ret);
+ if(0 != ret){
+ ret=-1;
+ goto exit;
+ }
+
+exit:
+ gpio_register_set_value(port, 0);
+ gpio_register_set_direction(port, 0);
+ return ret;
+
+}
+
+static int gpio_test_init_test_gpio_mode(void)
+{
+ const int test_gpio[] = {
+ 99,8,117,21,22,23,24,41,120,19,123,
+ 58,59,57,56,55,48,125,127,36,35,34,
+ 33,54,47,53,46,50,49,11,10,26,28,25,
+ 27,32,31,51,52,39,40,37,38,
+ 44,45
+ };
+
+ int i, j, ret, total, n = 0;
+ total = (sizeof(test_gpio)/sizeof(int));
+ //printf("[init]gpio_test_init_test_gpio_mode BEGIN\n");
+
+ /* [1 all gpio set to low] */
+ gpio_register_set_func_0(118);
+ gpio_register_set_direction(118, 0);
+
+ for(j = 0; j < 5 ; j++){
+ for(i = 0; i < total; i++){
+ gpio_register_set_func_0(test_gpio[i]);
+ gpio_register_set_direction(test_gpio[i], 1);
+ gpio_register_set_value(test_gpio[i], 0);
+ //ret = gpio_register_get_value(test_gpio[i]);
+ //printf("[init]get gpio%d=%d\n", test_gpio[i], ret);
+ }
+
+
+ for(i = 0; i <= 10; i++){
+ ret = gpio_register_get_value(118);
+ //printf("[init]get gpi118=%d\n", ret);
+ usleep(3000);
+ if(0 == (ret)){
+ break;
+ }
+ }
+
+ //printf("pre set 118: %d, times: %d\n",(ret), j);
+ if(0 == (ret)){
+ break;
+ }
+ }
+ if(0 != (ret)){
+ printf("!!!Set all low FAIL, please retest\n");
+ return -1;
+ }
+ return 0;
+}
+
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+ const int test_gpio[] = {
+ //GPIO PIN GPIO PIN GPIO PIN GPIO PIN
+ 99, 170, 8, 171, 117, 59, 21, 61,
+ 22, 62, 23, 144, 24, 147, 41, 159,
+ 120, 143, 19, 3, 123, 5, 58, 18,
+ 59, 19, 57, 20, 56, 21, 55, 22,
+ 48, 23, 125, 149, 127, 160, 36, 77,
+ 35, 78, 34, 79, 33, 80, 54, 163,
+ #if 0 //Hard Ware ERROR!
+ 47, 164,
+ 46, 166,
+ #endif
+ 53, 165, 50, 42, 49, 43, 11, 73,
+ 10, 74, 26, 65, 28, 66, 25, 67,
+ 27, 68, 32, 56, 31, 57, 51, 58,
+ 52, 60, 39, 192, 40, 193, 37, 194,
+ 38, 195,
+ #if 0 //undefine GNSS
+ 44, 161,
+ 45, 151,
+ #endif
+ };
+
+ int i, n = 0, ret, total;
+ int *fail_io = (int *)arg;
+ int try_count;
+ total = (sizeof(test_gpio)/sizeof(int));
+ printf("T108 V2 Start test gpio V0.8, total gpio=%d\n", (total/2));
+
+ for(try_count = 0; try_count < 4; try_count++){
+ n = 0;
+ /* [1 all gpio Init] */
+ gpio_test_init_test_gpio_mode();
+
+ /* [2 GPIOTEST] */
+ for(i = 0; i < total; i = i + 2){
+ ret = gpio_test(test_gpio[i]);
+ if(-1 == ret){
+ n++;
+ printf("!!!!!!!!!!!!gpio [%d] test failed!!!!!!!!!!!!\n", test_gpio[i]);
+ if(try_count != 3){
+ printf(" ---TEST FAILED! RETRY!--- \n");
+ usleep(5000);
+ break;
+ }
+ fail_io[n - 1] = test_gpio[i + 1];
+ }else{
+ //printf("############gpio [%d] test success############\n", test_gpio[i]);
+ }
+ }
+ if(0 == n){
+ printf(" ---ALL PASS---\n");
+ break;
+ }
+ }
+ return n;
+}
+
+
+#else
+int mbtk_at_gpio(bool gnss_support, void* arg)
+{
+ return -1;
+}
+
+#endif
+
diff --git a/mbtk/libmbtk_lib/factory/mbtk_gpio_def.h b/mbtk/libmbtk_lib/factory/mbtk_gpio_def.h
new file mode 100755
index 0000000..4234f86
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_gpio_def.h
@@ -0,0 +1,173 @@
+/**
+ * \file gpio-define.h
+ * \brief A Documented file.
+ *
+ * Detailed description
+ * \Author: Sniper <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-04-26
+ */
+
+#ifndef __GPIO_DEFINE_H__
+#define __GPIO_DEFINE_H__
+
+typedef unsigned int uint32; /* Unsigned 32 bit value */
+typedef unsigned short uint16; /* Unsigned 16 bit value */
+typedef unsigned char uint8; /* Unsigned 8 bit value */
+
+
+/*
+4组GPIO共128个GPIO,分别从GPIO_0到GPIO_127
+GPIO22位于0xd4019000这一组的BIT22
+
+GPIO0_BASE 0xD4019000
+GPIO1_BASE 0xD4019004
+GPIO2_BASE 0xD4019008
+GPIO3_BASE 0xD4019100
+ */
+
+#define GPIO_FUNC_MMC1_DAT3 0xD401E094
+#define GPIO_FUNC_MMC1_DAT2 0xD401E098
+#define GPIO_FUNC_MMC1_DAT1 0xD401E09C
+#define GPIO_FUNC_MMC1_DAT0 0xD401E0A0
+#define GPIO_FUNC_MMC1_CMD 0xD401E0A4
+#define GPIO_FUNC_MMC1_CLK 0xD401E0A8
+#define GPIO_FUNC_MMC1_CD 0xD401E0AC
+#define GPIO_FUNC_USB_ID 0xD401E0B0
+#define GPIO_FUNC_PRI_TDI 0xD401E0B4
+#define GPIO_FUNC_PRI_TMS 0xD401E0B8
+#define GPIO_FUNC_PRI_TCK 0xD401E0BC
+#define GPIO_FUNC_PRI_TDO 0xD401E0C0
+#define GPIO_FUNC_QSPI_VMODE_GPIO 0xD401E0C4
+#define GPIO_FUNC_VBUS_DRV 0xD401E0C8
+#define GPIO_FUNC_CLK_REQ 0xD401E0CC
+#define GPIO_FUNC_VCXO_REQ 0xD401E0D4
+#define GPIO_FUNC_VCXO_OUT 0xD401E0D8
+
+#define GPIO_FUNC_GPIO_00 0xD401E0DC
+#define GPIO_FUNC_GPIO_01 0xD401E0E0
+#define GPIO_FUNC_GPIO_02 0xD401E0E4
+#define GPIO_FUNC_GPIO_03 0xD401E0E8
+#define GPIO_FUNC_GPIO_04 0xD401E0EC
+#define GPIO_FUNC_GPIO_05 0xD401E0F0
+#define GPIO_FUNC_GPIO_06 0xD401E0F4
+#define GPIO_FUNC_GPIO_07 0xD401E0F8
+#define GPIO_FUNC_GPIO_08 0xD401E0FC
+#define GPIO_FUNC_GPIO_09 0xD401E100
+#define GPIO_FUNC_GPIO_10 0xD401E104
+
+#define GPIO_FUNC_GPIO_11 0xD401E108
+#define GPIO_FUNC_GPIO_12 0xD401E10C
+#define GPIO_FUNC_GPIO_13 0xD401E110
+#define GPIO_FUNC_GPIO_14 0xD401E114
+#define GPIO_FUNC_GPIO_15 0xD401E118
+#define GPIO_FUNC_GPIO_16 0xD401E11C
+#define GPIO_FUNC_GPIO_17 0xD401E120
+#define GPIO_FUNC_GPIO_18 0xD401E124
+#define GPIO_FUNC_GPIO_19 0xD401E128
+#define GPIO_FUNC_GPIO_20 0xD401E12C
+
+#define GPIO_FUNC_GPIO_21 0xD401E130
+#define GPIO_FUNC_GPIO_22 0xD401E134
+#define GPIO_FUNC_GPIO_23 0xD401E138
+#define GPIO_FUNC_GPIO_24 0xD401E13C
+#define GPIO_FUNC_GPIO_25 0xD401E140
+#define GPIO_FUNC_GPIO_26 0xD401E144
+#define GPIO_FUNC_GPIO_27 0xD401E148
+#define GPIO_FUNC_GPIO_28 0xD401E14C
+#define GPIO_FUNC_GPIO_29 0xD401E150
+#define GPIO_FUNC_GPIO_30 0xD401E154
+
+#define GPIO_FUNC_GPIO_31 0xD401E158
+#define GPIO_FUNC_GPIO_32 0xD401E15C
+#define GPIO_FUNC_GPIO_33 0xD401E160
+#define GPIO_FUNC_GPIO_34 0xD401E164
+#define GPIO_FUNC_GPIO_35 0xD401E168
+#define GPIO_FUNC_GPIO_36 0xD401E16C
+#define GPIO_FUNC_GPIO_37 0xD401E170
+#define GPIO_FUNC_GPIO_38 0xD401E174
+#define GPIO_FUNC_GPIO_39 0xD401E178
+#define GPIO_FUNC_GPIO_40 0xD401E17C
+
+#define GPIO_FUNC_GPIO_41 0xD401E180
+#define GPIO_FUNC_GPIO_42 0xD401E184
+#define GPIO_FUNC_GPIO_43 0xD401E188
+#define GPIO_FUNC_GPIO_44 0xD401E18C
+#define GPIO_FUNC_GPIO_45 0xD401E190
+#define GPIO_FUNC_GPIO_46 0xD401E194
+#define GPIO_FUNC_GPIO_47 0xD401E198
+#define GPIO_FUNC_GPIO_48 0xD401E19C
+#define GPIO_FUNC_GPIO_49 0xD401E1A0
+#define GPIO_FUNC_GPIO_50 0xD401E1A4
+
+#define GPIO_FUNC_GPIO_51 0xD401E1A8
+#define GPIO_FUNC_GPIO_52 0xD401E1AC
+#define GPIO_FUNC_GPIO_53 0xD401E1B0
+#define GPIO_FUNC_GPIO_54 0xD401E1B4
+#define GPIO_FUNC_DVL_0 0xD401E2B4
+#define GPIO_FUNC_DVL_1 0xD401E2B8
+#define GPIO_FUNC_GPIO_69 0xD401E2BC
+#define GPIO_FUNC_GPIO_70 0xD401E2C0
+
+#define GPIO_FUNC_QSPI_DAT3 0xD401E2C4
+#define GPIO_FUNC_QSPI_DAT2 0xD401E2C8
+#define GPIO_FUNC_QSPI_DAT1 0xD401E2CC
+#define GPIO_FUNC_QSPI_DAT0 0xD401E2D0
+#define GPIO_FUNC_QSPI_CLK 0xD401E2D4
+#define GPIO_FUNC_QSPI_CS1 0xD401E2D8
+#define GPIO_FUNC_GPIO_77 0xD401E2DC
+#define GPIO_FUNC_GPIO_78 0xD401E2E0
+#define GPIO_FUNC_GPIO_79 0xD401E2E4
+#define GPIO_FUNC_GPIO_80 0xD401E2E8
+
+#define GPIO_FUNC_SDIO_DAT3 0xD401E2EC
+#define GPIO_FUNC_SDIO_DAT2 0xD401E2F0
+#define GPIO_FUNC_SDIO_DAT1 0xD401E2F4
+#define GPIO_FUNC_SDIO_DAT0 0xD401E2F8
+#define GPIO_FUNC_SDIO_CMD 0xD401E2FC
+#define GPIO_FUNC_SDIO_CLK 0xD401E300
+#define GPIO_FUNC_GPIO_60 0xD401E304
+#define GPIO_FUNC_USIM_UCLK 0xD401E320
+#define GPIO_FUNC_USIM_UIO 0xD401E324
+#define GPIO_FUNC_USIM_URSTn 0xD401E328
+
+#define MMC1_DAT3 0x
+
+
+
+#define GPIO0_BASE 0xD4019000
+#define GPIO1_BASE 0xD4019004
+#define GPIO2_BASE 0xD4019008
+#define GPIO3_BASE 0xD4019100
+
+struct gpio_register_function
+{
+ int reg;
+ int func_gpio; // 第 [func_gpio] 功能为 GPIO
+};
+
+typedef struct
+{
+ uint16 output_pin;
+ uint16 input_pin;
+ uint8 mbtk_gpio_test_result; // 0 is pass, 1 is low failed, 2 is high failed
+}mbtk_gpio_test_pin_paired;
+
+
+typedef struct
+{
+ uint16 output_pin;
+ uint16 output_gpio;
+ uint16 input_gpio;
+ uint16 input_pin;
+ uint8 mbtk_gpio_test_result; // 0 is pass, 1 is low failed, 2 is high failed
+}mbtk_gpio_paired_info_struct;
+
+typedef struct
+{
+ uint16 gpio_num;
+ uint16 pin_num; //moudle pin num
+}mbtk_gpio_test_pin_and_gpio;
+
+#endif /*__GPIO_DEFINE_H__*/
+
diff --git a/mbtk/libmbtk_lib/factory/mbtk_power.c b/mbtk/libmbtk_lib/factory/mbtk_power.c
new file mode 100755
index 0000000..753f17f
--- /dev/null
+++ b/mbtk/libmbtk_lib/factory/mbtk_power.c
@@ -0,0 +1,692 @@
+#if 1
+#include <fcntl.h>
+#include <stdint.h>
+#include <libubox/blobmsg_json.h>
+#include <libubus.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+
+#include "mbtk_power.h"
+/****************************DEFINE***************************************/
+#define MBTK_POWER_RESULT_FAIL -1
+#define MBTK_POWER_RESULT_SUCCESS 0
+
+
+#define MBTK_POWER_CLOSE_FAIL -1
+#define MBTK_POWER_CLOSE_SUCCESS 0
+
+#define GNSS_SOCK_PATH "/tmp/mbtk_gnss_sock"
+
+static int sock_listen_fd = -1;
+
+typedef enum {
+ GNSS_CMD_INIT = 0,
+ GNSS_CMD_DEINIT,
+ GNSS_CMD_SETTING,
+ GNSS_CMD_DL
+} gnss_cmd_enum;
+
+
+/****************************DEFINE***************************************/
+
+/****************************VARIABLE***************************************/
+const struct blobmsg_policy mbtk_power_cb_policy1[] = {
+ [0] = {
+ .name = "event",
+ .type = BLOBMSG_TYPE_INT32,
+ },
+};
+/****************************VARIABLE***************************************/
+
+/****************************FUNC***************************************/
+static void mbtk_power_gnss_callback(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ UNUSED(type);
+
+ struct blob_attr *tb[1];
+ struct blob_attr *cur;
+ unsigned int event;
+ int *ubus_gnss_result = (int *)req->priv;
+ int rc;
+
+ /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+ rc = blobmsg_parse(mbtk_power_cb_policy1, 1, tb, blob_data(msg), blob_len(msg));
+ if (rc < 0)
+ {
+ LOGE("[MBTK_POWER] blobmsg_parse fail.");
+ //printf("blobmsg_parse fail\n");
+ *ubus_gnss_result = MBTK_POWER_CLOSE_FAIL;
+ return;
+ }
+
+ /*parse first parameter*/
+ cur = tb[0];
+ if (!cur)
+ {
+ LOGE("[MBTK_POWER] missing parameter.");
+ //printf("missing parameter\n");
+ *ubus_gnss_result = MBTK_POWER_CLOSE_FAIL;
+ return;
+ }
+
+ event = blobmsg_get_u32(cur);
+ LOGE("[MBTK_POWER] get event = [%d].", event);
+ //printf("get event = [%d].\n", event);
+
+#if 1
+ if(event != 0)
+#else
+ if(event != 7)
+#endif
+ {
+ *ubus_gnss_result = MBTK_POWER_CLOSE_FAIL;
+ }
+
+ return ;
+}
+
+static int mbtk_power_ubus_uloop_init(struct ubus_context **ctx)
+{
+ int ret = -1;
+ if(ctx == NULL)
+ {
+ LOGE("[MBTK_POWER] ctx is NULL");
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ ret = uloop_init();
+ if(ret != 0)
+ {
+ LOGE("[MBTK_POWER] uloop_init fail.ret = [%d]", ret);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ if(*ctx != NULL)
+ {
+ LOGE("[MBTK_POWER] mbtk_gnss_ctx not NULL.");
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ *ctx = ubus_connect(NULL);
+ if( !(*ctx) )
+ {
+ LOGE("[MBTK_POWER] ubus_connect fail.");
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ ubus_add_uloop(*ctx);
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+static int mbtk_power_ubus_uloop_deinit(struct ubus_context *ctx)
+{
+ if(ctx != NULL)
+ {
+ ubus_free(ctx);
+ ctx = NULL;
+ }
+
+ uloop_done();
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+static int mbtk_power_invoke_reply_data_cb(const char *service, const char *method, struct blob_attr *msg,
+ ubus_data_handler_t cb, void *cb_param, int timeout, struct ubus_context *ctx)
+{
+ int rc = -1;
+ uint32_t id;
+ struct ubus_request req;
+
+ /* Look up the target object id by the object path */
+ rc = ubus_lookup_id(ctx, service, &id);
+ if(rc)
+ {
+ LOGE("[MBTK_POWER] ubus_lookup_id fail.rc = [%d]", rc);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ rc = ubus_invoke(ctx, id, method, msg, cb, cb_param, timeout);
+ if(rc)
+ {
+ LOGE("[MBTK_POWER] ubus_invoke fail.rc = [%d]", rc);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+ //mbtk wyq for AT+MGPSC add start
+
+#if 0//#ifndef MBTK_GNSS_FACTORY_TEST_MODE
+ if(strncasecmp((char const *)line, "AT+MGPSC=", strlen("AT+MGPSC=")) == 0)
+ {
+ int mode,ret = 0;
+ (void)sscanf((const char *)line, "%*[^0-9]%d", &mode);
+ if(mode == 1 || mode == 5)
+ {
+ if(modem_if.echo_mode == MODEM_ECHO_MODE)
+ {
+ writen(ppp_uart2_fd, line, 10);
+ }
+
+ ret = mbtk_GPS_process(GNSS_CMD_INIT, &mode);
+
+ if(-1 == ret)
+ {
+ const char RESP_BUFF[] = "\r\n+GPS: gps server timeout.\r\n\r\nERROR\r\n";
+ writen(ppp_uart2_fd, RESP_BUFF, sizeof(RESP_BUFF) - 1);
+ }
+ else
+ {
+ const char RESP_BUFF[] = "\r\n+GPS: gps init success\r\n";
+ writen(ppp_uart2_fd, RESP_BUFF, sizeof(RESP_BUFF) - 1);
+ }
+ continue;
+ }
+ }
+#endif
+ //mbtk wyq for AT+MGPSC add end
+
+ static int mbtk_GPS_process(gnss_cmd_enum cmd, void *arg)
+ {
+ if(sock_listen_fd < 0) {
+ sock_listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(sock_listen_fd < 0)
+ {
+ LOGE("[MBTK_POWER]socket() fail[%d].", errno);
+ return -1;
+ }
+
+ struct sockaddr_un cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sun_family = AF_LOCAL;
+ strcpy(cli_addr.sun_path, GNSS_SOCK_PATH);
+ if(connect(sock_listen_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+ {
+ LOGE("[MBTK_POWER]connect() fail[%d].", errno);
+ close(sock_listen_fd);
+ sock_listen_fd = -1;
+ return -1;
+ }
+ }
+
+ char buff[100] = {0};
+ if(cmd == GNSS_CMD_INIT) {
+ if(arg) {
+ sprintf(buff, "gnss_init:%d", *(int*)arg);
+ } else {
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DEINIT) {
+ sprintf(buff, "gnss_deinit");
+ } else if(cmd == GNSS_CMD_SETTING) {
+ sprintf(buff, "gnss_setting:%s", arg);
+ } else if(cmd == GNSS_CMD_DL) {
+ sprintf(buff, "gnss_dl:%s", arg);
+ } else {
+ LOGE("[MBTK_POWER]Unknown cmd.");
+ return -1;
+ }
+
+ write(sock_listen_fd, buff, strlen(buff));
+
+ int len = 0;
+ while(1) {
+ memset(buff, 0, sizeof(buff));
+ len = read(sock_listen_fd, buff, sizeof(buff));
+ if(len > 0) {
+ LOGE("[MBTK_POWER]RSP : %s", buff);
+ if(cmd == GNSS_CMD_INIT) {
+ if(strstr(buff, "gnss_init") != 0) {
+ return 0;
+ } else {
+ LOGE("[MBTK_POWER]gnss_init response error.");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DEINIT) {
+ if(strstr(buff, "gnss_deinit") != 0) {
+ return 0;
+ } else {
+ LOGE("[MBTK_POWER]gnss_deinit response error.");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_SETTING) {
+ if(strstr(buff, "gnss_setting") != 0) {
+ return 0;
+ } else {
+ LOGE("[MBTK_POWER]gnss_setting response error.");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DL) {
+ if(strstr(buff, "gnss_dl") != 0) {
+ return 0;
+ } else {
+ LOGE("[MBTK_POWER]gnss_dl response error.");
+ return -1;
+ }
+ } else {
+ LOGE("[MBTK_POWER]Unknown response.\n");
+ return -1;
+ }
+ } else if(len == 0) {
+ LOGE("[MBTK_POWER]RSP is null.");
+ return -1;
+ } else {
+ LOGE("[MBTK_POWER]read = %d:errno = %d", len, errno);
+ }
+ }
+ }
+
+
+ int mbtk_mgpsc_set(int arg)
+ {
+ int ret = 0;
+ int *p = 3;
+
+ if (arg == 1)
+ {
+ ret = mbtk_GPS_process(GNSS_CMD_INIT, &p);
+
+ if (-1 == ret)
+ {
+ LOGE("[MBTK_POWER] mbtk_mgpsc_set fail.");
+ return -1;
+ }
+ }
+ else
+ {
+ ret = mbtk_GPS_process(GNSS_CMD_DEINIT, NULL);
+
+ if (-1 == ret)
+ {
+ LOGE("[MBTK_POWER] mbtk_mgpsc_set fail.");
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+
+
+
+static int mbtk_power_gnss_close(void)
+{
+ int ret = 0;
+
+ ret = mbtk_GPS_process(GNSS_CMD_DEINIT, NULL);
+
+ if (-1 == ret)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close fail.");
+ return MBTK_POWER_CLOSE_FAIL;
+ }
+
+ return MBTK_POWER_CLOSE_SUCCESS;
+}
+
+static int gpio_direct_set(char *value,int gpio)
+{
+ char buffer[50]= {0};
+ int file =-1;
+ int result =-1;
+
+ memset(buffer,0,50);
+ sprintf(buffer,"/sys/class/gpio/gpio%d/direction", gpio);
+ file = open(buffer, O_WRONLY);
+ if(file == -1)
+ {
+ LOGE("[MBTK_POWER] Open gpio[%d] direct fail.", gpio);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ result = write(file,value,strlen(value));
+ if(result != strlen(value))
+ {
+ LOGE("[MBTK_POWER] Set gpio[%d] direct fail.", gpio);
+ close(file);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+ close(file);
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+static int gpio_value_set(int value, int gpio)
+{
+ char buffer[50]= {0};
+ int file =-1;
+ int result =-1;
+
+ memset(buffer,0,50);
+ sprintf(buffer,"/sys/class/gpio/gpio%d/value", gpio);
+ file = open(buffer,O_WRONLY);
+ if(file == -1)
+ {
+ LOGE("[MBTK_POWER] Open gpio[%d] value fail.", gpio);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+ if(value == 0) {
+ result = write(file,"0",1);
+ } else {
+ result = write(file,"1",1);
+ }
+ if(result != 1)
+ {
+ LOGE("[MBTK_POWER] Set gpio[%d] value fail.", gpio);
+ close(file);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+ close(file);
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+//type:0 value 0
+//type:1 value 1
+//type:2 direction "out"
+//type:3 direction "in"
+
+static int one_gpio_export(int gpio, int type)
+{
+ int index=0;
+ int file=-1;
+ int file1=-1;
+ int result =-1;
+ char pin_index_buffer[5]= {0};
+ char buffer[50]= {0};
+ int ret =0;
+
+ file = open("/sys/class/gpio/export",O_WRONLY);
+ if(file == -1)
+ {
+ LOGE("[MBTK_POWER] Open gpio export file fail.");
+ return MBTK_POWER_RESULT_FAIL;
+ }
+
+ memset(buffer,0,50);
+ sprintf(buffer,"/sys/class/gpio/gpio%d", gpio);
+ file1 = open(buffer,O_RDONLY);
+ if(file1 != -1)
+ {
+ //file is created
+ close(file1);
+ }
+ else
+ { // create gpio
+ memset(pin_index_buffer,0,5);
+ sprintf(pin_index_buffer,"%d",gpio);
+ result = write(file,pin_index_buffer,strlen(pin_index_buffer));
+ if(result < 0)
+ {
+ LOGE("[MBTK_POWER] Gpio[%d] export fail.", gpio);
+ return MBTK_POWER_RESULT_FAIL;
+ }
+ }
+
+ close(file);
+
+
+ switch(type)
+ {
+ case 0 :
+ {
+ ret = gpio_value_set(0, gpio);
+ break;
+ }
+ case 1:
+ {
+ ret = gpio_value_set(1, gpio);
+ break;
+ }
+ case 2:
+ {
+ ret = gpio_direct_set("out", gpio);
+ break;
+ }
+ case 3:
+ {
+ ret = gpio_direct_set("in", gpio);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+
+ return ret;
+}
+
+/****************************FUNC***************************************/
+
+/****************************API***************************************/
+#if defined(MBTK_PROJECT_T108)
+int mbtk_system_sleep(void)
+{
+ int ubus_ret = 0;
+
+ ubus_ret = mbtk_power_gnss_close();
+ if(ubus_ret < 0)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close() fail.");
+ return MBTK_POWER_RESULT_GNSS_CLOSE_FAIL;
+ }
+
+ // echo off > /sys/devices/mbtk-dev-op.10/gps_power && echo mem > /sys/power/autosleep
+ // echo 1 > /sys/devices/asr-rfkill.0/pwr_ctrl && sleep 2 && echo 0 > /sys/devices/asr-rfkill.0/pwr_ctrl
+
+ if(!access("/sys/power/autosleep", W_OK))
+ {
+ system("echo mem > /sys/power/autosleep");
+ }
+ else
+ {
+ LOGE("[MBTK_POWER] /sys/power/autosleep can not write.");
+ //printf("/sys/power/autosleep can not write.");
+ return MBTK_POWER_RESULT_NO_SLEEP_NODE;
+ }
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+#elif defined(MBTK_PROJECT_L508_X6)
+int mbtk_system_sleep(void)
+{
+ int ubus_ret = 0;
+
+ ubus_ret = mbtk_power_gnss_close();
+ if(ubus_ret < 0)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close() fail.");
+ return MBTK_POWER_RESULT_GNSS_CLOSE_FAIL;
+ }
+
+ // echo off > /sys/devices/mbtk-dev-op.10/gps_power && echo mem > /sys/power/autosleep
+ // echo 1 > /sys/devices/asr-rfkill.0/pwr_ctrl && sleep 2 && echo 0 > /sys/devices/asr-rfkill.0/pwr_ctrl
+ //close Ldo6
+ system("i2cset -y -f 2 0x31 0x18 0x0f");
+ //GPS_WAKE_HOST to GPIO
+ system("hwacc w 0xd401e198 0x1040");
+ //HOST_WAKE_GPS to GPIO
+ //system("hwacc w 0xd401e0c0 0x1040");
+ //gpio34 to GPIO
+#if 1
+ system("hwacc w 0xd401e164 0x1040");
+ system("hwacc w 0xd401e166 0x1040");
+ system("hwacc w 0xd401e1b4 0x1040");
+
+ system("hwacc w 0xd401e2ec 0xa441");
+ system("hwacc w 0xd401e2f0 0xa441");
+ system("hwacc w 0xd401e2f4 0xa441");
+ system("hwacc w 0xd401e2f8 0xa441");
+ system("hwacc w 0xd401e2fc 0xa441");
+ system("hwacc w 0xd401e300 0xa441");
+#endif
+ one_gpio_export(117, 2);
+ one_gpio_export(117, 0);
+
+ one_gpio_export(119, 2);
+ one_gpio_export(119, 0);
+
+ one_gpio_export(127, 2);
+ one_gpio_export(127, 0);
+
+ one_gpio_export(33, 2);
+ one_gpio_export(33, 0);
+
+ one_gpio_export(34, 2);
+ one_gpio_export(34, 0);
+
+ one_gpio_export(54, 2);
+ one_gpio_export(54, 0);
+
+ one_gpio_export(21, 2);
+ one_gpio_export(21, 0);
+
+ one_gpio_export(118, 2);
+ one_gpio_export(118, 0);
+
+ if(!access("/sys/power/autosleep", W_OK))
+ {
+ system("echo mem > /sys/power/autosleep");
+ }
+ else
+ {
+ LOGE("[MBTK_POWER] /sys/power/autosleep can not write.");
+ //printf("/sys/power/autosleep can not write.");
+ return MBTK_POWER_RESULT_NO_SLEEP_NODE;
+ }
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+#elif defined(MBTK_PROJECT_L509)
+int mbtk_system_sleep(void)
+{
+ int ubus_ret = 0;
+
+ ubus_ret = mbtk_power_gnss_close();
+ if(ubus_ret < 0)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close() fail.");
+ return MBTK_POWER_RESULT_GNSS_CLOSE_FAIL;
+ }
+
+ // echo off > /sys/devices/mbtk-dev-op.10/gps_power && echo mem > /sys/power/autosleep
+ // echo 1 > /sys/devices/asr-rfkill.0/pwr_ctrl && sleep 2 && echo 0 > /sys/devices/asr-rfkill.0/pwr_ctrl
+
+ one_gpio_export(120, 2);
+ one_gpio_export(120, 0);
+
+ one_gpio_export(21, 2);
+ one_gpio_export(21, 0);
+
+ one_gpio_export(118, 2);
+ one_gpio_export(118, 0);
+
+ if(!access("/sys/power/autosleep", W_OK))
+ {
+ system("echo mem > /sys/power/autosleep");
+ }
+ else
+ {
+ LOGE("[MBTK_POWER] /sys/power/autosleep can not write.");
+ //printf("/sys/power/autosleep can not write.");
+ return MBTK_POWER_RESULT_NO_SLEEP_NODE;
+ }
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+#elif defined(MBTK_PROJECT_L508)
+int mbtk_system_sleep(void)
+{
+ int ubus_ret = 0;
+
+ ubus_ret = mbtk_power_gnss_close();
+ if(ubus_ret < 0)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close() fail.");
+ return MBTK_POWER_RESULT_GNSS_CLOSE_FAIL;
+ }
+
+ // echo off > /sys/devices/mbtk-dev-op.10/gps_power && echo mem > /sys/power/autosleep
+ // echo 1 > /sys/devices/asr-rfkill.0/pwr_ctrl && sleep 2 && echo 0 > /sys/devices/asr-rfkill.0/pwr_ctrl
+
+ one_gpio_export(119, 2);
+ one_gpio_export(119, 0);
+
+ one_gpio_export(21, 2);
+ one_gpio_export(21, 0);
+
+ one_gpio_export(118, 2);
+ one_gpio_export(118, 0);
+
+ if(!access("/sys/power/autosleep", W_OK))
+ {
+ system("echo mem > /sys/power/autosleep");
+ }
+ else
+ {
+ LOGE("[MBTK_POWER] /sys/power/autosleep can not write.");
+ //printf("/sys/power/autosleep can not write.");
+ return MBTK_POWER_RESULT_NO_SLEEP_NODE;
+ }
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+#elif defined(MBTK_PROJECT_PN1803)
+int mbtk_system_sleep(void)
+{
+ int ubus_ret = 0;
+
+ ubus_ret = mbtk_power_gnss_close();
+ if(ubus_ret < 0)
+ {
+ LOGE("[MBTK_POWER] mbtk_power_gnss_close() fail.");
+ return MBTK_POWER_RESULT_GNSS_CLOSE_FAIL;
+ }
+
+ // echo off > /sys/devices/mbtk-dev-op.10/gps_power && echo mem > /sys/power/autosleep
+ // echo 1 > /sys/devices/asr-rfkill.0/pwr_ctrl && sleep 2 && echo 0 > /sys/devices/asr-rfkill.0/pwr_ctrl
+
+ one_gpio_export(119, 2);
+ one_gpio_export(119, 0);
+
+ one_gpio_export(21, 2);
+ one_gpio_export(21, 0);
+
+ one_gpio_export(118, 2);
+ one_gpio_export(118, 0);
+
+ if(!access("/sys/power/autosleep", W_OK))
+ {
+ system("echo mem > /sys/power/autosleep");
+ }
+ else
+ {
+ LOGE("[MBTK_POWER] /sys/power/autosleep can not write.");
+ //printf("/sys/power/autosleep can not write.");
+ return MBTK_POWER_RESULT_NO_SLEEP_NODE;
+ }
+
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+
+#else
+int mbtk_system_sleep(void)
+{
+ return MBTK_POWER_RESULT_SUCCESS;
+}
+#endif
+/****************************API***************************************/
+#endif
diff --git a/mbtk/libmbtk_lib/fota/mbtk_fota.c b/mbtk/libmbtk_lib/fota/mbtk_fota.c
new file mode 100755
index 0000000..68e2ba0
--- /dev/null
+++ b/mbtk/libmbtk_lib/fota/mbtk_fota.c
@@ -0,0 +1,427 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <libubox/blobmsg_json.h>
+#include "libubus.h"
+#include "mbtk_fota.h"
+#include <semaphore.h>
+#include <cutils/properties.h>
+
+#include "mbtk_log.h"
+
+
+#ifdef DEBUG
+ #define fota_log(...) printf(__VA_ARGS__)
+#else
+ #define fota_log(...)
+#endif
+
+#define UNUSEDPARAM(param) (void)param;
+#define OTA_MAX_STRING_LEN 128
+
+static struct ubus_context *fota_ubus_ctx = NULL;
+static uint32_t fota_request_id;
+static struct ubus_subscriber notification_event;
+static pthread_t fota_status_pthread;
+static struct blob_buf b;
+static fota_callback fota_cb = NULL;
+sem_t sem;
+volatile int fota_dowload_flag = -1;
+//3: upding
+//4: updata success
+//5: updata fail
+
+enum {
+ ATTR_SMSGPS,
+ ATTR_SMSGPS_MAX,
+};
+
+static const struct blobmsg_policy ota_info_attr_policy[] = {
+ [ATTR_SMSGPS] ={.name = "notification", .type = BLOBMSG_TYPE_STRING,},
+};
+
+/**
+ * \brief strstr_n
+ *
+ * find string return number
+ *
+ * \param param
+ * \return return type
+ */
+static int strstr_n(const char *s1, const char *s2)
+{
+ int n;
+ int strlen = 0;
+
+ if(*s2) {
+ while(*s1) {
+ for(n = 0; *(s1+n) == *(s2 + n); n++) {
+ if(!*(s2 + n + 1)) {
+ strlen++;
+ return strlen;
+ }
+ }
+ s1++;
+ strlen++;
+ }
+ return 0;
+ }
+ else
+ return 0;
+}
+
+static int otad_notify(struct ubus_context* ctx, struct ubus_object* obj,
+ struct ubus_request_data* req, const char* method,
+ struct blob_attr* msg)
+{
+ UNUSEDPARAM(ctx);
+ UNUSEDPARAM(obj);
+ UNUSEDPARAM(req);
+ UNUSEDPARAM(method);
+ // User can get downloading process information from here
+ int ret, len;
+ char progress[4] = {0};
+ char *notify_str;
+
+ struct blob_attr *tb[ATTR_SMSGPS_MAX];
+ ret = blobmsg_parse(ota_info_attr_policy, ARRAY_SIZE(ota_info_attr_policy), tb,
+ blob_data(msg), blob_len(msg));
+
+ if (ret || !tb[ATTR_SMSGPS]) {
+ printf("invalid SMS\n");
+ return -1;
+ }
+
+ notify_str = blobmsg_get_string(tb[ATTR_SMSGPS]);
+ len = strlen(notify_str);
+ LOGE("%s : %s\r\n", __FUNCTION__, notify_str);
+// printf("L11111%s : %s\r\n", __FUNCTION__, notify_str);
+ if (strstr_n(notify_str, "start")) {
+ fota_cb(0, 0);
+ } else if (strstr_n(notify_str, "end[1]")) {
+ fota_cb(0, 100);
+ fota_dowload_flag = 4;
+// sem_post(&sem);
+ LOGE("download firmware success!\r\n");
+ } else if (strstr_n(notify_str, "end[0]")) {
+ fota_cb(1, 100);
+ fota_dowload_flag = 5;
+// sem_post(&sem);
+ LOGE("download firmware fail!\r\n");
+ }
+ ret = strstr_n(notify_str, "progress");
+ if (ret) {
+ memcpy(progress, ¬ify_str[ret + 8], len - ret - 9);
+ fota_cb(0, atoi(progress));
+ }
+ return 0;
+}
+
+static void otad_subscriber_remove_cb(struct ubus_context* ctx,
+ struct ubus_subscriber* obj, uint32_t id)
+{
+ UNUSEDPARAM(ctx);
+ UNUSEDPARAM(obj);
+ UNUSEDPARAM(id);
+ LOGE("%s,%d\n", __FUNCTION__, __LINE__);
+}
+
+
+/*******************************************************************************
+* @brief write firmware package, the firmware package is written in segments.
+ and The result of the write is output by calling the callback function.
+ the firmware package size must less than 32MB
+ @param
+ fname: firmware package file
+ segment_size: the length of once write, recommending 3*1024*1024 bytes
+ @return
+ if success return 0, else return -1
+ *******************************************************************************/
+int mbtk_fota_fw_write(char* fname, int segment_size)
+{
+ fota_dowload_flag = 3;
+ LOGE("mbtk_fota_fw_write start3\n");
+ int ret = -1;
+ static struct ubus_request req;
+ int _segment_size;
+ char cmd[128]={0};
+
+ if(!access("/sys/power/wake_lock", W_OK))
+ {
+ sprintf(cmd, "echo %s > /sys/power/wake_lock", "ota_lock");
+ system(cmd);
+ LOGE("/sys/power/wake_lock success\n");
+ }
+ else
+ {
+ LOGE("/sys/power/wake_lock can not write.\n");
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "url", fname);
+ blobmsg_add_u32(&b, "type", 2);
+ blobmsg_add_u32(&b, "sync", 1);
+ _segment_size = segment_size;
+ if (_segment_size > 1024) {
+ blobmsg_add_u32(&b, "segment_size", _segment_size);
+ }
+ blobmsg_add_u32(&b, "sync", 1);
+ ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req);
+ ubus_complete_request_async(fota_ubus_ctx, &req);
+
+ while(1)
+ {
+ /* V2������ */
+// sem_wait(&sem);
+// break;
+
+ if(fota_dowload_flag != 3)
+ {
+ // printf("break while(), fota_dowload_flag:%d", fota_dowload_flag);
+ break;
+ }
+ sleep(1);
+ }
+
+ if(!access("/sys/power/wake_unlock", W_OK))
+ {
+ char cmd[128]={0};
+ sprintf(cmd, "echo %s > /sys/power/wake_unlock", "ota_lock");
+ system(cmd);
+ LOGE("/sys/power/wake_unlock success\n");
+ }
+ else
+ {
+ LOGE("/sys/power/wake_unlock can not write.\n");
+ }
+ LOGE("%s, fota_dowload_flag = :%d", __FUNCTION__, fota_dowload_flag);
+ if(fota_dowload_flag == 4)
+ {
+ ret = 0;
+ }
+ return ret;
+}
+
+/*******************************************************************************
+* @brief download firmware by url, and write firmware package, the firmware
+ package is written in segments. The result of the write is output by
+ calling the callback function. the firmware package size must less than
+ 32MB
+ @param
+ url: [IN] the address of download firmware package file, the url
+ support http or https protocol.
+ segment_size: [IN] the length of once write, recommending 3*1024*1024 bytes
+ conn_timeout: [IN] timeout to connect to the server, if set 0 that means
+ switch to the default build-in connection timeout(300s)
+ download_timeout: [IN] timeout for download the firmware file. if set 0 that means
+ it never time out
+ @return
+ if success return 0, else return -1
+ *******************************************************************************/
+int mbtk_fota_fw_write_by_url(char* url, int segment_size,
+ int conn_timeout, int download_timeout)
+{
+ LOGE("mbtk_fota_fw_write_by_url start2\n");
+ int ret = -1;
+ fota_dowload_flag = 3;
+ static struct ubus_request req;
+ int _segment_size;
+ char cmd[128]={0};
+
+ if(!access("/sys/power/wake_lock", W_OK))
+ {
+ sprintf(cmd, "echo %s > /sys/power/wake_lock", "ota_lock");
+ system(cmd);
+ LOGE("/sys/power/wake_lock success\n");
+ }
+ else
+ {
+ LOGE("/sys/power/wake_lock can not write.\n");
+ }
+
+ blob_buf_init(&b, 0);
+ blobmsg_add_string(&b, "url", url);
+ blobmsg_add_string(&b, "username", "user name");
+ blobmsg_add_u32(&b, "type", 0);
+ blobmsg_add_u32(&b, "sync", 1);
+ _segment_size = segment_size;
+ if (_segment_size > 1024) {
+ blobmsg_add_u32(&b, "segment_size", _segment_size);
+ }
+ blobmsg_add_u32(&b, "sync", 1);
+ ubus_invoke_async(fota_ubus_ctx, fota_request_id, "download", b.head, &req);
+ ubus_complete_request_async(fota_ubus_ctx, &req);
+
+ while(1)
+ {
+ /* V2������ */
+// sem_wait(&sem);
+// break;
+
+ if(fota_dowload_flag != 3)
+ {
+ // printf("break while(), fota_dowload_flag:%d", fota_dowload_flag);
+ break;
+ }
+ sleep(1);
+ }
+
+ if(!access("/sys/power/wake_unlock", W_OK))
+ {
+ char cmd[128]={0};
+ sprintf(cmd, "echo %s > /sys/power/wake_unlock", "ota_lock");
+ system(cmd);
+ LOGE("/sys/power/wake_unlock success\n");
+ }
+ else
+ {
+ LOGE("/sys/power/wake_unlock can not write.\n");
+ }
+
+ LOGE("%s, fota_dowload_flag = :%d", __FUNCTION__, fota_dowload_flag);
+ if(fota_dowload_flag == 4)
+ {
+ ret = 0;
+ }
+ return ret;
+
+}
+/*******************************************************************************
+* @brief reboot system and clear env
+ @param
+ is_reboot: if set 1, after fota success, reboot system
+ @return
+ if success return 0, else return -1
+ *******************************************************************************/
+int mbtk_fota_done(int is_reboot)
+{
+ int ret;
+
+ ret = pthread_cancel(fota_status_pthread);
+ LOGE("kill pthread : %d \n", ret);
+ pthread_join(fota_status_pthread, NULL);
+ do {
+ ret = pthread_kill(fota_status_pthread, 0);
+ LOGE("kill pthread: %d \n", ret);
+ if (ret == ESRCH) {
+ LOGE("The specified thread does not exist or has terminated\n");
+ } else if (ret == EINVAL) {
+ LOGE("Useless signal\n");
+ } else {
+ LOGE("The thread exists\n");
+ }
+ usleep(100000);
+ } while (0 == ret);
+
+
+ ubus_free(fota_ubus_ctx);
+ uloop_done();
+
+ fota_cb = NULL;
+
+ if (is_reboot) {
+ system("sync");
+ system("reboot");
+ }
+ return 0;
+
+}
+
+int mbtk_fota_done1(int is_reboot)
+{
+ if (is_reboot) {
+ system("sync");
+ system("reboot");
+ }
+ return 0;
+}
+
+void* mbtk_fota_thread(void* argc)
+{
+ int ret, retries = 0;
+ UNUSEDPARAM(argc);
+
+ printf("mbtk_fota_thread() start\n");
+ pthread_detach(pthread_self());
+ //register for ril indication
+ ret = ubus_register_subscriber(fota_ubus_ctx, ¬ification_event);
+ if (ret) {
+ LOGE("%s,%d\n", __FUNCTION__, __LINE__);
+ pthread_exit(NULL);
+ }
+ notification_event.cb = otad_notify;
+ notification_event.remove_cb = otad_subscriber_remove_cb;
+
+ ubus_subscribe(fota_ubus_ctx, ¬ification_event, fota_request_id);
+ uloop_run();
+ ubus_unsubscribe(fota_ubus_ctx, ¬ification_event, fota_request_id);
+ pthread_exit(NULL);
+
+ return NULL;
+}
+
+
+int mbtk_fota_init(fota_callback cb)
+{
+ int id;
+ int retries = 0;
+
+ /*create ubus loop to listen to RIL event*/
+ uloop_init();
+ fota_ubus_ctx = ubus_connect(NULL);
+ if (!fota_ubus_ctx) {
+ LOGE("%s,%d\n", __FUNCTION__, __LINE__);
+ uloop_done();
+ return 0;
+ }
+
+ ubus_add_uloop(fota_ubus_ctx);
+
+ do {
+ //register for ril request
+ retries = 0;
+ if (ubus_lookup_id(fota_ubus_ctx, "ota", &fota_request_id)) {
+ LOGE("%s,%d\n", __FUNCTION__, __LINE__);
+ sleep(1);
+ } else {
+ break;
+ }
+ } while (retries++ < 20);
+ if (retries >= 20) {
+ LOGE("%s,%d\n", __FUNCTION__, __LINE__);
+ goto fail1;
+ }
+ pthread_create(&fota_status_pthread, NULL, (void*)mbtk_fota_thread, NULL);
+ fota_cb = cb;
+ return 0;
+fail1:
+ return 1;
+}
+
+int mbtk_fota_get_asr_reboot_cnt_flag(void)
+{
+ int type = 0;
+ char time_type[] ={0};
+ property_get("persist.mbtk.reboot_cnt", time_type, "0");
+
+ type = atoi(time_type);
+
+ return type;
+}
+
+
+int mbtk_fota_status(void)
+{
+ return fota_dowload_flag;
+}
+
+void mbtk_fota_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_fota_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/ftp/mbtk_ftp.c b/mbtk/libmbtk_lib/ftp/mbtk_ftp.c
new file mode 100755
index 0000000..f485ec7
--- /dev/null
+++ b/mbtk/libmbtk_lib/ftp/mbtk_ftp.c
@@ -0,0 +1,3062 @@
+/*************************************************************
+ Description:
+ $file_description$
+ Author:
+ LiuBin
+ Date:
+ 2020/10/28 11:49:08
+ *************************************************************/
+#include "mbtk_ftp.h"
+#include "mbtk_list.h"
+#include "mbtk_sock.h"
+#include "mbtk_str.h"
+#include "mbtk_sock2.h"
+#include<linux/msg.h>
+
+/*************************************************************
+ Constants and Macros
+ *************************************************************/
+#define FTP_HANDLE_MAX 5
+#define FTP_ANONYMOUS_USER "Anonymous"
+#define FTP_ANONYMOUS_PASS "@"
+
+//#define FTP_RESUME_DEBUG
+
+#ifdef MBTK_PLATFORM_QCOMM
+#define FTP_TIMEOUT 60000 // 60s
+#else
+#define FTP_TIMEOUT 3000 // 3s
+#endif
+
+/*************************************************************
+ typedef struct:local at
+ *************************************************************/
+typedef struct
+{
+ char host[64];
+ uint16 port;
+ mbtk_ftp_auth_type_enum auth_type;
+ bool ftp_type;
+ bool use_cert;
+ char name[FTP_SERVER_USER_NAME_MAX+1];
+ char pass[FTP_SERVER_USER_PASS_MAX+1];
+ mbtk_ftp_handle at_ftp_handle;
+ char remote_path[MBTK_FTP_FILE_NAME_MAX+1];
+ char local_path[MBTK_FTP_FILE_NAME_MAX+1];
+ int rest_size;
+ int read_size;
+ int put_len;
+} mbtk_at_init_parameter;
+
+mbtk_at_init_parameter mbtk_at_ftp_par={0};
+
+/*************************************************************
+ Variables:local
+ *************************************************************/
+static list_node_t *ftp_client_list = NULL;
+
+/*************************************************************
+ Variables:public
+ *************************************************************/
+
+/*************************************************************
+ Local Function Declaration
+ *************************************************************/
+
+/*************************************************************
+ Local Function Definitions
+ *************************************************************/
+static bool ftp_ch_is_space(char ch)
+{
+ if (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t')
+ return true;
+
+ return false;
+}
+
+static const char* ftp_str_next(const char* str, char *result, uint32 len)
+{
+ memset(result, 0x0, len);
+ const char* ptr = str;
+ const char* ptr_result;
+ while (*ptr && ftp_ch_is_space(*ptr))
+ {
+ ptr++;
+ }
+ if (*ptr == '\0')
+ {
+ return NULL;
+ }
+ // Point to first no space char.
+ ptr_result = ptr;
+ while (*ptr && !ftp_ch_is_space(*ptr))
+ {
+ ptr++;
+ }
+
+ // Point to first space char or '\0'.
+ memcpy(result, ptr_result, ptr - ptr_result);
+
+ if (*ptr == '\0')
+ {
+ return NULL;
+ }
+
+ return ptr;
+}
+
+static int ftp_cmd_handle(mbtk_ftp_info_s *info, const void *cmd, void *rsp,
+ uint32 *rsp_len)
+{
+ int err;
+ int rsp_code;
+ int len = strlen((char*) cmd);
+ // Write cmd
+ if(info->auth_type != 0)
+ {
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,cmd,len,60000,&err);
+ if(err!=0)
+ {
+ printf("\nmbtk_sock_write error:%d\n",err);
+ return err;
+ }
+ }
+ else
+ {
+ if (sock_write(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], cmd, len, 60000, &err)
+ != len)
+ {
+ LOGE("Socket write fail[err = %d].", err);
+ return -1;
+ }
+ }
+
+ // Read cmd response
+ if (rsp != NULL && *rsp_len > 0)
+ {
+ read_angin_1:
+ memset(rsp, 0x0, *rsp_len);
+ if(info->auth_type != 0)
+ {
+ unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+ len = mbtk_sock_read(info->ftp_ssl_handle,info->session,mbtk_ftp_ssl_read_buf,sizeof(mbtk_ftp_ssl_read_buf),FTP_TIMEOUT,&err);
+ if(err != 0)
+ {
+ printf("\n mbtk_sock_read error:%d \n",err);
+ }
+ rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+ printf("%s -> Code:%d; RSP:%s\n", (char*)cmd, rsp_code, (char* )mbtk_ftp_ssl_read_buf);
+ if (rsp_code == 0)
+ {
+ goto read_angin_1;
+ }
+ memcpy((char* )rsp, mbtk_ftp_ssl_read_buf, strlen(mbtk_ftp_ssl_read_buf));
+ //printf("\nrsp = %s\n",(char* )rsp);
+ return rsp_code;
+ }
+ else
+ {
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], rsp, *rsp_len, FTP_TIMEOUT,&err);
+ }
+ if (len <= 0)
+ {
+ LOGE("Socket read fail[len = %d].", len);
+ return -1;
+ }
+ rsp_code = atoi(rsp);
+ LOGI("%s -> Code:%d; RSP:%s", (char*)cmd, rsp_code, (char* )rsp);
+ //log_hex("FTP_RSP",(char* )rsp,len);
+
+ if (rsp_code == 0)
+ {
+ goto read_angin_1;
+ }
+
+ *rsp_len = len;
+ }
+ else
+ {
+ char buff[1024];
+
+ read_angin_2:
+ memset(buff, 0x0, 1024);
+ if(info->auth_type != 0)
+ {
+ unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+ len = mbtk_sock_read(info->ftp_ssl_handle,info->session,mbtk_ftp_ssl_read_buf,sizeof(mbtk_ftp_ssl_read_buf),FTP_TIMEOUT,&err);
+ if(err != 0)
+ {
+ printf("\nmbtk_sock_read error:%d\n",err);
+ }
+ rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+ printf("%s -> Code:%d; RSP:%s\n", (char*)cmd, rsp_code, (char* )mbtk_ftp_ssl_read_buf);
+ char *mbtk_ftp_ssl_read_buf_p = NULL;
+ mbtk_ftp_ssl_read_buf_p = strstr(mbtk_ftp_ssl_read_buf,"\n");
+ if(mbtk_ftp_ssl_read_buf_p!=NULL);
+ {
+ if(strlen(mbtk_ftp_ssl_read_buf_p)>1)
+ {
+ mbtk_ftp_ssl_read_buf_p++;
+ rsp_code = atoi(mbtk_ftp_ssl_read_buf_p);
+ }
+ }
+ if (rsp_code == 0)
+ {
+ goto read_angin_2;
+ }
+ return rsp_code;
+ }
+ else
+ {
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+ &err);
+ }
+ if (len <= 0)
+ {
+ LOGE("Socket read fail[len = %d].", len);
+ return -1;
+ }
+
+ rsp_code = atoi(buff);
+ LOGI("%s -> Code:%d; RSP:%s", (char*)cmd, rsp_code, buff);
+ //log_hex("FTP_RSP",buff,len);
+
+ if (rsp_code == 0)
+ {
+ goto read_angin_2;
+ }
+ }
+
+ return rsp_code;
+}
+
+// Create data socket service and waitting client connect.
+static mbtk_ftp_error_enum ftp_data_sock_service_create(mbtk_ftp_sock_s *sock)
+{
+ return FTP_ERR_SUCCESS;
+}
+
+static bool ftp_internal_ipv4_check(void *ipv4)
+{
+ char *ip = (char*) ipv4;
+ int ip1 = atoi(ip);
+ ip = strstr(ip, ".");
+ if (!ip)
+ return FALSE;
+ int ip2 = atoi(ip + 1);
+
+ if (ip1 == 10) // 10.x.x.x
+ {
+ return TRUE;
+ }
+ else if (ip1 == 172 && (ip2 >= 16 && ip2 <= 31)) // 172.16.0.0 ~ 172.31.255.255
+ {
+ return TRUE;
+ }
+ else if (ip1 == 192 && ip2 == 168) // 192.168.x.x
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+static mbtk_ftp_error_enum ftp_sock_set_by_port(mbtk_ftp_info_s *info,
+ mbtk_ftp_sock_s *sock)
+{
+ // port = port1 * 256 + port2
+ // "PORT ip1,ip2,ip3,ip4,port1,port2\r\n"
+ int code;
+ char cmd_buff[100];
+ memset(cmd_buff, 0x0, 100);
+ if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6 || sock->port <= 1024
+ || strlen((char*) sock->host) == 0)
+ {
+ LOGE("FTP params set error.");
+ return FTP_ERR_PARAM_SET;
+ }
+
+ if (ftp_data_sock_service_create(sock) != FTP_ERR_SUCCESS)
+ {
+ LOGE("FTP data services create fail.");
+ return FTP_ERR_UNKNOWN;
+ }
+
+ uint8 *ptr = sock->host;
+ while (*ptr)
+ {
+ if (*ptr == '.')
+ *ptr = ',';
+ ptr++;
+ }
+ // Waitting client connect.
+ snprintf(cmd_buff, 100, "PORT %s,%d,%d\r\n", sock->host, sock->port / 256,
+ sock->port % 256);
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ if (code / 100 != 2) // Not 2xx
+ {
+ LOGE("PORT rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_set_by_eprt(mbtk_ftp_info_s *info,
+ mbtk_ftp_sock_s *sock)
+{
+ int code;
+ char cmd_buff[100];
+ memset(cmd_buff, 0x0, 100);
+ if (sock->port <= 1024 || strlen((char*) sock->host) == 0)
+ {
+ LOGE("FTP params set error.");
+ return FTP_ERR_PARAM_SET;
+ }
+ if (ftp_data_sock_service_create(sock) != FTP_ERR_SUCCESS)
+ {
+ LOGE("FTP data services create fail.");
+ return FTP_ERR_UNKNOWN;
+ }
+
+ // "EPRT |2|1080::8:800:200C:417A|5282|"
+ if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+ {
+ uint8 *ptr = NULL;
+ if (sock->host[strlen((char*) sock->host) - 1] == ']')
+ sock->host[strlen((char*) sock->host) - 1] = '\0';
+
+ if (sock->host[0] == '[')
+ ptr = sock->host + 1;
+ else
+ ptr = sock->host;
+ snprintf(cmd_buff, 100, "EPRT |2|%s|%d|\r\n", ptr, sock->port);
+ }
+ else // IPV4 "EPRT |1|132.235.1.2|6275|"
+ {
+ snprintf(cmd_buff, 100, "EPRT |1|%s|%d|\r\n", sock->host, sock->port);
+ }
+
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ if (code / 100 != 2) // Not 2xx
+ {
+ LOGE("PORT rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_get_by_pasv(mbtk_ftp_info_s *info,
+ mbtk_ftp_sock_s *sock)
+{
+ int code;
+ uint8 rsp[1024];
+ uint32 rsp_len = 1024;
+ memset(sock, 0x0, sizeof(mbtk_ftp_sock_s));
+ code = ftp_cmd_handle(info, "PASV\r\n", rsp, &rsp_len);
+ /* Found reply-strings include:
+ * "227 Entering Passive Mode (127,0,0,1,4,51)"
+ * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+ * "227 Entering passive mode. 127,0,0,1,4,51"
+ */
+ if (code != 227)
+ {
+ LOGE("PASV rsp error[code = %d].", code);
+ if(code == 421)
+ {
+ printf("\n code:%d\n",code);
+ return FTP_ERR_UNKNOWN+1;
+ }
+ return FTP_ERR_UNKNOWN;
+ }
+
+ // Get IPv4 and port
+ uint8 *ptr = rsp + 4;
+ while (*ptr)
+ {
+ if (isdigit(*ptr))
+ break;
+ ptr++;
+ }
+ // ptr point to first digit.
+ memcpy(sock->host, ptr, strlen((char*) ptr));
+ ptr = sock->host;
+ int count = 0;
+ while (*ptr)
+ {
+ if (*ptr == ',')
+ {
+ *ptr = '.';
+ count++;
+ }
+ if (count == 4)
+ {
+ *ptr = '\0';
+ break;
+ }
+ ptr++;
+ }
+ ptr++;
+
+ // ptr point to first port digit.
+ int port1 = atoi((char*) ptr);
+ while (*ptr)
+ {
+ if (*ptr == ',')
+ break;
+ ptr++;
+ }
+ ptr++;
+
+ // ptr point to second port digit.
+ int port2 = atoi((char*) ptr);
+ sock->port = port1 * 256 + port2;
+
+ LOGI("PASV: %s:%d", sock->host, sock->port);
+
+ if(ftp_internal_ipv4_check(sock->host))
+ {
+ memset(sock->host,0x0,MBTK_FTP_IP_MAX + 1);
+ memcpy(sock->host,info->sock_info[FTP_SOCK_CTRL].host,strlen(info->sock_info[FTP_SOCK_CTRL].host));
+ LOGI("This is internal ipv4,so use IP - %s:%d",sock->host, sock->port);
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_sock_get_by_epsv(mbtk_ftp_info_s *info,
+ mbtk_ftp_sock_s *sock)
+{
+ int code;
+ char rsp[1024];
+ uint32 rsp_len = 1024;
+ memset(sock, 0x0, sizeof(mbtk_ftp_sock_s));
+ // |||6446|
+ code = ftp_cmd_handle(info, "EPSV\r\n", rsp, &rsp_len);
+ if (code != 229)
+ {
+ LOGE("EPSV rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ /* positive EPSV response */
+ char *ptr = strchr(rsp, '(');
+ if (ptr)
+ {
+ unsigned int num;
+ char separator[4];
+ ptr++;
+ if (5
+ == sscanf(ptr, "%c%c%c%u%c", &separator[0], &separator[1],
+ &separator[2], &num, &separator[3]))
+ {
+ const char sep1 = separator[0];
+ int i;
+
+ /* The four separators should be identical, or else this is an oddly
+ formatted reply and we bail out immediately. */
+ for (i = 1; i < 4; i++)
+ {
+ if (separator[i] != sep1)
+ {
+ ptr = NULL; /* set to NULL to signal error */
+ break;
+ }
+ }
+ if (num > 0xffff)
+ {
+ LOGE("Illegal port number in EPSV reply");
+ return FTP_ERR_UNKNOWN;
+ }
+ if (ptr)
+ {
+ sock->port = (uint32) (num & 0xffff);
+ memcpy(sock->host, info->sock_info[FTP_SOCK_CTRL].host,
+ strlen(info->sock_info[FTP_SOCK_CTRL].host));
+ }
+ }
+ else
+ {
+ ptr = NULL;
+ }
+ }
+ if (!ptr)
+ {
+ LOGE("Weirdly formatted EPSV reply");
+ return FTP_ERR_UNKNOWN;
+ }
+
+ LOGI("PASV: %s:%d", sock->host, sock->port);
+
+ return FTP_ERR_SUCCESS;
+}
+
+/*
+ * 04-26-20 02:13PM 379193 audio_0426.zip
+ * 09-10-20 02:31PM 4660645 Log.zip
+ * 10-28-20 01:53PM <DIR> PicLibs
+ */
+
+ /*
+ *-rw-r--r-- 1 ftp ftp 2097152000 Feb 18 17:28 ASR1803_Linux.tar.gz_aa
+ *-rw-r--r-- 1 ftp ftp 2097152000 Feb 18 17:21 ASR1803_Linux.tar.gz_ab
+ *-rw-r--r-- 1 ftp ftp 1198057917 Feb 18 17:29 ASR1803_Linux.tar.gz_ac
+ *-rw-r--r-- 1 ftp ftp 445043 Apr 06 2021 data
+ *drwxr-xr-x 1 ftp ftp 0 Apr 10 2021 L306
+ */
+static mbtk_ftp_error_enum ftp_cmd_list_parse(mbtk_ftp_info_s *info,
+ mbtk_ftp_file_info_s *file_list)
+{
+ char line[1024];
+ char line_buf[1024];
+ int len, err;
+ mbtk_ftp_file_info_s file_ptr;
+ memset(file_list, 0x0, sizeof(mbtk_ftp_file_info_s)-sizeof(void *));
+
+ // Save file number.
+ file_list->size = 0;
+ len = 1;
+ int read_line_count=0;
+ while (len > 0)
+ {
+ if(info->auth_type!=0)
+ {
+ len = mbtk_sock_readline(info->ftp_ssl_handle,info->session_data,line_buf,1024,FTP_TIMEOUT,&err,&read_line_count,line);
+ }
+ else
+ {
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_DATA], line, 1024,FTP_TIMEOUT, &err);
+ }
+ LOGD("Line:%s", line);
+ if(len <= 0)
+ {
+ if (err == MBTK_SOCK_SUCCESS)
+ return FTP_ERR_SUCCESS;
+ break;
+ }
+ else
+ len = strlen(line) - 1;
+ if (line[0] >= '0' && line[0] <= '9')
+ {
+ /*
+ * 04-26-20 02:13PM 379193 audio_0426.zip
+ * 09-10-20 02:31PM 4660645 Log.zip
+ * 10-28-20 01:53PM <DIR> PicLibs
+ */
+ line[len] = '\0';
+ /*
+ file_ptr = (mbtk_ftp_file_info_s*) malloc(
+ sizeof(mbtk_ftp_file_info_s));
+ if (!file_ptr)
+ {
+ LOGE("malloc() fail.");
+ return FTP_ERR_UNKNOWN;
+ }
+ */
+ memset(&file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+
+ char str[MBTK_FTP_FILE_NAME_MAX];
+ const char *temp = line;
+ // Data
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ if (strlen(str) > 0)
+ {
+ LOGV("Data:%s", str);
+ }
+
+ // Time
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ if (strlen(str) > 0)
+ {
+ LOGV("Time:%s", str);
+ }
+
+ // <DIR> or file size
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ if (strlen(str) > 0)
+ {
+ LOGV("<DIR>/size:%s", str);
+ if (!strcmp("<DIR>", str))
+ {
+ file_ptr.is_file = false;
+ file_ptr.size = 0;
+ }
+ else
+ {
+ file_ptr.is_file = true;
+ file_ptr.size = atoi(str);
+ }
+ }
+
+ const char *name = temp;
+ while (*name && ftp_ch_is_space(*name))
+ {
+ name++;
+ }
+
+ // Name
+ if (strlen(name) > 0)
+ {
+ LOGV("Name:%s",name);
+ memset(file_ptr.name,0,strlen(file_ptr.name)+1);
+ memcpy(file_ptr.name, name, strlen(name));
+ char *temp = (char*) file_ptr.name
+ + strlen((char*) file_ptr.name) - 1;
+ while (ftp_ch_is_space(*temp))
+ {
+ *temp = '\0';
+ temp--;
+ }
+ }
+ else
+ {
+ LOGE("Can not get name[%s].", line);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ (file_list->ftp_ls_cb_typedef)(&file_ptr);
+ //file_ptr->next = file_list->next;
+ //file_list->next = file_ptr;
+ //file_list->size++;
+ //free(file_ptr);
+ } else if(!ftp_ch_is_space(line[0])) {
+ /*
+ *-rw-r--r-- 1 ftp ftp 2097152000 Feb 18 17:28 ASR1803_Linux.tar.gz_aa
+ *-rw-r--r-- 1 ftp ftp 2097152000 Feb 18 17:21 ASR1803_Linux.tar.gz_ab
+ *-rw-r--r-- 1 ftp ftp 1198057917 Feb 18 17:29 ASR1803_Linux.tar.gz_ac
+ *-rw-r--r-- 1 ftp ftp 445043 Apr 06 2021 data
+ *drwxr-xr-x 1 ftp ftp 0 Apr 10 2021 L306
+ */
+ line[len] = '\0';
+ /*
+ file_ptr = (mbtk_ftp_file_info_s*) malloc(
+ sizeof(mbtk_ftp_file_info_s));
+ if (!file_ptr)
+ {
+ LOGE("malloc() fail.");
+ return FTP_ERR_UNKNOWN;
+ }
+ */
+ memset(&file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+
+ char str[MBTK_FTP_FILE_NAME_MAX];
+ const char *temp = line;
+ // rwx
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ if (strlen(str) > 0)
+ {
+ LOGV("rwx:%s", str);
+ file_ptr.is_file = (str[0] == '-' ? true : false);
+ }
+
+ // 1 ftp ftp
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+
+ // size
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ if (strlen(str) > 0)
+ {
+ LOGV("Size:%s", str);
+ file_ptr.size = atoi(str);
+ }
+
+ // Feb 18 17:28
+ // or
+ // Apr 10 2021
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+ temp = ftp_str_next(temp, str, MBTK_FTP_FILE_NAME_MAX);
+
+ const char *name = temp;
+ while (*name && ftp_ch_is_space(*name))
+ {
+ name++;
+ }
+
+ // Name
+ if (strlen(name) > 0)
+ {
+ LOGV("Name:%s",name);
+ memset(file_ptr.name,0,strlen(file_ptr.name)+1);
+ memcpy(file_ptr.name, name, strlen(name));
+ char *temp = (char*) file_ptr.name
+ + strlen((char*) file_ptr.name) - 1;
+ while (ftp_ch_is_space(*temp))
+ {
+ *temp = '\0';
+ temp--;
+ }
+ }
+ else
+ {
+ LOGE("Can not get name[%s].", line);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ (file_list->ftp_ls_cb_typedef)(&file_ptr);
+ //file_ptr->next = file_list->next;
+ //file_list->next = file_ptr;
+ //file_list->size++;
+ //free(file_ptr);
+ }else {
+ LOGE("Data error.");
+ return FTP_ERR_UNKNOWN;
+ }
+ }
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_download_process(mbtk_ftp_info_s *info)
+{
+#define READ_BUF_SIZE 2048
+ char buff[READ_BUF_SIZE];
+ int len, err, len_read;
+ int read_count = info->file_trans.size_send;
+
+#ifdef FTP_RESUME_DEBUG
+ int count = 0;
+#endif
+
+ if (info->file_trans.size_count - read_count > READ_BUF_SIZE)
+ len_read = READ_BUF_SIZE;
+ else
+ len_read = info->file_trans.size_count - read_count;
+
+ if(info->auth_type != 0)
+ len = mbtk_sock_read(info->ftp_ssl_handle,info->session_data,buff,len_read,FTP_TIMEOUT,&err);
+ else
+ len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,FTP_TIMEOUT, &err);
+ /*
+ while (len_read > 0 && (len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,
+ FTP_TIMEOUT, &err)) > 0)
+ */
+ while (len_read > 0 && len > 0)
+ {
+ read_count += len;
+
+#ifdef FTP_RESUME_DEBUG
+ count++;
+ if (count <= 1000)
+ {
+#endif
+ if (info->file_trans.data_cb)
+ {
+ info->file_trans.data_cb(buff, len);
+ }
+ else // Write to efs.
+ {
+ if (len != file_write(info->file_trans.fd, buff, len))
+ {
+ LOGE("EFS write fail.");
+ return FTP_ERR_EFS_FILE;
+ }
+ }
+ memset(buff,0,sizeof(buff));
+ info->file_trans.size_send = read_count;
+#ifdef FTP_RESUME_DEBUG
+ }
+#endif
+
+ if (info->file_trans.size_count - read_count > READ_BUF_SIZE)
+ len_read = READ_BUF_SIZE;
+ else
+ len_read = info->file_trans.size_count - read_count;
+
+ if(info->auth_type != 0)
+ len = mbtk_sock_read(info->ftp_ssl_handle,info->session_data,buff,len_read,FTP_TIMEOUT,&err);
+ else
+ len = sock_read(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_read,FTP_TIMEOUT, &err);
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_update_process(mbtk_ftp_info_s *info)
+{
+#define READ_BUF_SIZE 2048
+ char buff[READ_BUF_SIZE];
+ int len, err, len_write;
+ int file_total_size = 0;
+ int write_count = 0;
+
+ if(info->file_trans.fd > 0)
+ {
+ file_total_size = file_length(info->file_trans.fd);
+ info->file_trans.size_count = file_total_size;
+ while((len_write = file_read(info->file_trans.fd, buff, READ_BUF_SIZE)) > 0 )
+ {
+ LOGE("file_read.len:%d, buf;%s", len_write, buff);
+ if(info->auth_type != 0)
+ len = mbtk_sock_write(info->ftp_ssl_handle,info->session_data,buff,len_write,FTP_TIMEOUT,&err);
+ else
+ len = sock_write(&info->net_info, &info->sock_info[FTP_SOCK_DATA], buff, len_write,
+ FTP_TIMEOUT, &err);
+ if(len < 0)
+ {
+ LOGE("EFS write fail.len:%d, err;%d", len, err);
+ return FTP_ERR_EFS_FILE;
+ }
+
+ write_count += len;
+ }
+
+ info->file_trans.size_send = write_count;
+ if( write_count != file_total_size)
+ {
+ LOGE("socket write fail.,file_total_size:%d, write_count:%d", file_total_size,write_count);
+ return FTP_ERR_NET_WRITE;
+ }
+ else{
+ LOGE("socket write success.,file_total_size:%d, write_count:%d", file_total_size, write_count);
+ }
+
+ }
+ else
+ {
+ LOGE("EFS write fail.");
+ return FTP_ERR_EFS_FILE;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+
+/*
+ * audio_0426.zip
+ * Log.zip
+ * PicLibs
+ */
+static mbtk_ftp_error_enum ftp_cmd_nlst_parse(mbtk_ftp_info_s *info,
+ mbtk_ftp_file_info_s *file_list)
+{
+ char line[1024];
+ int len, err;
+ mbtk_ftp_file_info_s *file_ptr = NULL;
+ while ((len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_DATA], line, 1024,
+ FTP_TIMEOUT, &err)) > 0)
+ {
+ if (!ftp_ch_is_space(line[0]))
+ {
+ file_ptr = (mbtk_ftp_file_info_s*) malloc(
+ sizeof(mbtk_ftp_file_info_s));
+ if (!file_ptr)
+ {
+ LOGE("malloc() fail.");
+ return FTP_ERR_UNKNOWN;
+ }
+ memset(file_ptr, 0x0, sizeof(mbtk_ftp_file_info_s));
+ memcpy(file_ptr->name, line, strlen(line));
+ char *temp = (char*) file_ptr->name + strlen((char*) file_ptr->name)
+ - 1;
+ while (ftp_ch_is_space(*temp))
+ {
+ *temp = '\0';
+ temp--;
+ }
+
+ file_ptr->next = file_list->next;
+ file_list->next = file_ptr;
+ }
+ }
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_data_sock_read(mbtk_ftp_info_s *info,
+ mbtk_ftp_cmd_enum cmd, void *req, void *rsp)
+{
+ int err, len, code;
+ mbtk_ftp_error_enum result = FTP_ERR_SUCCESS;
+ char buff[1024];
+ if (info->is_data_sock_busy)
+ {
+ LOGW("Data socket is busy!");
+ return FTP_ERR_DATA_SOCK_BUSY;
+ }
+
+ info->is_data_sock_busy = true;
+ // Connect to service by data socket.
+ if (info->data_mode == FTP_MODE_PASSIVE)
+ {
+ mbtk_ftp_sock_s sock;
+ if(info->auth_type != FTP_AUTH_TYPE_NON) {
+ // PROT P
+ char cmd_ssl[50];
+ memset(cmd_ssl,0,50);
+ snprintf(cmd_ssl, 50, "PROT P\r\n");
+ code = ftp_cmd_handle(info, cmd_ssl, NULL,NULL);
+ if (code/100 != 2)
+ {
+ LOGE("PROT P error[code = %d].", code);
+ goto end;
+ }
+ }
+
+ if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+ {
+ if ((result = ftp_sock_get_by_epsv(info, &sock))
+ != FTP_ERR_SUCCESS)
+ {
+ goto end;
+ }
+ }
+ else
+ {
+ if ((result = ftp_sock_get_by_pasv(info, &sock))
+ != FTP_ERR_SUCCESS)
+ {
+ printf("\nftp_sock_get_by_pasv end.result=%d\n",result);
+ }
+ else
+ {
+ printf("\nftp_sock_get_by_pasv ok!\n");
+ }
+ }
+
+ if(info->auth_type != FTP_AUTH_TYPE_NON)
+ {
+ info->ftp_ssl_handle_data = mbtk_sock_init(&info->ftp_ssl_info_data);
+ if(info->ftp_ssl_handle_data == -1)
+ {
+ printf("mbtk_sock_init error\n");
+ }
+ info->ftp_sock_ssl_info_data = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+ memset(info->ftp_sock_ssl_info_data, 0x0, sizeof(mbtk_sock_info));
+ info->ftp_sock_ssl_info_data->is_support_ssl = info->auth_type;
+ info->ftp_sock_ssl_info_data->ftp_ssl_support=1;
+ info->ftp_sock_ssl_info_data->port = sock.port;
+ info->ftp_sock_ssl_info_data->type = MBTK_SOCK_TCP;
+ info->ftp_sock_ssl_info_data->ingnore_cert = ~(info->sock_info[FTP_SOCK_CTRL].use_cert);
+ memcpy(info->ftp_sock_ssl_info_data->address, sock.host, strlen(sock.host));
+ if(info->ftp_sock_ssl_info_data->is_support_ssl != 0)
+ {
+ info->ftp_sock_ssl_info_data->is_support_ssl = 0;
+ }
+ info->session_data = mbtk_sock_open(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data,60000,&err);
+ if(err!=0)
+ {
+ printf("mbtk_sock_open error : %d\n",err);
+ }
+ else
+ {
+ info->ftp_sock_ssl_info_data->is_support_ssl = info->auth_type;
+ //printf("\ninfo->session_data = %d \n",info->session_data);
+ }
+ }
+ else
+ {
+ memcpy(info->sock_info[FTP_SOCK_DATA].host, sock.host, strlen((char*)sock.host));
+ info->sock_info[FTP_SOCK_DATA].port = sock.port;
+ info->sock_info[FTP_SOCK_DATA].is_ssl = (info->auth_type != FTP_AUTH_TYPE_NON);
+ info->sock_info[FTP_SOCK_DATA].addr_family = info->sock_info[FTP_SOCK_CTRL].addr_family;
+ info->sock_info[FTP_SOCK_DATA].use_cert = info->sock_info[FTP_SOCK_CTRL].use_cert;
+ info->net_info.keep_alive = FALSE;
+ info->net_info.recv_buff_size = 32 * 1024; // 32K
+ info->sock_info[FTP_SOCK_DATA].fd = sock_open(&info->net_info, &info->sock_info[FTP_SOCK_DATA],
+ FTP_TIMEOUT, &err);
+ }
+
+ }
+ else // Active mode
+ {
+ if (req == NULL)
+ {
+ result = FTP_ERR_PARAM_SET;
+ goto end;
+ }
+ mbtk_ftp_sock_s *sock = (mbtk_ftp_sock_s*) req;
+
+ if (info->sock_info[FTP_SOCK_CTRL].addr_family == MBTK_ADDR_IPV6)
+ {
+ if ((result = ftp_sock_set_by_eprt(info, sock))
+ != FTP_ERR_SUCCESS)
+ {
+ goto end;
+ }
+ }
+ else
+ {
+ if ((result = ftp_sock_set_by_port(info, sock))
+ != FTP_ERR_SUCCESS)
+ {
+ goto end;
+ }
+ }
+
+ // Wait for client[service] connect.
+
+ }
+ if(info->auth_type != FTP_AUTH_TYPE_NON)
+ {
+ if(info->session_data < 0)
+ {
+ //printf("Socket open/connect ssl fail[err = %d].", err);
+ result = FTP_ERR_NET_CONN;
+ goto read_end;
+ }
+ }
+ else
+ {
+ if (info->sock_info[FTP_SOCK_DATA].fd < 0)
+ {
+ LOGE("Socket open/connect fail[err = %d].", err);
+ result = FTP_ERR_NET_CONN;
+ goto read_end;
+ }
+
+ if(info->auth_type == FTP_AUTH_TYPE_IMPLICIT) {
+ info->sock_info[FTP_SOCK_DATA].is_ssl = true;
+ }
+ }
+
+ if (cmd == FTP_CMD_GET) // Is download
+ {
+ char cmd[100];
+ if (info->file_trans.size_send > 0) // Resume transmission
+ {
+ // REST size
+ memset(cmd, 0x0, 100);
+ snprintf(cmd, 100, "REST %ld\r\n", info->file_trans.size_send);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code != 350)
+ {
+ LOGE("REST rsp error[code = %d].", code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+ }
+
+ memset(cmd, 0x0, 100);
+ snprintf(cmd, 100, "RETR %s\r\n", info->file_trans.remote_name);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+ code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+
+ int mbtk_errno;
+ if(info->auth_type != 0)
+ {
+ mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+ if(mbtk_errno != 0)
+ {
+ printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+ goto end;
+ }
+
+ }
+ result = ftp_download_process(info);
+ if(info->auth_type != 0)
+ {
+ char mbtk_ftp_ssl_read_buf[256];
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 6000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf);
+ }
+ if(info->auth_type != 0)
+ goto read_end;
+ }
+ else if (cmd == FTP_CMD_PUT) // Is download
+ {
+ if(info->auth_type != 0)
+ {
+ int mbtk_errno;
+ char cmd[100];
+ memset(cmd, 0x0, 100);
+ snprintf(cmd, 100, "STOR %s\r\n", info->file_trans.remote_name);
+ LOGE("STOR %s .name:%s ", cmd, info->file_trans.remote_name);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+ code);
+ //printf("RETR %s rsp error[code = %d].\n", info->file_trans.remote_name,code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+
+ mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+ if(mbtk_errno != 0)
+ {
+ printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+ goto end;
+ }
+ if(info->file_trans.size_count == 0)
+ {
+ result = ftp_update_process(info);
+ goto read_end;
+ }
+ else
+ {
+ //printf("FTP_SOCK_DATA,fd:%d\n",info->file_trans.size_count);
+ return FTP_ERR_SUCCESS;
+ }
+ goto end;
+ }
+ else
+ {
+ char cmd[100];
+ memset(cmd, 0x0, 100);
+ snprintf(cmd, 100, "STOR %s\r\n", info->file_trans.remote_name);
+ LOGE("STOR %s .name:%s ", cmd, info->file_trans.remote_name);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("RETR %s rsp error[code = %d].", info->file_trans.remote_name,
+ code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+
+ if(info->file_trans.size_count == 0)
+ {
+ result = ftp_update_process(info);
+ goto read_end;
+ }
+ else
+ {
+ LOGE("FTP_SOCK_DATA,fd:%d", info->sock_info[FTP_SOCK_DATA].fd);
+ return FTP_ERR_SUCCESS;
+ }
+ }
+ }
+ else if (cmd == FTP_CMD_LIST)
+ {
+ if(info->auth_type != 0)
+ {
+ int mbtk_errno;
+ code = ftp_cmd_handle(info, "LIST\r\n", NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("LIST rsp error[code = %d].", code);
+ result = FTP_ERR_UNKNOWN;
+ goto read_end;
+ }
+
+ mbtk_errno = mbtk_ssl_init_func(info->ftp_ssl_handle,info->ftp_sock_ssl_info_data->ingnore_cert,info->session_data);
+ if(mbtk_errno != 0)
+ {
+ printf("\nmbtk_ssl_init_func error = %d",mbtk_errno);
+ goto read_end;
+ }
+
+ result = ftp_cmd_list_parse(info, (mbtk_ftp_file_info_s*) rsp);
+ char mbtk_ftp_ssl_read_buf[1024];
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 6000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf);
+ int rsp_code = atoi(mbtk_ftp_ssl_read_buf);
+ if(rsp_code / 200)
+ result = FTP_ERR_SUCCESS;
+ goto read_end;
+ }
+ else
+ {
+ code = ftp_cmd_handle(info, "LIST\r\n", NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("LIST rsp error[code = %d].", code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+
+ result = ftp_cmd_list_parse(info, (mbtk_ftp_file_info_s*) rsp);
+ }
+ }
+ else if (cmd == FTP_CMD_NLST)
+ {
+ code = ftp_cmd_handle(info, "NLST\r\n", NULL, NULL);
+ if (code != 125 && code != 150)
+ {
+ LOGE("LIST rsp error[code = %d].", code);
+ result = FTP_ERR_UNKNOWN;
+ goto end;
+ }
+
+ result = ftp_cmd_nlst_parse(info, (mbtk_ftp_file_info_s*) rsp);
+ }
+ else
+ {
+ LOGE("No support this cmd[%d].", cmd);
+ result = FTP_ERR_UNKNOWN;
+ goto read_end;
+ }
+
+ // Read [226 Transfer complete.]
+read_code:
+ memset(buff, 0x0, 1024);
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+ &err);
+ if (len <= 0)
+ {
+ LOGE("Socket read fail[len = %d].", len);
+ result = FTP_ERR_NET_READ;
+ goto sock_error;
+ }
+ LOGI("RSP[len-%d]:%s",len,buff);
+ //log_hex("FTP_RSP",buff,len);
+ code = atoi(buff);
+ if (code == 0)
+ {
+ goto read_code;
+ }
+#if 1
+ // 426 Connection closed; aborted transfer of "/files/test"
+ else if (code == 426)
+ {
+ LOGE("Connection closed,restart download...");
+ result = FTP_ERR_UNKNOWN;
+ goto sock_error;
+ }
+#endif
+ else if (code != 226)
+ {
+ LOGE("Code not be 226[%s].", buff);
+ result = FTP_ERR_UNKNOWN;
+ goto read_end;
+ }
+
+ goto read_end;
+sock_error:
+ {
+ if (info->sock_info[FTP_SOCK_CTRL].fd > 0)
+ {
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close ctrl socket fail[%d].", err);
+ }
+ }
+ info->state = FTP_STATE_NON;
+ info->sock_info[FTP_SOCK_CTRL].fd = -1;
+ }
+read_end:
+ // Close data socket.
+ if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+ {
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close data socket fail[%d].", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ if(info->auth_type != 0)
+ {
+ if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+ {
+ LOGE("Close ssl data socket fail[%d].", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ // info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ if (info->data_mode == FTP_MODE_PASSIVE)
+ {
+
+ }
+ else
+ {
+
+ }
+
+end:
+ // Default is passive.
+ info->data_mode = FTP_MODE_PASSIVE;
+ info->is_data_sock_busy = false;
+
+ return result;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_pwd(mbtk_ftp_info_s *info,
+ char *path)
+{
+ int code;
+ char rsp[100];
+ uint32 rsp_len = 100;
+ code = ftp_cmd_handle(info, "PWD\r\n", rsp, &rsp_len);
+ if (code != 257)
+ {
+ LOGE("PWD rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ // "path" is current ....
+ char *ptr = strchr(rsp, '"');
+ if (!ptr)
+ {
+ LOGE("PWD rsp error[%d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ ptr++;
+ char *ptr_temp = ptr;
+ while (*ptr_temp)
+ {
+ if (*ptr_temp == '"')
+ {
+ *ptr_temp = '\0';
+ break;
+ }
+ ptr_temp++;
+ }
+ memcpy(path, ptr, strlen(ptr));
+ path[strlen(ptr)] = '\0';
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_cwd(mbtk_ftp_info_s *info,
+ const char *path)
+{
+ int code;
+ char cmd[100] = { 0 };
+ snprintf(cmd, 100, "CWD %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code != 250)
+ {
+ LOGE("CWD rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_mkd(mbtk_ftp_info_s *info,
+ const char *path)
+{
+ int code;
+ char cmd[100] = { 0 };
+ snprintf(cmd, 100, "MKD %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code == 257)
+ {
+ return FTP_ERR_SUCCESS;
+ }
+ else if (code == 550)
+ {
+ LOGE("Dir has exist[%s].", path);
+ return FTP_ERR_FILE_EXIST;
+ }
+ else
+ {
+ LOGE("MKD rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_rmd(mbtk_ftp_info_s *info,
+ const char *path)
+{
+ int code;
+ char cmd[100] = { 0 };
+ snprintf(cmd, 100, "RMD %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code == 250)
+ {
+ return FTP_ERR_SUCCESS;
+ }
+ else if (code == 550)
+ {
+ LOGE("Dir not exist or not empty[%s].", path);
+ return FTP_ERR_FILE_NO_FOUND;
+ }
+ else
+ {
+ LOGE("RMD rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_stat(mbtk_ftp_info_s *info,
+ void *status)
+{
+ int code;
+ char rsp[1024];
+ uint32 rsp_len = 1024;
+ code = ftp_cmd_handle(info, "STAT\r\n", rsp, &rsp_len);
+ if (code != 211)
+ {
+ LOGE("STAT rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ memcpy(status, rsp, rsp_len);
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_type(mbtk_ftp_info_s *info,
+ mbtk_ftp_data_type_enum type)
+{
+ int code;
+ if (type == FTP_DATA_TYPE_I)
+ code = ftp_cmd_handle(info, "TYPE I\r\n", NULL, NULL);
+ else if (type == FTP_DATA_TYPE_E)
+ code = ftp_cmd_handle(info, "TYPE E\r\n", NULL, NULL);
+ else
+ code = ftp_cmd_handle(info, "TYPE A\r\n", NULL, NULL);
+
+ if (code != 200)
+ {
+ LOGE("TYPE rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_size(mbtk_ftp_info_s *info,
+ const char *path, uint32 *size)
+{
+ int code;
+ char cmd[100] = { 0 };
+ char rsp[100];
+ uint32 rsp_len = 100;
+ snprintf(cmd, 100, "SIZE %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, rsp, &rsp_len);
+
+ if (code == 213)
+ {
+ // "213 4660645"
+ *size = atoi(rsp + 4);
+ }
+ else if (code == 550)
+ {
+ LOGW("No found file[%s].", path);
+ return FTP_ERR_FILE_NO_FOUND;
+ }
+ else
+ {
+ LOGE("SIZE rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_mdtm(mbtk_ftp_info_s *info,
+ const char *path, char *time)
+{
+ int code;
+ char cmd[100] = { 0 };
+ char rsp[100];
+ uint32 rsp_len = 100;
+ snprintf(cmd, 100, "MDTM %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, rsp, &rsp_len);
+
+ if (code == 213)
+ {
+ // "213 20181017014716"
+ memcpy(time, rsp + 4, 14);
+ }
+ else if (code == 550)
+ {
+ LOGW("No found file[%s].", path);
+ return FTP_ERR_FILE_NO_FOUND;
+ }
+ else
+ {
+ LOGE("MDTM rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_dele(mbtk_ftp_info_s *info,
+ const char *path)
+{
+ int code;
+ char cmd[100] = { 0 };
+ snprintf(cmd, 100, "DELE %s\r\n", path);
+ code = ftp_cmd_handle(info, cmd, NULL, NULL);
+ if (code == 250)
+ {
+ return FTP_ERR_SUCCESS;
+ }
+ else if (code == 550)
+ {
+ LOGW("No found file[%s].", path);
+ return FTP_ERR_FILE_NO_FOUND;
+ }
+ else
+ {
+ LOGE("DELE rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process_quit(mbtk_ftp_info_s *info)
+{
+ int code;
+ code = ftp_cmd_handle(info, "QUIT\r\n", NULL, NULL);
+ if (code != 221)
+ {
+ LOGE("CWD rsp error[code = %d].", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+static mbtk_ftp_error_enum ftp_cmd_process(mbtk_ftp_info_s *info,
+ mbtk_ftp_cmd_enum cmd, void *req, void *rsp)
+{
+ mbtk_ftp_error_enum result = FTP_ERR_SUCCESS;
+ if (info->state == FTP_STATE_READY) // FTP login
+ {
+ info->state = FTP_STATE_CMD_PROCESS;
+ switch (cmd)
+ {
+ case FTP_CMD_LIST:
+ {
+ result = ftp_data_sock_read(info, FTP_CMD_LIST, req, rsp);
+ break;
+ }
+ case FTP_CMD_NLST:
+ {
+ result = ftp_data_sock_read(info, FTP_CMD_NLST, req, rsp);
+ break;
+ }
+ case FTP_CMD_PWD:
+ {
+ result = ftp_cmd_process_pwd(info, rsp);
+ break;
+ }
+ case FTP_CMD_CWD:
+ {
+ result = ftp_cmd_process_cwd(info, (char*) req);
+ break;
+ }
+ case FTP_CMD_MKD:
+ {
+ result = ftp_cmd_process_mkd(info, (char*) req);
+ break;
+ }
+ case FTP_CMD_RMD:
+ {
+ result = ftp_cmd_process_rmd(info, (char*) req);
+ break;
+ }
+ case FTP_CMD_STAT:
+ {
+ result = ftp_cmd_process_stat(info, rsp);
+ break;
+ }
+ case FTP_CMD_TYPE:
+ {
+ mbtk_ftp_data_type_enum *type = (mbtk_ftp_data_type_enum*) req;
+ result = ftp_cmd_process_type(info, *type);
+ break;
+ }
+ case FTP_CMD_SIZE:
+ {
+ result = ftp_cmd_process_size(info, (char*) req, (uint32*) rsp);
+ break;
+ }
+ case FTP_CMD_MDTM:
+ {
+ result = ftp_cmd_process_mdtm(info, (char*) req, (char*) rsp);
+ break;
+ }
+ case FTP_CMD_DELE:
+ {
+ result = ftp_cmd_process_dele(info, (char*) req);
+ break;
+ }
+ case FTP_CMD_QUIT:
+ {
+ result = ftp_cmd_process_quit(info);
+ break;
+ }
+ default:
+ {
+ LOGE("Unknown cmd:%d", cmd);
+ result = FTP_ERR_UNKNOWN;
+ break;
+ }
+ }
+ info->state = FTP_STATE_READY;
+ }
+ else
+ {
+ LOGW("FTP state error[%d].", info->state);
+ result = FTP_ERR_UNKNOWN;
+ }
+
+ return result;
+}
+
+static mbtk_ftp_error_enum ftp_login(mbtk_ftp_info_s *info,mbtk_ftp_user_info_s *user)
+{
+ // Open net in the first.
+ if(info->net_info.net_id <= 0) {
+ if(sock_net_open(&info->net_info,info->sock_info[FTP_SOCK_CTRL].addr_family))
+ {
+ LOGE("sock_net_open() fail.");
+ return FTP_ERR_NET_CONN;
+ }
+ }
+
+ int err;
+ mbtk_ftp_error_enum ftp_err = FTP_ERR_SUCCESS;
+ info->state = FTP_STATE_CONNECTING;
+ info->net_info.keep_alive = TRUE;
+ info->net_info.recv_buff_size = 0; // Default
+ info->sock_info[FTP_SOCK_CTRL].fd = sock_open(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err);
+ if (info->sock_info[FTP_SOCK_CTRL].fd < 0) // Fail
+ {
+ LOGE("Socket open/connect fail[err = %d].", err);
+ ftp_err = FTP_ERR_NET_CONN;
+ goto login_fail;
+ }
+
+ if(info->auth_type == FTP_AUTH_TYPE_IMPLICIT)
+ info->sock_info[FTP_SOCK_CTRL].is_ssl = true;
+
+ // Ctrl socket connect success.
+ info->state = FTP_STATE_CONNECTED;
+ LOGI("FTP ctrl socket connected.");
+
+ char buff[1024];
+ int len;
+ char *ptr = NULL;
+
+ // 220-FileZilla Server version 0.9.43 beta
+ // 220-written by Tim Kosse (tim.kosse@filezilla-project.org)
+ // 220 Please visit http://sourceforge.net/projects/filezilla/
+ while(TRUE) {
+ memset(buff, 0x0, 1024);
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT,
+ &err);
+ if (len <= 0)
+ {
+ LOGE("Socket read fail[err = %d].", err);
+ ftp_err = FTP_ERR_NET_READ;
+ goto login_fail;
+ } else {// xxx yyyyyy
+ if((ptr = strstr(buff,"220 ")) || (ptr = strstr(buff,"230 "))) {
+ LOGI("RSP:%s",ptr);
+ break;
+ }
+ }
+ }
+
+ int code = atoi(ptr);
+ if (code == 230) // Has logged in.
+ {
+ info->state = FTP_STATE_READY;
+ LOGI("FTP Has logged in.");
+ return FTP_ERR_SUCCESS;
+ }
+ else if (code == 220) // Should logn in.
+ {
+ int len;
+ char cmd_buff[50];
+
+#if 0
+ // Read other data.
+ char buff[1024];
+ memset(buff,0x0,1024);
+ while((len = sock_read(&info->net_info,info->ctrl_sock.fd, buff, 1024, info->ssl_enable, 1000,
+ &err)) > 0)
+ {
+ LOGI("RSP[%d]:%s",len,buff);
+ memset(buff,0x0,1024);
+ }
+#endif
+
+ if(info->auth_type == FTP_AUTH_TYPE_EXPLICIT_SSL
+ || info->auth_type == FTP_AUTH_TYPE_EXPLICIT_TLS) {
+ if(info->auth_type == FTP_AUTH_TYPE_EXPLICIT_SSL) {
+ len = snprintf(cmd_buff, 50, "AUTH SSL\r\n");
+ } else {
+ len = snprintf(cmd_buff, 50, "AUTH TLS\r\n");
+ }
+ cmd_buff[len] = '\0';
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ if (code != 234 && code != 334)
+ {
+ LOGE("AUTH SSL/TLS fail[code = %d].", code);
+ ftp_err = FTP_ERR_LOGIN_DENIED;
+ goto login_fail;
+ }
+
+#if 0
+ if(sock_ssl_enable(&info->net_info,info->ctrl_sock.fd
+ ,info->ctrl_sock.host,info->ctrl_sock.port,info->use_cert,FTP_TIMEOUT)){
+ LOGE("sock_ssl_enable() fail.");
+ ftp_err = FTP_ERR_LOGIN_DENIED;
+ goto login_fail;
+ }
+#endif
+ info->sock_info[FTP_SOCK_CTRL].is_ssl = true;
+ }
+
+ if(info->auth_type != FTP_AUTH_TYPE_NON) {
+ len = snprintf(cmd_buff, 50, "PBSZ 0\r\n");
+ cmd_buff[len] = '\0';
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ if (code != 200 && code != 220)
+ {
+ LOGE("PBSZ 0 fail[code = %d].", code);
+ ftp_err = FTP_ERR_LOGIN_DENIED;
+ goto login_fail;
+ }
+ }
+
+ len = snprintf(cmd_buff, 50, "USER %s\r\n", user->name);
+ cmd_buff[len] = '\0';
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ if (code == 331) // USER is 331
+ {
+ len = snprintf(cmd_buff, 50, "PASS %s\r\n", user->pass);
+ cmd_buff[len] = '\0';
+ code = ftp_cmd_handle(info, cmd_buff, NULL, NULL);
+ }
+
+ if (code / 100 == 2) // USER/PASS is 2xx
+ {
+ info->state = FTP_STATE_READY;
+ LOGI("FTP logn in success.");
+ return FTP_ERR_SUCCESS;
+ }
+ else if (code == 332) // // USER/PASS is 332
+ {
+ LOGW("Should set ACCT.");
+ ftp_err = FTP_ERR_UNKNOWN;
+ goto login_fail;
+ }
+ else
+ {
+ LOGE("FTP login denied[code = %d].", code);
+ ftp_err = FTP_ERR_LOGIN_DENIED;
+ goto login_fail;
+ }
+ }
+ else
+ {
+ LOGE("FTP code error[%d].", code);
+ ftp_err = FTP_ERR_UNKNOWN;
+ goto login_fail;
+ }
+
+login_fail:
+ info->state = FTP_STATE_NON;
+ return ftp_err;
+}
+
+static mbtk_ftp_info_s* ftp_info_find(mbtk_ftp_handle handle)
+{
+ if (!ftp_client_list)
+ {
+ LOGE("FTP Client List not init.");
+ return NULL;
+ }
+
+ mbtk_ftp_info_s *result = NULL;
+ list_first(ftp_client_list);
+ while ((result = (mbtk_ftp_info_s*) list_next(ftp_client_list)))
+ {
+ if (result->handle == handle)
+ break;
+ }
+
+ return result;
+}
+
+mbtk_ftp_handle mbtk_ftp_upload_end(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ printf("No such FTP handle:%d\n", handle);
+ }
+
+ char buff[1024]={0};
+ int err=0;
+ int len=0;
+ int result;
+
+ if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+ {
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close data socket fail[%d].", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ // info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ if(info->auth_type != 0)
+ {
+ if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+ {
+ LOGE("Close ssl data socket fail[%d].", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ // info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ info->data_mode = FTP_MODE_PASSIVE;
+ info->is_data_sock_busy = false;
+ info->file_trans.size_count = 0;
+ info->file_trans.size_send = 0;
+
+ char line_buf[1024];
+ if(info->auth_type != 0)
+ len = mbtk_sock_read(info->ftp_ssl_handle,info->session,buff,sizeof(buff),FTP_TIMEOUT,&err);
+ else
+ len = sock_readline(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], buff, 1024, FTP_TIMEOUT, &err);
+ if(len > 0)
+ {
+ printf("\n%s\n",buff);
+ if(err != 0)
+ printf("socket read error: %d\n",err);
+ }
+ else
+ {
+ printf("socket_read error:%d\n",err);
+ result = -1;
+ }
+
+ return result;
+}
+
+static mbtk_ftp_handle ftp_next_handle()
+{
+ if (!ftp_client_list)
+ {
+ LOGE("FTP Client List not init.");
+ return -1;
+ }
+
+ mbtk_ftp_info_s *info = NULL;
+ mbtk_ftp_handle handle = 1;
+ bool used;
+ while (handle <= FTP_HANDLE_MAX)
+ {
+ used = false;
+ // This handle used?
+ list_first(ftp_client_list);
+ while ((info = (mbtk_ftp_info_s*) list_next(ftp_client_list)))
+ {
+ if (handle == info->handle)
+ {
+ used = true;
+ break;
+ }
+ }
+
+ if (!used)
+ {
+ break;
+ }
+
+ handle++;
+ }
+
+ LOGI("Get free handle:%d", handle);
+
+ return handle;
+}
+
+static void ftp_free_func(void *data)
+{
+ if (data)
+ {
+ mbtk_ftp_info_s *info = (mbtk_ftp_info_s*) data;
+ LOGI("Free FTP client[handle = %d].", info->handle);
+ free(info);
+ }
+}
+
+/*************************************************************
+ Public Function Definitions
+ *************************************************************/
+mbtk_ftp_handle mbtk_ftp_init(const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+ bool is_ipv6, bool use_cert)
+{
+ if (!ftp_client_list)
+ ftp_client_list = list_create(ftp_free_func);
+
+ if (!ftp_client_list)
+ {
+ LOGE("FTP Client List not init.");
+ return -1;
+ }
+
+ if (list_size(ftp_client_list) > FTP_HANDLE_MAX)
+ {
+ LOGE("FTP client is full.");
+ return -1;
+ }
+
+ if (host == NULL || strlen(host) == 0)
+ {
+ LOGE("Host error.");
+ return -1;
+ }
+
+ if (port == 0)
+ {
+ port = FTP_SERVICE_PORT_DEF;
+ }
+
+ mbtk_ftp_info_s *info = (mbtk_ftp_info_s*) malloc(sizeof(mbtk_ftp_info_s));
+ if (!info)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+ memset(info, 0x0, sizeof(mbtk_ftp_info_s));
+ list_add(ftp_client_list, info);
+ memcpy(info->sock_info[FTP_SOCK_CTRL].host, host, strlen(host));
+ info->sock_info[FTP_SOCK_CTRL].port = port;
+ // info->auth_type == FTP_AUTH_TYPE_IMPLICIT, info->is_ipv6 ? MBTK_ADDR_IPV6 : MBTK_ADDR_IPV4,info->use_cert,
+ info->sock_info[FTP_SOCK_CTRL].is_ssl = (auth_type == FTP_AUTH_TYPE_IMPLICIT);
+ info->sock_info[FTP_SOCK_CTRL].addr_family = is_ipv6 ? MBTK_ADDR_IPV6: MBTK_ADDR_IPV4;
+ info->sock_info[FTP_SOCK_CTRL].use_cert = use_cert;
+
+ info->handle = ftp_next_handle();
+ info->state = FTP_STATE_NON;
+ info->data_mode = FTP_MODE_PASSIVE;
+ info->sock_info[FTP_SOCK_CTRL].fd = -1;
+ info->sock_info[FTP_SOCK_DATA].fd = -1;
+ //info->is_ipv6 = is_ipv6;
+ info->auth_type = auth_type;
+ //info->use_cert = use_cert;
+
+ LOGI("FTP info#host:%s,port:%d,ipv6:%d,ssl:%d,cert:%d",info->sock_info[FTP_SOCK_CTRL].host,
+ info->sock_info[FTP_SOCK_CTRL].port,
+ is_ipv6,info->auth_type,use_cert);
+
+ if(auth_type != FTP_AUTH_TYPE_NON)
+ {
+ info->ftp_ssl_handle = mbtk_sock_init(&info->ftp_ssl_info);
+ if(info->ftp_ssl_handle == -1)
+ {
+ printf("mbtk_sock_init error\n");
+ }
+
+ info->ftp_sock_ssl_info = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+ memset(info->ftp_sock_ssl_info, 0x0, sizeof(mbtk_sock_info));
+ info->ftp_sock_ssl_info->is_support_ssl = (auth_type != FTP_AUTH_TYPE_NON);
+ info->ftp_sock_ssl_info->ftp_ssl_support = 1;
+ info->ftp_sock_ssl_info->port = port;
+ info->ftp_sock_ssl_info->type = MBTK_SOCK_TCP;
+ info->ftp_sock_ssl_info->ingnore_cert = !use_cert;
+ memcpy(info->ftp_sock_ssl_info->address, host, strlen(host));
+ }
+ return info->handle;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_reconfig(mbtk_ftp_handle handle,const void* host, uint16 port, mbtk_ftp_auth_type_enum auth_type,
+ bool is_ipv6, bool use_cert)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+ if(auth_type != FTP_AUTH_TYPE_NON)
+ {
+ info->ftp_sock_ssl_info = (mbtk_sock_info*) malloc(sizeof(mbtk_sock_info));
+ memset(info->ftp_sock_ssl_info, 0x0, sizeof(mbtk_sock_info));
+ if(host && strlen(host) > 0)
+ {
+ memcpy(info->ftp_sock_ssl_info->address, host, strlen(host));
+ info->ftp_sock_ssl_info->address[strlen(host)] = '\0';
+ }
+ info->ftp_sock_ssl_info->is_support_ssl = (auth_type != FTP_AUTH_TYPE_NON);
+ info->ftp_sock_ssl_info->ftp_ssl_support = 1;
+ info->ftp_sock_ssl_info->port = port;
+ info->ftp_sock_ssl_info->ingnore_cert = !use_cert;
+ info->ftp_sock_ssl_info->type = MBTK_SOCK_TCP;
+ }
+ if(info->state == FTP_STATE_NON)
+ {
+ if(host && strlen(host) > 0)
+ {
+ memcpy(info->sock_info[FTP_SOCK_CTRL].host, host, strlen(host));
+ info->sock_info[FTP_SOCK_CTRL].host[strlen(host)] = '\0';
+ }
+ info->sock_info[FTP_SOCK_CTRL].port = port;
+ info->sock_info[FTP_SOCK_CTRL].addr_family = is_ipv6 ? MBTK_ADDR_IPV6 : MBTK_ADDR_IPV4;
+ info->auth_type = auth_type;
+ info->sock_info[FTP_SOCK_CTRL].use_cert = use_cert;
+
+ return FTP_ERR_SUCCESS;
+ }
+ else
+ {
+ LOGE("Not reset FTP config.The state is %d", info->state);
+ return FTP_ERR_UNKNOWN;
+ }
+}
+
+mbtk_ftp_error_enum mbtk_ftp_user_set(mbtk_ftp_handle handle,void* user,void* pass)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ if(info->state == FTP_STATE_NON && !str_empty(user) && !str_empty(pass))
+ {
+ memset(&info->user,0x0,sizeof(mbtk_ftp_user_info_s));
+ memcpy(info->user.name, user, strlen(user));
+ memcpy(info->user.pass, pass, strlen(pass));
+ return FTP_ERR_SUCCESS;
+ }
+ else
+ {
+ LOGE("Not reset FTP config.The state is %d", info->state);
+ return FTP_ERR_UNKNOWN;
+ }
+}
+
+mbtk_ftp_error_enum mbtk_ftp_deinit(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ if (list_remove(ftp_client_list, info))
+ {
+ int err;
+ if(info->auth_type == FTP_AUTH_TYPE_NON) {
+ sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err);
+ sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err);
+ } else {
+ mbtk_sock_deinit(info->ftp_ssl_handle);
+ }
+ ftp_free_func(info);
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+/*
+ * Quit FTP service.
+ */
+mbtk_ftp_error_enum mbtk_ftp_quit(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ int err = 0;
+ if(info->sock_info[FTP_SOCK_CTRL].fd > 0) {
+ mbtk_ftp_error_enum ftp_err = ftp_cmd_process(info, FTP_CMD_QUIT, NULL,
+ NULL);
+ if (ftp_err != FTP_ERR_SUCCESS)
+ {
+ LOGE("FTP QUIT fail[%d].", ftp_err);
+ //return ftp_err;
+ }
+
+ // FTP quit success.
+ info->state = FTP_STATE_CONNECTED;
+ }
+
+ if(info->auth_type == FTP_AUTH_TYPE_NON) {
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_CTRL], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close ctrl socket fail[%d].", err);
+ return FTP_ERR_NET_CLOSE;
+ }
+
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close data socket fail[%d].", err);
+ return FTP_ERR_NET_CLOSE;
+ }
+ } else {
+ if(mbtk_sock_close(info->ftp_ssl_handle,info->session,6000,&err))
+ {
+ LOGE("Close ssl ctrl socket fail[%d].", err);
+ //return FTP_ERR_NET_CLOSE;
+ }
+
+ if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+ {
+ LOGE("Close ssl data socket fail[%d].", err);
+ //return FTP_ERR_NET_CLOSE;
+ }
+ }
+
+
+ info->state = FTP_STATE_NON;
+ info->data_mode = FTP_MODE_PASSIVE;
+ memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+ info->sock_info[FTP_SOCK_CTRL].fd = -1;
+ info->sock_info[FTP_SOCK_DATA].fd = -1;
+
+ return FTP_ERR_SUCCESS;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_net_close(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ if(info->net_info.net_id > 0) {
+ int err;
+ if(sock_net_close(&info->net_info, FTP_TIMEOUT,&err))
+ {
+ LOGE("sock_net_close() fail[%ld].",err);
+ return FTP_ERR_NET_CLOSE;
+ }
+
+ info->net_info.net_id = -1;
+ }
+
+ return FTP_ERR_SUCCESS;
+}
+
+
+mbtk_ftp_info_s* mbtk_ftp_info_get(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return NULL;
+ }
+
+ return info;
+}
+
+/*
+ * Login specified FTP service.
+ */
+mbtk_ftp_error_enum mbtk_ftp_login(mbtk_ftp_handle handle, void *name,
+ void *pass)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ if (info->state == FTP_STATE_NON)
+ {
+ mbtk_ftp_user_info_s user;
+ memset(&user,0x0,sizeof(mbtk_ftp_user_info_s));
+ if (!str_empty(name) && !str_empty(pass))
+ {
+ memcpy(user.name, name, strlen(name));
+ memcpy(user.pass, pass, strlen(pass));
+ memcpy(info->user.name, name, strlen(name));
+ memcpy(info->user.pass, pass, strlen(pass));
+ }
+ else
+ {
+ memcpy(user.name, FTP_ANONYMOUS_USER, strlen(FTP_ANONYMOUS_USER));
+ memcpy(user.pass, FTP_ANONYMOUS_PASS, strlen(FTP_ANONYMOUS_PASS));
+ memcpy(info->user.name, FTP_ANONYMOUS_USER, strlen(FTP_ANONYMOUS_USER));
+ memcpy(info->user.pass, FTP_ANONYMOUS_PASS, strlen(FTP_ANONYMOUS_PASS));
+ }
+
+ LOGI("FTP login#user:%s,pass:%s",user.name,user.pass);
+
+ if(info->auth_type != 0)
+ {
+ int mbtk_errno=-1;
+ info->session = mbtk_sock_open(info->ftp_ssl_handle,info->ftp_sock_ssl_info,60000,&mbtk_errno);
+ if(mbtk_errno!=0)
+ {
+ printf("mbtk_sock_open error : %d\n",mbtk_errno);
+ }
+ else
+ {
+ unsigned char mbtk_ftp_ssl_read_buf[16384 + 1];
+ char cmd[50];
+ memset(cmd,0,50);
+ int len_ssl;
+
+
+ memset(cmd,0,50);
+ snprintf(cmd, 50, "PBSZ 0\r\n");
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,
+ cmd,
+ sizeof(cmd),
+ 60000,
+ &mbtk_errno);
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 60000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read PBSZ 0:\n%s\n",mbtk_ftp_ssl_read_buf);
+ memset(cmd,0,50);
+ snprintf(cmd, 50, "PROT P\r\n");
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,
+ cmd,
+ sizeof(cmd),
+ 60000,
+ &mbtk_errno);
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 60000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read PROT P:\n%s\n",mbtk_ftp_ssl_read_buf);
+ memset(cmd,0,50);
+ snprintf(cmd, 50, "USER %s\r\n",info->user.name);
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,
+ cmd,
+ sizeof(cmd),
+ 60000,
+ &mbtk_errno);
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 60000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read USER:\n%s\n",mbtk_ftp_ssl_read_buf);
+ memset(cmd,0,50);
+ snprintf(cmd, 50, "PASS %s\r\n",info->user.pass);
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,
+ cmd,
+ sizeof(cmd),
+ 60000,
+ &mbtk_errno);
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 60000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read PASS:\n%s\n",mbtk_ftp_ssl_read_buf);
+ char *ptr = NULL;
+ if((ptr = strstr(mbtk_ftp_ssl_read_buf,"220 ")) || (ptr = strstr(mbtk_ftp_ssl_read_buf,"230 "))) {
+ LOGI("RSP:%s",ptr);
+ printf("RSP:%s\n",ptr);
+ }
+ else
+ {
+ printf("\nptr error.\n");
+ return FTP_ERR_UNKNOWN;
+ }
+ int code = atoi(ptr);
+ if (code / 100 == 2) // USER/PASS is 2xx
+ {
+ info->state = FTP_STATE_READY;
+ LOGI("FTP logn in success.");
+ printf("FTP logn in success.\n");
+ }
+ else if (code == 332) // // USER/PASS is 332
+ {
+ LOGW("Should set ACCT.");
+ printf("Should set ACCT.\n");
+ return FTP_ERR_UNKNOWN;
+ }
+ else
+ {
+ LOGE("FTP login denied[code = %d].", code);
+ printf("FTP login denied[code = %d].\n", code);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ memset(cmd,0,50);
+ snprintf(cmd, 50, "PWD\r\n");
+ mbtk_sock_write(info->ftp_ssl_handle,info->session,
+ cmd,
+ sizeof(cmd),
+ 60000,
+ &mbtk_errno);
+ memset(mbtk_ftp_ssl_read_buf,0,sizeof(mbtk_ftp_ssl_read_buf));
+ mbtk_sock_read(info->ftp_ssl_handle,info->session,
+ mbtk_ftp_ssl_read_buf,
+ sizeof(mbtk_ftp_ssl_read_buf),
+ 60000,
+ &mbtk_errno);
+ printf("\nmbtk_sock_read PWD:\n%s\n",mbtk_ftp_ssl_read_buf);
+ }
+ return mbtk_errno;
+ }
+
+ return ftp_login(info,&user);
+ }
+ else
+ {
+ LOGD("Has login.");
+ return FTP_ERR_SUCCESS;
+ }
+}
+
+/*
+ * Get current directory's path.
+ */
+mbtk_ftp_error_enum mbtk_ftp_pwd(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_PWD, NULL, path);
+}
+
+/*
+ * Go to specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_cd(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_CWD, path, NULL);
+}
+
+/*
+ * Get the native ip and free port.
+ */
+mbtk_ftp_error_enum mbtk_ftp_get_ip_and_port(char *ipBuf_out,
+ int *port,int iptype)
+{
+ char psz_port_cmd[128];
+ int i=0;
+
+ *port = rand() % (60000 - 50000 + 1) + 50000;
+ sprintf(psz_port_cmd, "netstat -an | grep :%d > /dev/null", *port);
+
+ char ipBuf[32] = "";
+ FILE *fstream=NULL;
+
+ char buff[1024];
+ char iptype_str[8];
+ memset(buff,0,sizeof(buff));
+ /*eth0可以换成eth1、docker0、em1、lo等*/
+ if(iptype == MBTK_ADDR_IPV6)
+ {
+
+ if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet6 addr: 2\" | awk '{print $3}'","r")))
+ {
+ snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");
+ }
+ if(NULL!=fgets(buff, sizeof(buff), fstream))
+ {
+ snprintf(ipBuf, 39, "%s",buff);
+ }
+ else
+ {
+ snprintf(ipBuf, 39, "%s","0:0:0:0:0:0:0:0");
+ pclose(fstream);
+ }
+ }
+ else
+ {
+ if(NULL==(fstream=popen("ifconfig ccinet0 | grep \"inet addr:\" | awk \'{print $2}\' | cut -c 6-","r")))
+ {
+ snprintf(ipBuf, 18, "%s","0.0.0.0");
+ }
+ if(NULL!=fgets(buff, sizeof(buff), fstream))
+ {
+ snprintf(ipBuf, 18, "%s",buff);
+ }
+ else
+ {
+ snprintf(ipBuf, 18, "%s","0.0.0.0");
+ pclose(fstream);
+ }
+ }
+ pclose(fstream);
+
+ printf("ip:%s\n", ipBuf);
+ memcpy(ipBuf_out, ipBuf, 32);
+ return 0;
+}
+/*
+ * Get current directory's subdirectory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_ls(mbtk_ftp_handle handle,
+ mbtk_ftp_file_info_s *list_head)
+{
+ if (!list_head)
+ {
+ LOGE("No set file list.");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_LIST, NULL, list_head);
+}
+
+/*
+ * Get specified file's size.
+ */
+uint32 mbtk_ftp_file_size(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return 0;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return 0;
+ }
+ uint32 size = 0;
+ if (ftp_cmd_process(info, FTP_CMD_SIZE, path, &size) != FTP_ERR_SUCCESS)
+ return 0;
+
+ return size;
+}
+
+/*
+ * Get specified file's modify time.
+ */
+mbtk_ftp_error_enum mbtk_ftp_file_time(mbtk_ftp_handle handle, void *path,
+ void *time)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_MDTM, path, time);
+}
+
+/*
+ * Delete specified file.
+ */
+mbtk_ftp_error_enum mbtk_ftp_file_del(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_DELE, path, NULL);
+}
+
+/*
+ * Create specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_mkdir(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_MKD, path, NULL);
+}
+
+/*
+ * Delete specified directory.
+ */
+mbtk_ftp_error_enum mbtk_ftp_dir_rmdir(mbtk_ftp_handle handle, void *path)
+{
+ if (!path)
+ {
+ LOGE("No set path");
+ return FTP_ERR_PARAM_SET;
+ }
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_RMD, path, NULL);
+}
+
+/*
+ * Set data type.
+ */
+mbtk_ftp_error_enum mbtk_ftp_data_type_set(mbtk_ftp_handle handle,
+ mbtk_ftp_data_type_enum data_type)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ return ftp_cmd_process(info, FTP_CMD_TYPE, &data_type, NULL);
+}
+
+/*
+ * Set FTP mode.
+ */
+mbtk_ftp_error_enum mbtk_ftp_mode_set(mbtk_ftp_handle handle,
+ mbtk_ftp_mode_enum mode)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ info->data_mode = mode;
+
+ return FTP_ERR_SUCCESS;
+}
+
+uint32 mbtk_ftp_download_start(mbtk_ftp_handle handle, void *remote_path,
+ void *local_path, mbtk_data_cb_func data_cb)
+{
+ if (!remote_path || (local_path && data_cb) || (!local_path && !data_cb))
+ {
+ LOGE("Param set error.");
+ return 0;
+ }
+
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return 0;
+ }
+
+ if (info->state >= FTP_STATE_READY && !info->is_trans)
+ {
+ int retry_time = 0;
+ memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+
+ // Set data type to "I"
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+ {
+ LOGE("Set data type to I fail.");
+ return 0;
+ }
+
+ // Get file size.
+ info->file_trans.size_count = mbtk_ftp_file_size(handle, remote_path);
+ if (info->file_trans.size_count > 0)
+ {
+ LOGI("File size:%d", info->file_trans.size_count);
+ }
+ else
+ {
+ LOGE("File not exist.");
+ return 0;
+ }
+
+ //Get file modify time.
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_file_time(handle, remote_path,
+ (char*) info->file_trans.modify_time))
+ {
+ LOGE("Get file modify time fail.");
+ return 0;
+ }
+
+ memcpy(info->file_trans.remote_name, remote_path,
+ strlen((char*) remote_path));
+ if (local_path)
+ {
+ memcpy(info->file_trans.local_name, local_path,
+ strlen((char*) local_path));
+ info->file_trans.data_cb = NULL;
+ }
+ else
+ {
+ info->file_trans.data_cb = data_cb;
+ }
+ info->file_trans.size_send = 0;
+ info->file_trans.is_download = true;
+ info->file_trans.fd = -1;
+ info->is_trans = true;
+
+ if (!info->file_trans.data_cb) // Save to efs
+ {
+ info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+ O_WRONLY | O_CREAT | O_TRUNC);
+ if (info->file_trans.fd <= 0)
+ {
+ LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+ return 0;
+ }
+ }
+
+ do {
+ // Start download file.
+ if (FTP_ERR_SUCCESS
+ != ftp_data_sock_read(info, FTP_CMD_GET, NULL, NULL))
+ {
+ LOGW("ftp_data_sock_read() fail.");
+ }
+
+ if(info->sock_info[FTP_SOCK_CTRL].fd <= 0) {
+ // Download fail.
+ LOGW("Ctrl socket error,should login angin.");
+ break;
+ } else if (info->file_trans.size_send == info->file_trans.size_count) {
+ // Download success
+ break;
+ }
+
+ // Should redownload without quit.
+ char time[20] = { 0 };
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_file_time(handle, info->file_trans.remote_name,
+ time))
+ {
+ LOGE("Get file modify time fail.");
+ break;
+ }
+
+ if (strcmp(time, (char*) info->file_trans.modify_time))
+ {
+ LOGW("Service file changed.");
+ break;
+ }
+
+ retry_time++;
+ } while(retry_time < 5);
+
+
+ if (!info->file_trans.data_cb && info->file_trans.fd > 0) // Save to efs
+ {
+ if (file_close(info->file_trans.fd))
+ {
+ LOGE("EFS close fail.");
+ return 0;
+ }
+ }
+
+ // Download success.
+ if (info->file_trans.size_send == info->file_trans.size_count)
+ {
+ LOGI("Download %s success[%d].", (char* )remote_path,
+ info->file_trans.size_count);
+
+ // Reset download configs.
+ info->is_trans = false;
+ // memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+ }
+ else
+ {
+ LOGW("Download %s fail[%d / %d].", (char* )remote_path,
+ info->file_trans.size_send, info->file_trans.size_count);
+ }
+
+ return info->file_trans.size_send;
+ }
+ else
+ {
+ LOGE("FTP state error[%d].", info->state);
+ return 0;
+ }
+}
+
+uint32 mbtk_ftp_download_continue(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return 0;
+ }
+
+ if(info->state == FTP_STATE_NON) {
+ if(FTP_ERR_SUCCESS != ftp_login(info,&info->user)) {
+ LOGE("FTP login fail.");
+ return 0;
+ }
+ }
+
+ if (info->state >= FTP_STATE_READY && info->is_trans
+ && info->file_trans.is_download
+ && info->file_trans.size_send < info->file_trans.size_count)
+ {
+ // Set data type to "I"
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+ {
+ LOGE("Set data type to I fail.");
+ return 0;
+ }
+
+ // Get file size.
+ uint32 size = mbtk_ftp_file_size(handle, info->file_trans.remote_name);
+ if (size > 0)
+ {
+ LOGI("File size:%d", size);
+ }
+ else
+ {
+ LOGE("File not exist.");
+ return 0;
+ }
+ if (size != info->file_trans.size_count)
+ {
+ LOGW("Service file changed.");
+ return 0;
+ }
+
+ //Get file modify time.
+ char time[20] = { 0 };
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_file_time(handle, info->file_trans.remote_name,
+ time))
+ {
+ LOGE("Get file modify time fail.");
+ return 0;
+ }
+ if (strcmp(time, (char*) info->file_trans.modify_time))
+ {
+ LOGW("Service file changed.");
+ return 0;
+ }
+
+ if (!info->file_trans.data_cb) // Save to efs
+ {
+ info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+ O_WRONLY | O_CREAT | O_APPEND);
+ if (info->file_trans.fd <= 0)
+ {
+ LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+ return FTP_ERR_EFS_FILE;
+ }
+ }
+
+ uint32 size_last = info->file_trans.size_send;
+ // Start download file.
+ if (FTP_ERR_SUCCESS
+ != ftp_data_sock_read(info, FTP_CMD_GET, NULL, NULL))
+ {
+ LOGW("Data download fail.");
+ }
+
+ if (!info->file_trans.data_cb && info->file_trans.fd > 0)
+ {
+ if (file_close(info->file_trans.fd))
+ {
+ LOGE("EFS close fail.");
+ return 0;
+ }
+ }
+
+ // Download success.
+ if (info->file_trans.size_send == info->file_trans.size_count)
+ {
+ LOGI("Download %s success[%d].", info->file_trans.remote_name,
+ info->file_trans.size_count);
+
+ // Reset download configs.
+ info->is_trans = false;
+ //memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+ }
+ else
+ {
+ LOGW("Download %s fail[%d / %d].", info->file_trans.remote_name,
+ info->file_trans.size_send, info->file_trans.size_count);
+ }
+
+ return info->file_trans.size_send - size_last;
+ }
+ else
+ {
+ LOGE("FTP state error[%d].", info->state);
+ return 0;
+ }
+}
+
+/*
+* Upload EFS: local_path is efs path;size_byte is 0.
+* Upload data: local_path is NULL;size_byte is data size.
+*/
+int mbtk_ftp_upload_start(mbtk_ftp_handle handle, const void *remote_path,
+ const void *local_path, uint32 size_byte)
+{
+ if (!remote_path || (size_byte == 0 && !local_path)
+ || (size_byte > 0 && local_path))
+ {
+ LOGE("Param set error.");
+ return -1;
+ }
+
+ int result = 0;
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return -1;
+ }
+
+ LOGE("info->state:%d, info->is_trans:%d", info->state,info->is_trans);
+
+ if (info->state >= FTP_STATE_READY && !info->is_trans)
+ {
+ // Set data type to "I"
+ if (FTP_ERR_SUCCESS
+ != mbtk_ftp_data_type_set(handle, FTP_DATA_TYPE_I))
+ {
+ LOGE("Set data type to I fail.");
+ return -1;
+ }
+
+ memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+ info->file_trans.is_download = false;
+
+ memcpy(info->file_trans.remote_name, remote_path,
+ strlen((char*) remote_path));
+
+ if (local_path)
+ {
+ memcpy(info->file_trans.local_name, local_path,
+ strlen((char*) local_path));
+ info->file_trans.fd = file_open((const char*)info->file_trans.local_name,
+ O_RDONLY);
+ if (info->file_trans.fd <= 0)
+ {
+ LOGE("Can not open EFS file[%s].", info->file_trans.local_name);
+ return -1;
+ }
+
+ }
+ info->file_trans.size_count = size_byte;
+ info->file_trans.size_send = 0;
+ // Start upload data.
+
+
+ // Start update file.
+ if (FTP_ERR_SUCCESS != ftp_data_sock_read(info, FTP_CMD_PUT, NULL, NULL))
+ {
+ LOGW("ftp_data_sock_read() fail.");
+ if(info->file_trans.size_count == info->file_trans.size_send && info->file_trans.size_send != 0)
+ {
+ result = FTP_ERR_SUCCESS;
+ }
+ else
+ {
+ mbtk_at_ftp_par.rest_size = info->file_trans.size_send;
+ result = FTP_ERR_UNKNOWN;
+ }
+ }
+
+ if (info->file_trans.fd > 0 ) // Save to efs
+ {
+ info->file_trans.size_count = 0;
+ info->file_trans.size_send = 0;
+ if (file_close(info->file_trans.fd))
+ {
+ LOGE("EFS close fail.");
+ return -1;
+ }
+ }
+
+ }
+ else
+ {
+ LOGE("FTP state error[%d].", info->state);
+ return -1;
+ }
+
+ return result;
+}
+
+/*
+* This only for upload data(No for upload efs).
+*/
+int mbtk_ftp_upload_send(mbtk_ftp_handle handle, const void *data,uint16 data_len)
+{
+ if (!data || data_len == 0)
+ {
+ LOGE("Param set error.");
+ return -1;
+ }
+
+ int err;
+ int result = 0;
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return -1;
+ }
+
+ if(info->file_trans.fd > 0) // Is upload from efs.
+ {
+ LOGE("Not upload from EFS.");
+ return -1;
+ }
+
+//LOGE("1socket:%d, data:%s, data_len:%d", info->sock_info[FTP_SOCK_DATA].fd, data, data_len );
+ if((info->file_trans.size_send + data_len) > info->file_trans.size_count)
+ {
+ printf("send over set length\n");
+ result = FTP_ERR_UNKNOWN;
+ goto overlong;
+ }
+ int len;
+ if(info->auth_type != 0)
+ len = mbtk_sock_write(info->ftp_ssl_handle,info->session_data,data,data_len,FTP_TIMEOUT,&err);
+ else
+ len = sock_write(&info->net_info, &info->sock_info[FTP_SOCK_DATA], data, data_len,
+ FTP_TIMEOUT, &err);
+ if(len < 0)
+ {
+ LOGE("EFS write fail.len:%d, err;%d", len, err);
+ return FTP_ERR_EFS_FILE;
+ }
+
+ info->file_trans.size_send += len;
+ mbtk_at_ftp_par.rest_size = info->file_trans.size_send;
+
+ LOGE("size_count:%d, size_send:%d.", info->file_trans.size_count,info->file_trans.size_send);
+
+ if((info->file_trans.size_count <= info->file_trans.size_send) )
+ {
+ printf("\nClose data socket begin!\n ");
+ // Close data socket.
+overlong: if (info->sock_info[FTP_SOCK_DATA].fd > 0)
+ {
+ if (sock_close(&info->net_info, &info->sock_info[FTP_SOCK_DATA], FTP_TIMEOUT, &err))
+ {
+ LOGE("Close data socket fail[%d].", err);
+ printf("\nClose data socket fail[%d].\n", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ printf("\nClose data socket ok[%d].\n", err);
+ // info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ if(info->auth_type != 0)
+ {
+ if(mbtk_sock_close(info->ftp_ssl_handle,info->session_data,6000,&err))
+ {
+ LOGE("Close ssl data socket fail[%d].", err);
+ printf("\nClose ssl data socket fail[%d].\n", err);
+ result = FTP_ERR_NET_CLOSE;
+ }
+ else
+ {
+ printf("\nClose ssl data socket ok[%d].\n", err);
+ // info->sock_info[FTP_SOCK_DATA].fd = -1;
+ }
+ }
+ info->data_mode = FTP_MODE_PASSIVE;
+ info->is_data_sock_busy = false;
+ info->file_trans.size_count = 0;
+ info->file_trans.size_send = 0;
+ }
+ else
+ {
+ LOGE("size_count:%d, size_send:%d.", info->file_trans.size_count,info->file_trans.size_send);
+ }
+
+
+ // Start update data.
+
+ return result;
+}
+
+mbtk_ftp_error_enum mbtk_ftp_trans_reset(mbtk_ftp_handle handle)
+{
+ mbtk_ftp_info_s *info = ftp_info_find(handle);
+ if (!info)
+ {
+ LOGE("No such FTP handle:%d", handle);
+ return FTP_ERR_UNKNOWN;
+ }
+
+ info->is_trans = false;
+ memset(&info->file_trans, 0x0, sizeof(mbtk_ftp_file_trans_info_s));
+
+ return FTP_ERR_SUCCESS;
+}
+
+void mbtk_ftp_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_ftp_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/ftp/mbtk_ftp_at.c b/mbtk/libmbtk_lib/ftp/mbtk_ftp_at.c
new file mode 100755
index 0000000..3541e2b
--- /dev/null
+++ b/mbtk/libmbtk_lib/ftp/mbtk_ftp_at.c
@@ -0,0 +1,593 @@
+/*************************************************************
+ Description:
+ $file_description$
+ Author:
+ LiuBin
+ Date:
+ 2020/10/28 11:49:08
+ *************************************************************/
+#include "mbtk_ftp.h"
+#include "mbtk_list.h"
+#include "mbtk_sock.h"
+#include "mbtk_str.h"
+#include "mbtk_sock2.h"
+#include<linux/msg.h>
+
+/*************************************************************
+ typedef struct:local at
+ *************************************************************/
+typedef struct
+{
+ char host[64];
+ uint16 port;
+ mbtk_ftp_auth_type_enum auth_type;
+ bool ftp_type;
+ bool use_cert;
+ char name[FTP_SERVER_USER_NAME_MAX+1];
+ char pass[FTP_SERVER_USER_PASS_MAX+1];
+ mbtk_ftp_handle at_ftp_handle;
+ char remote_path[MBTK_FTP_FILE_NAME_MAX+1];
+ char local_path[MBTK_FTP_FILE_NAME_MAX+1];
+ int rest_size;
+ int read_size;
+ int put_len;
+} mbtk_at_init_parameter;
+
+mbtk_at_init_parameter mbtk_at_ftp_par_at={0};
+
+/*************************************************************
+ Variables:local
+ *************************************************************/
+static list_node_t *ftp_client_list = NULL;
+
+/*************************************************************
+ Variables:public
+ *************************************************************/
+
+/*************************************************************
+ Local Function Declaration
+ *************************************************************/
+
+/*************************************************************
+ Local Function Definitions
+ *************************************************************/
+
+//at
+struct my_msg //消息队列结构体
+{
+ long int my_msg_type;
+ char *ptr;
+}mbtk_at_msg;
+
+int msgid;
+
+int mbtk_at_msgid(int *at_msgid)
+{
+ msgid = *at_msgid;
+ return 0;
+}
+
+void mbtk_at_printf(void *data)
+{
+ char *ptr = malloc(strlen(data)+1);
+ memset(ptr,0,strlen(data)+1);
+ memcpy(ptr, data, strlen(data)+1);
+ mbtk_at_msg.ptr = ptr;
+ mbtk_at_msg.my_msg_type=3;
+ msgsnd(msgid,&mbtk_at_msg,sizeof(&mbtk_at_msg),0); //发送数据到缓冲区
+}
+
+int mbtk_at_ftp(int parameter,int port,char *addr, char *pass, char *name,int at_auth_type ,bool ftp_type, bool use_cert)
+{
+ int at_ftp_ret = 0;
+
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ switch (parameter) {
+ case 0: {
+ mbtk_at_ftp_par_at.port = port;
+ break;
+ }
+ case 1: {
+ memset(mbtk_at_ftp_par_at.host, 0, strlen(mbtk_at_ftp_par_at.host)+1);
+ memcpy(mbtk_at_ftp_par_at.host, addr, strlen(addr)+1);
+ break;
+ }
+ case 2: {
+ memset(mbtk_at_ftp_par_at.pass, 0, strlen(mbtk_at_ftp_par_at.pass)+1);
+ memcpy(mbtk_at_ftp_par_at.pass, pass, strlen(pass)+1);
+ break;
+ }
+ case 3: {
+ memset(mbtk_at_ftp_par_at.name, 0, strlen(mbtk_at_ftp_par_at.name)+1);
+ memcpy(mbtk_at_ftp_par_at.name, name, strlen(name)+1);
+ break;
+ }
+ case 4: {
+ mbtk_at_ftp_par_at.auth_type = at_auth_type;
+ mbtk_at_ftp_par_at.use_cert = use_cert;
+ break;
+ }
+ case 5: {
+ mbtk_at_ftp_par_at.ftp_type = ftp_type;
+ break;
+ }
+ default :
+ at_ftp_ret = -1;
+ return at_ftp_ret;
+ }
+ return at_ftp_ret;
+}
+
+int mbtk_at_get_ftp_info(int parameter,int *port,char *addr, char *pass, char *name, int *at_auth_type ,int *ftp_type, int *use_cert)
+{
+ int at_ftp_ret = 0;
+
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ switch (parameter) {
+ case 0: {
+ *port = mbtk_at_ftp_par_at.port;
+ break;
+ }
+ case 1: {
+ memset(addr, 0, strlen(addr)+1);
+ memcpy(addr, mbtk_at_ftp_par_at.host, strlen(mbtk_at_ftp_par_at.host)+1);
+ break;
+ }
+ case 2: {
+ memset(pass, 0, strlen(pass)+1);
+ memcpy(pass, mbtk_at_ftp_par_at.pass, strlen(mbtk_at_ftp_par_at.pass)+1);
+ break;
+ }
+ case 3: {
+ memset(name, 0, strlen(name)+1);
+ memcpy(name, mbtk_at_ftp_par_at.name, strlen(mbtk_at_ftp_par_at.name)+1);
+ break;
+ }
+ case 4: {
+ *at_auth_type = mbtk_at_ftp_par_at.auth_type;
+ *use_cert = mbtk_at_ftp_par_at.use_cert;
+ break;
+ }
+ case 5: {
+ *ftp_type = mbtk_at_ftp_par_at.ftp_type;
+ break;
+ }
+ default :
+ at_ftp_ret = -1;
+ }
+ return at_ftp_ret;
+}
+
+int mbtk_at_ftp_mkrmdel(int cmd,char *dir)
+{
+ int at_ftp_ret = 0;
+
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+
+ char send_buf[1024];
+
+ mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+ 0, mbtk_at_ftp_par_at.use_cert);
+ mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+ if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+ at_ftp_ret = -1;
+
+ at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+ if(at_ftp_ret != 0)
+ {
+ printf("ftp_login err:%d\n",at_ftp_ret);
+ }
+ memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+ memcpy(mbtk_at_ftp_par_at.remote_path,dir,strlen(dir)+1);
+ switch (cmd)
+ {
+ case 0:
+ {
+ at_ftp_ret = mbtk_ftp_dir_mkdir(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPMKD: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPMKD: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ printf("+CFTPMKD: SUCCESS\n");
+ sprintf(send_buf,"+CFTPMKD: SUCCESS\n");
+ }
+ break;
+ }
+ case 1:
+ {
+ at_ftp_ret = mbtk_ftp_dir_rmdir(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPRMD: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPRMD: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ printf("+CFTPRMD: SUCCESS\n");
+ sprintf(send_buf,"+CFTPRMD: SUCCESS\n");
+ }
+ break;
+ }
+ case 2:
+ {
+ at_ftp_ret = mbtk_ftp_file_del(mbtk_at_ftp_par_at.at_ftp_handle,dir);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPDELE: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPDELE: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ printf("+CFTPDELE: SUCCESS\n");
+ sprintf(send_buf,"+CFTPDELE: SUCCESS\n");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ mbtk_at_printf(send_buf);
+ mbtk_at_printf("end");
+ mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+ mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+ return at_ftp_ret;
+}
+
+int mbtk_at_ftp_upload(char *remote_path,char *local_path, int size_byte, int rest_size)
+{
+ int at_ftp_ret=-1;
+ int len_size;
+ char send_buf[1024];
+
+ mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+ 0, mbtk_at_ftp_par_at.use_cert);
+ mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+ if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+ at_ftp_ret = -1;
+
+ at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+ if(at_ftp_ret != 0)
+ {
+ printf("ftp_login err:%d\n",at_ftp_ret);
+ }
+
+ memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+ memcpy(mbtk_at_ftp_par_at.remote_path, remote_path, strlen(remote_path)+1);
+ if(local_path!=NULL)
+ {
+ memset(mbtk_at_ftp_par_at.local_path, 0, strlen(mbtk_at_ftp_par_at.local_path)+1);
+ memcpy(mbtk_at_ftp_par_at.local_path, local_path, strlen(local_path)+1);
+ }
+ mbtk_at_ftp_par_at.put_len = size_byte;
+ mbtk_at_ftp_par_at.rest_size = rest_size;
+
+ {
+ FILE *fp;
+ fp=fopen(local_path,"r");
+ if(NULL==fp)
+ printf("Read file error\n");
+ else
+ {
+ printf("Open file success\n");
+ fseek(fp,0,SEEK_END); //将文件读写指针移动到文件尾
+ len_size=ftell(fp); //ftell函数获取从文件尾移动到文件开头的偏移量
+ fclose(fp);
+ }
+ }
+ if(local_path == NULL)
+ {
+ at_ftp_ret = mbtk_ftp_upload_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path,
+ NULL, size_byte);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ at_ftp_ret = mbtk_ftp_upload_send(mbtk_at_ftp_par_at.at_ftp_handle,"" ,size_byte);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ printf("+CFTPPUT: SUCCESS,<%d>\n",len_size);
+ sprintf(send_buf,"+CFTPPUT: SUCCESS,<%d>\n",len_size);
+ }
+ }
+ mbtk_ftp_upload_end(mbtk_at_ftp_par_at.at_ftp_handle);
+ }
+ else
+ {
+ at_ftp_ret = mbtk_ftp_upload_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path,
+ local_path, size_byte);
+ if(at_ftp_ret != 0)
+ {
+ printf("+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ sprintf(send_buf,"+CFTPPUT: FAIL,<%d>\n",at_ftp_ret);
+ }
+ else
+ {
+ printf("+CFTPPUT: SUCCESS,<%d>\n",len_size);
+ sprintf(send_buf,"+CFTPPUT: SUCCESS,<%d>\n",len_size);
+ }
+ }
+ mbtk_at_printf(send_buf);
+ mbtk_at_printf("end");
+ mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+ mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+ return at_ftp_ret;
+}
+
+void mbtk_at_ftp_data_cb(void *data, uint32 data_len)
+{
+ char resp_buf[2150];
+ printf("\n=====data_cb data[%s]=====\n=====data_cb data_len[%d]=====\n",data, data_len);
+
+ memset(resp_buf,0,2150);
+ sprintf(resp_buf, "+CFTPGET:");
+ mbtk_at_printf(resp_buf);
+
+ if(data_len > 1021)
+ {
+ memset(resp_buf,0,2150);
+ memcpy(resp_buf,data,1021);
+ mbtk_at_printf(resp_buf);
+ memset(resp_buf,0,2150);
+ sprintf(resp_buf, "<%d>", 1021);
+ mbtk_at_printf(resp_buf);
+
+ memset(resp_buf,0,2150);
+ sprintf(resp_buf, "+CFTPGET:");
+ mbtk_at_printf(resp_buf);
+ memset(resp_buf,0,2150);
+ memcpy(resp_buf,data+1021,data_len-1021);
+ mbtk_at_printf(resp_buf);
+ memset(resp_buf,0,2150);
+ sprintf(resp_buf, "<%d>", data_len-1021);
+ mbtk_at_printf(resp_buf);
+ }
+ else
+ {
+ memset(resp_buf,0,2150);
+ memcpy(resp_buf,data,data_len);
+ mbtk_at_printf(resp_buf);
+
+ memset(resp_buf,0,2150);
+ sprintf(resp_buf, "<%d>", data_len);
+ mbtk_at_printf(resp_buf);
+ }
+
+}
+
+int mbtk_at_ftp_download(void *remote_path, void *local_path, int data_cbc, int rest_size, int read_size)
+{
+
+ int at_ftp_ret=-1;
+ int len_size;
+
+ mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+ 0, mbtk_at_ftp_par_at.use_cert);
+ mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+ if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+ at_ftp_ret = -1;
+
+ at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+ if(at_ftp_ret != 0)
+ {
+ printf("ftp_login err:%d\n",at_ftp_ret);
+ }
+
+ memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+ memcpy(mbtk_at_ftp_par_at.remote_path, remote_path, strlen(remote_path)+1);
+ if(local_path!=NULL)
+ {
+ memset(mbtk_at_ftp_par_at.local_path, 0, strlen(mbtk_at_ftp_par_at.local_path)+1);
+ memcpy(mbtk_at_ftp_par_at.local_path, local_path, strlen(local_path)+1);
+ }
+ mbtk_at_ftp_par_at.rest_size = rest_size;
+ mbtk_at_ftp_par_at.read_size = read_size;
+
+ // Download file: /data
+ uint32 len_count = 0;
+ uint32 len;
+ int download_time = 0;
+ char resp_buf[1024];
+ int ret;
+
+ uint32 file_size = mbtk_ftp_file_size(mbtk_at_ftp_par_at.at_ftp_handle, remote_path);
+ if(file_size > 0)
+ {
+ if(rest_size > file_size)
+ {
+ printf("+CTPGETFILE: FAIL,<err>");
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",901);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+ goto exit;
+ }
+ printf("Will download file:/data[%d]\n", file_size);
+ /*
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "Will download file:/data[%d]",file_size);
+ mbtk_at_printf(resp_buf);
+ */
+ // Start download
+ if(data_cbc == 0)//to file
+ {
+ len = mbtk_ftp_download_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path, local_path, NULL);
+ /*
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "download size:/len[%d]",len);
+ mbtk_at_printf(resp_buf);
+ */
+ }
+ else if(data_cbc == 1)
+ {
+ len = mbtk_ftp_download_start(mbtk_at_ftp_par_at.at_ftp_handle, remote_path, NULL, mbtk_at_ftp_data_cb);
+ /*
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "download size:/len[%d]",len);
+ mbtk_at_printf(resp_buf);
+ */
+ }
+ else
+ {
+ printf("+CTPGETFILE: FAIL,<err>");
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",902);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+ goto exit;
+ }
+ if(len > 0)
+ {
+ len_count += len;
+ download_time++;
+ printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+ /*
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf,"Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+ mbtk_at_printf(resp_buf);
+ */
+ while (len_count < file_size
+ && download_time <= 10 // Try 10 times.
+ && (len = mbtk_ftp_download_continue(mbtk_at_ftp_par_at.at_ftp_handle)) > 0)
+ {
+ len_count += len;
+ download_time++;
+ printf("Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+ /*
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf,"Download[time-%d] size:[%d / %d]\n", download_time, len_count, file_size);
+ mbtk_at_printf(resp_buf);
+ */
+ }
+
+ printf("Download complete - [%d / %d].\n",len_count, file_size);
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "+CFTPGETFILE: SUCCESS,<%d>\r\n",len_count);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+ }
+ else
+ {
+ printf("FTP download fail[%d / %d].\n",len_count, file_size);
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d / %d> len=%d",len_count, file_size,len);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+ goto exit;
+ }
+ }else {
+ printf("File error.\n");
+ memset(resp_buf,0,1024);
+ sprintf(resp_buf, "+CTPGETFILE: FAIL,<%d>\r\n",904);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+ goto exit;
+ }
+
+
+exit:
+ if(file_size != len_count)
+ mbtk_at_ftp_par_at.rest_size = len_count;
+
+ //mbtk_at_printf(resp_buf);
+ mbtk_at_printf("end");
+ mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+ mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+ return at_ftp_ret;
+
+}
+
+void ftp_ls_at_cb_func(void *file_list_cb)
+{
+ int ret;
+ char resp_buf[1024 + 1];
+ printf("+CFTPLIST:\r\n%s\n", ((mbtk_ftp_file_info_s *)file_list_cb)->name);
+ sprintf(resp_buf, "%s",((mbtk_ftp_file_info_s *)file_list_cb)->name);
+ mbtk_at_printf(resp_buf);
+ //ret = ATRESP(30163, 0, 0, resp_buf);
+}
+
+
+int mbtk_at_ftp_list(char *ftp_path)
+{
+ int at_ftp_ret=-1;
+ int len_size;
+ char resp_buf[1024];
+
+ mbtk_at_ftp_par_at.at_ftp_handle = mbtk_ftp_init(mbtk_at_ftp_par_at.host, mbtk_at_ftp_par_at.port, mbtk_at_ftp_par_at.auth_type,
+ 0, mbtk_at_ftp_par_at.use_cert);
+ mbtk_ftp_data_type_set(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.ftp_type);//FTP_DATA_TYPE_I = 2 FTP_DATA_TYPE_A = 0
+ if(mbtk_at_ftp_par_at.at_ftp_handle < 0)
+ at_ftp_ret = -1;
+
+ at_ftp_ret = mbtk_ftp_login(mbtk_at_ftp_par_at.at_ftp_handle,mbtk_at_ftp_par_at.name,mbtk_at_ftp_par_at.pass);
+ if(at_ftp_ret != 0)
+ {
+ printf("ftp_login err:%d\n",at_ftp_ret);
+ }
+
+ memset(mbtk_at_ftp_par_at.remote_path, 0, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+ memcpy(mbtk_at_ftp_par_at.remote_path, ftp_path, strlen(ftp_path)+1);
+
+ at_ftp_ret = mbtk_ftp_cd(mbtk_at_ftp_par_at.at_ftp_handle, ftp_path);
+ if(FTP_ERR_SUCCESS != at_ftp_ret) {
+ printf("mbtk_ftp_cd() fail:%d\n", at_ftp_ret);
+ sprintf(resp_buf,"+CFTPLIST: FAIL:%d\n", at_ftp_ret);
+ goto exit;
+ }
+ mbtk_at_printf("+CFTPLIST:");
+ mbtk_ftp_file_info_s list_head;
+ list_head.ftp_ls_cb_typedef = ftp_ls_at_cb_func;
+ at_ftp_ret = mbtk_ftp_dir_ls(mbtk_at_ftp_par_at.at_ftp_handle, &list_head);
+ if(FTP_ERR_SUCCESS != at_ftp_ret) {
+ printf("mbtk_ftp_dir_ls() fail:%d\n", at_ftp_ret);
+ sprintf(resp_buf,"+CFTPLIST: FAIL:%d\n", at_ftp_ret);
+ goto exit;
+ }
+ else
+ {
+ printf("+CFTPLIST: SUCCESS\r\n");
+ sprintf(resp_buf,"+CFTPLIST: SUCCESS\r\n");
+ }
+exit:
+ mbtk_at_printf(resp_buf);
+ mbtk_at_printf("end");
+ mbtk_ftp_quit(mbtk_at_ftp_par_at.at_ftp_handle);
+ mbtk_ftp_deinit(mbtk_at_ftp_par_at.at_ftp_handle);
+ return at_ftp_ret;
+}
+
+int mbtk_at_get_ftp_data_info(char *remote_path, char *local_path, int *rest_size, int *read_size, int *put_len)
+{
+ if(remote_path != NULL)
+ {
+ memset(remote_path, 0, strlen(remote_path)+1);
+ memcpy(remote_path, mbtk_at_ftp_par_at.remote_path, strlen(mbtk_at_ftp_par_at.remote_path)+1);
+ }
+ if(local_path != NULL)
+ {
+ memset(local_path, 0, strlen(local_path)+1);
+ memcpy(local_path, mbtk_at_ftp_par_at.local_path, strlen(mbtk_at_ftp_par_at.local_path)+1);
+ }
+ if(rest_size != NULL)
+ *rest_size = mbtk_at_ftp_par_at.rest_size;
+ if(read_size != NULL)
+ *read_size = mbtk_at_ftp_par_at.read_size;
+ if(put_len != NULL)
+ *put_len = mbtk_at_ftp_par_at.put_len;
+ return 0;
+}
+
+
+
diff --git a/mbtk/libmbtk_lib/gnss/mbtk_gnss.c b/mbtk/libmbtk_lib/gnss/mbtk_gnss.c
new file mode 100755
index 0000000..cf9af27
--- /dev/null
+++ b/mbtk/libmbtk_lib/gnss/mbtk_gnss.c
@@ -0,0 +1,991 @@
+/*
+* mbtk_gnss.c
+*
+* MBTK GNSS API source.
+*
+*/
+/******************************************************************************
+
+ EDIT HISTORY FOR FILE
+
+ WHEN WHO WHAT,WHERE,WHY
+-------- -------- -------------------------------------------------------
+2024/7/11 LiuBin Initial version
+
+******************************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <time.h>
+
+#include "mbtk_gnss_inter.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+
+#define GNSS_BUFF_SIZE 2048
+
+static int gnss_cli_fd = -1;
+static pthread_t read_thread_id;
+static int exit_fd[2] = {-1};
+static mbtk_gnss_callback_func gnss_cb = NULL;
+static bool gnss_busy = FALSE;
+static pthread_cond_t gnss_cond;
+static pthread_mutex_t gnss_mutex;
+static gnss_err_enum gnss_result;
+
+#if 1//MBTK_GNSS_LOCATION_INFO
+static mbtk_gnss_location_info_t locl_info;
+
+extern long timezone;
+#endif
+
+static int sock_read(int fd, uint8 *msg, int data_len)
+{
+ memset(msg, 0, data_len);
+ int len = 0;
+
+ int read_len = 0;
+ while(1)
+ {
+ len = read(fd, msg + read_len, data_len - read_len);
+ if(len > 0)
+ {
+ read_len += len;
+ }
+ else if(len == 0)
+ {
+ LOGE("read() end.");
+ break;
+ }
+ else
+ {
+ if(EAGAIN == errno)
+ {
+ LOGV("Read end, lenght = %d", read_len);
+ }
+ else
+ {
+ LOGE("read() error[%d].", errno);
+ }
+ break;
+ }
+ }
+
+ if(read_len > 0)
+ {
+ // log_hex("DATA_RECV", msg, read_len);
+ return read_len;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static int sock_write(int fd, uint8 *msg, int data_len)
+{
+ int len = 0;
+ int write_len = 0;
+ while(write_len < data_len)
+ {
+ len = write(fd, msg + write_len, data_len - write_len);
+ if(len > 0)
+ {
+ write_len += len;
+ }
+ else if(len == 0)
+ {
+ LOGE("write() end.");
+ break;
+ }
+ else
+ {
+ LOGE("write() error[%d].", errno);
+ break;
+ }
+ }
+
+ if(write_len > 0)
+ {
+ //log_hex("DATA_SEND", msg, write_len);
+ return write_len;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static void gnss_timer_cb(int signo)
+{
+ if(gnss_busy) {
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_signal(&gnss_cond);
+ pthread_mutex_unlock(&gnss_mutex);
+ gnss_result = GNSS_ERR_TIMEOUT;
+ }
+ return;
+}
+
+#if 1//MBTK_GNSS_LOCATION_INFO
+static int strstr_n(const char *s1, const char *s2)
+{
+ int n;
+ int strlen = 0;
+
+ if(*s2)
+ {
+ while(*s1)
+ {
+ for(n = 0; *(s1+n) == *(s2 + n); n++)
+ {
+ if(!*(s2 + n + 1))
+ {
+ strlen++;
+ return strlen;
+ }
+ }
+ s1++;
+ strlen++;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+static int str2int( const char* head, const char* end )
+{
+ int result = 0;
+ int len = end - head;
+
+ for(; len > 0; len--, head++)
+ {
+ int c;
+ if (head >= end)
+ {
+ goto Fail;
+ }
+
+ c = *head - '0';
+ if ((unsigned)c >= 10)
+ {
+ goto Fail;
+ }
+ result = result * 10 + c;
+ }
+ return result;
+Fail:
+ return -1;
+}
+
+static double str2float( const char* head, const char* end )
+{
+ int len = end - head;
+ char temp[16];
+
+ if(len >= (int)sizeof(temp))
+ {
+ return 0;
+ }
+
+ memcpy( temp, head, len );
+ temp[len] = 0;
+ return strtod(temp, NULL);
+}
+
+static mbtk_token nmea_tokenizer_get(mbtk_nmeatokenizer* t, int index)
+{
+ mbtk_token tok;
+ static const char* dummy = "";
+
+ if (index < 0 || index >= t->count)
+ {
+ tok.head = tok.end = dummy;
+ }
+ else
+ {
+ tok = t->tokens[index];
+ }
+ return tok;
+}
+
+static int nmea_tokenizer_init(mbtk_nmeatokenizer* t, const char* head, const char* end, int param_num)
+{
+ int count = 0;
+ const char* p = head;
+ const char* q = end;
+ const char* tmp = NULL;
+ // the initial '$' is optional
+ if (p < q && p[0] == '$')
+ {
+ p += 1;
+ }
+ else
+ {
+ return -1;
+ }
+
+ //find '*',del '*25\r\n'
+ // get rid of checksum at the end of the sentecne
+ if (q >= p + 5 && q[-5] == '*')
+ {
+ q -= 5;
+ }
+ else
+ {
+ return -1;
+ }
+
+ while (p <= q)
+ {
+ tmp = memchr(p, ',', q-p);
+ if (tmp == NULL)
+ {
+ tmp = q;
+ }
+ // if (q > p) {
+ // q >= p include empty token: ,,
+ if (tmp >= p)
+ {
+ if (count < MAX_NMEA_TOKENS)
+ {
+ t->tokens[count].head = p;
+ t->tokens[count].end = tmp;
+ count += 1;
+ }
+ }
+
+ if (tmp <= q)
+ {
+ tmp += 1;
+ }
+
+ p = tmp;
+ }
+
+ if(count != param_num)
+ {
+ LOGD("count [%d], param_num [%d]", count, param_num);
+ return -1;
+ }
+
+ t->count = count;
+ return count;
+}
+
+static int nmea_update_date_time(mbtk_gnss_location_info_t* locl_info, mbtk_token date, mbtk_token time)
+{
+ char tmp_char[4] = {0};
+ struct tm tmp_time;
+
+ memset(&tmp_time, 0x0, sizeof(struct tm));
+ if (date.head + 6 > date.end)
+ {
+ LOGD("date get fail");
+ return -1;
+ }
+
+ memcpy(tmp_char, date.head, 2);
+ tmp_time.tm_mday = atoi(tmp_char);
+ memcpy(tmp_char, date.head + 2, 2);
+ tmp_time.tm_mon = atoi(tmp_char) - 1;
+ memcpy(tmp_char, date.head + 4, 2);
+ tmp_time.tm_year = 100 + atoi(tmp_char);
+
+ if (time.head + 6 > time.end)
+ {
+ LOGD("time get fail");
+ return -1;
+ }
+
+ memcpy(tmp_char, time.head, 2);
+ tmp_time.tm_hour = atoi(tmp_char);
+ memcpy(tmp_char, time.head + 2, 2);
+ tmp_time.tm_min = atoi(tmp_char);
+ memcpy(tmp_char, time.head + 4, 2);
+ tmp_time.tm_sec = atoi(tmp_char);
+ tmp_time.tm_isdst = -1;
+
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("data:%d-%d-%d %d:%d:%d", tmp_time.tm_year + 1900,
+ tmp_time.tm_mon,
+ tmp_time.tm_mday,
+ tmp_time.tm_hour,
+ tmp_time.tm_min,
+ tmp_time.tm_sec);
+#endif
+
+ time_t _t = mktime(&tmp_time);//parse location tmp_time
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("time: %ld", _t);
+#endif
+ tzset(); // auto set tz
+ _t = _t - timezone;
+ locl_info->timestamp = (int64_t)_t;
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("timestamp: %ld, %ld", locl_info->timestamp, timezone);
+#endif
+ return 0;
+}
+
+static int nmea_update_bearing(mbtk_gnss_location_info_t* locl_info, mbtk_token bearing)
+{
+ mbtk_token tok = bearing;
+
+ if (tok.head >= tok.end)
+ {
+ LOGD("bearing get fail");
+ return -1;
+ }
+
+ locl_info->bearing = str2float(tok.head, tok.end);
+ return 0;
+}
+
+static int nmea_update_speed(mbtk_gnss_location_info_t* locl_info, mbtk_token speed)
+{
+ mbtk_token tok = speed;
+
+ if (tok.head >= tok.end)
+ {
+ LOGD("speed get fail");
+ return -1;
+ }
+
+ locl_info->speed = str2float(tok.head, tok.end);
+ return 0;
+}
+
+static int nmea_update_latlong(mbtk_gnss_location_info_t* locl_info, mbtk_token latitude, mbtk_token longitude)
+{
+ double lat, lon;
+ mbtk_token tok;
+ tok = latitude;
+ if (tok.head + 6 > tok.end)
+ {
+ LOGD("latitude get fail");
+ return -1;
+ }
+ locl_info->latitude = str2float(tok.head, tok.end);
+
+ tok = longitude;
+ if (tok.head + 6 > tok.end)
+ {
+ LOGD("longitude get fail");
+ return -1;
+ }
+ locl_info->longitude = str2float(tok.head, tok.end);
+ return 0;
+}
+
+static int nmea_update_altitude(mbtk_gnss_location_info_t* locl_info, mbtk_token altitude)
+{
+ mbtk_token tok = altitude;
+
+ if (tok.head >= tok.end)
+ {
+ LOGD("altitude get fail");
+ return -1;
+ }
+
+ locl_info->altitude = str2float(tok.head, tok.end);
+ return 0;
+}
+
+static int ind_nmea_parse(const char *data, int data_len, mbtk_gnss_location_info_t* locl_info)
+{
+ int ret;
+ mbtk_nmeatokenizer tzer = {0};
+ if(strstr_n(data + 3, "RMC"))
+ {
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("ind data_len: [%d] data: %s", data_len, data);
+#endif
+ ret = nmea_tokenizer_init(&tzer, data, data + data_len, NMEA_RMC_PARAM_NUM);
+ if(ret < 0)
+ {
+ LOGD("nmea_tokenizer_init fail");
+ return -1;
+ }
+
+ mbtk_token tok_time = nmea_tokenizer_get(&tzer,1);
+ mbtk_token tok_fixStatus = nmea_tokenizer_get(&tzer,2);
+ mbtk_token tok_speed = nmea_tokenizer_get(&tzer,7);
+ mbtk_token tok_bearing = nmea_tokenizer_get(&tzer,8);
+ mbtk_token tok_date = nmea_tokenizer_get(&tzer,9);
+
+ if(tok_fixStatus.head[0] == 'A')
+ {
+ ret = nmea_update_date_time(locl_info, tok_date, tok_time);
+ if(ret < 0)
+ {
+ LOGD("nmea_update_date_time fail");
+ return -1;
+ }
+ locl_info->flags |= GNSS_LOCATION_HAS_TIMESTAMP;
+
+ ret = nmea_update_bearing(locl_info, tok_bearing);
+ if(ret < 0)
+ {
+ LOGD("nmea_update_bearing fail");
+ return -1;
+ }
+ locl_info->flags |= GNSS_LOCATION_HAS_BEARING;
+
+ ret = nmea_update_speed(locl_info, tok_speed);
+ if(ret < 0)
+ {
+ LOGD("nmea_update_speed fail");
+ return -1;
+ }
+ locl_info->flags |= GNSS_LOCATION_HAS_SPEED;
+ }
+ }
+ else if(strstr_n(data + 3, "GGA"))
+ {
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("ind data_len: [%d] data: %s", data_len, data);
+#endif
+ ret = nmea_tokenizer_init(&tzer, data, data + data_len, NMEA_GGA_PARAM_NUM);
+ if(ret < 0)
+ {
+ LOGD("nmea_tokenizer_init fail");
+ return -1;
+ }
+
+ mbtk_token tok_latitude = nmea_tokenizer_get(&tzer,2);
+ mbtk_token tok_longitude = nmea_tokenizer_get(&tzer,4);
+ mbtk_token tok_isPix = nmea_tokenizer_get(&tzer,6);
+ mbtk_token tok_altitude = nmea_tokenizer_get(&tzer,9);
+
+ if(tok_isPix.head[0] > '0' && tok_isPix.head[0] < '9')
+ {
+ ret = nmea_update_latlong(locl_info, tok_latitude, tok_longitude);
+ if(ret < 0)
+ {
+ LOGD("nmea_update_latlong fail");
+ return -1;
+ }
+ locl_info->flags |= GNSS_LOCATION_HAS_LAT_LONG;
+
+ ret = nmea_update_altitude(locl_info, tok_altitude);
+ if(ret < 0)
+ {
+ LOGD("nmea_update_altitude fail");
+ return -1;
+ }
+ locl_info->flags |= GNSS_LOCATION_HAS_ALTITUDE;
+ }
+ }
+ else
+ {
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("ind data_len: [%d] data: %s", data_len, data);
+#endif
+ }
+ return 0;
+}
+#endif
+
+
+static void gnss_rsp_process(const char *data, int data_len)
+{
+ int index = 0;
+ char buff[GNSS_BUFF_SIZE];
+ int buff_len = 0;
+ int ret = 0;
+ int tag_len = 0;
+ while(index < data_len) {
+ if(data[index] == MBTK_IND_START_FLAG) {
+ memset(buff, 0, sizeof(buff));
+ buff_len = 0;
+ } else if(data[index] == MBTK_IND_END_FLAG) {
+ buff[buff_len] = '\0';
+ if(memcmp(MBTK_IND_LOCATION_TAG, buff, strlen(MBTK_IND_LOCATION_TAG)) == 0) {
+ if(gnss_cb) {
+#if 1//MBTK_GNSS_LOCATION_INFO
+ tag_len = strlen(MBTK_IND_LOCATION_TAG);
+ ret = ind_nmea_parse(buff + tag_len, buff_len - tag_len, &locl_info);
+#if MBTK_GNSS_LOG_ENABLED
+ LOGD("gnss_cb: [%p], locl_info.flags [%d]", gnss_cb, locl_info.flags);
+#endif
+ if(locl_info.flags == GNSS_LOCATION_HAS_ALL) {
+ gnss_cb(MBTK_GNSS_IND_LOCATION, &locl_info, sizeof(mbtk_gnss_location_info_t));
+ locl_info.flags = 0;
+ }
+#endif
+ }
+ } else if(memcmp(MBTK_IND_NMEA_TAG, buff, strlen(MBTK_IND_NMEA_TAG)) == 0) {
+ if(gnss_cb) {
+ tag_len = strlen(MBTK_IND_NMEA_TAG);
+ gnss_cb(MBTK_GNSS_IND_NMEA, buff + tag_len, buff_len - tag_len);
+ }
+ } else {
+ LOGD("RSP[len - %d] : %s", buff_len, buff);
+ if(gnss_busy) {
+ // XXXXXX:<result>
+ char *ptr = strstr(buff, ":");
+ if(ptr) {
+ gnss_result = atoi(ptr + 1);
+ }
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_signal(&gnss_cond);
+ pthread_mutex_unlock(&gnss_mutex);
+ }
+ }
+ } else {
+ buff[buff_len++] = data[index];
+ }
+ index++;
+ }
+}
+
+static void* gnss_read_run(void* arg)
+{
+ int epoll_fd = epoll_create(5);
+ if(epoll_fd < 0)
+ {
+ LOGE("epoll_create() fail[%d].", errno);
+ return NULL;
+ }
+
+ uint32 event = EPOLLIN | EPOLLET;
+ struct epoll_event ev_cli, ev_exit;
+ ev_cli.data.fd = gnss_cli_fd;
+ ev_cli.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,gnss_cli_fd,&ev_cli);
+
+ ev_exit.data.fd = exit_fd[0];
+ ev_exit.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,exit_fd[0],&ev_exit);
+
+ int nready = -1;
+ struct epoll_event epoll_events[EPOLL_LISTEN_MAX];
+ while(1)
+ {
+ nready = epoll_wait(epoll_fd, epoll_events, EPOLL_LISTEN_MAX, -1);
+ if(nready > 0)
+ {
+ int i;
+ for(i = 0; i < nready; i++)
+ {
+ LOGV("fd[%d] event = %x",epoll_events[i].data.fd, epoll_events[i].events);
+ if(epoll_events[i].events & EPOLLHUP) // Closed by server.
+ {
+
+ }
+ else if(epoll_events[i].events & EPOLLIN)
+ {
+ if(gnss_cli_fd == epoll_events[i].data.fd) // Server data arrive.
+ {
+ char buff[GNSS_BUFF_SIZE + 1];
+ int len = sock_read(gnss_cli_fd, buff, GNSS_BUFF_SIZE);
+ if(len > 0) {
+ gnss_rsp_process(buff, len);
+ }
+ }
+ else if(exit_fd[0] == epoll_events[i].data.fd) //
+ {
+ char buff[100] = {0};
+ int len = read(exit_fd[0], buff, 100);
+ if(len > 0) {
+ LOGI("CMD : %s", buff);
+ if(strcmp(buff, "EXIT") == 0) {
+ goto read_thread_exit;
+ } else {
+ LOGD("Unkonw cmd : %s", buff);
+ }
+ } else {
+ LOGE("sock_read() fail.");
+ }
+ }
+ else
+ {
+ LOGW("Unknown socket : %d", epoll_events[i].data.fd);
+ }
+ }
+ else
+ {
+ LOGW("Unknown event : %x", epoll_events[i].events);
+ }
+ }
+ }
+ else
+ {
+ LOGW("epoll_wait() fail[%d].", errno);
+ }
+ }
+
+read_thread_exit:
+ LOGD("info_read thread exit.");
+ return NULL;
+}
+
+gnss_err_enum mbtk_gnss_init(mbtk_gnss_callback_func cb)
+{
+ if(gnss_cli_fd > 0) {
+ LOGW("GNSS client has inited.");
+ return GNSS_ERR_OK;
+ }
+
+ gnss_cli_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(gnss_cli_fd < 0)
+ {
+ LOGE("socket() fail[%d].", errno);
+ goto error;
+ }
+
+ // Set O_NONBLOCK
+ int flags = fcntl(gnss_cli_fd, F_GETFL, 0);
+ if (flags < 0)
+ {
+ LOGE("Get flags error:%d", errno);
+ goto error;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(gnss_cli_fd, F_SETFL, flags) < 0)
+ {
+ LOGE("Set flags error:%d", errno);
+ goto error;
+ }
+
+ struct sockaddr_un cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sun_family = AF_LOCAL;
+ strcpy(cli_addr.sun_path, SOCK_GNSS_PATH);
+ if(connect(gnss_cli_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+ {
+ LOGE("connect() fail[%d].", errno);
+ goto error;
+ }
+
+ if(pipe(exit_fd)) {
+ LOGE("pipe() fail[%d].", errno);
+ goto error;
+ }
+
+ if(pthread_create(&read_thread_id, NULL, gnss_read_run, NULL))
+ {
+ LOGE("pthread_create() fail.");
+ goto error;
+ }
+ pthread_mutex_init(&gnss_mutex, NULL);
+ pthread_cond_init(&gnss_cond, NULL);
+ gnss_cb = cb;
+ return GNSS_ERR_OK;
+
+error:
+ if(gnss_cli_fd > 0) {
+ close(gnss_cli_fd);
+ gnss_cli_fd = -1;
+ }
+ if(exit_fd[0] > 0) {
+ close(exit_fd[0]);
+ exit_fd[0] = -1;
+ }
+ if(exit_fd[1] > 0) {
+ close(exit_fd[1]);
+ exit_fd[1] = -1;
+ }
+
+ return GNSS_ERR_UNKNOWN;
+}
+
+gnss_err_enum mbtk_gnss_deinit()
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ }
+
+ if(exit_fd[1] > 0) {
+ write(exit_fd[1], "EXIT", 4);
+ }
+
+ int ret = pthread_join(read_thread_id, NULL);
+ if(ret){
+ LOGE("pthrad_join fail(%d)",ret);
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ close(gnss_cli_fd);
+ gnss_cli_fd = -1;
+ close(exit_fd[0]);
+ exit_fd[0] = -1;
+ close(exit_fd[1]);
+ exit_fd[1] = -1;
+ gnss_cb = NULL;
+ gnss_busy = FALSE;
+ pthread_mutex_destroy(&gnss_mutex);
+ pthread_cond_destroy(&gnss_cond);
+
+ return GNSS_ERR_OK;
+}
+
+/*===========================================================================
+FUNCTION mbtk_gnss_open
+
+DESCRIPTION:
+ Open/Close GNSS.
+
+PARAMETERS:
+ type [IN]: How to turn on or off GNSS,The available values are as follows:
+ 0 : Close GNSS;
+ 1-15 : Open GNSS with NMEA print;
+ (GNSS_PRINT_PORT_UART1 / GNSS_PRINT_PORT_USB_NMEA / GNSS_PRINT_PORT_USB_AT / GNSS_PRINT_PORT_TTY_AT)
+ Other : Open GNSS without print NMEA
+ timeout [IN]: Timeout with second.
+
+RETURN VALUE:
+ gnss_err_enum
+
+===========================================================================*/
+gnss_err_enum mbtk_gnss_open(int type, int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_init:x
+ char cmd[32] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_init:%d", type);
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+gnss_err_enum mbtk_gnss_close(int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_deinit
+ char *cmd = "gnss_deinit";
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+
+gnss_err_enum mbtk_gnss_setting(const char *setting_cmd, int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_setting:cmd
+ char cmd[1024] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_setting:%s", setting_cmd);
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+gnss_err_enum mbtk_gnss_dl(const char *fw_path, int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_dl:fw_name
+ char cmd[32] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_dl:%s", fw_path);
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+/**
+* Set GNSS data callback.
+*
+* gnss_ind : MBTK_GNSS_IND_LOCATION / MBTK_GNSS_IND_NMEA
+* timeout : Timeout with second.
+*
+*/
+gnss_err_enum mbtk_gnss_ind_set(uint32 gnss_ind, int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_ind:ind_type
+ char cmd[32] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_ind:%d", gnss_ind);
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+gnss_err_enum mbtk_gnss_eph_download(int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_agnss_get:<eph_data>,<alam_flag>
+ char cmd[32] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_agnss_get:%d,0", (int)GNSS_EPH_CFG);
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+gnss_err_enum mbtk_gnss_eph_inject(int timeout)
+{
+ if(gnss_cli_fd < 0) {
+ LOGW("GNSS client not inited.");
+ return GNSS_ERR_UNKNOWN;
+ }
+
+ if(gnss_busy) {
+ LOGE("BUSY");
+ return GNSS_ERR_BUSY;
+ } else {
+ gnss_result = GNSS_ERR_OK;
+ gnss_busy = TRUE;
+ if(timeout > 0) {
+ mbtk_timer_set(gnss_timer_cb, timeout * 1000);
+ }
+
+ // gnss_agnss_set
+ char cmd[32] = {0};
+ snprintf(cmd, sizeof(cmd), "gnss_agnss_set");
+ sock_write(gnss_cli_fd, cmd, strlen(cmd));
+
+ pthread_mutex_lock(&gnss_mutex);
+ pthread_cond_wait(&gnss_cond, &gnss_mutex);
+ pthread_mutex_unlock(&gnss_mutex);
+
+ gnss_busy = FALSE;
+
+ return gnss_result;
+ }
+}
+
+void mbtk_gnss_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_gnss_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/gnss/mbtk_gnss_5311.c b/mbtk/libmbtk_lib/gnss/mbtk_gnss_5311.c
new file mode 100755
index 0000000..e1333d1
--- /dev/null
+++ b/mbtk/libmbtk_lib/gnss/mbtk_gnss_5311.c
@@ -0,0 +1,1049 @@
+/**
+ * \file mbtk_gnss_5311.c
+ * \brief gnss module.
+ *
+ * Detailed description
+ * \Author: Sniper <yq.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2023-12-20
+ */
+#if 1
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+
+
+
+#include <libubox/blobmsg_json.h>
+#include <libubus.h>
+
+#include "mbtk_gnss_5311.h"
+
+/**********************************DEFINE***********************************/
+#define MBTK_GNSS_UBUS_SERVER "gps"
+#define MBTK_GNSS_UBUS_INIT "gnss_init"
+#define MBTK_GNSS_UBUS_INIT_PARAM "gnss_init_param"
+#define MBTK_GNSS_UBUS_SLEEP "gnss_sleep"
+#define MBTK_GNSS_UBUS_SLEEP_PARAM "gnss_sleep_param"
+#define MBTK_GNSS_UBUS_SET "gnss_setting"
+#define MBTK_GNSS_UBUS_SET_PARAM "gnss_setting_param"
+#define MBTK_GNSS_UBUS_GET_STATUS "gnss_get_state"
+#define MBTK_GNSS_UBUS_AGPS_SERVER "server_name"
+#define MBTK_GNSS_UBUS_ALAM_FLAG "alam_flag"
+#define MBTK_GNSS_UBUS_GET_AGPS "gnss_get_agps"
+#define MBTK_GNSS_UBUS_SET_AGPS "gnss_set_agps"
+
+#define MBTK_RESULT_FAIL -1
+#define MBTK_RESULT_SUCCESS 0
+
+#define MBTK_GNSS_CLOSE 0
+#define MBTK_GNSS_OPEN 1
+
+#define MBTK_GNSS_WAKEUP 0
+#define MBTK_GNSS_SLEEP 1
+
+#define DATABITS CS8
+#define BAUD B115200
+#define STOPBITS 0
+#define PARITYON 0
+#define PARITY 0
+
+#define MBTK_GNSS_NMEA_PORT "/dev/tty_gnss_nmea"
+
+#define GNSS_SOCK_PATH "/tmp/mbtk_gnss_sock"
+
+static int sock_listen_fd = -1;
+
+typedef enum {
+ GNSS_CMD_INIT = 0,
+ GNSS_CMD_DEINIT,
+ GNSS_CMD_SETTING,
+ GNSS_CMD_DL
+} gnss_cmd_enum;
+
+/**********************************DEFINE***********************************/
+
+/**********************************VARIABLE***********************************/
+const struct blobmsg_policy mbtk_gnss_ubus_cb_policy[] = {
+ [0] = {
+ .name = "event",
+ .type = BLOBMSG_TYPE_INT32,
+ },
+};
+
+const struct blobmsg_policy mbtk_gnss_state_resp_cb_policy[] = {
+ [0] = {
+ .name = "gps_state_resp",
+ .type = BLOBMSG_TYPE_STRING,
+ },
+};
+
+static int mbtk_gnss_uloop_init = 0;
+static struct ubus_context *mbtk_gnss_ctx = NULL;
+static int mbtk_gnss_status = MBTK_GNSS_CLOSE;
+static mbtk_gnss_nmea_status nmea_state = {0};
+/**********************************VARIABLE***********************************/
+
+/**********************************FUNC***********************************/
+struct ubus_context *mbtk_get_ubus_ctx(void)
+{
+ if (!mbtk_gnss_uloop_init)
+ {
+ return NULL;
+ }
+ if (mbtk_gnss_ctx != NULL)
+ {
+ return mbtk_gnss_ctx;
+ }
+
+ mbtk_gnss_ctx = ubus_connect(NULL);
+ if (!mbtk_gnss_ctx)
+ {
+ LOGE("[mbtk_gnss_api] ubus_connect connect fail.");
+ return NULL;
+ }
+
+ ubus_add_uloop(mbtk_gnss_ctx);
+ return mbtk_gnss_ctx;
+}
+
+int mbtk_gnss_ubus_uloop_init(void)
+{
+ int ret = -1;
+ if(mbtk_gnss_uloop_init == 0)
+ {
+ ret = uloop_init();
+ if(ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] uloop_init fail.ret = [%d]", ret);
+ return MBTK_RESULT_FAIL;
+ }
+
+ if(mbtk_gnss_ctx != NULL)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_ctx not NULL.");
+ return MBTK_RESULT_FAIL;
+ }
+
+ mbtk_gnss_ctx = ubus_connect(NULL);
+ if(!mbtk_gnss_ctx)
+ {
+ LOGE("[mbtk_gnss_api] ubus_connect fail.");
+ return MBTK_RESULT_FAIL;
+ }
+
+ ubus_add_uloop(mbtk_gnss_ctx);
+ }
+ mbtk_gnss_uloop_init = 1;
+ return MBTK_RESULT_SUCCESS;
+}
+
+
+int mbtk_gnss_ubus_uloop_deinit(void)
+{
+ if(mbtk_gnss_uloop_init == 1)
+ {
+ if(mbtk_gnss_ctx != NULL)
+ {
+ ubus_free(mbtk_gnss_ctx);
+ mbtk_gnss_ctx = NULL;
+ }
+
+ uloop_done();
+ mbtk_gnss_uloop_init = 0;
+ }
+ return MBTK_RESULT_SUCCESS;
+}
+
+static void mbtk_gnss_ubus_result_callback(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ UNUSED(type);
+
+ struct blob_attr *tb[1];
+ struct blob_attr *cur = NULL;
+ unsigned int event;
+ MBTK_GNSS_5311_RESULT_TYPE* ubus_gnss_result = (MBTK_GNSS_5311_RESULT_TYPE *)req->priv;
+ int rc;
+
+ /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+ rc = blobmsg_parse(mbtk_gnss_ubus_cb_policy, 1, tb, blob_data(msg), blob_len(msg));
+ if (rc < 0)
+ {
+ LOGE("[mbtk_gnss_api] blobmsg_parse fail.rc = [%d]", rc);
+ *ubus_gnss_result = MBTK_GNSS_RESULT_FAIL;
+ return;
+ }
+
+ /*parse first parameter*/
+ cur = tb[0];
+ if (!cur)
+ {
+ LOGE("[mbtk_gnss_api] cur is NULL.");
+ *ubus_gnss_result = MBTK_GNSS_RESULT_FAIL;
+ return;
+ }
+
+ event = blobmsg_get_u32(cur);
+ LOGE("[mbtk_gnss_api] get event = [%d].", event);
+
+ switch(event)
+ {
+ case ASR_GPS_INITIAL_SUCCESS:
+ case ASR_GPS_INITIALED:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_OPEN_SUCCESS;
+ break;
+ }
+ case ASR_GPS_INITIAL_FAILED:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_OPEN_FAIL;
+ break;
+ }
+ case ASR_GPS_DOWNLOAD_SUCCESS:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_DOWNLOAD_SUCCESS;
+ break;
+ }
+ case ASR_GPS_DOWNLOAD_FAIL:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_DOWNLOAD_FAIL;
+ break;
+ }
+ case ASR_GPS_SEND_DATA_SUCCESS:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_SEND_SUCCESS;
+ break;
+ }
+ case ASR_GPS_SEND_DATA_FAIL:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_SEND_FAIL;
+ break;
+ }
+ case ASR_GPS_DEINIT_SUCCESS:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_CLOSE_SUCCESS;
+ break;
+ }
+ case ASR_GPS_DEINIT_FAIL:
+ {
+ *ubus_gnss_result = MBTK_GNSS_RESULT_CLOSE_FAIL;
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+
+ return;
+}
+
+static void mbtk_gnss_state_get_callback(struct ubus_request *req, int type, struct blob_attr *msg)
+{
+ UNUSED(type);
+
+ struct blob_attr *tb[1];
+ struct blob_attr *cur;
+ char *gps_state = NULL;
+ int rc;
+ char *outString = (char *)req->priv;
+
+ /*parsing blob to be accessed easily with tb array - parse "1" argument*/
+ rc = blobmsg_parse(mbtk_gnss_state_resp_cb_policy, 1, tb, blob_data(msg), blob_len(msg));
+ if (rc < 0)
+ {
+ LOGE("[mbtk_gnss_api] blobmsg_parse fail.rc = [%d]", rc);
+ return;
+ }
+
+ /*parse first parameter*/
+ cur = tb[0];
+ if (!cur)
+ {
+ LOGE("[mbtk_gnss_api] cur is NULL.");
+ return;
+ }
+
+ gps_state = blobmsg_get_string(cur);
+ LOGE("[mbtk_gnss_api] get status = [%s].", gps_state);
+ memset(outString, 0x0, 128);
+ memcpy(outString, gps_state, strlen(gps_state));
+
+ return;
+}
+
+static void mbtk_gnss_open_port(int *fd_ptr, const char *file_path, int flag, int tty)
+{
+
+ int fd = -1;
+
+ if((fd = open(file_path, flag)) < 0)
+ {
+ LOGE("[mbtk_gnss_api] Open %s fail errno = [%d].", file_path, errno);
+ return;
+ }
+
+ LOGE("[mbtk_gnss_api] Open %s success.", file_path);
+ if (tty)
+ {
+ /* set newtio */
+ struct termios newtio;
+ memset(&newtio, 0, sizeof(newtio));
+ //(void)fcntl(fd, F_SETFL, 0);
+
+ /* no flow control for uart by default */
+ newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
+ newtio.c_iflag = IGNPAR;
+ //newtio.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ newtio.c_oflag = 0;
+ newtio.c_lflag = 0; /* disable ECHO, ICANON, etc... */
+
+ newtio.c_cc[VERASE] = 0x8; /* del */
+ newtio.c_cc[VEOF] = 4; /* Ctrl-d */
+ newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */
+ newtio.c_cc[VEOL] = 0xD; /* '\0' */
+
+ tcflush(fd, TCIOFLUSH);
+ tcsetattr(fd, TCSANOW, &newtio);
+ }
+
+ *fd_ptr = fd;
+}
+
+static int epoll_deregister(int epoll_fd,int fd )
+{
+ int ret;
+ do {
+ ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+static int epoll_register(int epoll_fd, int fd)
+{
+ struct epoll_event ev;
+ int ret, flags;
+
+ /* important: make the fd non-blocking */
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+ do {
+ ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
+ } while (ret < 0 && errno == EINTR);
+
+ return ret;
+}
+
+
+static void *gnss_nmea_thread(void* arg)
+{
+ int epoll_fd= epoll_create(2);
+ int started = 0;
+ int nmea_fd = nmea_state.fd;
+ int control_fd = nmea_state.control[1];
+ int i = 0;
+ int fd= -1;
+ int len = 0;
+ int offset = 0;
+ char nmea_buf[1025] = {0};
+ struct epoll_event events[2];
+ int ne, nevents;
+ int ret = -1;
+ char cmd = 0;
+ char c;
+
+ int pos = 0;
+ int overflow = 0;
+ char in[128] = {0};
+
+ /* register control file descriptors for polling */
+ epoll_register( epoll_fd, control_fd );
+ epoll_register( epoll_fd, nmea_fd );
+
+ LOGE("[mbtk_gnss_api] gnss_nmea_thread running");
+
+ for (;;)
+ {
+ nevents = -1;
+ nevents = epoll_wait( epoll_fd, events, 2, -1 );
+ if (nevents < 0)
+ {
+ if (errno != EINTR)
+ {
+ LOGE("[mbtk_gnss_api] epoll_wait() unexpected error: %s", strerror(errno));
+ }
+ continue;
+ }
+
+ for (ne = 0; ne < nevents; ne++)
+ {
+ if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0)
+ {
+ LOGE("[mbtk_gnss_api] EPOLLERR or EPOLLHUP after epoll_wait()!");
+ return NULL;
+ }
+
+ if ((events[ne].events & EPOLLIN) != 0)
+ {
+ fd = events[ne].data.fd;
+
+ if (fd == control_fd)
+ {
+ do {
+ ret = read( fd, &cmd, 1 );
+ } while (ret < 0 && errno == EINTR);
+ LOGE("[mbtk_gnss_api] entry nmea thread quit cmd = [%d]!", cmd);
+ if (cmd == 1)
+ {
+ epoll_deregister( epoll_fd, control_fd );
+ epoll_deregister( epoll_fd, nmea_fd );
+ LOGE("[mbtk_gnss_api] gnss thread quitting on demand");
+ return NULL;
+ }
+ }
+ else if (fd == nmea_fd)
+ {
+ memset(nmea_buf, 0x0, 1024);
+ len = read(fd, nmea_buf, 1024);
+ if(len > 0)
+ {
+ for(offset = 0; offset < len; offset++)
+ {
+ c = nmea_buf[offset];
+ if(pos == 0 && c != '$')
+ {
+ continue;
+ }
+
+ if (overflow) {
+ overflow = (c != '\n');
+ continue;
+ }
+
+ if (pos >= (int) sizeof(in)-1 )
+ {
+ overflow = 1;
+ pos = 0;
+ continue;
+ }
+
+ in[pos] = c;
+ pos += 1;
+
+ if (c == '\n')
+ {
+ if(nmea_state.callbacks != NULL)
+ {
+ nmea_state.callbacks((void *)in, pos);
+ }
+ memset(in, 0x0, pos);
+ pos = 0;
+ }
+ }
+ }
+ else
+ {
+ LOGE("[mbtk_gnss_api] read() fail:%d, errno = %d\n", len, errno);
+ }
+ }
+ else
+ {
+ LOGE("[mbtk_gnss_api] epoll_wait() returned unkown fd %d ?", fd);
+ }
+ }
+ }
+ }
+}
+
+static int mbtk_gnss_nmea_thread_init(void)
+{
+ if(nmea_state.init == 1)
+ {
+ LOGE("[mbtk_gnss_api] nmea thread is open.");
+ return MBTK_RESULT_SUCCESS;
+ }
+
+ mbtk_gnss_open_port(&nmea_state.fd, MBTK_GNSS_NMEA_PORT, O_RDWR | O_NONBLOCK | O_NOCTTY, 1);
+
+ if (socketpair( AF_LOCAL, SOCK_STREAM, 0, nmea_state.control ) < 0 )
+ {
+ LOGE("[mbtk_gnss_api] could not create thread control socket pair: %s", strerror(errno));
+
+ /*close the control socket pair && Retry again.*/
+ if(nmea_state.control[0] > 0)
+ {
+ close( nmea_state.control[0] );
+ nmea_state.control[0] = -1;
+ }
+
+ if(nmea_state.control[1] > 0)
+ {
+ close( nmea_state.control[1] );
+ nmea_state.control[1] = -1;
+ }
+ return MBTK_RESULT_FAIL;
+ }
+
+ pthread_create(&nmea_state.thread, NULL, gnss_nmea_thread, NULL);
+ if ( !nmea_state.thread )
+ {
+ LOGE("[mbtk_gnss_api] could not create gps thread: %s", strerror(errno));
+ return MBTK_RESULT_FAIL;
+ }
+
+ nmea_state.gnss_msg_state = MBTK_GNSS_MSG_NMEA_INFO;
+ nmea_state.init = 1;
+ return MBTK_RESULT_SUCCESS;
+}
+
+static int mbtk_gnss_nmea_thread_deinit(void)
+{
+ // tell the thread to quit, and wait for it
+ if(nmea_state.init == 1)
+ {
+ char cmd = 1;
+ void* dummy = NULL;
+ write( nmea_state.control[0], &cmd, 1 );
+ pthread_join(nmea_state.thread, &dummy);
+
+ // close the control socket pair
+ if(nmea_state.control[0] > 0)
+ {
+ close( nmea_state.control[0] );
+ nmea_state.control[0] = -1;
+ }
+ if(nmea_state.control[1] > 0)
+ {
+ close( nmea_state.control[1] );
+ nmea_state.control[1] = -1;
+ }
+
+ LOGE("[mbtk_gnss_api] %s: deinit", __FUNCTION__);
+
+ // close connection to the QEMU GPS daemon
+ if(nmea_state.fd)
+ {
+ close(nmea_state.fd);
+ nmea_state.fd = -1;
+ }
+
+ nmea_state.callbacks = NULL;
+ nmea_state.gnss_msg_state = MBTK_GNSS_MSG_NMEA_INFO;
+ nmea_state.init = 0;
+ }
+
+ return MBTK_RESULT_SUCCESS;
+}
+
+int mbtk_invoke_reply_data_cb(const char *service, const char *method, struct blob_attr *msg,
+ ubus_data_handler_t cb, void *cb_param, int timeout)
+{
+ struct ubus_context *ctx = NULL;
+ int rc = -1;
+ uint32_t id;
+ struct ubus_request req;
+
+ ctx = mbtk_get_ubus_ctx();
+ if(ctx == NULL)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_get_ubus_ctx fail.");
+ return MBTK_RESULT_FAIL;
+ }
+
+ /* Look up the target object id by the object path */
+ rc = ubus_lookup_id(ctx, service, &id);
+ if(rc)
+ {
+ LOGE("[mbtk_gnss_api] ubus_lookup_id fail.rc = [%d]", rc);
+ return MBTK_RESULT_FAIL;
+ }
+
+ rc = ubus_invoke(ctx, id, method, msg, cb, cb_param, timeout);
+ if(rc)
+ {
+ LOGE("[mbtk_gnss_api] ubus_invoke fail.rc = [%d]", rc);
+ return MBTK_RESULT_FAIL;
+ }
+ return MBTK_RESULT_SUCCESS;
+}
+
+ int mbtk_invoke_noreply(const char *service, const char *method, struct blob_attr *msg)
+ {
+ struct ubus_context *ctx;
+ int rc = -1;
+ uint32_t id;
+ struct ubus_request req;
+
+ ctx = mbtk_get_ubus_ctx();
+ if(ctx == NULL)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_get_ubus_ctx fail.");
+ return MBTK_RESULT_FAIL;
+ }
+ /* Look up the target object id by the object path */
+ rc = ubus_lookup_id(ctx, service, &id);
+ if(rc)
+ {
+ LOGE("[mbtk_gnss_api] ubus_lookup_id fail.rc = [%d]", rc);
+ return MBTK_RESULT_FAIL;
+ }
+
+ rc = ubus_invoke_async(ctx, id, method, msg, &req);
+ if(rc)
+ {
+ LOGE("[mbtk_gnss_api] ubus_invoke_async fail.rc = [%d]", rc);
+ return MBTK_RESULT_FAIL;
+ }
+
+ /* cancel req (on client side) because noreply is needed */
+ ubus_abort_request(ctx, &req);
+ return MBTK_RESULT_SUCCESS;
+ }
+
+ static int mbtk_GPS_process(gnss_cmd_enum cmd, void *arg)
+{
+ if(sock_listen_fd < 0) {
+ sock_listen_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(sock_listen_fd < 0)
+ {
+ printf("socket() fail[%d].\n", errno);
+ return -1;
+ }
+
+ struct sockaddr_un cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sun_family = AF_LOCAL;
+ strcpy(cli_addr.sun_path, GNSS_SOCK_PATH);
+ if(connect(sock_listen_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+ {
+ printf("connect() fail[%d].\n", errno);
+ close(sock_listen_fd);
+ sock_listen_fd = -1;
+ return -1;
+ }
+ }
+
+ char buff[100] = {0};
+ if(cmd == GNSS_CMD_INIT) {
+ if(arg) {
+ sprintf(buff, "gnss_init:%d", *(int*)arg);
+ } else {
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DEINIT) {
+ sprintf(buff, "gnss_deinit");
+ } else if(cmd == GNSS_CMD_SETTING) {
+ sprintf(buff, "gnss_setting:%s", arg);
+ } else if(cmd == GNSS_CMD_DL) {
+ sprintf(buff, "gnss_dl:%s", arg);
+ } else {
+ printf("Unknown cmd.\n");
+ return -1;
+ }
+
+ write(sock_listen_fd, buff, strlen(buff));
+
+ int len = 0;
+ while(1) {
+ memset(buff, 0, sizeof(buff));
+ len = read(sock_listen_fd, buff, sizeof(buff));
+ if(len > 0) {
+ printf("RSP : %s\n", buff);
+ if(cmd == GNSS_CMD_INIT) {
+ if(memcmp(buff, "gnss_init", 9) == 0) {
+ return atoi(buff + 10);
+ } else {
+ printf("gnss_init response error.\n");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DEINIT) {
+ if(memcmp(buff, "gnss_deinit", 11) == 0) {
+ return atoi(buff + 12);
+ } else {
+ printf("gnss_deinit response error.\n");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_SETTING) {
+ if(memcmp(buff, "gnss_setting", 12) == 0) {
+ return atoi(buff + 13);
+ } else {
+ printf("gnss_setting response error.\n");
+ return -1;
+ }
+ } else if(cmd == GNSS_CMD_DL) {
+ if(memcmp(buff, "gnss_dl", 7) == 0) {
+ return atoi(buff + 8);
+ } else {
+ printf("gnss_dl response error.\n");
+ return -1;
+ }
+ } else {
+ printf("Unknown response.\n");
+ return -1;
+ }
+ } else if(len == 0) {
+ printf("RSP is null.\n");
+ return -1;
+ } else {
+ printf("read = %d:errno = %d\n", len, errno);
+ }
+ }
+}
+
+/**********************************FUNC***********************************/
+
+/**********************************API***********************************/
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_init(void)
+{
+ int ret = MBTK_RESULT_FAIL;
+
+ ret = mbtk_gnss_ubus_uloop_init();
+ if(ret < 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_uloopinit fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+#ifndef MBTK_SG_SUPPORT
+ ret = mbtk_gnss_nmea_thread_init();
+ if(ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_nmea_thread_init fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+#endif
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_deinit(void)
+{
+ mbtk_gnss_nmea_thread_deinit();
+ mbtk_gnss_ubus_uloop_deinit();
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_open(void)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+ MBTK_GNSS_5311_RESULT_TYPE ubus_gnss_result = MBTK_GNSS_RESULT_SUCCESS;
+ uint gps_init_val = MBTK_GNSS_OPEN;
+
+
+ ret = mbtk_GPS_process(GNSS_CMD_INIT, &gps_init_val);
+
+ if (-1 == ret)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_open fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+
+ mbtk_gnss_status = MBTK_GNSS_OPEN;
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_close(void)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+
+ ret = mbtk_GPS_process(GNSS_CMD_DEINIT, NULL);
+
+ if (-1 == ret)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_close fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ mbtk_gnss_status = MBTK_GNSS_CLOSE;
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_sleep(void)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+ struct blob_buf outBlob;
+ unsigned int gps_sleep_val = MBTK_GNSS_SLEEP;
+ memset(&outBlob, 0, sizeof(outBlob));
+
+ blob_buf_init(&outBlob, 0);
+ blobmsg_add_u32(&outBlob, MBTK_GNSS_UBUS_SLEEP_PARAM, (unsigned int)gps_sleep_val);
+
+ ret = mbtk_invoke_noreply(MBTK_GNSS_UBUS_SERVER, MBTK_GNSS_UBUS_SLEEP, outBlob.head);
+ blob_buf_free(&outBlob);
+ if (ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_invoke_noreply fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_wakeup(void)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+ struct blob_buf outBlob;
+ unsigned int gps_sleep_val = MBTK_GNSS_WAKEUP;
+ memset(&outBlob, 0, sizeof(outBlob));
+
+ blob_buf_init(&outBlob, 0);
+ blobmsg_add_u32(&outBlob, MBTK_GNSS_UBUS_SLEEP_PARAM, (unsigned int)gps_sleep_val);
+
+ ret = mbtk_invoke_noreply(MBTK_GNSS_UBUS_SERVER, MBTK_GNSS_UBUS_SLEEP, outBlob.head);
+ blob_buf_free(&outBlob);
+ if (ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_invoke_noreply fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_param_config(const char *param_buf, int param_buf_len)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(param_buf == NULL || param_buf_len <= 0)
+ {
+ LOGE("[mbtk_gnss_api] param is error.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+ LOGE("[mbtk_gnss_api] set command [%s].", param_buf);
+
+ ret = mbtk_GPS_process(GNSS_CMD_SETTING, param_buf);
+ if (-1 == ret)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_gnss_setting fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_get_status(const char *status_buf, int status_buf_len, int *get_status_len)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ int ret = -1;
+ char status[128] = {0};
+ int status_len = 0;
+
+ ret = mbtk_invoke_reply_data_cb(MBTK_GNSS_UBUS_SERVER, MBTK_GNSS_UBUS_GET_STATUS, NULL, mbtk_gnss_state_get_callback, status, 4000);
+ if (ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_invoke_reply_data_cb fail.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ status_len = strlen(status);
+ if(status_len > 0 && status_len < status_buf_len)
+ {
+ memcpy(status_buf, status, status_len);
+ *get_status_len = status_len;
+ }
+ else
+ {
+ LOGE("[mbtk_gnss_api] status_len[%d] error.", status_len);
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_set_nmea_out_type(MBTK_GNSS_MSG_INFO_TYPE type)
+{
+ if(mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(type == MBTK_GNSS_MSG_LOCATION_INFO)
+ {
+ nmea_state.gnss_msg_state = type;
+ }
+ else if(type == MBTK_GNSS_MSG_NMEA_INFO)
+ {
+ nmea_state.gnss_msg_state = type;
+ }
+ else
+ {
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_add_nmea_out_func(mbtk_gnss_nmea_func_t cb)
+{
+ if(mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+
+ if(cb == NULL)
+ {
+ LOGE("[mbtk_gnss_api] cb is NULL.");
+ return MBTK_GNSS_RESULT_FAIL;
+ }
+ nmea_state.callbacks = cb;
+
+ return MBTK_GNSS_RESULT_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_5311_download_tle(char *host, int alam_flag)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_DOWNLOAD_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_DOWNLOAD_FAIL;
+ }
+
+ int ret = -1;
+ MBTK_GNSS_5311_RESULT_TYPE ubus_gnss_result = MBTK_GNSS_RESULT_DOWNLOAD_SUCCESS;
+ struct blob_buf outBlob;
+ memset(&outBlob, 0, sizeof(outBlob));
+
+ blob_buf_init(&outBlob, 0);
+ blobmsg_add_string(&outBlob, MBTK_GNSS_UBUS_AGPS_SERVER, host);
+ blobmsg_add_u32(&outBlob, MBTK_GNSS_UBUS_ALAM_FLAG, alam_flag);
+
+ //UBUS_STATUS_OK
+ ret = mbtk_invoke_reply_data_cb(MBTK_GNSS_UBUS_SERVER, MBTK_GNSS_UBUS_GET_AGPS, outBlob.head,
+ (ubus_data_handler_t *)mbtk_gnss_ubus_result_callback, &ubus_gnss_result, 8000);
+ blob_buf_free(&outBlob);
+ if (ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_invoke_reply_data_cb fail.");
+ return MBTK_GNSS_RESULT_DOWNLOAD_FAIL;
+ }
+
+ if(ubus_gnss_result != MBTK_GNSS_RESULT_DOWNLOAD_SUCCESS)
+ {
+ LOGE("[mbtk_gnss_api] ubus_gnss_result = [%d].", ubus_gnss_result);
+ return MBTK_GNSS_RESULT_DOWNLOAD_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_DOWNLOAD_SUCCESS;
+}
+
+MBTK_GNSS_5311_RESULT_TYPE mbtk_gnss_injectEphemeris(void)
+{
+ if (mbtk_gnss_uloop_init == 0)
+ {
+ LOGE("[mbtk_gnss_api] gnss not init.");
+ return MBTK_GNSS_RESULT_SEND_FAIL;
+ }
+
+ if(mbtk_gnss_status == MBTK_GNSS_CLOSE)
+ {
+ LOGE("[mbtk_gnss_api] gnss not open.");
+ return MBTK_GNSS_RESULT_SEND_FAIL;
+ }
+
+ int ret = -1;
+ MBTK_GNSS_5311_RESULT_TYPE ubus_gnss_result = MBTK_GNSS_RESULT_SUCCESS;
+
+ //UBUS_STATUS_OK
+ ret = mbtk_invoke_reply_data_cb(MBTK_GNSS_UBUS_SERVER, MBTK_GNSS_UBUS_SET_AGPS, NULL,
+ (ubus_data_handler_t *)mbtk_gnss_ubus_result_callback, &ubus_gnss_result, 8000);
+ if (ret != 0)
+ {
+ LOGE("[mbtk_gnss_api] mbtk_invoke_reply_data_cb fail.");
+ return MBTK_GNSS_RESULT_SEND_FAIL;
+ }
+
+ if(ubus_gnss_result != MBTK_GNSS_RESULT_SEND_SUCCESS)
+ {
+ LOGE("[mbtk_gnss_api] ubus_gnss_result = [%d].", ubus_gnss_result);
+ return MBTK_GNSS_RESULT_SEND_FAIL;
+ }
+
+ return MBTK_GNSS_RESULT_SEND_SUCCESS;
+}
+
+/**********************************API***********************************/
+
+#endif
diff --git a/mbtk/libmbtk_lib/gnss/mbtk_gnss_6228.c b/mbtk/libmbtk_lib/gnss/mbtk_gnss_6228.c
new file mode 100755
index 0000000..ab53662
--- /dev/null
+++ b/mbtk/libmbtk_lib/gnss/mbtk_gnss_6228.c
@@ -0,0 +1,2214 @@
+/**
+ * \file mbtk_gnss.c
+ * \brief gnss module.
+ *
+ * Detailed description
+ * \Author: Sniper <js.wang@mobiletek.cn>
+ * \Version: 1.0.0
+ * \Date: 2022-03-16
+ */
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/ioctl.h>
+#include "mbtk_type.h"
+#include "mbtk_gnss_6228.h"
+#include "mbtk_http.h"
+#include "mbtk_log.h"
+#include "ringbuffer.h"
+
+// #define DEBUG 1
+
+#ifdef DEBUG
+ #define gnss_log(...) printf(__VA_ARGS__)
+#else
+ #define gnss_log(...)
+#endif
+
+// 默认为 9600,打开为 115200,但是 AT+MGPSCMD 会重启。
+#define BAUDRATE_115200 1
+
+#define TTFF_TEST 0
+
+#define MBTK_GNSS_DEV "/dev/ttyS2"
+
+#define MBTK_UART_RECV_BUFFER_SIZE 1024
+#define MBTK_UART_SEND_BUFFER_MAX 128
+
+/******************************************************************************
+ * 时间处理相关的宏
+ *****************************************************************************/
+// 获取当前时间
+#define GET_TIME() { gettimeofday(&time_m, NULL); \
+ time_m.tv_sec += TIMEOUT_SEC;\
+}
+// 设置从循环中退出的时间
+#define SET_TIME_OUT(x) { gettimeofday(&time_m, NULL); \
+ time_m.tv_sec += x;\
+}
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ printf("\ntimeout!!!\n\n");\
+ close(fd); \
+ return ret; \
+ } \
+}
+// 检测时间是否超时,超时则退出当前循环
+#define CHK_TIME_BREAK() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ printf("\ntimeout!!!\n\n");\
+ break; \
+ } \
+}
+// 检测延时是否到达,到达则退出当前循环
+#define DELAY_TIME_BREAK() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ break; \
+ } \
+}
+
+typedef void (*gnss_msg_func_t)
+(
+ int index,
+ char *in_data,
+ void *out_ptr
+);
+
+struct mbtk_gnss_cmd_msg_t
+{
+ int index; // 序号
+ char *cmd_str; // 匹配字符
+ gnss_msg_func_t gnss_msg_func; // 回调函数
+ int is_continue; // 是否随NEMA数据一起输出
+};
+
+typedef enum
+{
+ E_MT_LOC_MSG_ID_STATUS_INFO = 0, /**< pv_data = &E_QL_LOC_STATUS_VALUE_T */
+ E_MT_LOC_MSG_ID_LOCATION_INFO, /**< pv_data = &QL_LOC_LOCATION_INFO_T */
+ E_MT_LOC_MSG_ID_SV_INFO, /**< pv_data = &QL_LOC_SV_STATUS_T */
+ E_MT_LOC_MSG_ID_NMEA_INFO, /**< pv_data = &QL_LOC_NMEA_INFO_T */
+ E_MT_LOC_MSG_ID_CAPABILITIES_INFO, /**< pv_data = &E_QL_LOC_CAPABILITIES_T */
+ E_MT_LOC_MSG_ID_AGPS_STATUS, /**< pv_data = &QL_LOC_AGPS_STATUS_T */
+ E_MT_LOC_MSG_ID_NI_NOTIFICATION, /**< pv_data = &QL_LOC_NI_NOTIFICATION_INTO_T */
+ E_MT_LOC_MSG_ID_XTRA_REPORT_SERVER, /**< pv_data = &QL_LOC_XTRA_REPORT_SERVER_INTO_T */
+}e_mt_loc_msg_id_t;
+
+typedef struct
+{
+ int64_t timestamp; /**< System Timestamp, marked for when got the nmea data */
+ int length; /**< NMEA string length. */
+ char nmea[255 + 1]; /**< NMEA string.*/
+}mopen_gnss_nmea_info_t; /* Message */
+
+struct mbtk_gnss_handle_t
+{
+ int dev_fd;
+ pthread_t uart_pthread;
+ pthread_t gnss_pthread;
+ mbtk_gnss_handler_func_t gnss_handler_func;
+ int mode; // 0 - stop, 1 - single, 2 - periodic, 3 - start
+ pthread_mutex_t _cond_mutex;
+ int reset_state;
+ int inited;
+ ring_buffer_t ring_buffer;
+ int getap_status;
+ char *rb;
+
+#if TTFF_TEST
+ pthread_t ttff_pid;
+ int location_state;
+#endif
+ /********************
+ 存储handle的地址指针
+ phandle = &handle
+ handle = mbtk_gnss_handle
+ *********************/
+ uint32 *phandle; // handle的地址指针
+};
+
+#if TTFF_TEST
+struct mbtk_gnss_ttff_t
+{
+ int type;
+ int timeout_sec;
+ int test_count;
+ int average_loc_time;
+};
+
+// ttff 测试 flag
+static int location_test = 0;
+static pthread_mutex_t loc_cond_mutex_r = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t loc_sync_cond = PTHREAD_COND_INITIALIZER;
+#endif
+
+struct mopen_gnss_device_info_t
+{
+ int device_info_valid;
+ int usrt_bandrate;
+ char product_name[10];
+ char dev_config[6];
+ char hw_ver[6];
+ char fw_ver[32];
+ char pn[16];
+ char sn[16];
+ char nmea_ver[4];
+};
+
+static struct mopen_gnss_device_info_t mopen_gnss_device_info;
+static struct mbtk_gnss_handle_t *mbtk_gnss_handle = NULL;
+static int firmware_extren_state = 0;
+
+static char g_no_sv = 0;// 参与定位的卫星数量
+
+int mopen_gnss_get_nmea_config(uint32 h_gnss);
+int mopen_gnss_get_ant_state_info(uint32 h_gnss);
+
+static void get_gnss_time_info(int cmd, char *str, void *data);
+static void get_gnss_agnss_state(int cmd, char *str, void *data);
+static void get_gnss_device_info(int type, char *str, void *usr_ptr);
+static void gnss_uart_info(int cmd, char *str, void *data);
+static void gnss_gsa_info(int cmd, char *str, void *data);
+static int mopen_uart_change(int fd, int check);
+
+static int select_read( int fd, int timeout );
+ssize_t deal_read(int fd, void *buf, size_t count);
+
+static struct mbtk_gnss_cmd_msg_t mbtk_gnss_cmd_msg_map[] = {
+{ 1, "$OK", NULL, 0},
+{ 2, "$Fail", NULL, 0},
+{ 3, "RMC", get_gnss_time_info, 1},
+{ 4, "GGA", get_gnss_time_info, 1},
+{ 5, "$PDTINFO", get_gnss_device_info, 0},
+{ 6, "$CFGNMEA", get_gnss_device_info, 0},
+{ 7, "$CFGPRT", gnss_uart_info, 0},
+{ 8, "$CFGAID", get_gnss_agnss_state, 0},
+{ 9, "$ANTSTAT", NULL, 0},
+#if TTFF_TEST
+{10, "GSA", gnss_gsa_info, 1},
+#endif
+};
+
+/**
+ * \brief strstr_n
+ *
+ * find string return number
+ *
+ * \param param
+ * \return return type
+ */
+int strstr_n(const char *s1, const char *s2)
+{
+ int n;
+ int strlen = 0;
+
+ if(*s2)
+ {
+ while(*s1)
+ {
+ for(n = 0; *(s1+n) == *(s2 + n); n++)
+ {
+ if(!*(s2 + n + 1))
+ {
+ strlen++;
+ return strlen;
+ }
+ }
+ s1++;
+ strlen++;
+ }
+ return 0;
+ }
+ else
+ return 0;
+}
+
+/**
+ * @brief gnss_get_para_from_nmea
+ *
+ * @details 从buf里面得到第num个逗号所在的位置
+ *
+ * @param param
+ *
+ * @return 0~0xfe,代表逗号所在位置的偏移.
+ * 0xff,代表不存在第cx个逗号
+ */
+static int gnss_get_para_from_nmea(const char *data, char *out_data, int num)
+{
+ int i = 0;
+ int n[2] = {0};
+ int tmp;
+
+ // 找到第num个",",结果放到 n[0]
+ for (i = 0; i < num; ++i) {
+ tmp = strstr_n(&data[n[0]], ",");
+ if(0 == tmp) {
+ gnss_log("%s %d : error\n", __func__, __LINE__);
+ gnss_log("error: [%d] %s\n", num, data);
+ return -1;
+ }
+ n[0] += tmp;
+ }
+ if ((n[1] = strstr_n(&data[n[0]], ",")) ||
+ (n[1] = strstr_n(&data[n[0]], "*")) &&
+ (n[1] > 1)) {
+ memcpy(out_data, &data[n[0]], n[1] - 1);
+ } else {
+ gnss_log("%s %d : error [%d]\n" , __func__, __LINE__, n[1]);
+ gnss_log("error: [%d] %s\n", num, data);
+ return -1;
+ }
+
+ return 0;
+}
+/**
+* @brief get_timestamp
+*
+* @details
+*
+* @param param
+*
+* @return return type
+*/
+static time_t get_timestamp(char *time)
+{
+ char tmp_char[4] = {0};
+ struct tm* tmp_time = (struct tm*)malloc(sizeof(struct tm));
+
+ memset(tmp_time, 0, sizeof(struct tm));
+ memset(tmp_char, 0, sizeof(tmp_char));
+ memcpy(tmp_char, &time[4], 2);
+ tmp_time->tm_sec = atoi(tmp_char);
+ memcpy(tmp_char, &time[2], 2);
+ tmp_time->tm_min = atoi(tmp_char);
+ memcpy(tmp_char, &time[0], 2);
+ tmp_time->tm_hour = atoi(tmp_char);
+ memcpy(tmp_char, &time[6], 2);
+ tmp_time->tm_mday = atoi(tmp_char);
+ memcpy(tmp_char, &time[8], 2);
+ tmp_time->tm_mon = atoi(tmp_char);
+ memcpy(tmp_char, &time[10], 2);
+ tmp_time->tm_year = 100 + atoi(tmp_char);
+
+ time_t _t = mktime(tmp_time);//按当地时区解析tmp_time
+ // gnss_log("timestamp: %ld\n",_t);
+ free(tmp_time);
+
+ return _t;
+}
+/**
+ * @brief get_gnss_device_info
+ *
+ * @details 获取设备信息
+ *
+ * @param type: 5-从$PDTINFO获取
+ * 6-从$CFGNMEA获取
+ *
+ * @return return type
+ */
+static void get_gnss_device_info(int type, char *str, void *usr_ptr)
+{
+ char tmp_str[32] = {0};
+ int i, ret;
+
+ if(5 == type) // define mbtk_gnss_cmd_msg_map
+ {
+ // $PDTINFO get product info
+ char *tmp_ptr[6] = {mopen_gnss_device_info.product_name,
+ mopen_gnss_device_info.dev_config,
+ mopen_gnss_device_info.hw_ver,
+ mopen_gnss_device_info.fw_ver,
+ mopen_gnss_device_info.pn,
+ mopen_gnss_device_info.sn
+ };
+ for (i = 0; i < 6; ++i) {
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, i + 1);
+ if(ret)
+ continue;
+ memcpy(tmp_ptr[i], tmp_str, strlen(tmp_str));
+ }
+ gnss_log("*************************\n");
+ gnss_log("-Pn: %s\n dc: %s\n hv: %s\n fw: %s\n pn: %s\n sn: %s\n ",
+ mopen_gnss_device_info.product_name,
+ mopen_gnss_device_info.dev_config,
+ mopen_gnss_device_info.hw_ver,
+ mopen_gnss_device_info.fw_ver,
+ mopen_gnss_device_info.pn,
+ mopen_gnss_device_info.sn);
+ }
+ if(6 == type) // define mbtk_gnss_cmd_msg_map
+ {
+ // $CFGNMEA get nmea version
+ memset(tmp_str, 0, sizeof(tmp_str));
+ ret = gnss_get_para_from_nmea(str, tmp_str, 1);
+ if(ret)
+ return;
+ memcpy(mopen_gnss_device_info.nmea_ver, tmp_str, strlen(tmp_str));
+ mopen_gnss_device_info.device_info_valid = TRUE;
+ }
+}
+
+static short int from_hex(char a)
+{
+ if (a >= 'A' && a <= 'F')
+ return a - 'A' + 10;
+ else if (a >= 'a' && a <= 'f')
+ return a - 'a' + 10;
+ else
+ return a - '0';
+}
+
+static int str_to_hex(char *str)
+{
+ unsigned char str_len = strlen(str);
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < str_len; ++i) {
+ ret = ret * 16 + from_hex(str[i]);
+ }
+ return ret;
+}
+
+static void get_gnss_agnss_state(int cmd, char *str, void *data)
+{
+ int ret;
+ char tmp_str[10] = {0};
+ int agps;
+ static int count = 0;
+
+ ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+ if(ret) {
+ printf("\n%s[%d] error!\n" , __FUNCTION__, __LINE__);
+ }
+ agps = str_to_hex(tmp_str);
+ gnss_log("\n%s[%d] agnss: %s[%x]\n" , __FUNCTION__, __LINE__, tmp_str, agps);
+ if(0 == agps && count < 5) {
+ mopen_gnss_get_aidinfo(mbtk_gnss_handle);
+ count++;
+ } else {
+ printf("\nagnss: %s\n", str);
+ count = 0;
+ }
+ // $CFGAID,0,00000000,00000000,00*3E
+}
+// 1节=1海里/小时=1.852公里/小时
+/**
+ * @brief function description
+ *
+ * @details 获取位置信息
+ *
+ * @param type: 1-从$RMC获取
+ * 2-从$GGA获取
+ * @return return type
+ */
+static void get_gnss_loc_info(int type, char *str,
+ struct mbtk_gnss_location_info_t *_mopen_location_info)
+
+{
+ char tmp_str[32] = {0};
+ int ret;
+
+ if(1 == type)
+ {
+ // $PDTINFO get product info
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, 7);
+ if(ret)
+ return;
+ _mopen_location_info->speed = atof(tmp_str);
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, 8);
+ if(ret)
+ return;
+ _mopen_location_info->bearing = atof(tmp_str);
+ }
+ else if(2 == type)
+ {
+ // $XXGGA get product info
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+ if(ret)
+ return;
+ _mopen_location_info->latitude = atof(tmp_str);
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, 4);
+ if(ret)
+ return;
+ _mopen_location_info->longitude = atof(tmp_str);
+ memset(tmp_str, 0, sizeof(tmp_str));
+ // get product name
+ ret = gnss_get_para_from_nmea(str, tmp_str, 9);
+ if(ret)
+ return;
+ _mopen_location_info->altitude = atof(tmp_str);
+ }
+}
+
+static void get_gnss_time_info(int cmd, char *str, void *data)
+{
+ int ret;
+ char param[36] = {0};
+ struct mbtk_gnss_location_info_t *mopen_location_info_ptr = (struct mbtk_gnss_location_info_t *)data;
+
+ if (3 == cmd) {
+ memset(param, 0, sizeof(param));
+ // get time
+ ret = gnss_get_para_from_nmea(str, param, 1);
+ if(ret)
+ return;
+ // get date
+ ret = gnss_get_para_from_nmea(str, ¶m[6], 9);
+ if(ret)
+ return;
+
+ mopen_location_info_ptr->timestamp = get_timestamp(param);
+ get_gnss_loc_info(1, str, mopen_location_info_ptr);
+ } else if(4 == cmd) /* GGA */{
+ get_gnss_loc_info(2, str, mopen_location_info_ptr);
+ ret = gnss_get_para_from_nmea(str, param, 7);
+ if(ret)
+ return;
+ char no_sv = (char)atoi(param);
+ gnss_log("SV number: %d, %d\n", g_no_sv, no_sv);
+ /*
+ 只能在临时固件下,才能获取APdata星历数据
+ 在6颗卫星保存文件,每增加2颗保存一次。
+ */
+ if (1 == firmware_extren_state &&
+ g_no_sv < (no_sv - 1) && no_sv > 5) {
+
+ g_no_sv = no_sv;
+ mbtk_gnss_get_ap_data();
+ }
+ }
+}
+
+static void gnss_uart_info(int cmd, char *str, void *data)
+{
+ int ret;
+ char tmp_str[12] = {0};
+
+ // $CFGPRT,1,h0,9600,129,3*57
+ ret = gnss_get_para_from_nmea(str, tmp_str, 3);
+ if(ret)
+ return;
+ mopen_gnss_device_info.usrt_bandrate = atoi(tmp_str);
+ gnss_log("CFGPRT: %s\n", str);
+ gnss_log("Uart bandrate: %d\n" , mopen_gnss_device_info.usrt_bandrate);
+ gnss_log("*************************\n");
+}
+/**
+ * \brief function description
+ *
+ * Detailed 处理gnss数据
+ *
+ * \param param
+ * \return return type
+ */
+static void process_gnss_callback(struct mbtk_gnss_handle_t *handle,
+ const char *data, int data_len)
+{
+ int ret = 0;
+ int i = 0;
+ static struct mbtk_gnss_location_info_t mopen_location_info;
+ static int64_t tmp_time = 0;
+ mopen_gnss_nmea_info_t nmea_info;
+
+ memset(&nmea_info, 0, sizeof(nmea_info));
+ if(0 == tmp_time)
+ memset(&mopen_location_info, 0, sizeof(mopen_location_info));
+
+ for (i = 0;
+ i < (sizeof(mbtk_gnss_cmd_msg_map) / sizeof(struct mbtk_gnss_cmd_msg_t));
+ ++i) {
+ if(strstr_n(data, mbtk_gnss_cmd_msg_map[i].cmd_str)) {
+ if(mbtk_gnss_cmd_msg_map[i].gnss_msg_func)
+ mbtk_gnss_cmd_msg_map[i].gnss_msg_func(mbtk_gnss_cmd_msg_map[i].index,
+ data, &mopen_location_info);
+ break;
+ }
+ }
+ if(0 == mbtk_gnss_cmd_msg_map[i].is_continue)
+ return;
+
+ tmp_time = mopen_location_info.timestamp;
+ nmea_info.timestamp = mopen_location_info.timestamp;
+ nmea_info.length = data_len;
+ memcpy(nmea_info.nmea, data, data_len);
+ gnss_log("nmea:[%d] %s", data_len, data);
+ if(handle->gnss_handler_func && handle->mode == 3 &&
+ nmea_info.timestamp)
+ handle->gnss_handler_func(handle, E_MT_LOC_MSG_ID_NMEA_INFO, &nmea_info, NULL);
+ if(handle->gnss_handler_func && handle->mode == 1 &&
+ mopen_location_info.latitude &&
+ mopen_location_info.longitude &&
+ mopen_location_info.altitude &&
+ mopen_location_info.timestamp &&
+ mopen_location_info.speed)
+ {
+ handle->gnss_handler_func(handle, E_MT_LOC_MSG_ID_LOCATION_INFO, &mopen_location_info, NULL);
+ memset(&mopen_location_info, 0, sizeof(mopen_location_info));
+ }
+
+ return;
+}
+
+/**
+ * \brief get_gnss_from_str
+ *
+ * Detailed 从串口数据解析出每条消息
+ *
+ * \param param
+ * \return return type
+ */
+static int get_gnss_from_str(struct mbtk_gnss_handle_t *handle,
+ const char *data, int data_len)
+{
+ char *tail = NULL;
+ static int seek = 0;
+ // 等待 OK, 如果20条结果没有等到,就异常
+ static int reset_count = 0;
+ int i = 0, ret = -1;
+
+ if (handle->reset_state)
+ {
+ // 等待 reset 回复的 OK
+ if(0 != memcmp(data, "$OK", 3) && reset_count < 20) {
+ printf("gnss reset invalid: [%s]\n", data);
+ reset_count++;
+ return -1;
+ }
+ if (reset_count > 19) {
+ printf("%s: device reset timeout!!!\n", __FUNCTION__);
+ LOGI("%s: device reset timeout!!!\n", __FUNCTION__);
+ }
+ reset_count = 0;
+ gnss_log("reset ok: %s\n", data);
+#if BAUDRATE_115200
+ ret = mopen_uart_change(handle->dev_fd, 0);
+ if(ret) {
+ printf("reset Uart set 115200 error\n");
+ }
+#endif
+ pthread_mutex_lock(&handle->_cond_mutex);
+ handle->reset_state = 0;
+ pthread_mutex_unlock(&handle->_cond_mutex);
+ }
+
+ if((data[0] == '$' || data[0] == '#') &&
+ data[data_len - 1] == '\n' &&
+ data_len < 128) {
+ process_gnss_callback(handle, data, data_len);
+ } else {
+ gnss_log("nmea error: %s\n", data);
+ }
+
+ return 1;
+}
+
+void mopen_gnss_NonBlock(int fd, int cmd)
+{
+ int flags;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ if(cmd)
+ flags |= O_NONBLOCK;
+ else
+ flags &= ~O_NONBLOCK;
+
+ fcntl(fd, F_SETFL, flags);
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+ struct termios options, oldtio;
+
+ if(fcntl(fd, F_SETFL, 0) < 0) {
+ printf("fcntl failed!\n");
+ return -1;
+ }
+
+ if(tcgetattr(fd, &oldtio) != 0) {
+ printf("setup serial error!\n");
+ return -1;
+ }
+
+ /* Get the current options for the port... */
+ tcgetattr(fd, &options);
+
+ /* Set the baud rates to baudrate... */
+ cfsetispeed(&options,baudrate);
+ cfsetospeed(&options,baudrate);
+ tcsetattr(fd, TCSANOW, &options);
+
+ if (0 != tcgetattr(fd, &options))
+ {
+ printf("get options error!\n");
+ return -1;
+ }
+
+ /*
+ * 8bit Data,no partity,1 stop bit...
+ */
+ options.c_cflag &= ~PARENB;//无奇偶校验
+ options.c_cflag &= ~CSTOPB;//停止位,1位
+ options.c_cflag &= ~CSIZE; //数据位的位掩码
+ options.c_cflag |= CS8; //数据位,8位
+
+ cfmakeraw(&options);
+
+ /*
+ * Set the new options for the port...
+ */
+ if (tcsetattr(fd, TCSANOW, &options) != 0)
+ {
+ printf("setup serial error!\n");
+ return -1 ;
+ }
+
+ return 0 ;
+}
+/*
+ 自适应波特率设置
+ */
+static int auto_set_uart_baudrate(int fd)
+{
+ char rbuf[512];
+ int rByte = 0;
+ int b[3] = {B115200, B9600, 0};
+ int ret = B9600;
+ struct timeval time_m, time_n;
+ // 时间超时标志
+ int timeout_sign = 0;
+ // 先测试默认的9600波特率
+ SET_TIME_OUT(3);
+ do {
+ gettimeofday(&time_n, NULL);
+ if(time_n.tv_sec > time_m.tv_sec) {
+ printf("Baudrate--test-9600--- timeout!\n");
+ if(timeout_sign)
+ break;
+ set_baudrate(fd, B115200);
+ ret = B115200;
+ timeout_sign = 1;
+ SET_TIME_OUT(3);
+ continue;
+ }
+
+ if(select_read(fd, 1) > 0)
+ usleep(50000);
+ else
+ continue;
+
+ rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+ if(rByte > 0) {
+ gnss_log("Auto Baudrate[%d]%s\n", rByte, rbuf);
+ if(strstr(rbuf, "$"))
+ return ret;
+ memset(rbuf, 0, sizeof(rbuf));
+ } else {
+ printf("*** read error\n");
+ }
+ }while(1);
+
+ return -1;
+}
+
+int mopen_gnss_open(char *dev, int baudrate)
+{
+ int ret;
+ int fd = 0;
+
+ fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY);
+ if(fd < 0) {
+ return -1;
+ }
+ gnss_log("curent dev: %s, fd: %d \n", dev, fd);
+
+ if(baudrate) {
+ gnss_log("set baudrate: %d \n", baudrate);
+ ret = set_baudrate(fd, baudrate);
+ if(-1 == ret) {
+ close(fd);
+ return -1;
+ }
+ } else {
+ set_baudrate(fd, B9600);
+ }
+
+ return fd;
+}
+
+static int mopen_gnss_read(int fd, char* buf, unsigned int buf_len)
+{
+ buf_len=(buf_len > MBTK_UART_RECV_BUFFER_SIZE ? MBTK_UART_RECV_BUFFER_SIZE : buf_len);
+ return read(fd, buf, buf_len);
+}
+
+int mopen_gnss_write(int fd, const char* buf, unsigned int buf_len)
+{
+ size_t size;
+ size_t size_to_wr;
+ ssize_t size_written;
+ if(MBTK_UART_SEND_BUFFER_MAX < buf_len)
+ {
+ return -1;
+ }
+ for(size = 0; size < buf_len;)
+ {
+ size_to_wr = buf_len - size;
+ if( size_to_wr > MBTK_UART_SEND_BUFFER_MAX)
+ size_to_wr = MBTK_UART_SEND_BUFFER_MAX;
+
+ size_written = write(fd, &buf[size], size_to_wr);
+ if (size_written==-1)
+ {
+ return -1;
+ }
+ gnss_log("send cmd: %s", &buf[size]);
+ size += size_written;
+ if(size_written != size_to_wr)
+ {
+ return size;
+ }
+ }
+ return size;
+}
+
+int mopen_gnss_close(int fd)
+{
+ return close(fd);
+}
+
+static void gnss_info_pthread(void* hdl)
+{
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)hdl;
+ int ret = 0, i;
+ char tmp;
+ char tmp_arr[128] = {0};
+
+ pthread_detach(pthread_self());
+
+ memset(tmp_arr, 0, sizeof(tmp_arr));
+ while(mbtk_gnss_handle->inited)
+ {
+ for (i = 0; i < 256; ++i) {
+ if (0 == mbtk_gnss_handle->inited)
+ goto exit;
+ ret = ring_buffer_peek(&gnss_handle->ring_buffer, &tmp, i);
+ if (0 == ret) {
+ usleep(300000);
+ gnss_log("ring_buffer_peek ringbuffer read error\n");
+ i--;
+ continue;
+ }
+ if (tmp == '\n') {
+ break;
+ }
+ }
+
+ if (i > (256 - 2))
+ continue;
+
+ ret = ring_buffer_dequeue_arr(&gnss_handle->ring_buffer, tmp_arr, i + 1);
+
+ if(ret > 0 && 0 == mbtk_gnss_handle->getap_status) {
+ // gnss_log("NEMA:[%d] %s", ret, tmp_arr);
+ get_gnss_from_str(gnss_handle, tmp_arr, ret);
+ memset(tmp_arr, 0, sizeof(tmp_arr));
+ } else {
+ gnss_log("ringbuffer read error\n");
+ }
+ usleep(5000);
+ }
+ exit:
+ pthread_exit(NULL);
+}
+
+static void gnss_uart_pthread(void* hdl)
+{
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)hdl;
+ int ret = 0;
+ char buf[MBTK_UART_RECV_BUFFER_SIZE] = {0};
+
+ pthread_detach(pthread_self());
+
+ memset(buf, 0, sizeof(buf));
+ while(mbtk_gnss_handle->inited)
+ {
+ while(mbtk_gnss_handle->getap_status){
+ // 在读AP_DATA星历时,不能输出NMEA
+ printf("g");
+ usleep(100000);
+ }
+ ret = mopen_gnss_read(gnss_handle->dev_fd, buf, MBTK_UART_RECV_BUFFER_SIZE);
+ if(ret > 0) {
+ // gnss_log("read: [%d] %s\n", ret, buf);
+ ring_buffer_queue_arr(&gnss_handle->ring_buffer, buf, ret);
+ memset(buf, 0, sizeof(buf));
+ } else {
+ gnss_log("read error\n");
+ }
+ usleep(100000);
+ }
+
+ pthread_exit(NULL);
+}
+
+ssize_t deal_read(int fd, void *buf, size_t count)
+{
+ int ret = 0;
+
+#if 0
+ ret = read(fd, buf, count);
+ return ret;
+#else
+ while (1)
+ {
+ ret = read(fd, buf, count);
+ if (ret == 0) {
+ printf("read serial return 0, please check serial device.\n");
+ exit(-5);
+ }
+ if(ret < 0) {
+ if ((errno == EAGAIN) || (errno == EINTR)) {
+ printf("read serial return -1, errno = %d, retry.\n", errno);
+ continue;
+ } else {
+ printf("read serial return -1, errno = %d, please check serial device.\n", errno);
+ exit(-5);
+ }
+ }
+ return ret;
+ }
+#endif
+}
+
+static int select_read( int fd, int timeout ) //1ms
+{
+ fd_set set;
+ struct timeval t;
+ int ret;
+ int i = timeout;
+
+ do {
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ t.tv_sec = 0;
+ t.tv_usec = 100;
+
+ ret = select(FD_SETSIZE, &set, NULL, NULL, &t );
+ if(ret == 0) continue;
+ if(ret < 0 && errno == EINTR)continue;
+ else return ret;
+ } while(i--);
+
+ return ret;
+}
+
+// check: 是否需要校验
+static int mopen_uart_change(int fd, int check)
+{
+ int rByte = 0, i = 20;
+ char name[32];
+ char rbuf[1024];
+
+ sprintf(name,"$CFGPRT,1,h0,115200,129,3\r\n");
+ rByte = write( fd, name, strlen(name));
+ tcdrain(fd);
+
+ set_baudrate(fd, B115200);
+ usleep(200000);
+ tcflush(fd, TCIFLUSH);
+
+ if (0 == check)
+ return 0;
+ do{
+ rByte = 0;
+ memset(rbuf, 0, sizeof(rbuf));
+ if(select_read(fd, 1) > 0) {
+ rByte = deal_read(fd, &rbuf, sizeof(rbuf) - 1);
+ rbuf[rByte] = 0;
+ gnss_log("%s: %s", __FUNCTION__, rbuf);
+ }
+ if(strstr(rbuf, "$")) {
+ return 0;
+ } else {
+ gnss_log("%d rByte = %d, [%s]\n", 20 - i, rByte, rbuf);
+ }
+ usleep(5000 * 100);
+ }while(i--);
+
+ return -1;
+}
+
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int mopen_open_gps(int state)
+{
+ int fd, ret;
+ char s[4] = "on";
+ fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+ if(fd < 0) {
+ LOGE("[%s] file [%s] open error\n", __FUNCTION__, GPS_DEV);
+ return -1;
+ }
+ if(0 == state)
+ {
+ memcpy(s, "off", 3);
+ }
+ ret = write(fd, s, 4);
+ if (ret < 0) {
+ LOGE("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int mbtk_gnss_client_init(uint32 *ph_gnss)
+{
+ int ret;
+
+ if(ph_gnss == NULL) {
+ printf("ARG error or has inited.");
+ return -1;
+ }
+
+ if (mbtk_gnss_handle) {
+ printf("GNSS has inited.");
+ *ph_gnss = (uint32)mbtk_gnss_handle;
+ return 0;
+ }
+ mbtk_gnss_handle = malloc(sizeof(struct mbtk_gnss_handle_t));
+ if(NULL == mbtk_gnss_handle)
+ {
+ printf("malloc memory error\n");
+ return -3;
+ }
+ memset(mbtk_gnss_handle, 0, sizeof(struct mbtk_gnss_handle_t));
+ memset(&mopen_gnss_device_info, 0, sizeof(mopen_gnss_device_info));
+
+ ret = mopen_open_gps(1);
+ if(ret) {
+ printf("GNSS open init error\n");
+ return -4;
+ }
+ sleep(1);
+
+ mbtk_gnss_handle->dev_fd = mopen_gnss_open(MBTK_GNSS_DEV, 0);
+
+ printf("Gnss Config Uart Baudrate Start -> \n");
+ ret = auto_set_uart_baudrate(mbtk_gnss_handle->dev_fd);
+ if(-1 == ret) {
+ ret = -2;
+ goto err;
+ } else if (B9600 == ret) {
+ ret = mopen_uart_change(mbtk_gnss_handle->dev_fd, 1);
+ if(ret)
+ {
+ printf("GNSS Uart set B115200 error\n");
+ mopen_gnss_close(mbtk_gnss_handle->dev_fd);
+ mopen_open_gps(0);
+ return -1;
+ }
+ }
+ printf("Gnss Config Uart Baudrate Successful.\n");
+
+ mbtk_gnss_handle->rb = malloc(MBTK_UART_RECV_BUFFER_SIZE);
+ if(NULL == mbtk_gnss_handle->rb)
+ {
+ printf("malloc memory error\n");
+ return -1;
+ }
+
+ ring_buffer_init(&mbtk_gnss_handle->ring_buffer,
+ mbtk_gnss_handle->rb,
+ MBTK_UART_RECV_BUFFER_SIZE);
+
+ mbtk_gnss_handle->inited = 1;
+
+ pthread_mutex_init(&mbtk_gnss_handle->_cond_mutex, NULL);
+ pthread_create(&mbtk_gnss_handle->uart_pthread, NULL, (void *)gnss_uart_pthread, (void *)mbtk_gnss_handle);
+ pthread_create(&mbtk_gnss_handle->gnss_pthread, NULL, (void *)gnss_info_pthread, (void *)mbtk_gnss_handle);
+
+ mopen_gnss_get_ant_state_info((uint32)mbtk_gnss_handle);
+ mopen_gnss_get_device_info((uint32)mbtk_gnss_handle);
+ mopen_gnss_get_nmea_config((uint32)mbtk_gnss_handle);
+ mopen_gnss_get_uart((uint32)mbtk_gnss_handle);
+ mopen_gnss_get_aidinfo((uint32)mbtk_gnss_handle);
+
+ *ph_gnss = (uint32)mbtk_gnss_handle;
+ mbtk_gnss_handle->phandle = ph_gnss;
+
+ return 0;
+ err:
+ mopen_gnss_close(mbtk_gnss_handle->dev_fd);
+ mopen_open_gps(0);
+ firmware_extren_state = 0;
+ if (mbtk_gnss_handle) free(mbtk_gnss_handle);
+ mbtk_gnss_handle = NULL;
+
+ return ret;
+}
+static int _kill_pthread(pthread_t pid, int kill)
+{
+ int ret;
+
+ if (kill) {
+ ret = pthread_cancel(pid);
+ pthread_join(pid, NULL);
+ }
+ do{
+ ret = pthread_kill(pid, 0);
+ if(ret == ESRCH)
+ gnss_log("The specified thread does not exist or has terminated\n");
+ else if(ret == EINVAL)
+ gnss_log("Useless signal\n");
+ else
+ gnss_log("The thread exists\n");
+ usleep(100000);
+ }while(0 == ret);
+
+ return 0;
+}
+int mbtk_gnss_client_deinit(uint32 h_gnss)
+{
+ int ret;
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+
+ if(h_gnss == NULL)
+ {
+ gnss_log("ARG error or not inited.");
+ return -1;
+ }
+ gnss_handle->inited = 0;
+#if TTFF_TEST
+ // ttff测试线程在运行,而且不是临时固件模式
+ if (gnss_handle->ttff_pid &&
+ 0 == firmware_extren_state &&
+ 0 == location_test) {
+ gnss_log("kill thread ttff.\n");
+ _kill_pthread(gnss_handle->ttff_pid, 1);
+ }
+#endif
+ gnss_log("kill thread info 0.\n");
+ _kill_pthread(gnss_handle->gnss_pthread, 0);
+
+ gnss_log("kill thread uart.\n");
+ _kill_pthread(gnss_handle->uart_pthread, 0);
+
+ mopen_gnss_close(gnss_handle->dev_fd);
+
+ ret = mopen_open_gps(0);
+ if(ret)
+ {
+ printf("GNSS close init error\n");
+ return -1;
+ }
+
+ firmware_extren_state = 0;
+ if (gnss_handle->rb) free(gnss_handle->rb);
+ free(h_gnss);
+ mbtk_gnss_handle = NULL;
+
+ return 0;
+}
+
+int mopen_gnss_send_cmd(uint32 h_gnss, const char *cmd, int cmd_len)
+{
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+ return mopen_gnss_write(gnss_handle->dev_fd, cmd, cmd_len);
+}
+
+/**
+ * \brief mbtk_gnss_dev_reset
+ *
+ * Detailed description
+ *
+ * \param
+ * type: 0 软件复位
+ * 1 芯片级复位(看门狗)
+ * 2 板级复位
+ * 3 接收机停止
+ * mode :
+ * 0 : 热启动
+ * 1 : 温启动
+ * 2 : 冷启动
+ * \return return type
+ */
+int mbtk_gnss_dev_reset(uint32 h_gnss, int type, int mode)
+{
+ int ret;
+ struct mbtk_gnss_handle_t *handle = (struct mbtk_gnss_handle_t *)h_gnss;
+ // h00 热启动
+ // h01 温启动
+ // h85 冷启动
+ char send_buf[24] = {0};
+
+ if(0 == h_gnss){
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ if (1 == handle->reset_state) {
+ printf("%s already reset_state.\n", __func__);
+ return -2;
+ }
+
+ if (0 == mode || 1 == mode) {
+ snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h0%d\r\n", type, mode);
+ } else if (2 == mode) {
+ snprintf(send_buf, sizeof(send_buf), "$RESET,%d,h85\r\n", type);
+ } else if (3 == mode) {
+ snprintf(send_buf, sizeof(send_buf), "$RESET,%d,hFF\r\n", type);
+ } else {
+ printf("%s reset mode invalid.\n", __func__);
+ return -2;
+ }
+
+ if ( 1 == firmware_extren_state ) {
+ if (mode > 1) {
+ mbtk_gnss_firmware_update();
+ } else {
+ memset(send_buf, 0, sizeof(send_buf));
+ // 在有GLONASS固件的情况下,冷启动指令为: $CFGSYS,H101
+ // 只发$RESET,0,hFF, 会重置波特率,待验证
+ snprintf(send_buf, sizeof(send_buf), "$CFGSYS,H101\r\n");
+ }
+ }
+
+ gnss_log("%s : %s\n", __FUNCTION__, send_buf);
+ LOGI("%s : %s", __FUNCTION__, send_buf);
+ pthread_mutex_lock(&handle->_cond_mutex);
+ handle->reset_state = 1;
+ pthread_mutex_unlock(&handle->_cond_mutex);
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("%s %d FAIL. ret:%d\n", __FUNCTION__, __LINE__, ret);
+ return -1;
+ }
+
+ // 加载GLONASS固件后,波特率为115200
+ if ( 0 == firmware_extren_state ) {
+ set_baudrate(handle->dev_fd, B9600);
+ gnss_log("%s : set B9600\n", __FUNCTION__);
+ }
+
+ return 0;
+}
+
+int mopen_gnss_get_device_info(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$PDTINFO\r\n";
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("mopen_gnss_client_init FAIL. ret:%d\n",ret);
+ return -1;
+ }
+
+ return 0;
+}
+/**
+ * @brief mopen_gnss_set_system_config
+ *
+ * @details 设置卫星系统配置
+ *
+ * @param mode
+ * 0 -> H01(1) –GPS L1+SBAS+QZSS
+ * 1 -> H10 – BDS B1
+ * 2 -> H101 2 – GPS+GLONASS+GALILEO+SBAS+QZSS
+ * 3 -> H11 3 – GPS+BDS+GALILEO+SBAS+QZSS
+ * @return return type
+ */
+int mbtk_gnss_set_system_config(uint32 h_gnss, int mode)
+{
+ int ret;
+ char send_buf[20] = "$CFGSYS,H10\r\n";
+ char *str_mode[4] = {"H01", "H10", "H101", "H11"};
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ if( mode > 3 )
+ {
+ printf("%s param invalid.\n", __func__);
+ return -2;
+ }
+ snprintf(send_buf, sizeof(send_buf), "$CFGSYS,%s\r\n", str_mode[mode]);
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+ return -3;
+ }
+
+ return 0;
+}
+/**
+ * @brief mopen_gnss_set_nema_config
+ *
+ * @details 设定NMEA 配置
+ * 输出的NMEA 协议版本
+ * h30 - 在 NMEA 标准 version 3.0 基础上扩展北斗相关的语句(NMEA 3.0)
+ * h51 - 在标准NMEA4.1 基础上扩展北斗相关语(NMEA 4.1)
+ * 默认配置: h51
+ *
+ * @param mode
+ * 0 -> h30
+ * 1 -> h51
+ *
+ * @return return type
+ */
+int mbtk_gnss_set_nema_config(uint32 h_gnss, int mode)
+{
+ int ret;
+ char send_buf[16] = "$CFGNMEA,h30\r\n";
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ if (mode) {
+ send_buf[10] = '5';
+ send_buf[11] = '1';
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+ return -3;
+ }
+
+ return 0;
+}
+int mopen_gnss_aidpos(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$AIDPOS,4002.229934,N,11618.096855,E,37.254\r\n";
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("mopen_gnss_client_init FAIL. ret:%d\n",ret);
+ return -1;
+ }
+ return 0;
+}
+/**
+ * @brief mopen_gnss_get_aidinfo
+ *
+ * @details 查询辅助数据状态
+ * $CFGAID,0,D7FBFBDF,00000000,08*47
+ * @param param
+ *
+ * @return return type
+ */
+int mopen_gnss_get_aidinfo(uint32 h_gnss)
+{
+ int ret;
+ // char *send_buf = "$AIDINFO\r\n";
+ char *send_buf = "$CFGAID,0\r\n";
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("%s FAIL. ret:%d\n", __FUNCTION__, ret);
+ return -1;
+ }
+ return 0;
+}
+/**
+ * @brief mopen_gnss_get_uart
+ *
+ * @details get uart config info.
+ * $CFGPRT,1,h0,9600,129,3*57
+ *
+ * @param param
+ *
+ * @return return type
+ */
+int mopen_gnss_get_uart(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$CFGPRT,1\r\n";
+ // char *send_buf = "$CFGPRT,2\r\n";
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("mopen_gnss_client_init FAIL. ret:%d\n",ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_set_uart(uint32 h_gnss, int baudrate)
+{
+ int ret;
+ char send_buf[28] = {0};
+ // char *send_buf = "$CFGPRT,1,h0,9600,1,3\r\n";
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ sprintf(send_buf, "$CFGPRT,1,h0,%d,1,3\r\n", baudrate);
+ gnss_log("%s %s", __FUNCTION__, send_buf);
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("mopen_gnss_client_init FAIL. ret:%d\n",ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_get_msg_output(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$CFGMSG,0,1\r\n"; // msg class, msg id
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ printf("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_set_msg_output(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$CFGMSG,0,1,1\r\n";// msg class, msg id, msg switch
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_set_lowpower(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$CFGLOWPOWER,0\r\n";// 0 - nomale, 1 - lowpower
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_get_ant_state_info(uint32 h_gnss)
+{
+ int ret;
+ char *cmd1_buf = "$ANTSTAT,1\r\n";
+ char *cmd2_buf = "$ANTSTAT1\r\n";
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, cmd1_buf, strlen(cmd1_buf));
+ if(ret < 0)
+ {
+ gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, cmd2_buf, strlen(cmd2_buf));
+ if(ret < 0)
+ {
+ gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mopen_gnss_get_nmea_config(uint32 h_gnss)
+{
+ int ret;
+ char *send_buf = "$CFGNMEA\r\n";
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ ret = mopen_gnss_send_cmd(h_gnss, send_buf, strlen(send_buf));
+ if(ret < 0)
+ {
+ gnss_log("%s FAIL. ret:%d\n", __func__, ret);
+ return -1;
+ }
+ return 0;
+}
+
+int mbtk_gnss_add_rx_msg_handler(uint32 h_gnss, mbtk_gnss_handler_func_t handler_ptr)
+{
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+
+ if(0 == h_gnss && NULL == handler_ptr)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ gnss_handle->gnss_handler_func = handler_ptr;
+
+ return 0;
+}
+
+#define AGNSS_TLE_FILE "/tmp/agnss_tle"
+
+static void http_data_cb_func(
+ int session_id, mbtk_http_data_type_enum type,
+ void *data,int data_len)
+{
+ static int agnss_fd = 0;
+ int ret = 0;
+
+ if(type == MBTK_HTTP_DATA_HEADER) {
+ gnss_log("Header(%d):%s\n", data_len, (char*)data);
+ if(agnss_fd > 0)
+ return;
+ unlink(AGNSS_TLE_FILE);
+ agnss_fd = open(AGNSS_TLE_FILE, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if (agnss_fd <= 0)
+ gnss_log("file open error\n");
+ gnss_log("agnss file open: %d\n", agnss_fd);
+ } else if(type == MBTK_HTTP_DATA_CONTENT) {
+ gnss_log("http Data(%d)\n", data_len);
+
+ ret = write(agnss_fd, (char*)data, data_len);
+ if (ret < 0) {
+ gnss_log("%s: error writing to file!\n", __FUNCTION__);
+ } else if (ret < data_len) {
+ gnss_log("%s: wrote less the buffer size!\n", __FUNCTION__);
+ }
+ } else {
+ gnss_log(">>>>>Complete<<<<<\n");
+ if(agnss_fd <= 0)
+ return;
+ close(agnss_fd);
+ agnss_fd = 0;
+ }
+}
+
+static int gnss_http_requst(char *id, char *pw)
+{
+ char tmp[128] = {0};
+
+ int http_handle = mbtk_http_handle_get(TRUE, http_data_cb_func);
+ if(http_handle < 0)
+ {
+ printf("mbtk_http_handle_get() fail.");
+ return -1;
+ }
+
+ int http_session = mbtk_http_session_create(http_handle, HTTP_OPTION_POST, HTTP_VERSION_1_1);
+ if(http_handle < 0)
+ {
+ printf("mbtk_http_session_create() fail.");
+ return -2;
+ }
+
+ if(mbtk_http_session_url_set(http_handle, http_session, "http://unicore-api.rx-networks.cn/rxn-api/locationApi/rtcm")) {
+ printf("mbtk_http_session_url_set() fail.\n");
+ return -3;
+ }
+
+ char* post_data = "[{\"rtAssistance\":{\"format\":\"rtcm\",\"msgs\":[\"GPS:2NAF\",\"BDS:2NAF\",\"QZS:2NAF\"]}}]\r\n";
+
+ mbtk_http_session_head_add(http_handle, http_session, \
+ "Host", "unicore-api.rx-networks.cn");
+
+ sprintf(tmp, "RXN-BASIC cId=%s,mId=Unicore,dId=12-23-34-45-58,pw=%s", id, pw);
+ mbtk_http_session_head_add(http_handle, http_session, \
+ "Authorization", tmp);
+
+ mbtk_http_session_head_add(http_handle, http_session, \
+ "Content-Type", "application/json");
+
+ mbtk_http_session_head_add(http_handle, http_session, \
+ "Accept", "application/octet-stream");
+ mbtk_http_session_content_set(http_handle, http_session,
+ post_data, strlen(post_data));
+
+ if(mbtk_http_session_start(http_handle, http_session)) {
+ printf("mbtk_http_session_start() fail.\n");
+ return -4;
+ }
+
+ if(mbtk_http_handle_free(http_handle))
+ {
+ printf("mbtk_http_handle_free() fail.");
+ return -5;
+ }
+
+ return 0;
+}
+
+/**********************************
+
+ ID1: TempID1Expire20221031
+ Base 64 PW1: RlJYdkFTNE9DWXJhN2ZWTA==
+**************************************/
+#define AGNSS_CONFIG_FILE "/etc/mbtk/gps.conf"
+
+/**
+ * @brief mopen_gnss_download_tle
+ *
+ * @details 下载星历数据
+ * (卫星星历,又称为两行轨道数据(TLE,Two-Line Orbital Element))
+ * 保存到文件:AGNSS_TLE_FILE
+ * @param param
+ *
+ * @return return type
+ */
+int mbtk_gnss_download_tle(void)
+{
+ FILE *fp;
+ char StrLine[64];
+ char _id[24] = {0};
+ char _passwd[28] = {0};
+ int i;
+ if((fp = fopen(AGNSS_CONFIG_FILE, "r")) == NULL)
+ {
+ printf("open %s error!\n", AGNSS_CONFIG_FILE);
+ return -1;
+ }
+
+ while (!feof(fp))
+ {
+ memset(StrLine, 0, 64);
+ fgets(StrLine, 64, fp);
+ gnss_log("%s\n", StrLine);
+ i = strstr_n(StrLine, ": ");
+ if(i && strstr_n(StrLine, "ID"))
+ {
+ memcpy(_id, &StrLine[i + 1], strlen(StrLine) - i - 2);
+ }
+ else if( i && strstr_n(StrLine, "Base 64"))
+ {
+ memcpy(_passwd, &StrLine[i + 1], strlen(StrLine) - i - 2);
+ }
+ }
+ fclose(fp);
+ gnss_log("%s : %s[%d], %s[%d]\n", __FUNCTION__, _id, strlen(_id), _passwd, strlen(_passwd));
+
+ return gnss_http_requst(_id, _passwd);
+}
+
+/**
+ * @brief mopen_gnss_injects_aidpos
+ *
+ * @details 注入星历, 128 bytes
+ *
+ * @param param
+ *
+ * @return return type
+ */
+int mbtk_gnss_injects_aidpos(uint32 h_gnss)
+{
+ int ret;
+ int agnss_fd = 0;
+ int size = 0;
+
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+
+ agnss_fd = open(AGNSS_TLE_FILE, O_RDWR);
+ if (agnss_fd <= 0)
+ {
+ printf("%s open file FAIL. errno:%d\n", __FUNCTION__, errno);
+ return -1;
+ }
+ char* databuf = (char*)malloc(128);
+ if(databuf == NULL)
+ {
+ gnss_log("%s malloc() fail.", __FUNCTION__);
+ return -1;
+ }
+ memset(databuf, 0, 128);
+ while(0 < (size = read(agnss_fd, databuf, 128)))
+ {
+ gnss_log("%s Write[%d]\r\n", __FUNCTION__, size);
+ ret = mopen_gnss_send_cmd(h_gnss, databuf, size);
+ if(ret < 0)
+ {
+ printf("%s send cmd FAIL. ret:%d\n", __FUNCTION__, ret);
+ break;
+ }
+ memset(databuf, 0, 128);
+ }
+ close(agnss_fd);
+ free(databuf);
+ mopen_gnss_get_aidinfo(h_gnss);
+
+ return 0;
+}
+/**
+ * @brief mopen_gnss_set_mode
+ *
+ * @details detailed description
+ *
+ * @param mode
+ * 0 : stop
+ * 1 : 输出一次坐标
+ * 2 : stop
+ * 3 : 输出nmea数据到回调函数
+ * 0 - stop, 1 - single, 2 - periodic, 3 - start
+ *
+ * @return return type
+ */
+int mbtk_gnss_set_mode(uint32 h_gnss, int mode)
+{
+ struct mbtk_gnss_handle_t *gnss_handle = (struct mbtk_gnss_handle_t *)h_gnss;
+ if(0 == h_gnss)
+ {
+ printf("%s handler invalid.\n", __func__);
+ return -1;
+ }
+ gnss_handle->mode = mode;
+
+ return 0;
+}
+
+int mbtk_gnss_print_version(uint32 h_gnss)
+{
+ printf("*************************\n");
+ printf("-Pn: %s\n dc: %s\n hv: %s\n fw: %s\n pn: %s\n sn: %s\n ",
+ mopen_gnss_device_info.product_name,
+ mopen_gnss_device_info.dev_config,
+ mopen_gnss_device_info.hw_ver,
+ mopen_gnss_device_info.fw_ver,
+ mopen_gnss_device_info.pn,
+ mopen_gnss_device_info.sn);
+ printf("Uart bandrate: %d\n" , mopen_gnss_device_info.usrt_bandrate);
+ printf("*************************\n");
+
+ return 0;
+}
+
+/**
+* @brief 使用popen调用终端并获取执行结果
+*
+* @param[in] cmd 命令内容
+* @param[out] result 保存结果的地址
+* @return 0或1 执行状态,成功或失败
+*/
+int exec_cmd(const char *cmd, char *result)
+{
+ FILE *pipe = popen(cmd, "r");
+ if(!pipe)
+ return -1;
+
+ char buffer[256] = {0};
+ while(!feof(pipe))
+ {
+ if(fgets(buffer, 256, pipe))
+ {
+ printf("%s", buffer);
+ memset(buffer, 0, sizeof(buffer));
+ }
+ }
+ pclose(pipe);
+ return 0;
+}
+
+#define GNSS_AP_DATA_FILE "/etc/mbtk/rtm.bin"
+
+int mbtk_gnss_get_ap_data(void)
+{
+ int state = 0;
+ uint32 *ph_gnss = NULL;
+ mbtk_gnss_handler_func_t cb;
+ int current_mode;
+ const char* cmd = "mbtk_gnss_update getap -d /dev/ttyS2 -b 115200 -a /etc/mbtk/rtm.bin";
+
+ if(access(GNSS_AP_DATA_FILE, F_OK) != -1) {
+ unlink(GNSS_AP_DATA_FILE);
+ }
+ mbtk_gnss_handle->getap_status = 1;
+ sleep(1);
+ printf("Mopen Gnss Get Ap Data -> \n");
+ int ret = exec_cmd(cmd, NULL);
+
+ usleep(100000);
+ mbtk_gnss_handle->getap_status = 0;
+ if(0 != ret) {
+ printf("Gnss getap result: %x\n", ret);
+ return -1;
+ }
+ LOGI("%s %d: %d.\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+}
+/*
+ sync : 1
+ */
+int mbtk_gnss_firmware_update(void)
+{
+ int state = 0;
+ uint32 *ph_gnss = NULL;
+ mbtk_gnss_handler_func_t cb;
+ int current_mode;
+ int fd = -1;
+ int ret = 0;
+
+ const char* cmd_1 = "mbtk_gnss_update downbl -d /dev/ttyS2 \
+ -l /etc/mbtk/bootloader_r3.0.0_build6773_uartboot_921600.pkg";
+
+ const char* cmd_2 = "mbtk_gnss_update sendap -d /dev/ttyS2 -b 921600 -a /etc/mbtk/rtm.bin";
+
+ const char* cmd_3 = "mbtk_gnss_update downfw -d /dev/ttyS2 -b 921600\
+ -f /etc/mbtk/UC6228CI-R3.4.21.0Build16211_G1L1E1_mfg.pkg";
+ // /etc/mbtk/UC6228CI-R3.4.0.0Build7258_mfg.pkg
+
+ if (mbtk_gnss_handle) {
+ printf("%s gnss thread runing!!!\n", __func__);
+ if (mbtk_gnss_handle->gnss_handler_func)
+ cb = mbtk_gnss_handle->gnss_handler_func;
+
+ ph_gnss = mbtk_gnss_handle->phandle;
+ current_mode = mbtk_gnss_handle->mode;
+ // 主线程是否在运行
+ if (mbtk_gnss_handle->gnss_pthread)
+ state = 1;
+ mbtk_gnss_client_deinit(mbtk_gnss_handle);
+ }
+ printf("Mopen Gnss Bootloader Update -> \n");
+ //int ret = exec_cmd(cmd_1, NULL);
+
+ fd=initial_serialPort("/dev/ttyS2");
+ ret = downloadBL(fd, "/etc/mbtk/bootloader_r3.0.0_build6773_uartboot_921600.pkg");
+ if(0 != ret) {
+ printf("Gnss update result: %x\n", ret);
+ close(fd);
+ return -1;
+ }
+
+ if(access(GNSS_AP_DATA_FILE, F_OK) != -1)
+ {
+ printf("Mopen Gnss Send AP Data -> \n");
+ //ret = exec_cmd(cmd_2, NULL);
+
+ set_baudrate(fd, B921600);
+ ret = sendAPData(fd, "/etc/mbtk/rtm.bin");
+
+ if(0 != ret) {
+ close(fd);
+ printf("Gnss update result: %x\n", ret);
+ }
+ }
+
+ printf("Mopen Gnss Firmware Update -> \n");
+ //ret = exec_cmd(cmd_3, NULL);
+ set_baudrate(fd, B921600);
+ ret = downloadFW(fd, "/etc/mbtk/UC6228CI-R3.4.21.0Build16211_G1L1E1_mfg.pkg");
+ close(fd);
+
+ if(0 != ret) {
+ printf("Gnss update result: %x\n", ret);
+ return -2;
+ }
+
+ if (0 == firmware_extren_state)
+ firmware_extren_state = 1;
+ if (state && ph_gnss) {
+ ret = mbtk_gnss_client_init(ph_gnss);
+ if (cb) {
+ mbtk_gnss_handle->gnss_handler_func = cb;
+ mbtk_gnss_handle->mode = current_mode;
+ }
+ }
+
+ LOGI("%s %d: %d.\n", __FUNCTION__, __LINE__, ret);
+ return ret;
+}
+
+int mbtk_at_gnss(int start_stop, void *cb)
+{
+ static uint32 loc = 0;
+ int ret = -1;
+
+ LOGI("%s %d", __FUNCTION__, __LINE__);
+ switch (start_stop) {
+ case 0: {
+ ret = mbtk_gnss_set_mode(loc, 0);
+ if(ret)
+ return -3;
+ ret = mbtk_gnss_client_deinit(loc);
+ if(ret)
+ return -3;
+ loc = 0;
+ return 0;
+ }
+ case 1: {
+ if (0 != loc)
+ return -1;
+
+ ret = mbtk_gnss_client_init(&loc);
+ if(ret || 0 == loc)
+ return -1;
+
+ if(NULL == cb)
+ return -2;
+
+ ret = mbtk_gnss_add_rx_msg_handler(loc, (mbtk_gnss_handler_func_t)cb);
+ if(ret)
+ return -2;
+ ret = mbtk_gnss_set_mode(loc, 3);
+ break;
+ }
+ case 2: {
+ ret = mbtk_gnss_set_mode(loc, 0);
+ break;
+ }
+ case 3: {
+ ret = mbtk_gnss_set_mode(loc, 3);
+ break;
+ }
+ case 4: {
+ ret = mopen_uart_change(((struct mbtk_gnss_handle_t *)loc)->dev_fd, 1);
+ if(ret) {
+ printf("reset Uart set 115200 error\n");
+ }
+ break;
+ }
+ case 6: {
+ ret = mbtk_gnss_firmware_update();
+ if(ret) {
+ printf("gnss firmware update error!!\n");
+ }
+ break;
+ }
+ case 11:{
+ ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,3);//GPS+BD
+ break;
+ }
+ case 10:{
+ ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,0);// only GPS
+ break;
+ }
+ case 9:{
+ ret = mbtk_gnss_set_system_config((uint32)mbtk_gnss_handle,2);//GPS+GLONASS
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ret;
+}
+/*
+ 0 热启动
+ 1 冷启动
+ 2 温启动
+ */
+int mbtk_at_gnss_reset(int type)
+{
+ switch (type)
+ {
+ case 0: {
+ // $RESET,0,h0
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 0);
+ }
+ case 1: {
+ // $RESET,0,h85
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 2);
+ }
+ case 2: {
+ // $RESET,0,h01
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 1);
+ }
+ case 3: {
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 3);
+ }
+ case 4: {
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 3, 0);
+ }
+ case 5: {
+ return mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 1, 0);
+ }
+ default:
+ break;
+ }
+ return -9;
+}
+
+#if TTFF_TEST
+static void gnss_gsa_info(int cmd, char *str, void *data)
+{
+ char tmp_str[32] = {0};
+ int ret;
+
+ gnss_log("[ GSA ]: ");
+ // $xxGSA
+ ret = gnss_get_para_from_nmea(str, tmp_str, 1);
+ if(0 == ret && ('A' == tmp_str[0])){
+ gnss_log("Smode: %s, ", tmp_str);
+ memset(tmp_str, 0, 32);
+ } else {
+ printf("%s [exit]: %s\n", __FUNCTION__, str);
+ return;
+ }
+
+ /* 定位模式:
+ 1-未定位
+ 2-2D 定位
+ 3-3D 定位
+ */
+ ret = gnss_get_para_from_nmea(str, tmp_str, 2);
+ if(ret){
+ gnss_log("L%d %s error! \n");
+ return;
+ }
+
+ gnss_log("fs: %s - [%d]", tmp_str, atoi(tmp_str));
+ if ( atoi(tmp_str) != mbtk_gnss_handle->location_state ) {
+ mbtk_gnss_handle->location_state = atoi(tmp_str);
+ if (mbtk_gnss_handle->location_state > 1 && location_test) {
+ pthread_mutex_lock(&loc_cond_mutex_r);
+ location_test = 0;
+ pthread_cond_signal(&loc_sync_cond);
+ pthread_mutex_unlock(&loc_cond_mutex_r);
+ }
+ }
+ gnss_log(" -- \n");
+}
+
+int mbtk_gnss_test_ttff(int type, int timeout_sec)
+{
+ struct timeval tnow;
+ struct timespec tout;
+ long t_start, t_end;
+ int ret;
+
+ pthread_mutex_lock(&loc_cond_mutex_r);
+ location_test = 1;
+ pthread_mutex_unlock(&loc_cond_mutex_r);
+
+ switch (type)
+ {
+ case 0: {
+ // $RESET,0,h0
+ mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 0);
+ break;
+ }
+ case 1: {
+ // $RESET,0,hFF
+ mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 3);
+ break;
+ }
+ case 2: {
+ // $RESET,0,h01
+ mbtk_gnss_dev_reset((uint32)mbtk_gnss_handle, 0, 1);
+ break;
+ }
+ case 3: {
+ // 在有GLONASS固件的情况下,冷启动指令为: $CFGSYS,H101
+ // 只发$RESET,0,hFF, 会重置波特率,待验证
+ mopen_gnss_set_system_config((uint32)mbtk_gnss_handle, 2);
+ break;
+ }
+ case 4: {
+ if ( 0 == firmware_extren_state )
+ return -2;
+
+ ret = mopen_gnss_firmware_update();
+ if(ret) {
+ printf("gnss firmware update error!!\n");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (0 == timeout_sec )
+ timeout_sec = 60 * 3;
+ gettimeofday(&tnow, NULL);
+ t_start = tnow.tv_sec * 1000 * 1000 + tnow.tv_usec;
+ tout.tv_sec = tnow.tv_sec + timeout_sec;
+ tout.tv_nsec = tnow.tv_usec;
+ if (tout.tv_nsec > 1000000000)
+ {
+ tout.tv_sec += 1;
+ tout.tv_nsec -= 1000000000;
+ }
+ pthread_mutex_lock(&loc_cond_mutex_r);
+ ret = pthread_cond_timedwait(&loc_sync_cond, &loc_cond_mutex_r, &tout);
+ pthread_mutex_unlock(&loc_cond_mutex_r);
+ gettimeofday(&tnow, NULL);
+ t_end = tnow.tv_sec * 1000 * 1000 + tnow.tv_usec;
+ gnss_log("gnss ttff time:%ld\n", t_end - t_start);
+ if(ret == ETIMEDOUT) {
+ location_test = 0;
+ return -1;
+ }
+
+ return (t_end - t_start)/1000;
+}
+
+#define GNSS_TEST_FILE "/tmp/gnss_test"
+#define INSERT_CUT_OFF_RULE() { memset(buffer, 0, sizeof(buffer)); \
+ sprintf(buffer, "----------------------------------\r\n"); \
+ ret = write(fd, buffer, strlen(buffer)); \
+ if (ret < 0) { \
+ printf("%s write error !!\n", __func__); \
+ } \
+}
+
+void *gnss_ttff_thread(void *data)
+{
+ struct mbtk_gnss_ttff_t *handle = (struct mbtk_gnss_ttff_t *)data;
+ int fd, ret, i;
+ int index, time_ms;
+ float loc_time;
+ char buffer[128] = {0};
+
+ pthread_detach(pthread_self());
+
+ if ( !access(GNSS_TEST_FILE, F_OK) ){
+ unlink(GNSS_TEST_FILE);
+ }
+
+ pthread_cond_init(&loc_sync_cond, NULL);
+ pthread_mutex_init(&loc_cond_mutex_r, NULL);
+ fd = open(GNSS_TEST_FILE, O_RDWR|O_CREAT|O_TRUNC, 0644);
+ if (fd <= 0) {
+ gnss_log("file open error\n");
+ }
+ INSERT_CUT_OFF_RULE()
+ sprintf(buffer, "type: %d, timeout: %d, count: %d\r\n", handle->type,
+ handle->timeout_sec,
+ handle->test_count);
+ ret = write(fd, buffer, strlen(buffer));
+ if (ret < 0) {
+ printf("%s write error !!\n", __func__);
+ }
+ INSERT_CUT_OFF_RULE()
+ for (i = 0; i < handle->test_count; ++i) {
+ memset(buffer, 0, sizeof(buffer));
+ time_ms = mbtk_gnss_test_ttff(handle->type, handle->timeout_sec);
+ if (-1 == time_ms)
+ loc_time = time_ms;
+ else
+ loc_time = ((float)time_ms) / 1000;
+ sprintf(buffer, "\t %d - [ %f s ]\r\n", i + 1, loc_time);
+ printf("\t %d - %f\n", i + 1, loc_time);
+ ret = write(fd, buffer, strlen(buffer));
+ if (ret < 0) {
+ printf("%s write error !!\n", __func__);
+ }
+ }
+
+ INSERT_CUT_OFF_RULE()
+ close(fd);
+ mbtk_gnss_handle->ttff_pid = 0;
+ pthread_cond_destroy(&loc_sync_cond);
+ pthread_mutex_destroy(&loc_cond_mutex_r);
+ pthread_exit(NULL);
+}
+#endif
+
+int mbtk_at_gnss_start_ttff(int type, int timeout_sec, int count)
+{
+#if TTFF_TEST
+ int ret;
+ static struct mbtk_gnss_ttff_t mbtk_gnss_ttff;
+
+ LOGI("%s %d, %d, %d", __FUNCTION__, type, timeout_sec, count);
+ if (NULL == mbtk_gnss_handle) {
+ printf("%s not init!!!\n", __func__);
+ return -1;
+ }
+ if (mbtk_gnss_handle->ttff_pid) {
+ printf("%s busy!!!\n", __func__);
+ return -2;
+ }
+ mbtk_gnss_ttff.type = type;
+ mbtk_gnss_ttff.timeout_sec = timeout_sec;
+ mbtk_gnss_ttff.test_count = count;
+ ret = pthread_create(&mbtk_gnss_handle->ttff_pid, NULL, (void *)gnss_ttff_thread, &mbtk_gnss_ttff);
+ if (ret != 0)
+ {
+ fprintf(stderr, "\n%s: Failed create pthread\n", __FUNCTION__);
+ return ret;
+ }
+
+#endif
+ return 0;
+}
diff --git a/mbtk/libmbtk_lib/gnss/mbtk_gnss_inter.h b/mbtk/libmbtk_lib/gnss/mbtk_gnss_inter.h
new file mode 100755
index 0000000..f56c7fb
--- /dev/null
+++ b/mbtk/libmbtk_lib/gnss/mbtk_gnss_inter.h
@@ -0,0 +1,29 @@
+/*
+* mbtk_gnss_inter.h
+*
+* MBTK GNSS internal header.
+*
+* Author : lb
+* Date : 2024/7/11 16:18:42
+*/
+#ifndef __MBTK_GNSS_INTER_H
+#define __MBTK_GNSS_INTER_H
+#include <pthread.h>
+
+#include "mbtk_gnss.h"
+#include "mbtk_type.h"
+
+#define SOCK_GNSS_PATH "/tmp/mbtk_gnss_sock"
+#define EPOLL_LISTEN_MAX 100
+
+typedef enum {
+ GNSS_EPH_GPS = 0,
+ GNSS_EPH_BDS,
+ GNSS_EPH_GLO,
+ GNSS_EPH_GPS_BDS,
+ GNSS_EPH_GPS_GLO,
+
+ GNSS_EPH_CFG = 10, //get eph data by cfg parameters
+} gnss_eph_data_enum;
+
+#endif /* __MBTK_GNSS_INTER_H */
diff --git a/mbtk/libmbtk_lib/gnss/mbtk_gnss_update.c b/mbtk/libmbtk_lib/gnss/mbtk_gnss_update.c
new file mode 100755
index 0000000..2c0657e
--- /dev/null
+++ b/mbtk/libmbtk_lib/gnss/mbtk_gnss_update.c
@@ -0,0 +1,1283 @@
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <time.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <ctype.h>
+#include <sched.h>
+#include <limits.h>
+#include <linux/serial.h>
+
+#define RTM_FILE_NAME "rtm.bin"
+
+#define PARA_ERR -1
+#define FILE_CHECK_ERR -2
+#define ENTER_UPDATE_MODE_ERR -3
+#define UPDATE_ERR -4
+#define UART_DEV_ERR -5
+
+#define XMODEM_SOH 0x01
+#define XMODEM_STX 0x02
+#define XMODEM_EOT 0x04
+#define XMODEM_ACK 0x06
+#define XMODEM_NAK 0x15
+#define XMODEM_CAN 0x18
+#define XMODEM_CRC_CHR 'C'
+#define XMODEM_CRC_SIZE 2 /* Crc_High Byte + Crc_Low Byte */
+#define XMODEM_FRAME_ID_SIZE 2 /* Frame_Id + 255-Frame_Id */
+#define XMODEM_DATA_SIZE_SOH 128 /* for Xmodem protocol */
+#define XMODEM_DATA_SIZE_STX 1024 /* for 1K xmodem protocol */
+#define USE_1K_XMODEM 1 /* 1 for use 1k_xmodem 0 for xmodem */
+#define TIMEOUT_USEC 0
+#define TIMEOUT_SEC 10
+
+#if (USE_1K_XMODEM)
+#define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_STX
+#define XMODEM_HEAD XMODEM_STX
+#else
+#define XMODEM_DATA_SIZE XMODEM_DATA_SIZE_SOH
+#define XMODEM_HEAD XMODEM_SOH
+#endif
+
+
+/******************************************************************************
+ * 时间处理相关的宏
+ *****************************************************************************/
+// 时间超时标志
+int timeout_sign = 1;
+// 获取当前时间
+#define GET_TIME() { gettimeofday(&time_m, NULL); \
+ time_m.tv_sec += TIMEOUT_SEC;\
+}
+// 设置从循环中退出的时间
+#define SET_TIME_OUT(x) { gettimeofday(&time_m, NULL); \
+ time_m.tv_sec += x;\
+}
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ printf("\ntimeout!!!\n\n");\
+ close(fd); \
+ return ret; \
+ } \
+}
+// 检测时间是否超时,超时则退出当前循环
+#define CHK_TIME_BREAK() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ timeout_sign = 1; \
+ printf("\ntimeout!!!\n\n");\
+ break; \
+ } \
+}
+// 检测延时是否到达,到达则退出当前循环
+#define DELAY_TIME_BREAK() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ timeout_sign = 1; \
+ break; \
+ } \
+}
+
+// 检测时间是否超时,超时则退出当前函数
+#define CHK_TIME1() { gettimeofday(&time_n, NULL); \
+ if(time_n.tv_sec > time_m.tv_sec) { \
+ printf("\ntimeout!!!\n\n");\
+ if(datafile != NULL) \
+ fclose(datafile); \
+ return ret; \
+ } \
+}
+
+
+/******************************************************************************
+ * APData 相关定义、声明
+ *****************************************************************************/
+// APData 数据头部定义
+typedef struct {
+ unsigned int ih_magic; // Image Header Magic Number
+ unsigned int ih_dcrc; // Image Data CRC checksum
+ unsigned int ih_time; // Image Creation Timestamp
+ unsigned int ih_size; // Image Data Size
+ unsigned int ih_compress; // Image Header compress or not:0, not compress
+ unsigned int pkg_flash_addr; // flash memory offset for package
+ unsigned int pkg_run_addr; // Run time address for this package
+ unsigned int ih_hcrc; // Image Header CRC checksum
+} uc_image_header_t;
+
+// APData 数据头部长度
+#define HEADERLEN 32
+// APData 接收状态类型
+typedef enum ReceStat{
+ WAIT_FD = 1,
+ WAIT_FC,
+ WAIT_FB,
+ WAIT_FA,
+ RECE_HEADER,
+ RECE_DATA,
+} RecvStat_t;
+// APData 接收状态变量
+static RecvStat_t recvStat = WAIT_FD;
+// APData 接收状态变量
+static int isStartReceive = 0;
+// APData 开始接收
+void af_start_receive();
+// APData 停止接收,在数据接收完成或出错时调用
+void af_stop_receive();
+// 获取isStartReceive 变量值
+int af_is_start_receive();
+// APData 数据接收入口
+int af_add_char(char *file, unsigned char c);
+// 校验 APData 数据头
+int af_check_header(unsigned char *pbuf, unsigned int len);
+// 校验 APData 数据区
+int af_check_data(unsigned int * pbuf, unsigned int len);
+// 获取 APData 数据长度
+int af_get_data_len();
+// APData 数据接收缓存
+unsigned int recv_buf[1024 * 2];
+unsigned char *pbuf;
+int data_len;
+// 校验文件
+int check_file(char *fname);
+
+/******************************************************************************
+ * 与接收机串口通讯相关定义、声明
+ *****************************************************************************/
+// select功能使用变量
+static int use_select = 1;
+// 初始化串口资源
+int initial_serialPort(char * serial_device);
+// 设置串口波特率
+static int set_baudrate(int fd, int baudrate);
+// 检测串口数据
+static int select_read(int fd, int timeout);
+// 读取串口数据
+static ssize_t deal_read(int fd, void *buf, size_t count);
+// 向接收机发送串口数据
+static void gps_dev_send(int fd, char *msg);
+// 通过xmodem协议向接收机发送串口数据
+int xmodem_send(int fd, char *fname);
+
+/******************************************************************************
+ * apflash 功能函数
+ *****************************************************************************/
+// 检测接收机发送的'YC'信号,如果收到,则标志着接收机进入boot模式,并可以通过xmodem发送数据
+int check_YC(char newchar);
+// 获取 APData 数据, 应该在接收机定位且星历数据接收完整时获取
+int getAPData(int fd, char *file);
+// 向接收机发送 APData 数据,有效的APData数据可以让CI模块迅速定位
+int sendAPData(int fd, char *ap);
+// 校验 APData 数据文件
+int checkAPData(char *apFile);
+// 为接收机加载BootLoader,该流程执行时,需要根据终端提示,给接收机下电和上电,确保接收机进入boot模式
+int downloadBL(int fd, char *bl);
+// 为接收机加载Firmware,该流程必须在加载BootLoader之后进行
+int downloadFW(int fd, char *fw);
+
+void printGetapUsage(char *app)
+{
+ printf("\n%s getap -d receiverPort [-b baudrate] [-h] -a apfile \n", app);
+ printf("\tfunction: read APData from receiver\n");
+ printf("\tparas:\n");
+ printf("\t\treceiverPort: Port that connected to receiver\n");
+ printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printSendapUsage(char *app)
+{
+ printf("\n%s sendap -d receiverPort [-b baudrate] [-h] -a apfile\n", app);
+ printf("\tfunction: send APData to receiver\n");
+ printf("\tparas:\n");
+ printf("\t\treceiverPort: Port that connected to receiver\n");
+ printf("\t\tbaudrate: baudrate of receiverPort\n");
+}
+
+void printCheckapUsage(char *app)
+{
+ printf("\n%s checkap -a apfile [-h]\n", app);
+ printf("\tfunction: check APData\n");
+ printf("\tparas:\n");
+ printf("\t\tapfile: APData file\n");
+}
+
+void printDownloadblUsage(char *app)
+{
+ printf("\n%s downbl -d receiverPort [-b baudrate] -l bootloader [-h]\n", app);
+ printf("\tfunction: download bootloader to receiver\n");
+ printf("\tparas:\n");
+ printf("\t\treceiverPort: Port that connected to receiver\n");
+ printf("\t\tbaudrate: baudrate of receiverPort\n");
+ printf("\t\tbootloader: bootloader file\n");
+}
+
+void printDownloadfwUsage(char *app)
+{
+ printf("\n%s downfw -d receiverPort [-b baudrate] -f firmware [-h]\n", app);
+ printf("\tfunction: download firmware to receiver\n");
+ printf("\tparas:\n");
+ printf("\t\treceiverPort: Port that connected to receiver\n");
+ printf("\t\tbaudrate: baudrate of receiverPort\n");
+ printf("\t\tfirmware: firmware file\n");
+}
+
+void printUsage(char *app)
+{
+ printGetapUsage(app);
+ printSendapUsage(app);
+ printCheckapUsage(app);
+ printDownloadblUsage(app);
+ printDownloadfwUsage(app);
+}
+
+#define GPS_DEV "/sys/devices/soc.0/d4000000.apb/mbtk-dev-op/gps_power"
+
+static int mopen_open_gps(int state)
+{
+ int fd, ret;
+ char s[4] = "on";
+ fd = open(GPS_DEV, O_RDWR | O_TRUNC, 0644);
+ if(fd < 0) {
+ printf("[%s] file [%s] open error\n", __FUNCTION__, GPS_DEV);
+ return -1;
+ }
+ if(0 == state)
+ {
+ memcpy(s, "off", 3);
+ }
+ ret = write(fd, s, 4);
+ if (ret < 0) {
+ printf("%s: error writing to file!\n", __FUNCTION__);
+ close(fd);
+ return -2;
+ }
+
+ close(fd);
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ int ret = 0;
+ int fd = -1;
+ int paraMask = 0;
+ int baud = 115200;
+ char devPort[200] = {0};
+ char fw[200] = {0};
+ char bl[200] = {0};
+ char ap[200] = {0};
+ int func = 0; // 1:getap, 2:sendap, 3:downbl, 4:downfw, 5:checkap
+
+ // Verify arguments
+ if (argc < 2) {
+ printf("Usage:\n");
+ printUsage(argv[0]);
+ exit(1);
+ }
+
+ if(strcmp(argv[1], "getap") == 0) {
+ func = 1;
+ paraMask = 1;
+ } else if (strcmp(argv[1], "sendap") == 0) {
+ func = 2;
+ paraMask = 1;
+ } else if (strcmp(argv[1], "downbl") == 0) {
+ func = 3;
+ paraMask = 9;
+ } else if (strcmp(argv[1], "downfw") == 0) {
+ func = 4;
+ paraMask = 5;
+ } else if (strcmp(argv[1], "checkap") == 0) {
+ func = 5;
+ paraMask = 16;
+ } else {
+ printf("Usage:\n");
+ printUsage(argv[0]);
+ exit(1);
+ }
+
+ for(;;) {
+ opterr = 0;
+ c = getopt(argc, argv, "d:b:f:l:a:h");
+ if(c < 0)
+ break;
+ switch(c) {
+ case 'd':
+ snprintf(devPort, 200, "%s", optarg);
+ printf("receiver port: %s\n", devPort);
+ paraMask &= ~1;
+ break;
+ case 'b':
+ baud = atoi(optarg);
+ printf("baud rate: %d\n", baud);
+ break;
+ case 'f':
+ snprintf(fw, 200, "%s", optarg);
+ printf("firmware: %s\n", fw);
+ paraMask &= ~4;
+ break;
+ case 'l':
+ snprintf(bl, 200, "%s", optarg);
+ printf("bootloader: %s\n", bl);
+ paraMask &= ~8;
+ break;
+ case 'a':
+ snprintf(ap, 200, "%s", optarg);
+ printf("apdata file: %s\n", ap);
+ paraMask &= ~16;
+ break;
+ case 'h':
+ default:
+ printf("Usage:\n");
+ if (func == 1)
+ printGetapUsage(argv[0]);
+ else if (func == 2)
+ printSendapUsage(argv[0]);
+ else if (func == 3)
+ printDownloadblUsage(argv[0]);
+ else if (func == 4)
+ printDownloadfwUsage(argv[0]);
+ else if (func == 5)
+ printCheckapUsage(argv[0]);
+ else
+ printUsage(argv[0]);
+ exit(1);
+ }
+ }
+ if (paraMask) {
+ if (func == 1)
+ printGetapUsage(argv[0]);
+ else if (func == 2)
+ printSendapUsage(argv[0]);
+ else if (func == 3)
+ printDownloadblUsage(argv[0]);
+ else if (func == 4)
+ printDownloadfwUsage(argv[0]);
+ else if (func == 5)
+ printCheckapUsage(argv[0]);
+ else
+ printUsage(argv[0]);
+ exit(1);
+ }
+
+ // Open serial port
+ if (func != 5) {
+ if ((fd = initial_serialPort(devPort)) == -1)
+ {
+ printf("Can't open COM\n");
+ return UART_DEV_ERR;
+ }
+ if (baud == 115200) {
+ set_baudrate(fd, B115200);
+ } else if (baud == 921600) {
+ set_baudrate(fd, B921600);
+ } else if (baud == 1843200) {
+ set_baudrate(fd, B1500000);
+ } else {
+ printf("baudrate %d not supported\n", baud);
+ close(fd);
+ exit(1);
+ }
+ }
+
+ // execute function
+ switch(func) {
+ case 1:
+ ret = getAPData(fd, ap);
+ break;
+ case 2:
+ ret = sendAPData(fd, ap);
+ break;
+ case 3:
+ ret = downloadBL(fd, bl);
+ break;
+ case 4:
+ ret = downloadFW(fd, fw);
+ break;
+ case 5:
+ ret = checkAPData(ap);
+ break;
+ default:break;
+ }
+ close(fd);
+ return ret;
+
+}
+
+int getAPData(int fd, char *file)
+{
+ int rByte = 0;
+ char rbuf[4096];
+ int ret = 0, i;
+ struct timeval time_m, time_n;
+
+ if (NULL == file) {
+ printf("Please input file!! \n");
+ return 1;
+ }
+ if (!fd)
+ return 1;
+ printf("Get apdata\n");
+ gps_dev_send(fd, "$ReqRecvFlash\r\n");
+ af_start_receive();
+ GET_TIME();
+ while(1) {
+ CHK_TIME();
+ if(select_read(fd,1) > 0)
+ usleep(50000);
+ else
+ continue;
+
+ rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+ if(rByte >= 1){
+ if(af_is_start_receive()) {
+ for(i = 0; i < rByte; i++)
+ af_add_char(file, rbuf[i]);
+ } else {
+ break;
+ }
+ }
+ }
+
+ checkAPData(file);
+ return 0;
+}
+
+int sendAPData(int fd, char *apFile)
+{
+ int rByte = 0;
+ char rbuf[4096];
+ int ret = 0;
+ struct timeval time_m, time_n;
+
+ if(access(apFile, F_OK) != -1)
+ {
+ // Download APData only if the file exits
+ printf("Download APData...\n");
+ if(xmodem_send(fd, apFile))
+ {
+ printf("xmodem error!\n");
+ close(fd);
+ return ENTER_UPDATE_MODE_ERR;
+ }
+ // Waiting for 'C'
+ GET_TIME();
+ while(1)
+ {
+ CHK_TIME();
+ if(select_read(fd,1) > 0)
+ usleep(500000);
+ else
+ continue;
+ rByte = deal_read(fd,&rbuf,sizeof(rbuf)-1);
+ rbuf[rByte] = 0;
+ if(rByte > 0)
+ {
+ if(rbuf[rByte - 1] == 'C')
+ break;
+ }
+ }
+ printf("download APData success\n");
+ }
+ else
+ {
+ printf("file err!\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int checkAPData(char *apFile)
+{
+ printf("Checking %s\n", apFile);
+ if(check_file(apFile))
+ {
+ printf("file error!\n");
+ return FILE_CHECK_ERR;
+
+ }
+ else
+ {
+ printf("pass\r\n");
+ }
+ return 0;
+}
+
+int downloadFW(int fd, char *fw)
+{
+ int ret;
+ struct timeval time_m, time_n;
+ char rbuf[512];
+
+ if(NULL == fw) {
+ printf("Error: Can't find firmware.\n");
+ return -1;
+ }
+ printf("Download firmware...\n");
+ if(xmodem_send(fd, fw) < 0) {
+ printf("xmodem error! send firmware failed!\n");
+ close(fd);
+ return UPDATE_ERR;
+ }
+
+ printf("Download firmware success\n");
+ return 0;
+}
+
+int downloadBL(int fd, char *bl)
+{
+ int rByte = 0;
+ char rbuf[4096];
+ char name[128];
+ int ret = 0;
+ struct timeval time_m, time_n;
+
+ if(NULL == bl) {
+ printf("Error: Can't find bootloader.\n");
+ return -1;
+ }
+ printf("------Please Powerdown the receiver!\n");
+ mopen_open_gps(0);
+ SET_TIME_OUT(3);
+ while(1) {
+ DELAY_TIME_BREAK(); //
+ if(select_read(fd,1) > 0)
+ usleep(50000);
+ else
+ continue;
+
+ rByte = deal_read(fd,&rbuf,sizeof(rbuf));
+ }
+ int start = 0,finish = 0;
+
+ memset(name, 0, sizeof(name));
+ sprintf(name,"M!T");
+ printf("waiting for YC, timeout is %d s\n", TIMEOUT_SEC);
+ printf("-------Please Powerup the receiver!\n");
+ mopen_open_gps(1);
+ // Waiting for 'YC'
+ GET_TIME();
+ while(1) {
+ int finish = 0, i;
+ CHK_TIME_BREAK(); //
+ rByte = write( fd, name, strlen(name));
+ rByte = select_read(fd,1);
+ if(rByte <= 0)
+ continue;
+ rByte = deal_read(fd, rbuf, sizeof(rbuf) - 1);
+ rbuf[rByte] = 0;
+ for (i = 0 ; i < rByte; i++)
+ {
+ if (check_YC(rbuf[i])) {
+ printf("Receive 'YC'\n");
+ finish = 1;
+ break;
+ }
+ }
+ if (finish)
+ break;
+ }
+ //wait 'YC' timeout deal
+ if (timeout_sign == 1)
+ {
+ //wait NAK
+ GET_TIME();
+ while(1)
+ {
+ CHK_TIME();
+ if(select_read(fd,1) <= 0)
+ continue;
+
+ rByte = deal_read(fd, rbuf,sizeof(rbuf));
+ if (rbuf[rByte-1] == 'C')
+ {
+ printf("###read xmodem start character 'C'.\n");
+ break;
+ }
+ }
+ }
+ use_select = 1;
+ printf("download bootloader...\n");
+
+ // Transfer bootloader via xmodem protocal
+ // if(xmodem_send(fd, "./bootloader.bin")) {
+ if(xmodem_send(fd, bl)) {
+ printf("xmodem error!\n");
+ close(fd);
+ return ENTER_UPDATE_MODE_ERR;
+ }
+ printf("download bootloader success\n");
+ return 0;
+}
+
+int check_YC(char newchar)
+{
+ int static state = 0;
+ int ret = 0;
+ switch (state) {
+ case 0:
+ if (newchar == 'Y')
+ state = 1;
+ break;
+ case 1:
+ if (newchar == 'C') {
+ state = 1;
+ ret = 1;
+ }
+ break;
+ default:
+ state = 0;
+ }
+ return ret;
+}
+
+const unsigned short CRC16_Table[256] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+unsigned short crc16_ccitt(const unsigned char *buf, int len)
+{
+ register int counter;
+ register unsigned short crc = 0;
+ for (counter = 0; counter < len; counter++)
+ crc = (crc << 8) ^ CRC16_Table[((crc >> 8) ^ *(char *)buf++) & 0x00FF];
+ return crc;
+}
+
+
+unsigned int checksum32(unsigned int * pbuf, unsigned int len)
+{
+ unsigned int i, sumValue = 0;
+ len >>=2;
+
+ for(i=0;i<len;i++)
+ {
+ sumValue += *pbuf++;
+ }
+ return sumValue;
+}
+
+void af_start_receive()
+{
+ recvStat = WAIT_FD;
+ isStartReceive = 1;
+ return;
+}
+
+void af_stop_receive()
+{
+ int i;
+ printf("%s:%d\r\n", __FUNCTION__, __LINE__);
+ printf("%s:%d recvStat = %d\r\n", __FUNCTION__, __LINE__, recvStat);
+ pbuf = (unsigned char *)recv_buf;
+ for(i = 0; i < 4636; i++){
+ if(i % 32 == 0)printf("\r\n");
+ printf("%02X ", pbuf[i]);
+ }
+ printf("\r\n");
+ isStartReceive = 0;
+ return;
+}
+
+int af_is_start_receive()
+{
+ return isStartReceive;
+}
+
+int af_check_header(unsigned char *pbuf, unsigned int len)
+{
+ unsigned int crc = crc16_ccitt(pbuf, len-4);
+
+ if(crc == *(unsigned int *)(pbuf + len - 4))
+ return 1;
+ else
+ return 0;
+}
+
+int af_check_data(unsigned int * pbuf, unsigned int len)
+{
+ unsigned int cs = checksum32(pbuf + 8, len);
+ if(cs == pbuf[1])
+ return 1;
+ else
+ return 0;
+}
+
+int af_get_data_len()
+{
+ int len = *(int *)(recv_buf+3);
+ return len;
+}
+
+int af_add_char(char *file, unsigned char c)
+{
+ int ret = 0;
+ switch(recvStat){
+ case WAIT_FD:
+ if(c == 0xfd){
+ pbuf = (unsigned char *)recv_buf;
+ pbuf[0] = c;
+ recvStat = WAIT_FC;
+ printf("------------received 0xfd\r\n");
+ }
+ break;
+ case WAIT_FC:
+ if(c == 0xfc){
+ pbuf[1] = c;
+ recvStat = WAIT_FB;
+ printf("------------received 0xfc\r\n");
+ }else{
+ af_stop_receive();
+ }
+ break;
+ case WAIT_FB:
+ if(c == 0xfb){
+ pbuf[2] = c;
+ recvStat = WAIT_FA;
+ printf("------------received 0xfb\r\n");
+ }else{
+ af_stop_receive();
+ }
+ break;
+ case WAIT_FA:
+ if(c == 0xfa){
+ pbuf[3] = c;
+ recvStat = RECE_HEADER;
+ pbuf += 4;
+ printf("------------received 0xfa\r\n");
+ }else{
+ af_stop_receive();
+ }
+ break;
+ case RECE_HEADER:
+ *pbuf = c;
+ pbuf++;
+ if((pbuf - (unsigned char *)recv_buf) == HEADERLEN){
+ if(af_check_header((unsigned char *)recv_buf, HEADERLEN)){
+ recvStat = RECE_DATA;
+ data_len = af_get_data_len();
+ }else{
+ af_stop_receive();
+ }
+ }
+ break;
+ case RECE_DATA:
+ *pbuf = c;
+ pbuf++;
+ if((pbuf - (unsigned char *)recv_buf) == data_len + HEADERLEN){
+ if(af_check_data(recv_buf, recv_buf[3])){
+ int fd = open(file, O_WRONLY|O_CREAT, S_IRWXU);
+ write(fd, recv_buf, pbuf - (unsigned char *)recv_buf);
+ printf("%s:%d rtm len = %ld\r\n", __FUNCTION__, __LINE__, pbuf-(unsigned char *)recv_buf);
+ close(fd);
+ printf("receive rtm\n");
+ }else{
+ printf("af_check_data false!");
+ }
+ af_stop_receive();
+ }
+ ret = 1;
+ break;
+ default:
+ printf("%s:recvStat = %d\r\n", __FUNCTION__, recvStat);
+ break;
+ }
+ return ret;
+}
+
+
+
+ssize_t deal_read(int fd, void *buf, size_t count)
+{
+ int ret = 0;
+
+ while (1)
+ {
+ ret = read(fd, buf, count);
+ if (ret == 0)
+ {
+ printf("read serial return 0, please check serial device.\n");
+ exit(UART_DEV_ERR);
+ }
+ if(ret < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ {
+ printf("read serial return -1, errno = %d, retry.\n", errno);
+ continue;
+ }
+ else
+ {
+ printf("read serial return -1, errno = %d, please check serial device.\n", errno);
+ exit(UART_DEV_ERR);
+ }
+ }
+ return ret;
+ }
+}
+
+unsigned short get_crc16 ( char *ptr, unsigned short count )
+{
+ unsigned short crc, i;
+
+ crc = 0;
+ while(count--)
+ {
+ crc = crc ^ (int) *ptr++ << 8;
+
+ for(i = 0; i < 8; i++)
+ {
+ if(crc & 0x8000)
+ crc = crc << 1 ^ 0x1021;
+ else
+ crc = crc << 1;
+ }
+ }
+
+ return (crc & 0xFFFF);
+}
+
+void dump_u(void *buf, int len)
+{
+ unsigned char *p = (unsigned char *)buf;
+ int i;
+
+ for(i = 0; i < len; i++) {
+ if(i % 16 == 0) printf("%04x:", i);
+ if(i % 16 == 8) printf(" -");
+ printf(" %02x", p[i]);
+ if(i % 16 == 15) printf("\n");
+ }
+ if(i % 16) printf("\n");
+}
+
+unsigned int get_file_size(const char * name)
+{
+ struct stat statbuff;
+ //unsigned int size, checksum;
+ if(stat(name, &statbuff) < 0)
+ return -1;
+ else
+ return statbuff.st_size;
+}
+
+
+int check_file(char * fname)
+{
+ FILE *fd;
+ uc_image_header_t header;
+ unsigned int buf[1024];
+ unsigned int fsize, checksum, i;
+ unsigned int len;
+ unsigned short crc;
+ size_t rByte;
+
+ if((fd=fopen(fname,"rb"))==NULL)
+ {
+ printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+ return -1;
+ }
+
+ fsize = get_file_size(fname);
+
+ printf("file size [%d]\n",fsize);
+
+ if(fsize == 0)
+ return -1;
+
+ while(fsize > sizeof(header)) {
+ rByte = fread((char *)&header, sizeof(char), sizeof(header), fd);
+
+ dump_u((char *)&header, sizeof(header));
+
+ crc = get_crc16 ( (char *) &header, sizeof(header)-4);
+ printf("crc16 [%08x]\n", crc);
+
+ if((header.ih_hcrc & 0xFFFF) != crc) {
+ fclose(fd);
+ return -1;
+ }
+
+ fsize -= sizeof(header);
+ fsize -= header.ih_size;
+ checksum = 0;
+ len = header.ih_size;
+ while(len > 0)
+ {
+ if(len >= 1024 )
+ rByte = 1024;
+ else
+ rByte = len;
+
+ memset(buf, 0, sizeof(buf));
+ rByte = fread((char *)buf, 1, rByte, fd);
+ for(i = 0; i < (rByte+3)/4; i++)
+ checksum += buf[i];
+
+ len -= rByte;
+ }
+ printf("checksum [%08x]\n\n",checksum);
+
+ if( checksum != header.ih_dcrc) {
+ fclose(fd);
+ return -1;
+ }
+ }
+
+ fclose(fd);
+ return 0;
+}
+
+static int select_read(int fd, int timeout) //1ms
+{
+ fd_set set;
+ struct timeval t;
+ int ret;
+ int i = timeout;
+
+ if(use_select) {
+ do {
+ FD_ZERO(&set);
+ FD_SET(fd, &set);
+ t.tv_sec = 0;
+ t.tv_usec = 100;
+
+ ret = select(FD_SETSIZE, &set, NULL, NULL, &t );
+ if(ret == 0) continue;
+ if(ret < 0 && errno == EINTR)continue;
+ else return ret;
+ } while(i--);
+ } else {
+ struct timeval t0, t1;
+ long dt = 0;
+ int c;
+
+ gettimeofday(&t0, NULL);
+ do {
+ c = 0;
+ ret = ioctl(fd, FIONREAD, &c);
+ if(c > 0) { ret = c; break; }
+
+ gettimeofday(&t1, NULL);
+ dt = t1.tv_usec - t0.tv_usec;
+ dt += (t1.tv_sec-t0.tv_sec)*1000*1000;
+ } while(dt/1000 < timeout);
+ }
+
+ return ret;
+}
+
+int set_baudrate(int fd, int baudrate)
+{
+ struct termios options, oldtio;
+
+ if(fcntl(fd, F_SETFL, 0) < 0) {
+ printf("fcntl failed!\n");
+ return -1;
+ }
+
+ if(tcgetattr(fd, &oldtio) != 0) {
+ printf("setup serial error!\n");
+ return -1;
+ }
+
+ /* Get the current options for the port... */
+ tcgetattr(fd, &options);
+
+ /* Set the baud rates to baudrate... */
+ cfsetispeed(&options,baudrate);
+ cfsetospeed(&options,baudrate);
+ tcsetattr(fd, TCSANOW, &options);
+
+ if (0 != tcgetattr(fd, &options))
+ {
+ printf("get options error!\n");
+ return -1;
+ }
+
+ /*
+ * 8bit Data,no partity,1 stop bit...
+ */
+ options.c_cflag &= ~PARENB;//无奇偶校验
+ options.c_cflag &= ~CSTOPB;//停止位,1位
+ options.c_cflag &= ~CSIZE; //数据位的位掩码
+ options.c_cflag |= CS8; //数据位,8位
+
+ cfmakeraw(&options);
+
+ /*
+ * Set the new options for the port...
+ */
+ if (tcsetattr(fd, TCSANOW, &options) != 0)
+ {
+ printf("setup serial error!\n");
+ return -1 ;
+ }
+
+ return 0 ;
+}
+
+int initial_serialPort(char * serial_device)
+{
+ int fd;
+ fd = open( serial_device , O_RDWR );
+ if ( fd == -1 )
+ {
+ /* open error! */
+ printf("Can't open serial port(%s)!(errno=%d:%s) \n", serial_device, errno, strerror(errno));
+ return -1;
+ }
+
+ set_baudrate(fd, B9600);
+
+ return fd ;
+}
+
+static void gps_dev_send(int fd, char *msg)
+{
+ int i, n, ret;
+
+ i = strlen(msg);
+
+ n = 0;
+
+ printf("function gps_dev_send: %s", msg);
+ do {
+
+ ret = write(fd, msg + n, i - n);
+
+ if (ret < 0 && errno == EINTR) {
+ continue;
+ }
+
+ n += ret;
+
+ } while (n < i);
+
+ // drain cmd
+ tcdrain(fd);
+
+ return;
+}
+
+int xmodem_send(int fd, char *fname)
+{
+ char packet_data[XMODEM_DATA_SIZE];
+ char frame_data[XMODEM_DATA_SIZE + XMODEM_CRC_SIZE + XMODEM_FRAME_ID_SIZE + 1];
+ int ret = -1;
+
+ FILE *datafile;
+ int complete,retry_num,pack_counter,read_number,write_number,i;
+ unsigned short crc_value;
+ unsigned char ack_id = 'C';
+ struct timeval time_m, time_n;
+
+ datafile = NULL;
+ pack_counter = 0; // 包计数器清零
+ complete = 0;
+ retry_num = 0;
+
+ printf("[%s]\n",fname);
+ //只读方式打开一个准备发送的文件,如果不存在就报错,退出程序。
+ if((datafile=fopen(fname,"rb"))==NULL)
+ {
+ printf("\n can't open (%s) or not exist!(errno=%d:%s) \n", fname, errno, strerror(errno));
+ return -1;
+ }
+ else
+ {
+ printf("Ready to send the file:%s\n",fname);
+ }
+
+ printf("Waiting for signal C/NAK!\n");
+ GET_TIME();
+ while(1)
+ {
+ CHK_TIME1();
+ if(select_read(fd,1) > 0)
+ usleep(10000);
+ else
+ continue;
+
+ //read(fd,&ack_id,1);
+ deal_read(fd,&ack_id,1);
+ if(ack_id == 'C')
+ break;
+ }
+
+ printf("The signal NAK: %02x ok!!!\n",ack_id);//打印接收到的NAK信息
+
+ while(!complete)
+ {
+ switch(ack_id)
+ {
+ case XMODEM_CRC_CHR: // 接收到字符'C'开始启动传输,并使用CRC校验
+ printf("begining to Send file %s...\n",fname);
+
+ case XMODEM_ACK: //0x06
+ retry_num = 0;
+ pack_counter++;
+
+ read_number = fread(packet_data, sizeof(char), XMODEM_DATA_SIZE, datafile);
+ //从打开的datafile指向的文件中读取
+ //XMODEM_DATA_SIZE 个(char)数据,
+ //放到packet_data这个数组中
+ if(read_number > 0)//read_number为返回的读取实际字节数
+ {
+ //printf("test:read_number:%d\n", read_number);
+ if(read_number < XMODEM_DATA_SIZE_STX)
+ {
+ printf("Start filling the last frame!\n");
+ for(; read_number < XMODEM_DATA_SIZE; read_number++)
+ packet_data[read_number] = 0x1A; // 不足128字节用0x1A填充
+ //printf("replenish data.\n");
+ }
+
+ frame_data[0] = XMODEM_HEAD; // 帧开始字符
+ frame_data[1] = (char)pack_counter; // 信息包序号
+ frame_data[2] = (char)(255 - frame_data[1]); // 信息包序号的补码
+
+ for(i=0; i < XMODEM_DATA_SIZE; i++) // 128字节的数据段
+ frame_data[i+3] = packet_data[i];//把收到的字符和信息头一起打包
+
+ crc_value = get_crc16(packet_data, XMODEM_DATA_SIZE); // 16位crc校验
+ frame_data[XMODEM_DATA_SIZE+3] = (unsigned char)(crc_value >> 8);// 高八位数据
+ frame_data[XMODEM_DATA_SIZE+4] = (unsigned char)(crc_value); //低八位数据
+
+ /* 发送133字节数据 */
+ write_number = write( fd, frame_data, XMODEM_DATA_SIZE + 5);//向串口写一个包数据,即133字节数据
+ printf("."); //ADD: process
+ fflush(stdout);
+ //printf("waiting for next ACK... \n......\n");
+
+ GET_TIME();
+ while(1)
+ {
+ CHK_TIME1();
+ if(select_read(fd,1) > 0)
+ usleep(10000);
+ else
+ continue;
+
+ //read(fd,&ack_id,1);
+ deal_read(fd,&ack_id,1);
+ break;
+ }
+
+ if(ack_id == XMODEM_ACK) {
+ //printf("ACK Ok!!Ready sending next pack!\n");
+ ;
+ }
+ else
+ {
+ printf("ACK Error!\n");
+ printf("0x%02X\n",ack_id);
+ //printf("pack_counter = %d\n", pack_counter);
+ }
+ }
+
+ else // 文件发送完成
+ {
+ ack_id = XMODEM_EOT;
+ complete = 1;
+ printf("Complete ACK\n");
+
+ GET_TIME();
+ while(ack_id != XMODEM_ACK)
+ {
+ CHK_TIME1();
+ ack_id = XMODEM_EOT;
+ write_number = write(fd,&ack_id,1);
+ while((deal_read(fd, &ack_id, 1)) <= 0);
+ }
+ printf("Send file successful!!!\n");
+ fclose(datafile);
+ datafile = NULL;
+ }
+ break;
+
+ case XMODEM_NAK:
+ if( retry_num++ > 10)
+ {
+ printf("Retry too many times,Quit!\n");
+ complete = 1;
+ }
+ else //重试,发送
+ {
+ write_number = write(fd, frame_data, XMODEM_DATA_SIZE + 5);
+ printf("Retry for ACK,%d,%d...", pack_counter, write_number);
+
+ GET_TIME();
+ while(1)
+ {
+ CHK_TIME1();
+ if(select_read(fd,1) > 0)
+ usleep(100);
+ else
+ continue;
+
+ //read(fd,&ack_id,1);
+ deal_read(fd,&ack_id,1);
+ break;
+ }
+
+ if( ack_id == XMODEM_ACK )
+ printf("OK\n");
+ else
+ printf("Error!\n");
+ }
+ break;
+ default:
+ printf("Fatal Error! %d\n", ack_id);
+ complete = 1;
+ return -1;
+ break;
+ }
+ }
+
+ if( datafile != NULL )
+ fclose(datafile);
+
+ return 0;
+}
diff --git a/mbtk/libmbtk_lib/http/mbtk_http.c b/mbtk/libmbtk_lib/http/mbtk_http.c
new file mode 100755
index 0000000..f83ae35
--- /dev/null
+++ b/mbtk/libmbtk_lib/http/mbtk_http.c
@@ -0,0 +1,1396 @@
+/*************************************************************
+Description:
+ MBTK HTTP c file.
+Author:
+ LiuBin
+Date:
+ 2020/4/30 13:51:42
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "mbtk_http_base.h"
+#include "mbtk_http.h"
+#include "mbtk_http_chunks.h"
+
+/*************************************************************
+ Constants and Macros
+*************************************************************/
+
+/*************************************************************
+ Variables:local
+*************************************************************/
+static mbtk_http_handle_t http_handles[HTTP_HANDLE_MAX] =
+{
+ {
+ .id = -1,
+ .data_cb = NULL,
+ .session_cnt = 0,
+ .session = {NULL}
+ }
+};
+
+/*************************************************************
+ Variables:public
+*************************************************************/
+
+
+/*************************************************************
+ Local Function Declaration
+*************************************************************/
+
+
+/*************************************************************
+ Local Function Definitions
+*************************************************************/
+static void http_session_free(mbtk_http_session_t *session)
+{
+ if(session)
+ {
+ if(session->req.header_cnt > 0)
+ {
+ int index;
+ for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
+ {
+ if(session->req.req_h[index] != NULL)
+ {
+ if(session->req.req_h[index]->value)
+ free(session->req.req_h[index]->value);
+ free(session->req.req_h[index]);
+ session->req.req_h[index] = NULL;
+ }
+ }
+ session->req.header_cnt = 0;
+ }
+
+ if(session->req.content)
+ {
+ free(session->req.content);
+ session->req.content = NULL;
+ }
+
+ if(session->rsp.header_cnt > 0)
+ {
+ int index;
+ for(index = 0; index < HTTP_REQUEST_HEADER_MAX; index++)
+ {
+ if(session->rsp.rsp_h[index] != NULL)
+ {
+ if(session->rsp.rsp_h[index]->value)
+ free(session->rsp.rsp_h[index]->value);
+ free(session->rsp.rsp_h[index]);
+ session->rsp.rsp_h[index] = NULL;
+ }
+ }
+ session->rsp.header_cnt = 0;
+ }
+
+ free(session);
+ }
+}
+
+static int http_session_close(mbtk_http_session_t *session)
+{
+ if(session)
+ {
+ if(session->sock_fd > 0)
+ {
+ if(mbtk_http_close(session->sock_fd))
+ {
+ LOGE("mbtk_http_close() fail.");
+ return -1;
+ }
+ session->sock_fd = -1;
+ }
+
+ session->state = HTTP_SESSION_STATE_NON;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static bool http_handle_check(int handle_id)
+{
+ if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
+ || http_handles[handle_id].id < 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool http_session_check(int handle_id, int session_id)
+{
+ if(handle_id < 0 || handle_id >= HTTP_HANDLE_MAX
+ || http_handles[handle_id].id < 0
+ || http_handles[handle_id].id != handle_id)
+ {
+ return FALSE;
+ }
+
+ if(session_id < 0 || session_id >= HTTP_SESSION_MAX
+ || http_handles[handle_id].session[session_id] == NULL
+ || http_handles[handle_id].session[session_id]->id != session_id)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bool http_is_space_char(char ch)
+{
+ if(ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n')
+ return TRUE;
+
+ return FALSE;
+}
+
+static bool http_str_empty(char *str)
+{
+ if(str == NULL || strlen(str) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+
+static int http_url_parse
+(
+ void* url,
+ void *host,
+ void *uri,
+ int *port,
+ bool *is_ssl
+)
+{
+ if(strlen(url) == 0)
+ {
+ return -1;
+ }
+ char *url_ptr = (char*)url;
+ char *host_ptr = (char*)host;
+
+ LOGI("URL[%d]:%s",strlen(url_ptr),url_ptr);
+
+ if(!memcmp(url_ptr,"https://",8))
+ {
+ *is_ssl = TRUE;
+ url_ptr += 8;
+ }
+ else if(!memcmp(url_ptr,"http://",7))
+ {
+ *is_ssl = FALSE;
+ url_ptr += 7;
+ }
+ else
+ {
+ *is_ssl = FALSE;
+ }
+
+ // ptr point to host.
+ while(*url_ptr)
+ {
+ if(*url_ptr == ':' || *url_ptr == '/') // Host end
+ break;
+ if(http_is_space_char(*url_ptr))
+ {
+ url_ptr++;
+ continue;
+ }
+ *host_ptr++ = *url_ptr++;
+ }
+
+ // "www.baidu.com"
+ if(*url_ptr == '\0') // No port and uri
+ {
+ if(*is_ssl)
+ {
+ *port = MBTK_HTTPS_PORT_DEF;
+ }
+ else
+ {
+ *port = MBTK_HTTP_PORT_DEF;
+ }
+ memcpy(uri,"/",1);
+
+ LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+ return 0;
+ }
+ else
+ {
+ //LOGI("Host end with:%x",*url_ptr);
+ if(*url_ptr == ':') // Port exist.
+ {
+ *port = atoi(url_ptr + 1);
+
+ // Point to '/' or NULL
+ while(*url_ptr && *url_ptr != '/')
+ {
+ url_ptr++;
+ }
+
+ // "www.baidu.com:80"
+ if(*url_ptr == '\0') // No uri
+ {
+ if(*port == 0)
+ {
+ if(*is_ssl)
+ {
+ *port = MBTK_HTTPS_PORT_DEF;
+ }
+ else
+ {
+ *port = MBTK_HTTP_PORT_DEF;
+ }
+ }
+ memcpy(uri,"/",1);
+
+ LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+ return 0;
+ }
+ }
+
+ // "www.baidu.com/xxx" or "www.baidu.com:80/xxx"
+ // Now,url_ptr point to '/'
+ if(*url_ptr != '/')
+ {
+ LOGE("URI must start with '/'.");
+ return -1;
+ }
+
+ //LOGI("URL3[%d]:%s",strlen(url_ptr),url_ptr);
+
+ memcpy(uri,url_ptr,strlen(url_ptr));
+
+ if(*port == 0)
+ {
+ if(*is_ssl)
+ {
+ *port = MBTK_HTTPS_PORT_DEF;
+ }
+ else
+ {
+ *port = MBTK_HTTP_PORT_DEF;
+ }
+ }
+
+ LOGI("HTTP parse success:'%s','%s', %d, %d",(char*)host,(char*)uri,*port,*is_ssl);
+ return 0;
+ }
+}
+
+static int http_session_req_head_add(mbtk_http_session_t *session,bool replace,
+ char *name, char *value)
+{
+ if(session == NULL || value == NULL)
+ return -1;
+
+ LOGI("Add request header - %s:%s",name,value);
+
+ int i = 0;
+ while(i < HTTP_REQUEST_HEADER_MAX)
+ {
+ if(session->req.req_h[i]
+ && !strncasecmp(session->req.req_h[i]->name,name,strlen(name))) // Is change value
+ {
+ break;
+ }
+ i++;
+ }
+
+ if(i == HTTP_REQUEST_HEADER_MAX) // Should add new header.
+ {
+ i = 0;
+ while(i < HTTP_REQUEST_HEADER_MAX)
+ {
+ if(session->req.req_h[i] == NULL) // Find NULL request.
+ {
+ session->req.req_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
+ if(session->req.req_h[i] == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+
+ memset(session->req.req_h[i],0x0,sizeof(mbtk_http_header_t));
+ memcpy(session->req.req_h[i]->name, name, strlen(name));
+ session->req.req_h[i]->value = NULL;
+ session->req.header_cnt++;
+ break;
+ }
+ i++;
+ }
+ }
+ else // Is change value
+ {
+ if(!replace)
+ {
+ LOGW("Found this header[%s],no replace.",name);
+ return 0;
+ }
+ }
+
+ if(i == HTTP_REQUEST_HEADER_MAX)
+ {
+ LOGE("Request header is full.");
+ return -1;
+ }
+
+ if(session->req.req_h[i]->value)
+ {
+ free(session->req.req_h[i]->value);
+ }
+ session->req.req_h[i]->value = (char*)malloc(strlen(value) + 1);
+ if(session->req.req_h[i]->value == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+ memset(session->req.req_h[i]->value,0x0,strlen(value) + 1);
+ memcpy(session->req.req_h[i]->value,value,strlen(value));
+
+ return 0;
+}
+
+#if 0
+static int http_session_rsp_head_add(mbtk_http_session_t *session,
+ char *name, char *value)
+{
+ if(session == NULL || value == NULL)
+ return -1;
+
+ int i = 0;
+ while(i < HTTP_REQUEST_HEADER_MAX)
+ {
+ if(session->rsp.rsp_h[i] == NULL) // Find NULL request.
+ {
+ session->rsp.rsp_h[i] = (mbtk_http_header_t*)malloc(sizeof(mbtk_http_header_t));
+ if(session->rsp.rsp_h[i] == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+
+ memcpy(session->rsp.rsp_h[i]->name,name,strlen(name));
+ session->rsp.rsp_h[i]->value = (char*)malloc(strlen(value) + 1);
+ if(session->rsp.rsp_h[i]->value == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+ memset(session->rsp.rsp_h[i]->value,0x0,strlen(value) + 1);
+ memcpy(session->rsp.rsp_h[i]->value,value,strlen(value));
+
+ session->rsp.header_cnt++;
+ return 0;
+ }
+ i++;
+ }
+
+ return -1;
+}
+#endif
+
+static char* http_option_str_get(mbtk_http_option_enum option)
+{
+ switch(option)
+ {
+ case HTTP_OPTION_HEAD:
+ return "HEAD";
+ case HTTP_OPTION_GET:
+ return "GET";
+ case HTTP_OPTION_POST:
+ return "POST";
+ case HTTP_OPTION_PUT:
+ return "PUT";
+ case HTTP_OPTION_DELETE:
+ return "DELETE";
+ case HTTP_OPTION_OPTIONS:
+ return "OPTIONS";
+ case HTTP_OPTION_TRACE:
+ return "TRACE";
+ case HTTP_OPTION_CONNECT:
+ return "CONNECT";
+ case HTTP_OPTION_LINK:
+ return "LINK";
+ case HTTP_OPTION_UNLINK:
+ return "UNLINK";
+ default:
+ return "";
+ }
+}
+
+static char* http_version_str_get(mbtk_http_version_enum version)
+{
+ switch(version)
+ {
+ case HTTP_VERSION_1_0:
+ return "1.0";
+ case HTTP_VERSION_1_1:
+ return "1.1";
+ case HTTP_VERSION_2:
+ return "2";
+ case HTTP_VERSION_3:
+ return "3";
+ default:
+ return "";
+ }
+}
+
+static char* http_header_find(mbtk_http_session_t *session,char* name)
+{
+ int i = 0;
+ while(i < HTTP_REQUEST_HEADER_MAX)
+ {
+ if(session->req.req_h[i] &&
+ !strncasecmp(session->req.req_h[i]->name,name,strlen(name)))
+ {
+ return session->req.req_h[i]->value;
+ }
+
+ i++;
+ }
+ return NULL;
+}
+
+static int http_header_str_get(mbtk_http_header_t *header,char *header_str,int header_str_len)
+{
+ if(header == NULL || header->value == NULL
+ || header_str == NULL)
+ return 0;
+
+ int len = 0;
+ len = snprintf(header_str,header_str_len,"%s: %s\r\n",
+ header->name, header->value);
+
+ return len;
+}
+
+static mbtk_http_version_enum http_version_get_by_str(char *version_str)
+{
+ if(!memcmp(version_str,"1.0",3))
+ return HTTP_VERSION_1_0;
+ else if(!memcmp(version_str,"1.1",3))
+ return HTTP_VERSION_1_1;
+ else if(!memcmp(version_str,"2",1))
+ return HTTP_VERSION_2;
+ else if(!memcmp(version_str,"3",1))
+ return HTTP_VERSION_3;
+ else
+ return HTTP_VERSION_1_1;
+}
+
+static int http_header_read(mbtk_http_session_t *session)
+{
+#define BUFFER_SIZE 2048
+ char line[BUFFER_SIZE];
+ char *ptr = NULL;
+ int len = 0;
+ while((len = mbtk_http_read_line(session->sock_fd,line,BUFFER_SIZE)) > 0)
+ {
+ if(!memcmp(line,"\r\n",2))
+ {
+ LOGD("Read empty line.");
+ break;
+ }
+
+ // Delete "\r\n"
+ ptr = line + len - 1; // Point to last char.
+ while(http_is_space_char(*ptr))
+ {
+ *ptr = '\0';
+ len--;
+ ptr--;
+ }
+
+ LOGV("LINE:%s",line);
+
+ if(http_handles[session->handle_id].show_rsp_header &&
+ http_handles[session->handle_id].data_cb)
+ {
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_HEADER,line,len);
+ }
+
+ if(!memcmp(line,"HTTP/",5)) // "HTTP/1.1 200 OK"
+ {
+ session->rsp.state_code = atoi(line + 9);
+ session->rsp.version = http_version_get_by_str(line + 5);
+ }
+ else // Is response header item.
+ {
+ if(!strncasecmp(line,"Content-Length",14))
+ {
+ ptr = line + 14;
+ while(ptr && !isdigit(*ptr))
+ {
+ ptr++;
+ }
+
+ if(ptr)
+ {
+ session->rsp.content_length = atol(ptr);
+ }
+ }
+ else if(!strncasecmp(line,"Transfer-Encoding",17))
+ {
+ ptr = line + 17;
+ while(ptr && !isalpha(*ptr))
+ {
+ ptr++;
+ }
+
+ if(ptr && !memcmp(ptr,"chunked",7))
+ {
+ session->rsp.is_chunked = TRUE;
+ }
+ }
+ }
+ }
+#undef BUFFER_SIZE
+
+ LOGD("RSP:HTTP/%s %d, is_chunked:%d,Content-Length:%d",http_version_str_get(session->rsp.version),
+ session->rsp.state_code,session->rsp.is_chunked,session->rsp.content_length);
+
+ return 0;
+}
+
+static int http_session_start_write(mbtk_http_session_t *session)
+{
+ LOGI("Start HTTP write.");
+
+#define BUFFER_SIZE 1024
+ session->state = HTTP_SESSION_STATE_WRITE_HEADER;
+ char buff[BUFFER_SIZE];
+ int len = 0;
+ int index = 0;
+ len += snprintf(buff + len,BUFFER_SIZE - len,"%s %s HTTP/%s\r\n",
+ http_option_str_get(session->option),
+ session->uri,
+ http_version_str_get(session->version));
+
+ // if no set "Host",should set default host.
+ char *host = http_header_find(session,"Host");
+ if(!host)
+ {
+ len += snprintf(buff + len,BUFFER_SIZE - len,"Host: %s\r\n", session->host);
+ }
+
+ if(mbtk_http_write(session->sock_fd,buff,len) != len)
+ {
+ LOGE("mbtk_http_write() fail.");
+ return -1;
+ }
+
+ char header_str[BUFFER_SIZE];
+ int header_str_len = 0;
+ while(index < HTTP_REQUEST_HEADER_MAX)
+ {
+ if(session->req.req_h[index] &&
+ (header_str_len = http_header_str_get(session->req.req_h[index], header_str, BUFFER_SIZE)) > 0)
+ {
+ if(mbtk_http_write(session->sock_fd,header_str,header_str_len) != header_str_len)
+ {
+ LOGE("mbtk_http_write() fail.");
+ return -1;
+ }
+ }
+ index++;
+ }
+
+ // Write request header success.
+ LOGI("HTTP write header complete.");
+
+#undef BUFFER_SIZE
+
+ // Write "\r\n"
+ if(mbtk_http_write(session->sock_fd,"\r\n",2) != 2)
+ {
+ LOGE("mbtk_http_write() fail.");
+ return -1;
+ }
+
+ LOGI("Start write HTTPsession->option. %d", session->option);
+ if(session->option == HTTP_OPTION_POST)
+ {
+ session->state = HTTP_SESSION_STATE_WRITE_CONTENT;
+ LOGI("Start write HTTP content data.");
+
+ if(session->req.content && session->req.content_len > 0)
+ {
+ if(mbtk_http_write(session->sock_fd,session->req.content,session->req.content_len) != session->req.content_len)
+ {
+ LOGE("mbtk_http_write() fail.");
+ return -1;
+ }
+
+ session->state = HTTP_SESSION_STATE_WRITE_END;
+ }
+ }
+ else
+ {
+ session->state = HTTP_SESSION_STATE_WRITE_END;
+
+ LOGI("HTTP write complete.");
+ }
+ return 0;
+}
+
+static int http_session_read_by_chunk(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+ http_chunk_code chunk_code;
+ http_chunker_t chunker;
+ char read_buf[BUFFER_SIZE + 1];
+ int read_len = 0;
+ char chunk_buf[BUFFER_SIZE + 1];
+ int chunk_len;
+ http_chunk_init(&chunker);
+ while(TRUE)
+ {
+ read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
+ //read_len = mbtk_http_read_line(session->sock_file,read_buf,BUFFER_SIZE);
+ if(read_len <= 0)
+ {
+ LOGE("Read fail.");
+ return -1;
+ }
+
+ chunk_code = http_chunk_parse(&chunker, read_buf, read_len, chunk_buf, &chunk_len);
+ if(chunk_code > CHUNKE_OK) // Fail.
+ {
+ LOGE("http_chunk_parse() fail[err - %d].",chunk_code);
+ return -1;
+ }
+
+ LOGD("Read chunk_len:%d",chunk_len);
+ chunk_buf[chunk_len] = '\0';
+
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_CONTENT,chunk_buf,chunk_len);
+
+ if(CHUNKE_STOP == chunk_code)
+ {
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_COMPLETE,NULL,0);
+
+ break;
+ }
+ }
+
+ LOGV("Chunk read success.");
+
+ return 0;
+}
+
+static int http_session_read_by_length(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+ char read_buf[BUFFER_SIZE + 1];
+ int read_len = 0;
+ int64 read_count = 0;
+ while(TRUE)
+ {
+ memset(read_buf,0x0,BUFFER_SIZE + 1);
+ read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,3000);
+ if(read_len <= 0)
+ {
+ LOGE("Read fail.");
+ return -1;
+ }
+
+
+ if(read_count + read_len >= session->rsp.content_length) // Read data complete.
+ {
+ if(http_handles[session->handle_id].data_cb)
+ {
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_CONTENT,read_buf,session->rsp.content_length - read_count);
+
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_COMPLETE,NULL,0);
+ }
+ break;
+ }
+
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
+
+ read_count += read_len;
+ }
+
+ return 0;
+}
+
+static int http_session_read_by_general(mbtk_http_session_t *session)
+{
+#undef BUFFER_SIZE
+#define BUFFER_SIZE 2048
+ char read_buf[BUFFER_SIZE + 1];
+ int read_len = 0;
+ while(TRUE)
+ {
+ read_len = mbtk_http_read(session->sock_fd,read_buf,BUFFER_SIZE,1000);
+ if(read_len <= 0)
+ {
+ if(read_len == -2 || read_len == 0) // Timeout or end
+ break;
+
+ LOGW("Read end[read_len - %d].",read_len);
+ //return -1;
+ break;
+ }
+
+ read_buf[read_len] = '\0';
+
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_CONTENT,read_buf,read_len);
+ }
+
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_COMPLETE,NULL,0);
+
+
+ return 0;
+}
+
+static int http_session_start_read(mbtk_http_session_t *session)
+{
+ LOGI("Start HTTP read.");
+ int result = 0;
+// usleep(500000);
+ session->state = HTTP_SESSION_STATE_READ_HEADER;
+ if(http_header_read(session))
+ {
+ result = -1;
+ goto read_end;
+ }
+
+ if(session->option != HTTP_OPTION_HEAD)
+ {
+ session->state = HTTP_SESSION_STATE_READ_CONTENT;
+ if(session->rsp.is_chunked)
+ {
+ if(http_session_read_by_chunk(session))
+ {
+ LOGE("http_session_read_by_chunk fail.");
+ result = -1;
+ goto read_end;
+ }
+ }
+ else if(session->rsp.content_length > 0)
+ {
+ if(http_session_read_by_length(session))
+ {
+ LOGE("http_session_read_by_length fail.");
+ result = -1;
+ goto read_end;
+ }
+ }
+ else
+ {
+ if(http_session_read_by_general(session))
+ {
+ LOGE("http_session_read_by_general fail.");
+ result = -1;
+ goto read_end;
+ }
+ }
+ }
+ else
+ {
+ if(http_handles[session->handle_id].data_cb)
+ http_handles[session->handle_id].data_cb(session->id,
+ MBTK_HTTP_DATA_COMPLETE,NULL,0);
+ }
+
+read_end:
+ session->state = HTTP_SESSION_STATE_READ_END;
+
+ LOGI("HTTP request complete[result - %d].",result);
+ if(http_session_close(session))
+ {
+ return -1;
+ }
+
+#if 0
+ // Free session after HTTP request complete.
+ http_session_free(session);
+ http_handles[handle_id].session[session_id] = NULL;
+ http_handles[handle_id].session_cnt--;
+#endif
+
+ return result;
+}
+
+static bool http_session_req_check(mbtk_http_session_t *session)
+{
+ if(session == NULL || session->port == 0 ||
+ strlen(session->host) == 0)
+ {
+ LOGE("Session not set host or port.");
+ return FALSE;
+ }
+
+ if(session->option != HTTP_OPTION_HEAD &&
+ session->option != HTTP_OPTION_POST &&
+ session->option != HTTP_OPTION_GET)
+ {
+ LOGE("Only support HEAD/GET/POST");
+ return FALSE;
+ }
+
+#if 0
+ if(session->version != HTTP_VERSION_1_0 &&
+ session->version != HTTP_VERSION_1_1)
+ {
+ LOGE("Only support HTTP 1.0/1.1");
+ return FALSE;
+ }
+#endif
+
+ if(session->option == HTTP_OPTION_POST)
+ {
+ char *value = NULL;
+ value = http_header_find(session, "Content-Length");
+ if(!value)
+ {
+ LOGE("POST must set 'Content-Length'");
+ return FALSE;
+ }
+ if(session->req.content_len != atoi(value))
+ {
+ LOGE("POST 'Content-Length' error.");
+ return FALSE;
+ }
+
+ value = http_header_find(session, "Content-Type");
+ if(!value)
+ {
+ LOGE("POST must set 'Content-Type'");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*************************************************************
+ Public Function Definitions
+*************************************************************/
+int mbtk_http_handle_get(bool show_rsp_header,mbtk_http_data_callback_func data_cb)
+{
+ int index = 0;
+ int i = 0;
+ for(; index < HTTP_HANDLE_MAX; index++)
+ {
+ if(http_handles[index].id < 0) // Find free handle
+ {
+ break;
+ }
+ }
+
+ if(index == HTTP_HANDLE_MAX)
+ {
+ LOGE("HTTP Handle is full.");
+ return -1;
+ }
+
+ memset(&(http_handles[index]),0x0,sizeof(mbtk_http_handle_t));
+ http_handles[index].id = index;
+ http_handles[index].show_rsp_header = show_rsp_header;
+ http_handles[index].data_cb = data_cb;
+ http_handles[index].session_cnt = 0;
+ for(i = 0; i < HTTP_SESSION_MAX; i++)
+ {
+ http_handles[index].session[i] = NULL;
+ }
+
+ if(mbtk_http_init())
+ {
+ LOGE("mbtk_http_init() fail.");
+ return -1;
+ }
+
+ return http_handles[index].id;
+}
+
+int mbtk_http_handle_free(int handle_id)
+{
+ int i = 0;
+ if(!http_handle_check(handle_id))
+ {
+ LOGE("Handle error.");
+ return -1;
+ }
+
+ http_handles[handle_id].id = -1;
+ http_handles[handle_id].data_cb = NULL;
+ if(http_handles[handle_id].session_cnt > 0)
+ {
+ for(i = 0; i < HTTP_SESSION_MAX; i++)
+ {
+ if(http_handles[handle_id].session[i] != NULL)
+ {
+ if(http_handles[handle_id].session[i]->state != HTTP_SESSION_STATE_NON)
+ {
+ if(http_session_close(http_handles[handle_id].session[i]))
+ {
+ return -1;
+ }
+ }
+
+ http_session_free(http_handles[handle_id].session[i]);
+ http_handles[handle_id].session[i] = NULL;
+ }
+ }
+
+ http_handles[handle_id].session_cnt = 0;
+ }
+
+ if(mbtk_http_deinit())
+ {
+ LOGE("mbtk_http_deinit() fail.");
+ return -1;
+ }
+
+ return 0;
+}
+
+int mbtk_http_session_create(int handle_id, mbtk_http_option_enum option,
+ mbtk_http_version_enum version)
+{
+ int handle_index = 0;
+ int session_index = 0;
+ if(!http_handle_check(handle_id))
+ {
+ LOGE("Handle error.");
+ return -1;
+ }
+
+ for(; handle_index < HTTP_HANDLE_MAX; handle_index++)
+ {
+ if(http_handles[handle_index].id == handle_id) // Find handle
+ {
+ break;
+ }
+ }
+
+ if(handle_index == HTTP_HANDLE_MAX)
+ {
+ LOGE("No found handle[handle - %d].",handle_id);
+ return -1;
+ }
+
+ if(http_handles[handle_index].session_cnt >= HTTP_SESSION_MAX)
+ {
+ LOGE("Session is full.");
+ return -1;
+ }
+
+ for(; session_index < HTTP_SESSION_MAX; session_index++)
+ {
+ if(http_handles[handle_index].session[session_index] == NULL) // Find first NULL session
+ {
+ break;
+ }
+ }
+
+ if(session_index == HTTP_SESSION_MAX)
+ {
+ LOGE("Session is full.");
+ return -1;
+ }
+
+ mbtk_http_session_t* session = (mbtk_http_session_t*)malloc(sizeof(mbtk_http_session_t));
+ if(session == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+ memset(session,0x0,sizeof(mbtk_http_session_t));
+ session->sock_fd = -1;
+ session->file_fd = -1;
+ session->handle_id = handle_id;
+ session->id = session_index;
+ session->state = HTTP_SESSION_STATE_NON;
+ session->is_ssl = FALSE;
+ session->ingnore_cert = TRUE;
+ session->version = version;
+ session->option = option;
+ session->req.content_len = 0;
+ session->req.content_len_send = 0;
+ session->rsp.is_chunked = FALSE;
+ session->rsp.content_length = 0;
+ session->rsp.header_cnt = 0;
+ http_handles[handle_index].session[session_index] = session;
+ http_handles[handle_index].session_cnt++;
+
+ return session->id;
+}
+
+int mbtk_http_session_option_reset(int handle_id, int session_id, mbtk_http_option_enum option)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state != HTTP_SESSION_STATE_NON)
+ {
+ LOGE("Session state error.[%d]",session->state);
+ return -1;
+ }
+
+ session->option = option;
+ return 0;
+}
+
+
+int mbtk_http_session_ingnore_cert_set(int handle_id, int session_id, bool ingnore_cert)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+
+ session->ingnore_cert = ingnore_cert;
+
+ LOGE("session->ingnore_cert:%d, ingnore_cert:%d\n", session->ingnore_cert, ingnore_cert);
+ return 0;
+}
+
+
+int mbtk_http_session_free(int handle_id,int session_id)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state != HTTP_SESSION_STATE_NON)
+ {
+ if(http_session_close(session))
+ {
+ return -1;
+ }
+ }
+
+ http_session_free(session);
+ http_handles[handle_id].session[session_id] = NULL;
+ http_handles[handle_id].session_cnt--;
+ return 0;
+}
+
+int mbtk_http_session_url_set(int handle_id,int session_id,void *url)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state == HTTP_SESSION_STATE_NON)
+ return http_url_parse(url, session->host,session->uri,&(session->port),&(session->is_ssl));
+ else
+ {
+ LOGE("Currenr session is process[state - %d].",session->state);
+ return -1;
+ }
+}
+
+int mbtk_http_session_head_add(int handle_id,int session_id,
+ char *name, char *value)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ if(http_str_empty(name) || http_str_empty(value))
+ {
+ LOGE("Param error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state == HTTP_SESSION_STATE_NON)
+ {
+ int result = http_session_req_head_add(session,TRUE,name,value);
+ if(!result && !strncasecmp(name,"Content-Length",14))
+ {
+ session->req.content_len = atoi(value);
+ }
+ return result;
+ }
+ else
+ {
+ LOGE("Currenr session is process[state - %d].",session->state);
+ return -1;
+ }
+}
+
+int mbtk_http_session_content_set(int handle_id,int session_id,
+ char *content,uint32 content_len)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ if(content_len <= 0 || content_len > HTTP_CONTENT_LEN_MAX)
+ {
+ LOGE("Content lenght error[%d].",content_len);
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state == HTTP_SESSION_STATE_NON)
+ {
+ if(session->option != HTTP_OPTION_POST)
+ {
+ LOGE("Content only for post.");
+ return -1;
+ }
+
+ if(session->req.content)
+ {
+ free(session->req.content);
+ session->req.content_len = 0;
+ }
+
+ session->req.content = (char*)malloc(content_len);
+ if(session->req.content == NULL)
+ {
+ LOGE("malloc() fail.");
+ return -1;
+ }
+
+ char *content_type = NULL;
+ if(strlen(content) == content_len) //
+ {
+ content_type = "text/plain";
+ }
+ else
+ {
+ content_type = "application/octet-stream";
+ }
+
+ if(http_session_req_head_add(session, FALSE, "Content-Type", content_type))
+ {
+ LOGE("Set 'Content-Type' fail.");
+ return -1;
+ }
+
+ memcpy(session->req.content,content,content_len);
+ session->req.content_len = content_len;
+
+ char len_str[20] = {0};
+ snprintf(len_str,20,"%d",content_len);
+ if(http_session_req_head_add(session,FALSE,"Content-Length",len_str))
+ {
+ LOGE("Set 'Content-Length' fail.");
+ return -1;
+ }
+
+
+ return 0;
+ }
+ else
+ {
+ LOGE("Currenr session is process[state - %d].",session->state);
+ return -1;
+ }
+}
+
+int mbtk_http_session_start(int handle_id,int session_id)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state == HTTP_SESSION_STATE_NON)
+ {
+ if(!http_session_req_check(session))
+ {
+ LOGE("http_session_req_check() fail.");
+ return -1;
+ }
+
+ // Must set "Connection" for post.
+ if(session->option == HTTP_OPTION_POST)
+ {
+ if(http_session_req_head_add(session,FALSE,"Connection","KeepAlive"))
+ {
+ LOGE("Set 'Content-Length' fail.");
+ return -1;
+ }
+ }
+
+ LOGI("HTTP request start.");
+ LOGI("host:%s, port:%d, uri:%s",session->host,session->port,session->uri);
+ LOGI("is_ssl:%d,ingnore_cert:%d, version:%d, option:%d, content_len:%d",session->is_ssl,
+ session->ingnore_cert, session->version,session->option,session->req.content_len);
+
+ int sock_fd = mbtk_http_open(session->is_ssl,session->ingnore_cert,session->host,session->port);
+
+ if(sock_fd < 0)
+ {
+ LOGE("mbtk_http_open() fail.");
+ return -1;
+ }
+ session->sock_fd = sock_fd;
+// int fd = mbtk_sock_fd_get(sock_fd);
+// if(fd < 0) {
+// LOGE("mbtk_sock_fd_get() fail.");
+// return -1;
+// }
+ // session->sock_file = fdopen(sock_fd,"r");
+ session->state = HTTP_SESSION_STATE_CONN;
+
+// if(!session->sock_file) {
+// LOGE("fdopen() fail.");
+// return -1;
+// }
+
+ LOGI("HTTP connected.");
+
+ if(http_session_start_write(session))
+ {
+ return -1;
+ }
+
+ if(session->state == HTTP_SESSION_STATE_WRITE_END)
+ {
+ if(http_session_start_read(session))
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ LOGI("Waitting post content data...");
+ }
+
+ return 0;
+ }
+ else
+ {
+ LOGE("Currenr session is process[state - %d].",session->state);
+ return -1;
+ }
+}
+
+int mbtk_http_session_content_send(int handle_id,int session_id,
+ char *data,int data_len)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return -1;
+ }
+
+ if(data_len <= 0 || data_len > HTTP_CONTENT_LEN_MAX)
+ {
+ LOGE("Content lenght error[%d].",data_len);
+ return -1;
+ }
+
+ LOGV("Post send:%d - %s",data_len,data);
+
+ mbtk_http_session_t *session = http_handles[handle_id].session[session_id];
+ if(session->state == HTTP_SESSION_STATE_WRITE_CONTENT)
+ {
+ if(session->option != HTTP_OPTION_POST)
+ {
+ LOGE("Content only for post.");
+ return -1;
+ }
+
+ if(session->req.content || session->req.content_len <= 0)
+ {
+ LOGE("This post not spit package.");
+ return -1;
+ }
+
+ // Discard excess data.
+ if(session->req.content_len_send + data_len > session->req.content_len)
+ data_len = session->req.content_len - session->req.content_len_send;
+
+ if(data_len != mbtk_http_write(session->sock_fd,data,data_len))
+ {
+ return -1;
+ }
+
+ session->req.content_len_send += data_len;
+
+ LOGI("HTTP post data send: %d / %d",session->req.content_len_send,
+ session->req.content_len);
+
+ // Post data send complete.
+ if(session->req.content_len_send >= session->req.content_len)
+ {
+ session->state = HTTP_SESSION_STATE_WRITE_END;
+
+ LOGI("HTTP write complete.");
+ if(http_session_start_read(session))
+ {
+ return -1;
+ }
+ }
+
+ return 0;
+ }
+ else
+ {
+ LOGE("Currenr session state error[%d].",session->state);
+ return -1;
+ }
+}
+
+const mbtk_http_session_t* mbtk_http_session_get(int handle_id,int session_id)
+{
+ if(!http_session_check(handle_id,session_id))
+ {
+ LOGE("Session error.");
+ return NULL;
+ }
+
+ return http_handles[handle_id].session[session_id];
+}
+
+void mbtk_http_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_http_lib");
+}
+
diff --git a/mbtk/libmbtk_lib/http/mbtk_http_base.c b/mbtk/libmbtk_lib/http/mbtk_http_base.c
new file mode 100755
index 0000000..657b838
--- /dev/null
+++ b/mbtk/libmbtk_lib/http/mbtk_http_base.c
@@ -0,0 +1,277 @@
+#include <sys/epoll.h>
+#include <string.h>
+
+#include "mbtk_log.h"
+#include "mbtk_http_base.h"
+
+static void http_sock_cb_func(int handle, int fd, int event);
+
+static bool http_sock_inited = FALSE;
+static int http_handle = -1;
+static int http_fd = -1;
+
+static void http_sock_cb_func(int handle, int fd, int event)
+{
+ if(http_handle == handle && http_fd == fd) {
+ if(event & EPOLLIN) { // READ
+
+ } else if(event & EPOLLRDHUP) { // Close
+
+ } else {
+ LOGW("Unknown event:%x",event);
+ }
+ }
+}
+
+int mbtk_http_init()
+{
+ if(http_sock_inited) {
+ LOGE("HTTP has inited.");
+ return -1;
+ }
+
+ mbtk_init_info init_info;
+ memset(&init_info, 0x0, sizeof(mbtk_init_info));
+ init_info.net_type = MBTK_NET_LINUX;
+ init_info.sock_cb = http_sock_cb_func;
+ http_handle = mbtk_sock_init(&init_info);
+ if(http_handle < 0) {
+ LOGE("mbtk_sock_init() fail.");
+ return -1;
+ }
+
+ http_sock_inited = TRUE;
+ return 0;
+}
+
+int mbtk_http_deinit()
+{
+ if(!http_sock_inited) {
+ LOGE("HTTP not inited.");
+ return -1;
+ }
+
+ int err = mbtk_sock_deinit(http_handle);
+ if(err != MBTK_SOCK_SUCCESS) {
+ LOGE("mbtk_sock_deinit() fail.");
+ return -1;
+ }
+
+ http_handle = -1;
+ http_sock_inited = FALSE;
+ return 0;
+}
+
+
+int mbtk_http_open
+(
+ bool is_ssl,
+ bool ingnore_cert,
+ const void *host,
+ uint16 port
+)
+{
+ int err;
+ mbtk_sock_info sock_info;
+ memset(&sock_info,0x0,sizeof(mbtk_sock_info));
+
+ sock_info.type = MBTK_SOCK_TCP;
+ sock_info.is_support_ssl = is_ssl;
+ sock_info.ingnore_cert = ingnore_cert;
+ memcpy(sock_info.address,host,strlen(host));
+ sock_info.port = port;
+
+ http_fd = mbtk_sock_open(http_handle,&sock_info, 3000, &err);
+
+ return http_fd;
+}
+
+/*=============================================
+FUNCTION
+ mbtk_http_read
+
+DESCRIPTION
+ read content from socket.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *buf Store read content.
+ len the length of Content.
+ timeout Set timeout
+
+RETURN VALUE
+ Length of read content
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_read
+(
+ int sock_fd,
+ void *buf,
+ uint16 len,
+ int timeout_ms
+)
+{
+ int err;
+ int read_len = mbtk_sock_read(http_handle, sock_fd, buf, len, timeout_ms, &err);
+ if(read_len < 0) {
+ if(err == MBTK_SOCK_ETIMEOUT) {
+ return -2;
+ } else {
+ return -1;
+ }
+ } else {
+ return read_len;
+ }
+}
+
+#if 0
+int mbtk_http_read_line
+(
+ FILE *file,
+ void *buf,
+ uint16 len
+)
+{
+ if(file) {
+ char *buf_ptr = (char*)buf;
+ char *line = NULL;
+read_again:
+ line = fgets(buf_ptr,len,file);
+ if(!line && errno == EWOULDBLOCK) {
+ usleep(100000);
+ goto read_again;
+ }
+ if(line && strlen(line) > 0
+ && strlen(line) <= len
+ && buf_ptr[strlen(line) - 1] == '\n') {
+ LOGV("Read-Line[%d]:%s",strlen(line),line);
+ return strlen(line);
+ }else{
+ LOGE("fgets() fail.");
+ return -1;
+ }
+ }
+
+ return -1;
+}
+#else
+int mbtk_http_read_line
+(
+ int sock_fd,
+ void *buf,
+ uint16 len
+)
+{
+#if 1
+ if(sock_fd > 0) {
+ char *buf_ptr = (char*)buf;
+ char read_buf[1];
+ int read_len = 0;
+ while(TRUE) {
+ if(mbtk_sock_read_sync(http_handle, sock_fd, read_buf, 1) == 1) {
+ *buf_ptr++ = read_buf[0];
+ read_len++;
+
+ if(read_buf[0] == '\n' || read_len >= len) {
+ return read_len;
+ }
+ } else {
+ return -1;
+ }
+ }
+ }
+#else
+ if(http_handle >= 0) {
+ char *buf_ptr = (char*)buf;
+ char read_buf[1];
+ int read_len = 0;
+ while(TRUE) {
+ if(read(http_fd, read_buf, 1) == 1) {
+ *buf_ptr++ = read_buf[0];
+ read_len++;
+
+ if(read_buf[0] == '\n' || read_len >= len) {
+ return read_len;
+ }
+ } else {
+ if(errno == EWOULDBLOCK) {
+ usleep(100000);
+ }
+ }
+ }
+ }
+
+#endif
+
+ return -1;
+}
+
+#endif
+
+/*=============================================
+FUNCTION
+ mbtk_http_write
+
+DESCRIPTION
+ Write content to socket.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *buf Content to be transferred
+ len the length of Content.
+
+RETURN VALUE
+ Length of written content
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_write
+(
+ int sock_fd,
+ void *buf,
+ uint16 len
+)
+{
+ int err;
+ LOGV("Write[%d]:%s",len,(char*)buf);
+ return mbtk_sock_write(http_handle, sock_fd, buf, len, 300, &err);
+}
+
+/*=============================================
+FUNCTION
+ mbtk_http_close
+
+DESCRIPTION
+ close HTTP service.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *err Error number
+
+RETURN VALUE
+ TURE or FALSE
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_close(int sock_fd)
+{
+ int err;
+
+ if(mbtk_sock_close(http_handle, sock_fd,1000, &err)) {
+ return -1;
+ }
+
+ sock_fd = -1;
+ return 0;
+}
+
diff --git a/mbtk/libmbtk_lib/http/mbtk_http_base.h b/mbtk/libmbtk_lib/http/mbtk_http_base.h
new file mode 100755
index 0000000..2490b78
--- /dev/null
+++ b/mbtk/libmbtk_lib/http/mbtk_http_base.h
@@ -0,0 +1,124 @@
+/*************************************************************
+Description:
+ HTTP platform related function implementation.
+Author:
+ LiuBin
+Date:
+ 2020/4/30 14:02:58
+*************************************************************/
+#ifndef _MBTK_HTTP_BASE_H
+#define _MBTK_HTTP_BASE_H
+
+#include <stdio.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_sock2.h"
+
+/*************************************************************
+ Public Function Declaration
+*************************************************************/
+int mbtk_http_init();
+int mbtk_http_deinit();
+int mbtk_http_open
+(
+ bool is_ssl,
+ bool ingnore_cert,
+ const void *host,
+ uint16 port
+);
+
+/*=============================================
+FUNCTION
+ mbtk_http_read
+
+DESCRIPTION
+ read content from socket.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *buf Store read content.
+ len the length of Content.
+ timeout Set timeout
+
+RETURN VALUE
+ Length of read content
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_read
+(
+ int sock_fd,
+ void *buf,
+ uint16 len,
+ int timeout_ms
+);
+
+#if 0
+int mbtk_http_read_line
+(
+ FILE *file,
+ void *buf,
+ uint16 len
+);
+#else
+int mbtk_http_read_line
+(
+ int sock_fd,
+ void *buf,
+ uint16 len
+);
+#endif
+
+/*=============================================
+FUNCTION
+ mbtk_http_write
+
+DESCRIPTION
+ Write content to socket.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *buf Content to be transferred
+ len the length of Content.
+
+RETURN VALUE
+ Length of written content
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_write
+(
+ int sock_fd,
+ void *buf,
+ uint16 len
+);
+
+/*=============================================
+FUNCTION
+ mbtk_http_close
+
+DESCRIPTION
+ close HTTP service.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ *err Error number
+
+RETURN VALUE
+ TURE or FALSE
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_http_close(int sock_fd);
+
+#endif /* _MBTK_HTTP_BASE_H */
diff --git a/mbtk/libmbtk_lib/http/mbtk_http_chunks.c b/mbtk/libmbtk_lib/http/mbtk_http_chunks.c
new file mode 100755
index 0000000..899e0c7
--- /dev/null
+++ b/mbtk/libmbtk_lib/http/mbtk_http_chunks.c
@@ -0,0 +1,131 @@
+#include <string.h>
+
+#include "mbtk_http_chunks.h"
+#include "mbtk_http_base.h"
+
+static bool http_isxdigit(char digit)
+{
+ return (digit >= 0x30 && digit <= 0x39) /* 0-9 */
+ || (digit >= 0x41 && digit <= 0x46) /* A-F */
+ || (digit >= 0x61 && digit <= 0x66); /* a-f */
+}
+
+void http_chunk_init(http_chunker_t *chunker)
+{
+ chunker->hexindex = 0; /* start at 0 */
+ chunker->dataleft = 0; /* no data left yet! */
+ chunker->state = CHUNK_HEX; /* we get hex first! */
+}
+
+http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len,
+ char *dest,int *dest_len)
+{
+ int piece;
+ char *datap = src;
+ int length = src_len;
+
+ *dest_len = 0;
+
+ while(length > 0)
+ {
+ switch(chunker->state)
+ {
+ case CHUNK_HEX:
+ if(http_isxdigit(*datap))
+ {
+ if(chunker->hexindex < MAXNUM_SIZE)
+ {
+ chunker->hexbuffer[chunker->hexindex] = *datap;
+ datap++;
+ length--;
+ chunker->hexindex++;
+ }
+ else
+ {
+ return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
+ }
+ }
+ else // Not hex char. ('\r')
+ {
+ if(0 == chunker->hexindex)
+ return CHUNKE_ILLEGAL_HEX;
+
+ chunker->hexbuffer[chunker->hexindex] = '\0';
+ sscanf(chunker->hexbuffer,"%x",&chunker->datasize);
+
+ LOGD("Chunk len:%s -> %d",chunker->hexbuffer,chunker->datasize);
+
+ chunker->state = CHUNK_LF; /* now wait for the CRLF */
+ }
+ break;
+ case CHUNK_LF:
+ if(*datap == 0x0a) // '\n'
+ {
+ if(0 == chunker->datasize) { // Chunk lenght is '0' (Is last chunk)
+ chunker->state = CHUNK_TRAILER;
+ } else {
+ chunker->state = CHUNK_DATA;
+ }
+ }
+
+ datap++;
+ length--;
+ break;
+ case CHUNK_DATA:
+ /* We expect 'datasize' of data. We have 'length' right now, it can be
+ more or less than 'datasize'. Get the smallest piece.
+ */
+ piece = (chunker->datasize >= length)?length:chunker->datasize;
+
+ memcpy(dest + *dest_len,datap,piece);
+ *dest_len += piece;
+
+ chunker->datasize -= piece; /* decrease amount left to expect */
+ datap += piece; /* move read pointer forward */
+ length -= piece; /* decrease space left in this round */
+
+ if(0 == chunker->datasize) // Next chunk
+ chunker->state = CHUNK_POSTLF;
+ break;
+ case CHUNK_POSTLF:
+ if(*datap == 0x0a)
+ {
+ http_chunk_init(chunker);
+ }
+ else if(*datap != 0x0d)
+ return CHUNKE_BAD_CHUNK;
+ datap++;
+ length--;
+ break;
+ case CHUNK_TRAILER:
+ if((*datap != 0x0d) && (*datap != 0x0a))
+ {
+ return CHUNKE_BAD_CHUNK;
+ }
+ if(*datap == 0x0d)
+ {
+ /* skip if CR */
+ datap++;
+ length--;
+ }
+ chunker->state = CHUNK_STOP;
+ break;
+ case CHUNK_STOP: // Complete
+ if(*datap == 0x0a)
+ {
+ length--;
+
+ /* Record the length of any data left in the end of the buffer
+ even if there's no more chunks to read */
+ chunker->dataleft = length;
+
+ return CHUNKE_STOP; /* return stop */
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ }
+ }
+ return CHUNKE_OK;
+}
+
+
diff --git a/mbtk/libmbtk_lib/http/mbtk_http_chunks.h b/mbtk/libmbtk_lib/http/mbtk_http_chunks.h
new file mode 100755
index 0000000..eff228c
--- /dev/null
+++ b/mbtk/libmbtk_lib/http/mbtk_http_chunks.h
@@ -0,0 +1,66 @@
+#ifndef _MBTK_HTTP_CHUNKS_H
+#define _MBTK_HTTP_CHUNKS_H
+#include "mbtk_type.h"
+
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
+ * to convert it, we "only" support 2^32 bytes chunk data.
+ */
+#define MAXNUM_SIZE 16
+
+typedef enum {
+ /* await and buffer all hexadecimal digits until we get one that isn't a
+ hexadecimal digit. When done, we go CHUNK_LF */
+ CHUNK_HEX,
+
+ /* wait for LF, ignore all else */
+ CHUNK_LF,
+
+ /* We eat the amount of data specified. When done, we move on to the
+ POST_CR state. */
+ CHUNK_DATA,
+
+ /* POSTLF should get a CR and then a LF and nothing else, then move back to
+ HEX as the CRLF combination marks the end of a chunk. A missing CR is no
+ big deal. */
+ CHUNK_POSTLF,
+
+ /* At this point optional trailer headers can be found, unless the next line
+ is CRLF */
+ CHUNK_TRAILER,
+
+ /* Used to mark that we're out of the game. NOTE: that there's a 'dataleft'
+ field in the struct that will tell how many bytes that were not passed to
+ the client in the end of the last buffer! */
+ CHUNK_STOP
+} http_chunk_state;
+
+typedef enum {
+ CHUNKE_STOP = -1,
+ CHUNKE_OK = 0,
+ CHUNKE_TOO_LONG_HEX = 1,
+ CHUNKE_ILLEGAL_HEX,
+ CHUNKE_BAD_CHUNK,
+ CHUNKE_BAD_ENCODING,
+ CHUNKE_OUT_OF_MEMORY,
+ CHUNKE_PASSTHRU_ERROR, /* Curl_httpchunk_read() returns a CURLcode to use */
+ CHUNKE_LAST
+} http_chunk_code;
+
+typedef struct {
+ char hexbuffer[MAXNUM_SIZE + 1];
+ int hexindex;
+ http_chunk_state state;
+ int datasize;
+ int dataleft; /* untouched data amount at the end of the last buffer */
+} http_chunker_t;
+
+/* The following functions are defined in http_chunks.c */
+void http_chunk_init(http_chunker_t *chunker);
+http_chunk_code http_chunk_parse(http_chunker_t *chunker, char *src, int src_len,
+ char *dest,int *dest_len);
+
+#endif /* _MBTK_HTTP_CHUNKS_H */
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTClient.c b/mbtk/libmbtk_lib/mqtt/MQTTClient.c
new file mode 100755
index 0000000..4a349a7
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTClient.c
@@ -0,0 +1,684 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTClient.h"
+
+regnwl_info_t regnwl_info = {0};
+
+
+int core_json_value(const char *input, uint32_t input_len, const char *key, uint32_t key_len, char **value,
+ uint32_t *value_len)
+{
+ int idx = 0;
+
+ for (idx = 0; idx < input_len; idx++) {
+ if (idx + key_len >= input_len) {
+ return -1;
+ }
+ if ((memcmp(&input[idx], key, key_len) == 0) &&
+ ((idx > 0) && (input[idx - 1] == '"')) &&
+ ((idx + key_len < input_len) && (input[idx + key_len] == '"'))) {
+ idx += key_len;
+ /* shortest ":x, or ":x} or ":x] */
+ if ((idx + 2 >= input_len) ||
+ (input[idx + 1] != ':')) {
+ return -1;
+ }
+ idx += 2;
+ if (input[idx] == '"') {
+ *value = (char *)&input[++idx];
+ for (; idx < input_len; idx++) {
+ if ((input[idx] == '"')) {
+ *value_len = (uint32_t)(idx - (*value - input));
+ return SUCCESS;
+ }
+ }
+ } else if (input[idx] == '{' || input[idx] == '[') {
+ char start = input[idx];
+ char end = (start == '{') ? ('}') : (']');
+ uint8_t count = 0;
+ *value = (char *)&input[idx];
+ for (; idx < input_len; idx++) {
+ if ((input[idx] == start)) {
+ count++;
+ } else if ((input[idx] == end)) {
+ if (--count == 0) {
+ *value_len = (uint32_t)(idx - (*value - input) + 1);
+ return SUCCESS;
+ }
+ }
+ }
+ } else {
+ *value = (char *)&input[idx];
+ for (; idx < input_len; idx++) {
+ if ((input[idx] == ',' || input[idx] == ']' || input[idx] == '}')) {
+ *value_len = (uint32_t)(idx - (*value - input));
+ return SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+void mbtk_ali_auth_regnwl_sava(MQTTMessage msg)
+{
+ printf("pub, payload: %d,%s\n", msg.payloadlen, msg.payload);
+ int32_t res = SUCCESS;
+
+ char *client_key = "clientId",*deviceToken_key="deviceToken";
+ uint32_t clientId_value_len = 0,deviceToken_value_len = 0;
+
+ char *client_value=NULL,*deviceToken_value=NULL;
+ if ((res = core_json_value((char *)msg.payload, msg.payloadlen,
+ client_key, strlen(client_key), &client_value, &clientId_value_len)) == SUCCESS)
+ {
+ memset(regnwl_info.clientId,0,clientId_value_len+1);
+ memcpy(regnwl_info.clientId,client_value,clientId_value_len);
+ printf("client_value:%s,\n regnwl_info->clientId:%s\n", client_value, regnwl_info.clientId);
+ }
+
+ if ((res = core_json_value((char *)msg.payload, msg.payloadlen,
+ deviceToken_key, strlen(deviceToken_key), &deviceToken_value, &deviceToken_value_len)) == SUCCESS)
+ {
+ memset(regnwl_info.deviceToken,0,deviceToken_value_len+1);
+ memcpy(regnwl_info.deviceToken,deviceToken_value,deviceToken_value_len);
+ printf("deviceToken_value:%s,\n regnwl_info->deviceToken:%s\n", deviceToken_value, regnwl_info.deviceToken);
+ }
+
+}
+
+
+void NewMessageData(MessageData* md, MQTTString* aTopicName, MQTTMessage* aMessgage) {
+ md->topicName = aTopicName;
+ md->message = aMessgage;
+}
+
+
+int getNextPacketId(Client *c) {
+ return c->next_packetid = (c->next_packetid == MAX_PACKET_ID) ? 1 : c->next_packetid + 1;
+}
+
+
+int sendPacket(Client* c, int length, Timer* timer)
+{
+ int rc = FAILURE,
+ sent = 0;
+
+ while (sent < length && !expired(timer))
+ {
+ rc = c->ipstack->mqttwrite(c->ipstack, &c->buf[sent], length, left_ms(timer));
+ if (rc < 0) // there was an error writing the data
+ break;
+ sent += rc;
+ }
+ printf("rc ----%d,sent----%d,length----%d\n",rc,sent,length);
+ if (sent == length)
+ {
+ countdown(&c->ping_timer, c->keepAliveInterval); // record the fact that we have successfully sent the packet
+ rc = SUCCESS;
+ }
+ else
+ rc = FAILURE;
+ return rc;
+}
+
+
+void MQTTClient(Client* c, Network* network, unsigned int command_timeout_ms, unsigned char* buf, size_t buf_size, unsigned char* readbuf, size_t readbuf_size)
+{
+ int i;
+ c->ipstack = network;
+
+ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ c->messageHandlers[i].topicFilter = 0;
+ c->command_timeout_ms = command_timeout_ms;
+ c->buf = buf;
+ c->buf_size = buf_size;
+ c->readbuf = readbuf;
+ c->readbuf_size = readbuf_size;
+ c->isconnected = 0;
+ c->ping_outstanding = 0;
+ c->defaultMessageHandler = NULL;
+ InitTimer(&c->ping_timer);
+}
+
+
+int decodePacket(Client* c, int* value, int timeout)
+{
+ unsigned char i;
+ int multiplier = 1;
+ int len = 0;
+ const int MAX_NO_OF_REMAINING_LENGTH_BYTES = 4;
+
+ *value = 0;
+ do
+ {
+ int rc = MQTTPACKET_READ_ERROR;
+
+ if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ {
+ rc = MQTTPACKET_READ_ERROR; /* bad data */
+ goto exit;
+ }
+ rc = c->ipstack->mqttread(c->ipstack, &i, 1, timeout);
+ if (rc != 1)
+ goto exit;
+ *value += (i & 127) * multiplier;
+ multiplier *= 128;
+ } while ((i & 128) != 0);
+exit:
+ return len;
+}
+
+
+int readPacket(Client* c, Timer* timer)
+{
+ int rc = FAILURE;
+ MQTTHeader header = {0};
+ int len = 0;
+ int rem_len = 0;
+
+ /* 1. read the header byte. This has the packet type in it */
+ memset(c->readbuf,0x0,c->readbuf_size);
+ if ((rc = c->ipstack->mqttread(c->ipstack, c->readbuf, 1, left_ms(timer))) != 1)
+ goto exit;
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ decodePacket(c, &rem_len, left_ms(timer));
+ len += MQTTPacket_encode(c->readbuf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if (rem_len > 0 && ((rc = c->ipstack->mqttread(c->ipstack, c->readbuf + len, rem_len, left_ms(timer)) )!= rem_len))
+ goto exit;
+
+ header.byte = c->readbuf[0];
+ rc = header.bits.type;
+exit:
+ return rc;
+}
+
+
+// assume topic filter and name is in correct format
+// # can only be at end
+// + and # can only be next to separator
+char isTopicMatched(char* topicFilter, MQTTString* topicName)
+{
+ char* curf = topicFilter;
+ char* curn = topicName->lenstring.data;
+ char* curn_end = curn + topicName->lenstring.len;
+
+ while (*curf && curn < curn_end)
+ {
+ if (*curn == '/' && *curf != '/')
+ break;
+ if (*curf != '+' && *curf != '#' && *curf != *curn)
+ break;
+ if (*curf == '+')
+ { // skip until we meet the next separator, or end of string
+ char* nextpos = curn + 1;
+ while (nextpos < curn_end && *nextpos != '/')
+ nextpos = ++curn + 1;
+ }
+ else if (*curf == '#')
+ curn = curn_end - 1; // skip until end of string
+ curf++;
+ curn++;
+ };
+
+ return (curn == curn_end) && (*curf == '\0');
+}
+
+
+int deliverMessage(Client* c, MQTTString* topicName, MQTTMessage* message)
+{
+ int i;
+ int rc = FAILURE;
+
+ // we have to find the right message handler - indexed by topic
+ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (c->messageHandlers[i].topicFilter != 0 && (MQTTPacket_equals(topicName, (char*)c->messageHandlers[i].topicFilter) ||
+ isTopicMatched((char*)c->messageHandlers[i].topicFilter, topicName)))
+ {
+ if (c->messageHandlers[i].fp != NULL)
+ {
+ MessageData md;
+ NewMessageData(&md, topicName, message);
+ c->messageHandlers[i].fp(&md);
+ rc = SUCCESS;
+ }
+ }
+ }
+
+ if (rc == FAILURE && c->defaultMessageHandler != NULL)
+ {
+ MessageData md;
+ NewMessageData(&md, topicName, message);
+ c->defaultMessageHandler(&md);
+ rc = SUCCESS;
+ }
+
+ return rc;
+}
+
+
+int keepalive(Client* c)
+{
+ int rc = SUCCESS;
+ if (c->keepAliveInterval == 0)
+ {
+ rc = SUCCESS;
+ goto exit;
+ }
+
+ if (expired(&c->ping_timer))
+ {
+ if (!c->ping_outstanding)
+ {
+ Timer timer;
+ InitTimer(&timer);
+ countdown_ms(&timer, 1000);
+ int len = MQTTSerialize_pingreq(c->buf, c->buf_size);
+ printf("len %d\n",len);
+ if (len > 0 && (rc = sendPacket(c, len, &timer)) == SUCCESS) // send the ping packet
+ c->ping_outstanding = 1;
+ printf("sendPacket---------------------------------------------\n");
+ }
+ else
+ {
+ printf("fail_count-------------\n",c->fail_count);
+ ++(c->fail_count);
+ if (c->fail_count >= MAX_FAIL_ALLOWED)
+ {
+ rc = DISCONNECTED;
+ goto exit;
+ }
+
+ }
+ countdown(&(c->ping_timer), c->keepAliveInterval);
+ }
+ //printf("keepalive rc is %d\n",rc);
+exit:
+ return rc;
+}
+
+
+int cycle(Client* c, Timer* timer)
+{
+ int len = 0,
+ rc = SUCCESS;
+ // read the socket, see what work is due
+ short packet_type = readPacket(c, timer);
+
+ if(packet_type <= 0)
+ {
+ //printf("[%s][%d]readPacket retrun socket close \n",__FUNCTION__, __LINE__);
+ //printf("[%s]....packet_type = %d\n", __FUNCTION__, packet_type);
+ rc = DISCONNECTED;
+ goto exit;
+ }
+
+ switch (packet_type)
+ {
+ case CONNACK:
+ case PUBACK:
+ case SUBACK:
+ break;
+ case PUBLISH:
+ {
+ memset(regnwl_info.deviceToken,0,sizeof(regnwl_info.deviceToken));
+ memset(regnwl_info.clientId,0,sizeof(regnwl_info.clientId));
+ MQTTString topicName;
+ MQTTMessage msg;
+ if (MQTTDeserialize_publish((unsigned char*)&msg.dup, (int*)&msg.qos, (unsigned char*)&msg.retained, (unsigned short*)&msg.id, &topicName,
+ (unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
+ goto exit;
+ if(memcmp(topicName.lenstring.data,"/ext/regnwl",strlen("/ext/regnwl")) == 0)
+ {
+ mbtk_ali_auth_regnwl_sava(msg);
+ }
+ deliverMessage(c, &topicName, &msg);
+ if (msg.qos != QOS0)
+ {
+ if (msg.qos == QOS1)
+ len = MQTTSerialize_ack(c->buf, c->buf_size, PUBACK, 0, msg.id);
+ else if (msg.qos == QOS2)
+ len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREC, 0, msg.id);
+ if (len <= 0)
+ rc = FAILURE;
+ else
+ rc = sendPacket(c, len, timer);
+ if (rc == FAILURE)
+ {
+ goto exit; // there was a problem
+ }
+
+ }
+ break;
+ }
+ case PUBREC:
+ {
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+ rc = FAILURE;
+ else if ((len = MQTTSerialize_ack(c->buf, c->buf_size, PUBREL, 0, mypacketid)) <= 0)
+ rc = FAILURE;
+ else if ((rc = sendPacket(c, len, timer)) != SUCCESS) // send the PUBREL packet
+ rc = FAILURE; // there was a problem
+ if (rc == FAILURE)
+ {
+ goto exit; // there was a problem
+ }
+
+ break;
+ }
+ case PUBCOMP:
+ break;
+ case PINGRESP:
+ c->ping_outstanding = 0;
+ c->fail_count = 0;
+ break;
+ }
+
+exit:
+ if (rc == SUCCESS)
+ rc = packet_type;
+
+;
+ return rc;
+}
+
+
+int MQTTYield(Client* c, int timeout_ms)
+{
+ int rc = SUCCESS;
+ Timer timer;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, timeout_ms);
+ static int i = 0;
+ if (c->isconnected)
+ rc = keepalive(c);
+ if(rc < 0)
+ {
+ return rc;
+ }
+/*
+ while (!expired(&timer))
+ {
+ rc = cycle(c, &timer);
+ if (rc == DISCONNECTED)
+ {
+ printf("cycle DISCONNECTED \n");
+ break;
+ }
+ rc = SUCCESS;
+ }
+*/
+ do
+ {
+ if (expired(&timer))
+ break; // we timed out
+ }
+ while ((rc = cycle(c, &timer)) != PUBLISH);
+ rc = SUCCESS;
+ return rc;
+}
+
+
+// only used in single-threaded mode where one command at a time is in process
+int waitfor(Client* c, int packet_type, Timer* timer)
+{
+ int rc = FAILURE;
+ do
+ {
+ if (expired(timer))
+ break; // we timed out
+ }
+ while ((rc = cycle(c, timer)) != packet_type && (rc = cycle(c, timer)) != DISCONNECTED);
+
+ return rc;
+}
+
+
+int MQTTConnect(Client* c, MQTTPacket_connectData* options)
+{
+ Timer connect_timer;
+ int rc = FAILURE;
+ MQTTPacket_connectData default_options = MQTTPacket_connectData_initializer;
+ int len = 0;
+ InitTimer(&connect_timer);
+ countdown_ms(&connect_timer, c->command_timeout_ms);
+
+ if (c->isconnected) // don't send connect packet again if we are already connected
+ goto exit;
+
+ if (options == 0)
+ options = &default_options; // set default options if none were supplied
+
+ c->keepAliveInterval = options->keepAliveInterval;
+ countdown(&c->ping_timer, c->keepAliveInterval);
+ printf("[%s]c->keepAliveInterval = %d", __FUNCTION__,c->keepAliveInterval);
+ if ((len = MQTTSerialize_connect(c->buf, c->buf_size, options)) <= 0)
+ goto exit;
+ if ((rc = sendPacket(c, len, &connect_timer)) != SUCCESS) // send the connect packet
+ goto exit; // there was a problem
+
+ // this will be a blocking call, wait for the connack
+ if (waitfor(c, CONNACK, &connect_timer) == CONNACK)
+ {
+ unsigned char connack_rc = 255;
+ char sessionPresent = 0;
+ if (MQTTDeserialize_connack((unsigned char*)&sessionPresent, &connack_rc, c->readbuf, c->readbuf_size) == 1)
+ rc = connack_rc;
+ else
+ rc = FAILURE;
+ }
+ else
+ rc = FAILURE;
+
+exit:
+ if (rc == SUCCESS)
+ c->isconnected = 1;
+ return rc;
+}
+
+
+int MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+ int rc = FAILURE;
+ Timer timer;
+ int len = 0;
+ MQTTString topic = MQTTString_initializer;
+ topic.cstring = (char *)topicFilter;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->command_timeout_ms);
+
+ if (!c->isconnected)
+ goto exit;
+
+ len = MQTTSerialize_subscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic, (int*)&qos);
+ if (len <= 0)
+ goto exit;
+ if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+ goto exit; // there was a problem
+
+ if (waitfor(c, SUBACK, &timer) == SUBACK) // wait for suback
+ {
+ int count = 0, grantedQoS = -1;
+ unsigned short mypacketid;
+ if (MQTTDeserialize_suback(&mypacketid, 1, &count, &grantedQoS, c->readbuf, c->readbuf_size) == 1)
+ rc = grantedQoS; // 0, 1, 2 or 0x80
+ if (rc != 0x80)
+ {
+ int i;
+ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if (c->messageHandlers[i].topicFilter == 0)
+ {
+ c->messageHandlers[i].topicFilter = topicFilter;
+ c->messageHandlers[i].fp = messageHandler;
+ rc = 0;
+ break;
+ }
+ }
+ }
+ }
+ else
+ rc = FAILURE;
+
+exit:
+ return rc;
+}
+
+int messageHandlersFindIndex(Client* c, const char* topicFilter)
+{
+ int i;
+ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if ((c->messageHandlers[i].topicFilter != NULL)
+ && (strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int MQTTUnsubscribe(Client* c, const char* topicFilter)
+{
+ int rc = FAILURE;
+ Timer timer;
+ MQTTString topic = MQTTString_initializer;
+ topic.cstring = (char *)topicFilter;
+ int len = 0;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->command_timeout_ms);
+
+ if (!c->isconnected)
+ goto exit;
+ if(messageHandlersFindIndex(c,topicFilter) < 0)
+ {
+ printf("This topic is not subscribed and cannot be unsubscribed.\n");
+ goto exit;
+ }
+ if ((len = MQTTSerialize_unsubscribe(c->buf, c->buf_size, 0, getNextPacketId(c), 1, &topic)) <= 0)
+ goto exit;
+ if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+ goto exit; // there was a problem
+ if (waitfor(c, UNSUBACK, &timer) == UNSUBACK)
+ {
+ unsigned short mypacketid; // should be the same as the packetid above
+ if (MQTTDeserialize_unsuback(&mypacketid, c->readbuf, c->readbuf_size) == 1)
+ {
+ int i;
+ for (i = 0; i < MAX_MESSAGE_HANDLERS; ++i)
+ {
+ if ((c->messageHandlers[i].topicFilter != NULL)
+ && (strcmp(c->messageHandlers[i].topicFilter, topicFilter) == 0))
+ {
+ c->messageHandlers[i].topicFilter=NULL;
+ rc = 0;
+ }
+ }
+ }
+ }
+ else
+ rc = FAILURE;
+
+exit:
+ return rc;
+}
+
+
+int MQTTPublish(Client* c, const char* topicName, MQTTMessage* message)
+{
+ int rc = FAILURE;
+ Timer timer;
+ MQTTString topic = MQTTString_initializer;
+ topic.cstring = (char *)topicName;
+ int len = 0;
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->command_timeout_ms);
+
+ if (!c->isconnected)
+ goto exit;
+ if (message->qos == QOS1 || message->qos == QOS2)
+ message->id = getNextPacketId(c);
+
+ len = MQTTSerialize_publish(c->buf, c->buf_size, 0, message->qos, message->retained, message->id,
+ topic, (unsigned char*)message->payload, message->payloadlen);
+
+ if (len <= 0)
+ goto exit;
+ if ((rc = sendPacket(c, len, &timer)) != SUCCESS) // send the subscribe packet
+ goto exit; // there was a problem
+
+ if (message->qos == QOS1)
+ {
+ if (waitfor(c, PUBACK, &timer) == PUBACK)
+ {
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+ rc = FAILURE;
+ }
+ else
+ rc = FAILURE;
+ }
+ else if (message->qos == QOS2)
+ {
+ if (waitfor(c, PUBCOMP, &timer) == PUBCOMP)
+ {
+ unsigned short mypacketid;
+ unsigned char dup, type;
+ if (MQTTDeserialize_ack(&type, &dup, &mypacketid, c->readbuf, c->readbuf_size) != 1)
+ rc = FAILURE;
+ }
+ else
+ rc = FAILURE;
+ }
+
+exit:
+ return rc;
+}
+
+
+int MQTTDisconnect(Client* c ,Network * n)
+{
+ int rc = FAILURE;
+ Timer timer; // we might wait for incomplete incoming publishes to complete
+ int len = MQTTSerialize_disconnect(c->buf, c->buf_size);
+
+ InitTimer(&timer);
+ countdown_ms(&timer, c->command_timeout_ms);
+
+ if (len > 0)
+ rc = sendPacket(c, len, &timer); // send the disconnect packet
+
+ c->isconnected = 0;
+ n->disconnect(n);
+ return rc;
+}
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTClient.h b/mbtk/libmbtk_lib/mqtt/MQTTClient.h
new file mode 100755
index 0000000..890a11b
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTClient.h
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander/Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef __MQTT_CLIENT_C_
+#define __MQTT_CLIENT_C_
+
+#include "MQTTPacket.h"
+#include "stdio.h"
+#include "MQTTLinux.h"
+
+#define MAX_PACKET_ID 65535
+#define MAX_MESSAGE_HANDLERS 5
+#define MAX_FAIL_ALLOWED 2
+
+enum QoS { QOS0, QOS1, QOS2 };
+
+// all failure return codes must be negative
+enum returnCode {DISCONNECTED = -3, BUFFER_OVERFLOW = -2, FAILURE = -1, SUCCESS = 0 };
+
+void NewTimer(Timer*);
+
+typedef struct MQTTMessage MQTTMessage;
+
+typedef struct MessageData MessageData;
+
+struct MQTTMessage
+{
+ enum QoS qos;
+ char retained;
+ char dup;
+ unsigned short id;
+ void *payload;
+ size_t payloadlen;
+};
+
+struct MessageData
+{
+ MQTTMessage* message;
+ MQTTString* topicName;
+};
+
+typedef struct {
+ char clientId[255];
+ char deviceToken[255];
+} regnwl_info_t;
+
+typedef void (*messageHandler)(MessageData*);
+
+typedef struct Client Client;
+
+int MQTTConnect (Client*, MQTTPacket_connectData*);
+int MQTTPublish (Client*, const char*, MQTTMessage*);
+int MQTTSubscribe (Client*, const char*, enum QoS, messageHandler);
+int MQTTUnsubscribe (Client*, const char*);
+int MQTTDisconnect (Client*,Network*);
+int MQTTYield (Client*, int);
+
+void setDefaultMessageHandler(Client*, messageHandler);
+
+void MQTTClient(Client*, Network*, unsigned int, unsigned char*, size_t, unsigned char*, size_t);
+
+struct Client {
+ unsigned int next_packetid;
+ unsigned int command_timeout_ms;
+ size_t buf_size, readbuf_size;
+ unsigned char *buf;
+ unsigned char *readbuf;
+ unsigned int keepAliveInterval;
+ char ping_outstanding;
+ int fail_count;
+ int isconnected;
+
+ struct MessageHandlers
+ {
+ const char* topicFilter;
+ void (*fp) (MessageData*);
+ } messageHandlers[MAX_MESSAGE_HANDLERS]; // Message handlers are indexed by subscription topic
+
+ void (*defaultMessageHandler) (MessageData*);
+
+ Network* ipstack;
+ Timer ping_timer;
+};
+
+#define DefaultClient {0, 0, 0, 0, NULL, NULL, 0, 0, 0}
+
+#endif
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTLinux.c b/mbtk/libmbtk_lib/mqtt/MQTTLinux.c
new file mode 100755
index 0000000..cdfd548
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTLinux.c
@@ -0,0 +1,204 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+// #include <openssl/ssl.h>
+// #include <openssl/err.h>
+#include "MQTTLinux.h"
+//#include "global.h"
+//#include "DC_iot_port.h"
+#include "mbtk_sock2.h"
+#define TIMEOUT 60*1000
+
+char expired(Timer* timer)
+{
+ struct timeval now, res;
+ gettimeofday(&now, NULL);
+ timersub(&timer->end_time, &now, &res);
+ return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0);
+}
+
+
+void countdown_ms(Timer* timer, unsigned int timeout)
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ struct timeval interval = {timeout / 1000, (timeout % 1000) * 1000};
+ timeradd(&now, &interval, &timer->end_time);
+}
+
+
+void countdown(Timer* timer, unsigned int timeout)
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ struct timeval interval = {timeout, 0};
+ timeradd(&now, &interval, &timer->end_time);
+}
+
+
+int left_ms(Timer* timer)
+{
+ struct timeval now, res;
+ gettimeofday(&now, NULL);
+ timersub(&timer->end_time, &now, &res);
+ //printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000);
+ return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000;
+}
+
+
+void InitTimer(Timer* timer)
+{
+ timer->end_time = (struct timeval){0, 0};
+}
+
+
+int linux_read(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+
+ int err;
+ int read_len = mbtk_sock_read(n->handle,n->my_socket, buffer, len, TIMEOUT, &err);
+ if(read_len < 0) {
+ if(err == MBTK_SOCK_ETIMEOUT) {
+ return -2;
+ } else {
+ return -1;
+ }
+ } else {
+ return read_len;
+ }
+
+
+
+#if 0
+
+ struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000};
+ //mDEBUG("[%s]timeout_ms = %d \n", __FUNCTION__, timeout_ms);
+ if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0))
+ {
+ interval.tv_sec = 0;
+ interval.tv_usec = 100;
+ }
+
+ setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval));
+
+ int bytes = 0;
+ while (bytes < len)
+ {
+
+ int rc = recv(n->my_socket, &buffer[bytes], (size_t)(len - bytes), 0);
+ //mDEBUG("[%s]socket recv rc = %d \n", __FUNCTION__, rc);
+
+ if(rc == 0)
+ {
+ //mDEBUG("[%s]socket close \n", __FUNCTION__);
+ bytes = 0;
+ break;
+ }
+
+ if (rc == -1)
+ {
+ if (errno != ENOTCONN && errno != ECONNRESET)
+ {
+ bytes = -1;
+ break;
+ }
+ }
+ else
+ bytes += rc;
+ }
+ return bytes;
+#endif
+}
+
+
+int linux_write(Network* n, unsigned char* buffer, int len, int timeout_ms)
+{
+
+ int err;
+ printf("Write[%d]:%s",len,(char*)buffer);
+ return mbtk_sock_write(n->handle, n->my_socket, buffer, len, TIMEOUT, &err);
+
+#if 0
+ struct timeval tv;
+
+ tv.tv_sec = 0; /* 30 Secs Timeout */
+ tv.tv_usec = timeout_ms * 1000; // Not init'ing this can cause strange errors
+
+ setsockopt(n->my_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
+
+ int rc = write(n->my_socket, buffer, len);
+
+ return rc;
+#endif
+}
+
+
+void linux_disconnect(Network* n)
+{
+ int errno;
+ mbtk_sock_close(n->handle,n->my_socket,TIMEOUT,&errno);
+}
+
+
+void NewNetwork(Network* n)
+{
+
+ n->my_socket = 0;
+ n->mqttread = linux_read;
+ n->mqttwrite = linux_write;
+ n->disconnect = linux_disconnect;
+ n->ingnore_cert = true;
+ n->is_support_ssl = false;
+}
+
+
+int ConnectNetwork(Network* n, char* addr, int port, bool is_support_ssl, bool ingnore_cert)
+{
+ mbtk_init_info *info ;
+ mbtk_sock_info *sock_info;
+ int rc = 0;
+ int errno;
+ info = NULL;
+ sock_info = (mbtk_sock_info *)malloc(sizeof(mbtk_sock_info));
+ if(sock_info ==NULL)
+ {
+ rc = -1;
+ return rc;
+ }
+ memcpy(sock_info->address, addr, strlen(addr));
+ sock_info->port = port;
+ sock_info->is_support_ssl = is_support_ssl;
+ sock_info->ingnore_cert = ingnore_cert;
+
+ printf("host %s\nport %d\nis_support_ssl %d\ningnore_cert %d\n",sock_info->address,sock_info->port,sock_info->is_support_ssl,sock_info->ingnore_cert);
+
+ mbtk_sock_handle handle = mbtk_sock_init(info);
+ if (handle < 0 )
+ {
+ rc = -1;
+ return rc;
+ }
+
+ int fd = mbtk_sock_open(handle, sock_info, TIMEOUT, &errno);
+ if(fd < 0)
+ {
+ rc = -1;
+ return rc;
+ }
+
+ n->my_socket = fd;
+ n->handle = handle;
+ return rc;
+}
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTLinux.h b/mbtk/libmbtk_lib/mqtt/MQTTLinux.h
new file mode 100755
index 0000000..6ca888a
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTLinux.h
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Allan Stockdill-Mander - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#ifndef __MQTT_LINUX_
+#define __MQTT_LINUX_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+
+// #include <openssl/ssl.h>
+// #include <openssl/err.h>
+//#include "DC_iot_port.h"
+
+typedef struct Timer Timer;
+
+struct Timer {
+ struct timeval end_time;
+};
+
+typedef struct Network Network;
+struct Network
+{
+ int my_socket;
+ bool is_support_ssl;
+ bool ingnore_cert;
+ int handle;
+ int (*mqttread) (Network*, unsigned char*, int, int);
+ int (*mqttwrite) (Network*, unsigned char*, int, int);
+ void (*disconnect) (Network*);
+};
+
+char expired(Timer*);
+void countdown_ms(Timer*, unsigned int);
+void countdown(Timer*, unsigned int);
+int left_ms(Timer*);
+
+void InitTimer(Timer*);
+
+int linux_read(Network*, unsigned char*, int, int);
+int linux_write(Network*, unsigned char*, int, int);
+void linux_disconnect(Network*);
+void NewNetwork(Network*);
+
+int ConnectNetwork(Network*, char*, int, bool ,bool );
+
+#endif
\ No newline at end of file
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnect.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnect.h
new file mode 100755
index 0000000..d77f18c
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnect.h
@@ -0,0 +1,136 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTCONNECT_H_
+#define MQTTCONNECT_H_
+
+#if !defined(DLLImport)
+ #define DLLImport
+#endif
+#if !defined(DLLExport)
+ #define DLLExport
+#endif
+
+
+typedef union
+{
+ unsigned char all; /**< all connect flags */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int username : 1; /**< 3.1 user name */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int will : 1; /**< will flag */
+ unsigned int cleansession : 1; /**< clean session flag */
+ unsigned int : 1; /**< unused */
+ } bits;
+#else
+ struct
+ {
+ unsigned int : 1; /**< unused */
+ unsigned int cleansession : 1; /**< cleansession flag */
+ unsigned int will : 1; /**< will flag */
+ unsigned int willQoS : 2; /**< will QoS value */
+ unsigned int willRetain : 1; /**< will retain setting */
+ unsigned int password : 1; /**< 3.1 password */
+ unsigned int username : 1; /**< 3.1 user name */
+ } bits;
+#endif
+} MQTTConnectFlags; /**< connect flags byte */
+
+
+
+/**
+ * Defines the MQTT "Last Will and Testament" (LWT) settings for
+ * the connect packet.
+ */
+typedef struct
+{
+ /** The eyecatcher for this structure. must be MQTW. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0 */
+ int struct_version;
+ /** The LWT topic to which the LWT message will be published. */
+ MQTTString topicName;
+ /** The LWT payload. */
+ MQTTString message;
+ /**
+ * The retained flag for the LWT message (see MQTTAsync_message.retained).
+ */
+ unsigned char retained;
+ /**
+ * The quality of service setting for the LWT message (see
+ * MQTTAsync_message.qos and @ref qos).
+ */
+ char qos;
+} MQTTPacket_willOptions;
+
+
+#define MQTTPacket_willOptions_initializer { {'M', 'Q', 'T', 'W'}, 0, {NULL, {0, NULL}}, {NULL, {0, NULL}}, 0, 0 }
+
+
+typedef struct
+{
+ /** The eyecatcher for this structure. must be MQTC. */
+ char struct_id[4];
+ /** The version number of this structure. Must be 0 */
+ int struct_version;
+ /** Version of MQTT to be used. 3 = 3.1 4 = 3.1.1
+ */
+ unsigned char MQTTVersion;
+ MQTTString clientID;
+ unsigned short keepAliveInterval;
+ unsigned char cleansession;
+ unsigned char willFlag;
+ MQTTPacket_willOptions will;
+ MQTTString username;
+ MQTTString password;
+} MQTTPacket_connectData;
+
+typedef union
+{
+ unsigned char all; /**< all connack flags */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int sessionpresent : 1; /**< session present flag */
+ unsigned int : 7; /**< unused */
+ } bits;
+#else
+ struct
+ {
+ unsigned int : 7; /**< unused */
+ unsigned int sessionpresent : 1; /**< session present flag */
+ } bits;
+#endif
+} MQTTConnackFlags; /**< connack flags byte */
+
+#define MQTTPacket_connectData_initializer { {'M', 'Q', 'T', 'C'}, 0, 4, {NULL, {0, NULL}}, 60, 1, 0, \
+ MQTTPacket_willOptions_initializer, {NULL, {0, NULL}}, {NULL, {0, NULL}} }
+
+DLLExport int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options);
+DLLExport int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent);
+DLLExport int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen);
+
+DLLExport int MQTTSerialize_disconnect(unsigned char* buf, int buflen);
+DLLExport int MQTTSerialize_pingreq(unsigned char* buf, int buflen);
+
+#endif /* MQTTCONNECT_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectClient.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectClient.c
new file mode 100755
index 0000000..405c23e
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectClient.c
@@ -0,0 +1,211 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT connect packet that would be produced using the supplied connect options.
+ * @param options the options to be used to build the connect packet
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_connectLength(MQTTPacket_connectData* options)
+{
+ int len = 0;
+
+ FUNC_ENTRY;
+
+ if (options->MQTTVersion == 3)
+ len = 12; /* variable depending on MQTT or MQIsdp */
+ else if (options->MQTTVersion == 4)
+ len = 10;
+
+ len += MQTTstrlen(options->clientID)+2;
+ if (options->willFlag)
+ len += MQTTstrlen(options->will.topicName)+2 + MQTTstrlen(options->will.message)+2;
+ if (options->username.cstring || options->username.lenstring.data)
+ len += MQTTstrlen(options->username)+2;
+ if (options->password.cstring || options->password.lenstring.data)
+ len += MQTTstrlen(options->password)+2;
+
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+/**
+ * Serializes the connect options into the buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param len the length in bytes of the supplied buffer
+ * @param options the options to be used to build the connect packet
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_connect(unsigned char* buf, int buflen, MQTTPacket_connectData* options)
+{
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ MQTTConnectFlags flags = {0};
+ int len = 0;
+ int rc = -1;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(len = MQTTSerialize_connectLength(options)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = CONNECT;
+ writeChar(&ptr, header.byte); /* write header */
+ ptr += MQTTPacket_encode(ptr, len); /* write remaining length */
+ if (options->MQTTVersion == 4)
+ {
+ writeCString(&ptr, "MQTT");
+ writeChar(&ptr, (char) 4);
+ }
+ else
+ {
+ writeCString(&ptr, "MQIsdp");
+ writeChar(&ptr, (char) 3);
+ }
+
+ flags.all = 0;
+ flags.bits.cleansession = options->cleansession;
+ flags.bits.will = (options->willFlag) ? 1 : 0;
+ if (flags.bits.will)
+ {
+ flags.bits.willQoS = options->will.qos;
+ flags.bits.willRetain = options->will.retained;
+ }
+
+ if (options->username.cstring || options->username.lenstring.data)
+ flags.bits.username = 1;
+ if (options->password.cstring || options->password.lenstring.data)
+ flags.bits.password = 1;
+ writeChar(&ptr, flags.all);
+ writeInt(&ptr, options->keepAliveInterval);
+ writeMQTTString(&ptr, options->clientID);
+ if (options->willFlag)
+ {
+ writeMQTTString(&ptr, options->will.topicName);
+ writeMQTTString(&ptr, options->will.message);
+ }
+ if (flags.bits.username)
+ writeMQTTString(&ptr, options->username);
+ if (flags.bits.password)
+ writeMQTTString(&ptr, options->password);
+
+ rc = ptr - buf;
+
+ exit: FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into connack data - return code
+ * @param sessionPresent the session present flag returned (only for MQTT 3.1.1)
+ * @param connack_rc returned integer value of the connack return code
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param len the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_connack(unsigned char* sessionPresent, unsigned char* connack_rc, unsigned char* buf, int buflen)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+ MQTTConnackFlags flags = {0};
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != CONNACK)
+ goto exit;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ flags.all = readChar(&curdata);
+ *sessionPresent = flags.bits.sessionpresent;
+ *connack_rc = readChar(&curdata);
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes a 0-length packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @param packettype the message type
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_zero(unsigned char* buf, int buflen, unsigned char packettype)
+{
+ MQTTHeader header = {0};
+ int rc = -1;
+ unsigned char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = packettype;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 0); /* write remaining length */
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_disconnect(unsigned char* buf, int buflen)
+{
+ return MQTTSerialize_zero(buf, buflen, DISCONNECT);
+}
+
+
+/**
+ * Serializes a disconnect packet into the supplied buffer, ready for writing to a socket
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer, to avoid overruns
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_pingreq(unsigned char* buf, int buflen)
+{
+ return MQTTSerialize_zero(buf, buflen, PINGREQ);
+}
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectServer.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectServer.c
new file mode 100755
index 0000000..7c1fe50
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTConnectServer.c
@@ -0,0 +1,148 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? a : b)
+
+
+/**
+ * Validates MQTT protocol name and version combinations
+ * @param protocol the MQTT protocol name as an MQTTString
+ * @param version the MQTT protocol version number, as in the connect packet
+ * @return correct MQTT combination? 1 is true, 0 is false
+ */
+int MQTTPacket_checkVersion(MQTTString* protocol, int version)
+{
+ int rc = 0;
+
+ if (version == 3 && memcmp(protocol->lenstring.data, "MQIsdp",
+ min(6, protocol->lenstring.len)) == 0)
+ rc = 1;
+ else if (version == 4 && memcmp(protocol->lenstring.data, "MQTT",
+ min(4, protocol->lenstring.len)) == 0)
+ rc = 1;
+ return rc;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into connect data structure
+ * @param data the connect data structure to be filled out
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param len the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_connect(MQTTPacket_connectData* data, unsigned char* buf, int len)
+{
+ MQTTHeader header = {0};
+ MQTTConnectFlags flags = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = &buf[len];
+ int rc = 0;
+ MQTTString Protocol;
+ int version;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != CONNECT)
+ goto exit;
+
+ curdata += MQTTPacket_decodeBuf(curdata, &mylen); /* read remaining length */
+
+ if (!readMQTTLenString(&Protocol, &curdata, enddata) ||
+ enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+ goto exit;
+
+ version = (int)readChar(&curdata); /* Protocol version */
+ /* If we don't recognize the protocol version, we don't parse the connect packet on the
+ * basis that we don't know what the format will be.
+ */
+ if (MQTTPacket_checkVersion(&Protocol, version))
+ {
+ flags.all = readChar(&curdata);
+ data->cleansession = flags.bits.cleansession;
+ data->keepAliveInterval = readInt(&curdata);
+ if (!readMQTTLenString(&data->clientID, &curdata, enddata))
+ goto exit;
+ data->willFlag = flags.bits.will;
+ if (flags.bits.will)
+ {
+ data->will.qos = flags.bits.willQoS;
+ data->will.retained = flags.bits.willRetain;
+ if (!readMQTTLenString(&data->will.topicName, &curdata, enddata) ||
+ !readMQTTLenString(&data->will.message, &curdata, enddata))
+ goto exit;
+ }
+ if (flags.bits.username)
+ {
+ if (enddata - curdata < 3 || !readMQTTLenString(&data->username, &curdata, enddata))
+ goto exit; /* username flag set, but no username supplied - invalid */
+ if (flags.bits.password &&
+ (enddata - curdata < 3 || !readMQTTLenString(&data->password, &curdata, enddata)))
+ goto exit; /* password flag set, but no password supplied - invalid */
+ }
+ else if (flags.bits.password)
+ goto exit; /* password flag set without username - invalid */
+ rc = 1;
+ }
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the connack packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param connack_rc the integer connack return code to be used
+ * @param sessionPresent the MQTT 3.1.1 sessionPresent flag
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_connack(unsigned char* buf, int buflen, unsigned char connack_rc, unsigned char sessionPresent)
+{
+ MQTTHeader header = {0};
+ int rc = 0;
+ unsigned char *ptr = buf;
+ MQTTConnackFlags flags = {0};
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = CONNACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+ flags.all = 0;
+ flags.bits.sessionpresent = sessionPresent;
+ writeChar(&ptr, flags.all);
+ writeChar(&ptr, connack_rc);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTDeserializePublish.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTDeserializePublish.c
new file mode 100755
index 0000000..dbc9e5d
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTDeserializePublish.c
@@ -0,0 +1,107 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+#include <string.h>
+
+#define min(a, b) ((a < b) ? 1 : 0)
+
+/**
+ * Deserializes the supplied (wire) buffer into publish data
+ * @param dup returned integer - the MQTT dup flag
+ * @param qos returned integer - the MQTT QoS value
+ * @param retained returned integer - the MQTT retained flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param topicName returned MQTTString - the MQTT topic in the publish
+ * @param payload returned byte buffer - the MQTT publish payload
+ * @param payloadlen returned integer - the length of the MQTT payload
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success
+ */
+int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+ unsigned char** payload, int* payloadlen, unsigned char* buf, int buflen)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != PUBLISH)
+ goto exit;
+ *dup = header.bits.dup;
+ *qos = header.bits.qos;
+ *retained = header.bits.retain;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ if (!readMQTTLenString(topicName, &curdata, enddata) ||
+ enddata - curdata < 0) /* do we have enough data to read the protocol version byte? */
+ goto exit;
+
+ if (*qos > 0)
+ *packetid = readInt(&curdata);
+
+ *payloadlen = enddata - curdata;
+ *payload = curdata;
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Deserializes the supplied (wire) buffer into an ack
+ * @param packettype returned integer - the MQTT packet type
+ * @param dup returned integer - the MQTT dup flag
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ *dup = header.bits.dup;
+ *packettype = header.bits.type;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ if (enddata - curdata < 2)
+ goto exit;
+ *packetid = readInt(&curdata);
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.c
new file mode 100755
index 0000000..3015a0e
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.c
@@ -0,0 +1,258 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+
+const char* MQTTPacket_names[] =
+{
+ "RESERVED", "CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL",
+ "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK",
+ "PINGREQ", "PINGRESP", "DISCONNECT"
+};
+
+
+const char* MQTTPacket_getName(unsigned short packetid)
+{
+ return MQTTPacket_names[packetid];
+}
+
+
+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data)
+{
+ int strindex = 0;
+
+ strindex = snprintf(strbuf, strbuflen,
+ "CONNECT MQTT version %d, client id %.*s, clean session %d, keep alive %d",
+ (int)data->MQTTVersion, data->clientID.lenstring.len, data->clientID.lenstring.data,
+ (int)data->cleansession, data->keepAliveInterval);
+ if (data->willFlag)
+ strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+ ", will QoS %d, will retain %d, will topic %.*s, will message %.*s",
+ data->will.qos, data->will.retained,
+ data->will.topicName.lenstring.len, data->will.topicName.lenstring.data,
+ data->will.message.lenstring.len, data->will.message.lenstring.data);
+ if (data->username.lenstring.data && data->username.lenstring.len > 0)
+ strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+ ", user name %.*s", data->username.lenstring.len, data->username.lenstring.data);
+ if (data->password.lenstring.data && data->password.lenstring.len > 0)
+ strindex += snprintf(&strbuf[strindex], strbuflen - strindex,
+ ", password %.*s", data->password.lenstring.len, data->password.lenstring.data);
+ return strindex;
+}
+
+
+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent)
+{
+ int strindex = snprintf(strbuf, strbuflen, "CONNACK session present %d, rc %d", sessionPresent, connack_rc);
+ return strindex;
+}
+
+
+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
+ unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+ int strindex = snprintf(strbuf, strbuflen,
+ "PUBLISH dup %d, QoS %d, retained %d, packet id %d, topic %.*s, payload length %d, payload %.*s",
+ dup, qos, retained, packetid,
+ (topicName.lenstring.len < 20) ? topicName.lenstring.len : 20, topicName.lenstring.data,
+ payloadlen, (payloadlen < 20) ? payloadlen : 20, payload);
+ return strindex;
+}
+
+
+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+ int strindex = snprintf(strbuf, strbuflen, "%s, packet id %d", MQTTPacket_names[packettype], packetid);
+ if (dup)
+ strindex += snprintf(strbuf + strindex, strbuflen - strindex, ", dup %d", dup);
+ return strindex;
+}
+
+
+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
+ MQTTString topicFilters[], int requestedQoSs[])
+{
+ return snprintf(strbuf, strbuflen,
+ "SUBSCRIBE dup %d, packet id %d count %d topic %.*s qos %d",
+ dup, packetid, count,
+ topicFilters[0].lenstring.len, topicFilters[0].lenstring.data,
+ requestedQoSs[0]);
+}
+
+
+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs)
+{
+ return snprintf(strbuf, strbuflen,
+ "SUBACK packet id %d count %d granted qos %d", packetid, count, grantedQoSs[0]);
+}
+
+
+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
+ int count, MQTTString topicFilters[])
+{
+ return snprintf(strbuf, strbuflen,
+ "UNSUBSCRIBE dup %d, packet id %d count %d topic %.*s",
+ dup, packetid, count,
+ topicFilters[0].lenstring.len, topicFilters[0].lenstring.data);
+}
+
+
+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
+{
+ int index = 0;
+ int rem_length = 0;
+ MQTTHeader header = {0};
+ int strindex = 0;
+
+ header.byte = buf[index++];
+ index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
+
+ switch (header.bits.type)
+ {
+ case CONNACK:
+ {
+ unsigned char sessionPresent, connack_rc;
+ if (MQTTDeserialize_connack(&sessionPresent, &connack_rc, buf, buflen) == 1)
+ strindex = MQTTStringFormat_connack(strbuf, strbuflen, connack_rc, sessionPresent);
+ }
+ break;
+ case PUBLISH:
+ {
+ unsigned char dup, retained, *payload;
+ unsigned short packetid;
+ int qos, payloadlen;
+ MQTTString topicName = MQTTString_initializer;
+ if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
+ &payload, &payloadlen, buf, buflen) == 1)
+ strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
+ topicName, payload, payloadlen);
+ }
+ break;
+ case PUBACK:
+ case PUBREC:
+ case PUBREL:
+ case PUBCOMP:
+ {
+ unsigned char packettype, dup;
+ unsigned short packetid;
+ if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
+ strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
+ }
+ break;
+ case SUBACK:
+ {
+ unsigned short packetid;
+ int maxcount = 1, count = 0;
+ int grantedQoSs[1];
+ if (MQTTDeserialize_suback(&packetid, maxcount, &count, grantedQoSs, buf, buflen) == 1)
+ strindex = MQTTStringFormat_suback(strbuf, strbuflen, packetid, count, grantedQoSs);
+ }
+ break;
+ case UNSUBACK:
+ {
+ unsigned short packetid;
+ if (MQTTDeserialize_unsuback(&packetid, buf, buflen) == 1)
+ strindex = MQTTStringFormat_ack(strbuf, strbuflen, UNSUBACK, 0, packetid);
+ }
+ break;
+ case PINGREQ:
+ case PINGRESP:
+ case DISCONNECT:
+ strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
+ break;
+ }
+ return strbuf;
+}
+
+
+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen)
+{
+ int index = 0;
+ int rem_length = 0;
+ MQTTHeader header = {0};
+ int strindex = 0;
+
+ header.byte = buf[index++];
+ index += MQTTPacket_decodeBuf(&buf[index], &rem_length);
+
+ switch (header.bits.type)
+ {
+ case CONNECT:
+ {
+ MQTTPacket_connectData data;
+ int rc;
+ if ((rc = MQTTDeserialize_connect(&data, buf, buflen)) == 1)
+ strindex = MQTTStringFormat_connect(strbuf, strbuflen, &data);
+ }
+ break;
+ case PUBLISH:
+ {
+ unsigned char dup, retained, *payload;
+ unsigned short packetid;
+ int qos, payloadlen;
+ MQTTString topicName = MQTTString_initializer;
+ if (MQTTDeserialize_publish(&dup, &qos, &retained, &packetid, &topicName,
+ &payload, &payloadlen, buf, buflen) == 1)
+ strindex = MQTTStringFormat_publish(strbuf, strbuflen, dup, qos, retained, packetid,
+ topicName, payload, payloadlen);
+ }
+ break;
+ case PUBACK:
+ case PUBREC:
+ case PUBREL:
+ case PUBCOMP:
+ {
+ unsigned char packettype, dup;
+ unsigned short packetid;
+ if (MQTTDeserialize_ack(&packettype, &dup, &packetid, buf, buflen) == 1)
+ strindex = MQTTStringFormat_ack(strbuf, strbuflen, packettype, dup, packetid);
+ }
+ break;
+ case SUBSCRIBE:
+ {
+ unsigned char dup;
+ unsigned short packetid;
+ int maxcount = 1, count = 0;
+ MQTTString topicFilters[1];
+ int requestedQoSs[1];
+ if (MQTTDeserialize_subscribe(&dup, &packetid, maxcount, &count,
+ topicFilters, requestedQoSs, buf, buflen) == 1)
+ strindex = MQTTStringFormat_subscribe(strbuf, strbuflen, dup, packetid, count, topicFilters, requestedQoSs);;
+ }
+ break;
+ case UNSUBSCRIBE:
+ {
+ unsigned char dup;
+ unsigned short packetid;
+ int maxcount = 1, count = 0;
+ MQTTString topicFilters[1];
+ if (MQTTDeserialize_unsubscribe(&dup, &packetid, maxcount, &count, topicFilters, buf, buflen) == 1)
+ strindex = MQTTStringFormat_unsubscribe(strbuf, strbuflen, dup, packetid, count, topicFilters);
+ }
+ break;
+ case PINGREQ:
+ case PINGRESP:
+ case DISCONNECT:
+ strindex = snprintf(strbuf, strbuflen, "%s", MQTTPacket_names[header.bits.type]);
+ break;
+ }
+ strbuf[strbuflen] = '\0';
+ return strbuf;
+}
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.h
new file mode 100755
index 0000000..f7bd0d1
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTFormat.h
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#if !defined(MQTTFORMAT_H)
+#define MQTTFORMAT_H
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+const char* MQTTPacket_getName(unsigned short packetid);
+int MQTTStringFormat_connect(char* strbuf, int strbuflen, MQTTPacket_connectData* data);
+int MQTTStringFormat_connack(char* strbuf, int strbuflen, unsigned char connack_rc, unsigned char sessionPresent);
+int MQTTStringFormat_publish(char* strbuf, int strbuflen, unsigned char dup, int qos, unsigned char retained,
+ unsigned short packetid, MQTTString topicName, unsigned char* payload, int payloadlen);
+int MQTTStringFormat_ack(char* strbuf, int strbuflen, unsigned char packettype, unsigned char dup, unsigned short packetid);
+int MQTTStringFormat_subscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid, int count,
+ MQTTString topicFilters[], int requestedQoSs[]);
+int MQTTStringFormat_suback(char* strbuf, int strbuflen, unsigned short packetid, int count, int* grantedQoSs);
+int MQTTStringFormat_unsubscribe(char* strbuf, int strbuflen, unsigned char dup, unsigned short packetid,
+ int count, MQTTString topicFilters[]);
+char* MQTTFormat_toClientString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+char* MQTTFormat_toServerString(char* strbuf, int strbuflen, unsigned char* buf, int buflen);
+
+#endif
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.c
new file mode 100755
index 0000000..c100f55
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.c
@@ -0,0 +1,410 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Sergio R. Caprile - non-blocking packet read functions for stream transport
+ *******************************************************************************/
+
+#include "StackTrace.h"
+#include "MQTTPacket.h"
+
+#include <string.h>
+
+/**
+ * Encodes the message length according to the MQTT algorithm
+ * @param buf the buffer into which the encoded data is written
+ * @param length the length to be encoded
+ * @return the number of bytes written to buffer
+ */
+int MQTTPacket_encode(unsigned char* buf, int length)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ do
+ {
+ char d = length % 128;
+ length /= 128;
+ /* if there are more digits to encode, set the top bit of this digit */
+ if (length > 0)
+ d |= 0x80;
+ buf[rc++] = d;
+ } while (length > 0);
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Decodes the message length according to the MQTT algorithm
+ * @param getcharfn pointer to function to read the next character from the data source
+ * @param value the decoded length returned
+ * @return the number of bytes read from the socket
+ */
+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value)
+{
+ unsigned char c;
+ int multiplier = 1;
+ int len = 0;
+#define MAX_NO_OF_REMAINING_LENGTH_BYTES 4
+
+ FUNC_ENTRY;
+ *value = 0;
+ do
+ {
+ int rc = MQTTPACKET_READ_ERROR;
+
+ if (++len > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ {
+ rc = MQTTPACKET_READ_ERROR; /* bad data */
+ goto exit;
+ }
+ rc = (*getcharfn)(&c, 1);
+ if (rc != 1)
+ goto exit;
+ *value += (c & 127) * multiplier;
+ multiplier *= 128;
+ } while ((c & 128) != 0);
+exit:
+ FUNC_EXIT_RC(len);
+ return len;
+}
+
+
+int MQTTPacket_len(int rem_len)
+{
+ rem_len += 1; /* header byte */
+
+ /* now remaining_length field */
+ if (rem_len < 128)
+ rem_len += 1;
+ else if (rem_len < 16384)
+ rem_len += 2;
+ else if (rem_len < 2097151)
+ rem_len += 3;
+ else
+ rem_len += 4;
+ return rem_len;
+}
+
+
+static unsigned char* bufptr;
+
+int bufchar(unsigned char* c, int count)
+{
+ int i;
+
+ for (i = 0; i < count; ++i)
+ *c = *bufptr++;
+ return count;
+}
+
+
+int MQTTPacket_decodeBuf(unsigned char* buf, int* value)
+{
+ bufptr = buf;
+ return MQTTPacket_decode(bufchar, value);
+}
+
+
+/**
+ * Calculates an integer from two bytes read from the input buffer
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the integer value calculated
+ */
+int readInt(unsigned char** pptr)
+{
+ unsigned char* ptr = *pptr;
+ int len = 256*(*ptr) + (*(ptr+1));
+ *pptr += 2;
+ return len;
+}
+
+
+/**
+ * Reads one character from the input buffer.
+ * @param pptr pointer to the input buffer - incremented by the number of bytes used & returned
+ * @return the character read
+ */
+char readChar(unsigned char** pptr)
+{
+ char c = **pptr;
+ (*pptr)++;
+ return c;
+}
+
+
+/**
+ * Writes one character to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param c the character to write
+ */
+void writeChar(unsigned char** pptr, char c)
+{
+ **pptr = c;
+ (*pptr)++;
+}
+
+
+/**
+ * Writes an integer as 2 bytes to an output buffer.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param anInt the integer to write
+ */
+void writeInt(unsigned char** pptr, int anInt)
+{
+ **pptr = (unsigned char)(anInt / 256);
+ (*pptr)++;
+ **pptr = (unsigned char)(anInt % 256);
+ (*pptr)++;
+}
+
+
+/**
+ * Writes a "UTF" string to an output buffer. Converts C string to length-delimited.
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param string the C string to write
+ */
+void writeCString(unsigned char** pptr, const char* string)
+{
+ int len = strlen(string);
+ writeInt(pptr, len);
+ memcpy(*pptr, string, len);
+ *pptr += len;
+}
+
+
+int getLenStringLen(char* ptr)
+{
+ int len = 256*((unsigned char)(*ptr)) + (unsigned char)(*(ptr+1));
+ return len;
+}
+
+
+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring)
+{
+ if (mqttstring.lenstring.len > 0)
+ {
+ writeInt(pptr, mqttstring.lenstring.len);
+ memcpy(*pptr, mqttstring.lenstring.data, mqttstring.lenstring.len);
+ *pptr += mqttstring.lenstring.len;
+ }
+ else if (mqttstring.cstring)
+ writeCString(pptr, mqttstring.cstring);
+ else
+ writeInt(pptr, 0);
+}
+
+
+/**
+ * @param mqttstring the MQTTString structure into which the data is to be read
+ * @param pptr pointer to the output buffer - incremented by the number of bytes used & returned
+ * @param enddata pointer to the end of the data: do not read beyond
+ * @return 1 if successful, 0 if not
+ */
+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata)
+{
+ int rc = 0;
+
+ FUNC_ENTRY;
+ /* the first two bytes are the length of the string */
+ if (enddata - (*pptr) > 1) /* enough length to read the integer? */
+ {
+ mqttstring->lenstring.len = readInt(pptr); /* increments pptr to point past length */
+ if (&(*pptr)[mqttstring->lenstring.len] <= enddata)
+ {
+ mqttstring->lenstring.data = (char*)*pptr;
+ *pptr += mqttstring->lenstring.len;
+ rc = 1;
+ }
+ }
+ mqttstring->cstring = NULL;
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Return the length of the MQTTstring - C string if there is one, otherwise the length delimited string
+ * @param mqttstring the string to return the length of
+ * @return the length of the string
+ */
+int MQTTstrlen(MQTTString mqttstring)
+{
+ int rc = 0;
+
+ if (mqttstring.cstring)
+ rc = strlen(mqttstring.cstring);
+ else
+ rc = mqttstring.lenstring.len;
+ return rc;
+}
+
+
+/**
+ * Compares an MQTTString to a C string
+ * @param a the MQTTString to compare
+ * @param bptr the C string to compare
+ * @return boolean - equal or not
+ */
+int MQTTPacket_equals(MQTTString* a, char* bptr)
+{
+ int alen = 0,
+ blen = 0;
+ char *aptr;
+
+ if (a->cstring)
+ {
+ aptr = a->cstring;
+ alen = strlen(a->cstring);
+ }
+ else
+ {
+ aptr = a->lenstring.data;
+ alen = a->lenstring.len;
+ }
+ blen = strlen(bptr);
+
+ return (alen == blen) && (strncmp(aptr, bptr, alen) == 0);
+}
+
+
+/**
+ * Helper function to read packet data from some source into a buffer
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param getfn pointer to a function which will read any number of bytes from the needed source
+ * @return integer MQTT packet type, or -1 on error
+ * @note the whole message must fit into the caller's buffer
+ */
+int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int))
+{
+ int rc = -1;
+ MQTTHeader header = {0};
+ int len = 0;
+ int rem_len = 0;
+
+ /* 1. read the header byte. This has the packet type in it */
+ if ((*getfn)(buf, 1) != 1)
+ goto exit;
+
+ len = 1;
+ /* 2. read the remaining length. This is variable in itself */
+ MQTTPacket_decode(getfn, &rem_len);
+ len += MQTTPacket_encode(buf + 1, rem_len); /* put the original remaining length back into the buffer */
+
+ /* 3. read the rest of the buffer using a callback to supply the rest of the data */
+ if((rem_len + len) > buflen)
+ goto exit;
+ if ((*getfn)(buf + len, rem_len) != rem_len)
+ goto exit;
+
+ header.byte = buf[0];
+ rc = header.bits.type;
+exit:
+ return rc;
+}
+
+/**
+ * Decodes the message length according to the MQTT algorithm, non-blocking
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @param value the decoded length returned
+ * @return integer the number of bytes read from the socket, 0 for call again, or -1 on error
+ */
+static int MQTTPacket_decodenb(MQTTTransport *trp)
+{
+ unsigned char c;
+ int rc = MQTTPACKET_READ_ERROR;
+
+ FUNC_ENTRY;
+ if(trp->len == 0){ /* initialize on first call */
+ trp->multiplier = 1;
+ trp->rem_len = 0;
+ }
+ do {
+ int frc;
+ if (++(trp->len) > MAX_NO_OF_REMAINING_LENGTH_BYTES)
+ goto exit;
+ if ((frc=(*trp->getfn)(trp->sck, &c, 1)) == -1)
+ goto exit;
+ if (frc == 0){
+ rc = 0;
+ goto exit;
+ }
+ trp->rem_len += (c & 127) * trp->multiplier;
+ trp->multiplier *= 128;
+ } while ((c & 128) != 0);
+ rc = trp->len;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+/**
+ * Helper function to read packet data from some source into a buffer, non-blocking
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param trp pointer to a transport structure holding what is needed to solve getting data from it
+ * @return integer MQTT packet type, 0 for call again, or -1 on error
+ * @note the whole message must fit into the caller's buffer
+ */
+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp)
+{
+ int rc = -1, frc;
+ MQTTHeader header = {0};
+
+ switch(trp->state){
+ default:
+ trp->state = 0;
+ /*FALLTHROUGH*/
+ case 0:
+ /* read the header byte. This has the packet type in it */
+ if ((frc=(*trp->getfn)(trp->sck, buf, 1)) == -1)
+ goto exit;
+ if (frc == 0)
+ return 0;
+ trp->len = 0;
+ ++trp->state;
+ /*FALLTHROUGH*/
+ /* read the remaining length. This is variable in itself */
+ case 1:
+ if((frc=MQTTPacket_decodenb(trp)) == MQTTPACKET_READ_ERROR)
+ goto exit;
+ if(frc == 0)
+ return 0;
+ trp->len = 1 + MQTTPacket_encode(buf + 1, trp->rem_len); /* put the original remaining length back into the buffer */
+ if((trp->rem_len + trp->len) > buflen)
+ goto exit;
+ ++trp->state;
+ /*FALLTHROUGH*/
+ case 2:
+ /* read the rest of the buffer using a callback to supply the rest of the data */
+ if ((frc=(*trp->getfn)(trp->sck, buf + trp->len, trp->rem_len)) == -1)
+ goto exit;
+ if (frc == 0)
+ return 0;
+ trp->rem_len -= frc;
+ trp->len += frc;
+ if(trp->rem_len)
+ return 0;
+
+ header.byte = buf[0];
+ rc = header.bits.type;
+ break;
+ }
+
+exit:
+ trp->state = 0;
+ return rc;
+}
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.h
new file mode 100755
index 0000000..f417929
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPacket.h
@@ -0,0 +1,133 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPACKET_H_
+#define MQTTPACKET_H_
+
+#if defined(__cplusplus) /* If this is a C++ compiler, use C linkage */
+extern "C" {
+#endif
+
+#if defined(WIN32_DLL) || defined(WIN64_DLL)
+ #define DLLImport __declspec(dllimport)
+ #define DLLExport __declspec(dllexport)
+#elif defined(LINUX_SO)
+ #define DLLImport extern
+ #define DLLExport __attribute__ ((visibility ("default")))
+#else
+ #define DLLImport
+ #define DLLExport
+#endif
+
+enum errors
+{
+ MQTTPACKET_BUFFER_TOO_SHORT = -2,
+ MQTTPACKET_READ_ERROR = -1,
+ MQTTPACKET_READ_COMPLETE
+};
+
+enum msgTypes
+{
+ CONNECT = 1, CONNACK, PUBLISH, PUBACK, PUBREC, PUBREL,
+ PUBCOMP, SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK,
+ PINGREQ, PINGRESP, DISCONNECT
+};
+
+/**
+ * Bitfields for the MQTT header byte.
+ */
+typedef union
+{
+ unsigned char byte; /**< the whole byte */
+#if defined(REVERSED)
+ struct
+ {
+ unsigned int type : 4; /**< message type nibble */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int retain : 1; /**< retained flag bit */
+ } bits;
+#else
+ struct
+ {
+ unsigned int retain : 1; /**< retained flag bit */
+ unsigned int qos : 2; /**< QoS value, 0, 1 or 2 */
+ unsigned int dup : 1; /**< DUP flag bit */
+ unsigned int type : 4; /**< message type nibble */
+ } bits;
+#endif
+} MQTTHeader;
+
+typedef struct
+{
+ int len;
+ char* data;
+} MQTTLenString;
+
+typedef struct
+{
+ char* cstring;
+ MQTTLenString lenstring;
+} MQTTString;
+
+#define MQTTString_initializer {NULL, {0, NULL}}
+
+int MQTTstrlen(MQTTString mqttstring);
+
+#include "MQTTConnect.h"
+#include "MQTTPublish.h"
+#include "MQTTSubscribe.h"
+#include "MQTTUnsubscribe.h"
+#include "MQTTFormat.h"
+
+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char type, unsigned char dup, unsigned short packetid);
+int MQTTDeserialize_ack(unsigned char* packettype, unsigned char* dup, unsigned short* packetid, unsigned char* buf, int buflen);
+
+int MQTTPacket_len(int rem_len);
+int MQTTPacket_equals(MQTTString* a, char* b);
+
+int MQTTPacket_encode(unsigned char* buf, int length);
+int MQTTPacket_decode(int (*getcharfn)(unsigned char*, int), int* value);
+int MQTTPacket_decodeBuf(unsigned char* buf, int* value);
+
+int readInt(unsigned char** pptr);
+char readChar(unsigned char** pptr);
+void writeChar(unsigned char** pptr, char c);
+void writeInt(unsigned char** pptr, int anInt);
+int readMQTTLenString(MQTTString* mqttstring, unsigned char** pptr, unsigned char* enddata);
+void writeCString(unsigned char** pptr, const char* string);
+void writeMQTTString(unsigned char** pptr, MQTTString mqttstring);
+
+DLLExport int MQTTPacket_read(unsigned char* buf, int buflen, int (*getfn)(unsigned char*, int));
+
+typedef struct {
+ int (*getfn)(void *, unsigned char*, int); /* must return -1 for error, 0 for call again, or the number of bytes read */
+ void *sck; /* pointer to whatever the system may use to identify the transport */
+ int multiplier;
+ int rem_len;
+ int len;
+ char state;
+}MQTTTransport;
+
+int MQTTPacket_readnb(unsigned char* buf, int buflen, MQTTTransport *trp);
+
+#ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
+}
+#endif
+
+
+#endif /* MQTTPACKET_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPublish.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPublish.h
new file mode 100755
index 0000000..d62dddb
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTPublish.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTPUBLISH_H_
+#define MQTTPUBLISH_H_
+
+#if !defined(DLLImport)
+ #define DLLImport
+#endif
+#if !defined(DLLExport)
+ #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+ MQTTString topicName, unsigned char* payload, int payloadlen);
+
+DLLExport int MQTTDeserialize_publish(unsigned char* dup, int* qos, unsigned char* retained, unsigned short* packetid, MQTTString* topicName,
+ unsigned char** payload, int* payloadlen, unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid);
+DLLExport int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid);
+DLLExport int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid);
+
+#endif /* MQTTPUBLISH_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSerializePublish.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSerializePublish.c
new file mode 100755
index 0000000..236791f
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSerializePublish.c
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Ian Craggs - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=453144
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Determines the length of the MQTT publish packet that would be produced using the supplied parameters
+ * @param qos the MQTT QoS of the publish (packetid is omitted for QoS 0)
+ * @param topicName the topic name to be used in the publish
+ * @param payloadlen the length of the payload to be sent
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_publishLength(int qos, MQTTString topicName, int payloadlen)
+{
+ int len = 0;
+
+ len += 2 + MQTTstrlen(topicName) + payloadlen;
+ if (qos > 0)
+ len += 2; /* packetid */
+ return len;
+}
+
+
+/**
+ * Serializes the supplied publish data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param qos integer - the MQTT QoS value
+ * @param retained integer - the MQTT retained flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param topicName MQTTString - the MQTT topic in the publish
+ * @param payload byte buffer - the MQTT publish payload
+ * @param payloadlen integer - the length of the MQTT payload
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_publish(unsigned char* buf, int buflen, unsigned char dup, int qos, unsigned char retained, unsigned short packetid,
+ MQTTString topicName, unsigned char* payload, int payloadlen)
+{
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ int rem_len = 0;
+ int rc = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_publishLength(qos, topicName, payloadlen)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.bits.type = PUBLISH;
+ header.bits.dup = dup;
+ header.bits.qos = qos;
+ header.bits.retain = retained;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeMQTTString(&ptr, topicName);
+
+ if (qos > 0)
+ writeInt(&ptr, packetid);
+
+ memcpy(ptr, payload, payloadlen);
+ ptr += payloadlen;
+
+ rc = ptr - buf;
+
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Serializes the ack packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param type the MQTT packet type
+ * @param dup the MQTT dup flag
+ * @param packetid the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_ack(unsigned char* buf, int buflen, unsigned char packettype, unsigned char dup, unsigned short packetid)
+{
+ MQTTHeader header = {0};
+ int rc = 0;
+ unsigned char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 4)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.bits.type = packettype;
+ header.bits.dup = dup;
+ header.bits.qos = (packettype == PUBREL) ? 1 : 0;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+ writeInt(&ptr, packetid);
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes a puback packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_puback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBACK, 0, packetid);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_pubrel(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBREL, dup, packetid);
+}
+
+
+/**
+ * Serializes a pubrel packet into the supplied buffer.
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return serialized length, or error if 0
+ */
+int MQTTSerialize_pubcomp(unsigned char* buf, int buflen, unsigned short packetid)
+{
+ return MQTTSerialize_ack(buf, buflen, PUBCOMP, 0, packetid);
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribe.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribe.h
new file mode 100755
index 0000000..383ca0d
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribe.h
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTSUBSCRIBE_H_
+#define MQTTSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+ #define DLLImport
+#endif
+#if !defined(DLLExport)
+ #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+ int count, MQTTString topicFilters[], int requestedQoSs[]);
+
+DLLExport int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid,
+ int maxcount, int* count, MQTTString topicFilters[], int requestedQoSs[], unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs);
+
+DLLExport int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int len);
+
+
+#endif /* MQTTSUBSCRIBE_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeClient.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeClient.c
new file mode 100755
index 0000000..5b1ca28
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeClient.c
@@ -0,0 +1,137 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT subscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_subscribeLength(int count, MQTTString topicFilters[])
+{
+ int i;
+ int len = 2; /* packetid */
+
+ for (i = 0; i < count; ++i)
+ len += 2 + MQTTstrlen(topicFilters[i]) + 1; /* length + topic + req_qos */
+ return len;
+}
+
+
+/**
+ * Serializes the supplied subscribe data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied bufferr
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters and reqQos arrays
+ * @param topicFilters - array of topic filter names
+ * @param requestedQoSs - array of requested QoS
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_subscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid, int count,
+ MQTTString topicFilters[], int requestedQoSs[])
+{
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ int rem_len = 0;
+ int rc = 0;
+ int i = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_subscribeLength(count, topicFilters)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = SUBSCRIBE;
+ header.bits.dup = dup;
+ header.bits.qos = 1;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ {
+ writeMQTTString(&ptr, topicFilters[i]);
+ writeChar(&ptr, requestedQoSs[i]);
+ }
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+
+/**
+ * Deserializes the supplied (wire) buffer into suback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the grantedQoSs array
+ * @param count returned integer - number of members in the grantedQoSs array
+ * @param grantedQoSs returned array of integers - the granted qualities of service
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_suback(unsigned short* packetid, int maxcount, int* count, int grantedQoSs[], unsigned char* buf, int buflen)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != SUBACK)
+ goto exit;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+ if (enddata - curdata < 2)
+ goto exit;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (*count > maxcount)
+ {
+ rc = -1;
+ goto exit;
+ }
+ grantedQoSs[(*count)++] = readChar(&curdata);
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeServer.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeServer.c
new file mode 100755
index 0000000..15bb15d
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTSubscribeServer.c
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Deserializes the supplied (wire) buffer into subscribe data
+ * @param dup integer returned - the MQTT dup flag
+ * @param packetid integer returned - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+ * @param count - number of members in the topicFilters and requestedQoSs arrays
+ * @param topicFilters - array of topic filter names
+ * @param requestedQoSs - array of requested QoS
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTDeserialize_subscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
+ int requestedQoSs[], unsigned char* buf, int buflen)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = -1;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != SUBSCRIBE)
+ goto exit;
+ *dup = header.bits.dup;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+ goto exit;
+ if (curdata >= enddata) /* do we have enough data to read the req_qos version byte? */
+ goto exit;
+ requestedQoSs[*count] = readChar(&curdata);
+ (*count)++;
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the supplied suback data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the grantedQoSs array
+ * @param grantedQoSs - array of granted QoS
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_suback(unsigned char* buf, int buflen, unsigned short packetid, int count, int* grantedQoSs)
+{
+ MQTTHeader header = {0};
+ int rc = -1;
+ unsigned char *ptr = buf;
+ int i;
+
+ FUNC_ENTRY;
+ if (buflen < 2 + count)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = SUBACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2 + count); /* write remaining length */
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ writeChar(&ptr, grantedQoSs[i]);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribe.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribe.h
new file mode 100755
index 0000000..1644ae5
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribe.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Xiang Rong - 442039 Add makefile to Embedded C client
+ *******************************************************************************/
+
+#ifndef MQTTUNSUBSCRIBE_H_
+#define MQTTUNSUBSCRIBE_H_
+
+#if !defined(DLLImport)
+ #define DLLImport
+#endif
+#if !defined(DLLExport)
+ #define DLLExport
+#endif
+
+DLLExport int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+ int count, MQTTString topicFilters[]);
+
+DLLExport int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int max_count, int* count, MQTTString topicFilters[],
+ unsigned char* buf, int len);
+
+DLLExport int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid);
+
+DLLExport int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int len);
+
+#endif /* MQTTUNSUBSCRIBE_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeClient.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeClient.c
new file mode 100755
index 0000000..0f8db7b
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeClient.c
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+/**
+ * Determines the length of the MQTT unsubscribe packet that would be produced using the supplied parameters
+ * @param count the number of topic filter strings in topicFilters
+ * @param topicFilters the array of topic filter strings to be used in the publish
+ * @return the length of buffer needed to contain the serialized version of the packet
+ */
+int MQTTSerialize_unsubscribeLength(int count, MQTTString topicFilters[])
+{
+ int i;
+ int len = 2; /* packetid */
+
+ for (i = 0; i < count; ++i)
+ len += 2 + MQTTstrlen(topicFilters[i]); /* length + topic*/
+ return len;
+}
+
+
+/**
+ * Serializes the supplied unsubscribe data into the supplied buffer, ready for sending
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @param dup integer - the MQTT dup flag
+ * @param packetid integer - the MQTT packet identifier
+ * @param count - number of members in the topicFilters array
+ * @param topicFilters - array of topic filter names
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_unsubscribe(unsigned char* buf, int buflen, unsigned char dup, unsigned short packetid,
+ int count, MQTTString topicFilters[])
+{
+ unsigned char *ptr = buf;
+ MQTTHeader header = {0};
+ int rem_len = 0;
+ int rc = -1;
+ int i = 0;
+
+ FUNC_ENTRY;
+ if (MQTTPacket_len(rem_len = MQTTSerialize_unsubscribeLength(count, topicFilters)) > buflen)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+
+ header.byte = 0;
+ header.bits.type = UNSUBSCRIBE;
+ header.bits.dup = dup;
+ header.bits.qos = 1;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, rem_len); /* write remaining length */;
+
+ writeInt(&ptr, packetid);
+
+ for (i = 0; i < count; ++i)
+ writeMQTTString(&ptr, topicFilters[i]);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Deserializes the supplied (wire) buffer into unsuback data
+ * @param packetid returned integer - the MQTT packet identifier
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return error code. 1 is success, 0 is failure
+ */
+int MQTTDeserialize_unsuback(unsigned short* packetid, unsigned char* buf, int buflen)
+{
+ unsigned char type = 0;
+ unsigned char dup = 0;
+ int rc = 0;
+
+ FUNC_ENTRY;
+ rc = MQTTDeserialize_ack(&type, &dup, packetid, buf, buflen);
+ if (type == UNSUBACK)
+ rc = 1;
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeServer.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeServer.c
new file mode 100755
index 0000000..b0e427d
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/MQTTUnsubscribeServer.c
@@ -0,0 +1,102 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ *******************************************************************************/
+
+#include "MQTTPacket.h"
+#include "StackTrace.h"
+
+#include <string.h>
+
+
+/**
+ * Deserializes the supplied (wire) buffer into unsubscribe data
+ * @param dup integer returned - the MQTT dup flag
+ * @param packetid integer returned - the MQTT packet identifier
+ * @param maxcount - the maximum number of members allowed in the topicFilters and requestedQoSs arrays
+ * @param count - number of members in the topicFilters and requestedQoSs arrays
+ * @param topicFilters - array of topic filter names
+ * @param buf the raw buffer data, of the correct length determined by the remaining length field
+ * @param buflen the length in bytes of the data in the supplied buffer
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTDeserialize_unsubscribe(unsigned char* dup, unsigned short* packetid, int maxcount, int* count, MQTTString topicFilters[],
+ unsigned char* buf, int len)
+{
+ MQTTHeader header = {0};
+ unsigned char* curdata = buf;
+ unsigned char* enddata = NULL;
+ int rc = 0;
+ int mylen = 0;
+
+ FUNC_ENTRY;
+ header.byte = readChar(&curdata);
+ if (header.bits.type != UNSUBSCRIBE)
+ goto exit;
+ *dup = header.bits.dup;
+
+ curdata += (rc = MQTTPacket_decodeBuf(curdata, &mylen)); /* read remaining length */
+ enddata = curdata + mylen;
+
+ *packetid = readInt(&curdata);
+
+ *count = 0;
+ while (curdata < enddata)
+ {
+ if (!readMQTTLenString(&topicFilters[*count], &curdata, enddata))
+ goto exit;
+ (*count)++;
+ }
+
+ rc = 1;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
+/**
+ * Serializes the supplied unsuback data into the supplied buffer, ready for sending
+ * @param buf the buffer into which the packet will be serialized
+ * @param buflen the length in bytes of the supplied buffer
+ * @param packetid integer - the MQTT packet identifier
+ * @return the length of the serialized data. <= 0 indicates error
+ */
+int MQTTSerialize_unsuback(unsigned char* buf, int buflen, unsigned short packetid)
+{
+ MQTTHeader header = {0};
+ int rc = 0;
+ unsigned char *ptr = buf;
+
+ FUNC_ENTRY;
+ if (buflen < 2)
+ {
+ rc = MQTTPACKET_BUFFER_TOO_SHORT;
+ goto exit;
+ }
+ header.byte = 0;
+ header.bits.type = UNSUBACK;
+ writeChar(&ptr, header.byte); /* write header */
+
+ ptr += MQTTPacket_encode(ptr, 2); /* write remaining length */
+
+ writeInt(&ptr, packetid);
+
+ rc = ptr - buf;
+exit:
+ FUNC_EXIT_RC(rc);
+ return rc;
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/StackTrace.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/StackTrace.h
new file mode 100755
index 0000000..c65a2ef
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/StackTrace.h
@@ -0,0 +1,78 @@
+/*******************************************************************************
+ * Copyright (c) 2014 IBM Corp.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * and Eclipse Distribution License v1.0 which accompany this distribution.
+ *
+ * The Eclipse Public License is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ * and the Eclipse Distribution License is available at
+ * http://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * Contributors:
+ * Ian Craggs - initial API and implementation and/or initial documentation
+ * Ian Craggs - fix for bug #434081
+ *******************************************************************************/
+
+#ifndef STACKTRACE_H_
+#define STACKTRACE_H_
+
+#include <stdio.h>
+#define NOSTACKTRACE 1
+
+#if defined(NOSTACKTRACE)
+#define FUNC_ENTRY
+#define FUNC_ENTRY_NOLOG
+#define FUNC_ENTRY_MED
+#define FUNC_ENTRY_MAX
+#define FUNC_EXIT
+#define FUNC_EXIT_NOLOG
+#define FUNC_EXIT_MED
+#define FUNC_EXIT_MAX
+#define FUNC_EXIT_RC(x)
+#define FUNC_EXIT_MED_RC(x)
+#define FUNC_EXIT_MAX_RC(x)
+
+#else
+
+#if defined(WIN32)
+#define inline __inline
+#define FUNC_ENTRY StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__FUNCTION__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__FUNCTION__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__FUNCTION__, __LINE__, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__FUNCTION__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__FUNCTION__, __LINE__, &x, TRACE_MAXIMUM)
+#else
+#define FUNC_ENTRY StackTrace_entry(__func__, __LINE__, TRACE_MINIMUM)
+#define FUNC_ENTRY_NOLOG StackTrace_entry(__func__, __LINE__, -1)
+#define FUNC_ENTRY_MED StackTrace_entry(__func__, __LINE__, TRACE_MEDIUM)
+#define FUNC_ENTRY_MAX StackTrace_entry(__func__, __LINE__, TRACE_MAXIMUM)
+#define FUNC_EXIT StackTrace_exit(__func__, __LINE__, NULL, TRACE_MINIMUM)
+#define FUNC_EXIT_NOLOG StackTrace_exit(__func__, __LINE__, NULL, -1)
+#define FUNC_EXIT_MED StackTrace_exit(__func__, __LINE__, NULL, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX StackTrace_exit(__func__, __LINE__, NULL, TRACE_MAXIMUM)
+#define FUNC_EXIT_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MINIMUM)
+#define FUNC_EXIT_MED_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MEDIUM)
+#define FUNC_EXIT_MAX_RC(x) StackTrace_exit(__func__, __LINE__, &x, TRACE_MAXIMUM)
+
+void StackTrace_entry(const char* name, int line, int trace);
+void StackTrace_exit(const char* name, int line, void* return_value, int trace);
+
+void StackTrace_printStack(FILE* dest);
+char* StackTrace_get(unsigned long);
+
+#endif
+
+#endif
+
+
+
+
+#endif /* STACKTRACE_H_ */
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.c
new file mode 100755
index 0000000..dfd3a3d
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.c
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+//#include "infra_config.h"
+
+//#ifdef INFRA_SHA1
+
+#include <stdlib.h>
+#include <string.h>
+#include "core_sha1.h"
+//#include "infra_sha1.h"
+
+#define SHA1_KEY_IOPAD_SIZE (64)
+#define SHA1_DIGEST_SIZE (20)
+
+
+/* Implementation that should never be optimized out by the compiler */
+static void core_sha1_zeroize( void *v, uint32_t n ) {
+ volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
+}
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+}
+#endif
+
+void core_sha1_init(iot_sha1_context *ctx)
+{
+ memset(ctx, 0, sizeof(iot_sha1_context));
+}
+
+void core_sha1_free(iot_sha1_context *ctx)
+{
+ if (ctx == NULL) {
+ return;
+ }
+
+ core_sha1_zeroize(ctx, sizeof(iot_sha1_context));
+}
+
+void core_sha1_clone(iot_sha1_context *dst,
+ const iot_sha1_context *src)
+{
+ *dst = *src;
+}
+
+/*
+ * SHA-1 context setup
+ */
+void core_sha1_starts(iot_sha1_context *ctx)
+{
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xEFCDAB89;
+ ctx->state[2] = 0x98BADCFE;
+ ctx->state[3] = 0x10325476;
+ ctx->state[4] = 0xC3D2E1F0;
+}
+
+void core_sha1_process(iot_sha1_context *ctx, const unsigned char data[64])
+{
+ uint32_t temp, W[16], A, B, C, D, E;
+
+ GET_UINT32_BE( W[ 0], data, 0 );
+ GET_UINT32_BE( W[ 1], data, 4 );
+ GET_UINT32_BE( W[ 2], data, 8 );
+ GET_UINT32_BE( W[ 3], data, 12 );
+ GET_UINT32_BE( W[ 4], data, 16 );
+ GET_UINT32_BE( W[ 5], data, 20 );
+ GET_UINT32_BE( W[ 6], data, 24 );
+ GET_UINT32_BE( W[ 7], data, 28 );
+ GET_UINT32_BE( W[ 8], data, 32 );
+ GET_UINT32_BE( W[ 9], data, 36 );
+ GET_UINT32_BE( W[10], data, 40 );
+ GET_UINT32_BE( W[11], data, 44 );
+ GET_UINT32_BE( W[12], data, 48 );
+ GET_UINT32_BE( W[13], data, 52 );
+ GET_UINT32_BE( W[14], data, 56 );
+ GET_UINT32_BE( W[15], data, 60 );
+
+#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
+
+#define R(t) \
+( \
+ temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \
+ W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \
+ ( W[t & 0x0F] = S(temp,1) ) \
+)
+
+#define P(a,b,c,d,e,x) \
+{ \
+ e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \
+}
+
+ A = ctx->state[0];
+ B = ctx->state[1];
+ C = ctx->state[2];
+ D = ctx->state[3];
+ E = ctx->state[4];
+
+#define F(x,y,z) (z ^ (x & (y ^ z)))
+#define K 0x5A827999
+
+ P( A, B, C, D, E, W[0] );
+ P( E, A, B, C, D, W[1] );
+ P( D, E, A, B, C, W[2] );
+ P( C, D, E, A, B, W[3] );
+ P( B, C, D, E, A, W[4] );
+ P( A, B, C, D, E, W[5] );
+ P( E, A, B, C, D, W[6] );
+ P( D, E, A, B, C, W[7] );
+ P( C, D, E, A, B, W[8] );
+ P( B, C, D, E, A, W[9] );
+ P( A, B, C, D, E, W[10] );
+ P( E, A, B, C, D, W[11] );
+ P( D, E, A, B, C, W[12] );
+ P( C, D, E, A, B, W[13] );
+ P( B, C, D, E, A, W[14] );
+ P( A, B, C, D, E, W[15] );
+ P( E, A, B, C, D, R(16) );
+ P( D, E, A, B, C, R(17) );
+ P( C, D, E, A, B, R(18) );
+ P( B, C, D, E, A, R(19) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0x6ED9EBA1
+
+ P( A, B, C, D, E, R(20) );
+ P( E, A, B, C, D, R(21) );
+ P( D, E, A, B, C, R(22) );
+ P( C, D, E, A, B, R(23) );
+ P( B, C, D, E, A, R(24) );
+ P( A, B, C, D, E, R(25) );
+ P( E, A, B, C, D, R(26) );
+ P( D, E, A, B, C, R(27) );
+ P( C, D, E, A, B, R(28) );
+ P( B, C, D, E, A, R(29) );
+ P( A, B, C, D, E, R(30) );
+ P( E, A, B, C, D, R(31) );
+ P( D, E, A, B, C, R(32) );
+ P( C, D, E, A, B, R(33) );
+ P( B, C, D, E, A, R(34) );
+ P( A, B, C, D, E, R(35) );
+ P( E, A, B, C, D, R(36) );
+ P( D, E, A, B, C, R(37) );
+ P( C, D, E, A, B, R(38) );
+ P( B, C, D, E, A, R(39) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) ((x & y) | (z & (x | y)))
+#define K 0x8F1BBCDC
+
+ P( A, B, C, D, E, R(40) );
+ P( E, A, B, C, D, R(41) );
+ P( D, E, A, B, C, R(42) );
+ P( C, D, E, A, B, R(43) );
+ P( B, C, D, E, A, R(44) );
+ P( A, B, C, D, E, R(45) );
+ P( E, A, B, C, D, R(46) );
+ P( D, E, A, B, C, R(47) );
+ P( C, D, E, A, B, R(48) );
+ P( B, C, D, E, A, R(49) );
+ P( A, B, C, D, E, R(50) );
+ P( E, A, B, C, D, R(51) );
+ P( D, E, A, B, C, R(52) );
+ P( C, D, E, A, B, R(53) );
+ P( B, C, D, E, A, R(54) );
+ P( A, B, C, D, E, R(55) );
+ P( E, A, B, C, D, R(56) );
+ P( D, E, A, B, C, R(57) );
+ P( C, D, E, A, B, R(58) );
+ P( B, C, D, E, A, R(59) );
+
+#undef K
+#undef F
+
+#define F(x,y,z) (x ^ y ^ z)
+#define K 0xCA62C1D6
+
+ P( A, B, C, D, E, R(60) );
+ P( E, A, B, C, D, R(61) );
+ P( D, E, A, B, C, R(62) );
+ P( C, D, E, A, B, R(63) );
+ P( B, C, D, E, A, R(64) );
+ P( A, B, C, D, E, R(65) );
+ P( E, A, B, C, D, R(66) );
+ P( D, E, A, B, C, R(67) );
+ P( C, D, E, A, B, R(68) );
+ P( B, C, D, E, A, R(69) );
+ P( A, B, C, D, E, R(70) );
+ P( E, A, B, C, D, R(71) );
+ P( D, E, A, B, C, R(72) );
+ P( C, D, E, A, B, R(73) );
+ P( B, C, D, E, A, R(74) );
+ P( A, B, C, D, E, R(75) );
+ P( E, A, B, C, D, R(76) );
+ P( D, E, A, B, C, R(77) );
+ P( C, D, E, A, B, R(78) );
+ P( B, C, D, E, A, R(79) );
+
+#undef K
+#undef F
+
+ ctx->state[0] += A;
+ ctx->state[1] += B;
+ ctx->state[2] += C;
+ ctx->state[3] += D;
+ ctx->state[4] += E;
+}
+
+/*
+ * SHA-1 process buffer
+ */
+void core_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen)
+{
+ uint32_t fill;
+ uint32_t left;
+
+ if( ilen == 0 )
+ return;
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if( ctx->total[0] < (uint32_t) ilen )
+ ctx->total[1]++;
+
+ if( left && ilen >= fill )
+ {
+ memcpy( (void *) (ctx->buffer + left), input, fill );
+ core_sha1_process( ctx, ctx->buffer );
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while( ilen >= 64 )
+ {
+ core_sha1_process( ctx, input );
+ input += 64;
+ ilen -= 64;
+ }
+
+ if( ilen > 0 )
+ memcpy( (void *) (ctx->buffer + left), input, ilen );
+}
+
+static const unsigned char sha1_padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * SHA-1 final digest
+ */
+void core_sha1_finish(iot_sha1_context *ctx, unsigned char output[20])
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = ( ctx->total[0] >> 29 )
+ | ( ctx->total[1] << 3 );
+ low = ( ctx->total[0] << 3 );
+
+ PUT_UINT32_BE( high, msglen, 0 );
+ PUT_UINT32_BE( low, msglen, 4 );
+
+ last = ctx->total[0] & 0x3F;
+ padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
+
+ core_sha1_update( ctx, sha1_padding, padn );
+ core_sha1_update( ctx, msglen, 8 );
+
+ PUT_UINT32_BE( ctx->state[0], output, 0 );
+ PUT_UINT32_BE( ctx->state[1], output, 4 );
+ PUT_UINT32_BE( ctx->state[2], output, 8 );
+ PUT_UINT32_BE( ctx->state[3], output, 12 );
+ PUT_UINT32_BE( ctx->state[4], output, 16 );
+}
+
+
+/*
+ * output = SHA-1( input buffer )
+ */
+void core_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20])
+{
+ iot_sha1_context ctx;
+
+ core_sha1_init(&ctx);
+ core_sha1_starts(&ctx);
+ core_sha1_update(&ctx, input, ilen);
+ core_sha1_finish(&ctx, output);
+ core_sha1_free(&ctx);
+}
+
+static int8_t core_hb2hex(uint8_t hb)
+{
+ hb = hb & 0xF;
+ return (int8_t)(hb < 10 ? '0' + hb : hb - 10 + 'a');
+}
+
+void core_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+ iot_sha1_context context;
+ unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[SHA1_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
+ unsigned char out[SHA1_DIGEST_SIZE];
+ int i;
+
+ if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+ return;
+ }
+
+ if (key_len > SHA1_KEY_IOPAD_SIZE) {
+ return;
+ }
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner SHA */
+ core_sha1_init(&context); /* init context for 1st pass */
+ core_sha1_starts(&context); /* setup context for 1st pass */
+ core_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE); /* start with inner pad */
+ core_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */
+ core_sha1_finish(&context, out); /* finish up 1st pass */
+
+ /* perform outer SHA */
+ core_sha1_init(&context); /* init context for 2nd pass */
+ core_sha1_starts(&context); /* setup context for 2nd pass */
+ core_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE); /* start with outer pad */
+ core_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */
+ core_sha1_finish(&context, out); /* finish up 2nd pass */
+
+ for (i = 0; i < SHA1_DIGEST_SIZE; ++i) {
+ digest[i * 2] = core_hb2hex(out[i] >> 4);
+ digest[i * 2 + 1] = core_hb2hex(out[i]);
+ }
+}
+
+void core_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len)
+{
+ iot_sha1_context context;
+ unsigned char k_ipad[SHA1_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[SHA1_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
+ unsigned char out[SHA1_DIGEST_SIZE];
+ int i;
+
+ if ((NULL == msg) || (NULL == digest) || (NULL == key)) {
+ return;
+ }
+
+ if (key_len > SHA1_KEY_IOPAD_SIZE) {
+ return;
+ }
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < SHA1_KEY_IOPAD_SIZE; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner SHA */
+ core_sha1_init(&context); /* init context for 1st pass */
+ core_sha1_starts(&context); /* setup context for 1st pass */
+ core_sha1_update(&context, k_ipad, SHA1_KEY_IOPAD_SIZE); /* start with inner pad */
+ core_sha1_update(&context, (unsigned char *) msg, msg_len); /* then text of datagram */
+ core_sha1_finish(&context, out); /* finish up 1st pass */
+
+ /* perform outer SHA */
+ core_sha1_init(&context); /* init context for 2nd pass */
+ core_sha1_starts(&context); /* setup context for 2nd pass */
+ core_sha1_update(&context, k_opad, SHA1_KEY_IOPAD_SIZE); /* start with outer pad */
+ core_sha1_update(&context, out, SHA1_DIGEST_SIZE); /* then results of 1st hash */
+ core_sha1_finish(&context, out); /* finish up 2nd pass */
+ memcpy(digest, out, SHA1_DIGEST_SIZE);
+}
+
+//#endif
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.h
new file mode 100755
index 0000000..8ae7946
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha1.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2015-2018 Alibaba Group Holding Limited
+ */
+
+
+
+
+#ifndef _CORE_SHA1_H_
+#define _CORE_SHA1_H_
+
+//#include "infra_types.h"
+#include <sys/types.h>
+
+#define SHA1_DIGEST_SIZE (20)
+
+typedef unsigned int uint32_t;
+typedef unsigned char uint8_t;
+// typedef char int8_t;
+
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+{ \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+}
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+{ \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+}
+#endif
+
+/**
+ * \brief SHA-1 context structure
+ */
+typedef struct {
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[5]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+} iot_sha1_context;
+
+/**
+ * \brief Initialize SHA-1 context
+ *
+ * \param ctx SHA-1 context to be initialized
+ */
+void core_sha1_init(iot_sha1_context *ctx);
+
+/**
+ * \brief Clear SHA-1 context
+ *
+ * \param ctx SHA-1 context to be cleared
+ */
+void core_sha1_free(iot_sha1_context *ctx);
+
+/**
+ * \brief Clone (the state of) a SHA-1 context
+ *
+ * \param dst The destination context
+ * \param src The context to be cloned
+ */
+void core_sha1_clone(iot_sha1_context *dst,
+ const iot_sha1_context *src);
+
+/**
+ * \brief SHA-1 context setup
+ *
+ * \param ctx context to be initialized
+ */
+void core_sha1_starts(iot_sha1_context *ctx);
+
+/**
+ * \brief SHA-1 process buffer
+ *
+ * \param ctx SHA-1 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void core_sha1_update(iot_sha1_context *ctx, const unsigned char *input, uint32_t ilen);
+
+/**
+ * \brief SHA-1 final digest
+ *
+ * \param ctx SHA-1 context
+ * \param output SHA-1 checksum result
+ */
+void core_sha1_finish(iot_sha1_context *ctx, unsigned char output[20]);
+
+/* Internal use */
+void core_sha1_process(iot_sha1_context *ctx, const unsigned char data[64]);
+
+/**
+ * \brief Output = SHA-1( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-1 checksum result
+ */
+void core_sha1(const unsigned char *input, uint32_t ilen, unsigned char output[20]);
+void core_hmac_sha1(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+void core_hmac_sha1_hex(const char *msg, int msg_len, char *digest, const char *key, int key_len);
+
+#endif
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.c b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.c
new file mode 100755
index 0000000..d819047
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.c
@@ -0,0 +1,329 @@
+#include "core_sha256.h"
+
+#define MINI_SHA256_SMALLER
+#define SHA256_KEY_IOPAD_SIZE (64)
+#define SHA256_DIGEST_SIZE (32)
+
+/*
+ * 32-bit integer manipulation macros (big endian)
+ */
+#ifndef GET_UINT32_BE
+#define GET_UINT32_BE(n,b,i) \
+ do { \
+ (n) = ( (uint32_t) (b)[(i) ] << 24 ) \
+ | ( (uint32_t) (b)[(i) + 1] << 16 ) \
+ | ( (uint32_t) (b)[(i) + 2] << 8 ) \
+ | ( (uint32_t) (b)[(i) + 3] ); \
+ } while( 0 )
+#endif
+
+#ifndef PUT_UINT32_BE
+#define PUT_UINT32_BE(n,b,i) \
+ do { \
+ (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \
+ (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \
+ (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \
+ (b)[(i) + 3] = (unsigned char) ( (n) ); \
+ } while( 0 )
+#endif
+
+
+static void utils_sha256_zeroize(void *v, uint32_t n)
+{
+ volatile unsigned char *p = v;
+ while (n--) {
+ *p++ = 0;
+ }
+}
+
+void core_sha256_init(core_sha256_context_t *ctx)
+{
+ memset(ctx, 0, sizeof(core_sha256_context_t));
+}
+
+void core_sha256_free(core_sha256_context_t *ctx)
+{
+ if (NULL == ctx) {
+ return;
+ }
+
+ utils_sha256_zeroize(ctx, sizeof(core_sha256_context_t));
+}
+
+void core_sha256_starts(core_sha256_context_t *ctx)
+{
+ uint8_t is224 = 0;
+ ctx->total[0] = 0;
+ ctx->total[1] = 0;
+
+ if (is224 == 0) {
+ /* SHA-256 */
+ ctx->state[0] = 0x6A09E667;
+ ctx->state[1] = 0xBB67AE85;
+ ctx->state[2] = 0x3C6EF372;
+ ctx->state[3] = 0xA54FF53A;
+ ctx->state[4] = 0x510E527F;
+ ctx->state[5] = 0x9B05688C;
+ ctx->state[6] = 0x1F83D9AB;
+ ctx->state[7] = 0x5BE0CD19;
+ }
+
+ ctx->is224 = is224;
+}
+
+static const uint32_t K[] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+#define SHR(x,n) ((x & 0xFFFFFFFF) >> n)
+#define ROTR(x,n) (SHR(x,n) | (x << (32 - n)))
+
+#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3))
+#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10))
+
+#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22))
+#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25))
+
+#define F0(x,y,z) ((x & y) | (z & (x | y)))
+#define F1(x,y,z) (z ^ (x & (y ^ z)))
+
+#define R(t) \
+ ( \
+ W[t] = S1(W[t - 2]) + W[t - 7] + \
+ S0(W[t - 15]) + W[t - 16] \
+ )
+
+#define P(a,b,c,d,e,f,g,h,x,K) \
+ { \
+ temp1 = h + S3(e) + F1(e,f,g) + K + x; \
+ temp2 = S2(a) + F0(a,b,c); \
+ d += temp1; h = temp1 + temp2; \
+ }
+
+void core_sha256_process(core_sha256_context_t *ctx, const unsigned char data[64])
+{
+ uint32_t temp1, temp2, W[64];
+ uint32_t A[8];
+ unsigned int i;
+
+ for (i = 0; i < 8; i++) {
+ A[i] = ctx->state[i];
+ }
+
+#if defined(MINI_SHA256_SMALLER)
+ for (i = 0; i < 64; i++) {
+ if (i < 16) {
+ GET_UINT32_BE(W[i], data, 4 * i);
+ } else {
+ R(i);
+ }
+
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i]);
+
+ temp1 = A[7];
+ A[7] = A[6];
+ A[6] = A[5];
+ A[5] = A[4];
+ A[4] = A[3];
+ A[3] = A[2];
+ A[2] = A[1];
+ A[1] = A[0];
+ A[0] = temp1;
+ }
+#else /* MINI_SHA256_SMALLER */
+ for (i = 0; i < 16; i++) {
+ GET_UINT32_BE(W[i], data, 4 * i);
+ }
+
+ for (i = 0; i < 16; i += 8) {
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i + 0], K[i + 0]);
+ P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i + 1], K[i + 1]);
+ P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i + 2], K[i + 2]);
+ P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i + 3], K[i + 3]);
+ P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i + 4], K[i + 4]);
+ P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i + 5], K[i + 5]);
+ P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i + 6], K[i + 6]);
+ P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i + 7], K[i + 7]);
+ }
+
+ for (i = 16; i < 64; i += 8) {
+ P(A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i + 0), K[i + 0]);
+ P(A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i + 1), K[i + 1]);
+ P(A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i + 2), K[i + 2]);
+ P(A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i + 3), K[i + 3]);
+ P(A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i + 4), K[i + 4]);
+ P(A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i + 5), K[i + 5]);
+ P(A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i + 6), K[i + 6]);
+ P(A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i + 7), K[i + 7]);
+ }
+#endif /* MINI_SHA256_SMALLER */
+
+ for (i = 0; i < 8; i++) {
+ ctx->state[i] += A[i];
+ }
+}
+void core_sha256_update(core_sha256_context_t *ctx, const unsigned char *input, uint32_t ilen)
+{
+ size_t fill;
+ uint32_t left;
+
+ if (ilen == 0) {
+ return;
+ }
+
+ left = ctx->total[0] & 0x3F;
+ fill = 64 - left;
+
+ ctx->total[0] += (uint32_t) ilen;
+ ctx->total[0] &= 0xFFFFFFFF;
+
+ if (ctx->total[0] < (uint32_t) ilen) {
+ ctx->total[1]++;
+ }
+
+ if (left && ilen >= fill) {
+ memcpy((void *)(ctx->buffer + left), input, fill);
+ core_sha256_process(ctx, ctx->buffer);
+ input += fill;
+ ilen -= fill;
+ left = 0;
+ }
+
+ while (ilen >= 64) {
+ core_sha256_process(ctx, input);
+ input += 64;
+ ilen -= 64;
+ }
+
+ if (ilen > 0) {
+ memcpy((void *)(ctx->buffer + left), input, ilen);
+ }
+}
+
+static const unsigned char sha256_padding[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+void core_sha256_finish(core_sha256_context_t *ctx, uint8_t output[32])
+{
+ uint32_t last, padn;
+ uint32_t high, low;
+ unsigned char msglen[8];
+
+ high = (ctx->total[0] >> 29)
+ | (ctx->total[1] << 3);
+ low = (ctx->total[0] << 3);
+
+ PUT_UINT32_BE(high, msglen, 0);
+ PUT_UINT32_BE(low, msglen, 4);
+
+ last = ctx->total[0] & 0x3F;
+ padn = (last < 56) ? (56 - last) : (120 - last);
+
+ core_sha256_update(ctx, sha256_padding, padn);
+ core_sha256_update(ctx, msglen, 8);
+
+ PUT_UINT32_BE(ctx->state[0], output, 0);
+ PUT_UINT32_BE(ctx->state[1], output, 4);
+ PUT_UINT32_BE(ctx->state[2], output, 8);
+ PUT_UINT32_BE(ctx->state[3], output, 12);
+ PUT_UINT32_BE(ctx->state[4], output, 16);
+ PUT_UINT32_BE(ctx->state[5], output, 20);
+ PUT_UINT32_BE(ctx->state[6], output, 24);
+
+ if (ctx->is224 == 0) {
+ PUT_UINT32_BE(ctx->state[7], output, 28);
+ }
+}
+
+void core_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32])
+{
+ core_sha256_context_t ctx;
+
+ core_sha256_init(&ctx);
+ core_sha256_starts(&ctx);
+ core_sha256_update(&ctx, input, ilen);
+ core_sha256_finish(&ctx, output);
+ core_sha256_free(&ctx);
+}
+
+void core_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32])
+{
+ core_sha256_context_t context;
+ uint8_t k_ipad[SHA256_KEY_IOPAD_SIZE]; /* inner padding - key XORd with ipad */
+ uint8_t k_opad[SHA256_KEY_IOPAD_SIZE]; /* outer padding - key XORd with opad */
+ int32_t i;
+
+ if ((NULL == msg) || (NULL == key) || (NULL == output)) {
+ return;
+ }
+
+ if (key_len > SHA256_KEY_IOPAD_SIZE) {
+ return;
+ }
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof(k_ipad));
+ memset(k_opad, 0, sizeof(k_opad));
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < SHA256_KEY_IOPAD_SIZE; i++) {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner SHA */
+ core_sha256_init(&context); /* init context for 1st pass */
+ core_sha256_starts(&context); /* setup context for 1st pass */
+ core_sha256_update(&context, k_ipad, SHA256_KEY_IOPAD_SIZE); /* start with inner pad */
+ core_sha256_update(&context, msg, msg_len); /* then text of datagram */
+ core_sha256_finish(&context, output); /* finish up 1st pass */
+
+ /* perform outer SHA */
+ core_sha256_init(&context); /* init context for 2nd pass */
+ core_sha256_starts(&context); /* setup context for 2nd pass */
+ core_sha256_update(&context, k_opad, SHA256_KEY_IOPAD_SIZE); /* start with outer pad */
+ core_sha256_update(&context, output, SHA256_DIGEST_SIZE); /* then results of 1st hash */
+ core_sha256_finish(&context, output); /* finish up 2nd pass */
+}
+
+int32_t core_hex2str(uint8_t *input, uint32_t input_len, char *output, uint8_t lowercase)
+{
+ char *upper = "0123456789ABCDEF";
+ char *lower = "0123456789abcdef";
+ char *encode = upper;
+ int i = 0, j = 0;
+
+ if (lowercase) {
+ encode = lower;
+ }
+
+ for (i = 0; i < input_len; i++) {
+ output[j++] = encode[(input[i] >> 4) & 0xf];
+ output[j++] = encode[(input[i]) & 0xf];
+ }
+
+ return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.h
new file mode 100755
index 0000000..2141941
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_sha256.h
@@ -0,0 +1,86 @@
+#ifndef _CORE_SHA256_H_
+#define _CORE_SHA256_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include "core_stdinc.h"
+
+#define CORE_SHA256_DIGEST_LENGTH (32)
+#define CORE_SHA256_BLOCK_LENGTH (64)
+#define CORE_SHA256_SHORT_BLOCK_LENGTH (CORE_SHA256_BLOCK_LENGTH - 8)
+#define CORE_SHA256_DIGEST_STRING_LENGTH (CORE_SHA256_DIGEST_LENGTH * 2 + 1)
+
+/**
+ * \brief SHA-256 context structure
+ */
+typedef struct {
+ uint32_t total[2]; /*!< number of bytes processed */
+ uint32_t state[8]; /*!< intermediate digest state */
+ unsigned char buffer[64]; /*!< data block being processed */
+ uint8_t is224; /*!< 0 => SHA-256, else SHA-224 */
+} core_sha256_context_t;
+
+/**
+ * \brief Initialize SHA-256 context
+ *
+ * \param ctx SHA-256 context to be initialized
+ */
+void core_sha256_init(core_sha256_context_t *ctx);
+
+/**
+ * \brief Clear SHA-256 context
+ *
+ * \param ctx SHA-256 context to be cleared
+ */
+void core_sha256_free(core_sha256_context_t *ctx);
+
+
+/**
+ * \brief SHA-256 context setup
+ *
+ * \param ctx context to be initialized
+ */
+void core_sha256_starts(core_sha256_context_t *ctx);
+
+/**
+ * \brief SHA-256 process buffer
+ *
+ * \param ctx SHA-256 context
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ */
+void core_sha256_update(core_sha256_context_t *ctx, const unsigned char *input, uint32_t ilen);
+
+/**
+ * \brief SHA-256 final digest
+ *
+ * \param ctx SHA-256 context
+ * \param output SHA-256 checksum result
+ */
+void core_sha256_finish(core_sha256_context_t *ctx, uint8_t output[32]);
+
+/* Internal use */
+void core_sha256_process(core_sha256_context_t *ctx, const unsigned char data[64]);
+
+/**
+ * \brief Output = SHA-256( input buffer )
+ *
+ * \param input buffer holding the data
+ * \param ilen length of the input data
+ * \param output SHA-256 checksum result
+ */
+void core_sha256(const uint8_t *input, uint32_t ilen, uint8_t output[32]);
+
+void core_hmac_sha256(const uint8_t *msg, uint32_t msg_len, const uint8_t *key, uint32_t key_len, uint8_t output[32]);
+
+int core_hex2str(uint8_t *input, uint32_t input_len, char *output, uint8_t lowercase);
+
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
diff --git a/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_stdinc.h b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_stdinc.h
new file mode 100755
index 0000000..d58acbc
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/MQTTPacket/core_stdinc.h
@@ -0,0 +1,16 @@
+#ifndef _CORE_STDINC_H_
+#define _CORE_STDINC_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
diff --git a/mbtk/libmbtk_lib/mqtt/mbtk_mqtt.c b/mbtk/libmbtk_lib/mqtt/mbtk_mqtt.c
new file mode 100755
index 0000000..3b78429
--- /dev/null
+++ b/mbtk/libmbtk_lib/mqtt/mbtk_mqtt.c
@@ -0,0 +1,676 @@
+/*************************************************************************
+ > File Name: main.c
+ > Author: LFJ
+ > Mail:
+ > Created Time: 2018年09月05日 星期三 13时48分17秒
+ ************************************************************************/
+
+#include <stdio.h>
+
+#include "MQTTClient.h"
+#include "mbtk_mqtt.h"
+#include "pthread.h"
+#include "string.h"
+#include "unistd.h"
+#include "sys/stat.h"
+#include "sys/types.h"
+#include "sys/socket.h"
+#include "netinet/in.h"
+#include "arpa/inet.h"
+#include "fcntl.h"
+#include "mbtk_sock2.h"
+
+#include "mbtk_type.h"
+#include "mbtk_http.h"
+#include "mbtk_log.h"
+
+/*
+static Cloud_MQTT_t *iot_mqtt;
+
+void set_mqtt_t(Cloud_MQTT_t *piot_mqtt)
+{
+ iot_mqtt = piot_mqtt;
+}
+Cloud_MQTT_t * get_mqtt_t()
+{
+ return iot_mqtt;
+}
+*/
+
+extern regnwl_info_t regnwl_info;
+
+
+#define CORE_AUTH_SDK_VERSION "sdk-c-4.1.0"
+#define CORE_AUTH_TIMESTAMP "2524608000000"
+#define MBTK_MQTT_HTTP_AUTH_PATH "/auth/register/device"
+#define MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256 "hmacsha256"
+
+
+const char * mqtt_url[7] = {
+ "iot-as-mqtt.cn-shanghai.aliyuncs.com", /* Shanghai */
+ "iot-as-mqtt.ap-southeast-1.aliyuncs.com", /* Singapore */
+ "iot-as-mqtt.ap-northeast-1.aliyuncs.com", /* Japan */
+ "iot-as-mqtt.us-west-1.aliyuncs.com", /* America */
+ "iot-as-mqtt.eu-central-1.aliyuncs.com", /* Germany */
+ "118.114.239.159", /* me */
+ NULL, /* Custom */
+ };
+
+
+const char *http_host[6] = {
+ "iot-auth.cn-shanghai.aliyuncs.com", /* Shanghai */
+ "iot-auth.ap-southeast-1.aliyuncs.com", /* Singapore */
+ "iot-auth.ap-northeast-1.aliyuncs.com", /* Japan */
+ "iot-auth.us-west-1.aliyuncs.com", /* America */
+ "iot-auth.eu-central-1.aliyuncs.com", /* Germany */
+ NULL, /* Custom */
+ };
+
+mbtk_mqtt_device_session_t mbtk_mqtt_device ={0};
+
+
+char mbtk_mqtt_http_url[255] ={0};
+char mbtk_mqtt_http_content[1024] ={0};
+
+char Device_Secret[255] = {0};
+
+
+int mbtk_imqtt_http_dynreg_sign(char *product_key,char* product_secret,char*device_name,char* random,char* sign)
+{
+ int sign_source_len = 0;
+ uint8_t signnum[32];
+ uint8_t *sign_source = NULL;
+ const char *dynamic_register_sign_fmt = "deviceName%sproductKey%srandom%s";
+
+ /* Start Dynamic Register */
+ /* Calculate SHA256 Value */
+ sign_source_len = strlen(dynamic_register_sign_fmt) + strlen(device_name) + strlen(product_key) + strlen(random) + 1;
+ sign_source = malloc(sign_source_len);
+ if (sign_source == NULL)
+ {
+ return -1;
+ }
+ memset(sign_source, 0, sign_source_len);
+ snprintf((char *)sign_source, sign_source_len, dynamic_register_sign_fmt, device_name, product_key, random);
+
+ core_hmac_sha256(sign_source, strlen((const char *)sign_source), (uint8_t *)product_secret, strlen(product_secret),
+ signnum);
+ core_hex2str(signnum, 32, sign,0);
+ free(sign_source);
+ sign_source = NULL;
+
+ return 0;
+
+}
+
+
+int mbtk_imqtt_send_post_request(char *product_key, char *product_secret, char *device_name, int host)
+{
+
+ printf("product_key: %s\n", product_key);
+ printf("product_secret: %s\n", product_secret);
+ printf("device_name: %s\n", device_name);
+
+ int32_t res = 0, content_len = 0;
+ char content[255] = {0};
+ char random[15+1]={0};;
+ char sign[65] = {0};
+ int dynamic_register_request_len = 0;
+// char *content_fmt = "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=%s";
+ char *signMethod = MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256;
+
+
+ memcpy(random, "8Ygb7ULYh53B6OA", strlen("8Ygb7ULYh53B6OA"));
+ char *content_src[] = { product_key, device_name, random,sign,signMethod};
+ mbtk_imqtt_http_dynreg_sign(product_key,product_secret,device_name,random,sign);
+
+ sprintf(content, "productKey=%s&deviceName=%s&random=%s&sign=%s&signMethod=%s",
+ product_key, device_name, random, sign, MBTK_MQTT_HTTP_SIGN_METHOD_HMACSHA256);
+
+ memset(mbtk_mqtt_http_url, 0, sizeof(mbtk_mqtt_http_url));
+ sprintf(mbtk_mqtt_http_url, "https://%s:443/auth/register/device", http_host[host]);
+
+ memset(mbtk_mqtt_http_content, 0, sizeof(mbtk_mqtt_http_content));
+ memcpy(mbtk_mqtt_http_content, content, strlen(content));
+
+ printf("mbtk_mqtt_http_url:%s\n", mbtk_mqtt_http_url);
+ printf("mbtk_mqtt_http_content:%s\n", mbtk_mqtt_http_content);
+
+ return 0;
+}
+
+void mbtk_mqt_http_device_secret_response(void *data,int data_len)
+{
+ if(data != NULL && data_len != 0)
+ {
+ char* ptr_start = NULL;
+ char* ptr_end = NULL;
+ char fac[64] = {'\0'};
+ ptr_start = strstr(data, "deviceSecret");
+ if(ptr_start != NULL)
+ {
+ ptr_end = strstr(ptr_start, "\",");
+ if(ptr_end != NULL)
+ {
+ strncpy(Device_Secret, ptr_start + 15, ptr_end - ptr_start - 15);
+ printf("device_secret:%s\n", Device_Secret);
+ }
+ printf("ptr_start:%s,\n ptr_end:%s\n", ptr_start, ptr_end);
+ }
+
+ }
+
+ return;
+}
+
+
+static void mbtk_mqtt_http_data_cb_func(
+ int session_id, mbtk_http_data_type_enum type,
+ void *data,int data_len)
+{
+ if(type == MBTK_HTTP_DATA_HEADER) {
+ printf("Header(%d):%s\n",data_len,(char*)data);
+ mbtk_mqt_http_device_secret_response((char*)data, data_len);
+ } else if(type == MBTK_HTTP_DATA_CONTENT) {
+ printf("Data(%d):%s\n",data_len,(char*)data);
+ mbtk_mqt_http_device_secret_response((char*)data, data_len);
+ } else {
+ printf(">>>>>Complete<<<<<\n");
+ }
+}
+
+int mbtk_aliyun_mqtt_one_type_one_secret_regint_get_info(mbtk_mqtt_device_session_t *mbtk_mqtt_device_t)
+{
+ printf("mbtk_mqtt_http_request 1111111");
+ char product_key[255] = {0};
+ char product_secret[255] = {0};
+ char device_name[255] = {0};
+
+ int http_handle = mbtk_http_handle_get(TRUE, mbtk_mqtt_http_data_cb_func);
+ if(http_handle < 0)
+ {
+ printf("mbtk_http_handle_get() fail.");
+ return -1;
+ }
+
+ int http_session = mbtk_http_session_create(http_handle,HTTP_OPTION_POST,HTTP_VERSION_1_1);
+ if(http_handle < 0)
+ {
+ printf("mbtk_http_session_create() fail.");
+ return -1;
+ }
+
+// mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_HEAD_ONLY);
+// mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_POST);
+
+ memcpy(product_key, mbtk_mqtt_device_t->product_key, strlen(mbtk_mqtt_device_t->product_key));
+ memcpy(product_secret, mbtk_mqtt_device_t->product_secret, strlen(mbtk_mqtt_device_t->product_secret));
+ memcpy(device_name, mbtk_mqtt_device_t->device_name, strlen(mbtk_mqtt_device_t->device_name));
+
+ mbtk_imqtt_send_post_request(product_key, product_secret,device_name, 0);
+
+ if(mbtk_http_session_url_set(http_handle, http_session, mbtk_mqtt_http_url)) {
+ printf("mbtk_http_session_url_set() fail.\n");
+ return -1;
+ }
+
+ const mbtk_http_session_t* session = mbtk_http_session_get(http_handle, http_session);
+ printf("HTTP:%d,%s,%d,%s\n",session->option,session->host,session->port,session->uri);
+
+ char *header = "Accept: text/xml,text/javascript,text/html,application/json\r\n" \
+ "Content-Type: application/x-www-form-urlencoded\r\n";
+
+
+ mbtk_http_session_head_add(http_handle, http_session, "Accept", "text/xml,text/javascript,text/html,application/json");
+
+ mbtk_http_session_head_add(http_handle, http_session, "Content-Type", "application/x-www-form-urlencoded");
+
+ mbtk_http_session_content_set(http_handle, http_session, mbtk_mqtt_http_content, strlen(mbtk_mqtt_http_content) );
+
+// mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_HEAD_ONLY);
+// mbtk_http_session_option_reset(http_handle, http_session , HTTP_OPTION_POST);
+
+ memset(Device_Secret, 0, sizeof(Device_Secret));
+ if(mbtk_http_session_start(http_handle, http_session)) {
+ printf("mbtk_http_session_start() fail.\n");
+ return -1;
+ }
+
+ if(mbtk_http_handle_free(http_handle))
+ {
+ printf("mbtk_http_handle_free() fail.");
+ return -1;
+ }
+
+ if(strlen(Device_Secret ) > 0)
+ {
+ printf("\nstrlen(Device_Secret :%d\n )", strlen(Device_Secret ));
+ memcpy(mbtk_mqtt_device_t->device_secret,Device_Secret, strlen(Device_Secret) );
+ }else{
+ printf("get Device_Secret fail\n");
+ return -1;
+ }
+
+ printf("MBTK_HTTP exit.");
+ return 0;
+
+}
+
+
+void mbtk_aliyun_mqtt_get_connect_para(char *password,char *cliendid,char *username, mbtk_mqtt_device_session_t *mbtk_mqtt_device_t)
+{
+ /*********password.mqttClientId.user_name *************/
+ char content[MBTK_IMQTT_PASSWORD_LEN] = {0};
+
+ printf("mbtk_mqtt_device_t->device_name: %s\n", mbtk_mqtt_device_t->device_name);
+ printf("mbtk_mqtt_device_t->product_key: %s\n", mbtk_mqtt_device_t->product_key);
+ printf("mbtk_mqtt_device_t->product_secret: %s\n", mbtk_mqtt_device_t->product_secret);
+
+ sprintf(content,"deviceName%sproductKey%srandom123",mbtk_mqtt_device_t->device_name,mbtk_mqtt_device_t->product_key);
+ core_hmac_sha1((const char*)content,strlen((const char*)content),(char *)password,mbtk_mqtt_device_t->product_secret,strlen(mbtk_mqtt_device_t->product_secret));
+
+
+// snprintf((char *)cliendid,MBTK_IMQTT_CLIENT_ID_LEN,"%s|securemode=-2,authType=regnwl,random=123,signmethod=hmacsha1,instanceId=%s|",mbtk_mqtt_device_t->device_name,"iot-06z00ag5qidat54");
+
+ snprintf((char *)cliendid,MBTK_IMQTT_CLIENT_ID_LEN,"%s|securemode=-2,authType=regnwl,random=123,signmethod=hmacsha1|",mbtk_mqtt_device_t->device_name);
+ snprintf((char *)username,MBTK_IMQTT_USER_NAME_LEN,"%s&%s",mbtk_mqtt_device_t->device_name,mbtk_mqtt_device_t->product_key);
+}
+
+
+void mbtk_imqtt_auth_hostname(char *dest, char *product_key, int host)
+{
+// char *host = "&product_key.iot-as-mqtt.cn-shanghai.aliyuncs.com";
+ int8_t public_instance = 1;
+
+ snprintf(dest, 100, "%s.%s", product_key, mqtt_url[host]);
+}
+
+
+void mbtk_imqtt_auth_clientid(char *dest,char *product_key, char *device_name)
+{
+// char *clientid = "gyj01ZAd7HF.MATT1|securemode=3,signmethod=hmacsha256,timestamp=1647830635443|";
+
+ sprintf(dest, "%s.%s|securemode=3,signmethod=hmacsha256,timestamp=%s|", product_key,device_name,CORE_AUTH_TIMESTAMP);
+}
+
+void mbtk_imqtt_auth_clientid_yixinyimi_unregin(char *dest,char *client_id)
+{
+// char *clientid = "client_id|securemode=-2,authType=connwl|";
+
+ sprintf(dest, "%s|securemode=-2,authType=connwl|", client_id);
+
+}
+
+
+void mbtk_aliyun_imqtt_auth_clientid(char *dest, char *product_key, char *device_name)
+{
+
+ sprintf(dest, "%s.%s|timestamp=%s,_ss=1,_v=%s,securemode=2,signmethod=hmacsha256,ext=3|", product_key,device_name,CORE_AUTH_TIMESTAMP,CORE_AUTH_SDK_VERSION);
+
+ //instanceId 实例id
+// sprintf(dest, "%s.%s|timestamp=%s,_ss=1,_v=%s,securemode=2,signmethod=hmacsha256,ext=3,instanceId=%s|", product_key,device_name,CORE_AUTH_TIMESTAMP,CORE_AUTH_SDK_VERSION,"iot-06z00ag5qidat54");
+}
+
+
+void mbtk_imqtt_auth_username(char *dest,char *device_name, char *product_key)
+{
+ //data.username.cstring="$deviceName&$productKey";
+
+ snprintf(dest,128, "%s&%s", device_name, product_key );
+}
+
+void mbtk_imqtt_auth_password(char *dest, char *device_name, char *product_key, char *device_secret)
+{
+// > data.password.cstring=hmacsha1($deviceSecret,$content);
+// $content为productKey,deviceName,timestamp,clientId按照手母顺序排序,然后将参数值依次拼接例如
+
+
+ char content[300] = {0};
+ uint8_t source_temp[65]={0};
+ sprintf(content,"clientId%s.%sdeviceName%sproductKey%stimestamp%s",product_key, device_name, device_name, product_key,CORE_AUTH_TIMESTAMP);
+
+// sprintf(content,"clientId%sdeviceName%sproductKey%stimestamp%s",client_id, device_name, product_key,CORE_AUTH_TIMESTAMP);
+ core_hmac_sha256((uint8_t *)content, strlen((const char *)content), (uint8_t *)device_secret, strlen(device_secret),
+ source_temp);
+
+ core_hex2str(source_temp, 32, dest,0);
+}
+
+void iot_aliyun_mqtt_init(Cloud_MQTT_t *piot_mqtt,int host,int port ,char *device_name,char *product_key,
+ char * DeviceSecret,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb)
+{
+ mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,product_key,host);
+ mbtk_imqtt_auth_clientid(piot_mqtt->mqtt_client_id,product_key,device_name);
+ mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device_name,product_key);
+ mbtk_imqtt_auth_password(piot_mqtt->mqtt_pass,device_name,product_key,DeviceSecret);
+ piot_mqtt->mqtt_port = port;
+ piot_mqtt->keepAliveInterval = keepAliveInterval;
+ // piot_mqtt->mqtt_version = version;
+ piot_mqtt->mqtt_version = 3;
+
+ printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+ memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+
+ sprintf(piot_mqtt->sub_topic, "%s", sub_topic); //将初始化好的订阅主题填到数组中
+ printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+ sprintf(piot_mqtt->pub_topic, "%s", pub_topic); //将初始化好的发布主题填到数组中
+ printf("pub:%s\n", piot_mqtt->pub_topic);
+
+ piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb; //设置接收到数据回调函数
+ printf("iot_mqtt_init end\n");
+}
+
+void mbtk_aliyun_mqtt_one_type_one_secret_unregin_set_info_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device,int keepAliveInterval,int version,pMessageArrived_Fun mqtt_data_rx_cb)
+{
+
+ mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,device->product_key,device->host);
+ mbtk_aliyun_mqtt_get_connect_para(piot_mqtt->mqtt_pass, piot_mqtt->mqtt_client_id, piot_mqtt->mqtt_user, device);
+
+ piot_mqtt->mqtt_port = device->port;
+ piot_mqtt->keepAliveInterval = keepAliveInterval;
+ piot_mqtt->mqtt_version = version;
+
+ printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ printf("piot_mqtt->mqtt_version:%d\n", piot_mqtt->mqtt_version);
+ memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+ memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+
+ piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb; //设置接收到数据回调函数
+ printf("iot_mqtt_init end\n");
+}
+
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_get_regin_info(char *clientId, char *deviceToken)
+{
+ int ret = 0;
+ if(strlen(regnwl_info.deviceToken) > 5)
+ {
+ memcpy(clientId, regnwl_info.clientId, strlen(regnwl_info.clientId));
+ memcpy(deviceToken, regnwl_info.deviceToken , strlen(regnwl_info.deviceToken));
+ }else{
+ ret= -1;
+ }
+
+ printf("regnwl_info.clientId:%s\n", regnwl_info.clientId);
+ printf("regn->deviceToken:%s\n", regnwl_info.deviceToken);
+ return ret;
+}
+
+
+void iot_aliyun_mqtt_one_type_one_secret_unregin_connect_init(Cloud_MQTT_t *piot_mqtt,mbtk_mqtt_device_session_t *device, char *clientId, char *deviceToken,
+ int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb)
+{
+ mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,device->product_key,device->host);
+ mbtk_imqtt_auth_clientid_yixinyimi_unregin(piot_mqtt->mqtt_client_id, clientId);
+ mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device->device_name,device->product_key);
+ sprintf(piot_mqtt->mqtt_pass, "%s", deviceToken);
+ piot_mqtt->mqtt_port = device->port;
+ piot_mqtt->keepAliveInterval = keepAliveInterval;
+ // piot_mqtt->mqtt_version = version;
+ piot_mqtt->mqtt_version = 3;
+
+ printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+ memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+
+ sprintf(piot_mqtt->sub_topic, "%s", sub_topic); //将初始化好的订阅主题填到数组中
+ printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+ sprintf(piot_mqtt->pub_topic, "%s", pub_topic); //将初始化好的发布主题填到数组中
+ printf("pub:%s\n", piot_mqtt->pub_topic);
+
+ piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb; //设置接收到数据回调函数
+ printf("iot_mqtt_init end\n");
+}
+
+
+void mbtk_aliyun_mqtt_one_type_one_secret_regint_connect_init(Cloud_MQTT_t *piot_mqtt,int host,int port ,char *device_name,char *product_key,
+ char * DeviceSecret,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb)
+{
+ mbtk_imqtt_auth_hostname(piot_mqtt->mqtt_host,product_key,host);
+ mbtk_aliyun_imqtt_auth_clientid(piot_mqtt->mqtt_client_id,product_key,device_name);
+ mbtk_imqtt_auth_username(piot_mqtt->mqtt_user,device_name,product_key);
+ mbtk_imqtt_auth_password(piot_mqtt->mqtt_pass,device_name,product_key,DeviceSecret);
+ piot_mqtt->mqtt_port = port;
+ piot_mqtt->keepAliveInterval = keepAliveInterval;
+ // piot_mqtt->mqtt_version = version;
+ piot_mqtt->mqtt_version = 3;
+
+ printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+ memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+
+ sprintf(piot_mqtt->sub_topic, "%s", sub_topic); //将初始化好的订阅主题填到数组中
+ printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+ sprintf(piot_mqtt->pub_topic, "%s", pub_topic); //将初始化好的发布主题填到数组中
+ printf("pub:%s\n", piot_mqtt->pub_topic);
+
+ piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb; //设置接收到数据回调函数
+ printf("iot_mqtt_init end\n");
+}
+
+
+void iot_mqtt_init(Cloud_MQTT_t *piot_mqtt,char *host,int port ,char *clientid,char *user,char *pass,int keepAliveInterval,int version,char *sub_topic,char *pub_topic,pMessageArrived_Fun mqtt_data_rx_cb)
+{
+
+ memcpy(piot_mqtt->mqtt_host,host,strlen(host));
+ memcpy(piot_mqtt->mqtt_client_id,clientid,strlen(clientid));
+ memcpy(piot_mqtt->mqtt_user,user,strlen(user));
+ memcpy(piot_mqtt->mqtt_pass,pass,strlen(pass));
+ piot_mqtt->mqtt_port = port;
+ piot_mqtt->keepAliveInterval = keepAliveInterval;
+ piot_mqtt->mqtt_version = version;
+
+
+ printf("mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ memset(piot_mqtt->sub_topic, '\0', MQTT_TOPIC_SIZE);
+ memset(piot_mqtt->pub_topic, '\0', MQTT_TOPIC_SIZE);
+
+ sprintf(piot_mqtt->sub_topic, "%s", sub_topic); //将初始化好的订阅主题填到数组中
+ printf("subscribe:%s\n", piot_mqtt->sub_topic);
+
+ sprintf(piot_mqtt->pub_topic, "%s", pub_topic); //将初始化好的发布主题填到数组中
+ printf("pub:%s\n", piot_mqtt->pub_topic);
+
+ piot_mqtt->DataArrived_Cb = mqtt_data_rx_cb; //设置接收到数据回调函数
+ printf("iot_mqtt_init end\n");
+}
+/*
+void MQTTMessageArrived_Cb(MessageData* md)
+{
+ MQTTMessage *message = md->message;
+
+ Cloud_MQTT_t *piot_mqtt = get_mqtt_t();
+
+ if (NULL != piot_mqtt->DataArrived_Cb) {
+ piot_mqtt->DataArrived_Cb((void *)message->payload, message->payloadlen);//异步消息体
+ }
+}
+*/
+
+int mbtk_aliyun_mqtt_one_type_one_secret_unregin_device_connect(Cloud_MQTT_t *piot_mqtt)
+{
+ int rc = 0, ret = 0;
+ Network* network = (Network*)malloc(sizeof(Network));
+ memset(network ,0x0, sizeof(Network));
+ NewNetwork(network);
+ piot_mqtt->network = network;
+
+ printf("topic = %s\n", piot_mqtt->sub_topic);
+// set_mqtt_t(piot_mqtt);
+ piot_mqtt->network->is_support_ssl = 1;
+ printf("23131mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ rc = ConnectNetwork(piot_mqtt->network, piot_mqtt->mqtt_host, piot_mqtt->mqtt_port,piot_mqtt->network->is_support_ssl,piot_mqtt->network->ingnore_cert);
+ if (rc != 0) {
+ ret = -101;
+ goto __END;
+ }
+ MQTTClient(&piot_mqtt->Client, piot_mqtt->network, 1000*30, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
+ MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+ data.MQTTVersion = piot_mqtt->mqtt_version;
+ data.clientID.cstring = piot_mqtt->mqtt_client_id;
+ data.username.cstring = piot_mqtt->mqtt_user;
+ data.password.cstring = piot_mqtt->mqtt_pass;
+ data.keepAliveInterval = piot_mqtt->keepAliveInterval;
+ data.willFlag = 0;
+ data.will.qos = 0;
+ data.will.retained = 0;
+ data.will.topicName.cstring = NULL;
+ data.will.message.cstring = NULL;
+
+ data.cleansession = 1;
+ rc = MQTTConnect(&piot_mqtt->Client, &data);
+ if (rc) {
+ printf("mqtt connect broker fail \n");
+ printf("rc = %d\n", rc);
+ ret = -102;
+ goto __END;
+ }
+__END:
+ return ret;
+}
+
+int mqtt_device_connect(Cloud_MQTT_t *piot_mqtt)
+{
+ int rc = 0, ret = 0;
+ Network* network = (Network*)malloc(sizeof(Network));
+ memset(network ,0x0, sizeof(Network));
+ NewNetwork(network);
+ piot_mqtt->network = network;
+
+ printf("topic = %s\n", piot_mqtt->sub_topic);
+// set_mqtt_t(piot_mqtt);
+ printf("23131mqtt_host is %s\nmqtt_port is %d\nmqtt_client_id is %s\nmqtt_user is %s\nmqtt_pass is %s\n",piot_mqtt->mqtt_host,piot_mqtt->mqtt_port,piot_mqtt->mqtt_client_id,piot_mqtt->mqtt_user,piot_mqtt->mqtt_pass);
+ rc = ConnectNetwork(piot_mqtt->network, piot_mqtt->mqtt_host, piot_mqtt->mqtt_port,piot_mqtt->network->is_support_ssl,piot_mqtt->network->ingnore_cert);
+ if (rc != 0) {
+ ret = -101;
+ goto __END;
+ }
+ MQTTClient(&piot_mqtt->Client, piot_mqtt->network, 1000, piot_mqtt->mqtt_buffer, MQTT_BUF_SIZE, piot_mqtt->mqtt_read_buffer, MQTT_BUF_SIZE);
+ MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
+
+ if (piot_mqtt->willFlag) {
+ data.willFlag = 1;
+ memcpy(&data.will, &piot_mqtt->will, sizeof(MQTTPacket_willOptions));
+ } else {
+ data.willFlag = 0;
+ }
+ data.MQTTVersion = piot_mqtt->mqtt_version;
+ data.clientID.cstring = piot_mqtt->mqtt_client_id;
+ data.username.cstring = piot_mqtt->mqtt_user;
+ data.password.cstring = piot_mqtt->mqtt_pass;
+ data.keepAliveInterval = piot_mqtt->keepAliveInterval;
+ data.cleansession = 1;
+ rc = MQTTConnect(&piot_mqtt->Client, &data);
+ if (rc) {
+ printf("mqtt connect broker fail \n");
+ printf("rc = %d\n", rc);
+ ret = -102;
+ goto __END;
+ }
+__END:
+ return ret;
+}
+
+int mqtt_device_disconnect(Cloud_MQTT_t *piot_mqtt)//断开mqtt连接
+{
+ int ret = 0;
+
+ ret = MQTTDisconnect(&piot_mqtt->Client,piot_mqtt->network);
+ printf("disconnectNetwork ret = %d\n", ret);
+
+ return ret;
+}
+
+void iot_yield(Cloud_MQTT_t *piot_mqtt,iot_device_info_t *gateway)
+{
+ int ret;
+ switch (gateway->iotstatus) {
+ case IOT_STATUS_LOGIN:
+ ret = mqtt_device_connect(piot_mqtt);
+ if (ret < 0) {
+ printf("iot connect error code %d\n", ret);
+ sleep(1);
+ }
+ break;
+ case IOT_STATUS_CONNECT:
+ ret = MQTTYield(&piot_mqtt->Client, 200);
+ //printf("iot_yield ret %d\n",ret);
+ if (ret != SUCCESS) {
+ printf("why???\n");
+ gateway->iotstatus = IOT_STATUS_DROP;
+ }
+ break;
+ case IOT_STATUS_DROP:
+ mqtt_device_disconnect(piot_mqtt);
+ //gateway.iotstatus = IOT_STATUS_LOGIN;
+ usleep(1000);
+ break;
+ default:
+ break;
+ }
+}
+
+int mqtt_will_msg_set(Cloud_MQTT_t *piot_mqtt, char *pbuf, int len)//设置遗嘱函数
+{
+ memset(piot_mqtt->will_topic, '\0', MQTT_TOPIC_SIZE);
+ MQTTPacket_willOptions mqtt_will = MQTTPacket_willOptions_initializer;
+
+ strcpy(piot_mqtt->will_topic, piot_mqtt->pub_topic);
+ memcpy(&piot_mqtt->will, &mqtt_will, sizeof(MQTTPacket_willOptions));
+
+ piot_mqtt->willFlag = 1;
+ piot_mqtt->will.retained = 0;
+ piot_mqtt->will.topicName.cstring = (char *)piot_mqtt->will_topic;
+ piot_mqtt->will.message.cstring = (char *)pbuf;
+ piot_mqtt->will.qos = QOS2;
+ return 0;
+
+}
+
+int mbtk_MQTTSubscribe(Client* c, const char* topicFilter, enum QoS qos, messageHandler messageHandler)
+{
+ return MQTTSubscribe(c, topicFilter, qos, messageHandler);
+}
+int mbtk_MQTTUnsubscribe(Client* c, const char* topicFilter)
+{
+ return MQTTUnsubscribe(c,topicFilter);
+}
+/*
+int mbtk_MQTTPublish(Client* c, const char* topicName, MQTTMessage* message)
+{
+ return MQTTPublish(c,topicName,message);
+}
+*/
+int mbtk_MQTTPublish(char *pbuf, int len, char retain,Client* c,const char* pub_topic,enum QoS qos,char dup)
+{
+ int ret = 0;
+ MQTTMessage message;
+ char my_topic[128] = {0};
+
+ strcpy(my_topic, pub_topic);
+
+ message.payload = (void *)pbuf;
+ message.payloadlen = len;
+ message.dup = dup;
+ message.qos = qos;
+ if (retain) {
+ message.retained = 1;
+ } else {
+ message.retained = 0;
+ }
+
+ ret = MQTTPublish(c, my_topic, &message); //发布一个主题
+
+ return ret;
+}
+
+void mbtk_mqtt_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_mqtt_lib");
+}
+
+
diff --git a/mbtk/libmbtk_lib/net/mbtk_dhcp.c b/mbtk/libmbtk_lib/net/mbtk_dhcp.c
new file mode 100755
index 0000000..b764f34
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_dhcp.c
@@ -0,0 +1,885 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <poll.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <arpa/inet.h>
+#include <time.h>
+
+#include "mbtk_log.h"
+#include "mbtk_type.h"
+#include "mbtk_ifc.h"
+#include "mbtk_dhcp.h"
+
+#define VERBOSE 2
+#define STATE_SELECTING 1
+#define STATE_REQUESTING 2
+
+#define TIMEOUT_INITIAL 4000
+#define TIMEOUT_MAX 32000
+
+static int verbose = 1;
+// static char errmsg[2048];
+
+static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
+{
+ uint8_t *x;
+
+ memset(msg, 0, sizeof(dhcp_msg));
+
+ msg->op = OP_BOOTREQUEST;
+ msg->htype = HTYPE_ETHER;
+ msg->hlen = 6;
+ msg->hops = 0;
+
+ msg->flags = htons(FLAGS_BROADCAST);
+
+ msg->xid = xid;
+
+ memcpy(msg->chaddr, hwaddr, 6);
+
+ x = msg->options;
+
+ *x++ = OPT_COOKIE1;
+ *x++ = OPT_COOKIE2;
+ *x++ = OPT_COOKIE3;
+ *x++ = OPT_COOKIE4;
+
+ *x++ = OPT_MESSAGE_TYPE;
+ *x++ = 1;
+ *x++ = type;
+
+ return x;
+}
+
+static int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
+{
+ uint8_t *x;
+
+ x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
+
+ *x++ = OPT_PARAMETER_LIST;
+ *x++ = 4;
+ *x++ = OPT_SUBNET_MASK;
+ *x++ = OPT_GATEWAY;
+ *x++ = OPT_DNS;
+ *x++ = OPT_BROADCAST_ADDR;
+
+ *x++ = OPT_END;
+
+ return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+static int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
+ uint32_t ipaddr, uint32_t serveraddr)
+{
+ uint8_t *x;
+
+ x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
+
+ *x++ = OPT_PARAMETER_LIST;
+ *x++ = 4;
+ *x++ = OPT_SUBNET_MASK;
+ *x++ = OPT_GATEWAY;
+ *x++ = OPT_DNS;
+ *x++ = OPT_BROADCAST_ADDR;
+
+ *x++ = OPT_REQUESTED_IP;
+ *x++ = 4;
+ memcpy(x, &ipaddr, 4);
+ x += 4;
+
+ *x++ = OPT_SERVER_ID;
+ *x++ = 4;
+ memcpy(x, &serveraddr, 4);
+ x += 4;
+
+ *x++ = OPT_END;
+
+ return DHCP_MSG_FIXED_SIZE + (x - msg->options);
+}
+
+
+static msecs_t get_msecs(void)
+{
+ struct timespec ts;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ {
+ return 0;
+ }
+ else
+ {
+ return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
+ (((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
+ }
+}
+
+static int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
+{
+ int s;
+ struct sockaddr_ll bindaddr;
+
+ if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0)
+ {
+ LOGE("socket(PF_PACKET)");
+ return -1;
+ }
+
+ memset(&bindaddr, 0, sizeof(bindaddr));
+ bindaddr.sll_family = AF_PACKET;
+ bindaddr.sll_protocol = htons(ETH_P_IP);
+ bindaddr.sll_halen = ETH_ALEN;
+ memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
+ bindaddr.sll_ifindex = if_index;
+
+ if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0)
+ {
+ LOGE("Cannot bind raw socket to interface");
+ return -1;
+ }
+
+ return s;
+}
+
+static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
+{
+ uint16_t *up = (uint16_t *)buffer;
+ uint32_t sum = startsum;
+ uint32_t upper16;
+
+ while (count > 1)
+ {
+ sum += *up++;
+ count -= 2;
+ }
+ if (count > 0)
+ {
+ sum += (uint16_t) *(uint8_t *)up;
+ }
+ while ((upper16 = (sum >> 16)) != 0)
+ {
+ sum = (sum & 0xffff) + upper16;
+ }
+ return sum;
+}
+
+static uint32_t finish_sum(uint32_t sum)
+{
+ return ~sum & 0xffff;
+}
+
+static int send_packet(int s, int if_index, dhcp_msg *msg, int size,
+ uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
+{
+ struct iphdr ip;
+ struct udphdr udp;
+ struct iovec iov[3];
+ uint32_t udpsum;
+ uint16_t temp;
+ struct msghdr msghdr;
+ struct sockaddr_ll destaddr;
+
+ ip.version = IPVERSION;
+ ip.ihl = sizeof(ip) >> 2;
+ ip.tos = 0;
+ ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
+ ip.id = 0;
+ ip.frag_off = 0;
+ ip.ttl = IPDEFTTL;
+ ip.protocol = IPPROTO_UDP;
+ ip.check = 0;
+ ip.saddr = saddr;
+ ip.daddr = daddr;
+ ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
+
+ udp.source = htons(sport);
+ udp.dest = htons(dport);
+ udp.len = htons(sizeof(udp) + size);
+ udp.check = 0;
+
+ /* Calculate checksum for pseudo header */
+ udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
+ udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
+ temp = htons(IPPROTO_UDP);
+ udpsum = checksum(&temp, sizeof(temp), udpsum);
+ temp = udp.len;
+ udpsum = checksum(&temp, sizeof(temp), udpsum);
+
+ /* Add in the checksum for the udp header */
+ udpsum = checksum(&udp, sizeof(udp), udpsum);
+
+ /* Add in the checksum for the data */
+ udpsum = checksum(msg, size, udpsum);
+ udp.check = finish_sum(udpsum);
+
+ iov[0].iov_base = (char *)&ip;
+ iov[0].iov_len = sizeof(ip);
+ iov[1].iov_base = (char *)&udp;
+ iov[1].iov_len = sizeof(udp);
+ iov[2].iov_base = (char *)msg;
+ iov[2].iov_len = size;
+ memset(&destaddr, 0, sizeof(destaddr));
+ destaddr.sll_family = AF_PACKET;
+ destaddr.sll_protocol = htons(ETH_P_IP);
+ destaddr.sll_ifindex = if_index;
+ destaddr.sll_halen = ETH_ALEN;
+ memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
+
+ msghdr.msg_name = &destaddr;
+ msghdr.msg_namelen = sizeof(destaddr);
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
+ msghdr.msg_flags = 0;
+ msghdr.msg_control = 0;
+ msghdr.msg_controllen = 0;
+ return sendmsg(s, &msghdr, 0);
+}
+
+static int receive_packet(int s, dhcp_msg *msg)
+{
+ int nread;
+ int is_valid;
+ struct dhcp_packet
+ {
+ struct iphdr ip;
+ struct udphdr udp;
+ dhcp_msg dhcp;
+ } packet;
+ int dhcp_size;
+ uint32_t sum;
+ uint16_t temp;
+ uint32_t saddr, daddr;
+
+ nread = read(s, &packet, sizeof(packet));
+ if (nread < 0)
+ {
+ return -1;
+ }
+ /*
+ * The raw packet interface gives us all packets received by the
+ * network interface. We need to filter out all packets that are
+ * not meant for us.
+ */
+ is_valid = 0;
+ if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr)))
+ {
+#if VERBOSE
+ LOGD("Packet is too small (%d) to be a UDP datagram", nread);
+#endif
+ }
+ else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2))
+ {
+#if VERBOSE
+ LOGD("Not a valid IP packet");
+#endif
+ }
+ else if (nread < ntohs(packet.ip.tot_len))
+ {
+#if VERBOSE
+ LOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
+#endif
+ }
+ else if (packet.ip.protocol != IPPROTO_UDP)
+ {
+#if VERBOSE
+ LOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
+#endif
+ }
+ else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT))
+ {
+#if VERBOSE
+ LOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
+#endif
+ }
+ else
+ {
+ is_valid = 1;
+ }
+
+ if (!is_valid)
+ {
+ return -1;
+ }
+
+ /* Seems like it's probably a valid DHCP packet */
+ /* validate IP header checksum */
+ sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
+ if (sum != 0)
+ {
+ LOGW("IP header checksum failure (0x%x)", packet.ip.check);
+ return -1;
+ }
+ /*
+ * Validate the UDP checksum.
+ * Since we don't need the IP header anymore, we "borrow" it
+ * to construct the pseudo header used in the checksum calculation.
+ */
+ dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
+ /*
+ * check validity of dhcp_size.
+ * 1) cannot be negative or zero.
+ * 2) src buffer contains enough bytes to copy
+ * 3) cannot exceed destination buffer
+ */
+ if ((dhcp_size <= 0) ||
+ ((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
+ ((int)sizeof(dhcp_msg) < dhcp_size))
+ {
+#if VERBOSE
+ LOGD("Malformed Packet");
+#endif
+ return -1;
+ }
+ saddr = packet.ip.saddr;
+ daddr = packet.ip.daddr;
+ nread = ntohs(packet.ip.tot_len);
+ memset(&packet.ip, 0, sizeof(packet.ip));
+ packet.ip.saddr = saddr;
+ packet.ip.daddr = daddr;
+ packet.ip.protocol = IPPROTO_UDP;
+ packet.ip.tot_len = packet.udp.len;
+ temp = packet.udp.check;
+ packet.udp.check = 0;
+ sum = finish_sum(checksum(&packet, nread, 0));
+ packet.udp.check = temp;
+ if (!sum)
+ sum = finish_sum(sum);
+ if (temp != sum)
+ {
+ LOGW("UDP header checksum failure (0x%x should be 0x%x)", sum, temp);
+ return -1;
+ }
+ memcpy(msg, &packet.dhcp, dhcp_size);
+ return dhcp_size;
+}
+
+static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
+{
+ int i;
+ char *cp = buf;
+ char *buf_end = buf + buf_size;
+ for (i = 0; i < len; i++)
+ {
+ cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
+ }
+}
+
+static const char *ipaddr(in_addr_t addr)
+{
+ struct in_addr in_addr;
+
+ in_addr.s_addr = addr;
+ return inet_ntoa(in_addr);
+}
+
+static const char *dhcp_type_to_name(uint32_t type)
+{
+ switch(type)
+ {
+ case DHCPDISCOVER:
+ return "discover";
+ case DHCPOFFER:
+ return "offer";
+ case DHCPREQUEST:
+ return "request";
+ case DHCPDECLINE:
+ return "decline";
+ case DHCPACK:
+ return "ack";
+ case DHCPNAK:
+ return "nak";
+ case DHCPRELEASE:
+ return "release";
+ case DHCPINFORM:
+ return "inform";
+ default:
+ return "???";
+ }
+}
+
+static void dump_dhcp_msg(dhcp_msg *msg, int len)
+{
+ unsigned char *x;
+ unsigned int n,c;
+ int optsz;
+ const char *name;
+ char buf[2048];
+
+ LOGD("===== DHCP message:");
+ if (len < DHCP_MSG_FIXED_SIZE)
+ {
+ LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
+ return;
+ }
+
+ len -= DHCP_MSG_FIXED_SIZE;
+
+ if (msg->op == OP_BOOTREQUEST)
+ name = "BOOTREQUEST";
+ else if (msg->op == OP_BOOTREPLY)
+ name = "BOOTREPLY";
+ else
+ name = "????";
+ LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
+ name, msg->op, msg->htype, msg->hlen, msg->hops);
+ LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
+ ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
+ LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
+ LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
+ LOGD("siaddr = %s", ipaddr(msg->siaddr));
+ LOGD("giaddr = %s", ipaddr(msg->giaddr));
+
+ c = msg->hlen > 16 ? 16 : msg->hlen;
+ hex2str(buf, sizeof(buf), msg->chaddr, c);
+ LOGD("chaddr = {%s}", buf);
+
+ for (n = 0; n < 64; n++)
+ {
+ unsigned char x = msg->sname[n];
+ if ((x < ' ') || (x > 127))
+ {
+ if (x == 0) break;
+ msg->sname[n] = '.';
+ }
+ }
+ msg->sname[63] = 0;
+
+ for (n = 0; n < 128; n++)
+ {
+ unsigned char x = msg->file[n];
+ if ((x < ' ') || (x > 127))
+ {
+ if (x == 0) break;
+ msg->file[n] = '.';
+ }
+ }
+ msg->file[127] = 0;
+
+ LOGD("sname = '%s'", msg->sname);
+ LOGD("file = '%s'", msg->file);
+
+ if (len < 4) return;
+ len -= 4;
+ x = msg->options + 4;
+
+ while (len > 2)
+ {
+ if (*x == 0)
+ {
+ x++;
+ len--;
+ continue;
+ }
+ if (*x == OPT_END)
+ {
+ break;
+ }
+ len -= 2;
+ optsz = x[1];
+ if (optsz > len) break;
+ if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE)
+ {
+ if ((unsigned int)optsz < sizeof(buf) - 1)
+ {
+ n = optsz;
+ }
+ else
+ {
+ n = sizeof(buf) - 1;
+ }
+ memcpy(buf, &x[2], n);
+ buf[n] = '\0';
+ }
+ else
+ {
+ hex2str(buf, sizeof(buf), &x[2], optsz);
+ }
+ if (x[0] == OPT_MESSAGE_TYPE)
+ name = dhcp_type_to_name(x[2]);
+ else
+ name = NULL;
+ LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
+ len -= optsz;
+ x = x + optsz + 2;
+ }
+}
+
+static int send_message(int sock, int if_index, dhcp_msg *msg, int size)
+{
+#if VERBOSE > 1
+ dump_dhcp_msg(msg, size);
+#endif
+ return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
+ PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
+}
+
+// static dhcp_info last_good_info;
+static int dhcp_configure(const char *ifname, dhcp_info *info)
+{
+ //last_good_info = *info;
+ return mbtk_ifc_configure1(ifname, info->ipaddr, info->prefixLength, info->gateway, 0);
+}
+
+static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
+{
+ if (sz < DHCP_MSG_FIXED_SIZE)
+ {
+ if (verbose) LOGD("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
+ return 0;
+ }
+ if (reply->op != OP_BOOTREPLY)
+ {
+ if (verbose) LOGD("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
+ return 0;
+ }
+ if (reply->xid != msg->xid)
+ {
+ if (verbose) LOGD("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
+ ntohl(msg->xid));
+ return 0;
+ }
+ if (reply->htype != msg->htype)
+ {
+ if (verbose) LOGD("Wrong Htype %d != %d\n", reply->htype, msg->htype);
+ return 0;
+ }
+ if (reply->hlen != msg->hlen)
+ {
+ if (verbose) LOGD("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
+ return 0;
+ }
+ if (memcmp(msg->chaddr, reply->chaddr, msg->hlen))
+ {
+ if (verbose) LOGD("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
+ return 0;
+ }
+ return 1;
+}
+
+int ipv4NetmaskToPrefixLength(in_addr_t mask)
+{
+ int prefixLength = 0;
+ uint32_t m = (uint32_t)ntohl(mask);
+ while (m & 0x80000000)
+ {
+ prefixLength++;
+ m = m << 1;
+ }
+ return prefixLength;
+}
+
+static int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
+{
+ uint8_t *x;
+ unsigned int opt;
+ int optlen;
+
+ memset(info, 0, sizeof(dhcp_info));
+ if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
+
+ len -= (DHCP_MSG_FIXED_SIZE + 4);
+
+ if (msg->options[0] != OPT_COOKIE1) return -1;
+ if (msg->options[1] != OPT_COOKIE2) return -1;
+ if (msg->options[2] != OPT_COOKIE3) return -1;
+ if (msg->options[3] != OPT_COOKIE4) return -1;
+
+ x = msg->options + 4;
+
+ while (len > 2)
+ {
+ opt = *x++;
+ if (opt == OPT_PAD)
+ {
+ len--;
+ continue;
+ }
+ if (opt == OPT_END)
+ {
+ break;
+ }
+ optlen = *x++;
+ len -= 2;
+ if (optlen > len)
+ {
+ break;
+ }
+ switch(opt)
+ {
+ case OPT_SUBNET_MASK:
+ if (optlen >= 4)
+ {
+ in_addr_t mask;
+ memcpy(&mask, x, 4);
+ info->prefixLength = ipv4NetmaskToPrefixLength(mask);
+ }
+ break;
+ case OPT_GATEWAY:
+ if (optlen >= 4) memcpy(&info->gateway, x, 4);
+ break;
+ case OPT_DNS:
+ if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
+ if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
+ break;
+ case OPT_LEASE_TIME:
+ if (optlen >= 4)
+ {
+ memcpy(&info->lease, x, 4);
+ info->lease = ntohl(info->lease);
+ }
+ break;
+ case OPT_SERVER_ID:
+ if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
+ break;
+ case OPT_MESSAGE_TYPE:
+ info->type = *x;
+ break;
+ default:
+ break;
+ }
+ x += optlen;
+ len -= optlen;
+ }
+
+ info->ipaddr = msg->yiaddr;
+
+ return 0;
+}
+
+void dump_dhcp_info(dhcp_info *info)
+{
+ char addr[20], gway[20];
+ LOGD("--- dhcp %s (%d) ---",
+ dhcp_type_to_name(info->type), info->type);
+ strcpy(addr, ipaddr(info->ipaddr));
+ strcpy(gway, ipaddr(info->gateway));
+ LOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
+ if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
+ if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
+ LOGD("server %s, lease %d seconds",
+ ipaddr(info->serveraddr), info->lease);
+}
+
+static int dhcp_init_ifc(const char *ifname)
+{
+ dhcp_msg discover_msg;
+ dhcp_msg request_msg;
+ dhcp_msg reply;
+ dhcp_msg *msg;
+ dhcp_info info;
+ int s, r, size;
+ int valid_reply;
+ uint32_t xid;
+ unsigned char hwaddr[6];
+ struct pollfd pfd;
+ unsigned int state;
+ unsigned int timeout;
+ int if_index;
+
+ xid = (uint32_t) get_msecs();
+ if (mbtk_ifc_get_hwaddr(ifname, hwaddr))
+ {
+ LOGE("cannot obtain interface address");
+ return -1;
+ }
+ if (mbtk_ifc_get_ifindex(ifname, &if_index))
+ {
+ LOGE("cannot obtain interface index");
+ return -1;
+ }
+
+ s = open_raw_socket(ifname, hwaddr, if_index);
+
+ timeout = TIMEOUT_INITIAL;
+ state = STATE_SELECTING;
+ info.type = 0;
+ goto transmit;
+
+ for (;;)
+ {
+ pfd.fd = s;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ r = poll(&pfd, 1, timeout);
+
+ if (r == 0)
+ {
+#if VERBOSE
+ LOGE("TIMEOUT");
+#endif
+ if (timeout >= TIMEOUT_MAX)
+ {
+ LOGE("timed out");
+ if ( info.type == DHCPOFFER )
+ {
+ LOGE("no acknowledgement from DHCP server\nconfiguring %s with offered parameters", ifname);
+ return dhcp_configure(ifname, &info);
+ }
+ errno = ETIME;
+ close(s);
+ return -1;
+ }
+ timeout = timeout * 2;
+
+ transmit:
+ size = 0;
+ msg = NULL;
+ switch(state)
+ {
+ case STATE_SELECTING:
+ msg = &discover_msg;
+ size = init_dhcp_discover_msg(msg, hwaddr, xid);
+ break;
+ case STATE_REQUESTING:
+ msg = &request_msg;
+ size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
+ break;
+ default:
+ r = 0;
+ }
+ if (size != 0)
+ {
+ r = send_message(s, if_index, msg, size);
+ if (r < 0)
+ {
+ LOGE("error sending dhcp msg: %s\n", strerror(errno));
+ }
+ }
+ continue;
+ }
+
+ if (r < 0)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR))
+ {
+ continue;
+ }
+ LOGE("poll failed");
+ return -1;
+ }
+
+ errno = 0;
+ r = receive_packet(s, &reply);
+ if (r < 0)
+ {
+ if (errno != 0)
+ {
+ LOGD("receive_packet failed (%d): %s", r, strerror(errno));
+ if (errno == ENETDOWN || errno == ENXIO)
+ {
+ return -1;
+ }
+ }
+ continue;
+ }
+
+#if VERBOSE > 1
+ dump_dhcp_msg(&reply, r);
+#endif
+ decode_dhcp_msg(&reply, r, &info);
+
+ if (state == STATE_SELECTING)
+ {
+ valid_reply = is_valid_reply(&discover_msg, &reply, r);
+ }
+ else
+ {
+ valid_reply = is_valid_reply(&request_msg, &reply, r);
+ }
+ if (!valid_reply)
+ {
+ LOGE("invalid reply");
+ continue;
+ }
+
+ if (verbose)
+ dump_dhcp_info(&info);
+
+ switch(state)
+ {
+ case STATE_SELECTING:
+ if (info.type == DHCPOFFER)
+ {
+ state = STATE_REQUESTING;
+ timeout = TIMEOUT_INITIAL;
+ xid++;
+ goto transmit;
+ }
+ break;
+ case STATE_REQUESTING:
+ if (info.type == DHCPACK)
+ {
+ LOGE("configuring %s", ifname);
+ close(s);
+ return dhcp_configure(ifname, &info);
+ }
+ else if (info.type == DHCPNAK)
+ {
+ LOGE("configuration request denied");
+ close(s);
+ return -1;
+ }
+ else
+ {
+ LOGE("ignoring %s message in state %d",
+ dhcp_type_to_name(info.type), state);
+ }
+ break;
+ }
+ }
+ close(s);
+ return 0;
+}
+
+
+int mbtk_do_dhcp(const char *name)
+{
+ int ret = 0;
+ if(mbtk_ifc_open())
+ {
+ LOGE("mbtk_ifc_open() fail.");
+ ret = -1;
+ goto return_result;
+ }
+
+ if (mbtk_ifc_set_addr(name, 0, 0))
+ {
+ LOGE("failed to set ip addr for %s to 0.0.0.0: %s", name, strerror(errno));
+ ret = -1;
+ goto return_result;
+ }
+
+ if (mbtk_ifc_up(name))
+ {
+ LOGE("failed to bring up interface %s: %s", name, strerror(errno));
+ ret = -1;
+ goto return_result;
+ }
+
+ if(dhcp_init_ifc(name))
+ {
+ LOGE("dhcp_init_ifc() fail.");
+ ret = -1;
+ goto return_result;
+ }
+
+return_result:
+
+ mbtk_ifc_close();
+
+ return ret;
+}
+
+
diff --git a/mbtk/libmbtk_lib/net/mbtk_ifc.c b/mbtk/libmbtk_lib/net/mbtk_ifc.c
new file mode 100755
index 0000000..51267f5
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_ifc.c
@@ -0,0 +1,577 @@
+/*
+* MBTK Network Interface control.
+*
+* Author : lb
+* Date : 2021/8/20 11:44:05
+*
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+//#include <net/if.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <linux/if_ether.h>
+#include <linux/sockios.h>
+//#include <cutils/properties.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include <linux/route.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include "mbtk_type.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "mbtk_ifc.h"
+
+#define IFNAMSIZ 16
+
+static int ifc_ctl_sock = -1;
+static pthread_mutex_t ifc_sock_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void ifc_init_ifr(const char *name, struct ifreq *ifr)
+{
+ memset(ifr, 0, sizeof(struct ifreq));
+ strncpy(ifr->ifr_name, name, IFNAMSIZ);
+ ifr->ifr_name[IFNAMSIZ - 1] = 0;
+}
+
+static int ifc_set_flags(int sock, const char *name, unsigned set, unsigned clr)
+{
+ struct ifreq ifr;
+ ifc_init_ifr(name, &ifr);
+
+ if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+ return -1;
+ ifr.ifr_flags = (ifr.ifr_flags & (~clr)) | set;
+ return ioctl(sock, SIOCSIFFLAGS, &ifr);
+}
+
+static void init_sockaddr_in(struct sockaddr *sa, in_addr_t addr)
+{
+ struct sockaddr_in *sin = (struct sockaddr_in *) sa;
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ sin->sin_addr.s_addr = addr;
+}
+
+#if 1
+static const char *ipaddr_to_string(in_addr_t addr)
+{
+ struct in_addr in_addr;
+
+ in_addr.s_addr = addr;
+ return inet_ntoa(in_addr);
+}
+#endif
+
+static in_addr_t prefixLengthToIpv4Netmask(int prefix_length)
+{
+ in_addr_t mask = 0;
+
+ // C99 (6.5.7): shifts of 32 bits have undefined results
+ if (prefix_length <= 0 || prefix_length > 32)
+ {
+ return 0;
+ }
+
+ mask = ~mask << (32 - prefix_length);
+ mask = htonl(mask);
+
+ return mask;
+}
+
+#if 1
+static int ifc_set_prefixLength(const char *name, int prefixLength)
+{
+ struct ifreq ifr;
+ // TODO - support ipv6
+// if (prefixLength > 32 || prefixLength < 0) return -1;
+
+ in_addr_t mask = prefixLengthToIpv4Netmask(prefixLength);
+ ifc_init_ifr(name, &ifr);
+ init_sockaddr_in(&ifr.ifr_addr, mask);
+
+ return ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr);
+}
+#endif
+
+int ifc_act_on_ipv4_route(int action, const char *ifname, struct in_addr dst, int prefix_length,
+ struct in_addr gw)
+{
+ struct rtentry rt;
+ int result;
+ in_addr_t netmask;
+
+ memset(&rt, 0, sizeof(rt));
+
+ rt.rt_dst.sa_family = AF_INET;
+ rt.rt_dev = (void*) ifname;
+
+ netmask = prefixLengthToIpv4Netmask(prefix_length);
+ init_sockaddr_in(&rt.rt_genmask, netmask);
+ init_sockaddr_in(&rt.rt_dst, dst.s_addr);
+ rt.rt_flags = RTF_UP;
+
+ if (prefix_length == 32)
+ {
+ rt.rt_flags |= RTF_HOST;
+ }
+
+ if (gw.s_addr != 0)
+ {
+ rt.rt_flags |= RTF_GATEWAY;
+ init_sockaddr_in(&rt.rt_gateway, gw.s_addr);
+ }
+
+ result = ioctl(ifc_ctl_sock, action, &rt);
+ if (result < 0)
+ {
+ if (errno == EEXIST)
+ {
+ result = 0;
+ }
+ else
+ {
+ result = -errno;
+ }
+ }
+ return result;
+}
+
+static int ifc_create_default_route1(const char *name, in_addr_t gw)
+{
+ struct in_addr in_dst, in_gw;
+
+ in_dst.s_addr = 0;
+ in_gw.s_addr = gw;
+
+ int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw);
+ LOGD("ifc_create_default_route(%s, %d) = %d", name, gw, ret);
+ return ret;
+}
+
+/* deprecated - v4 only */
+static int ifc_create_default_route2(const char *name, const char *gw)
+{
+ struct in_addr in_dst, in_gw;
+
+ in_dst.s_addr = 0;
+ if(gw == NULL)
+ {
+ in_gw.s_addr = 0;
+ }
+ else
+ {
+ if(inet_aton(gw,(struct in_addr *)&(in_gw.s_addr)) < 0)
+ {
+ LOGE("inet_aton error.");
+ return -1;
+ }
+ }
+
+ int ret = ifc_act_on_ipv4_route(SIOCADDRT, name, in_dst, 0, in_gw);
+ LOGD("ifc_create_default_route(%s) = %d", name, ret);
+ return ret;
+}
+
+int mbtk_ifc_open(void)
+{
+ pthread_mutex_lock(&ifc_sock_mutex);
+ if (ifc_ctl_sock == -1)
+ {
+ ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if (ifc_ctl_sock < 0)
+ {
+ LOGE("socket() failed: %s\n", strerror(errno));
+ }
+ }
+
+ return ifc_ctl_sock < 0 ? -1 : 0;
+}
+
+int mbtk_ifc_close(void)
+{
+ if (ifc_ctl_sock != -1)
+ {
+ (void)close(ifc_ctl_sock);
+ ifc_ctl_sock = -1;
+ }
+ pthread_mutex_unlock(&ifc_sock_mutex);
+
+ return 0;
+}
+
+int mbtk_ifc_set_addr(const char *name, in_addr_t addr, in_addr_t netmask)
+{
+ struct ifreq ifr, irf_mask;
+ int ret;
+
+ ifc_init_ifr(name, &ifr);
+ init_sockaddr_in(&ifr.ifr_addr, addr);
+
+ ret = ioctl(ifc_ctl_sock, SIOCSIFADDR, &ifr);
+ if(ret)
+ {
+ LOGD("set_addr(%s, %x) = %d fail.", name, addr, ret);
+ }
+
+ if(netmask)
+ {
+ ifc_init_ifr(name, &irf_mask);
+ init_sockaddr_in(&irf_mask.ifr_netmask, netmask);
+ ret = ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &irf_mask);
+ if(ret)
+ {
+ LOGD("set_netmask(%s, %x) = %d fail.", name, netmask, ret);
+ }
+ }
+
+ return ret;
+}
+
+int mbtk_ifc_ip_config(const char *ifname, const char *ipv4, const char *mask, const char *gateway)
+{
+ UNUSED(gateway);
+ struct ifreq ifr;
+
+// struct rtentry rt;
+ // Set IPv4
+ struct sockaddr_in *sin;
+ memset(&ifr,0,sizeof(ifr));
+ strcpy(ifr.ifr_name,ifname);
+ sin = (struct sockaddr_in*)&ifr.ifr_addr;
+ sin->sin_family = AF_INET;
+ if(ipv4) {
+ if(inet_aton(ipv4,&(sin->sin_addr)) < 0)
+ {
+ LOGE("inet_aton error.");
+ return -2;
+ }
+ } else {
+ memset(&(sin->sin_addr), 0, sizeof(struct in_addr));
+ }
+
+ if(ioctl(ifc_ctl_sock,SIOCSIFADDR,&ifr) < 0)
+ {
+ LOGE("ioctl SIOCSIFADDR error.");
+ return -3;
+ }
+
+#if 1
+#if 1
+ //netmask
+ if(mask) {
+ if(inet_aton(mask,&(sin->sin_addr)) < 0)
+ {
+ LOGE("inet_pton error.");
+ return -4;
+ }
+
+ if(ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0)
+ {
+ LOGE("ioctl error.");
+ return -5;
+ }
+ }
+#else
+
+ //struct ifreq ifr;
+ //strcpy(ifr.ifr_name, interface_name);
+ struct sockaddr_in netmask_addr;
+ bzero(&netmask_addr, sizeof(struct sockaddr_in));
+ netmask_addr.sin_family = PF_INET;
+ inet_aton(mask, &netmask_addr.sin_addr);
+ memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr,
+ sizeof(struct sockaddr_in));
+ if (ioctl(ifc_ctl_sock, SIOCSIFNETMASK, &ifr) < 0)
+ {
+ LOGE("ioctl() fail.");
+ return -1;
+ }
+#endif
+#endif
+
+#if 0
+ //gateway
+ memset(&rt, 0, sizeof(struct rtentry));
+ memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_family = AF_INET;
+ sin->sin_port = 0;
+ if(inet_aton(gateway, &sin->sin_addr)<0)
+ {
+ LOGE( "inet_aton error." );
+ }
+ memcpy ( &rt.rt_gateway, sin, sizeof(struct sockaddr_in));
+ ((struct sockaddr_in *)&rt.rt_dst)->sin_family=AF_INET;
+ ((struct sockaddr_in *)&rt.rt_genmask)->sin_family=AF_INET;
+ rt.rt_flags = RTF_GATEWAY;
+ if (ioctl(ifc_ctl_sock, SIOCADDRT, &rt)<0)
+ {
+ LOGE("ioctl(SIOCADDRT) error in set_default_route\n");
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+int mbtk_ifc_set_netmask(const char *ifname, const char *netmask)
+{
+ int s;
+ if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+ {
+ LOGE("Socket");
+ return -1;
+ }
+ struct ifreq ifr;
+ strcpy(ifr.ifr_name, ifname);
+ struct sockaddr_in netmask_addr;
+ bzero(&netmask_addr, sizeof(struct sockaddr_in));
+ netmask_addr.sin_family = PF_INET;
+ inet_aton(netmask, &netmask_addr.sin_addr);
+ memcpy(&ifr.ifr_ifru.ifru_netmask, &netmask_addr,
+ sizeof(struct sockaddr_in));
+ if (ioctl(s, SIOCSIFNETMASK, &ifr) < 0)
+ {
+ LOGE("ioctl");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+int mbtk_ifc_get_addr(const char *name, void *addr)
+{
+ int ret;
+ struct ifreq ifr;
+ ifc_init_ifr(name, &ifr);
+
+ ret = ioctl(ifc_ctl_sock, SIOCGIFADDR, &ifr);
+ LOGD("ifc_get_addr(%s, %x) = %d", name, ifr.ifr_addr, ret);
+ if(ret < 0) return -1;
+
+ memcpy(addr, &ifr.ifr_addr, sizeof(struct sockaddr));
+ return 0;
+}
+
+
+int mbtk_ifc_up(const char *name)
+{
+ int ret = ifc_set_flags(ifc_ctl_sock, name, IFF_UP, 0);
+// LOGI("mbtk_ifc_up(%s) = %d", name, ret);
+ return ret;
+}
+
+int mbtk_ifc_down(const char *name)
+{
+ int ret = ifc_set_flags(ifc_ctl_sock, name, 0, IFF_UP);
+// LOGI("mbtk_ifc_down(%s) = %d", name, ret);
+ return ret;
+}
+
+int mbtk_ifc_get_hwaddr(const char *name, void *ptr)
+{
+ int r;
+ struct ifreq ifr;
+ ifc_init_ifr(name, &ifr);
+
+ r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
+ if(r < 0) return -1;
+
+ memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+ return 0;
+}
+
+int mbtk_ifc_get_ifindex(const char *name, int *if_indexp)
+{
+ int r;
+ struct ifreq ifr;
+ ifc_init_ifr(name, &ifr);
+
+ r = ioctl(ifc_ctl_sock, SIOCGIFINDEX, &ifr);
+ if(r < 0) return -1;
+
+ *if_indexp = ifr.ifr_ifindex;
+ return 0;
+}
+
+int mbtk_ifc_configure1(const char *ifname,
+ in_addr_t address,
+ uint32_t prefixLength,
+ in_addr_t gateway,
+ in_addr_t netmask)
+{
+ if(mbtk_ifc_open())
+ {
+ LOGE("mbtk_ifc_open() fail.", strerror(errno));
+ return -1;
+ }
+
+ if (mbtk_ifc_up(ifname))
+ {
+ LOGE("failed to turn on interface %s: %s", ifname, strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+ if (mbtk_ifc_set_addr(ifname, address, netmask))
+ {
+ LOGE("failed to set ipaddr %s: %s", ipaddr_to_string(address), strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+ if (ifc_set_prefixLength(ifname, prefixLength))
+ {
+ LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+ if (ifc_create_default_route1(ifname, gateway))
+ {
+ LOGE("failed to set default route %s: %s", ipaddr_to_string(gateway), strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+
+ mbtk_ifc_close();
+ return 0;
+}
+
+int mbtk_ifc_configure2(const char *ifname,
+ const char *ipv4,
+ uint32_t prefixLength,
+ const char *gateway,
+ const char *netmask)
+{
+ if(mbtk_ifc_open())
+ {
+ LOGE("mbtk_ifc_open() fail.", strerror(errno));
+ return -1;
+ }
+
+ if(ipv4 == NULL) {
+ if (mbtk_ifc_down(ifname))
+ {
+ LOGE("failed to turn off interface %s: %s", ifname, strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+ } else {
+ if (mbtk_ifc_up(ifname))
+ {
+ LOGE("failed to turn on interface %s: %s", ifname, strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+ }
+
+ if (mbtk_ifc_ip_config(ifname, ipv4, netmask, gateway))
+ {
+ LOGE("failed to set ipaddr: %s", strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+
+// mbtk_ifc_set_netmask(ifname, netmask);
+
+#if 0
+ if (ifc_set_prefixLength(ifname, prefixLength))
+ {
+ LOGE("failed to set prefixLength %d: %s", prefixLength, strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+#endif
+
+#if 0
+ if (ifc_create_default_route2(ifname, gateway))
+ {
+ LOGE("failed to set default route: %s", strerror(errno));
+ mbtk_ifc_close();
+ return -1;
+ }
+#endif
+
+ mbtk_ifc_close();
+
+ return 0;
+}
+
+struct in6_ifreq {
+ struct in6_addr addr;
+ uint32_t prefixlen;
+ unsigned int ifindex;
+};
+
+int mbtk_ipv6_config(const char *ifname, const char *ipv6, uint32_t prefixLength)
+{
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+ int sockfd;
+ int err = 0;
+
+ // Create IPv6 socket to perform the ioctl operations on
+ sockfd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IP);
+ if(sockfd < 0) {
+ LOGE("socket() fail.[%d]", errno);
+ return -1;
+ }
+
+ if(ipv6) {
+ if(ifc_set_flags(sockfd, ifname, IFF_UP, 0) < 0) {
+ LOGE("if up fail[%d].", errno);
+ err = -1;
+ goto exit;
+ }
+
+ // Copy the interface name to the ifreq struct
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ // Get the ifrindex of the interface
+ if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0)
+ {
+ LOGE("ioctl SIOGIFINDEX error.");
+ err = -1;
+ goto exit;
+ }
+
+ // Prepare the in6_ifreq struct and set the address to the interface
+ if(inet_pton(AF_INET6, ipv6, &ifr6.addr) < 0) {
+ LOGE("inet_pton() fail[%d].", errno);
+ err = -1;
+ goto exit;
+ }
+ } else {
+ if(ifc_set_flags(sockfd, ifname, 0, IFF_UP) < 0) {
+ LOGE("if down fail[%d].", errno);
+ err = -1;
+ goto exit;
+ }
+
+ // Copy the interface name to the ifreq struct
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ // Get the ifrindex of the interface
+ if(ioctl(sockfd, SIOGIFINDEX, &ifr) < 0)
+ {
+ LOGE("ioctl SIOGIFINDEX error.");
+ err = -1;
+ goto exit;
+ }
+
+ // Set IPv6 to 0.
+ memset(&(ifr6.addr), 0, sizeof(struct in6_addr));
+ }
+ ifr6.ifindex = ifr.ifr_ifindex;
+ ifr6.prefixlen = prefixLength;
+ if(ioctl(sockfd, SIOCSIFADDR, &ifr6) < 0) {
+ LOGE("ioctl SIOCSIFADDR error.");
+ err = -1;
+ goto exit;
+ }
+
+ LOGD("Set IPv6 : %s success.", ipv6);
+exit:
+ close(socket);
+ return err;
+}
diff --git a/mbtk/libmbtk_lib/net/mbtk_net_control.c b/mbtk/libmbtk_lib/net/mbtk_net_control.c
new file mode 100755
index 0000000..722efda
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_net_control.c
@@ -0,0 +1,615 @@
+/*************************************************************
+Description:
+ C file for network control.
+Author:
+ LiuBin
+Date:
+ 2019/7/24 17:13:06
+*************************************************************/
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/route.h>
+#include <cutils/properties.h>
+#include <telephony/ril.h>
+
+#include "mbtk_type.h"
+#include "mbtk_net_control.h"
+#include "mbtk_task.h"
+#include "mbtk_utils.h"
+#include "mbtk_str.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "mbtk_net_control"
+#include "mbtk_log.h"
+
+/*************************************************************
+ Constants and Macros
+*************************************************************/
+#define NET_CONTROL_BUF_SIZE 1024
+#ifndef INFTIM
+#define INFTIM (-1) /* infinite poll timeout */
+#endif
+#define MBTK_NET_PING_HOST "223.5.5.5"
+#define MBTK_NET_PING_IP "180.97.33.107" // IP for www.baidu.com
+
+// #define MBTK_NET_MONITOR_SUPPORT
+
+/*************************************************************
+ Variables:local
+*************************************************************/
+static char net_interface[20];
+static char net_ip[20];
+static bool net_if_inited = FALSE;
+static mbtk_net_state_t net_state = MBTK_NET_STATE_OFF;
+static bool net_control_thread_running = FALSE;
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+static pthread_t net_control_thread_id = -1;
+static int net_control_fd = -1;
+static char net_if_name[100] = {0};
+#endif
+
+/*************************************************************
+ Variables:public
+*************************************************************/
+
+
+/*************************************************************
+ Local Function Declaration
+*************************************************************/
+static mbtk_net_state_callback_func net_state_cb = NULL;
+
+/*************************************************************
+ Local Function Definitions
+*************************************************************/
+// Test network connected?
+// ping www.baidu.com
+static bool net_connected(const char *inf)
+{
+ char cmd[100];
+ char cmd_rsp[100];
+
+ // IP get now, ping www.baidu.com
+ memset(cmd,0,100);
+ snprintf(cmd,100,
+ "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"",
+ inf,
+ MBTK_NET_PING_HOST);
+ if(!mbtk_cmd_line(cmd,cmd_rsp,100))
+ {
+ LOGE("ping www.baidu.com cmd error.");
+ return FALSE;
+ }
+
+ LOGI("cmd_rsp:%s",cmd_rsp);
+ // ping www.baidu.com success.
+ if(str_startwith(cmd_rsp, "8 bytes from "))
+ {
+ return TRUE;
+ }
+#if 0
+ else if(str_contains(cmd_rsp, "unknown host"))
+ {
+ // DNS error,ping IP angin.
+ memset(cmd,0,100);
+ snprintf(cmd,100,
+ "ping -I %s -c1 -s0 -w1000 %s | grep \"8 bytes from \"",
+ inf,
+ MBTK_NET_PING_IP);
+ if(!mbtk_cmd_line(cmd,cmd_rsp,100))
+ {
+ LOGW("ping www.baidu.com IP cmd error.");
+ return FALSE;
+ }
+
+ if(str_startwith(cmd_rsp, "8 bytes from "))
+ {
+ return TRUE;
+ }
+ else
+ {
+ LOGW("Network unconnected.(ping baidu IP fail)");
+ return FALSE;
+ }
+ }
+#endif
+ else
+ {
+ LOGW("Network unconnected.(ping baidu host fail)");
+ return FALSE;
+ }
+
+ LOGW("ifconfig cmd fail.");
+ return FALSE;
+}
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+static int net_control_netlink_init()
+{
+ struct sockaddr_nl sa;
+ int len = 2048;
+
+ net_control_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if(net_control_fd < 0)
+ {
+ LOGE("socket() fail.[%d]",errno);
+ return -1;
+ }
+
+ if(setsockopt(net_control_fd,
+ SOL_SOCKET, SO_RCVBUF, &len, sizeof(len)) < 0)
+ {
+ LOGE("setsockopt() fail.[%d]",errno);
+ return -1;
+ }
+
+ bzero(&sa, sizeof(sa));
+ sa.nl_family = AF_NETLINK;
+ sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE /*| RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE*/;
+ if(bind(net_control_fd,
+ (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ {
+ LOGE("bind() fail.[%d]",errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
+{
+ for ( ; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
+ if (attr->rta_type <= max) {
+ tb[attr->rta_type] = attr;
+ }
+ }
+}
+
+static void net_control_if_change(struct nlmsghdr *nh)
+{
+ int msg_len;
+ struct rtattr *tb[IFLA_MAX + 1];
+ struct ifinfomsg *ifinfo;
+ bzero(tb, sizeof(tb));
+ if(nh == NULL)
+ {
+ LOGE("mbtk_net_if_change() nh == NULL");
+ return;
+ }
+
+ ifinfo = NLMSG_DATA(nh);
+ if(ifinfo == NULL)
+ {
+ LOGE("mbtk_net_if_change() ifinfo == NULL");
+ return;
+ }
+
+ msg_len = nh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifinfo), msg_len); /* 8 */
+
+ LOGD("Interface changed:if_index=%d,if_name=%s,type=%s,state=%s",
+ ifinfo->ifi_index, (tb[IFLA_IFNAME] ? RTA_DATA(tb[IFLA_IFNAME]) : " "),
+ (nh->nlmsg_type == RTM_NEWLINK) ? "NEWLINK" : "DELLINK",
+ (ifinfo->ifi_flags & IFF_UP) ? "up" : "down");
+
+ if(net_state_cb) {
+ mbtk_net_if_change_info_t if_info;
+ memset(&if_info, 0x0, sizeof(mbtk_net_if_change_info_t));
+ if_info.if_index = ifinfo->ifi_index;
+ if(tb[IFLA_IFNAME]) {
+ memcpy(if_info.if_name, RTA_DATA(tb[IFLA_IFNAME]), strlen(RTA_DATA(tb[IFLA_IFNAME])));
+ }
+ if_info.type = (nh->nlmsg_type == RTM_NEWLINK) ? MBTK_NET_IF_CHANGE_TYPE_ADD : MBTK_NET_IF_CHANGE_TYPE_DEL;
+ if_info.state = (ifinfo->ifi_flags & IFF_UP) ? MBTK_NET_IF_CHANGE_STATE_UP : MBTK_NET_IF_CHANGE_STATE_DOWN;
+ if(str_empty(net_if_name)) { // No set if name, process all interface change.
+ net_state_cb(MBTK_NET_CHANGE_IF, &if_info);
+ } else {
+ // Only monitor specific interface.
+ if(strcmp(net_if_name, if_info.if_name) == 0) {
+ net_state_cb(MBTK_NET_CHANGE_IF, &if_info);
+ }
+ }
+ }
+}
+
+static void net_control_addr_change(struct nlmsghdr *nlh)
+{
+ int len;
+ struct rtattr *tb[IFA_MAX + 1];
+ struct ifaddrmsg *ifaddr;
+
+ bzero(tb, sizeof(tb));
+ ifaddr = NLMSG_DATA(nlh);
+ len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));
+ parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len);
+
+ if (tb[IFA_ADDRESS] != NULL) {
+ char tmp[256] = {0};
+ inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));
+ LOGD("Address changed:index=%d,type=%s,if_name=%s,addr=%s", ifaddr->ifa_index,
+ (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR",
+ tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", tmp);
+
+ if(net_state_cb) {
+ mbtk_net_addr_change_info_t addr_info;
+ memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t));
+ addr_info.if_index = ifaddr->ifa_index;
+ addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL;
+ if(tb[IFA_LABEL] != NULL) {
+ memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL])));
+ }
+ if (strlen(tmp) > 0) {
+ memcpy(addr_info.addr, tmp, strlen(tmp));
+ }
+ if(str_empty(net_if_name)) { // No set if name, process all address change.
+ net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+ } else {
+ // Only monitor specific address.
+ if(strcmp(net_if_name, addr_info.if_name) == 0) {
+ net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+ }
+ }
+ }
+ } else {
+ LOGD("Address changed:type=%s,if_name=%s,addr=%s",
+ (nlh->nlmsg_type == RTM_NEWADDR) ? "NEWADDR":"DELADDR",
+ tb[IFA_LABEL] ? RTA_DATA(tb[IFA_LABEL]) : "Unknown", "Unknown");
+
+ if(net_state_cb) {
+ mbtk_net_addr_change_info_t addr_info;
+ memset(&addr_info, 0x0, sizeof(mbtk_net_addr_change_info_t));
+ addr_info.if_index = ifaddr->ifa_index;
+ addr_info.type = (nlh->nlmsg_type == RTM_NEWADDR) ? MBTK_NET_ADDR_CHANGE_TYPE_ADD : MBTK_NET_ADDR_CHANGE_TYPE_DEL;
+ if(tb[IFA_LABEL] != NULL) {
+ memcpy(addr_info.if_name, RTA_DATA(tb[IFA_LABEL]), strlen(RTA_DATA(tb[IFA_LABEL])));
+ }
+ if(str_empty(net_if_name)) { // No set if name, process all address change.
+ net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+ } else {
+ // Only monitor specific address.
+ if(strcmp(net_if_name, addr_info.if_name) == 0) {
+ net_state_cb(MBTK_NET_CHANGE_ADDR, &addr_info);
+ }
+ }
+ }
+ }
+}
+
+static void* net_control_monitor_run(void *arg)
+{
+ LOGI("net_control_monitor_run start.");
+ if(net_control_netlink_init() < 0)
+ {
+ LOGE("mbtk_net_monitor_run() fail.");
+ return ((void*)0);
+ }
+
+ fd_set rd_set;
+ struct timeval timeout;
+ int select_r;
+ int read_r;
+ struct sockaddr_nl sa;
+ struct nlmsghdr *nh;
+ char buff[NET_CONTROL_BUF_SIZE];
+
+ while (net_control_thread_running)
+ {
+ FD_ZERO(&rd_set);
+ FD_SET(net_control_fd, &rd_set);
+ timeout.tv_sec = 5;
+ timeout.tv_usec = 0;
+ select_r = select(net_control_fd + 1, &rd_set, NULL, NULL, &timeout);
+ if (select_r < 0)
+ {
+ perror("select");
+ }
+ else if (select_r > 0)
+ {
+ if (FD_ISSET(net_control_fd, &rd_set))
+ {
+ read_r = read(net_control_fd, buff, NET_CONTROL_BUF_SIZE);
+ LOGI("Net change:read len:%d",read_r);
+#if 0
+ int i;
+ for(i = 0; i < 32 && i < read_r; i++)
+ LOGI("data:%x",buff[i]);
+#endif
+ for (nh = (struct nlmsghdr *) buff; NLMSG_OK(nh, read_r); nh = NLMSG_NEXT(nh, read_r))
+ {
+ LOGI("msg_type:%d",nh->nlmsg_type);
+ switch (nh->nlmsg_type)
+ {
+ default:
+ LOGI("nh->nlmsg_type = %d\n", nh->nlmsg_type);
+ break;
+ case NLMSG_DONE:
+ case NLMSG_ERROR:
+ break;
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ net_control_if_change(nh);
+ break;
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ net_control_addr_change(nh);
+ break;
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ //print_rtmsg(nh);
+ break;
+ }
+
+ }
+ }
+ }
+ }
+
+ LOGD("mbtk_net_monitor_run exist ...");
+
+ return ((void*)0);
+}
+
+static mbtk_task_info net_control_thread =
+{
+ .task_id = &net_control_thread_id,
+ .thread_run = net_control_monitor_run,
+ .args = NULL
+};
+#endif
+
+static int net_control_interface_init()
+{
+ // seth_ltex
+ int i = 0;
+ int size = 0;
+ char result[NET_CONTROL_BUF_SIZE];
+ char cmd[100];
+ int index = 0;
+ while(i <= 7)
+ {
+ size = snprintf(cmd, 100,"ifconfig ccinet%d", i);
+ cmd[size] = '\0';
+ memset(result,0x0,NET_CONTROL_BUF_SIZE);
+ if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+ {
+ index = str_indexof(result,"inet addr:");
+ if(index > 0)
+ {
+ size = snprintf(net_interface, 20,"ccinet%d", i);
+ net_interface[size] = '\0';
+
+ memcpy(net_ip,result + index + 10,20);
+
+ char *ptr = net_ip;
+ while(*ptr && *ptr != ' ')
+ {
+ ptr++;
+ }
+ *ptr = '\0';
+ break;
+ }
+ }
+ i++;
+ }
+
+ LOGI("Interface : %s, IP : %s",net_interface,net_ip);
+ if(index )
+ {
+ return 0;
+ }
+ else{
+ return -1;
+ }
+}
+
+static int net_control_init()
+{
+ if(net_if_inited)
+ {
+ LOGD("Network control has inited.");
+ return 0;
+ }
+
+ memset(net_ip,0x0,20);
+ memset(net_interface,0x0,20);
+ if(net_control_interface_init())
+ return -1;
+
+ net_if_inited = TRUE;
+ LOGI("net_control_init() success.");
+ return 0;
+}
+
+static int net_control_state_change(bool enable)
+{
+ int size;
+ char result[NET_CONTROL_BUF_SIZE];
+ char cmd[100];
+ if(enable)
+ {
+ // ifconfig seth_lte1 up
+ // ip route add default via 10.94.251.205 dev seth_lte1
+ size = snprintf(cmd,100,"ifconfig %s up",net_interface);
+ cmd[size] = '\0';
+
+ if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+ {
+ size = snprintf(cmd,100,"ip route add default via %s dev %s",net_ip,net_interface);
+ cmd[size] = '\0';
+
+ if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+ {
+ net_state = MBTK_NET_STATE_CONN;
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ // ifconfig seth_lte1 down
+ size = snprintf(cmd,100,"ifconfig %s down",net_interface);
+ cmd[size] = '\0';
+
+ if(mbtk_cmd_line(cmd, result, NET_CONTROL_BUF_SIZE))
+ {
+ net_state = MBTK_NET_STATE_OFF;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+/*************************************************************
+ Public Function Definitions
+*************************************************************/
+/*=============================================
+FUNCTION
+ mbtk_net_state_get()
+
+DESCRIPTION
+ Get network state.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ None
+
+RETURN VALUE
+ Current network state.
+
+SIDE EFFECTS
+ None
+=============================================*/
+mbtk_net_state_t mbtk_net_state_get()
+{
+ net_control_init();
+
+ net_state = MBTK_NET_STATE_OFF;
+ if(strlen(net_ip) > 0)
+ {
+ if(net_connected(net_interface))
+ net_state = MBTK_NET_STATE_CONN;
+ }
+
+ LOGI("[GET]Net state:%d",net_state);
+
+ if(net_state == MBTK_NET_STATE_CONN)
+ {
+ char value[PROPERTY_VALUE_MAX] = {0};
+ if (property_get("persist.mbtk.netstate", value, "0,0") > 0 && strcmp(value,"0,0")) {
+ int regStatus = 0, gprsState = 0;
+ char *ptr = value;
+ regStatus = atoi(ptr);
+ if((ptr = strstr(ptr, ",")))
+ {
+ gprsState = atoi(ptr + 1);
+ }
+
+ LOGI("regStatus : %d, gprsState : %d", regStatus, gprsState);
+ if(regStatus != 1 && regStatus != 5) // Not Home/Roaming Network.
+ {
+ net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+ }
+ else
+ {
+ if (gprsState == RADIO_TECH_LTE || gprsState == RADIO_TECH_LTEP)
+ {
+ net_state = MBTK_NET_STATE_CONN_4G;
+ }
+ else if ((gprsState == RADIO_TECH_GPRS) || (gprsState == RADIO_TECH_EDGE) || (gprsState == RADIO_TECH_GSM))
+ {
+ net_state = MBTK_NET_STATE_CONN_2G;
+ } else if((gprsState == RADIO_TECH_UMTS) || (gprsState == RADIO_TECH_HSDPA)
+ || (gprsState == RADIO_TECH_HSUPA) || (gprsState == RADIO_TECH_HSPA)) {
+ net_state = MBTK_NET_STATE_CONN_3G;
+ } else {
+ net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+ }
+ }
+ }
+ else
+ {
+ LOGE("property_get persist.mbtk.netstate fail.");
+ net_state = MBTK_NET_STATE_CONN_UNKNOWN;
+ goto end;
+ }
+ }
+
+end:
+ return net_state;
+}
+
+/*=============================================
+FUNCTION
+ mbtk_net_enable()
+
+DESCRIPTION
+ Set network state.
+
+DEPENDENCIES
+ None
+
+PARAMETERS
+ enable
+ TRUE : Enable network.
+ FALSE: Diable network.
+
+RETURN VALUE
+ 0 : Success
+ -1: Fail
+
+SIDE EFFECTS
+ None
+=============================================*/
+int mbtk_net_enable(bool enable)
+{
+ if( net_control_init())
+ return -1;
+
+ int result = net_control_state_change(enable);
+
+ LOGI("[SET]Net state:%d",net_state);
+
+ return result;
+}
+
+int mbtk_net_monitor_reg(const char* if_name, mbtk_net_state_callback_func state_cb)
+{
+ if( net_control_init())
+ return -1;
+
+#ifdef MBTK_NET_MONITOR_SUPPORT
+ net_control_thread_running = TRUE;
+ if(mbtk_task_start(&net_control_thread))
+ {
+ LOGE("Create thread fail.");
+ net_control_thread_id = -1;
+ net_control_thread_running = FALSE;
+ return -1;
+ }
+#endif
+
+ net_state_cb = state_cb;
+ if(str_empty(if_name)) {
+ memset(net_if_name, 0x0, sizeof(net_if_name));
+ } else {
+ memset(net_if_name, 0x0, sizeof(net_if_name));
+ memcpy(net_if_name, if_name, strlen(if_name));
+ }
+
+ return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/net/mbtk_sock.c b/mbtk/libmbtk_lib/net/mbtk_sock.c
new file mode 100755
index 0000000..d52abdb
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_sock.c
@@ -0,0 +1,659 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/select.h>
+#include <signal.h>
+#include <sys/time.h>
+
+#include "mbtk_sock.h"
+#include "mbtk_log.h"
+
+int sock_net_open(mbtk_net_info_s *net_info, mbtk_addr_family_e addr_family)
+{
+ return 0;
+}
+
+int sock_open(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err)
+{
+ if(net_info == NULL || sock_info == NULL) {
+ LOGE("ARG error.");
+ return -1;
+ }
+ int family = AF_INET;
+ if(sock_info->addr_family == MBTK_ADDR_IPV6) { // Only IPv6
+ family = AF_INET6;
+ }
+ if(sock_info->sock_type == MBTK_SOCK_UDP) { // UDP
+ // socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if((sock_info->fd = socket(family, SOCK_DGRAM, IPPROTO_UDP)) < 0){
+ LOGE("socket() fail.[%d]",errno);
+ goto result_fail;
+ }
+ } else if(sock_info->sock_type == MBTK_SOCK_TCP){ // TCP
+ if((sock_info->fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0){
+ LOGE("socket() fail.[%d]",errno);
+ goto result_fail;
+ }
+ } else {
+ LOGE("Unknown socket type:%d", sock_info->sock_type);
+ return -1;
+ }
+#if 1
+ // Set O_NONBLOCK
+ int flags = fcntl(sock_info->fd, F_GETFL, 0);
+ if (flags < 0) {
+ LOGE("Get flags error:%d", errno);
+ goto result_fail_with_close;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(sock_info->fd, F_SETFL, flags) < 0) {
+ LOGE("Set flags error:%d", errno);
+ goto result_fail_with_close;
+ }
+#endif
+ // Connect
+ LOGD("Start conn:%s:%d",sock_info->host,sock_info->port);
+ if (strlen(sock_info->host) > 0 && sock_info->port > 0)
+ {
+ if(family == AF_INET6)
+ {
+ struct addrinfo hints;
+ struct addrinfo *answer, *curr;
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_INET6; /* Allow IPv4 or IPv6 */
+ hints.ai_socktype = sock_info->sock_type; /* Datagram socket */
+ hints.ai_flags = 0;
+ hints.ai_protocol = 0; /* Any protocol */
+
+ int ret = getaddrinfo(sock_info->host, NULL, &hints, &answer);
+ if(ret < 0)
+ {
+ printf("\ngetaddrinfo error\n");
+ goto result_fail_with_close;
+ }
+
+ struct sockaddr_in6 *addr_in6=NULL;
+ struct sockaddr_in6 serverSockAddr;
+ bzero(&serverSockAddr, sizeof(struct sockaddr_in6));
+ serverSockAddr.sin6_family = AF_INET6;
+ serverSockAddr.sin6_port = htons(sock_info->port);
+ //memcpy(&serverSockAddr.sin6_addr, he->h_addr_list[0], sizeof(struct in6_addr));
+ //memcpy(&sock_info->addr.addr.dst_sock_addr6.sin6_addr, he->h_addr_list[0], sizeof(struct in_addr));
+ sock_info->addr.addr_len = sizeof(struct sockaddr_in6);
+
+ for (curr = answer; curr != NULL; curr = curr->ai_next)
+ {
+ addr_in6 = (struct sockaddr_in6 *)curr->ai_addr;
+ memcpy(&(serverSockAddr.sin6_addr), &(addr_in6->sin6_addr), sizeof(struct in6_addr));
+ }
+ if (connect(sock_info->fd, &serverSockAddr, sizeof(struct sockaddr_in6)) < 0)
+ {
+ if (EINPROGRESS != errno)
+ {
+ LOGE("connect() fail.[%d]", errno);
+ goto result_fail_with_close;
+ }
+ }
+ }
+ else
+ {
+ struct hostent *he = gethostbyname(sock_info->host);
+ if (he == NULL)
+ {
+ LOGE("gethostbyname() fail.[%d]", errno);
+ goto result_fail_with_close;
+ }
+ struct sockaddr_in serverSockAddr;
+ bzero(&serverSockAddr, sizeof(struct sockaddr_in));
+ serverSockAddr.sin_family = AF_INET;
+ serverSockAddr.sin_port = htons(sock_info->port);
+ memcpy(&serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+
+ log_hex("IPv4", he->h_addr_list[0], sizeof(struct in_addr));
+
+ memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+ sock_info->addr.addr_len = sizeof(struct sockaddr_in);
+ if (connect(sock_info->fd, (struct sockaddr *) &serverSockAddr, sizeof(serverSockAddr)) < 0)
+ {
+ if (EINPROGRESS != errno)
+ {
+ LOGE("connect() fail.[%d]", errno);
+ goto result_fail_with_close;
+ }
+ }
+ }
+
+ fd_set rset, wset;
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_SET(sock_info->fd, &rset);
+ FD_SET(sock_info->fd, &wset);
+ struct timeval time_out;
+ /*
+ time_out.tv_sec = timeout / 1000;
+ time_out.tv_usec = timeout % 1000 * 1000;
+ */
+ time_out.tv_sec = 100;
+ time_out.tv_usec = 0;
+ int nready = select(sock_info->fd + 1, &rset, &wset, NULL, &time_out);
+ LOGD("nready = %d", nready);
+ if (nready == 0) // Timeout
+ {
+ LOGE("Timeout.");
+ goto result_fail_with_close;
+ }
+ else
+ {
+ if (FD_ISSET(sock_info->fd, &rset) && FD_ISSET(sock_info->fd, &wset))
+ {
+ int error = -1;
+ socklen_t len = sizeof(int);
+ LOGE("Can read and write.");
+ if (getsockopt(sock_info->fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
+ {
+ LOGE("getsockopt fail.[%d]", errno);
+ goto result_fail_with_close;
+ }
+ else
+ {
+ LOGE("error = %d", error);
+ if (error != 0) // Fail
+ {
+ goto result_fail_with_close;
+ }
+ }
+ }
+ else if (FD_ISSET(sock_info->fd, &wset))
+ {
+ LOGI("Can write.");
+ }
+ else
+ {
+ LOGE("Can read(Impossible).");
+ goto result_fail_with_close;
+ }
+ }
+ }
+ else
+ {
+ LOGE("Can not conn.");
+ goto result_fail_with_close;
+ }
+
+ if (sock_info->is_ssl)
+ {
+
+ }
+
+ sock_info->read_buff.buffer = (char*)malloc(MBTK_BUFF_SIZE);
+ if(sock_info->read_buff.buffer) {
+ memset(sock_info->read_buff.buffer, 0x0, MBTK_BUFF_SIZE);
+ sock_info->read_buff.size = 0;
+ sock_info->read_buff.size_max = MBTK_BUFF_SIZE;
+ } else {
+ LOGE("malloc() fail.");
+ goto result_fail_with_close;
+ }
+
+ return sock_info->fd;
+result_fail_with_close:
+ close(sock_info->fd);
+ sock_info->fd = -1;
+result_fail:
+ LOGE("mbtk_sock_open() end:fail");
+ return -1;
+}
+
+int sock_addr_set(mbtk_net_info_s *net_info,mbtk_sock_info_s *sock_info,void *host, uint32 port)
+{
+ if(sock_info->fd <= 0) {
+ LOGE("Socket not open.");
+ return -1;
+ }
+
+ sock_info->addr.addr.serverSockAddr.sin_family = AF_INET;
+ sock_info->addr.addr.serverSockAddr.sin_port = htons(port);
+ struct hostent *he = gethostbyname(host);
+ if (he == NULL)
+ {
+ LOGE("gethostbyname() fail.[%d]", errno);
+ return -1;
+ }
+ else
+ {
+ LOGD("Ip(len-%d)", he->h_length);
+ int i = 0;
+ for(;i < he->h_length;i++){
+ LOGD("Ip Addr[%d]:%.2x", i, 0x0FF & he->h_addr_list[0][i]);
+ }
+ }
+ memcpy(&sock_info->addr.addr.serverSockAddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+ sock_info->addr.addr_len = sizeof(struct sockaddr_in);
+
+ return 0;
+}
+
+int sock_bind(int sockfd, bool is_ipv6, uint16 port)
+{
+ int ret_val;
+ struct sockaddr *ds_sockaddr = NULL;
+ struct sockaddr_in localaddr;
+ uint16 addr_legth = 0;
+
+ memset((char *) &localaddr, 0, sizeof(struct sockaddr_in));
+ localaddr.sin_family = AF_INET;
+ localaddr.sin_addr.s_addr = INADDR_ANY;
+ localaddr.sin_port = htons(port);
+ addr_legth = sizeof(struct sockaddr_in);
+ ds_sockaddr = (struct sockaddr *)&localaddr;
+ ret_val = bind(sockfd,ds_sockaddr,addr_legth);
+ if (ret_val < 0){
+ LOGE("bind() sockfd= %d fail", sockfd);
+ return -1;
+ }
+
+ return 0;
+}
+
+int sock_read(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+ unsigned int count = 0;
+ int len = 0;
+ int try_count = 0;
+ int times = timeout / 50;
+ memset(buffer, 0x0, buf_len);
+ while (count < buf_len)
+ {
+ try_count++;
+ if (sock_info->is_ssl)
+ {
+
+ }
+ else
+ {
+ len = read(sock_info->fd, (char*) buffer + count, buf_len - count);
+ }
+ if (len <= 0)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (count > 0) // Read data
+ break; // Read data end.
+
+ if (try_count >= times) // Timeout
+ {
+ count = -1;
+ if (times != 0)
+ {
+ *err = 10; // FTP_ERR_NET_TIMEOUT
+ }
+ LOGE("Not read enough data,return.[%d/%d]", count, buf_len);
+ break;
+ }
+ else
+ {
+ usleep(50000);
+ continue;
+ }
+ }
+ else
+ {
+ LOGD("read error.[%d]", errno);
+ if (errno == EINPROGRESS)
+ {
+ if (close(sock_info->fd) == 0) // Success
+ {
+ LOGD("Socket disconnected.Close it.");
+ sock_info->fd = -1;
+ }
+ if (count <= 0)
+ count = -1;
+ }
+ else
+ {
+ if (count <= 0)
+ count = 0;
+ }
+ break;
+ }
+ }
+ else
+ {
+ count += len;
+ }
+ }
+
+ LOGV("Read data[%d/%d].", count, buf_len);
+
+ return count;
+}
+
+int sock_read_async(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+ int len = -1;
+ int try_count = 0;
+ int times = timeout / 50;
+
+TCP_READ_AGAIN:
+ memset(buffer, 0x0, buf_len);
+ try_count++;
+ if (sock_info->is_ssl)
+ {
+
+ }
+ else
+ {
+ len = read(sock_info->fd, (char*) buffer, buf_len);
+ }
+ if (len < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ if(try_count == times)
+ {
+ LOGD("read timeout");
+ return -1;
+ }
+ usleep(50000);
+ goto TCP_READ_AGAIN;
+ }
+ else
+ {
+ LOGE("read error.[%d]", errno);
+ return -1;
+ }
+ }
+
+ LOGV("Read data[%d/%d].", len, buf_len);
+
+ return len;
+}
+
+#if 0
+int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+ if (sock_info->fd > 0)
+ {
+ char *buf_ptr = (char*)buffer;
+ char read_buf[1];
+ int read_len = 0;
+ while (TRUE)
+ {
+ if (sock_read_async(net_info, sock_info, read_buf, 1, timeout, err) == 1)
+ {
+ *buf_ptr++ = read_buf[0];
+ read_len++;
+
+ if (read_buf[0] == '\n' || read_len >= buf_len)
+ {
+ return read_len;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ }
+ return -1;
+}
+#else
+int sock_readline(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+ if (sock_info->fd > 0)
+ {
+ memset(buffer,0,buf_len);
+ int read_len = 0;
+ char *buf_ptr = (char*)buffer;
+ char *temp_ptr = sock_info->read_buff.buffer;
+
+ LOGV("TEMP buffer[fd - %d, len-%d]:%s", sock_info->fd, sock_info->read_buff.size, sock_info->read_buff.buffer);
+copy_angin:
+ while(sock_info->read_buff.size > 0 && *temp_ptr != '\n') {
+ *buf_ptr++ = *temp_ptr++;
+ sock_info->read_buff.size--;
+ read_len++;
+ }
+
+ LOGV("SIZE : %d,TEMP is \\n : %d", sock_info->read_buff.size, *temp_ptr == '\n');
+
+ if(sock_info->read_buff.size == 0) {
+ sock_info->read_buff.size = sock_read(net_info, sock_info, sock_info->read_buff.buffer,
+ sock_info->read_buff.size_max, timeout, err);
+ if(sock_info->read_buff.size <= 0) {
+ if(read_len == 0) { // No data.
+ LOGE("sock_read() fail.");
+ return -1;
+ } else {
+ return read_len;
+ }
+ }
+
+ temp_ptr = sock_info->read_buff.buffer;
+ goto copy_angin;
+ } else if(*temp_ptr == '\n') { // Read line.
+ *buf_ptr++ = '\n';
+ sock_info->read_buff.size--;
+ read_len++;
+
+ if(sock_info->read_buff.size > 0)
+ memcpy(sock_info->read_buff.buffer, temp_ptr + 1, sock_info->read_buff.size);
+
+ return read_len;
+ }
+
+ }
+ return -1;
+}
+#endif
+
+int sock_write(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout, int *err)
+{
+ int len = 0;
+ uint32 try_count = 0;
+ uint32 times = timeout * 100;
+ unsigned int count = 0;
+ while (count < buf_len)
+ {
+ try_count++;
+ if (sock_info->is_ssl)
+ {
+ //printf(" try_count = %d timeout = %d sock_info->is_ssl = 1\n",try_count,timeout);
+ if(try_count >= times)
+ {
+ printf("over time \n");
+ break;
+ }
+ }
+ else
+ {
+ len = write(sock_info->fd, (const char*)buffer + count, buf_len - count);
+ }
+ if (len < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ usleep(50000);
+ continue;
+ }
+ else
+ {
+ LOGE("write error.[%d]", errno);
+ if (count <= 0)
+ count = -1;
+ break;
+ }
+ }
+ else if (len == 0)
+ {
+ LOGE("write error(len == 0).[%d]", errno);
+ }
+ else
+ {
+ count += len;
+ }
+ }
+
+ if (count > 0)
+ {
+ LOGV("Write data[%d/%d] success.", count, buf_len);
+ }
+ else // Open session fail
+ {
+ LOGV("Write data[%d/%d] fail.", count, buf_len);
+ }
+
+ return count;
+}
+
+int sock_recv(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, void *buffer, uint32 buf_len, uint32 timeout)
+{
+ unsigned int count = 0;
+ int len = 0;
+ int try_count = 0;
+ int times = timeout / 50; // ms
+ memset(buffer, 0x0, buf_len);
+ while (count < buf_len)
+ {
+ try_count++;
+ len = recvfrom(sock_info->fd, (char*) buffer + count, buf_len - count, 0,
+ (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, (socklen_t *)&sock_info->addr.addr_len);
+ if (len <= 0)
+ {
+ if (errno == EWOULDBLOCK || errno == EAGAIN)
+ {
+ if (count > 0) // Read data
+ break; // Read data end.
+
+ if (try_count >= times) // Timeout
+ {
+ count = -1;
+ break;
+ }
+ else
+ {
+ usleep(50000);
+ continue;
+ }
+ }
+ else if (errno == EINPROGRESS)
+ {
+ if (close(sock_info->fd) == 0) // Success
+ {
+ LOGD("Socket disconnected.Close it.");
+ }
+ if (count <= 0)
+ count = -1;
+ break;
+ }
+ else
+ {
+ LOGE("recv error.[%d]", errno);
+ if (count <= 0)
+ count = -1;
+ break;
+ }
+ }
+ else
+ {
+ count += len;
+ }
+ }
+
+ LOGV("Read data[%d/%d].", count, buf_len);
+
+ return count;
+}
+
+int sock_sendto(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, const void *buffer, uint32 buf_len, uint32 timeout)
+{
+ int len = 0;
+ unsigned int count = 0;
+ int try_count = 0;
+ int times = timeout / 50; // ms
+ while (count < buf_len)
+ {
+ try_count++;
+ len = sendto(sock_info->fd,(char*) buffer + count, buf_len - count, 0,
+ (struct sockaddr *)&sock_info->addr.addr.serverSockAddr, sock_info->addr.addr_len);
+ if (len < 0)
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ if (count > 0) // Send part data
+ break;
+
+ if (try_count >= times) // Timeout
+ {
+ count = -1;
+ break;
+ }
+ else
+ {
+ usleep(50000);
+ continue;
+ }
+ }
+ else
+ {
+ LOGE("sendto error.[%d]", errno);
+ if (count <= 0)
+ count = -1;
+ break;
+ }
+ }
+ else if (len == 0)
+ {
+ LOGE("write error(len == 0).[%d]", errno);
+ }
+ else
+ {
+ count += len;
+ }
+ }
+
+ if (count == buf_len)
+ {
+ LOGV("Sendto data[%d/%d] success.", count, buf_len);
+ }
+ else
+ {
+ LOGV("Sendto data[%d/%d] fail.", count, buf_len);
+ }
+
+ return count;
+}
+
+int sock_close(mbtk_net_info_s *net_info, mbtk_sock_info_s *sock_info, uint32 timeout, int *err)
+{
+ if(sock_info->fd > 0) {
+ if(close(sock_info->fd) < 0)
+ {
+ LOGE("Close socket fail[%d].", errno);
+ return -1;
+ }
+ sock_info->fd = -1;
+ }
+
+ if(sock_info->read_buff.buffer) {
+ free(sock_info->read_buff.buffer);
+ sock_info->read_buff.buffer = NULL;
+ }
+ return 0;
+}
+
+int sock_net_close(mbtk_net_info_s *net_info, uint32 timeout, int *err)
+{
+ return 0;
+}
+
diff --git a/mbtk/libmbtk_lib/net/mbtk_sock2.c b/mbtk/libmbtk_lib/net/mbtk_sock2.c
new file mode 100755
index 0000000..ae5329e
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_sock2.c
@@ -0,0 +1,1741 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+#ifdef MBTK_POLARSSL_SUPPORT
+#include <polarssl/net.h>
+#include <polarssl/ssl.h>
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#include <polarssl/certs.h>
+#include <polarssl/x509.h>
+#include <polarssl/error.h>
+#include <polarssl/debug.h>
+#include <polarssl/config.h>
+#else
+#include <resolv.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+//#define SSL_VERIFY_PEER 0x01
+//#define SSL_FILETYPE_PEM 0x01
+//#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02
+
+#define DFL_CA_FILE "/ca.crt"
+#define DFL_CRT_FILE "/client.crt"
+#define DFL_KEY_FILE "/client.key"
+#endif
+#include <sys/ioctl.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "mbtk_sock"
+#include <mbtk_log.h>
+
+#include "mbtk_sock2.h"
+#include "mbtk_sock_internal.h"
+//#include "mbtk_openssl.h"
+
+#define SA struct sockaddr
+
+// Must define LOG_TAG in the first.
+//#include "mbtk_log.h"
+static int epoll_fd = -1;
+static int pipe_fds[2];
+static struct epoll_event epoll_events[20];
+static pthread_t sock_thread_id = -1;
+static bool sock_thread_running = FALSE;
+static mbtk_sock_s *mbtk_sock[MBTK_HANDLE_MAX_NUM] = {NULL};
+
+static int sock_find_first_free(const mbtk_sock_inter_info_s *inter_info)
+{
+ if(inter_info == NULL) {
+ LOGE("inter_info is NULL.");
+ return -1;
+ }
+
+ int index = 0;
+ //while((inter_info + index)->fd > 0) {
+ while(inter_info[index].fd > 0) {
+ index++;
+ }
+
+ if(index == MBTK_SOCK_MAX_NUM) {
+ LOGE("sock_infos too more.");
+ return -1;
+ }
+
+ return index;
+}
+
+static bool sock_info_check(int handle,mbtk_sock_inter_info_s *inter_info)
+{
+ if(inter_info == NULL || mbtk_sock[handle] == NULL) {
+ LOGE("internal_info is NULL.");
+ return FALSE;
+ }
+
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(inter_info->fd ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ return TRUE;
+ }
+ index++;
+ }
+
+ return FALSE;
+}
+
+static bool sock_is_close(int sockfd)
+{
+ char buff[32];
+ int recvBytes = recv(sockfd, buff, sizeof(buff), MSG_PEEK);
+
+ int err = errno;
+ //cout << "In close function, recv " << recvBytes << " bytes, err " << sockErr << endl;
+
+ if(recvBytes > 0) //Get data
+ return FALSE;
+
+ if((recvBytes == -1) && (err == EWOULDBLOCK)) //No receive data
+ return FALSE;
+
+ return TRUE;
+}
+
+static int sock_info_find_by_fd(int handle,int fd)
+{
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(fd == mbtk_sock[handle]->inter_infos[index].fd) {
+ return index;
+ }
+ index++;
+ }
+
+ return -1;
+}
+
+static void* sock_thread_run(void *data)
+{
+ LOGD("socket thread is running...");
+ if(data != NULL)
+ LOGD("sock_thread_run has arg.");
+
+ int nready;
+ if (socketpair( AF_UNIX, SOCK_STREAM, 0, pipe_fds) < 0) {
+ LOGE("socketpair() error.");
+ return NULL;
+ } else {
+ struct epoll_event ev;
+ ev.data.fd = pipe_fds[1];
+ ev.events = EPOLLIN | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,pipe_fds[1],&ev);
+ }
+
+ while(sock_thread_running) {
+ nready = epoll_wait(epoll_fd,epoll_events,20,-1);
+ int i;
+ for(i=0;i<nready;++i) {
+ LOGV("fd[%d] event = %x",epoll_events[i].data.fd,epoll_events[i].events);
+ if(pipe_fds[1] == epoll_events[i].data.fd) {
+ LOGD("Get exist sig.");
+ sock_thread_running = FALSE;
+ break;
+ }
+
+ int handle = 0;
+ while(handle < MBTK_HANDLE_MAX_NUM) {
+ if(mbtk_sock[handle] != NULL) {
+ int index = sock_info_find_by_fd(handle,epoll_events[i].data.fd);
+ if(index >= 0 && mbtk_sock[handle]->init_info.sock_cb != NULL) {
+ mbtk_sock_inter_info_s *inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ mbtk_sock_info *info = &(mbtk_sock[handle]->infos[index]);
+
+ //if(sock_is_close(epoll_events[i].data.fd)) {
+ // LOGE("Socket %d is closed.",epoll_events[i].data.fd);
+ // break;
+ //}
+ mbtk_sock_cb_info_s sock_info;
+ sock_info.sock_fd = inter_info->fd;
+ sock_info.event = epoll_events[i].events;
+ sock_info.sock_type = info->type;
+ mbtk_sock[handle]->init_info.sock_cb(handle, &sock_info);
+
+ if(epoll_events[i].events & EPOLLERR){ // error[ UDP server can't use.]
+ LOGD("%d EPOLLERR.",epoll_events[i].data.fd);
+ }
+
+ if ((epoll_events[i].events & EPOLLIN)
+ && (epoll_events[i].events & EPOLLOUT)) {
+ LOGD("%d can read and write.",epoll_events[i].data.fd);
+ int error = -1;
+ int len = sizeof(int);
+ if(getsockopt(epoll_events[i].data.fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){
+ LOGE("getsockopt fail.[%d]",errno);
+ }else{
+ LOGD("error = %d",error);
+ }
+ }
+
+ if (epoll_events[i].events & EPOLLOUT) { // Can write.
+ LOGD("%d can write.",epoll_events[i].data.fd);
+ }
+
+ if (epoll_events[i].events & EPOLLIN) { // Can read.
+ LOGD("%d can read.",epoll_events[i].data.fd);
+ }
+ }
+ }
+
+ handle++;
+ }
+ }
+ }
+
+ LOGD("socket thread exit.");
+ return ((void*)0);
+}
+
+static int sock_thread_start()
+{
+ sock_thread_running = TRUE;
+ if (0 != pthread_create(&sock_thread_id, NULL, sock_thread_run, NULL))
+ {
+ LOGE("error when create pthread,%d\n", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+void net_state_callback_func(mbtk_net_change_type_t type, const void *data)
+{
+ if(type == MBTK_NET_CHANGE_ADDR && data != NULL) {
+ int handle = 0;
+ const mbtk_net_addr_change_info_t *addr_info = (const mbtk_net_addr_change_info_t *)data;
+ while(handle < MBTK_HANDLE_MAX_NUM) {
+ if(mbtk_sock[handle] != NULL) {
+ if(mbtk_sock[handle]->init_info.net_cb != NULL) {
+ mbtk_net_cb_info_s net_info;
+ net_info.state = (addr_info->type == MBTK_NET_ADDR_CHANGE_TYPE_ADD) ? 1 : 0;
+ net_info.addr = addr_info->addr;
+ net_info.if_name = addr_info->if_name;
+ mbtk_sock[handle]->init_info.net_cb(handle, &net_info);
+ }
+ }
+
+ handle++;
+ }
+ }
+}
+
+extern mbtk_sock_handle mbtk_sock_init(mbtk_init_info *info)
+{
+ mbtk_sock_handle handle = 0;
+ while(handle < MBTK_HANDLE_MAX_NUM) {
+ if(mbtk_sock[handle] == NULL)
+ break;
+
+ handle++;
+ }
+
+ if(handle == MBTK_HANDLE_MAX_NUM) {
+ LOGE("Socket handle is full.");
+ return -1;
+ }
+
+ mbtk_sock[handle] = (mbtk_sock_s*)malloc(sizeof(mbtk_sock_s));
+ memset(mbtk_sock[handle],0x0,sizeof(mbtk_sock_s));
+ if(info != NULL) {
+ mbtk_sock[handle]->init_info.net_type = info->net_type;
+ mbtk_sock[handle]->init_info.net_cb = info->net_cb;
+ mbtk_sock[handle]->init_info.sock_cb = info->sock_cb;
+ if(!str_empty(info->if_name)) {
+ memcpy(mbtk_sock[handle]->init_info.if_name, info->if_name, strlen(info->if_name));
+ }
+ } else {
+ mbtk_sock[handle]->init_info.net_type = MBTK_NET_LINUX;
+ mbtk_sock[handle]->init_info.net_cb = NULL;
+ mbtk_sock[handle]->init_info.sock_cb = NULL;
+ }
+
+ if(!sock_thread_running) {
+ epoll_fd = epoll_create(256);
+ if(sock_thread_start()) {
+ LOGE("Start thread fail.");
+ return -1;
+ }
+ }
+
+ if(mbtk_net_monitor_reg(str_empty(info->if_name) ? NULL : info->if_name, net_state_callback_func)) {
+ LOGE("mbtk_net_monitor_reg() fail.");
+ return -1;
+ }
+
+ return handle;
+}
+
+#ifdef MBTK_POLARSSL_SUPPORT
+static int mbtk_polarssl_open(int fd ,bool ingnore_cert,mbtk_sock_inter_info_s* inter_info)
+{
+ LOGE("8\n");
+ int ret = 0, len, tail_len, i, written, frags;
+ unsigned char buf[SSL_MAX_CONTENT_LEN + 1];
+ const char *pers = "ssl_client";
+ opt.server_name = DFL_SERVER_NAME;
+ opt.server_addr = DFL_SERVER_ADDR;
+ opt.server_port = DFL_SERVER_PORT;
+ opt.debug_level = DFL_DEBUG_LEVEL;
+ opt.nbio = DFL_NBIO;
+ opt.request_page = DFL_REQUEST_PAGE;
+ opt.request_size = DFL_REQUEST_SIZE;
+ opt.ca_file = DFL_CA_FILE;
+ opt.ca_path = DFL_CA_PATH;
+ opt.crt_file = DFL_CRT_FILE;
+ opt.key_file = DFL_KEY_FILE;
+ opt.psk = DFL_PSK;
+ opt.psk_identity = DFL_PSK_IDENTITY;
+ opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
+ opt.renegotiation = DFL_RENEGOTIATION;
+ opt.allow_legacy = DFL_ALLOW_LEGACY;
+ opt.renegotiate = DFL_RENEGOTIATE;
+ opt.exchanges = DFL_EXCHANGES;
+ opt.min_version = DFL_MIN_VERSION;
+ opt.max_version = DFL_MAX_VERSION;
+ opt.auth_mode = DFL_AUTH_MODE;
+ opt.mfl_code = DFL_MFL_CODE;
+ opt.trunc_hmac = DFL_TRUNC_HMAC;
+ opt.reconnect = DFL_RECONNECT;
+ opt.reco_delay = DFL_RECO_DELAY;
+ opt.tickets = DFL_TICKETS;
+ opt.alpn_string = DFL_ALPN_STRING;
+
+ entropy_context entropy;
+ ctr_drbg_context ctr_drbg;
+ ssl_context ssl;
+ ssl_session saved_session;
+ x509_crt cacert;
+ x509_crt clicert;
+ pk_context pkey;
+
+ memset( &ssl, 0, sizeof( ssl_context ) );
+ memset( &saved_session, 0, sizeof( ssl_session ) );
+ x509_crt_init( &cacert );
+ x509_crt_init( &clicert );
+ pk_init( &pkey );
+ LOGE("9\n");
+ /*
+ * 0. Initialize the RNG and the session data
+ */
+
+ entropy_init( &entropy );
+ if( ( ret = ctr_drbg_init( &ctr_drbg, entropy_func, &entropy,
+ (const unsigned char *) pers,
+ strlen( pers ) ) ) != 0 )
+ {
+ LOGE( " failed\n ! ctr_drbg_init returned -0x%x\n", -ret );
+ return -1;
+ }
+ if(!ingnore_cert)
+ {
+ LOGE("10\n");
+ /*
+ * 1.1. Load the trusted CA
+ */
+ //ret = x509_crt_parse(&cacert,ca1_cert,strlen(ca1_cert));
+ ret = x509_crt_parse_file( &cacert, opt.ca_path );
+ if( ret < 0 )
+ {
+ LOGE( " failed\n ! ca x509_crt_parse returned -0x%x\n\n", -ret );
+ return -1;
+ }
+
+ /*
+ * 1.2. Load own certificate and private key
+ *
+ * (can be skipped if client authentication is not required)
+ */
+
+ ret = x509_crt_parse_file( &clicert, opt.crt_file );
+ if( ret != 0 )
+ {
+ LOGE( " failed\n ! crt x509_crt_parse returned -0x%x\n\n", -ret );
+ return -1;
+ }
+
+ ret = pk_parse_keyfile( &pkey, opt.key_file, NULL);
+ if( ret != 0 )
+ {
+ LOGE( " failed\n ! key x509_crt_parse returned -0x%x\n\n", -ret );
+ return -1;
+ }
+ }
+ /*
+ * 2. Setup stuff
+ */
+ LOGE( " . Setting up the SSL/TLS structure..." );
+
+ if( ( ret = ssl_init( &ssl ) ) != 0 )
+ {
+ LOGE( " failed\n ! ssl_init returned -0x%x\n\n", -ret );
+ return -1;
+ }
+
+ ssl_set_endpoint( &ssl, SSL_IS_CLIENT );
+ if(ingnore_cert)
+ {
+ opt.auth_mode = SSL_VERIFY_OPTIONAL;
+ }
+ else
+ {
+ opt.auth_mode = SSL_VERIFY_REQUIRED;
+ }
+
+ ssl_set_authmode( &ssl, opt.auth_mode );
+
+ ssl_set_rng( &ssl, ctr_drbg_random, &ctr_drbg );
+
+ ssl_set_bio( &ssl, net_recv, &fd, net_send, &fd );
+
+ ssl_set_renegotiation( &ssl, opt.renegotiation );
+ ssl_legacy_renegotiation( &ssl, opt.allow_legacy );
+
+ ssl_set_ca_chain( &ssl, &cacert, NULL, NULL );
+ if(!ingnore_cert)
+ {
+ if( ( ret = ssl_set_own_cert( &ssl, &clicert, &pkey ) ) != 0 )
+ {
+ LOGE( " failed\n ! ssl_set_own_cert returned %d\n\n", ret );
+ return -1;
+ }
+ }
+ if( opt.min_version != -1 )
+ ssl_set_min_version( &ssl, SSL_MAJOR_VERSION_3, opt.min_version );
+ if( opt.max_version != -1 )
+ ssl_set_max_version( &ssl, SSL_MAJOR_VERSION_3, opt.max_version );
+ /*
+ * 3. Handshake
+ */
+ LOGE( " . Performing the SSL/TLS handshake..." );
+
+ while( ( ret = ssl_handshake( &ssl ) ) != 0 )
+ {
+ if( ret != POLARSSL_ERR_NET_WANT_READ && ret != POLARSSL_ERR_NET_WANT_WRITE )
+ {
+ LOGE( " failed\n ! ssl_handshake returned -0x%x\n", -ret );
+ if( ret == POLARSSL_ERR_X509_CERT_VERIFY_FAILED )
+ LOGE(
+ " Unable to verify the server's certificate. "
+ "Either it is invalid,\n"
+ " or you didn't set ca_file or ca_path "
+ "to an appropriate value.\n"
+ " Alternatively, you may want to use "
+ "auth_mode=optional for testing purposes.\n" );
+ LOGE( "\n" );
+ return -1;;
+ }
+ }
+
+ LOGE( " ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n",ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+ printf( " ok\n [ Protocol is %s ]\n [ Ciphersuite is %s ]\n",ssl_get_version( &ssl ), ssl_get_ciphersuite( &ssl ) );
+
+ /*
+ * 4. Verify the server certificate
+ */
+ LOGE( " . Verifying peer X.509 certificate..." );
+
+ if( ( ret = ssl_get_verify_result( &ssl ) ) != 0 )
+ {
+ LOGE( " failed\n" );
+
+ if( ( ret & BADCERT_EXPIRED ) != 0 )
+ LOGE( " ! server certificate has expired\n" );
+
+ if( ( ret & BADCERT_REVOKED ) != 0 )
+ LOGE( " ! server certificate has been revoked\n" );
+
+ if( ( ret & BADCERT_CN_MISMATCH ) != 0 )
+ LOGE( " ! CN mismatch (expected CN=%s)\n", opt.server_name );
+
+ if( ( ret & BADCERT_NOT_TRUSTED ) != 0 )
+ LOGE( " ! self-signed or not signed by a trusted CA\n" );
+
+ }
+
+ if( ssl_get_peer_cert( &ssl ) != NULL )
+ {
+ LOGE( " . Peer certificate information ...\n" );
+ x509_crt_info( (char *) buf, sizeof( buf ) - 1, " ",
+ ssl_get_peer_cert( &ssl ) );
+ LOGE( "%s\n", buf );
+ }
+
+ inter_info->cacert = &cacert;
+ inter_info->clicert = &clicert;
+ inter_info->ctr_drbg = &ctr_drbg;
+ inter_info->entropy = &entropy;
+ inter_info->pkey = &pkey;
+ inter_info->saved_session = &saved_session;
+ inter_info->ssl = &ssl;
+
+ return 0;
+}
+
+static int mbtk_polarssl_close(mbtk_sock_inter_info_s *inter_info)
+{
+ if (inter_info == NULL)
+ {
+ return -1;
+ }
+
+ int ret = -1;
+ while( ( ret = ssl_close_notify( inter_info->ssl ) ) < 0 )
+ {
+ if( ret == POLARSSL_ERR_NET_CONN_RESET )
+ {
+ LOGE( " ok (already closed by peer)\n" );
+ ret = 0;
+ return -1;
+ }
+
+ if( ret != POLARSSL_ERR_NET_WANT_READ &&
+ ret != POLARSSL_ERR_NET_WANT_WRITE )
+ {
+ LOGE( " failed\n ! ssl_close_notify returned %d\n\n", ret );
+ return -1;
+ }
+ }
+
+ x509_crt_free( inter_info->clicert );
+ x509_crt_free( inter_info->cacert );
+ pk_free( inter_info->pkey );
+ ssl_session_free( inter_info->saved_session );
+ ssl_free( inter_info->ssl );
+ ctr_drbg_free( inter_info->ctr_drbg );
+ entropy_free( inter_info->entropy );
+ return 0;
+}
+
+static int mbtk_polarssl_write( ssl_context *ssl, const unsigned char *buf, size_t len )
+{
+ return ssl_write(ssl, buf, len);
+}
+
+static int mbtk_polarssl_read( ssl_context *ssl, unsigned char *buf, size_t len )
+{
+ return ssl_read(ssl, buf, len);
+}
+
+#else
+
+void ShowCerts(SSL * ssl)
+{
+ X509 *cert;
+ char *line;
+
+ cert = SSL_get_peer_certificate(ssl);
+ // SSL_get_verify_result()是重点,SSL_CTX_set_verify()只是配置启不启用并没有执行认证,调用该函数才会真证进行证书认证
+ // 如果验证不通过,那么程序抛出异常中止连接
+ if(SSL_get_verify_result(ssl) == X509_V_OK){
+ printf("证书验证通过\n");
+ }
+ if (cert != NULL) {
+ printf("数字证书信息:\n");
+ line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
+ printf("证书: %s\n", line);
+ free(line);
+ line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
+ printf("颁发者: %s\n", line);
+ free(line);
+ X509_free(cert);
+ } else
+ printf("无证书信息!\n");
+}
+
+static int mbtk_openssl_open(int fd ,bool ingnore_cert,mbtk_sock_inter_info_s* inter_info)
+{
+ SSL_CTX *ctx;
+ SSL *ssl;
+
+ /* SSL 库初始化,参看 ssl-server.c 代码 */
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ SSL_load_error_strings();
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ if (ctx == NULL) {
+ ERR_print_errors_fp(stdout);
+ return -1;
+ }
+
+ if(!ingnore_cert)
+ {
+ // 双向验证
+ // SSL_VERIFY_PEER---要求对证书进行认证,没有证书也会放行
+ // SSL_VERIFY_FAIL_IF_NO_PEER_CERT---要求客户端需要提供证书,但验证发现单独使用没有证书也会放行
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
+ // 设置信任根证书
+ if (SSL_CTX_load_verify_locations(ctx, "/ca.crt",NULL)<=0){
+ ERR_print_errors_fp(stdout);
+ printf("fail SSL_CTX_load_verify_locations()\n");
+ return -1;
+ }
+
+ /* 载入用户的数字证书, 此证书用来发送给客户端。 证书里包含有公钥 */
+ if (SSL_CTX_use_certificate_file(ctx, DFL_CRT_FILE, SSL_FILETYPE_PEM) <= 0) {
+ ERR_print_errors_fp(stdout);
+ printf("fail SSL_CTX_use_certificate_file()\n");
+ return -1;
+ }
+ /* 载入用户私钥 */
+ if (SSL_CTX_use_PrivateKey_file(ctx, DFL_KEY_FILE, SSL_FILETYPE_PEM) <= 0) {
+ ERR_print_errors_fp(stdout);
+ printf("fail SSL_CTX_use_PrivateKey_file()\n");
+ return -1;
+ }
+ /* 检查用户私钥是否正确 */
+ if (!SSL_CTX_check_private_key(ctx)) {
+ ERR_print_errors_fp(stdout);
+ printf("fail SSL_CTX_check_private_key()\n");
+ return -1;
+ }
+
+ }
+
+ /* 基于 ctx 产生一个新的 SSL */
+ ssl = SSL_new(ctx);
+ SSL_set_fd(ssl, fd);
+ /* 建立 SSL 连接 */
+ if (SSL_connect(ssl) == -1)
+ ERR_print_errors_fp(stderr);
+ else {
+ printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
+ if(!ingnore_cert)
+ {
+ ShowCerts(ssl);
+ }
+ }
+
+ inter_info->ctx = &ctx;
+
+ inter_info->ssl = &ssl;
+
+ return 0;
+}
+
+static int mbtk_openssl_close(mbtk_sock_inter_info_s *inter_info)
+{
+ SSL_shutdown(inter_info->ssl);
+ SSL_free(inter_info->ssl);
+// close(sockfd);
+ SSL_CTX_free(inter_info->ctx);
+ return 0;
+}
+
+static int mbtk_openssl_write( SSL *ssl, const unsigned char *buf, size_t len )
+{
+ return SSL_write(ssl, buf, len);
+}
+
+static int mbtk_openssl_read( SSL *ssl, unsigned char *buf, size_t len )
+{
+ return SSL_read(ssl, buf, len);
+}
+
+#endif
+
+extern mbtk_sock_session mbtk_sock_open(mbtk_sock_handle handle,mbtk_sock_info *info,
+ unsigned int timeout,
+ int *mbtk_errno)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ *mbtk_errno = MBTK_SOCK_ERROR;
+ if(info == NULL) {
+ LOGE("mbtk_sock_info not be NULL.");
+ return -1;
+ }
+
+ int index_free = sock_find_first_free(mbtk_sock[handle]->inter_infos);
+ if(index_free < 0) {
+ LOGE("sock_find_first_free() fail.");
+ return -1;
+ }
+
+ memcpy(&(mbtk_sock[handle]->infos[index_free]),info,sizeof(mbtk_sock_info));
+ if(info->type == MBTK_SOCK_UDP) { // UDP
+ if((mbtk_sock[handle]->inter_infos[index_free].fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0){
+ LOGE("socket() fail.[%d]",errno);
+ goto result_fail;
+ }
+ } else { // TCP
+ if((mbtk_sock[handle]->inter_infos[index_free].fd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
+ LOGE("socket() fail.[%d]",errno);
+ goto result_fail;
+ }
+ }
+ // Set O_NONBLOCK
+ int flags = fcntl(mbtk_sock[handle]->inter_infos[index_free].fd, F_GETFL, 0);
+ if (flags < 0) {
+ LOGE("Get flags error:%s\n", strerror(errno));
+ goto result_fail_with_close;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(mbtk_sock[handle]->inter_infos[index_free].fd, F_SETFL, flags) < 0) {
+ LOGE("Set flags error:%s\n", strerror(errno));
+ goto result_fail_with_close;
+ }
+
+ // Connect
+ LOGD("Start conn:%s:%d",info->address,info->port);
+ if(strlen(info->address) > 0 && info->port > 0) {
+ if(strlen(info->local_address) > 0 || info->local_port > 0) {
+ // 指定本地IP和端口,不指定内核会自动指定(一般不指定)
+ struct sockaddr_in loc_addr;
+ memset(&loc_addr, 0, sizeof(struct sockaddr_in));
+ loc_addr.sin_family = AF_INET;
+
+ // 指定IP
+ if(strlen(info->local_address) > 0) {
+ if(inet_pton(AF_INET, info->local_address, &loc_addr.sin_addr) < 0) {
+ LOGE("inet_pton() error:%d", errno);
+ goto result_fail_with_close;
+ }
+ }
+
+ if(info->local_port > 0) {
+ loc_addr.sin_port = htons(info->local_port);
+ }
+ if(bind(mbtk_sock[handle]->inter_infos[index_free].fd, (struct sockaddr *)&loc_addr, sizeof(loc_addr)) < 0) {
+ LOGE("bind() error:%d", errno);
+ if(errno == EADDRINUSE) { // 地址已在使用
+ LOGE("EADDRINUSE : Local port already occupied.");
+ }
+ goto result_fail_with_close;
+ } else {
+ LOGD("Bind ip/port success.");
+ }
+ }
+
+ struct sockaddr_in servaddr;
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(info->port);
+
+ struct hostent *he = gethostbyname(info->address);
+ if (he == NULL){
+ LOGE("gethostbyname() fail.[%d]",errno);
+ goto result_fail_with_close;
+ } else {
+ LOGD("Ip : %s",he->h_addr_list[0]);
+ }
+ memcpy(&servaddr.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
+
+ if(connect(mbtk_sock[handle]->inter_infos[index_free].fd, (SA *) &servaddr, sizeof(servaddr)) < 0){
+ if(EINPROGRESS != errno){
+ LOGE("connect() fail.[%d]",errno);
+ goto result_fail_with_close;
+ }
+ }
+
+ fd_set rset, wset;
+ FD_ZERO(&rset);
+ FD_ZERO(&wset);
+ FD_SET(mbtk_sock[handle]->inter_infos[index_free].fd, &rset);
+ FD_SET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset);
+ struct timeval time_out;
+ time_out.tv_sec = timeout/1000;
+ time_out.tv_usec = timeout%1000*1000;
+ int nready = select(mbtk_sock[handle]->inter_infos[index_free].fd + 1,
+ &rset, &wset, NULL, &time_out);
+ LOGD("nready = %d",nready);
+ if(nready == 0){// Timeout
+ LOGE("Timeout.");
+ printf("Timeout.\n");
+ goto result_fail_with_close;
+ }else{
+ if (FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &rset)
+ && FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset)) {
+ int error = -1;
+ int len = sizeof(int);
+ LOGE("Can read and write.");
+ if(getsockopt(mbtk_sock[handle]->inter_infos[index_free].fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0){
+ LOGE("getsockopt fail.[%d]",errno);
+ goto result_fail_with_close;
+ }else{
+ LOGE("error = %d",error);
+ if(error != 0){ // Fail
+ goto result_fail_with_close;
+ }
+ }
+ }else if(FD_ISSET(mbtk_sock[handle]->inter_infos[index_free].fd, &wset)){
+ LOGI("Can write.");
+ printf("Can write.\n");
+ }else{
+ LOGE("Can read(Impossible).");
+ goto result_fail_with_close;
+ }
+ }
+ } else {
+ LOGE("Can not conn.");
+ goto result_fail_with_close;
+ }
+
+ if(mbtk_sock[handle]->init_info.sock_cb) {
+ struct epoll_event ev;
+ ev.data.fd = mbtk_sock[handle]->inter_infos[index_free].fd;
+ ev.events = EPOLLIN | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,mbtk_sock[handle]->inter_infos[index_free].fd,&ev);
+ }
+#if 1
+ if(info->ftp_ssl_support)
+ {
+ if(info->is_support_ssl){
+ mbtk_sock[handle]->infos[index_free].is_support_ssl = 0;
+ unsigned char mbtk_ftp_ssl_read_buf_s[256];
+ int err_rw;
+ memset(mbtk_ftp_ssl_read_buf_s,0,sizeof(mbtk_ftp_ssl_read_buf_s));
+ mbtk_sock_read(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+ mbtk_ftp_ssl_read_buf_s,
+ sizeof(mbtk_ftp_ssl_read_buf_s),
+ 60000,
+ &err_rw);
+ printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf_s);
+
+ char cmd_buff[50];
+ int len=0,code;
+ memset(cmd_buff,0,sizeof(cmd_buff));
+
+ len = snprintf(cmd_buff, 50, "AUTH TLS\r\n");
+ cmd_buff[len] = '\0';
+ //printf("\n cmd_buff = %s\n", cmd_buff);
+
+ mbtk_sock_write(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+ cmd_buff,
+ strlen(cmd_buff),
+ 60000,
+ &err_rw);
+
+ memset(mbtk_ftp_ssl_read_buf_s,0,sizeof(mbtk_ftp_ssl_read_buf_s));
+ mbtk_sock_read(handle,mbtk_sock[handle]->inter_infos[index_free].fd,
+ mbtk_ftp_ssl_read_buf_s,
+ sizeof(mbtk_ftp_ssl_read_buf_s),
+ 60000,
+ &err_rw);
+ printf("\nmbtk_sock_read:\n%s\n",mbtk_ftp_ssl_read_buf_s);
+
+ mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
+ }else{
+ mbtk_sock[handle]->infos[index_free].is_support_ssl=1;
+ }
+ }
+#endif
+ if(info->is_support_ssl){
+#ifdef MBTK_POLARSSL_SUPPORT
+ if(mbtk_polarssl_open(mbtk_sock[handle]->inter_infos[index_free].fd,info->ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]) == -1){
+ LOGE("mbtk_openssl_init fail");
+ goto result_fail_with_close;
+ }
+#else
+ if(mbtk_openssl_open(mbtk_sock[handle]->inter_infos[index_free].fd,info->ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]) == -1){
+ LOGE("mbtk_openssl_init fail");
+ goto result_fail_with_close;
+ }
+
+
+#endif
+ }
+
+ *mbtk_errno = MBTK_SOCK_SUCCESS;
+
+ mbtk_sock[handle]->sock_num++;
+ return mbtk_sock[handle]->inter_infos[index_free].fd;
+result_fail_with_close:
+ close(mbtk_sock[handle]->inter_infos[index_free].fd);
+ mbtk_sock[handle]->inter_infos[index_free].fd = -1;
+result_fail:
+ memset(&(mbtk_sock[handle]->inter_infos[index_free]),0x0,sizeof(mbtk_sock_inter_info_s));
+ memset(&(mbtk_sock[handle]->infos[index_free]),0x0,sizeof(mbtk_sock_info));
+ LOGE("mbtk_sock_open() end:fail");
+ return -1;
+}
+extern int mbtk_ssl_init_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
+{
+ int i=0;
+ int index_free=0;
+
+ for (i=0;i<10;i++)
+ {
+ if(mbtk_sock[handle]->inter_infos[i].fd == fd)
+ {
+ index_free = i;
+ break;
+ }
+ }
+#ifdef MBTK_POLARSSL_SUPPORT
+ return mbtk_polarssl_open(mbtk_sock[handle]->inter_infos[index_free].fd,ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]);
+#else
+ return mbtk_openssl_open(mbtk_sock[handle]->inter_infos[index_free].fd,ingnore_cert,&mbtk_sock[handle]->inter_infos[index_free]);
+#endif
+}
+extern int mbtk_ssl_close_func(mbtk_sock_handle handle ,bool ingnore_cert,mbtk_sock_session fd)
+{
+ int i=0;
+ int index_free=0;
+
+ for (i=0;i<10;i++)
+ {
+ if(mbtk_sock[handle]->inter_infos[i].fd == fd)
+ {
+ index_free = i;
+ break;
+ }
+ }
+
+#ifdef MBTK_POLARSSL_SUPPORT
+ if(mbtk_sock[handle]->inter_infos[index_free].ssl!=NULL);
+ printf("\nmbtk_sock[handle]->inter_infos[index_free].ssl not empty\n");
+ return mbtk_polarssl_close(&mbtk_sock[handle]->inter_infos[index_free]);
+#else
+ if(mbtk_sock[handle]->inter_infos[index_free].ssl!=NULL);
+ printf("\nmbtk_sock[handle]->inter_infos[index_free].ssl not empty\n");
+ return mbtk_openssl_close(&mbtk_sock[handle]->inter_infos[index_free]);
+#endif
+}
+
+extern int mbtk_sock_write(mbtk_sock_handle handle,mbtk_sock_session session,
+ void *buffer,
+ unsigned int buf_len,
+ unsigned int timeout,
+ int *mbtk_errno)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ *mbtk_errno = MBTK_SOCK_ERROR;
+ if(buffer == NULL) {
+ LOGE("mbtk_sock_write() args error.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ int len = 0;
+ unsigned int count = 0;
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+ while(count < buf_len){
+ if(mbtk_sock[handle]->infos[index].is_support_ssl) {
+#ifdef MBTK_POLARSSL_SUPPORT
+ len = mbtk_polarssl_write(inter_info->ssl,(char*)buffer + count,buf_len - count);
+#else
+ len = mbtk_openssl_write(inter_info->ssl,(char*)buffer + count,buf_len - count);
+
+#endif
+ } else
+ len = write(inter_info->fd,(char*)buffer + count,buf_len - count);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ usleep(50000);
+ continue;
+ } else {
+ LOGE("write error.[%d]",errno);
+ if(count <= 0)
+ count = -1;
+ break;
+ }
+ } else if(len == 0) {
+ LOGE("write error(len == 0).[%d]",errno);
+ } else {
+ count += len;
+ }
+ }
+ } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP){
+ // Start send data
+ while(count < buf_len){
+ len = sendto(inter_info->fd,(char*)buffer + count,buf_len - count,0,NULL,0);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ usleep(50000);
+ continue;
+ } else {
+ LOGE("sendto error.[%d]",errno);
+ if(ECONNREFUSED == errno) { // Disconnected.
+ LOGD("Socket Disconnected.");
+ }
+ break;
+ }
+ } else if(len == 0) {
+ LOGD("write error(len == 0).[%d]",errno);
+ } else {
+ count += len;
+ }
+ }
+ } else {
+ LOGE("Socket type error.");
+ return -1;
+ }
+
+ if(count == buf_len){
+ LOGD("Write data[%d/%d] success.",count,buf_len);
+ } else { // Open session fail
+ LOGD("Write data[%d/%d] fail.",count,buf_len);
+ }
+
+ *mbtk_errno = MBTK_SOCK_SUCCESS;
+ return count;
+}
+
+extern int mbtk_sock_read(mbtk_sock_handle handle,mbtk_sock_session session,
+ void *buffer,
+ unsigned int buf_len,
+ unsigned int timeout,
+ int *mbtk_errno)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ *mbtk_errno = MBTK_SOCK_ERROR;
+ if(buffer == NULL) {
+ LOGE("mbtk_sock_write() args error.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ unsigned int count = 0;
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+ int len = 0;
+ int try_count = 0;
+ int times = timeout / 50;
+ memset(buffer,0x0,buf_len);
+ while(count < buf_len){
+ try_count++;
+ if(mbtk_sock[handle]->infos[index].is_support_ssl) {
+#ifdef MBTK_POLARSSL_SUPPORT
+ len = mbtk_polarssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+#else
+ len = mbtk_openssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+
+#endif
+ } else
+ len = read(inter_info->fd,(char*)buffer + count,buf_len - count);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ if(count > 0) // Read data
+ break; // Read data end.
+
+ if(try_count >= times){ // Timeout
+ count = -1;
+ if(times != 0) {
+ *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+ }
+ LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+ break;
+ } else {
+ usleep(50000);
+ continue;
+ }
+ } else {
+ LOGE("read error.[%d]",errno);
+ if(count <= 0)
+ count = -1;
+ break;
+ }
+ } else if(len == 0) {
+ LOGE("read error(len == 0).[%d]",errno);
+ if(errno == EINPROGRESS) {
+ if(close(inter_info->fd) == 0) {// Success
+ LOGD("Socket disconnected.Close it.");
+ }
+ if(count <= 0)
+ count = -1;
+ } else {
+ if(count <= 0)
+ count = 0;
+ }
+ break;
+ } else {
+ count += len;
+ }
+ }
+ } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+ // Start recv data
+ struct sockaddr_in seraddr;
+ socklen_t seraddr_len;
+ int try_count = 0;
+ int times = timeout / 50;
+ int len = 0;
+ memset(buffer,0x0,buf_len);
+ while(TRUE){
+ try_count++;
+ seraddr_len = sizeof(struct sockaddr_in);
+ len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){// No data can read.
+ if(count > 0) // Read data
+ break; // Read data end.
+
+ if(try_count >= times){ // Timeout
+ if(times == 0) {
+ LOGE("Can not read.");
+ } else {
+ LOGE("Timeout");
+ *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+ }
+ count = -1;
+ LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+ break;
+ } else {
+ usleep(50000);
+ continue;
+ }
+ } else {
+ LOGE("recvfrom error.[%d]",errno);
+ if(count <= 0)
+ count = -1;
+ break;
+ }
+ } else if(len == 0) {
+ LOGE("write error(len == 0).[%d]",errno);
+ if(count <= 0)
+ count = 0;
+ break;
+ } else {
+ count += len;
+ }
+ }
+ } else {
+ LOGE("Socket type error.");
+ return -1;
+ }
+
+// if(count == buf_len){
+// LOGD("Read data[%d/%d] success.",count,buf_len);
+// } else { // Open session fail
+// LOGD("Read data[%d/%d] fail.",count,buf_len);
+// }
+
+ LOGV("Read data[%d/%d].",count,buf_len);
+
+ *mbtk_errno = MBTK_SOCK_SUCCESS;
+ return count;
+}
+extern int mbtk_sock_readline(mbtk_sock_handle handle,mbtk_sock_session session,
+ void *buffer,
+ unsigned int buf_len,
+ unsigned int timeout,
+ int *mbtk_errno,
+ int *read_line_count,
+ char *buf_ptr)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ *mbtk_errno = MBTK_SOCK_ERROR;
+ if(buffer == NULL) {
+ LOGE("mbtk_sock_write() args error.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ unsigned int count = 0;
+ unsigned int read_count = 0;
+ memset(buf_ptr, 0, buf_len);
+ char *temp_ptr = (char *)buffer;
+copy_angin_ssl:
+ while(*read_line_count > 0 && *temp_ptr != '\n') {
+ if(*temp_ptr == NULL)
+ {
+ printf("\n*temp_ptr is null\n");
+ goto read_end;
+ }
+ *buf_ptr++ = *temp_ptr++;
+ (*read_line_count)--;
+ count++;
+ }
+ if(*read_line_count == 0)
+ {
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+ int len = 0;
+ int try_count = 0;
+ int times = timeout / 50;
+ memset(buffer,0x0,buf_len);
+ while(count < buf_len){
+ try_count++;
+ if(mbtk_sock[handle]->infos[index].is_support_ssl) {
+#ifdef MBTK_POLARSSL_SUPPORT
+ len = mbtk_polarssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+#else
+ len = mbtk_openssl_read(inter_info->ssl,(char*)buffer + count,buf_len - count);
+#endif
+ } else
+ len = read(inter_info->fd,(char*)buffer + count,buf_len - count);
+ *read_line_count = len;
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ if(count > 0) // Read data
+ {
+ *read_line_count = count;
+ count = 0;
+ goto copy_angin_ssl;
+ break; // Read data end.
+ }
+ else
+ {
+ //printf("\nread_end\n");
+ goto read_end;
+ }
+ if(try_count >= times){ // Timeout
+ count = -1;
+ if(times != 0) {
+ *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+ }
+ LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+ goto read_end;
+ break;
+ } else {
+ usleep(50000);
+ continue;
+ }
+ } else {
+ LOGE("read error.[%d]",errno);
+ if(count <= 0)
+ count = -1;
+ else {
+ *read_line_count = count;
+ }
+ break;
+ }
+ } else if(len == 0) {
+ LOGE("read error(len == 0).[%d]",errno);
+ if(errno == EINPROGRESS) {
+ if(close(inter_info->fd) == 0) {// Success
+ LOGD("Socket disconnected.Close it.");
+ }
+ if(count <= 0)
+ count = -1;
+ } else {
+ if(count <= 0)
+ count = 0;
+ else
+ count = -1;
+ }
+ goto read_end;
+ break;
+ } else {
+ count += len;
+ }
+ }
+ } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+ // Start recv data
+ struct sockaddr_in seraddr;
+ socklen_t seraddr_len;
+ int try_count = 0;
+ int times = timeout / 50;
+ int len = 0;
+ memset(buffer,0x0,buf_len);
+ while(TRUE){
+ try_count++;
+ seraddr_len = sizeof(struct sockaddr_in);
+ len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){// No data can read.
+ if(count > 0) // Read data
+ break; // Read data end.
+
+ if(try_count >= times){ // Timeout
+ if(times == 0) {
+ LOGE("Can not read.");
+ //printf("Can not read.\n");
+ } else {
+ LOGE("Timeout");
+ //printf("Timeout\n");
+ *mbtk_errno = MBTK_SOCK_ETIMEOUT;
+ }
+ count = -1;
+ LOGE("Not read enough data,return.[%d/%d]",count,buf_len);
+ //printf("Not read enough data,return.[%d/%d]\n",count,buf_len);
+ break;
+ } else {
+ usleep(50000);
+ continue;
+ }
+ } else {
+ LOGE("recvfrom error.[%d]",errno);
+ if(count <= 0)
+ count = -1;
+ break;
+ }
+ } else if(len == 0) {
+ LOGE("write error(len == 0).[%d]",errno);
+ if(count <= 0)
+ count = 0;
+ break;
+ } else {
+ count += len;
+ }
+ }
+ } else {
+ LOGE("Socket type error.");
+ //printf("Socket type error.\n");
+ return -1;
+ }
+ count = 0;
+ goto copy_angin_ssl;
+ } else if(*temp_ptr == '\n') { // Read line.
+ *buf_ptr++ = '\n';
+ (*read_line_count)--;
+ count++;
+
+ if(*read_line_count > 0)
+ memcpy(buffer, temp_ptr + 1, *read_line_count);
+ return count;
+ }
+ LOGV("Read data[%d/%d].",count,buf_len);
+read_end:
+ *mbtk_errno = MBTK_SOCK_SUCCESS;
+ return count;
+}
+
+extern int mbtk_sock_read_async(mbtk_sock_handle handle,mbtk_sock_session session,
+ void *buffer,
+ unsigned int buf_len)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ if(buffer == NULL) {
+ LOGE("mbtk_sock_write() args error.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ int len = 0;
+ int read_count = 0;
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+ memset(buffer,0x0,buf_len);
+ while(read_count < buf_len) {
+ if(mbtk_sock[handle]->infos[index].is_support_ssl) {
+#ifdef MBTK_POLARSSL_SUPPORT
+ len = ssl_read(inter_info->ssl,(char*)buffer + read_count,buf_len - read_count);
+#else
+ len = mbtk_openssl_read(inter_info->ssl,(char*)buffer + read_count,buf_len - read_count);
+
+#endif
+ } else
+ len = read(inter_info->fd,(char*)buffer + read_count,buf_len - read_count);
+
+ if(len > 0) {
+ read_count += len;
+ } else {
+ if(errno == EWOULDBLOCK) { // No data
+ break;
+ } else {
+ LOGE("Will retry : len = %d, errno = %d", len, errno);
+ }
+ }
+ }
+ } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+ // Start recv data
+ struct sockaddr_in seraddr;
+ socklen_t seraddr_len;
+ memset(buffer,0x0,buf_len);
+ seraddr_len = sizeof(struct sockaddr_in);
+ memset(buffer,0x0,buf_len);
+
+ while(read_count < buf_len) {
+ len = recvfrom(inter_info->fd,buffer + read_count,buf_len - read_count,0,&seraddr,&seraddr_len);
+
+ if(len > 0) {
+ read_count += len;
+ } else {
+ if(errno == EWOULDBLOCK) { // No data
+ break;
+ } else {
+ LOGE("Will retry : len = %d, errno = %d", len, errno);
+ }
+ }
+ }
+ } else {
+ LOGE("Socket type error.");
+ return -1;
+ }
+
+ LOGV("Read data[%d/%d].",read_count,buf_len);
+
+ return read_count;
+}
+
+extern int mbtk_sock_read_sync(mbtk_sock_handle handle,mbtk_sock_session session,
+ void *buffer,
+ unsigned int buf_len)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ if(buffer == NULL) {
+ LOGE("mbtk_sock_write() args error.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ int len;
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+TCP_READ_AGAIN:
+ memset(buffer,0x0,buf_len);
+ if(mbtk_sock[handle]->infos[index].is_support_ssl) {
+#ifdef MBTK_POLARSSL_SUPPORT
+ len = ssl_read(inter_info->ssl,(char*)buffer,buf_len);
+#else
+ len = mbtk_openssl_read(inter_info->ssl,(char*)buffer,buf_len);
+
+#endif
+ } else
+ len = read(inter_info->fd,(char*)buffer,buf_len);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ usleep(100000);
+ LOGW("Read retry...");
+ goto TCP_READ_AGAIN;
+ } else {
+ LOGE("read error.[%d]",errno);
+ return -1;
+ }
+ }
+ } else if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_UDP) {
+ // Start recv data
+ struct sockaddr_in seraddr;
+ socklen_t seraddr_len;
+UDP_READ_AGAIN:
+ memset(buffer,0x0,buf_len);
+ seraddr_len = sizeof(struct sockaddr_in);
+ len = recvfrom(inter_info->fd,buffer,buf_len,0,&seraddr,&seraddr_len);
+ if(len < 0){
+ if(errno == EWOULDBLOCK){
+ usleep(100000);
+ goto UDP_READ_AGAIN;
+ } else {
+ LOGE("read error.[%d]",errno);
+ return -1;
+ }
+ }
+ } else {
+ LOGE("Socket type error.");
+ return -1;
+ }
+
+ LOGV("Read data[%d/%d].",len,buf_len);
+
+ return len;
+}
+
+
+extern int mbtk_sock_close(mbtk_sock_handle handle,mbtk_sock_session session,
+ unsigned int timeout,
+ int *mbtk_errno)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ *mbtk_errno = MBTK_SOCK_ERROR;
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session == mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ int i;
+ for(i = 0;i < MBTK_SOCK_MAX_NUM;i++) {
+ if(mbtk_sock[handle]->inter_infos[i].fd == inter_info->fd){
+ if(mbtk_sock[handle]->init_info.sock_cb) {
+ struct epoll_event ev;
+ ev.data.fd = inter_info->fd;
+ ev.events = EPOLLIN | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_DEL,inter_info->fd,&ev);
+ }
+
+ if(close(inter_info->fd) < 0) {// Success
+ LOGE("Close socket fail[%d].",errno);
+ //break;
+ }
+ mbtk_sock[handle]->inter_infos[i].fd = -1;
+ memset(&(mbtk_sock[handle]->infos[i]),0x0,sizeof(mbtk_sock_info));
+ mbtk_sock[handle]->sock_num--;
+ break;
+ }
+ }
+
+ if(mbtk_sock[handle]->infos[index].is_support_ssl){
+#ifdef MBTK_POLARSSL_SUPPORT
+ if(mbtk_polarssl_close(inter_info)== -1)
+ {
+ LOGE("close ssl fail");
+ return -1;
+ }
+#else
+ if(mbtk_openssl_close(inter_info)== -1)
+ {
+ LOGE("close ssl fail");
+ return -1;
+ }
+
+#endif
+ }
+
+ *mbtk_errno = MBTK_SOCK_SUCCESS;
+ return 0;
+}
+
+extern int mbtk_sock_deinit(mbtk_sock_handle handle)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ if(mbtk_sock[handle]->sock_num > 0) {
+ LOGE("There are socket not close.");
+ return MBTK_SOCK_ERROR;
+ }
+
+ LOGD("mbtk_sock_deinit() start.");
+#if 0
+ sock_thread_running = FALSE;
+ write(pipe_fds[0],"0",1);
+
+ // Wait for thread exist.
+ while(sock_inited) {
+ usleep(100);
+ }
+#endif
+
+ int i;
+ for(i = 0;i < MBTK_SOCK_MAX_NUM;i++) {
+ if(mbtk_sock[handle]->inter_infos[i].fd > 0){
+ if(mbtk_sock[handle]->init_info.sock_cb) {
+ struct epoll_event ev;
+ ev.data.fd = mbtk_sock[handle]->inter_infos[i].fd;
+ ev.events = EPOLLIN | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_DEL,mbtk_sock[handle]->inter_infos[i].fd,&ev);
+ }
+
+ if(close(mbtk_sock[handle]->inter_infos[i].fd) < 0) {// Success
+ LOGE("Close socket fail[%d].",errno);
+ //break;
+ }
+ mbtk_sock[handle]->inter_infos[i].fd = -1;
+ memset(&(mbtk_sock[handle]->infos[i]),0x0,sizeof(mbtk_sock_info));
+ break;
+ }
+ }
+
+ //memset(&mbtk_sock,0x0,sizeof(mbtk_sock_s));
+ free(mbtk_sock[handle]);
+ mbtk_sock[handle] = NULL;
+ LOGD("mbtk_sock_deinit() end.");
+ return MBTK_SOCK_SUCCESS;
+}
+
+/*
+* Get TCP RECV buffer data length.
+*/
+int mbtk_sock_tcp_recv_len_get(mbtk_sock_handle handle,mbtk_sock_session session)
+{
+ if(handle < 0 || handle >= MBTK_HANDLE_MAX_NUM
+ || session < 0 || mbtk_sock[handle] == NULL) {
+ LOGE("Socket not inited.");
+ return -1;
+ }
+
+ mbtk_sock_inter_info_s *inter_info = NULL;
+ int index = 0;
+ while(index < MBTK_SOCK_MAX_NUM) {
+ if(session ==
+ mbtk_sock[handle]->inter_infos[index].fd) {
+ inter_info = &(mbtk_sock[handle]->inter_infos[index]);
+ break;
+ }
+ index++;
+ }
+ if(!sock_info_check(handle,inter_info)) {
+ LOGE("sock_info_check() fail.");
+ return -1;
+ }
+
+ index = sock_info_find_by_fd(handle,inter_info->fd);
+ if(index < 0) {
+ LOGE("No such socket in session list.");
+ return -1;
+ }
+
+ unsigned int count = 0;
+ int len = 0;
+ if(mbtk_sock[handle]->infos[index].type == MBTK_SOCK_TCP) {
+ if(ioctl(inter_info->fd, FIONREAD, &len))
+ {
+ LOGE("Get ioctl FIONREAD fail:%d", errno);
+ return -1;
+ }
+ } else {
+ LOGE("Only surrport for TCP.");
+ return -1;
+ }
+
+ return len;
+}
+
+void mbtk_net_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_net_lib");
+}
+
+
diff --git a/mbtk/libmbtk_lib/net/mbtk_sock_internal.h b/mbtk/libmbtk_lib/net/mbtk_sock_internal.h
new file mode 100755
index 0000000..de822bc
--- /dev/null
+++ b/mbtk/libmbtk_lib/net/mbtk_sock_internal.h
@@ -0,0 +1,64 @@
+#ifndef MBTK_SOCK_INTERNAL_INCLUDE
+#define MBTK_SOCK_INTERNAL_INCLUDE
+#include "mbtk_sock2.h"
+//#include <openssl/ssl.h>
+
+#define MBTK_HANDLE_MAX_NUM 5
+#define MBTK_SOCK_MAX_NUM 10
+
+typedef struct {
+ int fd;
+ mbtk_sock_type type; // socket type:TCP or UDP
+#ifdef MBTK_POLARSSL_SUPPORT
+ entropy_context* entropy;
+ ctr_drbg_context* ctr_drbg;
+ ssl_context *ssl;
+ ssl_session *saved_session;
+ x509_crt *cacert;
+ x509_crt *clicert;
+ pk_context* pkey;
+#else
+ SSL_CTX *ctx;
+ SSL *ssl;
+#endif
+} mbtk_sock_inter_info_s;
+
+typedef struct {
+ mbtk_init_info init_info;
+ int sock_num;
+ mbtk_sock_inter_info_s inter_infos[MBTK_SOCK_MAX_NUM];
+ mbtk_sock_info infos[MBTK_SOCK_MAX_NUM];
+} mbtk_sock_s;
+struct options
+{
+ const char *server_name; /* hostname of the server (client only) */
+ const char *server_addr; /* address of the server (client only) */
+ int server_port; /* port on which the ssl service runs */
+ int debug_level; /* level of debugging */
+ int nbio; /* should I/O be blocking? */
+ const char *request_page; /* page on server to request */
+ int request_size; /* pad request with header to requested size */
+ const char *ca_file; /* the file with the CA certificate(s) */
+ const char *ca_path; /* the path with the CA certificate(s) reside */
+ const char *crt_file; /* the file with the client certificate */
+ const char *key_file; /* the file with the client key */
+ const char *psk; /* the pre-shared key */
+ const char *psk_identity; /* the pre-shared key identity */
+ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */
+ int renegotiation; /* enable / disable renegotiation */
+ int allow_legacy; /* allow legacy renegotiation */
+ int renegotiate; /* attempt renegotiation? */
+ int renego_delay; /* delay before enforcing renegotiation */
+ int exchanges; /* number of data exchanges */
+ int min_version; /* minimum protocol version accepted */
+ int max_version; /* maximum protocol version accepted */
+ int auth_mode; /* verify mode for connection */
+ unsigned char mfl_code; /* code for maximum fragment length */
+ int trunc_hmac; /* negotiate truncated hmac or not */
+ int reconnect; /* attempt to resume session */
+ int reco_delay; /* delay in seconds before resuming session */
+ int tickets; /* enable / disable session tickets */
+ const char *alpn_string; /* ALPN supported protocols */
+} opt;
+
+#endif /* MBTK_SOCK_INTERNAL_INCLUDE */
diff --git a/mbtk/libmbtk_lib/ril/Makefile b/mbtk/libmbtk_lib/ril/Makefile
new file mode 100755
index 0000000..d9cb233
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/Makefile
@@ -0,0 +1,36 @@
+BUILD_ROOT = $(shell pwd)/..
+include $(BUILD_ROOT)/Make.defines
+
+LOCAL_PATH=$(BUILD_ROOT)/libmbtk_ril
+
+INC_DIR +=
+
+LIB_DIR +=
+
+LIBS += -llog -lmbtk_lib -lmbtk_net
+
+CFLAGS += -shared -Wl,-shared,-Bsymbolic
+
+LOCAL_SRC_FILES = $(wildcard *.cpp) $(wildcard *.c)
+OBJS = $(patsubst %.c, %.o, $(LOCAL_SRC_FILES))
+$(info OBJS = $(OBJS))
+
+OBJS = $(patsubst %.c, %.o, $(patsubst %.cpp, %.o, $(LOCAL_SRC_FILES)))
+$(info OBJS = $(OBJS))
+
+dtarget := $(OUT_DIR)/lib/libmbtk_ril.so
+
+all: $(dtarget)
+
+$(dtarget):$(OBJS)
+ $(CC) $(CFLAGS) $(DEFINE) $(LIB_DIR) $(LIBS) $(OBJS) -o $@
+
+%.o:%.c
+ $(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+%.o:%.cpp
+ $(CC) $(CFLAGS) $(INC_DIR) $(DEFINE) -c $< -o $@
+
+clean:
+ rm -f $(OBJS) $(dtarget)
+
diff --git a/mbtk/libmbtk_lib/ril/mbtk_alphabet.h b/mbtk/libmbtk_lib/ril/mbtk_alphabet.h
new file mode 100755
index 0000000..1ffece7
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/mbtk_alphabet.h
@@ -0,0 +1,140 @@
+//
+// Created by hitmoon on 15-12-10.
+//
+
+
+struct map_node {
+ unsigned short key;
+ unsigned short value;
+};
+
+
+#define map_size(map) (sizeof(map) / sizeof(struct map_node))
+
+
+// Unicode编码到GSM编码转换
+struct map_node UCS2ToBIT7[] = {
+ {0x000C, 0x1B0A},
+ {0x0024, 0x0002},
+ {0x0040, 0x0000},
+ {0x005B, 0x1B3C},
+ {0x005C, 0x1B2F},
+ {0x005D, 0x1B3E},
+ {0x005E, 0x1B14},
+ {0x005F, 0x0011},
+ {0x007B, 0x1B28},
+ {0x007C, 0x1B40},
+ {0x007D, 0x1B29},
+ {0x007E, 0x1B3D},
+ {0x00A0, 0x001B},
+ {0x00A1, 0x0040},
+ {0x00A3, 0x0001},
+ {0x00A4, 0x0024},
+ {0x00A5, 0x0003},
+ {0x00A7, 0x005F},
+ {0x00BF, 0x0060},
+ {0x00C4, 0x005B},
+ {0x00C5, 0x000E},
+ {0x00C6, 0x001C},
+ {0x00C9, 0x001F},
+ {0x00D1, 0x005D},
+ {0x00D6, 0x005C},
+ {0x00D8, 0x000B},
+ {0x00DC, 0x005E},
+ {0x00DF, 0x001E},
+ {0x00E0, 0x007F},
+ {0x00E4, 0x007B},
+ {0x00E5, 0x000F},
+ {0x00E6, 0x001D},
+ {0x00E7, 0x0009},
+ {0x00E8, 0x0004},
+ {0x00E9, 0x0005},
+ {0x00EC, 0x0007},
+ {0x00F1, 0x007D},
+ {0x00F2, 0x0008},
+ {0x00F6, 0x007C},
+ {0x00F8, 0x000C},
+ {0x00F9, 0x0006},
+ {0x00FC, 0x007E},
+ {0x0393, 0x0013},
+ {0x0394, 0x0010},
+ {0x0398, 0x0019},
+ {0x039B, 0x0014},
+ {0x039E, 0x001A},
+ {0x03A0, 0x0016},
+ {0x03A3, 0x0018},
+ {0x03A6, 0x0012},
+ {0x03A8, 0x0017},
+ {0x03A9, 0x0015},
+ {0x20AC, 0x1B65}
+};
+
+// GSM编码到Unicode编码转换
+struct map_node BIT7ToUCS2[] = {
+ {0x0000, 0x0040},
+ {0x0001, 0x00A3},
+ {0x0002, 0x0024},
+ {0x0003, 0x00A5},
+ {0x0004, 0x00E8},
+ {0x0005, 0x00E9},
+ {0x0006, 0x00F9},
+ {0x0007, 0x00EC},
+ {0x0008, 0x00F2},
+ {0x0009, 0x00E7},
+ {0x000B, 0x00D8},
+ {0x000C, 0x00F8},
+ {0x000E, 0x00C5},
+ {0x000F, 0x00E5},
+ {0x0010, 0x0394},
+ {0x0011, 0x005F},
+ {0x0012, 0x03A6},
+ {0x0013, 0x0393},
+ {0x0014, 0x039B},
+ {0x0015, 0x03A9},
+ {0x0016, 0x03A0},
+ {0x0017, 0x03A8},
+ {0x0018, 0x03A3},
+ {0x0019, 0x0398},
+ {0x001A, 0x039E},
+ {0x001B, 0x00A0},
+ {0x001C, 0x00C6},
+ {0x001D, 0x00E6},
+ {0x001E, 0x00DF},
+ {0x001F, 0x00C9},
+ {0x0024, 0x00A4},
+ {0x0040, 0x00A1},
+ {0x005B, 0x00C4},
+ {0x005C, 0x00D6},
+ {0x005D, 0x00D1},
+ {0x005E, 0x00DC},
+ {0x005F, 0x00A7},
+ {0x0060, 0x00BF},
+ {0x007B, 0x00E4},
+ {0x007C, 0x00F6},
+ {0x007D, 0x00F1},
+ {0x007E, 0x00FC},
+ {0x007F, 0x00E0}
+};
+// GSM编码转义序列到Unicode编码转换
+struct map_node BIT7EToUCS2[] = {
+ {0x000A, 0x000C},
+ {0x0014, 0x005E},
+ {0x0028, 0x007B},
+ {0x0029, 0x007D},
+ {0x002F, 0x005C},
+ {0x003C, 0x005B},
+ {0x003D, 0x007E},
+ {0x003E, 0x005D},
+ {0x0040, 0x007C},
+ {0x0065, 0x20AC}
+};
+
+// map 中查询键值
+int32_t map_get_value(struct map_node *map, unsigned int size, unsigned short key) {
+ int i = 0;
+ for (i = 0; i < size; i++) {
+ if (map[i].key == key)
+ return map[i].value;
+ }
+ return -1;
+}
diff --git a/mbtk/libmbtk_lib/ril/mbtk_info.c b/mbtk/libmbtk_lib/ril/mbtk_info.c
new file mode 100755
index 0000000..b61a3b0
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/mbtk_info.c
@@ -0,0 +1,1099 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "mbtk_info.h"
+#include "mbtk_list.h"
+#include "mbtk_utils.h"
+
+static int sock_read(int fd, uint8 *msg, int data_len)
+{
+ memset(msg, 0, data_len);
+ int len = 0;
+ int read_len = 0;
+ while(1)
+ {
+ len = read(fd, msg + read_len, data_len - read_len);
+ if(len > 0)
+ {
+ read_len += len;
+ }
+ else if(len == 0)
+ {
+ LOG("read() end.");
+ break;
+ }
+ else
+ {
+ if(EAGAIN == errno)
+ {
+ LOG("Read end, lenght = %d", read_len);
+ }
+ else
+ {
+ LOG("read() error[%d].", errno);
+ }
+ break;
+ }
+ }
+
+ if(read_len > 0)
+ {
+ log_hex("DATA_RECV", msg, read_len);
+ return read_len;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static int sock_write(int fd, uint8 *msg, int data_len)
+{
+ int len = 0;
+ int write_len = 0;
+ while(write_len < data_len)
+ {
+ len = write(fd, msg + write_len, data_len - write_len);
+ if(len > 0)
+ {
+ write_len += len;
+ }
+ else if(len == 0)
+ {
+ LOG("write() end.");
+ break;
+ }
+ else
+ {
+ LOG("write() error[%d].", errno);
+ break;
+ }
+ }
+
+ if(write_len > 0)
+ {
+ log_hex("DATA_SEND", msg, write_len);
+ return write_len;
+ }
+ else
+ {
+ return -1;
+ }
+}
+
+static int pack_num_check(const void* data, int data_len)
+{
+ int count = 0;
+ int pack_len;
+ const uint8* ptr = (const uint8*)data;
+ while(ptr < (const uint8*)data + data_len)
+ {
+ if(MBTK_INFO_PACKET_FLAG != byte_2_uint32(ptr, true))
+ {
+ LOG("pack_num_check() - TAG error.");
+ break;
+ }
+ ptr += sizeof(uint32);
+
+ pack_len = byte_2_uint16(ptr, false);
+ if(pack_len < SOCK_PACK_LEN_MIN - SOCK_PACK_EXTRA_LEN)
+ {
+ LOG("pack_num_check() - Packet length error.");
+ break;
+ }
+ ptr += sizeof(uint16);
+ ptr += pack_len;
+
+ count++;
+ }
+
+ return count;
+}
+
+char* type2str(mbtk_info_type_enum type)
+{
+ switch(type)
+ {
+ case MBTK_INFO_TYPE_REQ:
+ return "REQ";
+ case MBTK_INFO_TYPE_RSP:
+ return "RSP";
+ case MBTK_INFO_TYPE_IND:
+ return "IND";
+ default:
+ {
+ return "UNKNOWN";
+ }
+ }
+}
+
+char* apn2str(mbtk_ip_type_enum type)
+{
+ switch(type)
+ {
+ case MBTK_IP_TYPE_IP:
+ return "IP";
+ case MBTK_IP_TYPE_IPV6:
+ return "IPV6";
+ case MBTK_IP_TYPE_IPV4V6:
+ return "IPV4V6";
+ case MBTK_IP_TYPE_PPP:
+ return "PPP";
+ default:
+ {
+ return "UNKNOWN";
+ }
+ }
+}
+
+/*
+IPv6 : 254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239 -> uint128
+*/
+int str_2_ipv6(const void *ip_str, void *ipv6)
+{
+ const uint8 *ptr = (const uint8*)ip_str;
+ uint8 *ipv6_ptr = (uint8*)ipv6;
+ ipv6_ptr[0] = (uint8)atoi(ptr);
+ int i = 1;
+ while(i < 16) {
+ ptr = (const uint8*)strstr(ptr, ".");
+ if(ptr == NULL)
+ return -1;
+ ptr++;
+ ipv6_ptr[i] = (uint8)atoi(ptr);
+ i++;
+ }
+
+ return 0;
+}
+
+/*
+IPv6 : uint128 -> fe80::215:1dff:fe81:484c
+*/
+int ipv6_2_str(const void *ipv6, void *ipv6_str)
+{
+ const uint8 *ptr = (const uint8*)ipv6;
+ uint8 *ipv6_ptr = (uint8*)ipv6_str;
+ int i = 0;
+ int index = 0;
+ while(i < 16) {
+ index += sprintf(ipv6_ptr + index, "%02x%02x", ptr[i], ptr[i + 1]);
+ index += sprintf(ipv6_ptr + index, ":");
+ i += 2;
+ }
+
+ ipv6_ptr[index - 1] = '\0'; // Delete last ':'
+
+ return 0;
+}
+
+
+
+char* id2str(int id)
+{
+ switch(id)
+ {
+ // <string> IMEI
+ case MBTK_INFO_ID_DEV_IMEI_REQ:
+ case MBTK_INFO_ID_DEV_IMEI_RSP:
+ return "IMEI";
+ // <string> SN
+ case MBTK_INFO_ID_DEV_SN_REQ:
+ case MBTK_INFO_ID_DEV_SN_RSP:
+ return "SN";
+ // <string> MEID
+ case MBTK_INFO_ID_DEV_MEID_REQ:
+ case MBTK_INFO_ID_DEV_MEID_RSP:
+ return "MEID";
+ // <string> VERSION
+ case MBTK_INFO_ID_DEV_VERSION_REQ:
+ case MBTK_INFO_ID_DEV_VERSION_RSP:
+ return "VERSION";
+ case MBTK_INFO_ID_DEV_MODEL_REQ:
+ case MBTK_INFO_ID_DEV_MODEL_RSP:
+ return "MODEL";
+ // <uint8> 0:Close 1:Open
+ case MBTK_INFO_ID_DEV_VOLTE_REQ:
+ case MBTK_INFO_ID_DEV_VOLTE_RSP:
+ return "VOLTE";
+ // <string> Temperature
+ case MBTK_INFO_ID_DEV_TEMP_REQ: // Temperature
+ case MBTK_INFO_ID_DEV_TEMP_RSP:
+ return "TEMPERATURE";
+ case MBTK_INFO_ID_DEV_CELL_TIME_REQ:
+ case MBTK_INFO_ID_DEV_CELL_TIME_RSP:
+ return "CELL_TIME";
+ case MBTK_INFO_ID_DEV_TIME_REQ: // Time
+ case MBTK_INFO_ID_DEV_TIME_RSP:
+ return "Time";
+ case MBTK_INFO_ID_DEV_MODEM_REQ:
+ case MBTK_INFO_ID_DEV_MODEM_RSP:
+ return "MODEM";
+
+ // Sim Information
+
+ // <uint8> 0:NOT_EXIST 1:READY ...
+ case MBTK_INFO_ID_SIM_STATE_REQ:
+ case MBTK_INFO_ID_SIM_STATE_RSP:
+ return "SIM_STATE";
+ // <string> PIN
+ case MBTK_INFO_ID_SIM_PIN_REQ:
+ case MBTK_INFO_ID_SIM_PIN_RSP:
+ return "SIM_PIN";
+ // <string> PUK
+ case MBTK_INFO_ID_SIM_PUK_REQ:
+ case MBTK_INFO_ID_SIM_PUK_RSP:
+ return "SIM_PUK";
+ // <string> IMSI
+ case MBTK_INFO_ID_SIM_IMSI_REQ:
+ case MBTK_INFO_ID_SIM_IMSI_RSP:
+ return "IMSI";
+ // <string> ICCID
+ case MBTK_INFO_ID_SIM_ICCID_REQ:
+ case MBTK_INFO_ID_SIM_ICCID_RSP:
+ return "ICCID";
+ // <string> Phone Number
+ case MBTK_INFO_ID_SIM_PN_REQ:
+ case MBTK_INFO_ID_SIM_PN_RSP:
+ return "PHONE_NUMBER";
+ // Network Information
+ // <uint8> 0:OFF 1:ON
+ case MBTK_INFO_ID_NET_RADIO_REQ:
+ case MBTK_INFO_ID_NET_RADIO_RSP:
+ return "RADIO_STATE";
+ case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+ return "NET_AVAILABLE";
+ case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+ return "NET_SEL_MODE";
+ case MBTK_INFO_ID_NET_BAND_REQ:
+ case MBTK_INFO_ID_NET_BAND_RSP:
+ return "NET_BNAD";
+ // <uint16>[4] rssi,rscp,rsrp,snr
+ case MBTK_INFO_ID_NET_SIGNAL_REQ:
+ case MBTK_INFO_ID_NET_SIGNAL_RSP:
+ return "SIGNAL";
+ case MBTK_INFO_ID_NET_REG_REQ:
+ case MBTK_INFO_ID_NET_REG_RSP:
+ return "NET_REG";
+ // <string> cmnet/ctnet/3gnet/...
+ case MBTK_INFO_ID_NET_APN_REQ:
+ case MBTK_INFO_ID_NET_APN_RSP:
+ return "APN";
+ case MBTK_INFO_ID_NET_QSER_APN_REQ:
+ case MBTK_INFO_ID_NET_QSER_APN_RSP:
+ return "QSER_APN";
+ // Lock net/cell/frequency
+ case MBTK_INFO_ID_NET_CELL_REQ:
+ case MBTK_INFO_ID_NET_CELL_RSP:
+ return "NET_CELL";
+ case MBTK_INFO_ID_NET_DATA_CALL_REQ:
+ case MBTK_INFO_ID_NET_DATA_CALL_RSP:
+ return "DATA_CALL";
+ //ims
+ case MBTK_INFO_ID_NET_IMS_REQ:
+ case MBTK_INFO_ID_NET_IMS_RSP:
+ return "IMS";
+ // Call Information
+ case MBTK_INFO_ID_CALL_STATE_REQ:
+ case MBTK_INFO_ID_CALL_STATE_RSP:
+ return "CALL_STATE";
+ // SMS Information
+ case MBTK_INFO_ID_SMS_STATE_REQ:
+ case MBTK_INFO_ID_SMS_STATE_RSP:
+ return "SMS_STATE";
+ // PhoneBook Information
+ case MBTK_INFO_ID_PB_STATE_REQ:
+ case MBTK_INFO_ID_PB_STATE_RSP:
+ return "PB_STATE";
+ //led
+ case MBTK_INFO_ID_LED_REQ:
+ case MBTK_INFO_ID_LED_RSP:
+ return "LED";
+ // IND Information
+ // <uint8> State
+ case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+ return "IND_NET_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+ return "IND_CALL_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+ return "IND_SMS_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+ return "IND_RADIO_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+ return "IND_SIM_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_PDP_STATE_CHANGE:
+ return "IND_PDP_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_SERVER_STATE_CHANGE:
+ return "IND_SERVER_STATE";
+ // <uint8> State
+ case MBTK_INFO_ID_IND_SIGNAL_STATE_CHANGE:
+ return "IND_SIGNAL_STATE";
+ default:
+ {
+ return "UNKNOWN";
+ }
+ }
+}
+
+char* err2str(mbtk_info_err_enum err)
+{
+ switch(err)
+ {
+ case MBTK_INFO_ERR_SUCCESS:
+ return "SUCCESS";
+ case MBTK_INFO_ERR_FORMAT:
+ return "ERR_FORMAT";
+ case MBTK_INFO_ERR_REQ_UNKNOWN:
+ return "ERR_REQ_UNKNOWN";
+ case MBTK_INFO_ERR_REQ_PARAMETER:
+ return "ERR_REQ_PARAMETER";
+ case MBTK_INFO_ERR_UNSUPPORTED:
+ return "ERR_UNSUPPORTED";
+ case MBTK_INFO_ERR_MEMORY:
+ return "ERR_MEMORY";
+ case MBTK_INFO_ERR_IND_FULL:
+ return "ERR_IND_FULL";
+ case MBTK_INFO_ERR_IND_UNKNOWN:
+ return "ERR_IND_UNKNOWN";
+ case MBTK_INFO_ERR_CID_EXIST:
+ return "ERR_CID_EXIS";
+ case MBTK_INFO_ERR_CID_NO_EXIST:
+ return "ERR_CID_NO_EXIST";
+ case MBTK_INFO_ERR_NET_NO_INIT:
+ return "ERR_CID_NO_NET";
+ default:
+ {
+ if(err >= MBTK_INFO_ERR_CME) {
+ return "CME ERROR";
+ }
+
+ return "UNKNOWN";
+ }
+ }
+}
+
+/*
+0 GSM
+1 GSM_COMPACT
+2 UTRAN
+3 GSM_EGPRS
+4 UTRAN_HSDPA
+5 UTRAN_HSUPA
+6 UTRAN_HSDPA_HSUPA
+7 EUTRAN
+8 ECGSM
+*/
+mbtk_net_type_enum mbtk_net_type_get(mbtk_radio_technology_enum radio_tech)
+{
+ switch(radio_tech)
+ {
+ case MBTK_RADIO_TECH_GSM:
+ case MBTK_RADIO_TECH_GSM_COMPACT:
+ case MBTK_RADIO_TECH_GSM_EGPRS:
+ case MBTK_RADIO_TECH_UTRAN_HSPA:
+ {
+ return MBTK_NET_TYPE_GSM;
+ }
+ case MBTK_RADIO_TECH_UTRAN:
+ case MBTK_RADIO_TECH_UTRAN_HSDPA:
+ case MBTK_RADIO_TECH_UTRAN_HSUPA:
+ case MBTK_RADIO_TECH_UTRAN_HSDPA_HSUPA:
+ {
+ return MBTK_NET_TYPE_UMTS;
+ }
+ case MBTK_RADIO_TECH_E_UTRAN:
+ {
+ return MBTK_NET_TYPE_LTE;
+ }
+ default:
+ {
+ return MBTK_NET_TYPE_UNKNOWN;
+ }
+ }
+}
+
+
+#if 0
+void net_list_free(void *data)
+{
+ if (data)
+ {
+ mbtk_net_info_t *info = (mbtk_net_info_t*) data;
+ LOG("Free net [%s].", info->plmn);
+ free(info);
+ }
+}
+#endif
+
+mbtk_info_type_enum mbtk_info_type_get(int info_id)
+{
+ if(info_id > MBTK_INFO_ID_IND_BEGIN && info_id < MBTK_INFO_ID_IND_END)
+ {
+ return MBTK_INFO_TYPE_IND;
+ }
+ else if(info_id == MBTK_INFO_ID_DEV_BEGIN ||
+ info_id == MBTK_INFO_ID_DEV_END ||
+ info_id == MBTK_INFO_ID_SIM_BEGIN ||
+ info_id == MBTK_INFO_ID_SIM_END ||
+ info_id == MBTK_INFO_ID_NET_BEGIN ||
+ info_id == MBTK_INFO_ID_NET_END ||
+ info_id == MBTK_INFO_ID_CALL_BEGIN ||
+ info_id == MBTK_INFO_ID_CALL_END ||
+ info_id == MBTK_INFO_ID_SMS_BEGIN ||
+ info_id == MBTK_INFO_ID_SMS_END ||
+ info_id == MBTK_INFO_ID_PB_BEGIN ||
+ info_id == MBTK_INFO_ID_PB_END ||
+ info_id == MBTK_INFO_ID_LED_BEGIN ||
+ info_id == MBTK_INFO_ID_LED_END ||
+ info_id == MBTK_INFO_ID_WAKEUP_STA_BEGIN ||
+ info_id == MBTK_INFO_ID_WAKEUP_STA_END ||
+ info_id == MBTK_INFO_ID_OOS_STA_BEGIN ||
+ info_id == MBTK_INFO_ID_OOS_STA_END ||
+ info_id == MBTK_INFO_ID_REQ_UNKNOWN)
+ {
+ return MBTK_INFO_TYPE_UNKNOWN;
+ }
+ else if(info_id % 2 == 1)
+ {
+ return MBTK_INFO_TYPE_REQ;
+ }
+ else
+ {
+ return MBTK_INFO_TYPE_RSP;
+ }
+}
+
+mbtk_info_pack_t* mbtk_info_pack_creat(int info_id)
+{
+ mbtk_info_pack_t *pack = (mbtk_info_pack_t *)malloc(sizeof(mbtk_info_pack_t));
+ if(!pack)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+
+ pack->info_id = (uint16)info_id;
+ pack->info_err = (uint16)0;
+ pack->data_len = (uint16)0;
+ pack->data = NULL;
+
+ return pack;
+}
+
+#if 0
+int mbtk_info_pack_data_set(mbtk_info_pack_t *pack, const void *data, int data_len)
+{
+ if(!pack)
+ {
+ LOG("Packet is NULL.");
+ return -1;
+ }
+
+ mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+ // IND
+ if(info_type == MBTK_INFO_TYPE_IND)
+ {
+ switch(pack->info_id)
+ {
+ // <uint8> State
+ case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+ {
+ pack->data_len = (uint16)data_len;
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ default:
+ {
+ LOG("Unknown IND : %s", id2str(pack->info_id));
+ break;
+ }
+ }
+ }
+ //else if(pack->info_id % 2 == 1) // REQ (Set Data)
+ else if(info_type == MBTK_INFO_TYPE_REQ || info_type == MBTK_INFO_TYPE_RSP) // REQ or RSP
+ {
+ switch(pack->info_id)
+ {
+ case MBTK_INFO_ID_DEV_VOLTE_REQ: // <uint8> 0:Close 1:Open
+ case MBTK_INFO_ID_DEV_VOLTE_RSP:
+ case MBTK_INFO_ID_SIM_STATE_REQ: // <uint8> 0:NOT_EXIST 1:READY ...
+ case MBTK_INFO_ID_SIM_STATE_RSP:
+ case MBTK_INFO_ID_NET_RADIO_REQ: // <uint8> 0:OFF 1:ON
+ case MBTK_INFO_ID_NET_RADIO_RSP:
+ case MBTK_INFO_ID_NET_BAND_REQ: // mbtk_band_info_t
+ case MBTK_INFO_ID_NET_BAND_RSP:
+ case MBTK_INFO_ID_NET_CELL_REQ: // Lock net/cell/frequency
+ case MBTK_INFO_ID_NET_CELL_RSP:
+ case MBTK_INFO_ID_DEV_IMEI_REQ: // <string> SN
+ case MBTK_INFO_ID_DEV_IMEI_RSP:
+ case MBTK_INFO_ID_DEV_SN_REQ: // <string> SN
+ case MBTK_INFO_ID_DEV_SN_RSP:
+ case MBTK_INFO_ID_DEV_MEID_REQ: // <string> MEID
+ case MBTK_INFO_ID_DEV_MEID_RSP:
+ case MBTK_INFO_ID_DEV_VERSION_REQ: // <string> VERSION
+ case MBTK_INFO_ID_DEV_VERSION_RSP:
+ case MBTK_INFO_ID_DEV_TEMP_REQ: // <string> Temperature
+ case MBTK_INFO_ID_DEV_TEMP_RSP:
+ case MBTK_INFO_ID_SIM_PIN_REQ: // <string> PIN
+ case MBTK_INFO_ID_SIM_PIN_RSP:
+ case MBTK_INFO_ID_SIM_PUK_REQ: // <string> PUK
+ case MBTK_INFO_ID_SIM_PUK_RSP:
+ case MBTK_INFO_ID_SIM_IMSI_REQ: // <string> IMSI
+ case MBTK_INFO_ID_SIM_IMSI_RSP:
+ case MBTK_INFO_ID_SIM_ICCID_REQ: // <string> ICCID
+ case MBTK_INFO_ID_SIM_ICCID_RSP:
+ case MBTK_INFO_ID_NET_APN_REQ: // <string> cmnet/ctnet/3gnet/...
+ case MBTK_INFO_ID_NET_APN_RSP:
+ case MBTK_INFO_ID_NET_SEL_MODE_REQ: // mbtk_net_info_t
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+ case MBTK_INFO_ID_NET_AVAILABLE_REQ: // mbtk_net_info_t[]
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+ {
+ pack->data_len = (uint16)data_len;
+#if 1
+ pack->data = (uint8*)memdup(data, pack->data_len);
+#else
+ LOG("%d -> %d", data_len, pack->data_len);
+ log_hex("pack1", pack, sizeof(mbtk_info_pack_t));
+ #if 0
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ #else
+
+ LOG("1 pack->%p,data->%p", pack, pack->data);
+ pack->data = (uint8*)calloc(pack->data_len, sizeof(uint8));
+ LOG("2 pack->%p,data->%p", pack, pack->data);
+
+ memcpy(pack->data, data, data_len);
+ #endif
+
+ LOG("data_len - %d", pack->data_len);
+ log_hex("pack2", pack, sizeof(mbtk_info_pack_t));
+#endif
+ break;
+ }
+ case MBTK_INFO_ID_NET_SIGNAL_REQ: // <sint16>[4] rssi,rscp,rsrp,snr
+ case MBTK_INFO_ID_NET_SIGNAL_RSP:
+ {
+ // const mbtk_net_signal_t* signal = (const mbtk_net_signal_t*)data;
+ pack->data_len = (uint16)sizeof(mbtk_net_signal_t);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_NET_IPV4_DNS_REQ: // <uint32>[2] Preferred DNS,Alternate DNS
+ case MBTK_INFO_ID_NET_IPV4_DNS_RSP:
+ {
+ // const mbtk_net_dns_ipv4_t* dns_ipv4 = (const mbtk_net_dns_ipv4_t*)data;
+ pack->data_len = (uint16)sizeof(mbtk_net_dns_ipv4_t);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_NET_IPV6_DNS_REQ: // <uint32>[8] Preferred DNS,Alternate DNS
+ case MBTK_INFO_ID_NET_IPV6_DNS_RSP:
+ {
+ // const mbtk_net_dns_ipv6_t* dns_ipv6 = (const mbtk_net_dns_ipv6_t*)data;
+ pack->data_len = (uint16)sizeof(mbtk_net_dns_ipv6_t);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_NET_IPV4_REQ: // <uint32> IPv4
+ case MBTK_INFO_ID_NET_IPV4_RSP:
+ {
+ pack->data_len = (uint16)sizeof(uint32);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_NET_IPV6_REQ: // <uint32>[4] IPv6
+ case MBTK_INFO_ID_NET_IPV6_RSP:
+ {
+ pack->data_len = (uint16)(sizeof(uint32) * 4);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_NET_LOCAL_REQ: // <uint16>[2] tag,earfcn
+ case MBTK_INFO_ID_NET_LOCAL_RSP:
+ {
+ pack->data_len = (uint16)sizeof(mbtk_local_info_t);
+ pack->data = (uint8*)memdup(data, pack->data_len);
+ break;
+ }
+#if 0
+ case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)
+ {
+ const mbtk_net_info_t* net = (const mbtk_net_info_t*)data;
+ pack->data_len = sizeof(uint8) + sizeof(uint8) + sizeof(uint32);
+ pack->data = (uint8*)malloc(pack->data_len);
+ if(pack->data == NULL) {
+ LOG("malloc() fail.");
+ return -1;
+ }
+
+ pack->data[0] = net->net_sel_mode;
+ pack->data[1] = net->net_type;
+ uint32_2_byte((uint32)atoi((char*)net->plmn), pack->data + 2,false);
+ break;
+ }
+#endif
+#if 0
+ case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+ {
+ const mbtk_net_array_info_t* nets = (const mbtk_net_array_info_t*)data;
+ mbtk_net_info_t *net = NULL;
+ //LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP set");
+ //sleep(1);
+ list_first(nets->net_list);
+ pack->data_len = nets->count * sizeof(mbtk_net_info_t);
+ if(pack->data_len > 0) {
+ int i = 0;
+ pack->data = (uint8*)malloc(pack->data_len);
+ if(pack->data == NULL) {
+ LOG("malloc() fail.");
+ return -1;
+ }
+ memset(pack->data, 0, pack->data_len);
+
+ while ((net = (mbtk_net_info_t*) list_next(nets->net_list)))
+ {
+ #if 0
+ memcpy(pack->data + i, net, sizeof(mbtk_net_info_t));
+ i += sizeof(mbtk_net_info_t);
+ #else
+ pack->data[i++] = net->net_sel_mode;
+ pack->data[i++] = net->net_type;
+ //uint32_2_byte((uint32)atoi((char*)net->plmn), pack->data + i,false);
+ uint32_2_byte(net->plmn, pack->data + i,false);
+ i += sizeof(uint32);
+ #endif
+ }
+ }
+ break;
+ }
+#endif
+ default:
+ {
+ LOG("Unknown REQ/RSP : %s", id2str(pack->info_id));
+ break;
+ }
+ }
+ }
+ else
+ {
+ LOG("Unknown info : %s", id2str(pack->info_id));
+ return -1;
+ }
+ return 0;
+}
+
+void* mbtk_info_pack_data_get(mbtk_info_pack_t *pack, int *data_len)
+{
+ if(pack == NULL || pack->data_len == 0 || pack->data == NULL)
+ {
+ LOG("Packet is NULL.");
+ return NULL;
+ }
+
+ mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+ // IND
+ if(info_type == MBTK_INFO_TYPE_IND)
+ {
+ switch(pack->info_id)
+ {
+ // <uint8> State
+ case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+ case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+ {
+ return pack->data;
+ }
+ default:
+ {
+ LOG("Unknown IND : %s", id2str(pack->info_id));
+ break;
+ }
+ }
+ }
+ //else if(pack->info_id % 2 == 1) // REQ (Set Data)
+ else if(info_type == MBTK_INFO_TYPE_REQ || info_type == MBTK_INFO_TYPE_RSP) // REQ or RSP
+ {
+ switch(pack->info_id)
+ {
+ case MBTK_INFO_ID_DEV_VOLTE_REQ: // <uint8> 0:Close 1:Open
+ case MBTK_INFO_ID_DEV_VOLTE_RSP:
+ case MBTK_INFO_ID_SIM_STATE_REQ: // <uint8> 0:NOT_EXIST 1:READY ...
+ case MBTK_INFO_ID_SIM_STATE_RSP:
+ case MBTK_INFO_ID_NET_RADIO_REQ: // <uint8> 0:OFF 1:ON
+ case MBTK_INFO_ID_NET_RADIO_RSP:
+ case MBTK_INFO_ID_DEV_IMEI_REQ: // <string> SN
+ case MBTK_INFO_ID_DEV_IMEI_RSP:
+ case MBTK_INFO_ID_DEV_SN_REQ: // <string> SN
+ case MBTK_INFO_ID_DEV_SN_RSP:
+ case MBTK_INFO_ID_DEV_MEID_REQ: // <string> MEID
+ case MBTK_INFO_ID_DEV_MEID_RSP:
+ case MBTK_INFO_ID_DEV_VERSION_REQ: // <string> VERSION
+ case MBTK_INFO_ID_DEV_VERSION_RSP:
+ case MBTK_INFO_ID_DEV_TEMP_REQ: // <string> Temperature
+ case MBTK_INFO_ID_DEV_TEMP_RSP:
+ case MBTK_INFO_ID_SIM_PIN_REQ: // <string> PIN
+ case MBTK_INFO_ID_SIM_PIN_RSP:
+ case MBTK_INFO_ID_SIM_PUK_REQ: // <string> PUK
+ case MBTK_INFO_ID_SIM_PUK_RSP:
+ case MBTK_INFO_ID_SIM_IMSI_REQ: // <string> IMSI
+ case MBTK_INFO_ID_SIM_IMSI_RSP:
+ case MBTK_INFO_ID_SIM_ICCID_REQ: // <string> ICCID
+ case MBTK_INFO_ID_SIM_ICCID_RSP:
+ case MBTK_INFO_ID_NET_APN_REQ: // <string> cmnet/ctnet/3gnet/...
+ case MBTK_INFO_ID_NET_APN_RSP:
+ case MBTK_INFO_ID_NET_BAND_REQ: // mbtk_band_info_t
+ case MBTK_INFO_ID_NET_BAND_RSP:
+ case MBTK_INFO_ID_NET_CELL_REQ: // Lock net/cell/frequency
+ case MBTK_INFO_ID_NET_CELL_RSP:
+ case MBTK_INFO_ID_NET_SEL_MODE_REQ: // mbtk_net_info_t
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+ case MBTK_INFO_ID_NET_AVAILABLE_REQ: // mbtk_net_info_t[]
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+ {
+ return pack->data;
+ }
+ case MBTK_INFO_ID_NET_SIGNAL_REQ: // <sint16>[4] rssi,rscp,rsrp,snr
+ case MBTK_INFO_ID_NET_SIGNAL_RSP:
+ {
+ mbtk_net_signal_t* signal = (mbtk_net_signal_t*)malloc(sizeof(mbtk_net_signal_t));
+ if(!signal)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+
+ signal->rssi = (sint16)byte_2_uint16(pack->data, false);
+ signal->rscp = (sint16)byte_2_uint16(pack->data + sizeof(uint16), false);
+ signal->rsrp = (sint16)byte_2_uint16(pack->data + sizeof(uint16) * 2, false);
+ signal->snr = (sint16)byte_2_uint16(pack->data + sizeof(uint16) * 3, false);
+ return signal;
+ }
+ case MBTK_INFO_ID_NET_IPV4_DNS_REQ: // <uint32>[2] Preferred DNS,Alternate DNS
+ case MBTK_INFO_ID_NET_IPV4_DNS_RSP:
+ {
+ mbtk_net_dns_ipv4_t* dns_ipv4 = (mbtk_net_dns_ipv4_t*)malloc(sizeof(mbtk_net_dns_ipv4_t));
+ if(!dns_ipv4)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+
+ dns_ipv4->preferred_dns = byte_2_uint32(pack->data, false);
+ dns_ipv4->alternate_dns = byte_2_uint32(pack->data + sizeof(uint32), false);
+ return dns_ipv4;
+ }
+ case MBTK_INFO_ID_NET_IPV6_DNS_REQ: // <uint32>[8] Preferred DNS,Alternate DNS
+ case MBTK_INFO_ID_NET_IPV6_DNS_RSP:
+ {
+ return memdup(pack->data, sizeof(mbtk_net_dns_ipv6_t));
+ }
+ case MBTK_INFO_ID_NET_IPV4_REQ: // <uint32> IPv4
+ case MBTK_INFO_ID_NET_IPV4_RSP:
+ {
+ return memdup(pack->data, sizeof(uint32));
+ break;
+ }
+ case MBTK_INFO_ID_NET_IPV6_REQ: // <uint32>[4] IPv6
+ case MBTK_INFO_ID_NET_IPV6_RSP:
+ {
+ return memdup(pack->data, sizeof(uint32) * 4);
+ break;
+ }
+ case MBTK_INFO_ID_NET_LOCAL_REQ: // <uint16>[2] tag,earfcn
+ case MBTK_INFO_ID_NET_LOCAL_RSP:
+ {
+ mbtk_local_info_t* local = (mbtk_local_info_t*)malloc(sizeof(mbtk_local_info_t));
+ if(!local)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+
+ local->tag = (sint16)byte_2_uint16(pack->data, false);
+ local->earfcn = (sint16)byte_2_uint16(pack->data + sizeof(uint16), false);
+ return local;
+ }
+#if 0
+ case MBTK_INFO_ID_NET_SEL_MODE_REQ:
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)
+ {
+ mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+ if(!net)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+ memset(net, 0, sizeof(mbtk_net_info_t));
+ net->net_sel_mode = pack->data[0];
+ net->net_type = pack->data[1];
+ //itoa(byte_2_uint32(pack->data + 2, false), net->plmn, 10);
+ sprintf(net->plmn, "%d", byte_2_uint32(pack->data + 2, false));
+
+ return net;
+ }
+#endif
+#if 0
+ case MBTK_INFO_ID_NET_AVAILABLE_REQ:
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP: // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+ {
+ mbtk_net_array_info_t* nets = (mbtk_net_array_info_t*)malloc(sizeof(mbtk_net_array_info_t));
+ if(!nets)
+ {
+ LOG("malloc() error[%d]", errno);
+ return NULL;
+ }
+ nets->count = 0;
+ nets->net_list = list_create(NULL);
+ if(nets->net_list == NULL)
+ {
+ LOG("list_create() fail.");
+ free(nets);
+ return NULL;
+ }
+
+ int i = 0;
+ while(i < pack->data_len) {
+ LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 1");
+ sleep(1);
+ mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+ LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 2");
+ sleep(1);
+ if(!net)
+ {
+ LOG("malloc() error[%d]", errno);
+ sleep(3);
+ //list_free(nets->net_list);
+ //free(nets);
+ return NULL;
+ }
+ memset(net, 0, sizeof(mbtk_net_info_t));
+
+ LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 3");
+ sleep(1);
+#if 1
+ #if 1
+ #if 0
+ memcpy(net, pack->data + i, sizeof(mbtk_net_info_t));
+ i += sizeof(mbtk_net_info_t);
+ #else
+ net->net_sel_mode = pack->data[i++];
+ net->net_type = pack->data[i++];
+ //sprintf(net->plmn, "%d", byte_2_uint32(pack->data + i, false));
+ net->plmn = byte_2_uint32(pack->data + i, false);
+ i += sizeof(uint32);
+ #endif
+ #endif
+
+ LOG("MBTK_INFO_ID_NET_AVAILABLE_RSP get 5");
+ log_hex("NET 2", net, sizeof(mbtk_net_info_t));
+ sleep(1);
+
+ list_add(nets->net_list, net);
+
+#endif
+ LOG("list_add");
+ sleep(1);
+ }
+
+ sleep(10);
+
+ // Data lenght changed.
+ *data_len = sizeof(mbtk_net_array_info_t);
+ return nets;
+ }
+#endif
+ default:
+ {
+ LOG("Unknown REQ/RSP : %s", id2str(pack->info_id));
+ break;
+ }
+ }
+ }
+ else
+ {
+ LOG("Unknown info : %s", id2str(pack->info_id));
+ }
+
+ return NULL;
+}
+#endif
+
+int mbtk_info_pack_send(int fd, mbtk_info_pack_t *pack)
+{
+ if(!pack)
+ {
+ LOG("Packet is NULL.");
+ return -1;
+ }
+ uint8 data[SOCK_MSG_LEN_MAX] = {0};
+ uint8* data_ptr = data + SOCK_PACK_EXTRA_LEN;
+
+ data_ptr += uint16_2_byte(pack->info_id, data_ptr, false);
+ data_ptr += uint16_2_byte(pack->info_err, data_ptr, false);
+ data_ptr += uint16_2_byte(pack->data_len, data_ptr, false);
+ //log_hex("DATA1", data, 40);
+ if(pack->data_len > 0)
+ {
+ memcpy(data_ptr, pack->data, pack->data_len);
+ data_ptr += pack->data_len;
+ //log_hex("DATA2", data, 40);
+ }
+
+ // Set flag and packet length.
+ uint32_2_byte(MBTK_INFO_PACKET_FLAG, data, true);
+ uint16_2_byte(data_ptr - data - SOCK_PACK_EXTRA_LEN, data + sizeof(uint32), false);
+
+ //log_hex("DATA3", data, 40);
+ return sock_write(fd, data, data_ptr - data);
+}
+
+mbtk_info_pack_t** mbtk_info_pack_recv(int fd, bool is_server, mbtk_info_err_enum *err)
+{
+ uint8 msg[SOCK_MSG_LEN_MAX + 1];
+ *err = MBTK_INFO_ERR_SUCCESS;
+ int len = sock_read(fd, msg, SOCK_MSG_LEN_MAX + 1);
+ if(len < SOCK_PACK_LEN_MIN)
+ {
+ if(len > 0)
+ {
+ *err = MBTK_INFO_ERR_FORMAT;
+ LOG("Insufficient packet data.");
+ }
+ return NULL;
+ }
+
+ int pack_count = pack_num_check(msg, len);
+ LOG("Packet number : %d", pack_count);
+ if(pack_count < 1)
+ {
+ *err = MBTK_INFO_ERR_FORMAT;
+ LOG("Packet not found.");
+ return NULL;
+ }
+ uint8 *ptr = msg;
+ mbtk_info_pack_t** packs = (mbtk_info_pack_t**)malloc(sizeof(mbtk_info_pack_t*) * (pack_count + 1));
+ int i = 0;
+ while(i < pack_count)
+ {
+ // TAG
+ if(MBTK_INFO_PACKET_FLAG != byte_2_uint32(ptr, true))
+ {
+ *err = MBTK_INFO_ERR_FORMAT;
+ LOG("Packet TAG error.");
+ goto error;
+ }
+ ptr += sizeof(uint32);
+
+ // Jump packet length.
+ ptr += sizeof(uint16);
+
+ mbtk_info_id_enum info_id = (mbtk_info_id_enum)byte_2_uint16(ptr, false);
+ mbtk_info_type_enum info_type = mbtk_info_type_get(info_id);
+ if(is_server)
+ {
+ // For server,"info_type" must by REQ or IND(Register IND).
+ if(info_type != MBTK_INFO_TYPE_REQ && info_type != MBTK_INFO_TYPE_IND)
+ {
+ *err = MBTK_INFO_ERR_FORMAT;
+ LOG("Packet Type error : %d", info_type);
+ goto error;
+ }
+ }
+ else
+ {
+ // For client,"info_type" must by RSP or IND.
+ if(info_type != MBTK_INFO_TYPE_RSP && info_type != MBTK_INFO_TYPE_IND)
+ {
+ *err = MBTK_INFO_ERR_FORMAT;
+ LOG("Packet Type error.");
+ goto error;
+ }
+ }
+ ptr += sizeof(uint16);
+
+ mbtk_info_pack_t* pack = mbtk_info_pack_creat(info_id);
+ if(pack == NULL)
+ {
+ *err = MBTK_INFO_ERR_MEMORY;
+ LOG("Packet malloc() fail.");
+ goto error;
+ }
+
+ // "info_err"
+ pack->info_err = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+
+ // "data_len"
+ pack->data_len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+
+ if(pack->data_len > 0)
+ {
+ pack->data = (uint8*)memdup(ptr, pack->data_len);
+ ptr += pack->data_len;
+ }
+
+ packs[i++] = pack;
+ }
+ packs[i] = NULL;
+
+ return packs;
+
+error:
+ LOG("mbtk_info_pack_recv error, will free().");
+ if(packs)
+ {
+ mbtk_info_pack_t** pack_ptr = packs;
+ while(*pack_ptr)
+ {
+ mbtk_info_pack_free(pack_ptr);
+ pack_ptr++;
+ }
+
+ free(packs);
+ }
+ return NULL;
+}
+
+int mbtk_info_pack_free(mbtk_info_pack_t **pack)
+{
+ if(pack == NULL || *pack == NULL)
+ {
+ LOG("Packet is NULL.");
+ return -1;
+ }
+
+ // LOG("Free packet : %s", id2str((*pack)->info_id));
+#if 0
+ if((*pack)->data)
+ {
+ free((*pack)->data);
+ }
+#endif
+ free(*pack);
+ *pack = NULL;
+ return 0;
+}
+
+
diff --git a/mbtk/libmbtk_lib/ril/mbtk_info.h b/mbtk/libmbtk_lib/ril/mbtk_info.h
new file mode 100755
index 0000000..d58c498
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/mbtk_info.h
@@ -0,0 +1,543 @@
+#ifndef MBTK_INFO_INCLUDE
+#define MBTK_INFO_INCLUDE
+#include <netinet/in.h>
+
+#include "mbtk_type.h"
+#include "mbtk_list.h"
+#include "mbtk_log.h"
+#include "mbtk_utils.h"
+#include "mbtk_info_api.h"
+
+#define MBTK_INFO_PACKET_FLAG 0x5F6F7F8F
+#define SOCK_INFO_PATH "/tmp/info_sock"
+#define SOCK_MSG_LEN_MAX 2048
+
+// Tag(4) + Packet_Length(2)
+#define SOCK_PACK_EXTRA_LEN 6
+// SOCK_PACK_EXTRA_LEN + Id(2) + Error(2) + Number(2)
+#define SOCK_PACK_LEN_MIN (SOCK_PACK_EXTRA_LEN + 6)
+
+typedef enum
+{
+ MBTK_INFO_TYPE_REQ,
+ MBTK_INFO_TYPE_RSP,
+ MBTK_INFO_TYPE_IND,
+ MBTK_INFO_TYPE_UNKNOWN
+} mbtk_info_type_enum;
+
+typedef enum
+{
+ // Device Information
+ MBTK_INFO_ID_DEV_BEGIN = 0,
+ // <string> IMEI
+ MBTK_INFO_ID_DEV_IMEI_REQ,
+ MBTK_INFO_ID_DEV_IMEI_RSP,
+ // <string> SN
+ MBTK_INFO_ID_DEV_SN_REQ,
+ MBTK_INFO_ID_DEV_SN_RSP,
+ // <string> MEID
+ MBTK_INFO_ID_DEV_MEID_REQ,
+ MBTK_INFO_ID_DEV_MEID_RSP,
+ // <string> VERSION
+ MBTK_INFO_ID_DEV_VERSION_REQ,
+ MBTK_INFO_ID_DEV_VERSION_RSP,
+ // <string> MODEL
+ MBTK_INFO_ID_DEV_MODEL_REQ,
+ MBTK_INFO_ID_DEV_MODEL_RSP,
+ // <uint8> 0:Close 1:Open
+ MBTK_INFO_ID_DEV_VOLTE_REQ,
+ MBTK_INFO_ID_DEV_VOLTE_RSP,
+ // <string> Temperature
+ MBTK_INFO_ID_DEV_TEMP_REQ, // Temperature
+ MBTK_INFO_ID_DEV_TEMP_RSP,
+ // <uint8><string> YYYY-MM-DD-HH:MM:SS
+ MBTK_INFO_ID_DEV_TIME_REQ, // Time
+ MBTK_INFO_ID_DEV_TIME_RSP,
+ //<string> "23/03/20,01:58:00+32"
+ MBTK_INFO_ID_DEV_CELL_TIME_REQ, // Time
+ MBTK_INFO_ID_DEV_CELL_TIME_RSP,
+
+ MBTK_INFO_ID_DEV_MODEM_REQ,
+ MBTK_INFO_ID_DEV_MODEM_RSP,
+
+ MBTK_INFO_ID_DEV_END,
+
+ // Sim Information
+ MBTK_INFO_ID_SIM_BEGIN = 1000,
+ // <uint8> 0:NOT_EXIST 1:READY ...
+ MBTK_INFO_ID_SIM_STATE_REQ,
+ MBTK_INFO_ID_SIM_STATE_RSP,
+ // <uint8> 0: SIM 1: USIM 2: TEST SIM 3: TEST USIM 4: UNKNOWN
+ MBTK_INFO_ID_SIM_STYPE_REQ,
+ MBTK_INFO_ID_SIM_STYPE_RSP,
+ // <string> PIN
+ MBTK_INFO_ID_SIM_PIN_REQ,
+ MBTK_INFO_ID_SIM_PIN_RSP,
+ // <string> PIN
+ MBTK_INFO_ID_SIM_ENABLE_PIN_REQ,
+ MBTK_INFO_ID_SIM_ENABLE_PIN_RSP,
+ // <string> PUK
+ MBTK_INFO_ID_SIM_PUK_REQ,
+ MBTK_INFO_ID_SIM_PUK_RSP,
+ // <string> PLMN
+ MBTK_INFO_ID_SIM_PLMN_REQ,
+ MBTK_INFO_ID_SIM_PLMN_RSP,
+ // <uint8> <uint8> <uint8> <uint8> PIN PUK LAST TIMES
+ MBTK_INFO_ID_SIM_PINPUK_TIMES_REQ,
+ MBTK_INFO_ID_SIM_PINPUK_TIMES_RSP,
+ // <string> IMSI
+ MBTK_INFO_ID_SIM_IMSI_REQ,
+ MBTK_INFO_ID_SIM_IMSI_RSP,
+ // <string> ICCID
+ MBTK_INFO_ID_SIM_ICCID_REQ,
+ MBTK_INFO_ID_SIM_ICCID_RSP,
+ // <string> Phone Number
+ MBTK_INFO_ID_SIM_PN_REQ,
+ MBTK_INFO_ID_SIM_PN_RSP,
+ // <string> <string> old_PIN new_PIN
+ MBTK_INFO_ID_SIM_CHANGE_PIN_REQ,
+ MBTK_INFO_ID_SIM_CHANGE_PIN_RSP,
+
+ MBTK_INFO_ID_SIM_END,
+
+ // Network Information
+ MBTK_INFO_ID_NET_BEGIN = 2000,
+ // <uint8> 0:OFF 1:ON
+ MBTK_INFO_ID_NET_RADIO_REQ,
+ MBTK_INFO_ID_NET_RADIO_RSP,
+ // sel_mode(uint8)type(uint8)plmn(uint32)...sel_mode(uint8)type(uint8)plmn(uint32)
+ MBTK_INFO_ID_NET_AVAILABLE_REQ,
+ MBTK_INFO_ID_NET_AVAILABLE_RSP,
+ // <uint8> 0: automatic 1: manual
+ // or
+ // sel_mode(uint8)type(uint8)plmn(uint32)
+ MBTK_INFO_ID_NET_SEL_MODE_REQ,
+ MBTK_INFO_ID_NET_SEL_MODE_RSP,
+ // mbtk_band_info_t
+ MBTK_INFO_ID_NET_BAND_REQ,
+ MBTK_INFO_ID_NET_BAND_RSP,
+ // mbtk_signal_info_t
+ MBTK_INFO_ID_NET_SIGNAL_REQ,
+ MBTK_INFO_ID_NET_SIGNAL_RSP,
+ // mbtk_net_reg_info_t
+ MBTK_INFO_ID_NET_REG_REQ,
+ MBTK_INFO_ID_NET_REG_RSP,
+ // mbtk_apn_info_t
+ MBTK_INFO_ID_NET_APN_REQ,
+ MBTK_INFO_ID_NET_APN_RSP,
+ // mbtk_qser_apn_info_t
+ MBTK_INFO_ID_NET_QSER_APN_REQ,
+ MBTK_INFO_ID_NET_QSER_APN_RSP,
+ // mbtk_apn_del
+ MBTK_INFO_ID_NET_APN_DEL_REQ,
+ MBTK_INFO_ID_NET_APN_DEL_RSP,
+ // mbtk_cell_info_t[]
+ MBTK_INFO_ID_NET_CELL_REQ,
+ MBTK_INFO_ID_NET_CELL_RSP,
+ // REQ:
+ // <call_type[1]><cid[1]><timeout[1]>
+ // call_type : mbtk_data_call_type_enum
+ // cid : 1 - 15
+ // timeout : second
+ // RSP:
+ // <type[1]><ipv4><ipv6>
+ // type : 0-IPV4 1-IPV6 2-IPV4V6
+ // ipv4 : mbtk_ipv4_info_t
+ // ipv6 : mbtk_ipv6_info_t
+ MBTK_INFO_ID_NET_DATA_CALL_REQ,
+ MBTK_INFO_ID_NET_DATA_CALL_RSP,
+
+ // mbtk_net_ims
+ MBTK_INFO_ID_NET_IMS_REQ,
+ MBTK_INFO_ID_NET_IMS_RSP,
+
+ MBTK_INFO_ID_NET_IMS_REG_STATE_REQ,
+ MBTK_INFO_ID_NET_IMS_REG_STATE_RSP,
+
+
+ MBTK_INFO_ID_NET_END,
+
+
+ // Call Information
+ MBTK_INFO_ID_CALL_BEGIN = 3000,
+ MBTK_INFO_ID_CALL_STATE_REQ,
+ MBTK_INFO_ID_CALL_STATE_RSP,
+
+ // Start call.
+ MBTK_INFO_ID_CALL_START_REQ,
+ MBTK_INFO_ID_CALL_START_RSP,
+ //answer call
+ MBTK_INFO_ID_CALL_ANSWER_REQ,
+ MBTK_INFO_ID_CALL_ANSWER_RSP,
+ //hang up all call
+ MBTK_INFO_ID_CALL_HANGUP_REQ,
+ MBTK_INFO_ID_CALL_HANGUP_RSP,
+ //hang up a call
+ MBTK_INFO_ID_CALL_HANGUP_A_REQ,
+ MBTK_INFO_ID_CALL_HANGUP_A_RSP,
+ //hang up waiting or background call
+ MBTK_INFO_ID_CALL_HANGUP_B_REQ,
+ MBTK_INFO_ID_CALL_HANGUP_B_RSP,
+ //hang up foreground resume background
+ MBTK_INFO_ID_CALL_HANGUP_C_REQ,
+ MBTK_INFO_ID_CALL_HANGUP_C_RSP,
+ //wait in call
+ MBTK_INFO_ID_CALL_WAITIN_REQ,
+ MBTK_INFO_ID_CALL_WAITIN_RSP,
+ //mute call
+ MBTK_INFO_ID_CALL_MUTE_REQ,
+ MBTK_INFO_ID_CALL_MUTE_RSP,
+ //dtmf call
+ MBTK_INFO_ID_CALL_DTMF_REQ,
+ MBTK_INFO_ID_CALL_DTMF_RSP,
+
+ MBTK_INFO_ID_CALL_END,
+
+ // SMS Information
+ MBTK_INFO_ID_SMS_BEGIN = 4000,
+ MBTK_INFO_ID_SMS_STATE_REQ,
+ MBTK_INFO_ID_SMS_STATE_RSP,
+ MBTK_INFO_ID_SMS_CMGF_REQ,
+ MBTK_INFO_ID_SMS_CMGF_RSP,
+ MBTK_INFO_ID_SMS_CPMS_REQ,
+ MBTK_INFO_ID_SMS_CPMS_RSP,
+ MBTK_INFO_ID_SMS_CMGS_REQ,
+ MBTK_INFO_ID_SMS_CMGS_RSP,
+ MBTK_INFO_ID_SMS_CMSS_REQ,
+ MBTK_INFO_ID_SMS_CMSS_RSP,
+ MBTK_INFO_ID_SMS_CMGR_REQ,
+ MBTK_INFO_ID_SMS_CMGR_RSP,
+ MBTK_INFO_ID_SMS_CMGW_REQ,
+ MBTK_INFO_ID_SMS_CMGW_RSP,
+ MBTK_INFO_ID_SMS_CMGD_REQ,
+ MBTK_INFO_ID_SMS_CMGD_RSP,
+ MBTK_INFO_ID_SMS_CMGL_REQ,
+ MBTK_INFO_ID_SMS_CMGL_RSP,
+ MBTK_INFO_ID_SMS_CSCA_REQ,
+ MBTK_INFO_ID_SMS_CSCA_RSP,
+ MBTK_INFO_ID_SMS_CSMP_REQ,
+ MBTK_INFO_ID_SMS_CSMP_RSP,
+ MBTK_INFO_ID_SMS_CSCB_REQ,
+ MBTK_INFO_ID_SMS_CSCB_RSP,
+ MBTK_INFO_ID_SMS_CNMI_REQ,
+ MBTK_INFO_ID_SMS_CNMI_RSP,
+
+ MBTK_INFO_ID_SMS_END,
+
+ // PhoneBook Information
+ MBTK_INFO_ID_PB_BEGIN = 5000,
+ MBTK_INFO_ID_PB_STATE_REQ,
+ MBTK_INFO_ID_PB_STATE_RSP,
+
+ MBTK_INFO_ID_PB_END,
+
+ //wakeup
+ MBTK_INFO_ID_WAKEUP_STA_BEGIN = 6000,
+ MBTK_INFO_ID_WAKEUP_STA_REQ,
+ MBTK_INFO_ID_WAKEUP_STA_RSP,
+
+ MBTK_INFO_ID_WAKEUP_STA_END,
+
+ //oos(out of service))
+ MBTK_INFO_ID_OOS_STA_BEGIN = 7000,
+ MBTK_INFO_ID_OOS_STA_REQ,
+ MBTK_INFO_ID_OOS_STA_RSP,
+
+ MBTK_INFO_ID_OOS_STA_END,
+
+ //led
+ MBTK_INFO_ID_LED_BEGIN = 8000,
+ MBTK_INFO_ID_LED_REQ,
+ MBTK_INFO_ID_LED_RSP,
+ MBTK_INFO_ID_LED_END,
+
+ // IND Information
+ MBTK_INFO_ID_IND_BEGIN = 10000,
+ // <uint8> State
+ MBTK_INFO_ID_IND_NET_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_CALL_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_SMS_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_RADIO_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_SIM_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_PDP_STATE_CHANGE,
+ // <uint8> State
+ MBTK_INFO_ID_IND_SERVER_STATE_CHANGE,////mbtk wyq for server_ready_status add
+ // <uint8> State
+ MBTK_INFO_ID_IND_SIGNAL_STATE_CHANGE,
+
+
+ MBTK_INFO_ID_IND_END,
+ MBTK_INFO_ID_REQ_UNKNOWN // Unknown information.
+} mbtk_info_id_enum;
+
+typedef enum {
+ MBTK_NET_CS_STATE = 0,
+ MBTK_NET_PS_STATE
+} mbtk_net_state_type_enum;
+
+typedef enum {
+ MBTK_INFO_ERR_SUCCESS = 300,
+ MBTK_INFO_ERR_FORMAT, // Packet format error.
+ MBTK_INFO_ERR_REQ_UNKNOWN, // Unknown request.
+ MBTK_INFO_ERR_REQ_PARAMETER, // Request parameter error.
+ MBTK_INFO_ERR_UNSUPPORTED, // Unsupported operation.
+ MBTK_INFO_ERR_MEMORY, // Insufficient memory.
+ MBTK_INFO_ERR_IND_FULL, // Register IND fail(FULL).
+ MBTK_INFO_ERR_IND_UNKNOWN, // Register IND fail(Unknown IND).
+ MBTK_INFO_ERR_CID, // CID error.
+ MBTK_INFO_ERR_TIMEOUT, // Timeout.
+ MBTK_INFO_ERR_TIME_FORMAT, // Time format error.
+
+ //mbtk wyq for data_call add start
+ MBTK_INFO_ERR_CID_EXIST,
+ MBTK_INFO_ERR_CID_NO_EXIST,
+ MBTK_INFO_ERR_NET_NO_INIT,
+ //mbtk wyq for data_call add end
+
+ MBTK_INFO_ERR_UNKNOWN = 400, // Unknown error.
+ // CME error start index.
+ MBTK_INFO_ERR_CME = 500,
+ MBTK_INFO_ERR_CME_NON = 1000
+} mbtk_info_err_enum;
+
+/*
+GSM band��
+ 1 �C PGSM 900 (standard or primary)
+ 2 �C DCS GSM 1800
+ 4 �C PCS GSM 1900
+ 8 �C EGSM 900 (extended)
+ 16 �C GSM 450
+ 32 �C GSM 480
+ 64 �C GSM 850
+ 512 - BAND_LOCK_BIT // used for GSM band setting
+*/
+typedef enum
+{
+ MBTK_GSM_BAND_PGSM_900 = 1,
+ MBTK_GSM_BAND_DCS_GSM_1800 = 2,
+ MBTK_GSM_BAND_PCS_GSM_1900 = 4,
+ MBTK_GSM_BAND_EGSM_900 = 8,
+ MBTK_GSM_BAND_GSM_450 = 16,
+ MBTK_GSM_BAND_GSM_480 = 32,
+ MBTK_GSM_BAND_GSM_850 = 64,
+ MBTK_GSM_BAND_BAND_LOCK_BIT = 512
+} mbtk_gsm_band_enum;
+
+/*
+UMTS band��
+ 1 �C UMTS_BAND_1
+ 2 �C UMTS_BAND_2
+ 4 �C UMTS_BAND_3
+ 8 �C UMTS_BAND_4
+ 16 �C UMTS_BAND_5
+ 32 �C UMTS_BAND_6
+ 64 �C UMTS_BAND_7
+ 128 �C UMTS_BAND_8
+ 256 �C UMTS_BAND_9
+*/
+typedef enum
+{
+ MBTK_UMTS_BAND_1 = 1,
+ MBTK_UMTS_BAND_2 = 2,
+ MBTK_UMTS_BAND_3 = 4,
+ MBTK_UMTS_BAND_4 = 8,
+ MBTK_UMTS_BAND_5 = 16,
+ MBTK_UMTS_BAND_6 = 32,
+ MBTK_UMTS_BAND_7 = 64,
+ MBTK_UMTS_BAND_8 = 128,
+ MBTK_UMTS_BAND_9 = 256
+} mbtk_umts_band_enum;
+
+/*
+LTEbandH(TDD-LTE band)
+ 32 �C TDLTE_BAND_38
+ 64 �C TDLTE_BAND_39
+ 128 �C TDLTE_BAND_40
+ 256 �C TDLTE_BAND_41
+*/
+typedef enum
+{
+ MBTK_TDLTE_BAND_38 = 32,
+ MBTK_TDLTE_BAND_39 = 64,
+ MBTK_TDLTE_BAND_40 = 128,
+ MBTK_TDLTE_BAND_41 = 256
+} mbtk_tdlte_band_enum;
+
+/*
+LTEbandL(FDD-LTE band)
+ 1 �C FDDLTE_BAND_1
+ 4 �C FDDLTE _BAND_3
+ 8 �C FDDLTE _BAND_4
+ 64 �C FDDLTE _BAND_7
+ 65536 �C FDDLTE _BAND_17
+ 524288 �C FDDLTE _BAND_20
+*/
+typedef enum
+{
+ MBTK_FDDLTE_BAND_1 = 1,
+ MBTK_FDDLTE_BAND_3 = 4,
+ MBTK_FDDLTE_BAND_4 = 8,
+ MBTK_FDDLTE_BAND_7 = 64,
+ MBTK_FDDLTE_BAND_17 = 65536,
+ MBTK_FDDLTE_BAND_20 = 524288
+} mbtk_fddlte_band_enum;
+
+typedef enum
+{
+ MBTK_LTE_EXT_BAND_65 = 1,
+ MBTK_LTE_EXT_BAND_66 = 2,
+ MBTK_LTE_EXT_BAND_67 = 4,
+ MBTK_LTE_EXT_BAND_68 = 8,
+ MBTK_LTE_EXT_BAND_69 = 16
+} mbtk_lte_ext_band_enum;
+
+/*
+0: unknown
+1: available
+2: current
+3: forbidden
+*/
+typedef enum
+{
+ MBTK_NET_AVIL_STATE_UNKNOWN = 0,
+ MBTK_NET_AVIL_STATE_AVAILABLE,
+ MBTK_NET_AVIL_STATE_CURRENT,
+ MBTK_NET_AVIL_STATE_FORBIDDEN
+} mbtk_net_avil_state_enum;
+
+typedef struct
+{
+ uint16 tac;
+ uint16 earfcn;
+} mbtk_local_info_t;
+
+typedef struct
+{
+ uint16 info_id;
+ uint16 info_err;
+ const uint8 *data;
+ uint16 data_len;
+} mbtk_info_pack_t;
+
+typedef struct
+{
+ uint8 type; // 0: GSM 1: UMTS 2: LTE
+ bool running;
+
+ int cell_num;
+ mbtk_cell_info_t cell[CELL_NUM_MAX];
+} mbtK_cell_pack_info_t;
+
+typedef enum {
+ MBTK_MOBILE_ORIGINATED_CALL,
+ MBTK_TERMINATED_CALL,
+} mbtk_call_dir_enum;
+
+typedef enum {
+ MBTK_VOICE,
+ MBTK_DATA,
+ MBTK_FAX,
+ MBTK_VOICE_FOLLOWED_BY_DATA_VOICE_MODE,
+ MBTK_ALTERNATING_VOICE_VOICE_MODE,
+ MBTK_ALTERNATING_FAX_VOICE_MODE,
+ MBTK_VOICE_FOLLOWED_BY_DATA_DATA_MODE,
+ MBTK_ALTERNATING_VOICE_DATA_MODE,
+ MBTK_ALTERNATING_FAX_FAX_MODE,
+ MBTL_UNKNOW,
+} mbtk_call_mode_enum;
+
+typedef enum {
+ MBTK_NOT_MULITYPARTY_CALL,
+ MBTK_MULITYPARTY__CALL,
+} mbtk_call_mpty_enum;
+
+typedef struct
+{
+ int cid;
+ bool act;
+ bool waitting;
+} info_cgact_wait_t;
+
+typedef struct
+{
+ uint32 count;
+ list_node_t *net_list;
+} mbtk_net_array_info_t;
+
+typedef struct
+{
+ bool inited;
+ mbtk_radio_state_enum radio_state;
+ mbtk_sim_state_enum sim_state;
+ mbtk_radio_technology_enum net_type;
+ mbtk_ip_type_enum ip_type;
+ struct sockaddr_in addr4;
+ struct sockaddr_in preferred_dns4;
+ struct sockaddr_in alternate_dns4;
+
+ struct sockaddr_in6 addr6;
+ struct sockaddr_in6 preferred_dns6;
+ struct sockaddr_in6 alternate_dns6;
+} net_info_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+char* type2str(mbtk_info_type_enum type);
+
+char* apn2str(mbtk_ip_type_enum type);
+
+char* id2str(int id);
+
+char* err2str(mbtk_info_err_enum err);
+
+/*
+IPv6 : 254.128.0.0.0.0.0.0.0.1.0.2.144.5.212.239 -> uint128
+*/
+int str_2_ipv6(const void *ip_str, void *ipv6);
+
+/*
+IPv6 : uint128 -> fe80::215:1dff:fe81:484c
+*/
+int ipv6_2_str(const void *ipv6, void *ipv6_str);
+
+/*
+0 GSM
+1 GSM_COMPACT
+2 UTRAN
+3 GSM_EGPRS
+4 UTRAN_HSDPA
+5 UTRAN_HSUPA
+6 UTRAN_HSDPA_HSUPA
+7 EUTRAN
+8 ECGSM
+*/
+mbtk_net_type_enum mbtk_net_type_get(mbtk_radio_technology_enum radio_tech);
+
+mbtk_info_type_enum mbtk_info_type_get(int info_id);
+
+mbtk_info_pack_t* mbtk_info_pack_creat(int info_id);
+
+#if 0
+int mbtk_info_pack_data_set(mbtk_info_pack_t *pack, const void *data, int data_len);
+void* mbtk_info_pack_data_get(mbtk_info_pack_t *pack, int *data_len);
+#endif
+
+int mbtk_info_pack_send(int fd, mbtk_info_pack_t *pack);
+
+mbtk_info_pack_t** mbtk_info_pack_recv(int fd, bool is_server, mbtk_info_err_enum *err);
+
+int mbtk_info_pack_free(mbtk_info_pack_t **pack);
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* MBTK_INFO_INCLUDE */
+
+
diff --git a/mbtk/libmbtk_lib/ril/mbtk_info_api.c b/mbtk/libmbtk_lib/ril/mbtk_info_api.c
new file mode 100755
index 0000000..7823f3d
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/mbtk_info_api.c
@@ -0,0 +1,2589 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#include "mbtk_info.h"
+#include "mbtk_list.h"
+#include "mbtk_utils.h"
+
+#include "time.h"
+
+#define EPOLL_LISTEN_MAX 100
+#define EPOLL_LISTEN_MAX 100
+
+#if 0
+struct
+{
+ uint8 operator[128];
+ uint8 operator[128];
+ uint8 mcc_mnc[10];
+} operator_mcc_mnc =
+{
+ {"China Mobile","CMCC","46000"},
+ {"China Unicom","CU","46001"},
+ {"China Mobile","CMCC","46002"},
+ {"China Telecom","CT","46003"},
+ {"China Mobile","CMCC","46004"},
+ {"China Telecom","CT","46005"},
+ {"China Unicom","CU","46006"},
+ {"China Mobile","CMCC","46007"},
+ {"China Mobile","CMCC","46008"},
+ {"China Unicom","CU","46009"},
+ {"China Telecom","CT","46011"},
+ {NULL, NULL, NULL}
+};
+#endif
+
+static int pack_process(mbtk_info_handle_t* handle, mbtk_info_pack_t* pack)
+{
+ mbtk_info_type_enum info_type = mbtk_info_type_get(pack->info_id);
+ LOG("Type : %s, ID : %s, Result : %s ,Length : %d", type2str(info_type),
+ id2str(pack->info_id),
+ err2str(pack->info_err),
+ pack->data_len);
+ if(0 && pack->data_len > 0)
+ {
+ log_hex("DATA", pack->data, pack->data_len);
+ }
+ // IND Message.
+ if(info_type == MBTK_INFO_TYPE_IND)
+ {
+ if(pack->data_len > 0 && pack->data != NULL) // IND message.
+ {
+ log_hex(id2str(pack->info_id), pack->data, pack->data_len);
+ switch(pack->info_id)
+ {
+ case MBTK_INFO_ID_IND_NET_STATE_CHANGE:
+ {
+ if(handle->net_state_cb)
+ handle->net_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_IND_CALL_STATE_CHANGE:
+ {
+ if(handle->call_state_cb)
+ handle->call_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_IND_SMS_STATE_CHANGE:
+ {
+ if(handle->sms_state_cb)
+ handle->sms_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_IND_RADIO_STATE_CHANGE:
+ {
+ if(handle->radio_state_cb)
+ handle->radio_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_IND_SIM_STATE_CHANGE:
+ {
+ if(handle->sim_state_cb)
+ handle->sim_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ case MBTK_INFO_ID_IND_PDP_STATE_CHANGE:
+ {
+ if(handle->pdp_state_cb)
+ handle->pdp_state_cb(pack->data, pack->data_len);
+ break;
+ }
+ //mbtk wyq for server_ready_status add start
+ case MBTK_INFO_ID_IND_SERVER_STATE_CHANGE:
+ {
+ handle->server_ready_status = 1;
+ LOG("handshake message recv ok.");
+ break;
+ }
+ //mbtk xr for signal_status add start
+ case MBTK_INFO_ID_IND_SIGNAL_STATE_CHANGE:
+ {
+ if(handle->signal_state_cb)
+ handle->signal_state_cb(pack->data, pack->data_len);
+ break;
+ }
+
+ //mbtk wyq for server_ready_status add end
+ default:
+ {
+ LOG("Unknown IND : %d", pack->info_id);
+ break;
+ }
+ }
+ }
+ else // Register IND response.
+ {
+ handle->info_err = pack->info_err;
+ if(pack->info_err == MBTK_INFO_ERR_SUCCESS)
+ {
+ LOG("IND %s register success.", id2str(pack->info_id));
+ }
+ else
+ {
+ LOG("IND %s register fail : %s", id2str(pack->info_id), err2str(pack->info_err));
+ }
+
+ if(handle->is_waitting) {
+ pthread_mutex_lock(&handle->mutex);
+ pthread_cond_signal(&handle->cond);
+ pthread_mutex_unlock(&handle->mutex);
+ }
+ }
+ }
+ else // Response Information.
+ {
+ handle->info_err = pack->info_err;
+
+ // Set data length.
+ // If data change,will change this lenght in mbtk_info_pack_data_get().
+ handle->data_len = pack->data_len;
+ // Copy data buffer,because it will be released.
+ if(handle->data && pack->data && pack->data_len > 0) {
+ memcpy(handle->data, pack->data, handle->data_len);
+ }
+
+ if(handle->is_waitting) {
+ pthread_mutex_lock(&handle->mutex);
+ pthread_cond_signal(&handle->cond);
+ pthread_mutex_unlock(&handle->mutex);
+ }
+
+
+#if 0
+ if(pack->info_err == MBTK_INFO_ERR_SUCCESS)
+ {
+ LOG("REQ %s success.", id2str(pack->info_id));
+#if 0
+ if(pack->data_len > 0)
+ {
+ log_hex("DATA", pack->data, pack->data_len);
+ }
+#endif
+ switch(pack->info_id)
+ {
+ case MBTK_INFO_ID_NET_AVAILABLE_RSP:
+ {
+ mbtk_net_array_info_t* nets = (mbtk_net_array_info_t*)mbtk_info_pack_data_get(pack);
+ if(nets)
+ {
+ mbtk_net_info_t *net = NULL;
+ list_first(nets->net_list);
+ while ((net = (mbtk_net_info_t*) list_next(nets->net_list)))
+ {
+ LOG("NET : %d, %d, %s", net->net_sel_mode, net->net_type, net->plmn);
+ }
+ list_free(nets->net_list);
+ free(nets);
+ }
+ else
+ {
+ LOG("mbtk_info_pack_data_get() fail.");
+ }
+
+ break;
+ }
+ case MBTK_INFO_ID_NET_SEL_MODE_RSP:
+ {
+ mbtk_net_info_t* net = (mbtk_net_info_t*)mbtk_info_pack_data_get(pack);
+ if(net)
+ {
+ LOG("NET : %d, %d, %d", net->net_sel_mode, net->net_type, net->plmn);
+ free(net);
+ }
+ else
+ {
+ LOG("mbtk_info_pack_data_get() fail.");
+ }
+
+ break;
+ }
+ case MBTK_INFO_ID_NET_BAND_RSP:
+ {
+ mbtk_band_info_t* band = (mbtk_band_info_t*)mbtk_info_pack_data_get(pack);
+ if(band) {
+ LOG("BAND : %d, %d, %d, %d, %d", band->net_pref,
+ band->gsm_band,
+ band->umts_band,
+ band->tdlte_band,
+ band->fddlte_band);
+ } else {
+ LOG("mbtk_info_pack_data_get() fail.");
+ }
+
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ LOG("REQ %s fail : %s", id2str(pack->info_id), err2str(pack->info_err));
+ }
+#endif
+ }
+ return 0;
+}
+
+
+static void* info_read_run(void* arg)
+{
+ int epoll_fd = epoll_create(5);
+ if(epoll_fd < 0)
+ {
+ LOG("epoll_create() fail[%d].", errno);
+ return NULL;
+ }
+ mbtk_info_handle_t* handle = (mbtk_info_handle_t*)arg;
+
+ uint32 event = EPOLLIN | EPOLLET;
+ struct epoll_event ev_cli, ev_exit;
+ ev_cli.data.fd = handle->client_fd;
+ ev_cli.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,handle->client_fd,&ev_cli);
+
+ ev_exit.data.fd = handle->exit_fd[0];
+ ev_exit.events = event; //EPOLLIN | EPOLLERR | EPOLLET;
+ epoll_ctl(epoll_fd,EPOLL_CTL_ADD,handle->exit_fd[0],&ev_exit);
+
+ int nready = -1;
+ struct epoll_event epoll_events[EPOLL_LISTEN_MAX];
+ while(1)
+ {
+ nready = epoll_wait(epoll_fd, epoll_events, EPOLL_LISTEN_MAX, -1);
+ if(nready > 0)
+ {
+ int i;
+ for(i = 0; i < nready; i++)
+ {
+ LOG("fd[%d] event = %x",epoll_events[i].data.fd, epoll_events[i].events);
+ if(epoll_events[i].events & EPOLLHUP) // Closed by server.
+ {
+
+ }
+ else if(epoll_events[i].events & EPOLLIN)
+ {
+ if(handle->client_fd == epoll_events[i].data.fd) // Server data arrive.
+ {
+ // Read and process every message.
+ mbtk_info_err_enum err = MBTK_INFO_ERR_SUCCESS;
+ mbtk_info_pack_t **pack = mbtk_info_pack_recv(handle->client_fd, false, &err);
+
+ // Parse packet error,send error response to client.
+ if(pack == NULL)
+ {
+ if(err != MBTK_INFO_ERR_SUCCESS)
+ {
+ LOG("RSP packet error[%s].", err2str(err));
+ }
+ }
+ else
+ {
+ mbtk_info_pack_t** pack_ptr = pack;
+ while(*pack_ptr)
+ {
+ pack_process(handle, *pack_ptr);
+ mbtk_info_pack_free(pack_ptr);
+ pack_ptr++;
+ }
+ free(pack);
+ }
+ }
+ else if(handle->exit_fd[0] == epoll_events[i].data.fd) //
+ {
+ char buff[100] = {0};
+ int len = read(handle->exit_fd[0], buff, 100);
+ if(len > 0) {
+ LOGI("CMD : %s", buff);
+ if(strcmp(buff, "EXIT") == 0) {
+ goto read_thread_exit;
+ } else {
+ LOGD("Unkonw cmd : %s", buff);
+ }
+ } else {
+ LOGE("sock_read() fail.");
+ }
+ }
+ else
+ {
+ LOG("Unknown socket : %d", epoll_events[i].data.fd);
+ }
+ }
+ else
+ {
+ LOG("Unknown event : %x", epoll_events[i].events);
+ }
+ }
+ }
+ else
+ {
+ LOG("epoll_wait() fail[%d].", errno);
+ }
+ }
+
+read_thread_exit:
+ LOGD("info_read thread exit.");
+ return NULL;
+}
+
+#if 0
+static int info_item_get(mbtk_info_handle_t* handle, mbtk_info_id_enum id, void* data)
+{
+ int data_len = 0;
+ if(data == NULL) {
+ LOG("data is null.");
+ return -1;
+ }
+ mbtk_info_pack_t* pack = mbtk_info_pack_creat(id);
+ if(pack == NULL) {
+ LOG("mbtk_info_item_get() fail.");
+ return -1;
+ }
+
+ mbtk_info_pack_send(handle->client_fd, pack);
+ mbtk_info_pack_free(&pack);
+ handle->data = data;
+
+ // Wait for server response.
+ pthread_mutex_lock(&handle->mutex);
+ handle->is_waitting = true;
+ pthread_cond_wait(&handle->cond, &handle->mutex);
+ handle->is_waitting = false;
+ pthread_mutex_unlock(&handle->mutex);
+
+ if(handle->info_err == MBTK_INFO_ERR_SUCCESS)
+ {
+ LOG("REQ %s success.", id2str(id));
+ if(data && handle->data_len > 0) {
+ data_len = handle->data_len;
+ handle->data_len = 0;
+ handle->data = NULL;
+ }
+ return data_len;
+ } else {
+ LOG("REQ %s fail : %s", id2str(id), err2str(handle->info_err));
+ return -1;
+ }
+}
+#endif
+
+/*
+* Return recv data length.
+* -1 : fail.
+*/
+static int info_item_process(mbtk_info_handle_t *handle,
+ mbtk_info_id_enum id,
+ const void *send_buff,
+ int send_buff_len,
+ void *recv_buff)
+{
+ if(handle == NULL/* || ((send_buff == NULL || send_buff_len == 0) && recv_buff == NULL)*/) {
+ LOG("ARG error.");
+ return -1;
+ }
+
+ mbtk_info_pack_t* pack = mbtk_info_pack_creat(id);
+ if(pack == NULL) {
+ return -1;
+ }
+ if(send_buff && send_buff_len > 0) { // Set the data to be sent.
+ // log_hex("data", send_buff, send_buff_len);
+ // mbtk_info_pack_data_set(pack, data, data_len);
+ pack->data_len = (uint16)send_buff_len;
+ pack->data = (const uint8*)send_buff;
+ }
+
+ pthread_mutex_lock(&handle->send_mutex);
+ pthread_mutex_lock(&handle->mutex);
+ handle->is_waitting = true;
+
+ mbtk_info_pack_send(handle->client_fd, pack);
+ mbtk_info_pack_free(&pack);
+
+ if(recv_buff != NULL)
+ handle->data = recv_buff;
+ // Wait for server response.
+ pthread_cond_wait(&handle->cond, &handle->mutex);
+ handle->is_waitting = false;
+ pthread_mutex_unlock(&handle->mutex);
+ if(handle->info_err == MBTK_INFO_ERR_SUCCESS)
+ {
+ LOG("REQ %s success.", id2str(id));
+ int recv_len = 0;
+ if(recv_buff && handle->data_len > 0) {
+ recv_len = handle->data_len;
+ handle->data_len = 0;
+ handle->data = NULL;
+ }
+ pthread_mutex_unlock(&handle->send_mutex);
+
+ return recv_len;
+ } else {
+ LOG("REQ %s fail : %s", id2str(id), err2str(handle->info_err));
+ pthread_mutex_unlock(&handle->send_mutex);
+
+ return -1;
+ }
+}
+
+void mbtk_ril_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_ril_lib");
+}
+
+mbtk_info_handle_t* mbtk_info_handle_get()
+{
+ mbtk_info_handle_t* handle = (mbtk_info_handle_t*)malloc(sizeof(mbtk_info_handle_t));
+ if(!handle)
+ {
+ LOG("malloc() error[%d].", errno);
+ return NULL;
+ }
+ memset(handle, 0, sizeof(mbtk_info_handle_t));
+ handle->client_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
+ if(handle->client_fd < 0)
+ {
+ LOG("socket() fail[%d].", errno);
+ goto error;
+ }
+
+ // Set O_NONBLOCK
+ int flags = fcntl(handle->client_fd, F_GETFL, 0);
+ if (flags < 0)
+ {
+ LOG("Get flags error:%d", errno);
+ goto error;
+ }
+ flags |= O_NONBLOCK;
+ if (fcntl(handle->client_fd, F_SETFL, flags) < 0)
+ {
+ LOG("Set flags error:%d", errno);
+ goto error;
+ }
+
+ struct sockaddr_un cli_addr;
+ memset(&cli_addr, 0, sizeof(cli_addr));
+ cli_addr.sun_family = AF_LOCAL;
+ strcpy(cli_addr.sun_path, SOCK_INFO_PATH);
+ if(connect(handle->client_fd, (struct sockaddr *)&cli_addr, sizeof(cli_addr)))
+ {
+ LOG("connect() fail[%d].", errno);
+ goto error;
+ }
+
+ if(pipe(handle->exit_fd)) {
+ LOG("pipe() fail[%d].", errno);
+ goto error;
+ }
+#if 0
+ pthread_attr_t thread_attr;
+ pthread_attr_init(&thread_attr);
+ if(pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED))
+ {
+ LOG("pthread_attr_setdetachstate() fail.");
+ goto error;
+ }
+
+ if(pthread_create(&(handle->read_thread_id), &thread_attr, info_read_run, handle))
+ {
+ LOG("pthread_create() fail.");
+ goto error;
+ }
+ pthread_attr_destroy(&thread_attr);
+#else
+ if(pthread_create(&(handle->read_thread_id), NULL, info_read_run, handle))
+ {
+ LOG("pthread_create() fail.");
+ goto error;
+ }
+#endif
+
+ pthread_mutex_init(&handle->mutex, NULL);
+#ifndef MBTK_SG_SUPPORT
+ pthread_mutex_init(&handle->send_mutex, NULL);
+#endif
+ pthread_cond_init(&handle->cond, NULL);
+ handle->is_waitting = false;
+
+ //mbtk wyq for server_ready_status add start
+ int timeout = 5;//The wait server timeout by default
+ LOG("wait server handshake message--->.");
+ while(timeout)
+ {
+ if(handle->server_ready_status)
+ {
+ break;
+ }
+ else
+ {
+ sleep(1);
+ timeout--;
+ }
+ }
+
+ if(timeout <= 0)
+ {
+ if(handle->exit_fd[1] > 0)
+ {
+ write(handle->exit_fd[1], "EXIT", 4);
+ }
+ pthread_join(handle->read_thread_id,NULL);
+ LOG("mbtk_info_handle_get() server not ready.");
+ goto error;
+ }
+ else
+ {
+ LOG("mbtk_info_handle_get() server ready ok.");
+ }
+ //mbtk wyq for server_ready_status add end
+ return handle;
+error:
+ if(handle)
+ {
+ if(handle->client_fd > 0)
+ {
+ close(handle->client_fd);
+ }
+ if(handle->exit_fd[0] > 0) {
+ close(handle->exit_fd[0]);
+ }
+ if(handle->exit_fd[1] > 0) {
+ close(handle->exit_fd[1]);
+ }
+ free(handle);
+ handle = NULL;
+ }
+
+ return NULL;
+}
+
+int mbtk_info_handle_free(mbtk_info_handle_t** handle)
+{
+ if(handle == NULL || *handle == NULL)
+ {
+ LOG("Handle is NULL.");
+ return -1;
+ }
+
+ if((*handle)->exit_fd[1] > 0) {
+ write((*handle)->exit_fd[1], "EXIT", 4);
+ }
+
+ // Wait read_thread exit.
+ pthread_join((*handle)->read_thread_id,NULL);
+
+ if((*handle)->exit_fd[0] > 0) {
+ close((*handle)->exit_fd[0]);
+ (*handle)->exit_fd[0] = -1;
+ }
+
+ if((*handle)->exit_fd[1] > 0) {
+ close((*handle)->exit_fd[1]);
+ (*handle)->exit_fd[1] = -1;
+ }
+
+ if((*handle)->client_fd > 0)
+ {
+ close((*handle)->client_fd);
+ (*handle)->client_fd = -1;
+ }
+ free(*handle);
+ *handle = NULL;
+ return 0;
+}
+
+/*
+* Get platform version.
+*/
+int mbtk_version_get(mbtk_info_handle_t* handle, void *version)
+{
+ if(handle == NULL || version == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_VERSION_REQ, NULL, 0, version) > 0) {
+ LOG("Version : %s", version);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform version.
+*/
+int mbtk_model_get(mbtk_info_handle_t* handle, void *model)
+{
+ if(handle == NULL || model == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_MODEL_REQ, NULL, 0, model) > 0) {
+ LOG("Version : %s", model);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform IMEI.
+*/
+int mbtk_imei_get(mbtk_info_handle_t* handle, void *imei)
+{
+ if(handle == NULL || imei == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_IMEI_REQ, NULL, 0, imei) > 0) {
+ LOG("IMEI : %s", imei);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform SN.
+*/
+int mbtk_sn_get(mbtk_info_handle_t* handle, void *sn)
+{
+ if(handle == NULL || sn == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_SN_REQ, NULL, 0, sn) > 0) {
+ LOG("SN : %s", sn);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform MEID.
+*/
+int mbtk_meid_get(mbtk_info_handle_t* handle, void *meid)
+{
+ if(handle == NULL || meid == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_MEID_REQ, NULL, 0, meid) > 0) {
+ LOG("MEID : %s", meid);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Return VoLTE state.
+*/
+int mbtk_volte_state_get(mbtk_info_handle_t* handle, int *volte_state)
+{
+ uint8 state;
+ if(handle == NULL || volte_state == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_VOLTE_REQ, NULL, 0, &state) > 0) {
+ LOG("VoLTE State : %d", state);
+ *volte_state = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set VoLTE state.
+*
+* volte_state:
+* 0 : Close VoLTE.
+* 1 : Open VoLTE.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_volte_state_set(mbtk_info_handle_t* handle, int volte_state)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_DEV_VOLTE_REQ, (uint8*)&volte_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get platform IMSI.
+*/
+int mbtk_imsi_get(mbtk_info_handle_t* handle, void *imsi)
+{
+ if(handle == NULL || imsi == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_IMSI_REQ, NULL, 0, imsi) > 0) {
+ LOG("IMSI : %s", imsi);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform ICCID.
+*/
+int mbtk_iccid_get(mbtk_info_handle_t* handle, void *iccid)
+{
+ if(handle == NULL || iccid == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_ICCID_REQ, NULL, 0, iccid) > 0) {
+ LOG("ICCID : %s", iccid);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get current phone number.
+*/
+int mbtk_phone_number_get(mbtk_info_handle_t* handle, void *phone_number)
+{
+ if(handle == NULL || phone_number == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_PN_REQ, NULL, 0, phone_number) > 0) {
+ LOG("Phone Number : %s", phone_number);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get PIN’s number of remaining retry
+*/
+int mbtk_pin_last_num_get(mbtk_info_handle_t* handle, mbtk_pin_puk_last_times *last_times)
+{
+ if(handle == NULL || last_times == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_PINPUK_TIMES_REQ, NULL, 0, last_times) > 0) {
+ LOG("Sim sim_pin_puk_last_times : %d, %d, %d, %d", last_times->p1_retry,last_times->p2_retry,last_times->puk1_retry,last_times->puk2_retry);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* emable PIN
+*/
+int mbtk_enable_pin(mbtk_info_handle_t* handle, mbtk_enable_pin_info *pin)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_ENABLE_PIN_REQ, pin, sizeof(mbtk_enable_pin_info), NULL) >= 0) {
+ LOG("pin Number : %s", pin->pin_value);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+
+}
+
+/*
+* Verify PIN
+*/
+int mbtk_verify_pin(mbtk_info_handle_t* handle, char *pin)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_PIN_REQ, pin, strlen(pin), NULL) >= 0) {
+ LOG("pin Number : %s", pin);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+
+}
+
+/*
+* Verify PIN
+*/
+int mbtk_change_pin(mbtk_info_handle_t* handle, mbtk_change_pin_info *pin)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_CHANGE_PIN_REQ, pin, sizeof(mbtk_change_pin_info), NULL) >= 0) {
+ LOG("Change PIN : %s -> %s", pin->old_pin_value, pin->new_pin_value);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* unblock_pin
+*/
+int mbtk_unlock_pin(mbtk_info_handle_t* handle, mbtk_unlock_pin_info *pin)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_PUK_REQ, pin, sizeof(mbtk_unlock_pin_info), NULL) >= 0) {
+ LOG("Unlock : %s , %s", pin->pin_value , pin->puk_value);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get plmn list
+*/
+int mbtk_get_plmn_list(mbtk_info_handle_t* handle, mbtk_plmn_info *pin)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_PLMN_REQ, NULL, 0, pin) >= 0) {
+ //LOG("pin Number : %s", pin);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+
+/*
+* Get available network.
+*/
+int mbtk_available_net_get(mbtk_info_handle_t* handle, list_node_t **net_list)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ *net_list = list_create(NULL);
+ if(*net_list == NULL)
+ {
+ LOG("list_create() fail.");
+ return MBTK_INFO_ERR_MEMORY;
+ }
+
+ uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+ int buff_len;
+ if((buff_len = info_item_process(handle, MBTK_INFO_ID_NET_AVAILABLE_REQ, NULL, 0, buff)) > 0) {
+ int i = 0;
+ while (i < buff_len / sizeof(mbtk_net_info_t))
+ {
+ mbtk_net_info_t* net = (mbtk_net_info_t*)malloc(sizeof(mbtk_net_info_t));
+ if(net == NULL)
+ {
+ LOG("malloc() fail.");
+ list_free(*net_list);
+ return MBTK_INFO_ERR_MEMORY;
+ }
+ memcpy(net, buff + i * sizeof(mbtk_net_info_t), sizeof(mbtk_net_info_t));
+ list_add(*net_list, net);
+
+ LOG("NET-%d: %d, %d, %d, %d", i + 1, net->net_sel_mode, net->net_type, net->net_state, net->plmn);
+ i++;
+ }
+
+ return 0;
+ } else {
+ list_free(*net_list);
+ return handle->info_err;
+ }
+}
+
+/*
+* Set network select mode. (+COPS=...)
+*/
+int mbtk_net_sel_mode_set(mbtk_info_handle_t* handle, const mbtk_net_info_t *net)
+{
+ if(handle == NULL || net == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_NET_SEL_MODE_REQ, net, sizeof(mbtk_net_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get network select mode. (+COPS?)
+*/
+int mbtk_net_sel_mode_get(mbtk_info_handle_t* handle, mbtk_net_info_t *net)
+{
+ if(handle == NULL || net == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_SEL_MODE_REQ, NULL, 0, net) > 0) {
+ LOG("NET : %d, %d, %d, %d", net->net_sel_mode, net->net_type, net->net_state, net->plmn);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform support bands.
+*/
+int mbtk_support_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band)
+{
+ uint8 type = 0; // Get support bands.
+ if(handle == NULL || band == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, &type, sizeof(uint8), band) > 0) {
+ LOG("BAND : %d, %d, %d, %d, %d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get platform current bands.
+*/
+int mbtk_current_band_get(mbtk_info_handle_t* handle, mbtk_band_info_t *band)
+{
+ uint8 type = 1; // Get current bands.
+ if(handle == NULL || band == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, &type, sizeof(uint8), band) > 0) {
+ LOG("BAND : %d, %d, %d, %d, %d", band->net_pref, band->gsm_band, band->umts_band, band->tdlte_band, band->fddlte_band);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set platform current bands.
+*/
+int mbtk_current_band_set(mbtk_info_handle_t* handle, const mbtk_band_info_t *band)
+{
+ if(handle == NULL || band == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_NET_BAND_REQ, band, sizeof(mbtk_band_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get current cell infomation.
+*/
+int mbtk_cell_get(mbtk_info_handle_t* handle, mbtk_cell_type_enum *type, list_node_t **cell_list)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ *cell_list = list_create(NULL);
+ if(*cell_list == NULL)
+ {
+ LOG("list_create() fail.");
+ return MBTK_INFO_ERR_MEMORY;
+ }
+
+ uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+ int buff_len;
+ if((buff_len = info_item_process(handle, MBTK_INFO_ID_NET_CELL_REQ, NULL, 0, buff)) > 0) {
+ int i = 0;
+ *type = buff[0]; // Set network type.
+ while (i < (buff_len - sizeof(uint8)) / sizeof(mbtk_cell_info_t))
+ {
+ mbtk_cell_info_t* cell = (mbtk_cell_info_t*)malloc(sizeof(mbtk_cell_info_t));
+ if(cell == NULL)
+ {
+ LOG("malloc() fail.");
+ list_free(*cell_list);
+ return MBTK_INFO_ERR_MEMORY;
+ }
+ memcpy(cell, buff + sizeof(uint8) + i * sizeof(mbtk_cell_info_t), sizeof(mbtk_cell_info_t));
+ list_add(*cell_list, cell);
+
+ // LOG("Cell-%d: %d, %d, %d, %d, %d", i + 1, cell->value1, cell->value2, cell->value3, cell->value4, cell->value5);
+ i++;
+ }
+
+ return 0;
+ } else {
+ list_free(*cell_list);
+ return handle->info_err;
+ }
+}
+/*
+* Set cell info.
+*
+* at*CELL=<mode>,<act>,< band>,<freq>,<cellId>
+* at*cell=2,3,,40936,429 //
+* at*cell=0 //
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_cell_set(mbtk_info_handle_t* handle, char * info, char* response)
+{
+ printf("mbtk_cell_set() info:%s, len:%d",info, strlen(info));
+ char req[128] = {0};
+ if( info_item_process(handle, MBTK_INFO_ID_NET_CELL_REQ, info, strlen(info), req) > 0){
+ memcpy(response, req, strlen(req));
+ return 0;
+ }
+ else{
+ return 0;
+ // return handle->info_err;
+ }
+}
+
+/*
+* Get all APN informations.
+*/
+int mbtk_apn_get(mbtk_info_handle_t* handle, int *apn_num, mbtk_apn_info_t apns[])
+{
+ int len;
+ if(handle == NULL || apn_num == NULL || apns == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ uint8 data[SOCK_MSG_LEN_MAX];
+ if((len = info_item_process(handle, MBTK_INFO_ID_NET_APN_REQ, NULL, 0, data)) > 0) {
+ /*
+ <apn_num[1]><cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>...
+ <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+ */
+ uint8* ptr = data;
+ if(apn_num == NULL || apns == NULL || *apn_num < *ptr) {
+ *apn_num = 0;
+ LOGE("APN array size to not enough.");
+ return -1;
+ }
+ *apn_num = *ptr++;
+ LOG("APN Number : %d", *apn_num);
+ int i = 0;
+ while(i < *apn_num) {
+ memset(&(apns[i]), 0 ,sizeof(mbtk_apn_info_t));
+ apns[i].cid = *ptr++;
+ apns[i].ip_type = (mbtk_ip_type_enum)(*ptr++);
+
+ // apn
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].apn, ptr, len);
+ ptr += len;
+ }
+ // user
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].user, ptr, len);
+ ptr += len;
+ }
+
+ // pass
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].pass, ptr, len);
+ ptr += len;
+ }
+ // auth
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].auth, ptr, len);
+ ptr += len;
+ }
+
+ i++;
+ }
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get all APN informations.
+*/
+int mbtk_qser_apn_get(mbtk_info_handle_t* handle, int *apn_num, mbtk_qser_apn_info_s apns[])
+{
+ int len;
+ if(handle == NULL || apn_num == NULL || apns == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ uint8 data[SOCK_MSG_LEN_MAX];
+ if((len = info_item_process(handle, MBTK_INFO_ID_NET_QSER_APN_REQ, NULL, 0, data)) > 0) {
+ /*
+ <apn_num[1]><cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth[1]><apn_type_len[2]><apn_type_len>...
+ <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth[1]><apn_type_len[2]><apn_type_len>
+ */
+ uint8* ptr = data;
+ if(apn_num == NULL || apns == NULL || *apn_num < *ptr) {
+ *apn_num = 0;
+ LOGE("APN array size to not enough.");
+ return -1;
+ }
+ *apn_num = *ptr++;
+ LOGD("APN Number : %d", *apn_num);
+ int i = 0;
+ while(i < *apn_num) {
+ memset(&(apns[i]), 0x0 ,sizeof(mbtk_qser_apn_info_s));
+ apns[i].cid = *ptr++;
+ apns[i].ip_type = (mbtk_ip_type_enum)(*ptr++);
+
+ // apn
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].apn_name, ptr, len);
+ ptr += len;
+ }
+ // user
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].user_name, ptr, len);
+ ptr += len;
+ }
+
+ // pass
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].user_pass, ptr, len);
+ ptr += len;
+ }
+ // auth
+ apns[i].auth_proto = (mbtk_apn_auth_proto_enum)(*ptr++);
+
+ //apn_type
+ len = byte_2_uint16(ptr, false);
+ ptr += sizeof(uint16);
+ if(len > 0) { // Has APN
+ memcpy(apns[i].apn_type, ptr, len);
+ ptr += len;
+ }
+
+ i++;
+ }
+ }
+ else if(len == 0)
+ {
+ LOGD("get data len : 0.");
+ *apn_num = 0;
+ return 0;
+ }
+ else
+ {
+ return handle->info_err;
+ }
+
+ return 0;
+}
+
+/*
+* qser Set current APN informations.
+*/
+int mbtk_qser_apn_set(mbtk_info_handle_t* handle, mbtk_qser_apn_info_s *apninfo, unsigned char *cid)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ uint8 data[SOCK_MSG_LEN_MAX];
+ memset(data, 0, SOCK_MSG_LEN_MAX);
+ // cid : 2 - 7
+ if(apninfo->req_type != MBTK_APN_REQ_TYPE_ADD && (apninfo->cid < MBTK_APN_CID_MIN || apninfo->cid > MBTK_APN_CID_MAX)) {
+ LOGE("CID error.");
+ return -1;
+ }
+
+ uint8* ptr = data;
+ // <cid[1]><ip_type[1]><req_type[1]><auth[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><apn_type[2]>
+ *ptr++ = (uint8)apninfo->cid;
+ *ptr++ = (uint8)apninfo->ip_type;
+ *ptr++ = (uint8)apninfo->req_type;
+ *ptr++ = (uint8)apninfo->auth_proto;
+ if(str_empty(apninfo->apn_name)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen((char *)apninfo->apn_name), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, apninfo->apn_name, strlen((char *)apninfo->apn_name));
+ ptr += strlen((char *)apninfo->apn_name);
+ }
+ if(str_empty(apninfo->user_name)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen((char *)apninfo->user_name), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, apninfo->user_name, strlen((char *)apninfo->user_name));
+ ptr += strlen((char *)apninfo->user_name);
+ }
+
+ if(str_empty(apninfo->user_pass)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen((char *)apninfo->user_pass), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, apninfo->user_pass, strlen((char *)apninfo->user_pass));
+ ptr += strlen((char *)apninfo->user_pass);
+ }
+
+ if(str_empty(apninfo->apn_type)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ }
+ else
+ {
+ uint16_2_byte((uint16)strlen((char *)apninfo->apn_type), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, apninfo->apn_type, strlen((char *)apninfo->apn_type));
+ ptr += strlen((char *)apninfo->apn_type);
+ }
+
+ if(info_item_process(handle, MBTK_INFO_ID_NET_QSER_APN_REQ, data, ptr - data, (void *)cid) < 0)
+ {
+ return handle->info_err;
+ }
+
+ return 0;
+}
+
+/*
+* Set current APN informations.
+*/
+int mbtk_apn_set(mbtk_info_handle_t* handle, int cid, mbtk_ip_type_enum ip_type, const void* apn_name,
+ const void *user_name, const void *user_pass, const void *auth)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ uint8 data[SOCK_MSG_LEN_MAX];
+ memset(data, 0, SOCK_MSG_LEN_MAX);
+ // cid : 2 - 7
+ if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+ LOGE("CID error.");
+ return -1;
+ }
+ uint8* ptr = data;
+ // <cid[1]><ip_type[1]><apn_len[2]><apn><user_len[2]><user><pass_len[2]><pass><auth_len[2]><auth>
+ *ptr++ = (uint8)cid;
+ *ptr++ = (uint8)ip_type;
+ if(str_empty(apn_name)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen(apn_name), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, apn_name, strlen(apn_name));
+ ptr += strlen(apn_name);
+ }
+ if(str_empty(user_name)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen(user_name), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, user_name, strlen(user_name));
+ ptr += strlen(user_name);
+ }
+
+ if(str_empty(user_pass)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen(user_pass), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, user_pass, strlen(user_pass));
+ ptr += strlen(user_pass);
+ }
+
+ if(str_empty(auth)) {
+ uint16_2_byte((uint16)0, ptr, false);
+ ptr += sizeof(uint16);
+ } else {
+ uint16_2_byte((uint16)strlen(auth), ptr, false);
+ ptr += sizeof(uint16);
+ memcpy(ptr, auth, strlen(auth));
+ ptr += strlen(auth);
+ }
+
+ return info_item_process(handle, MBTK_INFO_ID_NET_APN_REQ, data, ptr - data, NULL) ? handle->info_err : 0;
+}
+
+int mbtk_apn_del(mbtk_info_handle_t* handle, unsigned char profile_idx)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ profile_idx++;
+ if(info_item_process(handle, MBTK_INFO_ID_NET_APN_DEL_REQ, &profile_idx, sizeof(profile_idx), NULL) >= 0)
+ {
+ LOG("profile_idx Number : %d", profile_idx);
+ return 0;
+ }
+ else
+ {
+ return handle->info_err;
+ }
+
+}
+
+/*
+* Start data call.
+*/
+int mbtk_data_call_start(mbtk_info_handle_t* handle, int cid, int auto_conn_interval, bool boot_conn, int timeout)
+{
+ uint8 data[10];
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ memset(data, 0, 10);
+ if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+ LOGE("CID error.");
+ return -1;
+ }
+ uint8* ptr = data;
+ /* <call_type[1]><cid[1]><auto_conn_interval[1]><boot_conn[1]><timeout[1]>
+ call_type : mbtk_data_call_type_enum
+ cid : 2 - 7
+ timeout : second
+ */
+ *ptr++ = (uint8)MBTK_DATA_CALL_START;
+ *ptr++ = (uint8)cid;
+ *ptr++ = (uint8)(auto_conn_interval > 0 ? auto_conn_interval : 0); // 拨号失败后重拨间隔(s)
+ *ptr++ = (uint8)(boot_conn ? 1 : 0); // 开机自动拨号
+ if(timeout <= 0) {
+ *ptr++ = (uint8)MBTK_DATA_CALL_TIMEOUT_DEFAULT;
+ } else {
+ *ptr++ = (uint8)timeout;
+ }
+
+ return info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 5, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Stop data call.
+*/
+int mbtk_data_call_stop(mbtk_info_handle_t* handle, int cid, int timeout)
+{
+ uint8 data[10];
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ memset(data, 0, 10);
+ if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+ LOGE("CID error.");
+ return -1;
+ }
+ uint8* ptr = data;
+ /* <call_type[1]><cid[1]><timeout[1]>
+ call_type : mbtk_data_call_type_enum
+ cid : 2 - 7
+ timeout : second
+ */
+ *ptr++ = (uint8)MBTK_DATA_CALL_STOP;
+ *ptr++ = (uint8)cid;
+ *ptr++ = (uint8)timeout;
+
+ return info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 3, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get data call state.
+*/
+int mbtk_data_call_state_get(mbtk_info_handle_t* handle, int cid, mbtk_ipv4_info_t *ipv4, mbtk_ipv6_info_t *ipv6)
+{
+ uint8 data[10];
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ uint8 recv_buff[SOCK_MSG_LEN_MAX]={0};
+ memset(data, 0, 10);
+ if(cid < MBTK_APN_CID_MIN || cid > MBTK_APN_CID_MAX) {
+ LOGE("CID error.");
+ return -1;
+ }
+ uint8* ptr = data;
+ /* <call_type[1]><cid[1]><timeout[1]>
+ call_type : mbtk_data_call_type_enum
+ cid : 2 - 7
+ timeout : second
+ */
+ *ptr++ = (uint8)MBTK_DATA_CALL_STATE;
+ *ptr++ = (uint8)cid;
+ *ptr++ = (uint8)0;
+
+ if(ipv4) {
+ memset(ipv4, 0, sizeof(mbtk_ipv4_info_t));
+ }
+
+ if(ipv6) {
+ memset(ipv6, 0, sizeof(mbtk_ipv6_info_t));
+ }
+
+ if(info_item_process(handle, MBTK_INFO_ID_NET_DATA_CALL_REQ, data, 3, recv_buff) > 0) {
+ if(recv_buff[0] == 0) { // IPv4 Only.
+ if(ipv4) {
+ memcpy(ipv4, recv_buff + sizeof(uint8), sizeof(mbtk_ipv4_info_t));
+ }
+ } else if(recv_buff[0] == 1) { // IPv6 Only.
+ if(ipv6) {
+ memcpy(ipv6, recv_buff + sizeof(uint8), sizeof(mbtk_ipv6_info_t));
+ }
+ } else if(recv_buff[0] == 2) { // IPv4 and IPv6.
+ if(ipv4) {
+ memcpy(ipv4, recv_buff + sizeof(uint8), sizeof(mbtk_ipv4_info_t));
+ }
+
+ if(ipv6) {
+ memcpy(ipv6, recv_buff + sizeof(uint8) + sizeof(mbtk_ipv4_info_t), sizeof(mbtk_ipv6_info_t));
+ }
+ } else {
+ LOGE("Unknown IP type : %d", recv_buff[0]);
+ return -1;
+ }
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+
+
+/*
+* Get current network signal.
+*/
+int mbtk_net_signal_get(mbtk_info_handle_t* handle, mbtk_signal_info_t *signal)
+{
+ if(handle == NULL || signal == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_SIGNAL_REQ, NULL, 0, signal) > 0) {
+ LOG("Signal : %d, %d, %d, %d, %d, %d, %d", signal->rssi, signal->rxlev, signal->ber, signal->rscp, signal->ecno,
+ signal->rsrq, signal->rsrp);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get current network register information.
+*/
+int mbtk_net_reg_get(mbtk_info_handle_t* handle, mbtk_net_reg_info_t *reg)
+{
+ if(handle == NULL || reg == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_REG_REQ, NULL, 0, reg) > 0) {
+ if(reg->call_state || reg->data_state || reg->ims_state) {
+ LOGD("REG : call_state=%d, data_state=%d, ims_state=%d, net_type=%d, %04x, %08x", reg->call_state, reg->data_state, reg->ims_state, reg->type, reg->lac, reg->ci);
+ } else {
+ LOGE("Net not reg.");
+ }
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get current IMS enable or not.
+*/
+int mbtk_net_ims_get(mbtk_info_handle_t* handle, int* enable)
+{
+ uint8 state;
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_IMS_REQ, NULL, 0, &state) > 0) {
+ LOG("IMS enable : %d", state);
+ *enable = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+
+}
+
+/*
+* Set IMS enable or not. This function takes effect after starting the device.
+*/
+int mbtk_net_ims_set(mbtk_info_handle_t* handle, int enable)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ return info_item_process(handle, MBTK_INFO_ID_NET_IMS_REQ, (uint8*)&enable, sizeof(uint8), NULL) ? handle->info_err : 0;
+
+}
+
+/*
+* Get current network IMS register state.
+*/
+int mbtk_net_ims_reg_state_get(mbtk_info_handle_t* handle, int* reg)
+{
+ uint8 state;
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_IMS_REG_STATE_REQ, NULL, 0, &state) > 0) {
+ LOG("reg type : %d", state);
+ *reg = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+
+/*
+* Get radio state.
+*/
+int mbtk_radio_state_get(mbtk_info_handle_t* handle, int *radio_state)
+{
+ uint8 state;
+ if(handle == NULL || radio_state == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_NET_RADIO_REQ, NULL, 0, &state) > 0) {
+ LOG("Radio state : %d", state);
+ *radio_state = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set radio state.
+*/
+int mbtk_radio_state_set(mbtk_info_handle_t* handle, int radio_state)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_NET_RADIO_REQ, (uint8*)&radio_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get time type.
+*/
+int mbtk_time_get(mbtk_info_handle_t* handle, int *time_type)
+{
+ uint8 state;
+ if(handle == NULL || time_type == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ, NULL, 0, &state) > 0) {
+ LOG("Time type : %d", state);
+ *time_type = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+*Get Absolute time
+*"23/05/24 06:09:32 +32 00"
+*/
+int mbtk_get_abs_time(char *time_str, time_t *time_out)
+{
+ struct tm tm_;
+
+ char *ptr = strstr(time_str + 10, " ");
+ *ptr = '\0';
+
+ LOGD("time : \"%s\"", time_str);
+#if 1
+ if(strptime(time_str, "%y/%m/%d %T", &tm_) == NULL) {
+ LOGE("strptime() fail.");
+ return -1;
+ }
+#else
+ int year, month, day, hour, minute,second,time_zone;
+ if(strstr(time_str, "+")) {
+ sscanf(time_str, "%d/%d/%d %d:%d:%d +%d",&year,&month,&day,&hour,&minute,&second,&time_zone);
+ } else if(strstr(time_str, "-")) {
+ sscanf(time_str, "%d/%d/%d %d:%d:%d -%d",&year,&month,&day,&hour,&minute,&second,&time_zone);
+ } else {
+ LOGE("Time format error:%s", time_str);
+ return -1;
+ }
+
+ // 1970+
+ if(year < 70) { // 20xx
+ tm_.tm_year = 2000 + year;
+ } else { // 19xx
+ tm_.tm_year = 1900 + year;
+ }
+ tm_.tm_mon = month - 1;
+ tm_.tm_mday = day;
+ tm_.tm_hour = hour;
+ tm_.tm_min = minute;
+ tm_.tm_sec = second;
+ tm_.tm_isdst = 0;
+#endif
+
+ time_t timeStamp = mktime(&tm_);
+ LOGD("tm_.tm_year = %d,tm_.tm_mon = %d,tm_.tm_mday = %d,tm_.tm_hour = %d,tm_.tm_min = %d,tm_.tm_sec = %d,tm_.tm_isdst = %d",tm_.tm_year,tm_.tm_mon,tm_.tm_mday,tm_.tm_hour,tm_.tm_min,tm_.tm_sec,tm_.tm_isdst);
+ LOGD("time = %ld,%x", timeStamp,timeStamp);
+ *time_out = timeStamp;
+
+ return 0;
+}
+
+/*
+* Get time type.
+* "23/05/24,06:09:32+32" -> "23/05/24 06:09:32 +32 00"
+*/
+int mbtk_net_time_get(mbtk_info_handle_t* handle, char* time_str)
+{
+ uint8 buff[SOCK_MSG_LEN_MAX] = {0};
+ if(handle == NULL || time_str == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ //printf("mbtk_net_time_get begin info_item_process\n");
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_CELL_TIME_REQ, NULL, 0, buff) > 0) {
+ memcpy(time_str,buff,strlen(buff));
+
+ uint8 *temp = strstr(time_str, ",");
+ if(temp) {
+ *temp = ' '; // ',' -> ' '
+
+ temp = strstr(time_str, "+");
+ if(temp == NULL) {
+ temp = strstr(time_str, "-");
+ }
+
+ if(temp) {
+ // Copy +XX or -XX
+ uint8 *last_ptr = temp + strlen(temp) + 1;
+ while(last_ptr > temp) {
+ *last_ptr = *(last_ptr - 1);
+ last_ptr--;
+ }
+
+ *last_ptr = ' ';
+
+ memcpy(temp + strlen(temp), "00", 2);
+
+ LOGD("%s -> %s", buff, time_str);
+ return 0;
+ } else {
+ LOGE("Time error:%s",buff);
+ return MBTK_INFO_ERR_TIME_FORMAT;
+ }
+ } else {
+ LOGE("Time error:%s",buff);
+ return MBTK_INFO_ERR_TIME_FORMAT;
+ }
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set time.
+*
+* time_type:
+* 0: Cell time
+* 1: NTP time
+* 2: User time
+* time_str: "YYYY-MM-DD HH:MM:SS"
+*/
+int mbtk_time_set(mbtk_info_handle_t* handle, mbtk_time_type_enum time_type, char* time_str)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ uint8 buffer[100] = {0};
+ buffer[0] = (uint8)time_type;
+ if(time_type == MBTK_TIME_TYPE_USER) {
+ if(!str_empty(time_str)) {
+ memcpy(buffer + sizeof(uint8), time_str, strlen(time_str));
+ return info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ,
+ buffer, sizeof(uint8) + strlen(time_str), NULL) ? handle->info_err : 0;
+ } else {
+ return -1;
+ }
+ } else {
+ return info_item_process(handle, MBTK_INFO_ID_DEV_TIME_REQ,
+ buffer, sizeof(uint8), NULL) ? handle->info_err : 0;
+ }
+}
+
+/*
+* Return sms cmgf.
+*/
+int mbtk_sms_cmgf_get(mbtk_info_handle_t* handle, int *volte_state)
+{
+ uint8 state;
+ if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGF_REQ, NULL, 0, &state) > 0) {
+ LOG("mbtk_sms_cmgf_get()-----------sms cmgf : %d", state);
+ *volte_state = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set sms cmgf.
+*
+* volte_state:
+* 0 : PDU mode.
+* 1 : text mode.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgf_set(mbtk_info_handle_t* handle, int mode)
+{
+ printf("mbtk_sms_cmgf_set()--------mode=:%d, len:%d", mode, sizeof(uint8));
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CMGF_REQ, (uint8*)&mode, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cmgs.
+*
+if PDU mode (+CMGF=0):
++CMGS=<length><CR>
+PDU is given<ctrl-Z/ESC>
+
+if text mode (+CMGF=1):
++CMGS=<da>[,<toda>]<CR>
+text is entered<ctrl-Z/ESC>
+
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgs_set(mbtk_info_handle_t* handle, char * cmgs, char *resp)
+{
+ printf("mbtk_sms_cmgs_set(1)--------cmgs=:%s, len:%d", cmgs, strlen(cmgs));
+// char req[20] = {0}
+ if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGS_REQ, cmgs, strlen(cmgs), resp) > 0){
+ printf("resp:%s\n", resp);
+ return 0;
+ }else{
+ return handle->info_err;
+ }
+}
+
+/*
+* Set sms cmgw.
+*
+if text mode (+CMGF=1):
++CMGW=<oa/da>[,<tooa/toda>[,<stat>]]
+<CR>
+text is entered<ctrl-Z/ESC>
+if PDU mode (+CMGF=0):
++CMGW=<length>[,<stat>]<CR>PDU is
+given<ctrl-Z/ESC>
+
+*/
+
+int mbtk_sms_cmgw_set(mbtk_info_handle_t* handle, char * cmgw, char *resp)
+{
+ printf("mbtk_sms_cmgw_set() ----------cmgw:%s, len:%d", cmgw, strlen(cmgw));
+ if(info_item_process(handle, MBTK_INFO_ID_SMS_CMGW_REQ, cmgw, strlen(cmgw), resp) > 0){
+ printf("resp:%s\n", resp);
+ return 0;
+ }else{
+ return handle->info_err;
+ }
+}
+
+/*
+* Set sms cmgd.
+*
+* +CMGD=<index>[,<delflag>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgd_set(mbtk_info_handle_t* handle, char * cmdg)
+{
+ printf("mbtk_sms_cmgd_set() cmdg:%s, len:%d",cmdg, strlen(cmdg));
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CMGD_REQ, cmdg, strlen(cmdg), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get sms cmgd.
+*
+* +CMGD: (XXX,XXX)(0-4)
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgd_get(mbtk_info_handle_t* handle, char * cmdg)
+{
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CMGD_REQ, NULL, 0, cmdg) ? handle->info_err : 0;
+}
+
+
+/*
+* Set sms cmgl.
+*
+* AT+CMGL[=<stat>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgl_set(mbtk_info_handle_t* handle, char * cmgl, char *resp)
+{
+ printf("0mbtk_sms_cmgl_set() cmgl:%s, len:%d\n",cmgl, strlen(cmgl));
+ char reg[5*1024] ={0};
+ if( info_item_process(handle, MBTK_INFO_ID_SMS_CMGL_REQ, cmgl, strlen(cmgl), reg) > 0){
+ printf("len:%d , reg:%s\n", strlen(reg), reg);
+ // memcpy(resp, reg, strlen(reg));
+ return 0;
+ }else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Return sms csca.
+*/
+int mbtk_sms_csca_get(mbtk_info_handle_t* handle, char *buf)
+{
+ // char state;
+ if(info_item_process(handle, MBTK_INFO_ID_SMS_CSCA_REQ, NULL, 0, buf) > 0) {
+ LOG("mbtk_sms_csca_get()-----------sms csca : %s", buf);
+ // *volte_state = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set sms csca.
+*
+* AT+CSCA=<number> [,<type>]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_csca_set(mbtk_info_handle_t* handle, char * csca)
+{
+ printf("mbtk_sms_csca_set() csca:%s, len:%d",csca, strlen(csca));
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CSCA_REQ, csca, strlen(csca), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms csmp.
+*
+* AT+CSMP=[<fo>[,<vp>[,<pid>[,<dcs>]]]]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_csmp_set(mbtk_info_handle_t* handle, char * csmp)
+{
+ printf("mbtk_sms_csmp_set() csmp:%s, len:%d",csmp, strlen(csmp));
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CSMP_REQ, csmp, strlen(csmp), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cscb.
+*
+* AT+CSCB=<[<mode>[,<mids>[,<dcss>]]]>
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cscb_set(mbtk_info_handle_t* handle, char * cscb)
+{
+ printf("mbtk_sms_cscb_set() cscb:%s, len:%d",cscb, strlen(cscb));
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CSCB_REQ, cscb, strlen(cscb), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set sms cnmi.
+*
+at+cnmi=1,2
+
+OK
+if sending fails:
++CMS ERROR: <err>
+*/
+int mbtk_sms_cnmi_set(mbtk_info_handle_t* handle)
+{
+ printf("mbtk_sms_cnmi_set()------------start\n");
+
+ return info_item_process(handle, MBTK_INFO_ID_SMS_CNMI_REQ, NULL, 0, NULL)? handle->info_err : 0;
+}
+
+/*
+* Set sms cmss.
+*
++CMSS=<index>[,<da>[,<toda>]]
+
+if sending successful:
++CMSS: <mr>
+OK
+if sending fails:
++CMS ERROR: <err>
+*/
+int mbtk_sms_cmss_set(mbtk_info_handle_t* handle, char * cmss, char *resp)
+{
+ printf("mbtk_sms_cmss_set()------------cmss:%s, len:%d", cmss, strlen(cmss));
+ if( info_item_process(handle, MBTK_INFO_ID_SMS_CMSS_REQ, cmss, strlen(cmss), resp) > 0){
+ printf("resp:%s\n", resp);
+ return 0;
+ }else{
+ return handle->info_err;
+ }
+}
+
+/*
+* Return sms cmgf.
+*/
+int mbtk_sms_cpms_get(mbtk_info_handle_t* handle, char * mem)
+{
+ char req[128] = {0};
+ if(info_item_process(handle, MBTK_INFO_ID_SMS_CPMS_REQ, NULL, 0, &req) > 0) {
+ LOG("mbtk_sms_cpms_get() req : %s, strlen(mem_ptr):%d\n", req, strlen(req));
+ memcpy(mem, req, strlen(req));
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+
+/*
+* Set sms cpms.
+*
+* AT+CPMS=<mem1>[,<mem2>[,<mem3>]]
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cpms_set(mbtk_info_handle_t* handle, char * mem, char* response)
+{
+ printf("mbtk_sms_cpms_set() mem:%s, len:%d",mem, strlen(mem));
+ char req[128] = {0};
+ if( info_item_process(handle, MBTK_INFO_ID_SMS_CPMS_REQ, mem, strlen(mem), req) > 0){
+ memcpy(response, req, strlen(req));
+ return 0;
+ }
+ else{
+ return handle->info_err;
+ }
+}
+
+/*
+* Set sms cm.
+*
+* +CMGR=<index>
+
+if PDU mode (+CMGF=0) ��command successful:
++CMGR: <stat>,[<alpha>],<length><CR><LF><pdu>
+OK
+if text mode (+CMGF=1), command successful and SMS-DELIVER:
++CMGR:<stat>,<oa>,[<alpha>],<scts>[,<tooa>,<fo>,<pid>,<dcs
+>, <sca>,<tosca>,<length>]<CR><LF><data>
+OK
+if text mode (+CMGF=1), command successful and SMS-SUBMIT:
++CMGR:
+<stat>,<da>,[<alpha>][,<toda>,<fo>,<pid>,<dcs>,[<vp>],
+<sca>,<tosca>,<length>]<CR><LF><data>
+OK
+otherwise:
++CMS ERROR: <err>
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_sms_cmgr_set(mbtk_info_handle_t* handle, int index, char *resp)
+{
+ printf("mbtk_sms_cmgr_set() --------------index:%d",index);
+ if( info_item_process(handle, MBTK_INFO_ID_SMS_CMGR_REQ, (uint8*)&index, sizeof(uint8), resp) > 0){
+ printf("resp:%s\n", resp);
+ return 0;
+ }else{
+ return handle->info_err;
+ }
+}
+
+
+/*
+* Get sim state.
+*/
+int mbtk_sim_state_get(mbtk_info_handle_t* handle, mbtk_sim_state_enum *sim_state)
+{
+ uint8 state;
+ if(handle == NULL || sim_state == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_STATE_REQ, NULL, 0, &state) > 0) {
+ *sim_state = (mbtk_sim_state_enum)state;
+ LOG("Sim state : %d", *sim_state);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get sim card type.
+*/
+int mbtk_sim_card_type_get(mbtk_info_handle_t* handle, mbtk_sim_card_type_enum *sim_card_type)
+{
+ uint8 state;
+ if(handle == NULL || sim_card_type == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_SIM_STYPE_REQ, NULL, 0, &state) > 0) {
+ *sim_card_type = (mbtk_sim_card_type_enum)state;
+ LOG("Sim sim_card_type : %d", *sim_card_type);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Get system temperature.
+*
+* type[IN]:
+* 0: Soc temperature.
+* 1: RF temperature.
+* temp[OUT]:
+* temperature in celsius.
+*/
+int mbtk_temp_get(mbtk_info_handle_t* handle, int type, mbtk_thermal_info_t* temp)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(type != 0 && type != 1)
+ {
+ return -1;
+ }
+
+ uint8 temp_type = (uint8)type;
+
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_TEMP_REQ, &temp_type, sizeof(uint8), temp) > 0) {
+
+ LOG("Temperature : %d", temp->ther);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+
+ return 0;
+}
+
+
+/*
+* Set sim power state.
+* power:
+* 0: Sim power off.
+* 1: Sim power on.
+*/
+int mbtk_sim_power_set(int power)
+{
+ if(power != 0 && power != 1)
+ {
+ return -1;
+ }
+
+ // /sys/devices/virtual/usim_event/usim0/send_event
+ char cmd[100] = {0};
+ sprintf(cmd, "echo %d > /sys/devices/virtual/usim_event/usim0/send_event", power ? 0 : 1);
+ system(cmd);
+
+ return 0;
+}
+
+/*
+* System power.
+* type:
+* 0: Reboot system.
+* 1: Poweroff system.
+* 2: Halt system.
+*/
+int mbtk_system_reboot(int type)
+{
+ if(type != 0 && type != 1 && type != 2)
+ {
+ return -1;
+ }
+
+ switch(type) {
+ case 0: {
+ system("reboot");
+ break;
+ }
+ case 1: {
+ system("poweroff");
+ break;
+ }
+ case 2: {
+ system("halt");
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+* set modem fun
+*
+*/
+int mbtk_set_modem_fun(mbtk_info_handle_t* handle, mbtk_modem_info_t *info)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_DEV_MODEM_REQ, info, sizeof(mbtk_modem_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* get modem fun
+*
+*/
+int mbtk_get_modem_fun(mbtk_info_handle_t* handle, int* fun)
+{
+ uint8 state;
+ if(handle == NULL || fun == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_DEV_MODEM_REQ, NULL, 0, &state) > 0) {
+ LOG("modem type : %d", state);
+ *fun = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* call_start
+*
+*/
+int mbtk_call_start(mbtk_info_handle_t* handle, char* phone_number)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(str_empty(phone_number))
+ return -1;
+
+ return info_item_process(handle, MBTK_INFO_ID_CALL_START_REQ,
+ phone_number, strlen(phone_number), NULL) ? handle->info_err : 0;
+}
+/*
+* Answer the phone call.
+*
+*/
+int mbtk_call_answer(mbtk_info_handle_t* handle)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_ANSWER_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up all call.
+*
+*/
+int mbtk_call_hang(mbtk_info_handle_t* handle)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up a call.
+*
+*/
+int mbtk_a_call_hang(mbtk_info_handle_t* handle, int phone_id)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_A_REQ, (uint8*)&phone_id, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up waiting or background call.
+*
+*/
+int mbtk_waiting_or_background_call_hang(mbtk_info_handle_t* handle)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_B_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Hang up foreground resume background call.
+*
+*/
+int mbtk_foreground_resume_background_call_hang(mbtk_info_handle_t* handle)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_HANGUP_C_REQ, NULL, 0, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Get current call phone number.
+*/
+int mbtk_call_reg_get(mbtk_info_handle_t* handle, mbtk_call_info_t *reg)
+{
+ if(info_item_process(handle, MBTK_INFO_ID_CALL_WAITIN_REQ, NULL, 0, reg) > 0) {
+ LOG("CLCC : %d, %d, %d, %d, %d, %s, %d", reg->dir1, reg->dir, reg->state, reg->mode, reg->mpty, reg->phone_number, reg->type);
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Return mute state.
+*/
+int mbtk_mute_state_get(mbtk_info_handle_t* handle, int *mute_state)
+{
+ uint8 state;
+ if(info_item_process(handle, MBTK_INFO_ID_CALL_MUTE_REQ, NULL, 0, &state) > 0) {
+ LOG("Mute State : %d", state);
+ *mute_state = state;
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* Set mute state.
+*
+* mute_state:
+* 0 : of mute.
+* 1 : on mute.
+*
+* Restarting takes effect after execution.
+*/
+int mbtk_mute_state_set(mbtk_info_handle_t* handle, int mute_state)
+{
+ return info_item_process(handle, MBTK_INFO_ID_CALL_MUTE_REQ, (uint8*)&mute_state, sizeof(uint8), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set wakeup state.
+*
+* wakeup_state:(0~31)
+* 0 : means resume all
+* 1~31 means suspend
+* Control the active reporting of some platform modems to reduce wakeup
+*/
+
+int mbtk_wakeup_state_set(mbtk_info_handle_t* handle, uint32 wakeup_state)
+{
+ return info_item_process(handle, MBTK_INFO_ID_WAKEUP_STA_REQ, (uint32*)&wakeup_state, sizeof(uint32), NULL) ? handle->info_err : 0;
+}
+
+/*
+* oos get.
+*/
+int mbtk_oos_get(mbtk_info_handle_t* handle, mbtk_oos_info *oos_info)
+{
+ if(info_item_process(handle, MBTK_INFO_ID_OOS_STA_REQ, NULL, 0, oos_info) > 0) {
+ return 0;
+ } else {
+ return handle->info_err;
+ }
+}
+
+/*
+* oos set .
+*/
+int mbtk_oos_set(mbtk_info_handle_t* handle, mbtk_oos_info *oos_info)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ return info_item_process(handle, MBTK_INFO_ID_OOS_STA_REQ, oos_info, sizeof(mbtk_oos_info), NULL) ? handle->info_err : 0;
+}
+
+
+/*
+* Set DTMF character.
+*
+*/
+int mbtk_dtmf_send(mbtk_info_handle_t* handle, mbtk_call_dtmf_info_t *dtmf_character)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_CALL_DTMF_REQ,
+ dtmf_character, sizeof(mbtk_call_dtmf_info_t), NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set net led.
+*
+*/
+int mbtk_led_set(mbtk_info_handle_t* handle, mbtk_led_type type, mbtk_led_status status)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ char buff[3] = {0};
+ if(type == MBTK_LED_TYPE_NET)
+ {
+ buff[0] = 0;
+ }
+ else
+ {
+ buff[0] = 1;
+ }
+
+ if(status == MBTK_LED_STATUS_CLOSE)
+ {
+ buff[1] = 0;
+ }
+ else
+ {
+ buff[1] = 1;
+ }
+ return info_item_process(handle, MBTK_INFO_ID_LED_REQ, buff, 2, NULL) ? handle->info_err : 0;
+}
+
+/*
+* Set pdp state change callback function.
+*/
+int mbtk_pdp_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_PDP_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->pdp_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set network state change callback function.
+*/
+int mbtk_net_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_NET_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->net_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set call state change callback function.
+*/
+int mbtk_call_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_CALL_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->call_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set sms state change callback function.
+*/
+int mbtk_sms_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_SMS_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->sms_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set radio state change callback function.
+*/
+int mbtk_radio_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_RADIO_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->radio_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set sim state change callback function.
+*/
+int mbtk_sim_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_SIM_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->sim_state_cb = cb;
+ return 0;
+ }
+}
+
+/*
+* Set signal state change callback function.
+*/
+int mbtk_signal_state_change_cb_reg(mbtk_info_handle_t* handle, mbtk_info_callback_func cb)
+{
+ if(handle == NULL)
+ {
+ LOGE("ARG error.");
+ return -1;
+ }
+ if(info_item_process(handle, MBTK_INFO_ID_IND_SIGNAL_STATE_CHANGE, NULL, 0, NULL) < 0) {
+ return handle->info_err;
+ } else {
+ handle->signal_state_cb = cb;
+ return 0;
+ }
+}
+
diff --git a/mbtk/libmbtk_lib/ril/mbtk_pdu_sms.c b/mbtk/libmbtk_lib/ril/mbtk_pdu_sms.c
new file mode 100755
index 0000000..5825cb6
--- /dev/null
+++ b/mbtk/libmbtk_lib/ril/mbtk_pdu_sms.c
@@ -0,0 +1,1086 @@
+//
+// Created by hitmoon on 15-12-9.
+//
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "mbtk_pdu_sms.h"
+#include "mbtk_alphabet.h"
+
+#define SUB_STR_SIZE 512
+char temp[SUB_STR_SIZE];
+
+// some constant
+
+//长短信信息元素参考号
+enum EnumCSMIEI mCSMIEI;
+// 服务中心地址
+char *mSCA;
+// 请求状态报告
+bool mSRR;
+// 拒绝副本
+bool mRD;
+// 短信有效期
+char *mVP;
+// 长短信信息元素消息参考号
+int mCSMMR;
+
+// initialize PDU constants
+void sms_init()
+{
+ mCSMMR = 0;
+ mRD = false;
+ mSRR = false;
+ mSCA = "";
+ mVP = "";
+ mCSMIEI = BIT8MIEI;
+}
+
+
+char *sub_str(const char *str, int start, int size) {
+ memset(temp, '\0', SUB_STR_SIZE);
+ if (size > 0)
+ strncpy(temp, str + start, size);
+ else if (size < 0)
+ strcpy(temp, str + start);
+
+ return temp;
+}
+
+struct SMS_Struct PDUDecoding(const char *data) {
+
+ struct SMS_Struct sms;
+ int end_index;
+ int PDUType;
+ // 短信中心
+ sms.SCA = SCADecoding(data, &end_index);
+
+ // 协议数据单元类型
+ PDUType = strtol(sub_str(data, end_index, 2), NULL, 16);
+ end_index += 2;
+
+ sms.RP = PDUType & (1 << 7) ? true : false; // 应答路径
+ sms.UDHI = PDUType & (1 << 6) ? true : false; // 用户数据头标识
+ sms.SRI = PDUType & (1 << 5) ? true : false; // 状态报告指示
+ sms.MMS = PDUType & (1 << 2) ? false : true; // 更多信息发送
+ sms.MTI = PDUType & 3; // 信息类型指示
+
+ // 发送方SME的地址
+ sms.OA = OADecoding(data, end_index, &end_index);
+
+ // 协议标识
+ sms.PID = strtol(sub_str(data, end_index, 2), NULL, 16);
+ end_index += 2;
+
+ // 数据编码方案
+ int DCSType = strtol(sub_str(data, end_index, 2), NULL, 16);
+ end_index += 2;
+
+ // 文本压缩指示
+ sms.TC = DCSType & (1 << 5);
+ // 编码字符集
+ sms.DCS = (enum EnumDCS) ((DCSType >> 2) & 3);
+
+ if (DCSType & (1 << 4)) {
+ // 信息类型信息 0:立即显示 1:移动设备特定类型 2:SIM特定类型 3:终端设备特定类型
+ sms.MC = DCSType & 3;
+ }
+ else {
+ // 不含信息类型信息
+ sms.MC = -1;
+ }
+ // 服务中心时间戳(BCD编码)
+ sms.SCTS = SCTSDecoding(data, end_index);
+ end_index += 14;
+
+ // 用户数据头
+ if (sms.UDHI) {
+ sms.UDH = UDHDecoding(data, end_index + 2);
+ }
+ else {
+ sms.UDH = NULL;
+ }
+
+ // 用户数据
+ sms.UD = UserDataDecoding(data, end_index, sms.UDHI, sms.DCS);
+
+ return sms;
+}
+
+
+char *SCADecoding(const char *data, int *EndIndex) {
+ int len;
+
+ char *result;
+ char *buf;
+ int i = 0;
+
+ len = strtol(sub_str(data, 0, 2), NULL, 16);
+ if (len == 0) {
+ *EndIndex = 2;
+ return NULL;
+ }
+
+ *EndIndex = (len + 1) * 2;
+
+ result = (char *) malloc(sizeof(char) * len * 2);
+ //wmemset(result, '0', sizeof(char) * (len * 2 + 1));
+
+ buf = result;
+ len *= 2;
+
+ // 服务中心地址类型
+ if (strncmp(data + 2, "91", 2) == 0) {
+ sprintf(buf++, "+");
+ }
+
+ // 服务中心地
+
+ for (i = 4; i < *EndIndex; i += 2) {
+ sprintf(buf++, "%c", data[i + 1]);
+ sprintf(buf++, "%c", data[i]);
+ }
+
+ // 去掉填充的 'F'
+ if (result[strlen(result) - 1] == L'F') {
+ result[strlen(result) - 1] = L'\0';
+ }
+
+ return result;
+}
+
+char *OADecoding(const char *data, int index, int *EndIndex) {
+ int len;
+ char *result, *buf;
+
+ len = strtol(sub_str(data, index, 2), NULL, 16);
+
+ if (len == 0) {
+ *EndIndex = index + 2;
+ return NULL;
+ }
+
+ *EndIndex = index + 4 + len;
+
+ result = (char *) malloc(sizeof(char) * (len + 2));
+ //wmemset(result, 0, sizeof(char) * (len + 1));
+ buf = result;
+
+ if (strncmp(data + index + 2, "91", 2) == 0) {
+ sprintf(buf++, "+");
+ }
+
+ // 电话号码
+ int i = 0;
+ for (i = 0; i < len; i += 2) {
+ sprintf(buf++, "%c", data[index + i + 5]);
+ sprintf(buf++, "%c", data[index + i + 4]);
+
+ }
+
+ if (len % 2 != 0) {
+ result[strlen(result) - 1] = '\0';
+ (*EndIndex)++;
+ }
+ return result;
+}
+
+char *SCTSDecoding(const char *data, int index) {
+
+ char *result;
+
+ result = (char *) malloc(sizeof(char) * 32);
+ sprintf(result, "20%02d-%02d-%02d %02d:%02d:%02d",
+ BCDDecoding(data, index, 0), // 年
+ BCDDecoding(data, index + 2, 0), // 月
+ BCDDecoding(data, index + 4, 0), // 日
+ BCDDecoding(data, index + 6, 0), // 时
+ BCDDecoding(data, index + 8, 0), // 分
+ BCDDecoding(data, index + 10, 0) // 秒
+
+ );
+ return result;
+}
+
+int BCDDecoding(const char *data, int index, bool isMSB) {
+
+ int n1, n10;
+
+ n1 = strtol(sub_str(data, index, 1), NULL, 10);
+ n10 = strtol(sub_str(data, index + 1, 1), NULL, 10);
+
+ if (isMSB) {
+ if (n10 >= 8)
+ return -((n10 - 8) * 10 + n1); // 负值
+ else
+ return n10 * 10 + n1;
+ }
+ else {
+ return n10 * 10 + n1;
+ }
+}
+
+struct UDHS *UDHDecoding(const char *data, int index) {
+
+ int len;
+ struct UDHS *result;
+
+ len = strtol(sub_str(data, index, 2), NULL, 16);
+ index += 2;
+ int i = 0;
+
+ result = (struct UDHS *) malloc(sizeof(struct UDHS));
+ result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH) * len);
+ result->count = 0;
+ memset(result->UDH, 0, sizeof(struct PDUUDH) * len);
+
+ while (i < len) {
+ // 信息元素标识(Information Element Identifier
+ char IEI = strtol(sub_str(data, index, 2), NULL, 16);
+ index += 2;
+ // 信息元素数据长度(Length of Information Element)
+ int IEDL = strtol(sub_str(data, index, 2), NULL, 16);
+ index += 2;
+ // 信息元素数据(Information Element Data)
+ char *IED = (char *) malloc(sizeof(char) * (IEDL + 1));
+ int j = 0;
+ for (j = 0; j < IEDL; j++) {
+ IED[j] = strtol(sub_str(data, index, 2), NULL, 16);
+ index += 2;
+ }
+ result->UDH[result->count].IEI = IEI;
+ result->UDH[result->count].IED = IED;
+ result->count++;
+ i += IEDL + 2;
+ }
+
+ return result;
+}
+
+char *UserDataDecoding(const char *data, int index, bool UDHI, enum EnumDCS dcs) {
+ char *result = NULL;
+ char *buf;
+
+ // 用户数据区长度
+ int UDL = strtol(sub_str(data, index, 2), NULL, 16);
+ index += 2;
+
+ // 跳过用户数据头
+ int UDHL = 0;
+ if (UDHI) {
+ // 用户数据头长度
+ UDHL = strtol(sub_str(data, index, 2), NULL, 16);
+ UDHL++;
+ index += UDHL << 1;
+
+ }
+
+ // 获取用户数据
+ if (dcs == UCS2) {
+ int len = (UDL - UDHL) >> 1;
+ int utf8_len;
+
+ result = (char *) malloc(sizeof(char) * (len * 3));
+ buf = result;
+ u_int32_t code[2];
+
+ int i = 0;
+ for (i = 0; i < len; i++) {
+ code[0] = strtol(sub_str(data, (i << 2) + index, 4), NULL, 16);
+ code[1] = 0;
+ utf32toutf8((wchar_t*)code, (unsigned char*)buf, len * 3, &utf8_len);
+ buf += utf8_len;
+ }
+
+ buf[0] = '\0';
+ return result;
+ }
+ else if (dcs == BIT7) {
+ int Septets = UDL - (UDHL * 8 + 6) / 7; // 7-Bit编码字符数
+
+ int FillBits = (UDHL * 8 + 6) / 7 * 7 - UDHL * 8; // 填充位数
+ return BIT7Decoding(BIT7Unpack(data, index, Septets, FillBits), Septets);
+ }
+ else {// 8Bit编码
+ // 获取数据长度
+ UDL -= UDHL;
+ result = (char *) malloc(sizeof(char) * (UDL + 1));
+ int i = 0;
+ for (i = 0; i < UDL; i++) {
+ result[i] = strtol(sub_str(data, (i << 1) + index, 2), NULL, 16);
+ }
+ return result;
+ }
+
+ return "Error!";
+}
+
+char *BIT7Unpack(const char *data, int index, int Septets, int FillBits) {
+ char *result;
+
+ result = (char *) malloc(sizeof(char) * (Septets + 1));
+ // 每8个7-Bit编码字符存放到7个字节
+ int PackLen = (Septets * 7 + FillBits + 7) / 8;
+ int n = 0;
+ int left = 0;
+
+// printf("Unapck data = %s\n", data + index);
+// printf("Septets = %d\n", Septets);
+// printf("pack len = %d\n", PackLen);
+// printf("fillbits = %d\n", FillBits);
+
+ int i = 0;
+ for (i = 0; i < PackLen; i++) {
+
+ int Order = (i + (7 - FillBits)) % 7;
+ int Value = strtol(sub_str(data, (i << 1) + index, 2), NULL, 16);
+ if (i != 0 || FillBits == 0) {
+ result[n++] = ((Value << Order) + left) & 0x7F;
+ }
+// printf("left = %d, i = %d, order = %d, value = %d\n", left, i, Order, Value);
+// printf("result[%d] = %d\n", n - 1, result[n - 1]);
+ left = Value >> (7 - Order);
+ if (Order == 6) {
+ if (n == Septets)
+ break;
+ result[n++] = left;
+ //printf("result[%d] = %d\n", n - 1, result[n - 1]);
+ left = 0;
+ }
+ }
+
+ return result;
+}
+
+char *BIT7Decoding(char *BIT7Data, unsigned int size)
+{
+ char *result, *buf;
+
+ result = (char *) malloc(sizeof(char) * (size + 1));
+ buf = result;
+
+ int i = 0;
+ for (i = 0; i < size; i++) {
+ u_int16_t key = BIT7Data[i];
+ if (isBIT7Same(key)) {
+ sprintf(buf++, "%c", key);
+ }
+ else if (map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key) >= 0) {
+ u_int16_t value;
+ if (key == 0x1B) { // 转义字符
+ value = map_get_value(BIT7EToUCS2, map_size(BIT7EToUCS2), BIT7Data[i + 1]);
+ if (i < size - 1 && value > 0) {
+ sprintf(buf++, "%c", value);
+ i++;
+ }
+ else {
+ value = map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key);
+ sprintf(buf++, "%c", value);
+ }
+ }
+ else {
+ //printf("go b\n");
+ value = map_get_value(BIT7ToUCS2, map_size(BIT7ToUCS2), key);
+ //printf("value = %u\n", value);
+ sprintf(buf++, "%c", value);
+
+ }
+ }
+ else {// 异常数据
+ sprintf(buf++, "?");
+ }
+
+ }
+ return result;
+
+}
+
+int isBIT7Same(u_int16_t UCS2) {
+ if ((UCS2 >= 0x61 && UCS2 <= 0x7A) ||
+ (UCS2 >= 0x41 && UCS2 <= 0x5A) ||
+ (UCS2 >= 0x25 && UCS2 <= 0x3F) ||
+ (UCS2 >= 0x20 && UCS2 <= 0x23) ||
+ UCS2 == 0x0A || UCS2 == 0x0D) {
+ return 1;
+ }
+ return 0;
+}
+
+struct PDUS *PDUEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs) {
+ enum EnumDCS DCS;
+
+ sms_init();
+
+// if (isGSMString(UDC))
+// DCS = BIT7;
+// else
+ DCS = UCS2;
+
+ return PDUDoEncoding(SCA, DA, UDC, udhs, DCS);
+}
+
+struct PDUS *PDUDoEncoding(char *SCA, char *DA, char *UDC, struct UDHS *udhs, enum EnumDCS DCS) {
+ // 短信拆分
+ struct UDS *uds = UDCSplit(UDC, udhs, DCS);
+ struct PDUS *pdus;
+
+ if (uds == NULL)
+ return NULL;
+ pdus = (struct PDUS *) malloc(sizeof(struct PDUS));
+ pdus->count = 0;
+ pdus->PDU = (char **) malloc(sizeof(char *) * uds->total);
+
+ if (uds->total > 1) {
+ // 长短信
+ int CSMMR = mCSMMR;
+ if (++mCSMMR > 0xFFFF)
+ mCSMMR = 0;
+ // 生成短信编码序列
+ int i = 0;
+ for (i = 0; i < uds->total; i++) {
+ // 更新用户数据头
+ struct UDHS *CSMUDH = UpdateUDH(udhs, CSMMR, uds->total, i);
+ pdus->PDU[i] = SoloPDUEncoding(SCA, DA, uds->Data[i], CSMUDH, DCS);
+ pdus->count++;
+ }
+
+ }
+ else { // 单条短信
+ pdus->PDU[0] = SoloPDUEncoding(SCA, DA, uds->Data[0], udhs, DCS);
+ pdus->count = 1;
+ }
+
+ return pdus;
+}
+
+int isGSMString(char *Data) {
+
+ if (Data == NULL || strcmp(Data, "") == 0)
+ return 1;
+
+ if (is_acsii((unsigned char*)Data) == 0) {
+ int len;
+ len = utf8len((unsigned char *) Data);
+
+ u_int16_t *code = (u_int16_t *) malloc(sizeof(u_int16_t) * len);
+ utf8toutf16((unsigned char *) Data, code, len, &len);
+
+ while (*code) {
+ if (!(isBIT7Same(*code) || map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), *code) >= 0))
+ return 0;
+ code++;
+ }
+
+ return 1;
+ }
+ else
+ return 1;
+
+}
+
+struct UDS *UDCSplit(char *UDC, struct UDHS *udhs, enum EnumDCS DCS) {
+ int UDHL = getUDHL(udhs);
+ struct UDS *result;
+
+ if (DCS == BIT7) {
+ // 7-Bit编码
+ // 计算剩余房间数
+ int room = BIT7UDL - (UDHL * 8 + 6) / 7;
+ if (room < 1) {
+ if (UDC == NULL || strcmp(UDC, "") == 0) {
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->Data = (char **)malloc(sizeof(char *));
+ result->total = 1;
+ result->Data[0] = UDC;
+ return result;
+ }
+ else
+ return NULL;
+ }
+
+ // 不需要拆分
+ if (SeptetsLength(UDC) <= room) {
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->Data = (char **)malloc(sizeof(char *));
+ result->total = 1;
+ result->Data[0] = UDC;
+ return result;
+ }
+ else // 拆分短信
+ {
+ if (UDHL == 0)
+ UDHL++;
+ if (mCSMIEI == BIT8MIEI)
+ UDHL += 5; // 1字节消息参考号
+ else
+ UDHL += 6; // 2字节消息参考号
+ // 更新剩余房间数
+ room = BIT7UDL - (UDHL * 8 + 6) / 7;
+ if (room < 1)
+ return NULL;
+
+ int i = 0;
+ int len = strlen(UDC);
+
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->total = 0;
+ result->Data = (char **) malloc(MAX_SMS_NR * sizeof(char *));
+
+ while (i < len) {
+ int step = SeptetsToChars(UDC, i, room);
+ if (i + step < len) {
+ result->Data[result->total] = (char *) malloc(sizeof(char) * (step + 1));
+ strcpy(result->Data[result->total++], sub_str(UDC, i, step));
+ }
+ else {
+ result->Data[result->total] = (char *) malloc(sizeof(char) * (len - i + 1));
+ strcpy(result->Data[result->total++], sub_str(UDC, i, -1));
+ }
+
+ i += step;
+
+ }
+ return result;
+
+ }
+ }
+ else { // UCS2编码
+ // 计算剩余房间数
+ int room = (BIT8UDL - UDHL) >> 1;
+ if (room < 1) {
+ if (UDC == NULL || strcmp(UDC, "") == 0) {
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->Data = (char **)malloc(sizeof(char *));
+ result->total = 1;
+ result->Data[0] = UDC;
+ return result;
+ }
+ else
+ return NULL;
+ }
+ if (UDC == NULL || utf8len(UDC) <= room) {
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->Data = (char **)malloc(sizeof(char *));
+ result->total = 1;
+ result->Data[0] = UDC;
+ return result;
+ }
+ else // 需要拆分成多条短信
+ {
+ if (UDHL == 0)
+ UDHL++;
+ if (mCSMIEI == BIT8MIEI)
+ UDHL += 5; // 1字节消息参考号
+ else
+ UDHL += 6; // 2字节消息参考号
+
+ // 更新剩余房间数
+ room = (BIT8UDL - UDHL) >> 1;
+ if (room < 1)
+ return NULL;
+
+ int len = utf8len(UDC);
+
+ result = (struct UDS *) malloc(sizeof(struct UDS));
+ result->total = 0;
+ result->Data = (char **) malloc(MAX_SMS_NR * sizeof(char *));
+ int index = 0;
+ int i = 0;
+ for (i = 0; i < len; i += room) {
+ int real_size;
+ if (i + room < len) {
+ real_size = utf8_get_size(UDC + index, room);
+ result->Data[result->total] = (char*)malloc(sizeof(char) * (real_size + 1));
+ strcpy(result->Data[result->total++],sub_str(UDC, index, real_size));
+ }
+ else {
+ real_size = utf8_get_size(UDC + index, len - i);
+ result->Data[result->total] = (char*)malloc(sizeof(char) * (real_size + 1));
+ strcpy(result->Data[result->total++], sub_str(UDC, index, -1));
+ }
+ index += real_size;
+ }
+ return result;
+ }
+
+ }
+}
+
+int getUDHL(struct UDHS *udhs) {
+ if (udhs == NULL)
+ return 0;
+
+ // 加上1字节的用户数据头长度
+ int UDHL = 1;
+ int i = 0;
+ for (i = 0; i < udhs->count; i++) {
+ UDHL += strlen(udhs->UDH[i].IED) + 2;
+ }
+ return UDHL;
+}
+
+int SeptetsLength(char *source) {
+ if (source == NULL || strcmp(source, "") == 0) {
+ return 0;
+ }
+ int len = strlen(source);
+ while (*source) {
+ u_int16_t code = (u_int16_t) *source;
+ if (map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code) > 0xFF) {
+ len++;
+ }
+ source++;
+ }
+ return len;
+}
+
+int SeptetsToChars(char *source, int index, int septets) {
+ if (source == NULL || strcmp(source, "") == 0)
+ return 0;
+ int count = 0;
+ int i;
+
+ for (i = index; i < strlen(source); i++) {
+ u_int16_t code = (u_int16_t) source[i];
+ if (map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code) > 0xFF)
+ count++;
+
+ if (++count >= septets) {
+ if (count == septets)
+ i++;
+ break;
+ }
+ }
+ return i - index;
+}
+
+struct UDHS *UpdateUDH(struct UDHS *udhs, int CSMMR, int total, int index) {
+ struct UDHS *result;
+
+ result = (struct UDHS *) malloc(sizeof(struct UDHS));
+
+ if (udhs == NULL || udhs->count == 0) {
+ result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH));
+ result->count = 1;
+
+ }
+ else {
+ result->UDH = (struct PDUUDH *) malloc(sizeof(struct PDUUDH) * (udhs->count + 1));
+ result->count = udhs->count + 1;
+ // 复制 UDH
+ memcpy(&result->UDH[1], udhs->UDH, sizeof(struct PDUUDH) * udhs->count);
+ }
+ // 插入第一个位置
+ if (mCSMIEI == BIT8MIEI) {
+ result->UDH[0].IED = (char *) malloc(sizeof(char) * 3);
+ result->UDH[0].count = 3;
+ result->UDH[0].IED[0] = CSMMR & 0xFF;
+ result->UDH[0].IED[1] = total;
+ result->UDH[0].IED[2] = index + 1;
+ result->UDH[0].IEI = 0;
+ }
+ else {
+ result->UDH[0].IED = (char *) malloc(sizeof(char) * 4);
+ result->UDH[0].count = 4;
+ result->UDH[0].IED[0] = (CSMMR >> 8) & 0xFF;
+ result->UDH[0].IED[1] = CSMMR & 0xFF;
+ result->UDH[0].IED[2] = total;
+ result->UDH[0].IED[3] = index + 1;
+ result->UDH[0].IEI = 8;
+ }
+
+ return result;
+}
+
+char *SoloPDUEncoding(char *SCA, char *DA, char *UC, struct UDHS *udhs, enum EnumDCS DCS) {
+ char *result;
+ char *buf, *ret;
+ int index;
+
+ result = (char *) malloc(sizeof(char) * 400);
+ buf = result;
+
+/* // 短信中心
+ ret = SCAEncoding(SCA);
+ index = strlen(ret);
+ sprintf(buf, "%s", ret);
+ printf("buf:%s\n",buf);
+ buf += index;
+
+*/
+ // 协议数据单元类型
+ if (udhs == NULL || udhs->count == 0) {
+ ret = PDUTypeEncoding(false);
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ }
+ else {
+ ret = PDUTypeEncoding(true);
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ }
+ // 消息参考值
+ ret = MREncoding();
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ // 接收方SME地址
+ ret = DAEncoding(DA);
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ // 协议标识
+ ret = PIDEncoding();
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ // 编码方案
+ ret = DCSEncoding(UC, DCS);
+ sprintf(buf, "%s", ret);
+ buf += strlen(ret);
+ // 有效期
+ sprintf(buf, "%s", mVP);
+ buf += strlen(mVP);
+
+ // 用户数据长度及内容
+ ret = UDEncoding(UC, udhs, DCS);
+ sprintf(buf, "%s", ret);
+
+ return result;
+}
+
+char *SCAEncoding(char *SCA) {
+
+ if (SCA == NULL || strcmp(SCA, "") == 0) {
+ // 表示使用SIM卡内部的设置值,该值通过AT+CSCA指令设置
+ return "00";
+ }
+
+ char *result;
+ char *buf;
+ int len;
+ len = strlen(SCA);
+ result = (char *) malloc((len + 5) * sizeof(char));
+ buf = result;
+
+ int index = 0;
+ if (SCA[0] == '+') {
+ // 国际号码
+ sprintf(buf, "%02X", len / 2 + 1);
+ buf += 2;
+ sprintf(buf, "91");
+ buf += 2;
+ index = 1;
+ }
+ else {
+ // 国内号码
+ sprintf(buf, "%02X", len / 2 + 1);
+ buf += 2;
+ sprintf(buf, "81");
+ buf += 2;
+ }
+ // SCA地址编码
+ for (; index < len; index += 2) {
+ if (index == len - 1) {
+ // 补“F”凑成偶数个
+ sprintf(buf++, "F");
+ sprintf(buf++, "%c", SCA[index]);
+
+ }
+ else {
+ sprintf(buf++, "%c", SCA[index + 1]);
+ sprintf(buf++, "%c", SCA[index]);
+ }
+ }
+
+ return result;
+}
+
+char *PDUTypeEncoding(bool UDH) {
+ // 信息类型指示(Message Type Indicator)
+ // 01 SMS-SUBMIT(MS -> SMSC)
+ int PDUType = 0x11; // 508TLC change
+// int PDUType = 0x01;
+ char *result;
+ result = (char *) malloc(3 * sizeof(char));
+
+ // 用户数据头标识(User Data Header Indicator)
+ if (UDH) {
+ PDUType |= 0x40;
+ }
+ // 有效期格式(Validity Period Format)
+ if (strlen(mVP) == 2) {
+ // VP段以整型形式提供(相对的)
+ PDUType |= 0x10;
+ }
+ else if (strlen(mVP) == 14) {
+ // VP段以8位组的一半(semi-octet)形式提供(绝对的)
+ PDUType |= 0x18;
+ }
+
+ // 请求状态报告(Status Report Request)
+ if (mSRR) {
+ // 请求状态报告
+ PDUType |= 0x20;
+ }
+
+ // 拒绝复本(Reject Duplicate)
+ if (mRD) {
+ PDUType |= 0x04;
+ }
+ sprintf(result, "%02X", PDUType);
+ return result;
+}
+
+char *MREncoding() {
+ // 由手机设置
+ return "00";
+}
+
+char *DAEncoding(char *DA) {
+ if (DA == NULL || strcmp(DA, "") == 0) {
+ // 地址长度0,地址类型未知
+ return "0080";
+ }
+ char *result, *buf;
+ int len = strlen(DA);
+ int index;
+
+ result = (char *) malloc(sizeof(char) * (len + 5));
+ buf = result;
+
+ if (DA[0] == '+') {
+ // 国际号码
+ // 地址长度编码
+ sprintf(buf, "%02X", len - 1);
+ buf += 2;
+ // 地址类型
+ sprintf(buf, "91");
+ buf += 2;
+ index = 1;
+ }
+ else {
+ // 国内号码
+ // 地址长度编码
+ sprintf(buf, "%02X", len);
+ buf += 2;
+ // 地址类型
+ sprintf(buf, "81");
+ buf += 2;
+ }
+
+ for (; index < len; index += 2) {
+ // 号码部分奇偶位对调
+ if (index == len - 1) {
+ sprintf(buf++, "F");
+ sprintf(buf++, "%c", DA[index]);
+ }
+ else {
+ sprintf(buf++, "%c", DA[index + 1]);
+ sprintf(buf++, "%c", DA[index]);
+ }
+ }
+ return result;
+
+}
+
+char *PIDEncoding() {
+ return "00";
+}
+
+char *DCSEncoding(char *UD, enum EnumDCS DCS) {
+ if (DCS == BIT7) {
+ // 7-Bit编码
+ return "00";
+ }
+ else {
+ // UCS2编码
+ return "0800";
+ }
+}
+
+char *UDEncoding(char *UD, struct UDHS *udhs, enum EnumDCS DCS) {
+ int UDHL;
+
+ char *result;
+
+ // 用户数据头编码
+ char *header = UDHEncoding(udhs, &UDHL);
+
+ // 用户数据内容编码
+ int UDCL;
+ char *body;
+
+ body = UDCEncoding(UD, &UDCL, UDHL, DCS);
+
+ // 用户数据区长度
+ int UDL;
+ if (DCS == BIT7) {
+ // 7-Bit编码
+ UDL = (UDHL * 8 + 6) / 7 + UDCL;
+ }
+ else {
+ // UCS2编码或者8-Bit编码
+ UDL = UDHL + UDCL;
+ }
+
+ int len = strlen(header) + strlen(body) + 2;
+ result = (char *) malloc(sizeof(char) * (len + 1));
+ sprintf(result, "%02X%s%s", UDL, header, body);
+
+ return result;
+
+}
+
+char *UDHEncoding(struct UDHS *udhs, int *UDHL) {
+
+ *UDHL = 0;
+
+ if (udhs == NULL || udhs->count == 0)
+ return "";
+ int i = 0;
+ for (i = 0; i < udhs->count; i++) {
+ *UDHL += udhs->UDH[i].count + 2;
+ }
+
+ char *result;
+ char *buf;
+ result = (char *) malloc(sizeof(char) * ((*UDHL + 1) * 2 + 1));
+ buf = result;
+
+ sprintf(buf, "%02X", *UDHL);
+ buf += 2;
+
+ for (i = 0; i < udhs->count; i++) {
+ // 信息元素标识1字节
+ sprintf(buf, "%02X", udhs->UDH[i].IEI);
+ buf += 2;
+ // 信息元素长度1字节
+ sprintf(buf, "%02X", udhs->UDH[i].count);
+ buf += 2;
+ // 信息元素数据
+ int j = 0;
+ for (j = 0; j < udhs->UDH[i].count; j++) {
+ sprintf(buf, "%02X", udhs->UDH[i].IED[j]);
+ buf += 2;
+ }
+
+ }
+ // 加上1字节的用户数据头长度
+ (*UDHL)++;
+ return result;
+
+}
+
+char *UDCEncoding(char *UDC, int *UDCL, int UDHL, enum EnumDCS DCS) {
+ if (UDC == NULL || strcmp(UDC, "") == 0) {
+ *UDCL = 0;
+ return "";
+ }
+
+ if (DCS == BIT7) {
+ // 7-Bit编码,需要参考用户数据头长度,已保证7-Bit边界对齐
+ return BIT7Pack(BIT7Encoding(UDC, UDCL), UDHL);
+ }
+ else {
+ // UCS2编码
+
+ int len = utf8len((unsigned char*)UDC);
+ int len2;
+ unsigned short *code;
+
+ code = (unsigned short*)malloc(sizeof(unsigned short) * len);
+ utf8toutf16((unsigned char*)UDC, code, len, &len2);
+ *UDCL = len * 2;
+ char *result = (char *) malloc(sizeof(char) * (*UDCL * 2 + 1));
+ char *buf = result;
+
+ int i = 0;
+ for (i = 0; i < len; i++) {
+ sprintf(buf, "%04X", code[i]);
+ buf += 4;
+ }
+ free(code);
+ return result;
+ }
+}
+
+struct ByteArray *BIT7Encoding(char *UDC, int *Septets) {
+ struct ByteArray *result;
+
+ int len = strlen(UDC);
+
+ result = (struct ByteArray *) malloc(sizeof(struct ByteArray));
+ result->len = 0;
+ result->array = (char *) malloc(sizeof(char) * (len * 2 + 1));
+ *Septets = 0;
+
+ int i = 0;
+ for (i = 0; i < len; i++) {
+ u_int16_t code = (u_int16_t) UDC[i];
+ if (isBIT7Same(code)) {
+ // 编码不变
+ result->array[(*Septets)++] = code;
+ }
+ else {
+ u_int16_t value = map_get_value(UCS2ToBIT7, map_size(UCS2ToBIT7), code);
+ if (value >= 0) {
+ if (value > 0xFF) {
+ // 转义序列
+ result->array[(*Septets)++] = value >> 8;
+ result->array[(*Septets)++] = value & 0xFF;
+ }
+ else {
+ result->array[(*Septets)++] = value;
+ }
+ }
+ else {
+ // 未知字符
+ result->array[(*Septets)++] = (u_int16_t) '?';
+ }
+ }
+ }
+ // 重新调整大小
+ result->len = *Septets;
+
+ return result;
+}
+
+char *BIT7Pack(struct ByteArray *Bit7Array, int UDHL) {
+ // 7Bit对齐需要的填充位
+ int fillBits = (UDHL * 8 + 6) / 7 * 7 - (UDHL * 8);
+
+ // 压缩字节数
+ int len = Bit7Array->len;
+ int packLen = (len * 7 + fillBits + 7) / 8;
+ char *result;
+ char *buf;
+
+ result = (char *) malloc(sizeof(char) * (packLen * 2 + 1));
+ buf = result;
+
+ int left = 0;
+ int i = 0;
+ for (i = 0; i < len; i++) {
+ // 每8个字节压缩成7个字节
+ int32_t Value = Bit7Array->array[i];
+ int32_t index = (i + 8 - fillBits) % 8;
+ if (index == 0) {
+ left = Value;
+ }
+ else {
+ int32_t n = ((Value << (8 - index)) | left) & 0xFF;
+ sprintf(buf, "%02X", n);
+ buf += 2;
+ left = Value >> index;
+ }
+ }
+
+
+ if ((len * 7 + fillBits) % 8 != 0) {
+ // 写入剩余数据
+ sprintf(buf, "%02X", left);
+ buf += 2;
+ }
+ buf[0] = '\0';
+ return result;
+}
+
diff --git a/mbtk/libmbtk_lib/tcpip/mbtk_tcpip_at.c b/mbtk/libmbtk_lib/tcpip/mbtk_tcpip_at.c
new file mode 100755
index 0000000..fadb1a6
--- /dev/null
+++ b/mbtk/libmbtk_lib/tcpip/mbtk_tcpip_at.c
@@ -0,0 +1,665 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <pthread.h>
+#include <sys/epoll.h>
+#include <string.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <netinet/tcp.h>
+
+#include "mbtk_log.h"
+#include "mbtk_tcpip.h"
+#include "mbtk_net_control.h"
+
+#define MBTK_TCPIP_CID_DEFAULT 0
+#define MBTK_TCPIP_READ_BUFF_SIZE 2048
+#define TCPIP_DEBUG 0
+
+typedef struct {
+ mbtk_sock_session sock_fd;
+ char ser_addr[256];
+ int ser_port;
+ char local_addr[256];
+ int local_port;
+ bool ack_support;
+ bool ssl_support;
+ bool ignore_cert;
+ uint32 heartbeat_time;
+ uint32 delay_time;
+
+ mbtk_tcpip_read_callback_func read_cb;
+
+ uint32 data_traffic_send;
+ uint32 data_traffic_recv;
+
+} mbtk_tcpip_cli_info_t;
+
+typedef struct {
+ mbtk_sock_session sock_fd;
+ char ser_addr[256];
+ int ser_port;
+
+ int cli_num;
+ mbtk_tcpip_cli_info_t *cli_list;
+} mbtk_tcpip_ser_info_t;
+
+typedef struct {
+ int link_id;
+ int link_cid;
+ bool link_connected;
+ mbtk_sock_type prot_type; // TCP/UDP
+
+ mbtk_tcpip_type_enum type;
+ union
+ {
+ mbtk_tcpip_cli_info_t cli_info;
+ mbtk_tcpip_ser_info_t ser_info;
+ } tcpip_info;
+
+} mbtk_tcpip_link_t;
+
+static mbtk_tcpip_link_t tcpip_link[MBTK_TCPIP_LINK_MAX];
+static bool tcpip_inited = FALSE;
+static mbtk_sock_handle tcpip_handle;
+static mbtk_tcpip_net_callback_func tcpip_net_cb = NULL;
+static mbtk_tcpip_sock_callback_func tcpip_sock_cb = NULL;
+
+/*
+struct tcp_info
+{
+ u_int8_t tcpi_state;
+ u_int8_t tcpi_ca_state;
+ u_int8_t tcpi_retransmits;
+ u_int8_t tcpi_probes;
+ u_int8_t tcpi_backoff;
+ u_int8_t tcpi_options;
+ u_int8_t tcpi_snd_wscale : 4, tcpi_rcv_wscale : 4;
+
+ u_int32_t tcpi_rto;
+ u_int32_t tcpi_ato;
+ u_int32_t tcpi_snd_mss;
+ u_int32_t tcpi_rcv_mss;
+
+ u_int32_t tcpi_unacked;
+ u_int32_t tcpi_sacked;
+ u_int32_t tcpi_lost;
+ u_int32_t tcpi_retrans;
+ u_int32_t tcpi_fackets;
+
+ u_int32_t tcpi_last_data_sent;
+ u_int32_t tcpi_last_ack_sent;
+ u_int32_t tcpi_last_data_recv;
+ u_int32_t tcpi_last_ack_recv;
+
+ u_int32_t tcpi_pmtu;
+ u_int32_t tcpi_rcv_ssthresh;
+ u_int32_t tcpi_rtt;
+ u_int32_t tcpi_rttvar;
+ u_int32_t tcpi_snd_ssthresh;
+ u_int32_t tcpi_snd_cwnd;
+ u_int32_t tcpi_advmss;
+ u_int32_t tcpi_reordering;
+
+ u_int32_t tcpi_rcv_rtt;
+ u_int32_t tcpi_rcv_space;
+
+ u_int32_t tcpi_total_retrans;
+};
+
+*/
+void tcp_info_print(struct tcp_info *tcp)
+{
+ if(tcp) {
+ LOGD("tcpi_state = %d", tcp->tcpi_state);
+ LOGD("tcpi_ca_state = %d", tcp->tcpi_ca_state);
+ LOGD("tcpi_retransmits = %d", tcp->tcpi_retransmits);
+ LOGD("tcpi_probes = %d", tcp->tcpi_probes);
+ LOGD("tcpi_backoff = %d", tcp->tcpi_backoff);
+ LOGD("tcpi_options = %d", tcp->tcpi_options);
+ LOGD("tcpi_snd_wscale = %d", 0x0F & tcp->tcpi_snd_wscale);
+ LOGD("tcpi_rcv_wscale = %d", 0xF0 & tcp->tcpi_rcv_wscale);
+ LOGD("tcpi_rto = %d", tcp->tcpi_rto);
+ LOGD("tcpi_ato = %d", tcp->tcpi_ato);
+ LOGD("tcpi_snd_mss = %d", tcp->tcpi_snd_mss);
+ LOGD("tcpi_rcv_mss = %d", tcp->tcpi_rcv_mss);
+ LOGD("tcpi_unacked = %d", tcp->tcpi_unacked);
+ LOGD("tcpi_sacked = %d", tcp->tcpi_sacked);
+ LOGD("tcpi_lost = %d", tcp->tcpi_lost);
+ LOGD("tcpi_retrans = %d", tcp->tcpi_retrans);
+ LOGD("tcpi_fackets = %d", tcp->tcpi_fackets);
+ LOGD("tcpi_last_data_sent = %d", tcp->tcpi_last_data_sent);
+ LOGD("tcpi_last_ack_sent = %d", tcp->tcpi_last_ack_sent);
+ LOGD("tcpi_last_data_recv = %d", tcp->tcpi_last_data_recv);
+ LOGD("tcpi_last_ack_recv = %d", tcp->tcpi_last_ack_recv);
+ LOGD("tcpi_pmtu = %d", tcp->tcpi_pmtu);
+ LOGD("tcpi_rcv_ssthresh = %d", tcp->tcpi_rcv_ssthresh);
+ LOGD("tcpi_rtt = %d", tcp->tcpi_rtt);
+ LOGD("tcpi_rttvar = %d", tcp->tcpi_rttvar);
+ LOGD("tcpi_snd_ssthresh = %d", tcp->tcpi_snd_ssthresh);
+ LOGD("tcpi_snd_cwnd = %d", tcp->tcpi_snd_cwnd);
+ LOGD("tcpi_advmss = %d", tcp->tcpi_advmss);
+ LOGD("tcpi_reordering = %d", tcp->tcpi_reordering);
+ LOGD("tcpi_rcv_rtt = %d", tcp->tcpi_rcv_rtt);
+ LOGD("tcpi_rcv_space = %d", tcp->tcpi_rcv_space);
+ LOGD("tcpi_total_retrans = %d", tcp->tcpi_total_retrans);
+ }
+}
+
+static int tcpip_fd_2_link(int fd)
+{
+ int link_id = 0;
+ mbtk_tcpip_link_t *link = NULL;
+ for(; link_id < MBTK_TCPIP_LINK_MAX; link_id++) {
+ link = tcpip_link + link_id;
+ if(link->link_connected) {
+ if(link->type == MBTK_TCPIP_TYPE_CLIENT) {
+ if(link->tcpip_info.cli_info.sock_fd > 0 && link->tcpip_info.cli_info.sock_fd == fd) {
+ break;
+ }
+ } else {
+ // Not support.
+
+ }
+ }
+ }
+
+ if(link_id == MBTK_TCPIP_LINK_MAX) {
+ return -1;
+ } else {
+ return link_id;
+ }
+}
+
+static void tcpip_sock_cb_func(int handle, mbtk_sock_cb_info_s *sock_info)
+{
+ if(tcpip_inited && tcpip_handle == handle/* && http_fd == fd*/) {
+ if(sock_info->event & (EPOLLIN | EPOLLOUT)) { // Cand read or write.
+ int sock_error = 0;
+ socklen_t socklen = sizeof(sock_error);
+ if(getsockopt(sock_info->sock_fd, SOL_SOCKET, SO_ERROR, &sock_error, (socklen_t*)&socklen) == 0) {
+ LOGV("Socket error:%d", sock_error);
+ }
+
+ if(sock_error) {
+ LOGW("errno = %d", errno);
+ if(sock_error == ECONNRESET|| errno == EAGAIN)
+ {
+ //
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ if(sock_info->sock_type == MBTK_SOCK_TCP) {
+ struct tcp_info info;
+ int len = sizeof(info);
+ if(getsockopt(sock_info->sock_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len) == 0) {
+ LOGV("State : %d", info.tcpi_state);
+#if TCPIP_DEBUG
+ //tcp_info_print(&info);
+#endif
+ }
+
+ if(TCP_ESTABLISHED != info.tcpi_state) {
+ LOGW("errno = %d", errno);
+ int link_id = tcpip_fd_2_link(sock_info->sock_fd);
+ if(link_id >= 0) {
+ // Socket disconnected?
+ mbtk_tcpip_sock_close(link_id);
+
+ if(tcpip_sock_cb) {
+ tcpip_sock_cb(link_id, 0);
+ }
+ }
+ return;
+ }
+ }
+ }
+
+ if(sock_info->event & EPOLLIN) { // READ
+ LOGV("fd[%d] can read.", sock_info->sock_fd);
+ int link_id = tcpip_fd_2_link(sock_info->sock_fd);
+ if(link_id >= 0) {
+ if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+ if(tcpip_link[link_id].tcpip_info.cli_info.read_cb) {
+ char buff[MBTK_TCPIP_READ_BUFF_SIZE];
+ memset(buff, 0x0, MBTK_TCPIP_READ_BUFF_SIZE);
+ int read_len = mbtk_sock_read_async(tcpip_handle, sock_info->sock_fd, buff, MBTK_TCPIP_READ_BUFF_SIZE);
+ if(read_len > 0) {
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += read_len;
+ tcpip_link[link_id].tcpip_info.cli_info.read_cb(link_id, (const char*)buff, read_len);
+ }
+#if 0
+ else { // Socket error(Such as server disconnected.).
+ LOGW("errno = %d", errno);
+ // Socket disconnected?
+ mbtk_tcpip_sock_close(link_id);
+
+ if(tcpip_sock_cb) {
+ tcpip_sock_cb(link_id, 0);
+ }
+ }
+#endif
+ while(read_len > 0) {
+ memset(buff, 0x0, MBTK_TCPIP_READ_BUFF_SIZE);
+ read_len = mbtk_sock_read_async(tcpip_handle, sock_info->sock_fd, buff, MBTK_TCPIP_READ_BUFF_SIZE);
+ // LOGD("read_len = %d", read_len);
+ if(read_len > 0) {
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += read_len;
+ tcpip_link[link_id].tcpip_info.cli_info.read_cb(link_id, (const char*)buff, read_len);
+ }
+ }
+ }
+ } else {
+ // Not support.
+
+ }
+ }
+ } else if(sock_info->event & EPOLLRDHUP) { // Close
+ LOGD("fd[%d] Closed?", sock_info->sock_fd);
+ } else {
+ LOGW("Unknown event:%x",sock_info->event);
+ }
+ }
+}
+
+static void tcpip_net_cb_func(mbtk_sock_handle handle, mbtk_net_cb_info_s *info)
+{
+ if(tcpip_inited && tcpip_handle == handle) {
+ LOGD("Net state : %d, %s, %s", info->state, info->if_name, info->addr);
+ if(info->state == 0) {
+ mbtk_tcpip_net_close();
+ }
+
+ if(tcpip_net_cb) {
+ tcpip_net_cb(info->state, info->addr);
+ }
+ }
+}
+
+static bool tcpip_link_check(int link_id)
+{
+ if(tcpip_inited && link_id >= 0 && link_id < MBTK_TCPIP_LINK_MAX) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static bool tcpip_link_connected(int link_id)
+{
+ if(!tcpip_link_check(link_id)) {
+ return FALSE;
+ }
+
+ if(!tcpip_link[link_id].link_connected) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static int tcpip_link_reset(mbtk_tcpip_link_t *link, int link_id)
+{
+ if(link) {
+ // Close socket if necessary.
+ if(link->link_connected) {
+ if(link->type == MBTK_TCPIP_TYPE_CLIENT) {
+ if(link->tcpip_info.cli_info.sock_fd > 0) {
+ int err;
+ if(mbtk_sock_close(tcpip_handle, link->tcpip_info.cli_info.sock_fd, 3000, &err) == 0
+ && err == MBTK_SOCK_SUCCESS) {
+ LOGD("Close socket[%d] success.", link->tcpip_info.cli_info.sock_fd);
+ } else {
+ LOGE("Close socket[%d] fail.", link->tcpip_info.cli_info.sock_fd);
+ return -1;
+ }
+ }
+ } else {
+ // Not support.
+
+ return -1;
+ }
+ }
+
+ memset(link, 0x0, sizeof(mbtk_tcpip_link_t));
+ link->link_id = link_id;
+ link->link_cid = MBTK_TCPIP_CID_DEFAULT;
+ return 0;
+ }
+
+ return -1;
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_net_open(mbtk_tcpip_net_callback_func net_cb, mbtk_tcpip_sock_callback_func sock_cb)
+{
+ if(tcpip_inited) {
+ LOGW("TCP/IP has inited.");
+ return MBTK_TCPIP_ERR_SUCCESS;
+ } else {
+ //mbtk_log_init("radio", "MBTK_TCPIP");
+ mbtk_net_state_t net_state = mbtk_net_state_get();
+ if(net_state == MBTK_NET_STATE_OFF) {
+ LOGE("Network unavailable.");
+ return MBTK_TCPIP_ERR_NET_UNAVAILABLE;
+ }
+
+ memset(&tcpip_link, 0x0, sizeof(mbtk_tcpip_link_t) * MBTK_TCPIP_LINK_MAX);
+ int i = 0;
+ for(; i < MBTK_TCPIP_LINK_MAX; i++) {
+ tcpip_link_reset(tcpip_link + i, i);
+ }
+
+ mbtk_init_info init_info;
+ init_info.net_type = MBTK_NET_LINUX;
+ init_info.net_cb = tcpip_net_cb_func;
+ init_info.sock_cb = tcpip_sock_cb_func;
+ sprintf(init_info.if_name, "ccinet%d", MBTK_TCPIP_CID_DEFAULT);
+ tcpip_handle = mbtk_sock_init(&init_info);
+ if(tcpip_handle < 0) {
+ LOGE("mbtk_sock_init() fail.");
+ return MBTK_TCPIP_ERR_NET_HANDLE;
+ }
+
+ tcpip_net_cb = net_cb;
+ tcpip_sock_cb = sock_cb;
+ tcpip_inited = TRUE;
+ return MBTK_TCPIP_ERR_SUCCESS;
+ }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_net_close()
+{
+ if(tcpip_inited) {
+ int i = 0;
+ mbtk_tcpip_err_enum tcpip_err = MBTK_TCPIP_ERR_SUCCESS;
+
+ // Close all socket.
+ for(; i < MBTK_TCPIP_LINK_MAX; i++) {
+ if(tcpip_link_reset(tcpip_link + i, i)) {
+ tcpip_err = MBTK_TCPIP_ERR_UNKNOWN;
+ }
+ }
+
+ if(tcpip_err == MBTK_TCPIP_ERR_SUCCESS) {
+ tcpip_inited = FALSE;
+ }
+ return tcpip_err;
+ } else {
+ LOGW("TCP/IP not inited.");
+ return MBTK_TCPIP_ERR_SUCCESS;
+ }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_sock_open(const mbtk_tcpip_info_t *tcpip_info)
+{
+ if(tcpip_info == NULL || strlen(tcpip_info->ser_addr) == 0 || tcpip_info->ser_port <= 0) {
+ LOGE("ARG error.");
+ return MBTK_TCPIP_ERR_ARG;
+ }
+
+ if(!tcpip_link_check(tcpip_info->link_id)) {
+ LOGE("Link[%d] error.", tcpip_info->link_id);
+ return MBTK_TCPIP_ERR_LINK_UNAVAILABLE;
+ }
+
+ if(tcpip_link_connected(tcpip_info->link_id)) {
+ LOGE("Link[%d] has connected.", tcpip_info->link_id);
+ return MBTK_TCPIP_ERR_LINK_UNAVAILABLE;
+ }
+
+ if(tcpip_info->tcpip_type == MBTK_TCPIP_TYPE_CLIENT) {
+ mbtk_tcpip_link_t *link = tcpip_link + tcpip_info->link_id;
+
+ int err;
+ mbtk_sock_info sock_info;
+ memset(&sock_info, 0x0, sizeof(mbtk_sock_info));
+ sock_info.type = tcpip_info->prot_type;
+ sock_info.is_support_ssl = tcpip_info->ssl_support;
+ sock_info.ingnore_cert = tcpip_info->ignore_cert;
+ memcpy(sock_info.address, tcpip_info->ser_addr, strlen(tcpip_info->ser_addr));
+ sock_info.port = tcpip_info->ser_port;
+ sock_info.local_port = tcpip_info->local_port;
+
+ link->tcpip_info.cli_info.sock_fd = mbtk_sock_open(tcpip_handle, &sock_info, 3000, &err);
+ if(link->tcpip_info.cli_info.sock_fd > 0) {
+ link->prot_type = tcpip_info->prot_type;
+ link->type = MBTK_TCPIP_TYPE_CLIENT;
+ memcpy(link->tcpip_info.cli_info.ser_addr, tcpip_info->ser_addr, strlen(tcpip_info->ser_addr));
+ link->tcpip_info.cli_info.ser_port = tcpip_info->ser_port;
+ link->tcpip_info.cli_info.local_port = tcpip_info->local_port;
+ link->tcpip_info.cli_info.ack_support = tcpip_info->ack_support;
+ link->tcpip_info.cli_info.ssl_support = tcpip_info->ssl_support;
+ link->tcpip_info.cli_info.ignore_cert = tcpip_info->ignore_cert;
+ link->tcpip_info.cli_info.heartbeat_time = tcpip_info->heartbeat_time;
+ link->tcpip_info.cli_info.delay_time = tcpip_info->delay_time;
+ link->tcpip_info.cli_info.read_cb = tcpip_info->read_cb;
+ link->link_connected = TRUE;
+ LOGD("Open socket[%d] success.");
+ return MBTK_TCPIP_ERR_SUCCESS;
+ } else {
+ LOGE("Open socket[%d] fail.");
+ return MBTK_TCPIP_ERR_UNKNOWN;
+ }
+ } else {
+ LOGE("Only support CLIENT now!");
+ return MBTK_TCPIP_ERR_UNKNOWN;
+ }
+}
+
+mbtk_tcpip_err_enum mbtk_tcpip_sock_close(int link_id)
+{
+ if(!tcpip_link_connected(link_id)) {
+ LOGE("Link[%d] not connected.", link_id);
+ return MBTK_TCPIP_ERR_LINK_NOT_CONNECT;
+ }
+
+ if(tcpip_link_reset(tcpip_link + link_id, link_id)) {
+ LOGE("Close link[%d] fail.", link_id);
+ return MBTK_TCPIP_ERR_UNKNOWN;
+ }
+
+ return MBTK_TCPIP_ERR_SUCCESS;
+}
+
+int mbtk_tcpip_send(int link_id, const char* data, int data_len, const char* ser_addr, int ser_port)
+{
+ if(!tcpip_link_connected(link_id)) {
+ LOGE("Link[%d] not connected.", link_id);
+ return -1;
+ }
+
+ if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+ int err;
+ int len = mbtk_sock_write(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd,
+ data, data_len, 3000, &err);
+ if(len > 0) {
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send += len;
+ }
+ return len;
+ } else {
+ // Not support.
+ return -1;
+ }
+
+ return 0;
+}
+
+int mbtk_tcpip_read(int link_id, char* buff, int buff_size)
+{
+ if(!tcpip_link_connected(link_id)) {
+ LOGE("Link[%d] not connected.", link_id);
+ return -1;
+ }
+
+ if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+ if(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.read_cb) {
+ LOGE("Set read_cb function,can not manual read.");
+ return -1;
+ }
+ int len = mbtk_sock_read_async(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd,
+ buff, buff_size);
+ if(len > 0) {
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv += len;
+ }
+ return len;
+ } else {
+ // Not support.
+ return -1;
+ }
+}
+
+/*
+* Get the data traffic of the specified link. Return -1 if fail.
+*/
+int mbtk_tcpip_data_traffic_get(int link_id)
+{
+ if(!tcpip_link_connected(link_id)) {
+ LOGE("Link[%d] not connected.", link_id);
+ return -1;
+ }
+
+ if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+ return tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv
+ + tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send;
+ } else {
+ // Not support.
+ return -1;
+ }
+}
+
+/*
+* Reset the data traffic of the specified link.
+*/
+mbtk_tcpip_err_enum mbtk_tcpip_data_traffic_reset(int link_id)
+{
+ if(!tcpip_link_connected(link_id)) {
+ LOGE("Link[%d] not connected.", link_id);
+ return MBTK_TCPIP_ERR_LINK_NOT_CONNECT;
+ }
+
+ if(tcpip_link[link_id].type == MBTK_TCPIP_TYPE_CLIENT) {
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_recv = 0;
+ tcpip_link[link_id].tcpip_info.cli_info.data_traffic_send = 0;
+ return MBTK_TCPIP_ERR_SUCCESS;
+ } else {
+ // Not support.
+
+ }
+
+ return MBTK_TCPIP_ERR_UNKNOWN;
+}
+
+/*
+* Return 0 if disconnected, 1 for connected, other for fail.
+*/
+int mbtk_tcpip_link_state_get(int link_id)
+{
+ if(!tcpip_link_check(link_id)) {
+ LOGE("Link error.");
+ return -1;
+ }
+
+ return tcpip_link[link_id].link_connected ? 1 : 0;
+}
+
+/*
+* Get TCP state informations.
+*/
+int mbtk_tcpip_info_get(int link_id, mbtk_tcpip_tcp_state_info_s *state_info)
+{
+ if(!tcpip_link_check(link_id)) {
+ LOGE("Link error.");
+ return -1;
+ }
+
+ if(state_info == NULL) {
+ LOGE("ARG error.");
+ return -1;
+ }
+
+ memset(state_info, 0x0, sizeof(mbtk_tcpip_tcp_state_info_s));
+
+ struct tcp_info info;
+ memset(&info, 0x0, sizeof(struct tcp_info));
+ int len = sizeof(info);
+ if(tcpip_link[link_id].prot_type == MBTK_SOCK_TCP) {
+ if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t*)&len)) {
+ LOGE("Get TCP_INFO fail:%d", errno);
+ return -1;
+ }
+
+#if TCPIP_DEBUG
+ tcp_info_print(&info);
+#endif
+ state_info->state = info.tcpi_state;
+ } else {
+ state_info->state = 0;
+ }
+
+#if TCPIP_DEBUG
+ int rcvbuf_size;
+ len = sizeof(rcvbuf_size);
+ if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, (socklen_t*)&len)) {
+ LOGE("Get SO_RCVBUF fail:%d", errno);
+ return -1;
+ }
+ LOGD("SO_RCVBUF = %d", rcvbuf_size);
+
+ int sndbuf_size;
+ len = sizeof(sndbuf_size);
+ if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_SNDBUF, &sndbuf_size, (socklen_t*)&len)) {
+ LOGE("Get SO_SNDBUF fail:%d", errno);
+ return -1;
+ }
+ LOGD("SO_SNDBUF = %d", sndbuf_size);
+
+ int rcvlowat_size;
+ len = sizeof(rcvlowat_size);
+ if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_RCVLOWAT, &rcvlowat_size, (socklen_t*)&len)) {
+ LOGE("Get SO_RCVLOWAT fail:%d", errno);
+ return -1;
+ }
+ LOGD("SO_RCVLOWAT = %d", rcvlowat_size);
+
+ int sndlowat_size;
+ len = sizeof(sndlowat_size);
+ if(getsockopt(tcpip_link[link_id].tcpip_info.cli_info.sock_fd, SOL_SOCKET, SO_SNDLOWAT, &sndlowat_size, (socklen_t*)&len)) {
+ LOGE("Get SO_SNDLOWAT fail:%d", errno);
+ return -1;
+ }
+ LOGD("SO_SNDLOWAT = %d", sndlowat_size);
+#endif
+
+ state_info->link_id = link_id;
+ state_info->sock_fd = tcpip_link[link_id].tcpip_info.cli_info.sock_fd;
+ state_info->recv_data_len = mbtk_sock_tcp_recv_len_get(tcpip_handle, tcpip_link[link_id].tcpip_info.cli_info.sock_fd);
+
+ return 0;
+}
+
+/*
+* Set socket auto read callback function,NULL for close auto read.
+*/
+void mbtk_tcpip_set_read_cb(int link_id, mbtk_tcpip_read_callback_func read_cb)
+{
+ if(!tcpip_link_check(link_id)) {
+ LOGE("Link error.");
+ return;
+ }
+
+ tcpip_link[link_id].tcpip_info.cli_info.read_cb = read_cb;
+}
+
+void mbtk_tcpip_lib_info_print()
+{
+ MBTK_SOURCE_INFO_PRINT("mbtk_tcpip_lib");
+}
+