428 lines
12 KiB
C
428 lines
12 KiB
C
#include "app_config.h"
|
||
#if (defined CONFIG_UI_ENABLE) && (defined RAW_STREAM_ENABLE)
|
||
#include "wifi_raw_stream.h"
|
||
#include "system/includes.h"
|
||
#include "wifi/wifi_connect.h"
|
||
#include "event/net_event.h"
|
||
#include "net/assign_macaddr.h"
|
||
|
||
static u32 total_payload_len = 0;
|
||
static u32 jpeg_total_payload_len = 0;
|
||
static u8 pcm_finish = 0;
|
||
static u8 jpeg_finish = 0;
|
||
static u32 old_frame_seq = 0;//记录音频数据包号
|
||
static u32 jpeg_old_frame_seq = 0;//记录视频数据包号
|
||
#define PCM_BUF_SIZE 9000 //接收音频包
|
||
#define JPG_MAX_SIZE 100*1024
|
||
static u8 recBuf[JPG_MAX_SIZE] = {0};
|
||
#define MAX_PAYLOAD (500-sizeof(struct frm_head))//最后4字节属于h264流的
|
||
static u32 seq = 1;
|
||
|
||
static OS_MUTEX mutex1;
|
||
static OS_MUTEX mutex2;
|
||
static OS_MUTEX mutex3;
|
||
#define WIFI_TX_MAX_LEN 2510 //一次最大发送字节数
|
||
|
||
static int send_cnt = 0;
|
||
static int fps_cnt = 0;
|
||
static int wifi_raw_send(u8 *buf, int len);
|
||
static int startJpeg = 0;
|
||
static int checkPing = 0;
|
||
static int pingTime = 0;
|
||
|
||
#define LOSE_PING_TIME_CHECK 60 * 1000 //10s
|
||
#define SEND_PING_TIME 2 * 1000 //10s
|
||
void jpgImageDataRec(char *buf, int len);
|
||
extern int jpeg2yuv_jpeg_frame_write(u8 *buf, u32 len);
|
||
|
||
#define PCM_DATA_TYPE 1
|
||
#define JPEG_DATA_TYPE 2
|
||
|
||
int isc_log_en()//如果定义该函数丢帧信息屏蔽 //带宽不足打印
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
static void send_status(void *p)
|
||
{
|
||
printf("-->U = %d KB/S \r\n", send_cnt * 27);
|
||
send_cnt = 0;
|
||
}
|
||
|
||
#ifdef RAW_STREAM_RECEIVER
|
||
static void fps_status(void *p)
|
||
{
|
||
printf("-->FPS = %d fps \r\n", fps_cnt);
|
||
fps_cnt = 0;
|
||
}
|
||
#endif
|
||
|
||
static void lose_online_ping(void)
|
||
{
|
||
printf("-->lose online ping");
|
||
startJpeg = 0;
|
||
seq = 0;
|
||
}
|
||
|
||
static void send_online_ping(void)
|
||
{
|
||
struct frm_head ping_head = {0};
|
||
ping_head.type |= ONLINE_PING_TYPE;
|
||
wifi_raw_send((u8 *)&ping_head, sizeof(struct frm_head));
|
||
}
|
||
|
||
static void send_reset_rsp(void)
|
||
{
|
||
printf("-->send RESET RSP");
|
||
struct frm_head ping_head = {0};
|
||
ping_head.type |= RESET_RSP_TYPE;
|
||
wifi_raw_send((u8 *)&ping_head, sizeof(struct frm_head));
|
||
}
|
||
|
||
//发送复位请求
|
||
static void send_reset_req(void)
|
||
{
|
||
printf("-->send RESET REQ");
|
||
struct frm_head pong_head = {0};
|
||
pong_head.type |= RESET_REQ_TYPE;
|
||
wifi_raw_send((u8 *)&pong_head, sizeof(struct frm_head));
|
||
}
|
||
|
||
//接收音频视频数据
|
||
static int get_jpeg_packet(char *buf, int len, char *pcm_buf, int *pcm_buf_len, struct __JPG_INFO *info)
|
||
{
|
||
u32 position = 0;
|
||
u32 jpg_position = 0;
|
||
u32 frame_head_size = sizeof(struct frm_head);
|
||
u8 frame_type;
|
||
u32 cur_frame_seq;
|
||
u32 frame_offset;
|
||
u32 slice_data_len;
|
||
u32 frame_size;
|
||
|
||
static u8 ps = 0;
|
||
|
||
if (len < frame_head_size) {
|
||
printf("\n%s %d->data err\n", __func__, __LINE__);
|
||
goto ERROR;
|
||
}
|
||
|
||
do {
|
||
struct frm_head *head_info = (struct frm_head *)(buf + position);
|
||
frame_type = head_info->type & 0x7F; //数据类型 是音频 还是 视频
|
||
cur_frame_seq = head_info->seq;//帧序号
|
||
frame_offset = head_info->offset;//当前帧偏移
|
||
slice_data_len = head_info->payload_size;//当前数据长度
|
||
frame_size = head_info->frm_sz;//帧头长度
|
||
len -= (frame_head_size + slice_data_len);//如果帧头长+数据长度!=包长度
|
||
|
||
if (len < 0) {
|
||
printf("\n%s %d->data err\n", __func__, __LINE__); //认为是错误的数据包
|
||
goto ERROR;
|
||
}
|
||
|
||
switch (frame_type) {
|
||
case PCM_AUDIO_TYPE:
|
||
if (cur_frame_seq < old_frame_seq) { //如果当前的seq小于旧的seq,说明是旧的数据包,跳过不处理
|
||
printf("\n%s %d->recv old seq\n", __func__, __LINE__);
|
||
goto continue_deal;
|
||
|
||
} else if (cur_frame_seq > old_frame_seq) { //如果当前seq大于旧的seq,认为是新的数据包,接收包初始化
|
||
if (total_payload_len && (pcm_finish == 0)) {
|
||
printf("\n%s %d->recv old seq\n", __func__, __LINE__);
|
||
}
|
||
|
||
old_frame_seq = cur_frame_seq;
|
||
total_payload_len = 0;
|
||
pcm_finish = 0;
|
||
memset(pcm_buf, CHECK_CODE, PCM_BUF_SIZE);
|
||
}
|
||
|
||
if (bytecmp((unsigned char *)pcm_buf + frame_offset, CHECK_CODE, CHECK_CODE_NUM) != 0) {
|
||
printf("\n%s %d->repeat seq\n", __func__, __LINE__);
|
||
goto continue_deal;
|
||
|
||
}
|
||
|
||
if (frame_offset + slice_data_len > PCM_BUF_SIZE) {
|
||
printf("\n%s %d->large data pcm buf too small\n", __func__, __LINE__);
|
||
goto ERROR;
|
||
}
|
||
|
||
memcpy(pcm_buf + frame_offset, (buf + position) + frame_head_size, slice_data_len);//对应数据放置到对应的位置
|
||
total_payload_len += slice_data_len;//累加总长度
|
||
|
||
if (total_payload_len == frame_size) { //如果数据量相等,说明帧数据接收完成
|
||
*pcm_buf_len = total_payload_len;
|
||
pcm_finish = 1;
|
||
/*printf("\n%s %d->finish\n", __func__, __LINE__);*/
|
||
return PCM_DATA_TYPE;
|
||
}
|
||
goto continue_deal;
|
||
|
||
case JPEG_VIDEO_TYPE:
|
||
if (frame_offset + slice_data_len > JPG_MAX_SIZE) {
|
||
printf("\n%s %d->large data pcm buf too small\n", __func__, __LINE__);
|
||
goto ERROR;
|
||
}
|
||
|
||
if (cur_frame_seq < jpeg_old_frame_seq) { //如果当前的seq小于旧的seq,说明是旧的数据包,跳过不处理
|
||
printf("\n%s %d->jpeg_recv old seq\n", __func__, __LINE__);
|
||
goto continue_deal;
|
||
|
||
} else if (cur_frame_seq > jpeg_old_frame_seq) { //如果当前seq大于旧的seq,认为是新的数据包,接收包初始化
|
||
|
||
if (jpeg_total_payload_len && (jpeg_finish == 0)) {
|
||
printf("\n [MSG] lose packet or disorder packet\n");
|
||
}
|
||
|
||
jpeg_old_frame_seq = cur_frame_seq;
|
||
jpeg_total_payload_len = 0;
|
||
jpeg_finish = 0;
|
||
memset(info->buf, CHECK_CODE, JPG_MAX_SIZE);
|
||
}
|
||
|
||
if (bytecmp((unsigned char *)info->buf + frame_offset, CHECK_CODE, CHECK_CODE_NUM) != 0) {
|
||
/* printf("\n%s %d->jpeg_repeat seq\n", __func__, __LINE__); */
|
||
goto continue_deal;
|
||
|
||
}
|
||
|
||
memcpy(info->buf + frame_offset, (buf + position) + frame_head_size, slice_data_len);//对应数据放置到对应的位置
|
||
jpeg_total_payload_len += slice_data_len;//累加总长度
|
||
|
||
if (jpeg_total_payload_len == frame_size) { //如果数据量相等,说明帧数据接收完成
|
||
info->buf_len = jpeg_total_payload_len;
|
||
jpeg_finish = 1;
|
||
|
||
return JPEG_DATA_TYPE;
|
||
}
|
||
|
||
continue_deal:
|
||
position += (frame_head_size + slice_data_len);
|
||
break;
|
||
|
||
case ONLINE_PING_TYPE:
|
||
printf("-->receive ONLINE PING\r\n");
|
||
if (checkPing) {
|
||
sys_timer_modify(checkPing, LOSE_PING_TIME_CHECK);
|
||
}
|
||
break;
|
||
|
||
case RESET_REQ_TYPE:
|
||
printf("-->receive RESET REQ \r\n");
|
||
old_frame_seq = 0;
|
||
jpeg_old_frame_seq = 0;
|
||
send_reset_rsp();
|
||
if (!pingTime) {
|
||
pingTime = sys_timer_add(NULL, send_online_ping, SEND_PING_TIME);
|
||
} else {
|
||
sys_timer_modify(pingTime, SEND_PING_TIME);
|
||
}
|
||
|
||
break;
|
||
|
||
case RESET_RSP_TYPE:
|
||
printf("-->receive RESET RSP \r\n");
|
||
startJpeg = 1;
|
||
|
||
if (!checkPing) {
|
||
checkPing = sys_timer_add(NULL, lose_online_ping, LOSE_PING_TIME_CHECK);
|
||
} else {
|
||
sys_timer_modify(checkPing, LOSE_PING_TIME_CHECK);
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
printf("\n%s %d---type >> %d\n", __func__, __LINE__, frame_type);
|
||
break;
|
||
}
|
||
} while (len > 0);
|
||
|
||
return 0;
|
||
ERROR:
|
||
|
||
return -1;
|
||
|
||
}
|
||
|
||
#ifdef RAW_STREAM_SENDER
|
||
int net_rt_send_frame(struct raw_stream_info *info, char *buffer, size_t len, u8 type)
|
||
{
|
||
u16 payload_len = 0;
|
||
u32 total_udp_send = 0;
|
||
struct frm_head frame_head = {0};
|
||
|
||
u32 remain_len = len;
|
||
|
||
if (info == NULL || info->udp_send_buf == NULL) {
|
||
printf("use net_rt_stream_open_pkg\n");
|
||
return -1;
|
||
}
|
||
|
||
os_mutex_pend(&mutex2, 0);
|
||
|
||
frame_head.offset = 0;
|
||
frame_head.frm_sz = len;
|
||
frame_head.type &= ~LAST_FREG_MAKER;
|
||
frame_head.type |= type;
|
||
|
||
frame_head.seq = seq++;
|
||
while (remain_len) {
|
||
|
||
if (remain_len < MAX_PAYLOAD) {
|
||
payload_len = remain_len;
|
||
frame_head.type |= LAST_FREG_MAKER;
|
||
} else {
|
||
payload_len = MAX_PAYLOAD;
|
||
}
|
||
|
||
frame_head.payload_size = payload_len;
|
||
total_udp_send = 0;
|
||
memcpy(info->udp_send_buf + total_udp_send, &frame_head, sizeof(struct frm_head));
|
||
total_udp_send += sizeof(struct frm_head);
|
||
|
||
memcpy(info->udp_send_buf + total_udp_send, buffer + frame_head.offset, payload_len);
|
||
|
||
total_udp_send += payload_len;
|
||
|
||
if (total_udp_send <= UDP_SEND_SIZE_MAX) {
|
||
wifi_raw_send(info->udp_send_buf, total_udp_send);
|
||
} else {
|
||
printf("total_udp_send over limit !!! \n");
|
||
break;
|
||
}
|
||
|
||
remain_len -= payload_len;
|
||
frame_head.offset += payload_len;
|
||
}
|
||
|
||
os_mutex_post(&mutex2);
|
||
|
||
return len;
|
||
}
|
||
#endif
|
||
|
||
static const u8 pkg_head_fill_magic[] = {
|
||
/*dst*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,/*src*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,/*BSSID*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
|
||
};
|
||
|
||
static void wifi_rx_cb(void *rxwi, struct ieee80211_frame *wh, void *data, u32 len, struct netif *netif)
|
||
{
|
||
#if 0
|
||
static const u8 pkg_head_fill_magic[] = {
|
||
/*dst*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,/*src*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,/*BSSID*/ 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, /*Seq,Frag num*/0x88, 0x88,
|
||
};
|
||
#endif
|
||
|
||
|
||
if (len < 25 || memcmp(&((u8 *)data)[28], pkg_head_fill_magic, sizeof(pkg_head_fill_magic))) {
|
||
return;
|
||
}
|
||
|
||
u8 *payload = &((u8 *)data)[48];
|
||
u32 payload_len = len - 24;
|
||
|
||
jpgImageDataRec(payload, payload_len);
|
||
}
|
||
|
||
void set_pake_mac_addr(u8 *pkg_head_fill_magic)
|
||
{
|
||
u8 *addr = wifi_get_wifi_send_pkg_ptr();
|
||
u8 *aim_addr = addr + 24;
|
||
memcpy(aim_addr, pkg_head_fill_magic, 20);
|
||
}
|
||
|
||
static int wifi_raw_send(u8 *buf, int len)
|
||
{
|
||
os_mutex_pend(&mutex1, 0);
|
||
if (len > WIFI_TX_MAX_LEN) {
|
||
return -1;
|
||
}
|
||
|
||
u8 *pos = wifi_get_payload_ptr();
|
||
|
||
memcpy(pos, buf, len);
|
||
|
||
wifi_send_data(len, WIFI_TXRATE_54M);
|
||
|
||
os_mutex_post(&mutex1);
|
||
return len;
|
||
}
|
||
|
||
void video_init_task(void *p)
|
||
{
|
||
int user_video_rec0_open(void);
|
||
int user_video_rec0_close(void);
|
||
u32 user_video_frame_callback(void *data, u32 len, u8 type);
|
||
|
||
os_time_dly(10);//延时10个os_tick,等待摄像头电源稳定
|
||
user_video_rec0_open();//打开摄像头
|
||
}
|
||
|
||
int wifi_raw_init(void)
|
||
{
|
||
printf(">>>>>>>wifi_raw_init<<<<<<<<<<");
|
||
set_pake_mac_addr(pkg_head_fill_magic);
|
||
wifi_raw_on(0);
|
||
wifi_set_rts_threshold(0xffff);//配置即使长包也不发送RTS
|
||
wifi_set_channel(14);//配置WIFI RF 通信信道
|
||
wifi_set_long_retry(10);
|
||
wifi_set_short_retry(30);
|
||
wifi_set_frame_cb(wifi_rx_cb, NULL); //注册接收802.11数据帧回调
|
||
os_mutex_create(&mutex1);
|
||
os_mutex_create(&mutex2);
|
||
os_mutex_create(&mutex3);
|
||
|
||
#ifdef RAW_STREAM_RECEIVER
|
||
sys_timer_add(NULL, fps_status, 1 * 1000);
|
||
pingTime = sys_timer_add(NULL, send_online_ping, SEND_PING_TIME);
|
||
void raw_stream_to_lcd(void);
|
||
raw_stream_to_lcd();
|
||
#endif
|
||
|
||
#ifdef RAW_STREAM_SENDER
|
||
thread_fork("video_init_task", 12, 1000, 0, NULL, video_init_task, NULL);
|
||
#endif
|
||
}
|
||
|
||
#ifdef RAW_STREAM_SENDER
|
||
static u8 sendBuf[4 * 1024];
|
||
void jpgImageDataSend(char *buffer, size_t len)
|
||
{
|
||
if (startJpeg) {
|
||
struct raw_stream_info stream_info;
|
||
stream_info.udp_send_buf = sendBuf;
|
||
net_rt_send_frame(&stream_info, buffer, len, JPEG_VIDEO_TYPE);
|
||
} else {
|
||
send_reset_req();
|
||
}
|
||
}
|
||
#endif
|
||
|
||
static struct __JPG_INFO jpg_info = {
|
||
.buf_len = sizeof(recBuf),
|
||
.buf = recBuf,
|
||
};
|
||
|
||
|
||
void jpgImageDataRec(char *buf, int len)
|
||
{
|
||
int ret;
|
||
os_mutex_pend(&mutex3, 0);
|
||
ret = get_jpeg_packet(buf, len, NULL, NULL, &jpg_info);
|
||
if (JPEG_DATA_TYPE == ret) {
|
||
#ifdef RAW_STREAM_RECEIVER
|
||
jpeg2yuv_jpeg_frame_write(jpg_info.buf, jpg_info.buf_len);
|
||
fps_cnt++;
|
||
#endif
|
||
} else if (PCM_DATA_TYPE == ret) {
|
||
|
||
}
|
||
os_mutex_post(&mutex3);
|
||
}
|
||
#endif
|
||
|
||
|