tom_modem: release a new at tool
This commit is contained in:
parent
656c32260d
commit
fb355ce04e
35
application/tom_modem/Makefile
Normal file
35
application/tom_modem/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
|
||||
PKG_NAME:= tom_modem
|
||||
PKG_RELEASE:=beta
|
||||
PKG_VERSION:=0.9
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/$(PKG_NAME)
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=Fujr Modem Communite Tool
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/description
|
||||
Modem Communite Tool for 5G modem (By Fujr)
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C $(PKG_BUILD_DIR) \
|
||||
$(TARGET_CONFIGURE_OPTS) CFLAGS="$(TARGET_CFLAGS)"
|
||||
endef
|
||||
|
||||
define Package/$(PKG_NAME)/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/tom_modem $(1)/usr/bin/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,$(PKG_NAME)))
|
28
application/tom_modem/src/Makefile
Normal file
28
application/tom_modem/src/Makefile
Normal file
@ -0,0 +1,28 @@
|
||||
TARGET = tom_modem
|
||||
|
||||
CFLAGS = -Wall -Ipdu_lib
|
||||
|
||||
SRCS = main.c utils.c pdu_lib/pdu.c pdu_lib/ucs2_to_utf8.c
|
||||
|
||||
OBJS = $(SRCS:.c=.o)
|
||||
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) $(LDFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(TARGET)
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
|
||||
.PHONY:clean
|
||||
clean:
|
||||
rm -rf *.o *.*~ *~ *.swap $(all)
|
||||
depend:
|
||||
$(CC) $(CFLAGS) -MM $(SRCS) > .depend
|
||||
|
||||
# 包含依赖文件
|
||||
ifneq "$(wildcard .depend)" ""
|
||||
include .depend
|
||||
endif
|
201
application/tom_modem/src/main.c
Normal file
201
application/tom_modem/src/main.c
Normal file
@ -0,0 +1,201 @@
|
||||
#include "modem_types.h"
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
|
||||
void _timeout(int signo)
|
||||
{
|
||||
err_msg("Exit with Signal %d", signo);
|
||||
kill(getpid(), SIGINT);
|
||||
}
|
||||
|
||||
int parse_user_input(int argc, char *argv[], PROFILE_T *profile)
|
||||
{
|
||||
int opt = 1;
|
||||
int option;
|
||||
profile->sms_index = -1;
|
||||
#define has_more_argv() (opt < argc ? 1 : 0)
|
||||
while (opt < argc)
|
||||
{
|
||||
option = match_option(argv[opt]);
|
||||
if (option == -1)
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
opt++;
|
||||
switch (option)
|
||||
{
|
||||
case AT_CMD:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->at_cmd = argv[opt++];
|
||||
break;
|
||||
case TTY_DEV:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->tty_dev = argv[opt++];
|
||||
break;
|
||||
case BAUD_RATE:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->baud_rate = atoi(argv[opt++]);
|
||||
break;
|
||||
case DATA_BITS:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->data_bits = atoi(argv[opt++]);
|
||||
break;
|
||||
case PARITY:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->parity = argv[opt++];
|
||||
break;
|
||||
case STOP_BITS:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->stop_bits = atoi(argv[opt++]);
|
||||
break;
|
||||
case FLOW_CONTROL:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->flow_control = argv[opt++];
|
||||
break;
|
||||
case TIMEOUT:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->timeout = atoi(argv[opt++]);
|
||||
break;
|
||||
case OPERATION:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->op = match_operation(argv[opt++]);
|
||||
break;
|
||||
case DEBUG:
|
||||
profile->debug = 1;
|
||||
break;
|
||||
case SMS_PDU:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->sms_pdu = argv[opt++];
|
||||
break;
|
||||
case SMS_INDEX:
|
||||
if (!has_more_argv())
|
||||
{
|
||||
usage();
|
||||
return -1;
|
||||
}
|
||||
profile->sms_index = atoi(argv[opt++]);
|
||||
break;
|
||||
default:
|
||||
err_msg("Invalid option: %s", argv[opt]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// default settings:
|
||||
if (profile->baud_rate == 0 )
|
||||
{
|
||||
profile->baud_rate = 115200;
|
||||
}
|
||||
if (profile->data_bits == 0)
|
||||
{
|
||||
profile->data_bits = 8;
|
||||
}
|
||||
if (profile->timeout == 0)
|
||||
{
|
||||
profile->timeout = 3;
|
||||
}
|
||||
if (profile->op == 0 || profile->op == -1)
|
||||
{
|
||||
profile->op = AT_OP;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int run_op(PROFILE_T *profile)
|
||||
{
|
||||
switch (profile->op)
|
||||
{
|
||||
case AT_OP:
|
||||
at(profile);
|
||||
break;
|
||||
case SMS_READ_OP:
|
||||
sms_read(profile);
|
||||
break;
|
||||
case SMS_SEND_OP:
|
||||
sms_send(profile);
|
||||
break;
|
||||
case SMS_DELETE_OP:
|
||||
sms_delete(profile);
|
||||
break;
|
||||
default:
|
||||
err_msg("Invalid operation");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
// init
|
||||
self_name = argv[0];
|
||||
PROFILE_T *profile = &s_profile;
|
||||
parse_user_input(argc, argv, profile);
|
||||
dump_profile();
|
||||
signal(SIGALRM, _timeout);
|
||||
|
||||
// try open tty devices
|
||||
if (open_tty_device(profile))
|
||||
{
|
||||
err_msg("Failed to open tty device");
|
||||
return -1;
|
||||
}
|
||||
if (run_op(profile))
|
||||
{
|
||||
err_msg("Failed to run operation %d", profile->op);
|
||||
return -1;
|
||||
}
|
||||
|
||||
dbg_msg("Exit");
|
||||
return 0;
|
||||
}
|
43
application/tom_modem/src/main.h
Normal file
43
application/tom_modem/src/main.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _MAIN_H_
|
||||
#define _MAIN_H_
|
||||
#include "modem_types.h"
|
||||
#include "main.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
#include <signal.h>
|
||||
#include <sys/select.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define DEFAULT_TIMEOUT 3
|
||||
//
|
||||
|
||||
FILE *fdi; // file descriptor for input
|
||||
FILE *fdo; // file descriptor for output
|
||||
int tty_fd; // file descriptor for tty device
|
||||
|
||||
PROFILE_T s_profile; // global profile
|
||||
char *self_name; // program name
|
||||
|
||||
extern int at(PROFILE_T *profile);
|
||||
|
||||
extern int sms_read(PROFILE_T *profile);
|
||||
|
||||
extern int sms_send(PROFILE_T *profile);
|
||||
|
||||
extern int sms_delete(PROFILE_T *profile);
|
||||
|
||||
extern void dump_profile();
|
||||
|
||||
extern int match_option(char *option_name);
|
||||
|
||||
extern int match_operation(char *operation_name);
|
||||
|
||||
extern int open_tty_device(PROFILE_T *profile);
|
||||
|
||||
extern int usage();
|
||||
|
||||
#endif
|
125
application/tom_modem/src/modem_types.h
Normal file
125
application/tom_modem/src/modem_types.h
Normal file
@ -0,0 +1,125 @@
|
||||
|
||||
#ifndef _MODEM_TYPES_H_
|
||||
#define _MODEM_TYPES_H_
|
||||
|
||||
//options
|
||||
#define AT_CMD_S 'c'
|
||||
#define TTY_DEV_S 'd'
|
||||
#define BAUD_RATE_S 'b'
|
||||
#define DATA_BITS_S 'B'
|
||||
#define PARITY_S 'P'
|
||||
#define STOP_BITS_S 'S'
|
||||
#define FLOW_CONTROL_S 'F'
|
||||
#define TIMEOUT_S 't'
|
||||
#define OPERATION_S 'o'
|
||||
#define DEBUG_S 'D'
|
||||
#define SMS_PDU_S 'p'
|
||||
#define SMS_INDEX_S 'i'
|
||||
|
||||
#define AT_CMD_L "at_cmd"
|
||||
#define TTY_DEV_L "tty_dev"
|
||||
#define BAUD_RATE_L "baud_rate"
|
||||
#define DATA_BITS_L "data_bits"
|
||||
#define PARITY_L "parity"
|
||||
#define STOP_BITS_L "stop_bits"
|
||||
#define FLOW_CONTROL_L "flow_control"
|
||||
#define TIMEOUT_L "timeout"
|
||||
#define OPERATION_L "operation"
|
||||
#define DEBUG_L "debug"
|
||||
#define SMS_PDU_L "sms_pdu"
|
||||
#define SMS_INDEX_L "sms_index"
|
||||
|
||||
//operations
|
||||
#define AT_OP_S 'a'
|
||||
#define AT_OP_L "at"
|
||||
#define SMS_READ_OP_S 'r'
|
||||
#define SMS_READ_OP_L "sms_read"
|
||||
#define SMS_SEND_OP_S 's'
|
||||
#define SMS_SEND_OP_L "sms_send"
|
||||
#define SMS_DELETE_OP_S 'd'
|
||||
#define SMS_DELETE_OP_L "sms_delete"
|
||||
|
||||
#define SET_READ_STORAGE "AT+CPMS=\"%s\""
|
||||
#define SET_PDU_FORMAT "AT+CMGF=0"
|
||||
#define READ_ALL_SMS "AT+CMGL=4"
|
||||
#define SEND_SMS "AT+CMGS=%d"
|
||||
#define DELETE_SMS "AT+CMGD=%d"
|
||||
|
||||
#define SMS_BUF_SIZE 16384
|
||||
#define LINE_BUF 1024
|
||||
#define SMS_LIST_SIZE 128
|
||||
#define COMMON_BUF_SIZE 1024
|
||||
#define PHONE_NUMBER_SIZE 64
|
||||
#define SMS_TEXT_SIZE 256
|
||||
#define SMS_PDU_STR_SIZE 512
|
||||
#define SMS_PDU_HEX_SIZE 512
|
||||
|
||||
// at_tool profile
|
||||
typedef struct _PROFILE {
|
||||
// AT command
|
||||
// TTY device
|
||||
// Baud rate
|
||||
// Data bits
|
||||
// Parity
|
||||
// Stop bits
|
||||
// Flow control
|
||||
// Timeout
|
||||
// operation
|
||||
// debug mode
|
||||
char *at_cmd;
|
||||
char *tty_dev;
|
||||
int baud_rate;
|
||||
int data_bits;
|
||||
char *parity;
|
||||
int stop_bits;
|
||||
char *flow_control;
|
||||
int timeout;
|
||||
int op;
|
||||
int debug;
|
||||
char *sms_pdu;
|
||||
int sms_index;
|
||||
} PROFILE_T;
|
||||
|
||||
typedef struct _SMS {
|
||||
int sms_index;
|
||||
int sms_lenght;
|
||||
int ref_number;
|
||||
int segment_number;
|
||||
int timestamp;
|
||||
int total_segments;
|
||||
int type;
|
||||
char *sender;
|
||||
char *sms_text;
|
||||
char *sms_pdu;
|
||||
} SMS_T;
|
||||
|
||||
enum SMS_CHARSET {
|
||||
SMS_CHARSET_7BIT,
|
||||
SMS_CHARSET_UCS2
|
||||
};
|
||||
|
||||
enum OPTIONS {
|
||||
AT_CMD,
|
||||
TTY_DEV,
|
||||
BAUD_RATE,
|
||||
DATA_BITS,
|
||||
PARITY,
|
||||
STOP_BITS,
|
||||
FLOW_CONTROL,
|
||||
TIMEOUT,
|
||||
OPERATION,
|
||||
DEBUG,
|
||||
SMS_PDU,
|
||||
SMS_INDEX
|
||||
};
|
||||
|
||||
enum OPERATIONS {
|
||||
NULL_OP,
|
||||
AT_OP,
|
||||
SMS_READ_OP,
|
||||
SMS_SEND_OP,
|
||||
SMS_DELETE_OP
|
||||
};
|
||||
|
||||
|
||||
#endif
|
21
application/tom_modem/src/pdu_lib/Makefile
Normal file
21
application/tom_modem/src/pdu_lib/Makefile
Normal file
@ -0,0 +1,21 @@
|
||||
ALL: pdu_decoder
|
||||
|
||||
#CROSS_COMPILE=mips-openwrt-linux-
|
||||
|
||||
#CC = $(CROSS_COMPILE)gcc
|
||||
|
||||
#CFLAGS = -O2
|
||||
|
||||
pdu.o:
|
||||
$(CC) $(CFLAGS) -c pdu.c
|
||||
pdu_decoder.o:
|
||||
$(CC) $(CFLAGS) -c pdu_decoder.c
|
||||
ucs2_to_utf8:
|
||||
$(CC) $(CFLAGS) -c ucs2_to_utf8.c
|
||||
pdu_decoder: pdu.o pdu_decoder.o ucs2_to_utf8
|
||||
$(CC) $(CFLAGS) ucs2_to_utf8.o pdu.o pdu_decoder.o -o pdu_decoder
|
||||
clean:
|
||||
rm -f *.o pdu_decoder
|
||||
test: clean ALL
|
||||
echo "0891683108501405F8240BA10156686616F60008414090912385235C6D4191CF6C4752A860015BC67801FF1A00350030003900360036FF0C4EB2FF0C8BB05F9762BD59566BCF592990FD8981676554E6FF0C611F89C9597D76848BDD63A883507ED960A87684670B53CBFF019884795D60A84E2D5956FF01"|./pdu_decoder
|
||||
echo "0891683108501405F8640BA10156686616F6000841400100957423830608048A3002026B21767B5F556D4191CF6C475373900100356D4191CF5E01FF0853EF63620035004D6D4191CFFF09FF0C731B623394FE63A5FF1A0068007400740070003A002F002F007300680061006B0065002E00730064002E006300680069006E0061006D006F00620069006C0065002E0063006F006D30025C714E1C79FB52A8"|./pdu_decoder
|
421
application/tom_modem/src/pdu_lib/pdu.c
Normal file
421
application/tom_modem/src/pdu_lib/pdu.c
Normal file
@ -0,0 +1,421 @@
|
||||
/*
|
||||
* 2017 - 2021 Cezary Jackiewicz <cezary@eko.one.pl>
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
*/
|
||||
// Copyright 2011 The Avalon Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
//
|
||||
// SMS encoding/decoding functions, which are based on examples from:
|
||||
// http://www.dreamfabric.com/sms/
|
||||
|
||||
#include "pdu.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
enum {
|
||||
BITMASK_7BITS = 0x7F,
|
||||
BITMASK_8BITS = 0xFF,
|
||||
BITMASK_HIGH_4BITS = 0xF0,
|
||||
BITMASK_LOW_4BITS = 0x0F,
|
||||
|
||||
TYPE_OF_ADDRESS_UNKNOWN = 0x81,
|
||||
TYPE_OF_ADDRESS_INTERNATIONAL_PHONE = 0x91,
|
||||
TYPE_OF_ADDRESS_NATIONAL_SUBSCRIBER = 0xC8,
|
||||
TYPE_OF_ADDRESS_ALPHANUMERIC = 0xD0,
|
||||
|
||||
SMS_DELIVER_ONE_MESSAGE = 0x04,
|
||||
SMS_SUBMIT = 0x11,
|
||||
|
||||
SMS_MAX_7BIT_TEXT_LENGTH = 160,
|
||||
};
|
||||
|
||||
// Swap decimal digits of a number (e.g. 12 -> 21).
|
||||
static unsigned char
|
||||
SwapDecimalNibble(const unsigned char x)
|
||||
{
|
||||
return (x / 16) + ((x % 16) * 10);
|
||||
}
|
||||
|
||||
// Encode/Decode PDU: Translate ASCII 7bit characters to 8bit buffer.
|
||||
// SMS encoding example from: http://www.dreamfabric.com/sms/.
|
||||
//
|
||||
// 7-bit ASCII: "hellohello"
|
||||
// [0]:h [1]:e [2]:l [3]:l [4]:o [5]:h [6]:e [7]:l [8]:l [9]:o
|
||||
// 1101000 1100101 1101100 1101100 1101111 1101000 1100101 1101100 1101100 1101111
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// /-------------/ ///-------/// /////-///// \------------\ ||||||| \\\\\\ .
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// input buffer position
|
||||
// 10000000 22111111 33322222 44443333 55555333 66666655 77777776 98888888 --999999
|
||||
// | ||| ||||| | ||||||| ||||||
|
||||
// 8bit encoded buffer
|
||||
// 11101000 00110010 10011011 11111101 01000110 10010111 11011001 11101100 00110111
|
||||
// E8 32 9B FD 46 97 D9 EC 37
|
||||
|
||||
|
||||
// Encode PDU message by merging 7 bit ASCII characters into 8 bit octets.
|
||||
int
|
||||
EncodePDUMessage(const char* sms_text, int sms_text_length, unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
// Check if output buffer is big enough.
|
||||
if ((sms_text_length * 7 + 7) / 8 > buffer_size)
|
||||
return -1;
|
||||
|
||||
int output_buffer_length = 0;
|
||||
int carry_on_bits = 1;
|
||||
int i = 0;
|
||||
|
||||
for (; i < sms_text_length - 1; ++i) {
|
||||
output_buffer[output_buffer_length++] =
|
||||
((sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1)) |
|
||||
((sms_text[i + 1] & BITMASK_7BITS) << (8 - carry_on_bits));
|
||||
carry_on_bits++;
|
||||
if (carry_on_bits == 8) {
|
||||
carry_on_bits = 1;
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (i <= sms_text_length)
|
||||
output_buffer[output_buffer_length++] = (sms_text[i] & BITMASK_7BITS) >> (carry_on_bits - 1);
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
// Decode PDU message by splitting 8 bit encoded buffer into 7 bit ASCII
|
||||
// characters.
|
||||
int
|
||||
DecodePDUMessage_GSM_7bit(const unsigned char* buffer, int buffer_length, char* output_sms_text, int sms_text_length)
|
||||
{
|
||||
int output_text_length = 0;
|
||||
if (buffer_length > 0)
|
||||
output_sms_text[output_text_length++] = BITMASK_7BITS & buffer[0];
|
||||
|
||||
if (sms_text_length > 1) {
|
||||
int carry_on_bits = 1;
|
||||
int i = 1;
|
||||
for (; i < buffer_length; ++i) {
|
||||
|
||||
output_sms_text[output_text_length++] = BITMASK_7BITS & ((buffer[i] << carry_on_bits) | (buffer[i - 1] >> (8 - carry_on_bits)));
|
||||
|
||||
if (output_text_length == sms_text_length) break;
|
||||
|
||||
carry_on_bits++;
|
||||
|
||||
if (carry_on_bits == 8) {
|
||||
carry_on_bits = 1;
|
||||
output_sms_text[output_text_length++] = buffer[i] & BITMASK_7BITS;
|
||||
if (output_text_length == sms_text_length) break;
|
||||
}
|
||||
|
||||
}
|
||||
if (output_text_length < sms_text_length) // Add last remainder.
|
||||
output_sms_text[output_text_length++] = buffer[i - 1] >> (8 - carry_on_bits);
|
||||
}
|
||||
|
||||
return output_text_length;
|
||||
}
|
||||
|
||||
#define GSM_7BITS_ESCAPE 0x1b
|
||||
|
||||
static const unsigned char gsm7bits_to_latin1[128] = {
|
||||
'@', 0xa3, '$', 0xa5, 0xe8, 0xe9, 0xf9, 0xec, 0xf2, 0xc7, '\n', 0xd8, 0xf8, '\r', 0xc5, 0xe5,
|
||||
0, '_', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xc6, 0xe6, 0xdf, 0xc9,
|
||||
' ', '!', '"', '#', 0xa4, '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
|
||||
0xa1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0xc4, 0xd6, 0xd1, 0xdc, 0xa7,
|
||||
0xbf, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0xe4, 0xf6, 0xf1, 0xfc, 0xe0,
|
||||
};
|
||||
|
||||
static const unsigned char gsm7bits_extend_to_latin1[128] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\f', 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, 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,
|
||||
};
|
||||
|
||||
static int
|
||||
G7bitToAscii(char* buffer, int buffer_length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i<buffer_length; i++) {
|
||||
if (buffer[i] < 128) {
|
||||
if (buffer[i] == GSM_7BITS_ESCAPE) {
|
||||
buffer[i] = gsm7bits_extend_to_latin1[buffer[i + 1]];
|
||||
memmove(&buffer[i + 1], &buffer[i + 2], buffer_length - i - 1);
|
||||
buffer_length--;
|
||||
} else {
|
||||
buffer[i] = gsm7bits_to_latin1[buffer[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer_length;
|
||||
}
|
||||
|
||||
#define NPC '?'
|
||||
|
||||
static const int latin1_to_gsm7bits[256] = {
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, 0x0a, NPC,-0x0a, 0x0d, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
0x20, 0x21, 0x22, 0x23, 0x02, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x00, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,-0x3c,-0x2f,-0x3e,-0x14, 0x11,
|
||||
NPC, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,-0x28,-0x40,-0x29,-0x3d, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, 0x40, NPC, 0x01, 0x24, 0x03, NPC, 0x5f, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, NPC, 0x60,
|
||||
NPC, NPC, NPC, NPC, 0x5b, 0x0e, 0x1c, 0x09, NPC, 0x1f, NPC, NPC, NPC, NPC, NPC, NPC,
|
||||
NPC, 0x5d, NPC, NPC, NPC, NPC, 0x5c, NPC, 0x0b, NPC, NPC, NPC, 0x5e, NPC, NPC, 0x1e,
|
||||
0x7f, NPC, NPC, NPC, 0x7b, 0x0f, 0x1d, NPC, 0x04, 0x05, NPC, NPC, 0x07, NPC, NPC, NPC,
|
||||
NPC, 0x7d, 0x08, NPC, NPC, NPC, 0x7c, NPC, 0x0c, 0x06, NPC, NPC, 0x7e, NPC, NPC, NPC,
|
||||
};
|
||||
|
||||
static int
|
||||
AsciiToG7bit(const char* buffer, int buffer_length, unsigned char* output_buffer)
|
||||
{
|
||||
int i, j, val;
|
||||
|
||||
j=0;
|
||||
for (i = 0; i < buffer_length; i++) {
|
||||
val = latin1_to_gsm7bits[buffer[i] & 0xFF];
|
||||
if (val < 0) {
|
||||
output_buffer[j++] = GSM_7BITS_ESCAPE;
|
||||
output_buffer[j++] = -1*val;
|
||||
} else {
|
||||
if (((buffer[i] & 0xFF) & 0xE0) == 0xC0) { /* test for two byte utf8 char */
|
||||
val = NPC;
|
||||
i++;
|
||||
} else if (((buffer[i] & 0xFF) & 0xF0) == 0xE0) { /* test for three byte utf8 char */
|
||||
val = NPC;
|
||||
i++;
|
||||
i++;
|
||||
}
|
||||
output_buffer[j++] = val;
|
||||
}
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
// Encode a digit based phone number for SMS based format.
|
||||
static int
|
||||
EncodePhoneNumber(const char* phone_number, unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
int output_buffer_length = 0;
|
||||
const int phone_number_length = strlen(phone_number);
|
||||
|
||||
// Check if the output buffer is big enough.
|
||||
if ((phone_number_length + 1) / 2 > buffer_size)
|
||||
return -1;
|
||||
|
||||
int i = 0;
|
||||
for (; i < phone_number_length; ++i) {
|
||||
|
||||
if (phone_number[i] < '0' && phone_number[i] > '9')
|
||||
return -1;
|
||||
|
||||
if (i % 2 == 0) {
|
||||
output_buffer[output_buffer_length++] = BITMASK_HIGH_4BITS | (phone_number[i] - '0');
|
||||
} else {
|
||||
output_buffer[output_buffer_length - 1] =
|
||||
(output_buffer[output_buffer_length - 1] & BITMASK_LOW_4BITS) |
|
||||
((phone_number[i] - '0') << 4);
|
||||
}
|
||||
}
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
// Decode a digit based phone number for SMS based format.
|
||||
static int
|
||||
DecodePhoneNumber(const unsigned char* buffer, int phone_number_length, char* output_phone_number)
|
||||
{
|
||||
int i = 0;
|
||||
for (; i < phone_number_length; ++i) {
|
||||
if (i % 2 == 0)
|
||||
output_phone_number[i] = (buffer[i / 2] & BITMASK_LOW_4BITS) + '0';
|
||||
else
|
||||
output_phone_number[i] = ((buffer[i / 2] & BITMASK_HIGH_4BITS) >> 4) + '0';
|
||||
}
|
||||
output_phone_number[phone_number_length] = '\0'; // Terminate C string.
|
||||
return phone_number_length;
|
||||
}
|
||||
|
||||
// Encode a SMS message to PDU
|
||||
int
|
||||
pdu_encode(const char* service_center_number, const char* phone_number, const char* sms_text,
|
||||
unsigned char* output_buffer, int buffer_size)
|
||||
{
|
||||
if (buffer_size < 2)
|
||||
return -1;
|
||||
|
||||
int output_buffer_length = 0;
|
||||
|
||||
// 1. Set SMS center number.
|
||||
int length = 0;
|
||||
if (service_center_number && strlen(service_center_number) > 0) {
|
||||
output_buffer[1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
|
||||
length = EncodePhoneNumber(service_center_number,
|
||||
output_buffer + 2, buffer_size - 2);
|
||||
if (length < 0 && length >= 254)
|
||||
return -1;
|
||||
length++; // Add type of address.
|
||||
}
|
||||
output_buffer[0] = length;
|
||||
output_buffer_length = length + 1;
|
||||
if (output_buffer_length + 4 > buffer_size)
|
||||
return -1; // Check if it has space for four more bytes.
|
||||
|
||||
// 2. Set type of message.
|
||||
output_buffer[output_buffer_length++] = SMS_SUBMIT;
|
||||
output_buffer[output_buffer_length++] = 0x00; // Message reference.
|
||||
|
||||
// 3. Set phone number.
|
||||
output_buffer[output_buffer_length] = strlen(phone_number);
|
||||
|
||||
if (strlen(phone_number) < 6) {
|
||||
output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_UNKNOWN;
|
||||
} else {
|
||||
output_buffer[output_buffer_length + 1] = TYPE_OF_ADDRESS_INTERNATIONAL_PHONE;
|
||||
}
|
||||
|
||||
length = EncodePhoneNumber(phone_number,
|
||||
output_buffer + output_buffer_length + 2,
|
||||
buffer_size - output_buffer_length - 2);
|
||||
output_buffer_length += length + 2;
|
||||
if (output_buffer_length + 4 > buffer_size)
|
||||
return -1; // Check if it has space for four more bytes.
|
||||
|
||||
|
||||
// 4. Protocol identifiers.
|
||||
output_buffer[output_buffer_length++] = 0x00; // TP-PID: Protocol identifier.
|
||||
output_buffer[output_buffer_length++] = 0x00; // TP-DCS: Data coding scheme.
|
||||
output_buffer[output_buffer_length++] = 0xB0; // TP-VP: Validity: 10 days
|
||||
|
||||
// 5. SMS message.
|
||||
int sms_text_length = strlen(sms_text);
|
||||
char sms_text_7bit[2*SMS_MAX_7BIT_TEXT_LENGTH];
|
||||
sms_text_length = AsciiToG7bit(sms_text, sms_text_length, sms_text_7bit);
|
||||
if (sms_text_length > SMS_MAX_7BIT_TEXT_LENGTH)
|
||||
return -1;
|
||||
output_buffer[output_buffer_length++] = sms_text_length;
|
||||
length = EncodePDUMessage(sms_text_7bit, sms_text_length,
|
||||
output_buffer + output_buffer_length,
|
||||
buffer_size - output_buffer_length);
|
||||
if (length < 0)
|
||||
return -1;
|
||||
output_buffer_length += length;
|
||||
|
||||
return output_buffer_length;
|
||||
}
|
||||
|
||||
int pdu_decode(const unsigned char* buffer, int buffer_length,
|
||||
time_t* output_sms_time,
|
||||
char* output_sender_phone_number, int sender_phone_number_size,
|
||||
char* output_sms_text, int sms_text_size,
|
||||
int* tp_dcs,
|
||||
int* ref_number,
|
||||
int* total_parts,
|
||||
int* part_number,
|
||||
int* skip_bytes)
|
||||
{
|
||||
|
||||
if (buffer_length <= 0)
|
||||
return -1;
|
||||
|
||||
const int sms_deliver_start = 1 + buffer[0];
|
||||
if (sms_deliver_start + 1 > buffer_length)
|
||||
return -2;
|
||||
|
||||
const int user_data_header_length = (buffer[sms_deliver_start]>>4);
|
||||
|
||||
const int sender_number_length = buffer[sms_deliver_start + 1];
|
||||
if (sender_number_length + 1 > sender_phone_number_size)
|
||||
return -3; // Buffer too small to hold decoded phone number.
|
||||
|
||||
const int sender_type_of_address = buffer[sms_deliver_start + 2];
|
||||
if (sender_type_of_address == TYPE_OF_ADDRESS_ALPHANUMERIC) {
|
||||
int sender_len1 = DecodePDUMessage_GSM_7bit(buffer + sms_deliver_start + 3, (sender_number_length + 1) / 2, output_sender_phone_number, sender_number_length);
|
||||
int sender_len2 = G7bitToAscii(output_sender_phone_number, sender_len1 - 1);
|
||||
output_sender_phone_number[sender_len2] = 0;
|
||||
} else {
|
||||
DecodePhoneNumber(buffer + sms_deliver_start + 3, sender_number_length, output_sender_phone_number);
|
||||
}
|
||||
|
||||
const int sms_pid_start = sms_deliver_start + 3 + (buffer[sms_deliver_start + 1] + 1) / 2;
|
||||
|
||||
// Decode timestamp.
|
||||
struct tm sms_broken_time;
|
||||
sms_broken_time.tm_year = 100 + SwapDecimalNibble(buffer[sms_pid_start + 2]);
|
||||
sms_broken_time.tm_mon = SwapDecimalNibble(buffer[sms_pid_start + 3]) - 1;
|
||||
sms_broken_time.tm_mday = SwapDecimalNibble(buffer[sms_pid_start + 4]);
|
||||
sms_broken_time.tm_hour = SwapDecimalNibble(buffer[sms_pid_start + 5]);
|
||||
sms_broken_time.tm_min = SwapDecimalNibble(buffer[sms_pid_start + 6]);
|
||||
sms_broken_time.tm_sec = SwapDecimalNibble(buffer[sms_pid_start + 7]);
|
||||
(*output_sms_time) = timegm(&sms_broken_time);
|
||||
|
||||
const int sms_start = sms_pid_start + 2 + 7;
|
||||
if (sms_start + 1 > buffer_length) return -1; // Invalid input buffer.
|
||||
|
||||
int tmp;
|
||||
if((user_data_header_length&0x04)==0x04) {
|
||||
tmp = buffer[sms_start + 1] + 1;
|
||||
*skip_bytes = tmp;
|
||||
*ref_number = 0x000000FF&buffer[sms_start + tmp - 2];
|
||||
*total_parts = 0x000000FF&buffer[sms_start + tmp - 1];
|
||||
*part_number = 0x000000FF&buffer[sms_start + tmp];
|
||||
} else {
|
||||
tmp = 0;
|
||||
*skip_bytes = tmp;
|
||||
*ref_number = tmp;
|
||||
*total_parts = tmp;
|
||||
*part_number = tmp;
|
||||
}
|
||||
|
||||
int output_sms_text_length = buffer[sms_start];
|
||||
if (sms_text_size < output_sms_text_length) return -1; // Cannot hold decoded buffer.
|
||||
|
||||
const int sms_tp_dcs_start = sms_pid_start + 1;
|
||||
*tp_dcs = buffer[sms_tp_dcs_start];
|
||||
|
||||
switch((*tp_dcs / 4) % 4)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// GSM 7 bit
|
||||
int decoded_sms_text_size = DecodePDUMessage_GSM_7bit(buffer + sms_start + 1, buffer_length - (sms_start + 1),
|
||||
output_sms_text, output_sms_text_length);
|
||||
if (decoded_sms_text_size != output_sms_text_length) return -1; // Decoder length is not as expected.
|
||||
output_sms_text_length = G7bitToAscii(output_sms_text, output_sms_text_length);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// UCS2
|
||||
memcpy(output_sms_text, buffer + sms_start + 1, output_sms_text_length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Add a C string end.
|
||||
if (output_sms_text_length < sms_text_size)
|
||||
output_sms_text[output_sms_text_length] = 0;
|
||||
else
|
||||
output_sms_text[sms_text_size-1] = 0;
|
||||
|
||||
return output_sms_text_length;
|
||||
}
|
52
application/tom_modem/src/pdu_lib/pdu.h
Normal file
52
application/tom_modem/src/pdu_lib/pdu.h
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 2017 - 2021 Cezary Jackiewicz <cezary@eko.one.pl>
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
*/
|
||||
// Copyright 2011 The Avalon Project Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Apache License 2.0
|
||||
// that can be found in the LICENSE file.
|
||||
#ifndef SMS_PDU_H_
|
||||
#define SMS_PDU_H_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
enum { SMS_MAX_PDU_LENGTH = 256 };
|
||||
|
||||
/*
|
||||
* Encode an SMS message. Output the encoded message into output pdu buffer.
|
||||
* Returns the length of the SMS encoded message in the output buffer or
|
||||
* a negative number in case encoding failed (for example provided output buffer
|
||||
* does not have enough space).
|
||||
*/
|
||||
int pdu_encode(const char* service_center_number, const char* phone_number, const char* text,
|
||||
unsigned char* pdu, int pdu_size);
|
||||
|
||||
/*
|
||||
* Decode an SMS message. Output the decoded message into the sms text buffer.
|
||||
* Returns the length of the SMS dencoded message or a negative number in
|
||||
* case encoding failed (for example provided output buffer has not enough
|
||||
* space).
|
||||
*/
|
||||
int pdu_decode(const unsigned char* pdu, int pdu_len,
|
||||
time_t* sms_time,
|
||||
char* phone_number, int phone_number_size,
|
||||
char* text, int text_size,
|
||||
int* tp_dcs,
|
||||
int* ref_number,
|
||||
int* total_parts,
|
||||
int* part_number,
|
||||
int* skip_bytes);
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8);
|
||||
|
||||
int DecodePDUMessage_GSM_7bit(const unsigned char* buffer,
|
||||
int buffer_length,
|
||||
char* output_sms_text,
|
||||
int sms_text_length);
|
||||
|
||||
int EncodePDUMessage(const char* sms_text,
|
||||
int sms_text_length,
|
||||
unsigned char* output_buffer,
|
||||
int buffer_size);
|
||||
|
||||
#endif // SMS_SMS_H_
|
111
application/tom_modem/src/pdu_lib/pdu_decoder.c
Normal file
111
application/tom_modem/src/pdu_lib/pdu_decoder.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
* SMS PDU Decoder
|
||||
*/
|
||||
#include "pdu.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8);
|
||||
|
||||
int sms_decode()
|
||||
{
|
||||
char buffer[2*SMS_MAX_PDU_LENGTH+4];
|
||||
char *p = buffer;
|
||||
char t[2];
|
||||
int d;
|
||||
do
|
||||
{
|
||||
t[0] = getchar();
|
||||
if(t[0]=='\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
t[1] = getchar();
|
||||
if(t[1]=='\n')
|
||||
{
|
||||
break;
|
||||
}
|
||||
*p = strtol(t,NULL,16);
|
||||
p++;
|
||||
}while(1);
|
||||
|
||||
time_t sms_time;
|
||||
char sms_phone[40];
|
||||
char sms_text[161];
|
||||
int tp_dcs_type;
|
||||
int ref_number;
|
||||
int total_parts;
|
||||
int part_number;
|
||||
int skip_bytes;
|
||||
|
||||
int sms_text_length = pdu_decode((const unsigned char*)buffer,
|
||||
sizeof(buffer),
|
||||
&sms_time,
|
||||
sms_phone, sizeof(sms_phone),
|
||||
sms_text, sizeof(sms_text),
|
||||
&tp_dcs_type,
|
||||
&ref_number,
|
||||
&total_parts,
|
||||
&part_number,
|
||||
&skip_bytes);
|
||||
|
||||
printf("From:%s\n",sms_phone);
|
||||
printf("Textlen=%d\n",sms_text_length);
|
||||
char time_data_str[64];
|
||||
strftime(time_data_str,64,"%D %T", localtime(&sms_time));
|
||||
printf("Date/Time:%s\n",time_data_str);
|
||||
|
||||
if (total_parts > 0) {
|
||||
printf("Reference number: %d\n", ref_number);
|
||||
printf("SMS segment %d of %d\n", part_number, total_parts);
|
||||
}
|
||||
|
||||
switch((tp_dcs_type / 4) % 4)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// GSM7 bit
|
||||
int i = skip_bytes;
|
||||
if(skip_bytes > 0) i = (skip_bytes*8+6)/7;
|
||||
for(;i<sms_text_length;i++)
|
||||
{
|
||||
printf("%c", sms_text[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// UCS2
|
||||
for(int i = skip_bytes;i<sms_text_length;i+=2)
|
||||
{
|
||||
int ucs2_char = 0x000000FF&sms_text[i+1];
|
||||
ucs2_char|=(0x0000FF00&(sms_text[i]<<8));
|
||||
unsigned char utf8_char[5];
|
||||
int len = ucs2_to_utf8(ucs2_char,utf8_char);
|
||||
int j;
|
||||
for(j=0;j<len;j++)
|
||||
{
|
||||
printf("%c",utf8_char[j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
return sms_decode();
|
||||
}
|
||||
|
53
application/tom_modem/src/pdu_lib/ucs2_to_utf8.c
Normal file
53
application/tom_modem/src/pdu_lib/ucs2_to_utf8.c
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* 2014 lovewilliam <ztong@vt.edu>
|
||||
* from http://www.lemoda.net/c/ucs2-to-utf8/ucs2-to-utf8.c
|
||||
*/
|
||||
/* Input: a Unicode code point, "ucs2".
|
||||
|
||||
Output: UTF-8 characters in buffer "utf8".
|
||||
|
||||
Return value: the number of bytes written into "utf8", or -1 if
|
||||
there was an error.
|
||||
|
||||
This adds a zero byte to the end of the string. It assumes that the
|
||||
buffer "utf8" has at least four bytes of space to write to. */
|
||||
|
||||
#define UNICODE_SURROGATE_PAIR -2
|
||||
#define UNICODE_BAD_INPUT -1
|
||||
|
||||
int ucs2_to_utf8 (int ucs2, unsigned char * utf8)
|
||||
{
|
||||
if (ucs2 < 0x80) {
|
||||
utf8[0] = ucs2;
|
||||
utf8[1] = '\0';
|
||||
return 1;
|
||||
}
|
||||
if (ucs2 >= 0x80 && ucs2 < 0x800) {
|
||||
utf8[0] = (ucs2 >> 6) | 0xC0;
|
||||
utf8[1] = (ucs2 & 0x3F) | 0x80;
|
||||
utf8[2] = '\0';
|
||||
return 2;
|
||||
}
|
||||
if (ucs2 >= 0x800 && ucs2 < 0xFFFF) {
|
||||
if (ucs2 >= 0xD800 && ucs2 <= 0xDFFF) {
|
||||
/* Ill-formed. */
|
||||
return UNICODE_SURROGATE_PAIR;
|
||||
}
|
||||
utf8[0] = ((ucs2 >> 12) ) | 0xE0;
|
||||
utf8[1] = ((ucs2 >> 6 ) & 0x3F) | 0x80;
|
||||
utf8[2] = ((ucs2 ) & 0x3F) | 0x80;
|
||||
utf8[3] = '\0';
|
||||
return 3;
|
||||
}
|
||||
if (ucs2 >= 0x10000 && ucs2 < 0x10FFFF) {
|
||||
/* http://tidy.sourceforge.net/cgi-bin/lxr/source/src/utf8.c#L380 */
|
||||
utf8[0] = 0xF0 | (ucs2 >> 18);
|
||||
utf8[1] = 0x80 | ((ucs2 >> 12) & 0x3F);
|
||||
utf8[2] = 0x80 | ((ucs2 >> 6) & 0x3F);
|
||||
utf8[3] = 0x80 | ((ucs2 & 0x3F));
|
||||
utf8[4] = '\0';
|
||||
return 4;
|
||||
}
|
||||
return UNICODE_BAD_INPUT;
|
||||
}
|
||||
|
777
application/tom_modem/src/utils.c
Normal file
777
application/tom_modem/src/utils.c
Normal file
@ -0,0 +1,777 @@
|
||||
#include "utils.h"
|
||||
#include "pdu_lib/pdu.h"
|
||||
|
||||
int match_option(char *option_name)
|
||||
{
|
||||
char short_option;
|
||||
char *long_option;
|
||||
// if start with '-' then it is an single character option
|
||||
if (option_name[0] == '-' && option_name[1] != '-')
|
||||
{
|
||||
|
||||
short_option = option_name[1];
|
||||
switch (short_option)
|
||||
{
|
||||
case AT_CMD_S:
|
||||
return AT_CMD;
|
||||
case TTY_DEV_S:
|
||||
return TTY_DEV;
|
||||
case BAUD_RATE_S:
|
||||
return BAUD_RATE;
|
||||
case DATA_BITS_S:
|
||||
return DATA_BITS;
|
||||
case PARITY_S:
|
||||
return PARITY;
|
||||
case STOP_BITS_S:
|
||||
return STOP_BITS;
|
||||
case FLOW_CONTROL_S:
|
||||
return FLOW_CONTROL;
|
||||
case TIMEOUT_S:
|
||||
return TIMEOUT;
|
||||
case OPERATION_S:
|
||||
return OPERATION;
|
||||
case DEBUG_S:
|
||||
return DEBUG;
|
||||
case SMS_PDU_S:
|
||||
return SMS_PDU;
|
||||
case SMS_INDEX_S:
|
||||
return SMS_INDEX;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (option_name[0] == '-' && option_name[1] == '-')
|
||||
{
|
||||
long_option = option_name + 2;
|
||||
if (strcmp(long_option, AT_CMD_L) == 0)
|
||||
{
|
||||
return AT_CMD;
|
||||
}
|
||||
else if (strcmp(long_option, TTY_DEV_L) == 0)
|
||||
{
|
||||
return TTY_DEV;
|
||||
}
|
||||
else if (strcmp(long_option, BAUD_RATE_L) == 0)
|
||||
{
|
||||
return BAUD_RATE;
|
||||
}
|
||||
else if (strcmp(long_option, DATA_BITS_L) == 0)
|
||||
{
|
||||
return DATA_BITS;
|
||||
}
|
||||
else if (strcmp(long_option, PARITY_L) == 0)
|
||||
{
|
||||
return PARITY;
|
||||
}
|
||||
else if (strcmp(long_option, STOP_BITS_L) == 0)
|
||||
{
|
||||
return STOP_BITS;
|
||||
}
|
||||
else if (strcmp(long_option, FLOW_CONTROL_L) == 0)
|
||||
{
|
||||
return FLOW_CONTROL;
|
||||
}
|
||||
else if (strcmp(long_option, TIMEOUT_L) == 0)
|
||||
{
|
||||
return TIMEOUT;
|
||||
}
|
||||
else if (strcmp(long_option, OPERATION_L) == 0)
|
||||
{
|
||||
return OPERATION;
|
||||
}
|
||||
else if (strcmp(long_option, DEBUG_L) == 0)
|
||||
{
|
||||
return DEBUG;
|
||||
}
|
||||
else if (strcmp(long_option, SMS_PDU_L) == 0)
|
||||
{
|
||||
return SMS_PDU;
|
||||
}
|
||||
else if (strcmp(long_option, SMS_INDEX_L) == 0)
|
||||
{
|
||||
return SMS_INDEX;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
// if start with '--' then it is a long option
|
||||
return -1;
|
||||
}
|
||||
|
||||
int match_operation(char *operation_name)
|
||||
{
|
||||
|
||||
char short_op;
|
||||
int opstr_len = strlen(operation_name);
|
||||
if (opstr_len == 1)
|
||||
{
|
||||
short_op = operation_name[0];
|
||||
switch (short_op)
|
||||
{
|
||||
case AT_OP_S:
|
||||
return AT_OP;
|
||||
case SMS_READ_OP_S:
|
||||
return SMS_READ_OP;
|
||||
case SMS_SEND_OP_S:
|
||||
return SMS_SEND_OP;
|
||||
case SMS_DELETE_OP_S:
|
||||
return SMS_DELETE_OP;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (opstr_len > 1)
|
||||
{
|
||||
if (strcmp(operation_name, AT_OP_L) == 0)
|
||||
{
|
||||
return AT_OP;
|
||||
}
|
||||
else if (strcmp(operation_name, SMS_READ_OP_L) == 0)
|
||||
{
|
||||
return SMS_READ_OP;
|
||||
}
|
||||
else if (strcmp(operation_name, SMS_SEND_OP_L) == 0)
|
||||
{
|
||||
return SMS_SEND_OP;
|
||||
}
|
||||
else if (strcmp(operation_name, SMS_DELETE_OP_L) == 0)
|
||||
{
|
||||
return SMS_DELETE_OP;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int open_tty_device(PROFILE_T *profile)
|
||||
{
|
||||
tty_fd = open(profile->tty_dev, O_RDWR | O_NOCTTY);
|
||||
if (tty_fd < 0)
|
||||
{
|
||||
err_msg("Error opening tty device: %s", profile->tty_dev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (set_tty_device(profile) != 0)
|
||||
{
|
||||
err_msg("Error setting tty device");
|
||||
return -1;
|
||||
}
|
||||
tcflush(tty_fd, TCIOFLUSH);
|
||||
atexit(clean_up);
|
||||
close(tty_fd);
|
||||
tty_fd = open(profile->tty_dev, O_RDWR | O_NOCTTY);
|
||||
fdi = fdopen(tty_fd, "r");
|
||||
fdo = fdopen(tty_fd, "w");
|
||||
if (fdi == NULL || fdo == NULL)
|
||||
{
|
||||
err_msg("Error opening file descriptor");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setvbuf(fdo, NULL, _IOFBF, 0))
|
||||
{
|
||||
err_msg("Error setting buffer for fdi");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setvbuf(fdi, NULL, _IOLBF, 0))
|
||||
{
|
||||
err_msg("Error setting buffer for fdi");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_tty_device(PROFILE_T *profile)
|
||||
{
|
||||
int baud_rate, data_bits, stop_bits;
|
||||
char *flow_control;
|
||||
struct termios tty;
|
||||
baud_rate = profile->baud_rate;
|
||||
data_bits = profile->data_bits;
|
||||
stop_bits = profile->stop_bits;
|
||||
flow_control = profile->flow_control;
|
||||
if (tcgetattr(tty_fd, &tty) != 0)
|
||||
{
|
||||
err_msg("Error getting tty attributes");
|
||||
return -1;
|
||||
}
|
||||
memmove(&oldtio, &tty, sizeof(struct termios));
|
||||
cfmakeraw(&tty);
|
||||
tty.c_cflag |= CLOCAL; // 忽略调制解调器控制线,允许本地连接
|
||||
tty.c_cflag |= CREAD; // 使能接收
|
||||
|
||||
// clear flow control ,stop bits parity
|
||||
tty.c_cflag &= ~CRTSCTS;
|
||||
tty.c_cflag &= ~CSTOPB;
|
||||
tty.c_cflag &= ~PARENB;
|
||||
tty.c_oflag &= ~OPOST;
|
||||
tty.c_cc[VMIN] = 1;
|
||||
tty.c_cc[VTIME] = 0;
|
||||
|
||||
// set data bits 5,6,7,8
|
||||
tty.c_cflag &= ~CSIZE; // 清除数据位设置
|
||||
switch (data_bits)
|
||||
{
|
||||
case 5:
|
||||
tty.c_cflag |= CS5;
|
||||
break;
|
||||
case 6:
|
||||
tty.c_cflag |= CS6;
|
||||
break;
|
||||
case 7:
|
||||
tty.c_cflag |= CS7;
|
||||
break;
|
||||
case 8:
|
||||
tty.c_cflag |= CS8;
|
||||
break;
|
||||
default:
|
||||
tty.c_cflag |= CS8;
|
||||
break;
|
||||
}
|
||||
|
||||
// set baud rate
|
||||
switch (baud_rate)
|
||||
{
|
||||
case 4800:
|
||||
cfsetspeed(&tty, B4800);
|
||||
break;
|
||||
case 9600:
|
||||
cfsetspeed(&tty, B9600);
|
||||
break;
|
||||
case 19200:
|
||||
cfsetspeed(&tty, B19200);
|
||||
break;
|
||||
case 38400:
|
||||
cfsetspeed(&tty, B38400);
|
||||
break;
|
||||
case 57600:
|
||||
cfsetspeed(&tty, B57600);
|
||||
break;
|
||||
case 115200:
|
||||
cfsetspeed(&tty, B115200);
|
||||
break;
|
||||
|
||||
default:
|
||||
cfsetspeed(&tty, B115200);
|
||||
break;
|
||||
}
|
||||
if (tcsetattr(tty_fd, TCSANOW, &tty) != 0)
|
||||
{
|
||||
err_msg("Error setting tty attributes");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int char_to_hex(char c)
|
||||
{
|
||||
// convert char to hex
|
||||
int is_digit, is_lower, is_upper;
|
||||
is_digit = c - '0';
|
||||
is_lower = c - 'a' + 10;
|
||||
is_upper = c - 'A' + 10;
|
||||
if (is_digit >= 0 && is_digit <= 9)
|
||||
{
|
||||
return is_digit;
|
||||
}
|
||||
else if (is_lower >= 10 && is_lower <= 15)
|
||||
{
|
||||
return is_lower;
|
||||
}
|
||||
else if (is_upper >= 10 && is_upper <= 15)
|
||||
{
|
||||
return is_upper;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void clean_up()
|
||||
{
|
||||
if (tcsetattr(tty_fd, TCSANOW, &oldtio) != 0)
|
||||
{
|
||||
err_msg("Error restoring old tty attributes");
|
||||
return;
|
||||
}
|
||||
dbg_msg("Clean up success");
|
||||
tcflush(tty_fd, TCIOFLUSH);
|
||||
close(tty_fd);
|
||||
}
|
||||
|
||||
static void escape_json(char *input, char *output)
|
||||
{
|
||||
char *p = input;
|
||||
char *q = output;
|
||||
while (*p)
|
||||
{
|
||||
if (*p == '"')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = '"';
|
||||
}
|
||||
else if (*p == '\\')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = '\\';
|
||||
}
|
||||
else if (*p == '/')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = '/';
|
||||
}
|
||||
else if (*p == '\b')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = 'b';
|
||||
}
|
||||
else if (*p == '\f')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = 'f';
|
||||
}
|
||||
else if (*p == '\n')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = 'n';
|
||||
}
|
||||
else if (*p == '\r')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = 'r';
|
||||
}
|
||||
else if (*p == '\t')
|
||||
{
|
||||
*q++ = '\\';
|
||||
*q++ = 't';
|
||||
}
|
||||
else
|
||||
{
|
||||
*q++ = *p;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
int usage()
|
||||
{
|
||||
err_msg("Usage: %s [options]", self_name);
|
||||
err_msg("Options:");
|
||||
err_msg(" -c, --at_cmd <AT command> AT command");
|
||||
err_msg(" -d, --tty_dev <TTY device> TTY device **REQUIRED**");
|
||||
err_msg(" -b, --baud_rate <baud rate> Baud rate Default: 115200 Supported: 4800,9600,19200,38400,57600,115200");
|
||||
err_msg(" -B, --data_bits <data bits> Data bits Default: 8 Supported: 5,6,7,8");
|
||||
err_msg(" -t, --timeout <timeout> Timeout Default: 3");
|
||||
err_msg(" -o, --operation <operation> Operation(at[a:defualt], sms_read[r], sms_send[s], sms_delete[d])");
|
||||
err_msg(" -D, --debug Debug mode Default: off");
|
||||
err_msg(" -p, --sms_pdu <sms pdu> SMS PDU");
|
||||
err_msg(" -i, --sms_index <sms index> SMS index");
|
||||
err_msg("Example:");
|
||||
err_msg(" %s -c ATI -d /dev/ttyUSB2 -b 115200 -B 8 -o at #advance at mode set bautrate and data bit", self_name);
|
||||
err_msg(" %s -c ATI -d /dev/ttyUSB2 # normal at mode", self_name);
|
||||
err_msg(" %s -d /dev/mhi_DUN -o r # read sms", self_name);
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
void dump_profile()
|
||||
{
|
||||
dbg_msg("AT command: %s", s_profile.at_cmd);
|
||||
dbg_msg("TTY device: %s", s_profile.tty_dev);
|
||||
dbg_msg("Baud rate: %d", s_profile.baud_rate);
|
||||
dbg_msg("Data bits: %d", s_profile.data_bits);
|
||||
dbg_msg("Parity: %s", s_profile.parity);
|
||||
dbg_msg("Stop bits: %d", s_profile.stop_bits);
|
||||
dbg_msg("Flow control: %s", s_profile.flow_control);
|
||||
dbg_msg("Timeout: %d", s_profile.timeout);
|
||||
dbg_msg("Operation: %d", s_profile.op);
|
||||
dbg_msg("Debug: %d", s_profile.debug);
|
||||
dbg_msg("SMS PDU: %s", s_profile.sms_pdu);
|
||||
dbg_msg("SMS index: %d", s_profile.sms_index);
|
||||
}
|
||||
|
||||
int tty_read(FILE *fdi, char *output, int len, int timeout)
|
||||
{
|
||||
return tty_read_keyword(fdi, output, len, timeout, NULL);
|
||||
}
|
||||
|
||||
int tty_read_keyword(FILE *fdi, char *output, int len, int timeout, char *key_word)
|
||||
{
|
||||
int ret, fd;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
char tmp[LINE_BUF] = {0};
|
||||
int msg_len = 0;
|
||||
int key_word_len = 0;
|
||||
fd = fileno(fdi);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = timeout;
|
||||
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(fd, &rfds);
|
||||
if (key_word != NULL)
|
||||
{
|
||||
key_word_len = strlen(key_word);
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
ret = select(fd + 1, &rfds, NULL, NULL, &tv);
|
||||
if (ret == -1)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
{
|
||||
err_msg("Interrupted by signal");
|
||||
return -1;
|
||||
}
|
||||
err_msg("Error in select");
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fgets(tmp, LINE_BUF, fdi);
|
||||
if (output != NULL)
|
||||
msg_len += snprintf(output + msg_len, len - msg_len, "%s", tmp);
|
||||
dbg_msg("%s", tmp);
|
||||
}
|
||||
if (key_word != NULL){
|
||||
if (strncmp(tmp, key_word, key_word_len) == 0)
|
||||
{
|
||||
dbg_msg("Received end sign: %s", tmp);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (strncmp(tmp, "OK", 2) == 0 ||
|
||||
strncmp(tmp, "ERROR", 5) == 0 ||
|
||||
strncmp(tmp, "+CMS ERROR:", 11) == 0 ||
|
||||
strncmp(tmp, "NO CARRIER", 10) == 0){
|
||||
dbg_msg("Received end sign: %s", tmp);
|
||||
if (key_word == NULL){
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tty_write(FILE *fdo, char *input)
|
||||
{
|
||||
int cmd_len, ret;
|
||||
char *cmd_line;
|
||||
cmd_len = strlen(input) + 3;
|
||||
cmd_line = (char *)malloc(cmd_len);
|
||||
if (cmd_line == NULL)
|
||||
{
|
||||
err_msg("Error allocating memory");
|
||||
return -1;
|
||||
}
|
||||
snprintf(cmd_line, cmd_len, "%s\r\n", input);
|
||||
ret = fputs(cmd_line, fdo);
|
||||
free(cmd_line);
|
||||
fflush(fdo);
|
||||
usleep(100);
|
||||
if (ret < 0)
|
||||
{
|
||||
err_msg("Error writing to tty %d" , ret);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int at(PROFILE_T *profile)
|
||||
{
|
||||
char output[COMMON_BUF_SIZE] = {0};
|
||||
if (profile->at_cmd == NULL)
|
||||
{
|
||||
err_msg("AT command is empty");
|
||||
return -1;
|
||||
}
|
||||
alarm(profile->timeout);
|
||||
|
||||
if (tty_write(fdo, profile->at_cmd))
|
||||
{
|
||||
err_msg("Error writing to tty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tty_read(fdi, output, COMMON_BUF_SIZE, 1000))
|
||||
{
|
||||
err_msg("Error reading from tty");
|
||||
return -1;
|
||||
}
|
||||
user_msg("%s", output);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sms_read(PROFILE_T *profile)
|
||||
{
|
||||
SMS_T *sms_list[SMS_LIST_SIZE];
|
||||
SMS_T *sms;
|
||||
char sms_pdu[SMS_BUF_SIZE] = {0};
|
||||
tty_write(fdo, SET_PDU_FORMAT);
|
||||
alarm(profile->timeout);
|
||||
if (tty_read_keyword(fdi, NULL, COMMON_BUF_SIZE, 1000, "OK"))
|
||||
{
|
||||
err_msg("Error setting PDU format");
|
||||
return -1;
|
||||
}
|
||||
dbg_msg("Set PDU format success");
|
||||
tty_write(fdo, READ_ALL_SMS);
|
||||
alarm(profile->timeout);
|
||||
if (tty_read_keyword(fdi, sms_pdu, SMS_BUF_SIZE, 1000, "OK"))
|
||||
{
|
||||
err_msg("Error reading SMS");
|
||||
return -1;
|
||||
}
|
||||
alarm(0);
|
||||
|
||||
|
||||
//遍历 sms_pdu 的每一行
|
||||
char *line = strtok(sms_pdu, "\n");
|
||||
int sms_count = 0;
|
||||
while (line != NULL)
|
||||
{
|
||||
|
||||
if (strncmp(line, "+CMGL:", 6) == 0)
|
||||
{
|
||||
//解析 line +CMGL: 2,1,,102 获取短信索引
|
||||
sms = (SMS_T *)malloc(sizeof(SMS_T));
|
||||
memset(sms, 0, sizeof(SMS_T));
|
||||
char *pdu = strtok(NULL, "\n");
|
||||
sms->sms_pdu = (char *)malloc(strlen(pdu));
|
||||
sms->sender = (char *)malloc(PHONE_NUMBER_SIZE);
|
||||
sms->sms_text = (char *)malloc(SMS_TEXT_SIZE);
|
||||
sms->sms_index = get_sms_index(line);
|
||||
memcpy(sms->sms_pdu, pdu, strlen(pdu));
|
||||
int sms_len = decode(sms);
|
||||
if (sms_len > 0)
|
||||
{
|
||||
sms_list[sms_count] = sms;
|
||||
sms_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
destroy_sms(sms);
|
||||
}
|
||||
}
|
||||
line = strtok(NULL, "\n");
|
||||
}
|
||||
|
||||
// for (int i = 1; i <= sms_count; i++)
|
||||
// {
|
||||
// dump_sms(sms_list[i]);
|
||||
// //destroy_sms(sms_list[i]);
|
||||
// }
|
||||
display_sms_in_json(sms_list,sms_count);
|
||||
dbg_msg("Read SMS success");
|
||||
dbg_msg("%s", sms_pdu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sms_send(PROFILE_T *profile)
|
||||
{
|
||||
if (profile->sms_pdu == NULL)
|
||||
{
|
||||
err_msg("SMS PDU is empty");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pdu_len = strlen(profile->sms_pdu);
|
||||
int pdu_expected_len = (pdu_len) / 2 - 1;
|
||||
char *send_sms_cmd;
|
||||
char *write_pdu_cmd;
|
||||
tty_write(fdo, SET_PDU_FORMAT);
|
||||
alarm(profile->timeout);
|
||||
if (tty_read_keyword(fdi, NULL, COMMON_BUF_SIZE, 1000, "OK"))
|
||||
{
|
||||
err_msg("Error setting PDU format");
|
||||
return -1;
|
||||
}
|
||||
dbg_msg("Set PDU format success");
|
||||
send_sms_cmd = (char *)malloc(32);
|
||||
write_pdu_cmd = (char *)malloc(256);
|
||||
snprintf(send_sms_cmd, 32, SEND_SMS, pdu_expected_len);
|
||||
dbg_msg("Send SMS command: %s", send_sms_cmd);
|
||||
snprintf(write_pdu_cmd, 256, "%s%c", profile->sms_pdu, 0x1A);
|
||||
dbg_msg("Write PDU command: %s", write_pdu_cmd);
|
||||
free(send_sms_cmd);
|
||||
free(write_pdu_cmd);
|
||||
alarm(0);
|
||||
tty_write(fdo, send_sms_cmd);
|
||||
sleep(1);
|
||||
tty_write(fdo, write_pdu_cmd);
|
||||
alarm(profile->timeout);
|
||||
if (tty_read_keyword(fdi, NULL, COMMON_BUF_SIZE, 1000, "+CMGS:"))
|
||||
{
|
||||
err_msg("Error sending SMS STEP 2");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sms_delete(PROFILE_T *profile)
|
||||
{
|
||||
if (profile->sms_index < 0)
|
||||
{
|
||||
err_msg("SMS index is empty");
|
||||
return -1;
|
||||
}
|
||||
char *delete_sms_cmd;
|
||||
delete_sms_cmd = (char *)malloc(32);
|
||||
snprintf(delete_sms_cmd, 32, DELETE_SMS, profile->sms_index);
|
||||
tty_write(fdo, delete_sms_cmd);
|
||||
alarm(profile->timeout);
|
||||
if (tty_read_keyword(fdi, NULL, COMMON_BUF_SIZE, 1000, "OK"))
|
||||
{
|
||||
err_msg("Error deleting SMS");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int decode(SMS_T *sms)
|
||||
{
|
||||
char sms_text[SMS_TEXT_SIZE] = {0};
|
||||
int tp_dcs;
|
||||
int skip_bytes;
|
||||
int pdu_str_len;
|
||||
time_t sms_time;
|
||||
unsigned char hex_pdu[SMS_PDU_HEX_SIZE] = {0};
|
||||
pdu_str_len = strlen(sms->sms_pdu);
|
||||
for (int i = 0; i < pdu_str_len; i += 2)
|
||||
{
|
||||
hex_pdu[i / 2] = char_to_hex(sms->sms_pdu[i]) << 4;
|
||||
hex_pdu[i / 2] |= char_to_hex(sms->sms_pdu[i + 1]);
|
||||
}
|
||||
int sms_len = pdu_decode(hex_pdu, pdu_str_len/2,
|
||||
&sms->timestamp,
|
||||
sms->sender, PHONE_NUMBER_SIZE,
|
||||
sms_text, SMS_TEXT_SIZE,
|
||||
&tp_dcs,
|
||||
&sms->ref_number,
|
||||
&sms->total_segments,
|
||||
&sms->segment_number,
|
||||
&skip_bytes);
|
||||
if (sms_len <= 0)
|
||||
{
|
||||
err_msg("Error decoding pdu");
|
||||
return sms_len;
|
||||
}
|
||||
sms->sms_lenght = sms_len;
|
||||
|
||||
switch ((tp_dcs / 4) % 4)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
// GSM 7 bit
|
||||
sms->type = SMS_CHARSET_7BIT;
|
||||
int i;
|
||||
i = skip_bytes;
|
||||
if (skip_bytes > 0)
|
||||
i = (skip_bytes * 8 + 6) / 7;
|
||||
for (; i < strlen(sms_text); i++)
|
||||
{
|
||||
sprintf(sms->sms_text + i, "%c", sms_text[i]);
|
||||
}
|
||||
i++;
|
||||
sprintf(sms->sms_text + i, "%c", '\0');
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
// UCS2
|
||||
sms->type = SMS_CHARSET_UCS2;
|
||||
int offset = 0;
|
||||
for (int i = skip_bytes; i < SMS_TEXT_SIZE; i += 2)
|
||||
{
|
||||
int ucs2_char = 0x000000FF & sms_text[i + 1];
|
||||
ucs2_char |= (0x0000FF00 & (sms_text[i] << 8));
|
||||
unsigned char utf8_char[5];
|
||||
int len = ucs2_to_utf8(ucs2_char, utf8_char);
|
||||
int j;
|
||||
for (j = 0; j < len; j++)
|
||||
{
|
||||
sprintf(sms->sms_text + offset, "%c", utf8_char[j]);
|
||||
if (utf8_char[j] != '\0')
|
||||
{
|
||||
offset++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
offset++;
|
||||
sprintf(sms->sms_text + offset, "%c", '\0');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return sms_len;
|
||||
}
|
||||
|
||||
int display_sms_in_json(SMS_T **sms,int num)
|
||||
{
|
||||
|
||||
char msg_json[SMS_BUF_SIZE];
|
||||
int offset;
|
||||
offset = sprintf(msg_json, "{\"msg\":[");
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
char escaped_text[SMS_TEXT_SIZE];
|
||||
escape_json(sms[i]->sms_text, escaped_text);
|
||||
if (sms[i]->ref_number)
|
||||
offset += sprintf(msg_json + offset, "{\"index\":%d,\"sender\":\"%s\",\"timestamp\":%d,\"content\":\"%s\",\"reference\":%d,\"total\":%d,\"part\":%d},",
|
||||
sms[i]->sms_index, sms[i]->sender, sms[i]->timestamp, escaped_text, sms[i]->ref_number, sms[i]->total_segments, sms[i]->segment_number);
|
||||
else
|
||||
offset += sprintf(msg_json + offset, "{\"index\":%d,\"sender\":\"%s\",\"timestamp\":%d,\"content\":\"%s\"},",
|
||||
sms[i]->sms_index, sms[i]->sender, sms[i]->timestamp, escaped_text);
|
||||
}
|
||||
offset--;
|
||||
offset += sprintf(msg_json + offset, "]}");
|
||||
user_msg("%s\n", msg_json);
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
int dump_sms(SMS_T *sms)
|
||||
{
|
||||
dbg_msg("SMS Index: %d", sms->sms_index);
|
||||
dbg_msg("SMS Text: %s", sms->sms_text);
|
||||
dbg_msg("SMS Sender: %s", sms->sender);
|
||||
dbg_msg("SMS Timestamp: %d", sms->timestamp);
|
||||
dbg_msg("SMS Segment: %d/%d", sms->segment_number, sms->total_segments);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int destroy_sms(SMS_T *sms)
|
||||
{
|
||||
if (sms->sms_pdu != NULL)
|
||||
{
|
||||
free(sms->sms_pdu);
|
||||
}
|
||||
if (sms->sender != NULL)
|
||||
{
|
||||
free(sms->sender);
|
||||
}
|
||||
if (sms->sms_text != NULL)
|
||||
{
|
||||
free(sms->sms_text);
|
||||
}
|
||||
free(sms);
|
||||
return 0;
|
||||
}
|
59
application/tom_modem/src/utils.h
Normal file
59
application/tom_modem/src/utils.h
Normal file
@ -0,0 +1,59 @@
|
||||
#ifndef _UTILS_H
|
||||
#define _UTILS_H
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "modem_types.h"
|
||||
#include "main.h"
|
||||
|
||||
extern PROFILE_T s_profile;
|
||||
extern FILE *fdi; // file descriptor for input
|
||||
extern FILE *fdo; // file descriptor for output
|
||||
extern int tty_fd; // file descriptor for tty device
|
||||
struct termios oldtio; // old tty setting
|
||||
|
||||
|
||||
|
||||
#define dbg_msg(fmt, args...) do { \
|
||||
if (s_profile.debug) { \
|
||||
fprintf(stderr, "[DBG]" fmt, ##args); \
|
||||
fprintf(stderr, "\n"); \
|
||||
fflush(stderr); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define err_msg(fmt, args...) do { \
|
||||
if (1) { \
|
||||
fprintf(stderr, "[ERR]" fmt , ##args); \
|
||||
fprintf(stderr, "\n"); \
|
||||
fflush(stderr); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define get_sms_index(line) \
|
||||
({ \
|
||||
const char *index_str = (line) + 7; \
|
||||
const char *first_comma = strchr(index_str, ','); \
|
||||
int sms_index = -1; \
|
||||
if (first_comma) { \
|
||||
char temp[(size_t)(first_comma - index_str) + 1]; \
|
||||
memcpy(temp, index_str, first_comma - index_str); \
|
||||
temp[(size_t)(first_comma - index_str)] = '\0'; \
|
||||
sms_index = atoi(temp); \
|
||||
} \
|
||||
sms_index; \
|
||||
})
|
||||
|
||||
#define user_msg(fmt, args...) (fprintf(stdout, fmt , ##args))
|
||||
|
||||
|
||||
|
||||
int match_option(char *option_name);
|
||||
|
||||
int match_operation(char *operation_name);
|
||||
|
||||
int open_tty_device(PROFILE_T *profile);
|
||||
|
||||
static int set_tty_device(PROFILE_T *profile);
|
||||
|
||||
static void clean_up();
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user