Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
fcc912a9
提交
fcc912a9
authored
1月 10, 2011
作者:
Anthony Minessale
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add mod_fsk
上级
62941f69
显示空白字符变更
内嵌
并排
正在显示
8 个修改的文件
包含
1698 行增加
和
0 行删除
+1698
-0
Makefile
src/mod/applications/mod_fsk/Makefile
+6
-0
fsk.c
src/mod/applications/mod_fsk/fsk.c
+351
-0
fsk.h
src/mod/applications/mod_fsk/fsk.h
+113
-0
fsk_callerid.c
src/mod/applications/mod_fsk/fsk_callerid.c
+398
-0
fsk_callerid.h
src/mod/applications/mod_fsk/fsk_callerid.h
+144
-0
mod_fsk.c
src/mod/applications/mod_fsk/mod_fsk.c
+486
-0
uart.c
src/mod/applications/mod_fsk/uart.c
+124
-0
uart.h
src/mod/applications/mod_fsk/uart.h
+76
-0
没有找到文件。
src/mod/applications/mod_fsk/Makefile
0 → 100644
浏览文件 @
fcc912a9
BASE
=
../../../..
LOCAL_SOURCES
=
fsk.c uart.c fsk_callerid.c
LOCAL_OBJS
=
fsk.o uart.o fsk_callerid.o
include
$(BASE)/build/modmake.rules
src/mod/applications/mod_fsk/fsk.c
0 → 100644
浏览文件 @
fcc912a9
/*
* bell202.c
*
* Copyright (c) 2005 Robert Krten. 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 AUTHOR ``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 AUTHOR 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.
*
* This module contains a Bell-202 1200-baud FSK decoder, suitable for
* use in a library. The general style of the library calls is modeled
* after the POSIX pthread_*() functions.
*
* 2005 03 20 R. Krten created
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <math.h>
#include "fsk.h"
#include "uart.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
fsk_modem_definition_t
fsk_modem_definitions
[]
=
{
{
/* FSK_V23_FORWARD_MODE1 */
1700
,
1300
,
600
},
{
/* FSK_V23_FORWARD_MODE2 */
2100
,
1300
,
1200
},
{
/* FSK_V23_BACKWARD */
450
,
390
,
75
},
{
/* FSK_BELL202 */
2200
,
1200
,
1200
},
};
/*
* dsp_fsk_attr_init
*
* Initializes the attributes structure; this must be done before the
* attributes structure is used.
*/
void
dsp_fsk_attr_init
(
dsp_fsk_attr_t
*
attr
)
{
memset
(
attr
,
0
,
sizeof
(
*
attr
));
}
/*
* dsp_fsk_attr_get_bithandler
* dsp_fsk_attr_set_bithandler
* dsp_fsk_attr_get_bytehandler
* dsp_fsk_attr_set_bytehandler
* dsp_fsk_attr_getsamplerate
* dsp_fsk_attr_setsamplerate
*
* These functions get and set their respective elements from the
* attributes structure. If an error code is returned, it is just
* zero == ok, -1 == fail.
*/
bithandler_func_t
dsp_fsk_attr_get_bithandler
(
dsp_fsk_attr_t
*
attr
,
void
**
bithandler_arg
)
{
*
bithandler_arg
=
attr
->
bithandler_arg
;
return
attr
->
bithandler
;
}
void
dsp_fsk_attr_set_bithandler
(
dsp_fsk_attr_t
*
attr
,
bithandler_func_t
bithandler
,
void
*
bithandler_arg
)
{
attr
->
bithandler
=
bithandler
;
attr
->
bithandler_arg
=
bithandler_arg
;
}
bytehandler_func_t
dsp_fsk_attr_get_bytehandler
(
dsp_fsk_attr_t
*
attr
,
void
**
bytehandler_arg
)
{
*
bytehandler_arg
=
attr
->
bytehandler_arg
;
return
attr
->
bytehandler
;
}
void
dsp_fsk_attr_set_bytehandler
(
dsp_fsk_attr_t
*
attr
,
bytehandler_func_t
bytehandler
,
void
*
bytehandler_arg
)
{
attr
->
bytehandler
=
bytehandler
;
attr
->
bytehandler_arg
=
bytehandler_arg
;
}
int
dsp_fsk_attr_get_samplerate
(
dsp_fsk_attr_t
*
attr
)
{
return
attr
->
sample_rate
;
}
int
dsp_fsk_attr_set_samplerate
(
dsp_fsk_attr_t
*
attr
,
int
samplerate
)
{
if
(
samplerate
<=
0
)
{
return
-
1
;
}
attr
->
sample_rate
=
samplerate
;
return
0
;
}
/*
* dsp_fsk_create
*
* Creates a handle for subsequent use. The handle is created to contain
* a context data structure for use by the sample handler function. The
* function expects an initialized attributes structure, and returns the
* handle or a NULL if there were errors.
*
* Once created, the handle can be used until it is destroyed.
*/
dsp_fsk_handle_t
*
dsp_fsk_create
(
dsp_fsk_attr_t
*
attr
)
{
int
i
;
double
phi_mark
,
phi_space
;
dsp_fsk_handle_t
*
handle
;
handle
=
malloc
(
sizeof
(
*
handle
));
if
(
!
handle
)
{
return
NULL
;
}
memset
(
handle
,
0
,
sizeof
(
*
handle
));
/* fill the attributes member */
memcpy
(
&
handle
->
attr
,
attr
,
sizeof
(
*
attr
));
/* see if we can do downsampling. We only really need 6 samples to "match" */
if
(
attr
->
sample_rate
/
fsk_modem_definitions
[
FSK_BELL202
].
freq_mark
>
6
)
{
handle
->
downsampling_count
=
attr
->
sample_rate
/
fsk_modem_definitions
[
FSK_BELL202
].
freq_mark
/
6
;
}
else
{
handle
->
downsampling_count
=
1
;
}
handle
->
current_downsample
=
1
;
/* calculate the correlate size (number of samples required for slowest wave) */
handle
->
corrsize
=
attr
->
sample_rate
/
handle
->
downsampling_count
/
fsk_modem_definitions
[
FSK_BELL202
].
freq_mark
;
/* allocate the correlation sin/cos arrays and initialize */
for
(
i
=
0
;
i
<
4
;
i
++
)
{
handle
->
correlates
[
i
]
=
malloc
(
sizeof
(
double
)
*
handle
->
corrsize
);
if
(
handle
->
correlates
[
i
]
==
NULL
)
{
/* some failed, back out memory allocations */
dsp_fsk_destroy
(
&
handle
);
return
NULL
;
}
}
/* now initialize them */
phi_mark
=
2
.
*
M_PI
/
((
double
)
attr
->
sample_rate
/
(
double
)
handle
->
downsampling_count
/
(
double
)
fsk_modem_definitions
[
FSK_BELL202
].
freq_mark
);
phi_space
=
2
.
*
M_PI
/
((
double
)
attr
->
sample_rate
/
(
double
)
handle
->
downsampling_count
/
(
double
)
fsk_modem_definitions
[
FSK_BELL202
].
freq_space
);
for
(
i
=
0
;
i
<
handle
->
corrsize
;
i
++
)
{
handle
->
correlates
[
0
][
i
]
=
sin
(
phi_mark
*
(
double
)
i
);
handle
->
correlates
[
1
][
i
]
=
cos
(
phi_mark
*
(
double
)
i
);
handle
->
correlates
[
2
][
i
]
=
sin
(
phi_space
*
(
double
)
i
);
handle
->
correlates
[
3
][
i
]
=
cos
(
phi_space
*
(
double
)
i
);
}
/* initialize the ring buffer */
handle
->
buffer
=
malloc
(
sizeof
(
double
)
*
handle
->
corrsize
);
if
(
!
handle
->
buffer
)
{
/* failed; back out memory allocations */
dsp_fsk_destroy
(
&
handle
);
return
NULL
;
}
memset
(
handle
->
buffer
,
0
,
sizeof
(
double
)
*
handle
->
corrsize
);
handle
->
ringstart
=
0
;
/* initalize intra-cell position */
handle
->
cellpos
=
0
;
handle
->
celladj
=
fsk_modem_definitions
[
FSK_BELL202
].
baud_rate
/
(
double
)
attr
->
sample_rate
*
(
double
)
handle
->
downsampling_count
;
/* if they have provided a byte handler, add a UART to the processing chain */
if
(
handle
->
attr
.
bytehandler
)
{
dsp_uart_attr_t
uart_attr
;
dsp_uart_handle_t
*
uart_handle
;
dsp_uart_attr_init
(
&
uart_attr
);
dsp_uart_attr_set_bytehandler
(
&
uart_attr
,
handle
->
attr
.
bytehandler
,
handle
->
attr
.
bytehandler_arg
);
uart_handle
=
dsp_uart_create
(
&
uart_attr
);
if
(
uart_handle
==
NULL
)
{
dsp_fsk_destroy
(
&
handle
);
return
NULL
;
}
handle
->
attr
.
bithandler
=
dsp_uart_bit_handler
;
handle
->
attr
.
bithandler_arg
=
uart_handle
;
}
return
handle
;
}
/*
* dsp_fsk_destroy
*
* Destroys a handle, releasing any associated memory. Sets handle pointer to NULL
* so A destroyed handle can not be used for anything after the destroy.
*/
void
dsp_fsk_destroy
(
dsp_fsk_handle_t
**
handle
)
{
int
i
;
/* if empty handle, just return */
if
(
*
handle
==
NULL
)
{
return
;
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
if
((
*
handle
)
->
correlates
[
i
]
!=
NULL
)
{
free
((
*
handle
)
->
correlates
[
i
]);
(
*
handle
)
->
correlates
[
i
]
=
NULL
;
}
}
if
((
*
handle
)
->
buffer
!=
NULL
)
{
free
((
*
handle
)
->
buffer
);
(
*
handle
)
->
buffer
=
NULL
;
}
if
((
*
handle
)
->
attr
.
bytehandler
)
{
dsp_uart_handle_t
**
dhandle
=
(
void
*
)(
&
(
*
handle
)
->
attr
.
bithandler_arg
);
dsp_uart_destroy
(
dhandle
);
}
free
(
*
handle
);
*
handle
=
NULL
;
}
/*
* dsp_fsk_sample
*
* This is the main processing entry point. The function accepts a normalized
* sample (i.e., one whose range is between -1 and +1). The function performs
* the Bell-202 FSK modem decode processing, and, if it detects a valid bit,
* will call the bithandler associated with the attributes structure.
*
* For the Bell-202 standard, a logical zero (space) is 2200 Hz, and a logical
* one (mark) is 1200 Hz.
*/
void
dsp_fsk_sample
(
dsp_fsk_handle_t
*
handle
,
double
normalized_sample
)
{
double
val
;
double
factors
[
4
];
int
i
,
j
;
/* if we can avoid processing samples, do so */
if
(
handle
->
downsampling_count
!=
1
)
{
if
(
handle
->
current_downsample
<
handle
->
downsampling_count
)
{
handle
->
current_downsample
++
;
return
;
/* throw this sample out */
}
handle
->
current_downsample
=
1
;
}
/* store sample in buffer */
handle
->
buffer
[
handle
->
ringstart
++
]
=
normalized_sample
;
if
(
handle
->
ringstart
>=
handle
->
corrsize
)
{
handle
->
ringstart
=
0
;
}
/* do the correlation calculation */
factors
[
0
]
=
factors
[
1
]
=
factors
[
2
]
=
factors
[
3
]
=
0
;
/* clear out intermediate sums */
j
=
handle
->
ringstart
;
for
(
i
=
0
;
i
<
handle
->
corrsize
;
i
++
)
{
if
(
j
>=
handle
->
corrsize
)
{
j
=
0
;
}
val
=
handle
->
buffer
[
j
];
factors
[
0
]
+=
handle
->
correlates
[
0
][
i
]
*
val
;
factors
[
1
]
+=
handle
->
correlates
[
1
][
i
]
*
val
;
factors
[
2
]
+=
handle
->
correlates
[
2
][
i
]
*
val
;
factors
[
3
]
+=
handle
->
correlates
[
3
][
i
]
*
val
;
j
++
;
}
/* store the bit (bit value is comparison of the two sets of correlate factors) */
handle
->
previous_bit
=
handle
->
current_bit
;
handle
->
current_bit
=
(
factors
[
0
]
*
factors
[
0
]
+
factors
[
1
]
*
factors
[
1
]
>
factors
[
2
]
*
factors
[
2
]
+
factors
[
3
]
*
factors
[
3
]);
/* if there's a transition, we can synchronize the cell position */
if
(
handle
->
previous_bit
!=
handle
->
current_bit
)
{
handle
->
cellpos
=
0
.
5
;
/* adjust cell position to be in the middle of the cell */
}
handle
->
cellpos
+=
handle
->
celladj
;
/* walk the cell along */
if
(
handle
->
cellpos
>
1
.
0
)
{
handle
->
cellpos
-=
1
.
0
;
switch
(
handle
->
state
)
{
case
FSK_STATE_DATA
:
{
(
*
handle
->
attr
.
bithandler
)
(
handle
->
attr
.
bithandler_arg
,
handle
->
current_bit
);
}
break
;
case
FSK_STATE_CHANSEIZE
:
{
if
(
handle
->
last_bit
!=
handle
->
current_bit
)
{
handle
->
conscutive_state_bits
++
;
}
else
{
handle
->
conscutive_state_bits
=
0
;
}
if
(
handle
->
conscutive_state_bits
>
15
)
{
handle
->
state
=
FSK_STATE_CARRIERSIG
;
handle
->
conscutive_state_bits
=
0
;
}
}
break
;
case
FSK_STATE_CARRIERSIG
:
{
if
(
handle
->
current_bit
)
{
handle
->
conscutive_state_bits
++
;
}
else
{
handle
->
conscutive_state_bits
=
0
;
}
if
(
handle
->
conscutive_state_bits
>
15
)
{
handle
->
state
=
FSK_STATE_DATA
;
handle
->
conscutive_state_bits
=
0
;
}
}
break
;
}
handle
->
last_bit
=
handle
->
current_bit
;
}
}
src/mod/applications/mod_fsk/fsk.h
0 → 100644
浏览文件 @
fcc912a9
/*
* bell202.h
*
* Copyright (c) 2005 Robert Krten. 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 AUTHOR ``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 AUTHOR 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.
*
* This module contains the manifest constants and declarations for
* the Bell-202 1200 baud FSK modem.
*
* 2005 03 20 R. Krten created
*/
#ifndef __FSK_H__
#define __FSK_H__
#include "uart.h"
typedef
struct
{
int
freq_space
;
/* Frequency of the 0 bit */
int
freq_mark
;
/* Frequency of the 1 bit */
int
baud_rate
;
/* baud rate for the modem */
}
fsk_modem_definition_t
;
/* Must be kept in sync with fsk_modem_definitions array in fsk.c */
/* V.23 definitions: http://www.itu.int/rec/recommendation.asp?type=folders&lang=e&parent=T-REC-V.23 */
typedef
enum
{
FSK_V23_FORWARD_MODE1
=
0
,
/* Maximum 600 bps for long haul */
FSK_V23_FORWARD_MODE2
,
/* Standard 1200 bps V.23 */
FSK_V23_BACKWARD
,
/* 75 bps return path for V.23 */
FSK_BELL202
/* Bell 202 half-duplex 1200 bps */
}
fsk_modem_types_t
;
typedef
enum
{
FSK_STATE_CHANSEIZE
=
0
,
FSK_STATE_CARRIERSIG
,
FSK_STATE_DATA
}
fsk_state_t
;
typedef
struct
dsp_fsk_attr_s
{
int
sample_rate
;
/* sample rate in HZ */
bithandler_func_t
bithandler
;
/* bit handler */
void
*
bithandler_arg
;
/* arbitrary ID passed to bithandler as first argument */
bytehandler_func_t
bytehandler
;
/* byte handler */
void
*
bytehandler_arg
;
/* arbitrary ID passed to bytehandler as first argument */
}
dsp_fsk_attr_t
;
typedef
struct
{
fsk_state_t
state
;
dsp_fsk_attr_t
attr
;
/* attributes structure */
double
*
correlates
[
4
];
/* one for each of sin/cos for mark/space */
int
corrsize
;
/* correlate size (also number of samples in ring buffer) */
double
*
buffer
;
/* sample ring buffer */
int
ringstart
;
/* ring buffer start offset */
double
cellpos
;
/* bit cell position */
double
celladj
;
/* bit cell adjustment for each sample */
int
previous_bit
;
/* previous bit (for detecting a transition to sync-up cell position) */
int
current_bit
;
/* current bit */
int
last_bit
;
int
downsampling_count
;
/* number of samples to skip */
int
current_downsample
;
/* current skip count */
int
conscutive_state_bits
;
/* number of bits in a row that matches the pattern for the current state */
}
dsp_fsk_handle_t
;
/*
* Function prototypes
*
* General calling order is:
* a) create the attributes structure (dsp_fsk_attr_init)
* b) initialize fields in the attributes structure (dsp_fsk_attr_set_*)
* c) create a Bell-202 handle (dsp_fsk_create)
* d) feed samples through the handler (dsp_fsk_sample)
*/
void
dsp_fsk_attr_init
(
dsp_fsk_attr_t
*
attributes
);
bithandler_func_t
dsp_fsk_attr_get_bithandler
(
dsp_fsk_attr_t
*
attributes
,
void
**
bithandler_arg
);
void
dsp_fsk_attr_set_bithandler
(
dsp_fsk_attr_t
*
attributes
,
bithandler_func_t
bithandler
,
void
*
bithandler_arg
);
bytehandler_func_t
dsp_fsk_attr_get_bytehandler
(
dsp_fsk_attr_t
*
attributes
,
void
**
bytehandler_arg
);
void
dsp_fsk_attr_set_bytehandler
(
dsp_fsk_attr_t
*
attributes
,
bytehandler_func_t
bytehandler
,
void
*
bytehandler_arg
);
int
dsp_fsk_attr_get_samplerate
(
dsp_fsk_attr_t
*
attributes
);
int
dsp_fsk_attr_set_samplerate
(
dsp_fsk_attr_t
*
attributes
,
int
samplerate
);
dsp_fsk_handle_t
*
dsp_fsk_create
(
dsp_fsk_attr_t
*
attributes
);
void
dsp_fsk_destroy
(
dsp_fsk_handle_t
**
handle
);
void
dsp_fsk_sample
(
dsp_fsk_handle_t
*
handle
,
double
normalized_sample
);
extern
fsk_modem_definition_t
fsk_modem_definitions
[];
#endif
src/mod/applications/mod_fsk/fsk_callerid.c
0 → 100644
浏览文件 @
fcc912a9
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* mod_fsk -- FSK data transfer
*
*/
#include "switch.h"
#include "fsk_callerid.h"
void
bitstream_init
(
bitstream_t
*
bsp
,
uint8_t
*
data
,
uint32_t
datalen
,
endian_t
endian
,
uint8_t
ss
)
{
memset
(
bsp
,
0
,
sizeof
(
*
bsp
));
bsp
->
data
=
data
;
bsp
->
datalen
=
datalen
;
bsp
->
endian
=
endian
;
bsp
->
ss
=
ss
;
if
(
endian
<
0
)
{
bsp
->
top
=
bsp
->
bit_index
=
7
;
bsp
->
bot
=
0
;
}
else
{
bsp
->
top
=
bsp
->
bit_index
=
0
;
bsp
->
bot
=
7
;
}
}
int8_t
bitstream_get_bit
(
bitstream_t
*
bsp
)
{
int8_t
bit
=
-
1
;
if
(
bsp
->
byte_index
>=
bsp
->
datalen
)
{
goto
done
;
}
if
(
bsp
->
ss
)
{
if
(
!
bsp
->
ssv
)
{
bsp
->
ssv
=
1
;
return
0
;
}
else
if
(
bsp
->
ssv
==
2
)
{
bsp
->
byte_index
++
;
bsp
->
ssv
=
0
;
return
1
;
}
}
bit
=
(
bsp
->
data
[
bsp
->
byte_index
]
>>
(
bsp
->
bit_index
))
&
1
;
if
(
bsp
->
bit_index
==
bsp
->
bot
)
{
bsp
->
bit_index
=
bsp
->
top
;
if
(
bsp
->
ss
)
{
bsp
->
ssv
=
2
;
goto
done
;
}
if
(
++
bsp
->
byte_index
>
bsp
->
datalen
)
{
bit
=
-
1
;
goto
done
;
}
}
else
{
bsp
->
bit_index
=
bsp
->
bit_index
+
bsp
->
endian
;
}
done:
return
bit
;
}
static
void
fsk_byte_handler
(
void
*
x
,
int
data
)
{
fsk_data_state_t
*
state
=
(
fsk_data_state_t
*
)
x
;
uint8_t
byte
=
(
uint8_t
)
data
;
top:
if
(
state
->
init
==
3
)
{
return
;
}
if
(
state
->
dlen
)
{
goto
add_byte
;
}
if
(
state
->
bpos
==
1
)
{
state
->
blen
=
byte
;
if
((
uint32_t
)(
state
->
dlen
=
state
->
bpos
+
byte
+
2
)
>
state
->
bufsize
)
{
state
->
dlen
=
state
->
bufsize
;
}
goto
top
;
}
add_byte:
if
(
state
->
bpos
<=
state
->
dlen
)
{
state
->
buf
[
state
->
bpos
++
]
=
byte
;
}
else
{
state
->
init
=
3
;
}
}
switch_status_t
fsk_data_init
(
fsk_data_state_t
*
state
,
uint8_t
*
data
,
uint32_t
datalen
)
{
memset
(
state
,
0
,
sizeof
(
*
state
));
state
->
buf
=
data
;
state
->
bufsize
=
datalen
;
state
->
bpos
=
2
;
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
fsk_data_add_sdmf
(
fsk_data_state_t
*
state
,
const
char
*
date
,
char
*
number
)
{
size_t
dlen
=
strlen
(
date
);
size_t
nlen
=
strlen
(
number
);
state
->
buf
[
0
]
=
CID_TYPE_SDMF
;
memcpy
(
&
state
->
buf
[
state
->
bpos
],
date
,
dlen
);
state
->
bpos
+=
dlen
;
memcpy
(
&
state
->
buf
[
state
->
bpos
],
number
,
nlen
);
state
->
bpos
+=
nlen
;
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
fsk_data_add_mdmf
(
fsk_data_state_t
*
state
,
mdmf_type_t
type
,
const
uint8_t
*
data
,
uint32_t
datalen
)
{
state
->
buf
[
0
]
=
CID_TYPE_MDMF
;
state
->
buf
[
state
->
bpos
++
]
=
type
;
state
->
buf
[
state
->
bpos
++
]
=
(
uint8_t
)
datalen
;
memcpy
(
&
state
->
buf
[
state
->
bpos
],
data
,
datalen
);
state
->
bpos
+=
datalen
;
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
fsk_data_add_checksum
(
fsk_data_state_t
*
state
)
{
uint32_t
i
;
uint8_t
check
=
0
;
state
->
buf
[
1
]
=
(
uint8_t
)(
state
->
bpos
-
2
);
for
(
i
=
0
;
i
<
state
->
bpos
;
i
++
)
{
check
=
check
+
state
->
buf
[
i
];
}
state
->
checksum
=
state
->
buf
[
state
->
bpos
]
=
(
uint8_t
)(
256
-
check
);
state
->
bpos
++
;
state
->
dlen
=
state
->
bpos
;
state
->
blen
=
state
->
buf
[
1
];
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
fsk_data_parse
(
fsk_data_state_t
*
state
,
size_t
*
type
,
char
**
data
,
size_t
*
len
)
{
size_t
i
;
int
sum
=
0
;
top:
if
(
state
->
checksum
!=
0
||
state
->
ppos
>=
state
->
dlen
-
1
)
{
return
SWITCH_STATUS_FALSE
;
}
if
(
!
state
->
ppos
)
{
for
(
i
=
0
;
i
<
state
->
bpos
;
i
++
)
{
sum
+=
state
->
buf
[
i
];
}
state
->
checksum
=
sum
%
256
;
state
->
ppos
=
2
;
if
(
state
->
buf
[
0
]
!=
CID_TYPE_MDMF
&&
state
->
buf
[
0
]
!=
CID_TYPE_SDMF
)
{
state
->
checksum
=
-
1
;
}
goto
top
;
}
if
(
state
->
buf
[
0
]
==
CID_TYPE_SDMF
)
{
/* convert sdmf to mdmf so we don't need 2 parsers */
if
(
state
->
ppos
==
2
)
{
*
type
=
MDMF_DATETIME
;
*
len
=
8
;
}
else
{
if
(
state
->
buf
[
state
->
ppos
]
==
'P'
||
state
->
buf
[
state
->
ppos
]
==
'O'
)
{
*
type
=
MDMF_NO_NUM
;
*
len
=
1
;
}
else
{
*
type
=
MDMF_PHONE_NUM
;
*
len
=
state
->
blen
-
8
;
}
}
*
data
=
(
char
*
)
&
state
->
buf
[
state
->
ppos
];
state
->
ppos
+=
*
len
;
return
SWITCH_STATUS_SUCCESS
;
}
else
if
(
state
->
buf
[
0
]
==
CID_TYPE_MDMF
)
{
*
type
=
state
->
buf
[
state
->
ppos
++
];
*
len
=
state
->
buf
[
state
->
ppos
++
];
*
data
=
(
char
*
)
&
state
->
buf
[
state
->
ppos
];
state
->
ppos
+=
*
len
;
return
SWITCH_STATUS_SUCCESS
;
}
return
SWITCH_STATUS_FALSE
;
}
switch_status_t
fsk_demod_feed
(
fsk_data_state_t
*
state
,
int16_t
*
data
,
size_t
samples
)
{
uint32_t
x
;
int16_t
*
sp
=
data
;
if
(
state
->
init
==
3
)
{
return
SWITCH_STATUS_FALSE
;
}
for
(
x
=
0
;
x
<
samples
;
x
++
)
{
dsp_fsk_sample
(
state
->
fsk1200_handle
,
(
double
)
*
sp
++
/
32767
.
0
);
if
(
state
->
dlen
&&
state
->
bpos
>=
state
->
dlen
)
{
state
->
init
=
3
;
return
SWITCH_STATUS_FALSE
;
}
}
return
SWITCH_STATUS_SUCCESS
;
}
switch_status_t
fsk_demod_destroy
(
fsk_data_state_t
*
state
)
{
dsp_fsk_destroy
(
&
state
->
fsk1200_handle
);
memset
(
state
,
0
,
sizeof
(
*
state
));
return
SWITCH_STATUS_SUCCESS
;
}
int
fsk_demod_init
(
fsk_data_state_t
*
state
,
int
rate
,
uint8_t
*
buf
,
size_t
bufsize
)
{
dsp_fsk_attr_t
fsk1200_attr
;
if
(
state
->
fsk1200_handle
)
{
dsp_fsk_destroy
(
&
state
->
fsk1200_handle
);
}
memset
(
state
,
0
,
sizeof
(
*
state
));
memset
(
buf
,
0
,
bufsize
);
state
->
buf
=
buf
;
state
->
bufsize
=
bufsize
;
dsp_fsk_attr_init
(
&
fsk1200_attr
);
dsp_fsk_attr_set_samplerate
(
&
fsk1200_attr
,
rate
);
dsp_fsk_attr_set_bytehandler
(
&
fsk1200_attr
,
fsk_byte_handler
,
state
);
state
->
fsk1200_handle
=
dsp_fsk_create
(
&
fsk1200_attr
);
if
(
state
->
fsk1200_handle
==
NULL
)
{
return
SWITCH_STATUS_FALSE
;
}
return
SWITCH_STATUS_SUCCESS
;
}
size_t
fsk_modulator_generate_bit
(
fsk_modulator_t
*
fsk_trans
,
int8_t
bit
,
int16_t
*
buf
,
size_t
buflen
)
{
size_t
i
;
for
(
i
=
0
;
i
<
buflen
;
i
++
)
{
fsk_trans
->
bit_accum
+=
fsk_trans
->
bit_factor
;
if
(
fsk_trans
->
bit_accum
>=
FSK_MOD_FACTOR
)
{
fsk_trans
->
bit_accum
-=
(
FSK_MOD_FACTOR
+
fsk_trans
->
bit_factor
);
break
;
}
buf
[
i
]
=
teletone_dds_state_modulate_sample
(
&
fsk_trans
->
dds
,
bit
);
}
return
i
;
}
int32_t
fsk_modulator_generate_carrier_bits
(
fsk_modulator_t
*
fsk_trans
,
uint32_t
bits
)
{
uint32_t
i
=
0
;
size_t
r
=
0
;
int8_t
bit
=
1
;
for
(
i
=
0
;
i
<
bits
;
i
++
)
{
if
((
r
=
fsk_modulator_generate_bit
(
fsk_trans
,
bit
,
fsk_trans
->
sample_buffer
,
sizeof
(
fsk_trans
->
sample_buffer
)
/
2
)))
{
if
(
fsk_trans
->
write_sample_callback
(
fsk_trans
->
sample_buffer
,
r
,
fsk_trans
->
user_data
)
!=
SWITCH_STATUS_SUCCESS
)
{
break
;
}
}
else
{
break
;
}
}
return
i
;
}
void
fsk_modulator_generate_chan_sieze
(
fsk_modulator_t
*
fsk_trans
)
{
uint32_t
i
=
0
;
size_t
r
=
0
;
int8_t
bit
=
0
;
for
(
i
=
0
;
i
<
fsk_trans
->
chan_sieze_bits
;
i
++
)
{
if
((
r
=
fsk_modulator_generate_bit
(
fsk_trans
,
bit
,
fsk_trans
->
sample_buffer
,
sizeof
(
fsk_trans
->
sample_buffer
)
/
2
)))
{
if
(
fsk_trans
->
write_sample_callback
(
fsk_trans
->
sample_buffer
,
r
,
fsk_trans
->
user_data
)
!=
SWITCH_STATUS_SUCCESS
)
{
break
;
}
}
else
{
break
;
}
bit
=
!
bit
;
}
}
void
fsk_modulator_send_data
(
fsk_modulator_t
*
fsk_trans
)
{
size_t
r
=
0
;
int8_t
bit
=
0
;
while
((
bit
=
bitstream_get_bit
(
&
fsk_trans
->
bs
))
>
-
1
)
{
if
((
r
=
fsk_modulator_generate_bit
(
fsk_trans
,
bit
,
fsk_trans
->
sample_buffer
,
sizeof
(
fsk_trans
->
sample_buffer
)
/
2
)))
{
if
(
fsk_trans
->
write_sample_callback
(
fsk_trans
->
sample_buffer
,
r
,
fsk_trans
->
user_data
)
!=
SWITCH_STATUS_SUCCESS
)
{
break
;
}
}
else
{
break
;
}
}
}
switch_status_t
fsk_modulator_init
(
fsk_modulator_t
*
fsk_trans
,
fsk_modem_types_t
modem_type
,
uint32_t
sample_rate
,
fsk_data_state_t
*
fsk_data
,
float
db_level
,
uint32_t
carrier_bits_start
,
uint32_t
carrier_bits_stop
,
uint32_t
chan_sieze_bits
,
fsk_write_sample_t
write_sample_callback
,
void
*
user_data
)
{
memset
(
fsk_trans
,
0
,
sizeof
(
*
fsk_trans
));
fsk_trans
->
modem_type
=
modem_type
;
teletone_dds_state_set_tone
(
&
fsk_trans
->
dds
,
fsk_modem_definitions
[
fsk_trans
->
modem_type
].
freq_space
,
sample_rate
,
0
);
teletone_dds_state_set_tone
(
&
fsk_trans
->
dds
,
fsk_modem_definitions
[
fsk_trans
->
modem_type
].
freq_mark
,
sample_rate
,
1
);
fsk_trans
->
bit_factor
=
(
uint32_t
)((
fsk_modem_definitions
[
fsk_trans
->
modem_type
].
baud_rate
*
FSK_MOD_FACTOR
)
/
(
float
)
sample_rate
);
fsk_trans
->
samples_per_bit
=
(
uint32_t
)
(
sample_rate
/
fsk_modem_definitions
[
fsk_trans
->
modem_type
].
baud_rate
);
fsk_trans
->
est_bytes
=
(
int32_t
)(((
fsk_data
->
dlen
*
10
)
+
carrier_bits_start
+
carrier_bits_stop
+
chan_sieze_bits
)
*
((
fsk_trans
->
samples_per_bit
+
1
)
*
2
));
fsk_trans
->
bit_accum
=
0
;
fsk_trans
->
fsk_data
=
fsk_data
;
teletone_dds_state_set_tx_level
(
&
fsk_trans
->
dds
,
db_level
);
bitstream_init
(
&
fsk_trans
->
bs
,
fsk_trans
->
fsk_data
->
buf
,
(
uint32_t
)
fsk_trans
->
fsk_data
->
dlen
,
ENDIAN_BIG
,
1
);
fsk_trans
->
carrier_bits_start
=
carrier_bits_start
;
fsk_trans
->
carrier_bits_stop
=
carrier_bits_stop
;
fsk_trans
->
chan_sieze_bits
=
chan_sieze_bits
;
fsk_trans
->
write_sample_callback
=
write_sample_callback
;
fsk_trans
->
user_data
=
user_data
;
return
SWITCH_STATUS_SUCCESS
;
}
src/mod/applications/mod_fsk/fsk_callerid.h
0 → 100644
浏览文件 @
fcc912a9
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* mod_fsk -- FSK data transfer
*
*/
#ifndef __FSK_CALLER_ID_H
#define __FSK_CALLER_ID_H
SWITCH_BEGIN_EXTERN_C
#include "fsk.h"
#include "uart.h"
#define FSK_MOD_FACTOR 0x10000
typedef
enum
{
ENDIAN_BIG
=
1
,
ENDIAN_LITTLE
=
-
1
}
endian_t
;
typedef
enum
{
CID_TYPE_SDMF
=
0x04
,
CID_TYPE_MDMF
=
0x80
}
cid_type_t
;
typedef
enum
{
MDMF_DATETIME
=
1
,
MDMF_PHONE_NUM
=
2
,
MDMF_DDN
=
3
,
MDMF_NO_NUM
=
4
,
MDMF_PHONE_NAME
=
7
,
MDMF_NO_NAME
=
8
,
MDMF_ALT_ROUTE
=
9
,
MDMF_NAME_VALUE
=
10
,
MDMF_INVALID
=
11
}
mdmf_type_t
;
struct
bitstream
{
uint8_t
*
data
;
uint32_t
datalen
;
uint32_t
byte_index
;
uint8_t
bit_index
;
int8_t
endian
;
uint8_t
top
;
uint8_t
bot
;
uint8_t
ss
;
uint8_t
ssv
;
};
struct
fsk_data_state
{
dsp_fsk_handle_t
*
fsk1200_handle
;
uint8_t
init
;
uint8_t
*
buf
;
size_t
bufsize
;
size_t
blen
;
size_t
bpos
;
size_t
dlen
;
size_t
ppos
;
int
checksum
;
};
typedef
struct
bitstream
bitstream_t
;
typedef
struct
fsk_data_state
fsk_data_state_t
;
typedef
switch_status_t
(
*
fsk_write_sample_t
)(
int16_t
*
buf
,
size_t
buflen
,
void
*
user_data
);
struct
fsk_modulator
{
teletone_dds_state_t
dds
;
bitstream_t
bs
;
uint32_t
carrier_bits_start
;
uint32_t
carrier_bits_stop
;
uint32_t
chan_sieze_bits
;
uint32_t
bit_factor
;
uint32_t
bit_accum
;
uint32_t
sample_counter
;
int32_t
samples_per_bit
;
int32_t
est_bytes
;
fsk_modem_types_t
modem_type
;
fsk_data_state_t
*
fsk_data
;
fsk_write_sample_t
write_sample_callback
;
void
*
user_data
;
int16_t
sample_buffer
[
64
];
};
typedef
int
(
*
fsk_data_decoder_t
)(
fsk_data_state_t
*
state
);
typedef
void
(
*
logger_t
)(
const
char
*
file
,
const
char
*
func
,
int
line
,
int
level
,
const
char
*
fmt
,
...);
typedef
struct
fsk_modulator
fsk_modulator_t
;
switch_status_t
fsk_data_init
(
fsk_data_state_t
*
state
,
uint8_t
*
data
,
uint32_t
datalen
);
void
bitstream_init
(
bitstream_t
*
bsp
,
uint8_t
*
data
,
uint32_t
datalen
,
endian_t
endian
,
uint8_t
ss
);
int8_t
bitstream_get_bit
(
bitstream_t
*
bsp
);
switch_status_t
fsk_data_add_mdmf
(
fsk_data_state_t
*
state
,
mdmf_type_t
type
,
const
uint8_t
*
data
,
uint32_t
datalen
);
switch_status_t
fsk_data_add_checksum
(
fsk_data_state_t
*
state
);
switch_status_t
fsk_data_parse
(
fsk_data_state_t
*
state
,
size_t
*
type
,
char
**
data
,
size_t
*
len
);
switch_status_t
fsk_demod_feed
(
fsk_data_state_t
*
state
,
int16_t
*
data
,
size_t
samples
);
switch_status_t
fsk_demod_destroy
(
fsk_data_state_t
*
state
);
int
fsk_demod_init
(
fsk_data_state_t
*
state
,
int
rate
,
uint8_t
*
buf
,
size_t
bufsize
);
size_t
fsk_modulator_generate_bit
(
fsk_modulator_t
*
fsk_trans
,
int8_t
bit
,
int16_t
*
buf
,
size_t
buflen
);
int32_t
fsk_modulator_generate_carrier_bits
(
fsk_modulator_t
*
fsk_trans
,
uint32_t
bits
);
void
fsk_modulator_generate_chan_sieze
(
fsk_modulator_t
*
fsk_trans
);
void
fsk_modulator_send_data
(
fsk_modulator_t
*
fsk_trans
);
switch_status_t
fsk_modulator_init
(
fsk_modulator_t
*
fsk_trans
,
fsk_modem_types_t
modem_type
,
uint32_t
sample_rate
,
fsk_data_state_t
*
fsk_data
,
float
db_level
,
uint32_t
carrier_bits_start
,
uint32_t
carrier_bits_stop
,
uint32_t
chan_sieze_bits
,
fsk_write_sample_t
write_sample_callback
,
void
*
user_data
);
#define fsk_modulator_send_all(_it) fsk_modulator_generate_chan_sieze(_it); \
fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_start); \
fsk_modulator_send_data(_it); \
fsk_modulator_generate_carrier_bits(_it, _it->carrier_bits_stop)
SWITCH_END_EXTERN_C
#endif
src/mod/applications/mod_fsk/mod_fsk.c
0 → 100644
浏览文件 @
fcc912a9
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2011, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthm@freeswitch.org>
*
* mod_fsk.c -- FSK data transfer
*
*/
#include <switch.h>
#include "fsk_callerid.h"
/* Prototypes */
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_fsk_shutdown
);
SWITCH_MODULE_RUNTIME_FUNCTION
(
mod_fsk_runtime
);
SWITCH_MODULE_LOAD_FUNCTION
(
mod_fsk_load
);
/* SWITCH_MODULE_DEFINITION(name, load, shutdown, runtime)
* Defines a switch_loadable_module_function_table_t and a static const char[] modname
*/
SWITCH_MODULE_DEFINITION
(
mod_fsk
,
mod_fsk_load
,
mod_fsk_shutdown
,
NULL
);
switch_status_t
my_write_sample
(
int16_t
*
buf
,
size_t
buflen
,
void
*
user_data
)
{
switch_buffer_t
*
buffer
=
(
switch_buffer_t
*
)
user_data
;
switch_buffer_write
(
buffer
,
buf
,
buflen
*
2
);
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
write_fsk_data
(
uint32_t
rate
,
int32_t
db
,
switch_buffer_t
*
buffer
,
switch_event_t
*
event
,
const
char
*
prefix
)
{
fsk_modulator_t
fsk_trans
;
fsk_data_state_t
fsk_data
=
{
0
};
uint8_t
databuf
[
1024
]
=
""
;
char
time_str
[
9
];
struct
tm
tm
;
time_t
now
;
switch_event_header_t
*
hp
;
switch_size_t
plen
=
0
;
memset
(
&
fsk_trans
,
0
,
sizeof
(
fsk_trans
));
time
(
&
now
);
localtime_r
(
&
now
,
&
tm
);
strftime
(
time_str
,
sizeof
(
time_str
),
"%m%d%H%M"
,
&
tm
);
fsk_data_init
(
&
fsk_data
,
databuf
,
sizeof
(
databuf
));
fsk_data_add_mdmf
(
&
fsk_data
,
MDMF_DATETIME
,
(
uint8_t
*
)
time_str
,
strlen
(
time_str
));
if
(
prefix
)
{
plen
=
strlen
(
prefix
);
}
if
(
event
)
{
for
(
hp
=
event
->
headers
;
hp
;
hp
=
hp
->
next
)
{
char
*
packed
;
char
*
name
=
hp
->
name
;
if
(
plen
&&
strncasecmp
(
name
,
prefix
,
plen
))
{
continue
;
}
name
+=
plen
;
if
(
zstr
(
name
))
{
continue
;
}
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"Encoding [%s][%s]
\n
"
,
hp
->
name
,
hp
->
value
);
if
(
!
strcasecmp
(
name
,
"phone_num"
))
{
fsk_data_add_mdmf
(
&
fsk_data
,
MDMF_PHONE_NUM
,
(
uint8_t
*
)
hp
->
value
,
strlen
(
hp
->
value
));
}
else
if
(
!
strcasecmp
(
name
,
"phone_name"
))
{
fsk_data_add_mdmf
(
&
fsk_data
,
MDMF_PHONE_NAME
,
(
uint8_t
*
)
hp
->
value
,
strlen
(
hp
->
value
));
}
else
{
packed
=
switch_mprintf
(
"%q:%q"
,
name
,
hp
->
value
);
fsk_data_add_mdmf
(
&
fsk_data
,
MDMF_NAME_VALUE
,
(
uint8_t
*
)
packed
,
strlen
(
packed
));
free
(
packed
);
}
}
}
fsk_data_add_checksum
(
&
fsk_data
);
fsk_modulator_init
(
&
fsk_trans
,
FSK_BELL202
,
rate
,
&
fsk_data
,
db
,
180
,
5
,
300
,
my_write_sample
,
buffer
);
fsk_modulator_send_all
((
&
fsk_trans
));
fsk_demod_destroy
(
&
fsk_data
);
return
SWITCH_STATUS_SUCCESS
;
}
SWITCH_STANDARD_APP
(
fsk_send_function
)
{
switch_event_t
*
event
=
NULL
;
switch_buffer_t
*
buffer
;
switch_slin_data_t
sdata
=
{
0
};
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
switch_frame_t
*
read_frame
;
switch_status_t
status
;
if
(
data
)
{
switch_ivr_sleep
(
session
,
1000
,
SWITCH_TRUE
,
NULL
);
switch_core_session_send_dtmf_string
(
session
,
(
const
char
*
)
data
);
switch_ivr_sleep
(
session
,
1500
,
SWITCH_TRUE
,
NULL
);
}
if
(
switch_core_session_set_codec_slin
(
session
,
&
sdata
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_ERROR
,
"FAILURE
\n
"
);
return
;
}
switch_buffer_create_dynamic
(
&
buffer
,
1024
,
2048
,
0
);
switch_channel_get_variables
(
channel
,
&
event
);
write_fsk_data
(
sdata
.
codec
.
implementation
->
actual_samples_per_second
,
-
14
,
buffer
,
event
,
"fsk_"
);
while
(
switch_channel_ready
(
channel
))
{
status
=
switch_core_session_read_frame
(
session
,
&
read_frame
,
SWITCH_IO_FLAG_NONE
,
0
);
if
(
!
SWITCH_READ_ACCEPTABLE
(
status
))
{
break
;
}
if
((
sdata
.
write_frame
.
datalen
=
switch_buffer_read
(
buffer
,
sdata
.
write_frame
.
data
,
sdata
.
codec
.
implementation
->
decoded_bytes_per_packet
))
<=
0
)
{
break
;
}
if
(
sdata
.
write_frame
.
datalen
<
sdata
.
codec
.
implementation
->
decoded_bytes_per_packet
)
{
memset
((
char
*
)
sdata
.
write_frame
.
data
+
sdata
.
write_frame
.
datalen
,
255
,
sdata
.
codec
.
implementation
->
decoded_bytes_per_packet
-
sdata
.
write_frame
.
datalen
);
sdata
.
write_frame
.
datalen
=
sdata
.
codec
.
implementation
->
decoded_bytes_per_packet
;
}
sdata
.
write_frame
.
samples
=
sdata
.
write_frame
.
datalen
/
2
;
switch_core_session_write_frame
(
sdata
.
session
,
&
sdata
.
write_frame
,
SWITCH_IO_FLAG_NONE
,
0
);
}
switch_buffer_destroy
(
&
buffer
);
switch_core_codec_destroy
(
&
sdata
.
codec
);
switch_core_session_set_read_codec
(
session
,
NULL
);
}
typedef
struct
{
switch_core_session_t
*
session
;
fsk_data_state_t
fsk_data
;
uint8_t
fbuf
[
512
];
int
skip
;
}
switch_fsk_detect_t
;
static
switch_bool_t
fsk_detect_callback
(
switch_media_bug_t
*
bug
,
void
*
user_data
,
switch_abc_type_t
type
)
{
switch_fsk_detect_t
*
pvt
=
(
switch_fsk_detect_t
*
)
user_data
;
//switch_frame_t *frame = NULL;
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
pvt
->
session
);
switch
(
type
)
{
case
SWITCH_ABC_TYPE_INIT
:
{
switch_codec_implementation_t
read_impl
=
{
0
};
switch_core_session_get_read_impl
(
pvt
->
session
,
&
read_impl
);
if
(
fsk_demod_init
(
&
pvt
->
fsk_data
,
read_impl
.
actual_samples_per_second
,
pvt
->
fbuf
,
sizeof
(
pvt
->
fbuf
)))
{
return
SWITCH_FALSE
;
}
break
;
}
case
SWITCH_ABC_TYPE_CLOSE
:
{
fsk_demod_destroy
(
&
pvt
->
fsk_data
);
}
break
;
case
SWITCH_ABC_TYPE_WRITE_REPLACE
:
case
SWITCH_ABC_TYPE_READ_REPLACE
:
{
switch_frame_t
*
rframe
;
if
(
type
==
SWITCH_ABC_TYPE_READ_REPLACE
)
{
rframe
=
switch_core_media_bug_get_read_replace_frame
(
bug
);
}
else
{
rframe
=
switch_core_media_bug_get_write_replace_frame
(
bug
);
}
if
(
!
pvt
->
skip
&&
fsk_demod_feed
(
&
pvt
->
fsk_data
,
rframe
->
data
,
rframe
->
datalen
/
2
)
!=
SWITCH_STATUS_SUCCESS
)
{
char
str
[
1024
]
=
""
;
size_t
type
,
mlen
;
char
*
sp
;
switch_event_t
*
event
;
const
char
*
app_var
;
switch_event_create_plain
(
&
event
,
SWITCH_EVENT_CHANNEL_DATA
);
while
(
fsk_data_parse
(
&
pvt
->
fsk_data
,
&
type
,
&
sp
,
&
mlen
)
==
SWITCH_STATUS_SUCCESS
)
{
char
*
varname
=
NULL
,
*
val
,
*
p
;
switch_copy_string
(
str
,
sp
,
mlen
+
1
);
*
(
str
+
mlen
)
=
'\0'
;
switch_clean_string
(
str
);
//printf("TYPE %u LEN %u VAL [%s]\n", (unsigned)type, (unsigned)mlen, str);
val
=
str
;
switch
(
type
)
{
case
MDMF_DATETIME
:
varname
=
"fsk_datetime"
;
break
;
case
MDMF_PHONE_NAME
:
varname
=
"fsk_phone_name"
;
break
;
case
MDMF_PHONE_NUM
:
varname
=
"fsk_phone_num"
;
break
;
case
MDMF_NAME_VALUE
:
varname
=
switch_core_session_sprintf
(
pvt
->
session
,
"fsk_%s"
,
val
);
if
((
p
=
strchr
(
varname
,
':'
)))
{
*
p
++
=
'\0'
;
val
=
p
;
}
break
;
default:
break
;
}
if
(
varname
&&
val
)
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
pvt
->
session
),
SWITCH_LOG_DEBUG
,
"%s setting FSK var [%s][%s]
\n
"
,
switch_channel_get_name
(
channel
),
varname
,
val
);
switch_channel_set_variable
(
channel
,
varname
,
val
);
if
(
event
)
{
switch_event_add_header_string
(
event
,
SWITCH_STACK_BOTTOM
,
varname
,
val
);
}
}
}
if
(
event
)
{
if
(
switch_core_session_queue_event
(
pvt
->
session
,
&
event
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_event_destroy
(
&
event
);
}
}
if
((
app_var
=
switch_channel_get_variable
(
channel
,
"execute_on_fsk"
)))
{
char
*
app_arg
;
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
pvt
->
session
),
SWITCH_LOG_DEBUG
,
"%s processing execute_on_fsk [%s]
\n
"
,
switch_channel_get_name
(
channel
),
app_var
);
if
((
app_arg
=
strchr
(
app_var
,
' '
)))
{
*
app_arg
++
=
'\0'
;
}
switch_core_session_execute_application
(
pvt
->
session
,
app_var
,
app_arg
);
}
pvt
->
skip
=
10
;
}
memset
(
rframe
->
data
,
255
,
rframe
->
datalen
);
if
(
type
==
SWITCH_ABC_TYPE_READ_REPLACE
)
{
switch_core_media_bug_set_read_replace_frame
(
bug
,
rframe
);
}
else
{
switch_core_media_bug_set_write_replace_frame
(
bug
,
rframe
);
}
if
(
pvt
->
skip
&&
!--
pvt
->
skip
)
{
return
SWITCH_FALSE
;
}
}
break
;
case
SWITCH_ABC_TYPE_WRITE
:
default:
break
;
}
return
SWITCH_TRUE
;
}
switch_status_t
stop_fsk_detect_session
(
switch_core_session_t
*
session
)
{
switch_media_bug_t
*
bug
;
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
if
((
bug
=
switch_channel_get_private
(
channel
,
"fsk"
)))
{
switch_channel_set_private
(
channel
,
"fsk"
,
NULL
);
switch_core_media_bug_remove
(
session
,
&
bug
);
return
SWITCH_STATUS_SUCCESS
;
}
return
SWITCH_STATUS_FALSE
;
}
switch_status_t
fsk_detect_session
(
switch_core_session_t
*
session
,
const
char
*
flags
)
{
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
switch_media_bug_t
*
bug
;
switch_status_t
status
;
switch_fsk_detect_t
*
pvt
=
{
0
};
switch_codec_implementation_t
read_impl
=
{
0
};
int
bflags
=
SMBF_READ_REPLACE
;
if
(
strchr
(
flags
,
'w'
))
{
bflags
=
SMBF_WRITE_REPLACE
;
}
switch_core_session_get_read_impl
(
session
,
&
read_impl
);
if
(
!
(
pvt
=
switch_core_session_alloc
(
session
,
sizeof
(
*
pvt
))))
{
return
SWITCH_STATUS_MEMERR
;
}
pvt
->
session
=
session
;
if
(
switch_channel_pre_answer
(
channel
)
!=
SWITCH_STATUS_SUCCESS
)
{
return
SWITCH_STATUS_FALSE
;
}
if
((
status
=
switch_core_media_bug_add
(
session
,
"fsk_detect"
,
NULL
,
fsk_detect_callback
,
pvt
,
0
,
bflags
|
SMBF_NO_PAUSE
,
&
bug
))
!=
SWITCH_STATUS_SUCCESS
)
{
return
status
;
}
switch_channel_set_private
(
channel
,
"fsk"
,
bug
);
return
SWITCH_STATUS_SUCCESS
;
}
SWITCH_STANDARD_APP
(
fsk_recv_function
)
{
fsk_detect_session
(
session
,
data
);
}
SWITCH_STANDARD_APP
(
fsk_display_function
)
{
/* expected to be called via 'execute_on_fsk' -- passes display update over FSK */
const
char
*
cid_name
,
*
cid_num
;
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
switch_core_session_message_t
*
msg
;
switch_core_session_t
*
psession
,
*
usession
=
NULL
;
char
*
flags
=
(
char
*
)
data
;
cid_name
=
switch_channel_get_variable
(
channel
,
"fsk_phone_name"
);
cid_num
=
switch_channel_get_variable
(
channel
,
"fsk_phone_num"
);
if
(
zstr
(
cid_name
))
{
cid_name
=
cid_num
;
}
if
(
zstr
(
cid_num
))
{
return
;
}
if
(
strchr
(
flags
,
'b'
))
{
if
(
switch_core_session_get_partner
(
session
,
&
psession
)
==
SWITCH_STATUS_SUCCESS
)
{
usession
=
psession
;
}
}
if
(
!
usession
)
{
usession
=
session
;
}
msg
=
switch_core_session_alloc
(
usession
,
sizeof
(
*
msg
));
MESSAGE_STAMP_FFL
(
msg
);
msg
->
message_id
=
SWITCH_MESSAGE_INDICATE_DISPLAY
;
msg
->
string_array_arg
[
0
]
=
switch_core_session_strdup
(
usession
,
cid_name
);
msg
->
string_array_arg
[
1
]
=
switch_core_session_strdup
(
usession
,
cid_num
);
msg
->
from
=
__FILE__
;
switch_core_session_queue_message
(
usession
,
msg
);
if
(
psession
)
{
switch_core_session_rwunlock
(
psession
);
psession
=
NULL
;
}
}
SWITCH_STANDARD_APP
(
fsk_simplify_function
)
{
/* expected to be called via 'execute_on_fsk' -- redirects call to point-to-point and eliminates legs in the middle */
switch_channel_t
*
channel
=
switch_core_session_get_channel
(
session
);
const
char
*
sip_uri
,
*
fsk_simplify_profile
,
*
fsk_simplify_context
;
char
*
bridgeto
;
if
(
!
(
sip_uri
=
switch_channel_get_variable
(
channel
,
"fsk_uri"
)))
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_ERROR
,
"%s Missing URI field!
\n
"
,
switch_channel_get_name
(
channel
));
}
if
(
!
(
fsk_simplify_profile
=
switch_channel_get_variable
(
channel
,
"fsk_simplify_profile"
)))
{
fsk_simplify_profile
=
"internal"
;
}
fsk_simplify_context
=
switch_channel_get_variable
(
channel
,
"fsk_simplify_context"
);
if
(
!
zstr
(
sip_uri
))
{
switch_core_session_t
*
psession
;
switch_channel_t
*
pchannel
;
bridgeto
=
switch_core_session_sprintf
(
session
,
"bridge:sofia/%s/sip:%s"
,
fsk_simplify_profile
,
sip_uri
);
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_DEBUG
,
"%s transfering to [%s]
\n
"
,
switch_channel_get_name
(
channel
),
bridgeto
);
if
(
switch_core_session_get_partner
(
session
,
&
psession
)
==
SWITCH_STATUS_SUCCESS
)
{
pchannel
=
switch_core_session_get_channel
(
psession
);
switch_channel_set_flag
(
pchannel
,
CF_REDIRECT
);
switch_channel_set_flag
(
pchannel
,
CF_TRANSFER
);
}
switch_ivr_session_transfer
(
session
,
bridgeto
,
"inline"
,
fsk_simplify_context
);
if
(
psession
)
{
switch_ivr_session_transfer
(
psession
,
"sleep:5000"
,
"inline"
,
NULL
);
switch_core_session_rwunlock
(
psession
);
}
}
}
/* Macro expands to: switch_status_t mod_fsk_load(switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
SWITCH_MODULE_LOAD_FUNCTION
(
mod_fsk_load
)
{
switch_application_interface_t
*
app_interface
;
/* connect my internal structure to the blank pointer passed to me */
*
module_interface
=
switch_loadable_module_create_module_interface
(
pool
,
modname
);
SWITCH_ADD_APP
(
app_interface
,
"fsk_send"
,
"fsk_send"
,
NULL
,
fsk_send_function
,
NULL
,
SAF_NONE
);
SWITCH_ADD_APP
(
app_interface
,
"fsk_recv"
,
"fsk_recv"
,
NULL
,
fsk_recv_function
,
NULL
,
SAF_NONE
);
SWITCH_ADD_APP
(
app_interface
,
"fsk_simplify"
,
"fsk_simplify"
,
NULL
,
fsk_simplify_function
,
NULL
,
SAF_NONE
);
SWITCH_ADD_APP
(
app_interface
,
"fsk_display"
,
"fsk_display"
,
NULL
,
fsk_display_function
,
NULL
,
SAF_NONE
);
/* indicate that the module should continue to be loaded */
return
SWITCH_STATUS_SUCCESS
;
}
/*
Called when the system shuts down
Macro expands to: switch_status_t mod_fsk_shutdown() */
SWITCH_MODULE_SHUTDOWN_FUNCTION
(
mod_fsk_shutdown
)
{
/* Cleanup dynamically allocated config settings */
return
SWITCH_STATUS_SUCCESS
;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4
*/
src/mod/applications/mod_fsk/uart.c
0 → 100644
浏览文件 @
fcc912a9
/*
* uart.c
*
* Copyright (c) 2005 Robert Krten. 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 AUTHOR ``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 AUTHOR 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.
*
* This module contains a simple 8-bit UART, which performs a callback
* with the decoded byte value.
*
* 2005 06 11 R. Krten created
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "uart.h"
/*
* dsp_uart_attr_init
*
* Initializes the attributes structure; this must be done before the
* attributes structure is used.
*/
void
dsp_uart_attr_init
(
dsp_uart_attr_t
*
attr
)
{
memset
(
attr
,
0
,
sizeof
(
*
attr
));
}
/*
* dsp_uart_attr_get_bytehandler
* dsp_uart_attr_set_bytehandler
*
* These functions get and set their respective elements from the
* attributes structure. If an error code is returned, it is just
* zero == ok, -1 == fail.
*/
bytehandler_func_t
dsp_uart_attr_get_bytehandler
(
dsp_uart_attr_t
*
attr
,
void
**
bytehandler_arg
)
{
*
bytehandler_arg
=
attr
->
bytehandler_arg
;
return
attr
->
bytehandler
;
}
void
dsp_uart_attr_set_bytehandler
(
dsp_uart_attr_t
*
attr
,
bytehandler_func_t
bytehandler
,
void
*
bytehandler_arg
)
{
attr
->
bytehandler
=
bytehandler
;
attr
->
bytehandler_arg
=
bytehandler_arg
;
}
dsp_uart_handle_t
*
dsp_uart_create
(
dsp_uart_attr_t
*
attr
)
{
dsp_uart_handle_t
*
handle
;
handle
=
malloc
(
sizeof
(
*
handle
));
if
(
handle
)
{
memset
(
handle
,
0
,
sizeof
(
*
handle
));
/* fill the attributes member */
memcpy
(
&
handle
->
attr
,
attr
,
sizeof
(
*
attr
));
}
return
handle
;
}
void
dsp_uart_destroy
(
dsp_uart_handle_t
**
handle
)
{
if
(
*
handle
)
{
free
(
*
handle
);
*
handle
=
NULL
;
}
}
void
dsp_uart_bit_handler
(
void
*
x
,
int
bit
)
{
dsp_uart_handle_t
*
handle
=
(
dsp_uart_handle_t
*
)
x
;
if
(
!
handle
->
have_start
)
{
if
(
bit
)
{
return
;
/* waiting for start bit (0) */
}
handle
->
have_start
=
1
;
handle
->
data
=
0
;
handle
->
nbits
=
0
;
return
;
}
handle
->
data
>>=
1
;
handle
->
data
|=
0x80
*
!!
bit
;
handle
->
nbits
++
;
if
(
handle
->
nbits
==
8
)
{
handle
->
attr
.
bytehandler
(
handle
->
attr
.
bytehandler_arg
,
handle
->
data
);
handle
->
nbits
=
0
;
handle
->
data
=
0
;
handle
->
have_start
=
0
;
}
/* might consider handling errors in the future... */
}
src/mod/applications/mod_fsk/uart.h
0 → 100644
浏览文件 @
fcc912a9
/*
* uart.h
*
* Copyright (c) 2005 Robert Krten. 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 AUTHOR ``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 AUTHOR 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.
*
* This module contains the manifest constants and declarations for
* the UART module.
*
* 2005 06 19 R. Krten created
*/
#ifndef __UART_H__
#define __UART_H__
typedef
void
(
*
bytehandler_func_t
)
(
void
*
,
int
);
typedef
void
(
*
bithandler_func_t
)
(
void
*
,
int
);
typedef
struct
dsp_uart_attr_s
{
bytehandler_func_t
bytehandler
;
/* byte handler */
void
*
bytehandler_arg
;
/* arbitrary ID passed to bytehandler as first argument */
}
dsp_uart_attr_t
;
typedef
struct
{
dsp_uart_attr_t
attr
;
int
have_start
;
/* wait for start bit to show up */
int
data
;
/* data buffer */
int
nbits
;
/* number of bits accumulated so far */
}
dsp_uart_handle_t
;
/*
* Function prototypes
*
* General calling order is:
* a) create the attributes structure (dsp_uart_attr_init)
* b) initialize fields in the attributes structure (dsp_uart_attr_set_*)
* c) create a Bell-202 handle (dsp_uart_create)
* d) feed bits through dsp_uart_bit_handler
*/
void
dsp_uart_attr_init
(
dsp_uart_attr_t
*
attributes
);
bytehandler_func_t
dsp_uart_attr_get_bytehandler
(
dsp_uart_attr_t
*
attributes
,
void
**
bytehandler_arg
);
void
dsp_uart_attr_set_bytehandler
(
dsp_uart_attr_t
*
attributes
,
bytehandler_func_t
bytehandler
,
void
*
bytehandler_arg
);
dsp_uart_handle_t
*
dsp_uart_create
(
dsp_uart_attr_t
*
attributes
);
void
dsp_uart_destroy
(
dsp_uart_handle_t
**
handle
);
void
dsp_uart_bit_handler
(
void
*
handle
,
int
bit
);
#endif
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论