Files
TAIXIN/sdk/app/video_app/gen420_hardware_msi.c

372 lines
9.5 KiB
C
Raw Normal View History

#include "basic_include.h"
#include "lib/multimedia/msi.h"
#include "hal/h264.h"
#include "lib/video/gen/gen420_dev.h"
#include "dev/gen/hggen420.h"
#include "stream_define.h"
#include "lib/heap/av_heap.h"
#include "lib/heap/av_psram_heap.h"
#include "gen420_hardware_msi.h"
#include "lib/video/dvp/jpeg/jpg.h"
// data申请空间函数
#define STREAM_MALLOC av_psram_malloc
#define STREAM_FREE av_psram_free
#define STREAM_ZALLOC av_psram_zalloc
// 结构体申请空间函数
#define STREAM_LIBC_MALLOC av_malloc
#define STREAM_LIBC_FREE av_free
#define STREAM_LIBC_ZALLOC av_zalloc
#define GEN420_MAX_MSG (10)
#define MAX_GEN420_HARDWARE_RX 8
enum gen420_hardware_enum
{
GEN420_HARDWARE_READY = BIT(0), //将gen420的work停止
};
struct gen420_hardware_s
{
struct msi *msi;
struct gen420_device *gen420_dev;
os_msgqueue_t msgq;
struct os_event evt;
struct os_task task;
uint8_t *gen420_sram;
uint8_t *gen420_sram2;
uint8_t *gen420_sram3;
};
os_msgqueue_t *gen420_msgq = NULL;
volatile struct list_head gen420_queue_head;
static struct os_semaphore gen420wq_sem = {0,NULL};
void gen420wq_sema_init()
{
os_sema_init(&gen420wq_sem,0);
}
void gen420wq_sema_down(int32 tmo_ms)
{
os_sema_down(&gen420wq_sem,tmo_ms);
}
void gen420wq_sema_up()
{
os_sema_up(&gen420wq_sem);
}
int register_gen420_queue(uint8_t type,uint32_t w,uint32_t h,gen420_kick_fn kick_fn,gen420_free_fn free_fn,uint32 priv){
struct gen420_msg_s *wq;
struct msi *msi = msi_find("gen420_h", 0);
struct gen420_hardware_s *gen420 = (struct gen420_hardware_s *)msi->priv;
msi_put(msi);
if(gen420->gen420_sram == NULL){
gen420->gen420_sram = (uint8_t *)STREAM_LIBC_MALLOC(8 * 1024);
gen420->gen420_sram2 = (uint8_t *)STREAM_LIBC_MALLOC(2 * 1024);
gen420->gen420_sram3 = (uint8_t *)STREAM_LIBC_MALLOC(2 * 1024);
//任意一个空间申请不到,都算失败
if(gen420->gen420_sram && gen420->gen420_sram2 && gen420->gen420_sram3){
gen420_sram_linebuf_adr(gen420->gen420_dev, (uint32)gen420->gen420_sram, (uint32)(gen420->gen420_sram2), (uint32)(gen420->gen420_sram3));
}
else
{
os_printf(KERN_ERR"[%s] malloc failed!!!\n",__func__);
if(gen420->gen420_sram)
{
STREAM_LIBC_FREE(gen420->gen420_sram);
gen420->gen420_sram = NULL;
}
if(gen420->gen420_sram2)
{
STREAM_LIBC_FREE(gen420->gen420_sram2);
gen420->gen420_sram2 = NULL;
}
if(gen420->gen420_sram3)
{
STREAM_LIBC_FREE(gen420->gen420_sram3);
gen420->gen420_sram3 = NULL;
}
return -1;
}
}
wq = malloc(sizeof(struct gen420_msg_s));
wq->type = type;
wq->kick_fn = kick_fn;
wq->free_fn = free_fn;
wq->w = w;
wq->h = h;
wq->sta = 0;
wq->devid = type;
wq->fn_data = (void *)priv;
INIT_LIST_HEAD(&wq->list);
list_add_tail(&wq->list,(struct list_head*)&gen420_queue_head);
return 0;
}
int unregister_gen420_queue(uint32_t devid){
int ret = 0;
struct list_head *dlist;
struct gen420_msg_s* gen420dev;
struct msi *msi = msi_find("gen420_h", 0);
struct gen420_hardware_s *gen420 = (struct gen420_hardware_s *)msi->priv;
msi_put(msi);
if(list_empty((struct list_head *)&gen420_queue_head) != TRUE){
dlist = (struct list_head *)&gen420_queue_head;
do{
dlist = dlist->next;
if(dlist == &gen420_queue_head){
return -1;
}else{
gen420dev = list_entry((struct list_head *)dlist,struct gen420_msg_s,list);
if(gen420dev->devid == devid){
list_del(&gen420dev->list);
free(gen420dev);
if(list_empty((struct list_head *)&gen420_queue_head) == TRUE){
if(gen420->gen420_sram)
{
STREAM_LIBC_FREE(gen420->gen420_sram);
gen420->gen420_sram = NULL;
}
if(gen420->gen420_sram2)
{
STREAM_LIBC_FREE(gen420->gen420_sram2);
gen420->gen420_sram2 = NULL;
}
if(gen420->gen420_sram3)
{
STREAM_LIBC_FREE(gen420->gen420_sram3);
gen420->gen420_sram3 = NULL;
}
}
return 1;
}
}
}while(1);
}else{
ret = -1;
}
return ret;
}
int change_gen420dev_w_h(uint8_t devid,uint16_t w,uint16_t h){
struct list_head *dlist;
struct gen420_msg_s* gen420dev;
if(list_empty((struct list_head *)&gen420_queue_head) != TRUE){
dlist = (struct list_head *)&gen420_queue_head;
do{
dlist = dlist->next;
if(dlist == &gen420_queue_head){
return -1;
}else{
gen420dev = list_entry((struct list_head *)dlist,struct gen420_msg_s,list);
if(gen420dev->devid == devid){
gen420dev->w = w;
gen420dev->h = h;
return 1;
}
}
}while(1);
}
return 0;
}
int wake_up_gen420_queue(uint8_t devid,uint8_t *data_rom){
int ret = 0;
struct list_head *dlist;
struct gen420_msg_s* gen420dev;
if(list_empty((struct list_head *)&gen420_queue_head) != TRUE){
dlist = (struct list_head *)&gen420_queue_head;
do{
dlist = dlist->next;
if(dlist == &gen420_queue_head){
return -1;
}else{
gen420dev = list_entry((struct list_head *)dlist,struct gen420_msg_s,list);
if(gen420dev->devid == devid){
if(gen420dev->sta == 1){
return 2; //this id all ready running
}
gen420dev->sta = 1;
gen420dev->data = (uint8_t *)data_rom;
gen420wq_sema_up();
return 1;
}
}
}while(1);
}else{
ret = -1;
}
return ret;
}
extern volatile uint8 done_percent;
void gen420_hardware_thread(void *d)
{
uint32_t have_h264_jpg_stream = 0;
int32_t res;
// int32_t err;
int32_t kick_res;
struct list_head *dlist;
struct msi *msi = (struct msi*)d;
struct gen420_msg_s *msg = NULL;
struct gen420_hardware_s *gen420 = (struct gen420_hardware_s *)msi->priv;
struct gen420_msg_s *msgsub[GEN420_MAX_MSG]; //0: jpg for sub stream 1: h264 for sub stream 2-255: user 目前先限定最多3个用户同时使用
// int8_t msg_cnt = 0;
uint8_t itk = 0;
uint32_t flags;
while(1)
{
rewait:
gen420wq_sema_down(-1);
for(itk = 0;itk < GEN420_MAX_MSG;itk++){
msgsub[itk] = NULL;
}
flags = disable_irq();
if(list_empty((struct list_head *)&gen420_queue_head) != TRUE){ //每次都会把链表从头查到尾
dlist =(struct list_head *) &gen420_queue_head;
do{
dlist = dlist->next;
if(dlist == &gen420_queue_head){
break;
}else{
msg = list_entry((struct list_head *)dlist,struct gen420_msg_s,list);
if(msg->type < 2){
have_h264_jpg_stream = 1;
}
if(msg->sta == 1){
//memcpy(msgsub[msg->type],msg,sizeof(struct gen420_msg_s));
msgsub[msg->type] = msg;
//msg->sta = 0;
}
}
}while(1);
}else{
enable_irq(flags);
continue;
}
enable_irq(flags);
for(itk = 0;itk < GEN420_MAX_MSG;itk++)
{
if(msgsub[itk] != NULL){
//如果类型超过2,就是自定义的,那么要看看是否有副码流,如果有副码流,需要等待副码流去编码后再执行自定义的
//如果没有辅码流需要编码,则不需要执行去等待VPP小于80%去编码(这里80%是为了给足够时间去编辅码流,如果没有辅码流,这里就没有意义了)
if(msgsub[itk]->type >= 2 && have_h264_jpg_stream)
{
while(done_percent > 80){
if(have_h264_jpg_stream)
{
//os_sleep_ms(1);
//os_sleep_ms(1);
goto rewait;
}else{
os_sleep_ms(1);
}
}
}
msg = msgsub[itk];
if(msg->kick_fn){
kick_res = msg->kick_fn(msg); //配置对应的h264/jpg的数据源为gen420
//没有kick成功,直接释放
if(kick_res == 0)
{
gen420_frame_size(gen420->gen420_dev, msg->w, msg->h);
gen420_psram_adr(gen420->gen420_dev, (uint32)msg->data, (uint32)(msg->data + msg->w * msg->h), (uint32)(msg->data + msg->w * msg->h + msg->w * msg->h / 4));
gen420_dma_run(gen420->gen420_dev);
res = os_event_wait(&gen420->evt, GEN420_HARDWARE_READY, NULL, OS_EVENT_WMODE_CLEAR, 1000);
//有异常?正常不应该1s都没有完成
if(res)
{
os_printf("%s:%d err\n",__FUNCTION__,__LINE__);
}
}
else
{
os_printf(KERN_ERR"gen420_hardware kick error:%d\n",kick_res);
}
}
msg->sta = 0;
//如果副码流已经用完,就代表其他数据流可以使用了
if(msg->type < 2)
{
have_h264_jpg_stream = 0;
}
if(msg && msg->free_fn)
{
msg->free_fn(msg);
}
}
}
have_h264_jpg_stream = 0;
}
//gen420_hardware_thread_end:
return;
}
static int32 gen420_msi_isr(uint32 irq, uint32 irq_data, uint32 param1, uint32 param2)
{
struct gen420_hardware_s *gen420 = (struct gen420_hardware_s *)irq_data;
os_event_set(&gen420->evt, GEN420_HARDWARE_READY, NULL);
return 0;
}
struct msi *gen420_hardware_msi_init()
{
uint8_t is_new = 0;
struct msi *msi = msi_new("gen420_h", 0, &is_new);
if(is_new)
{
struct gen420_hardware_s *gen420 = (struct gen420_hardware_s *)msi->priv;
gen420 = (struct gen420_hardware_s *)STREAM_LIBC_ZALLOC(sizeof(struct gen420_hardware_s));
msi->priv = (void*)gen420;
gen420->gen420_dev = (struct gen420_device *)dev_get(HG_GEN420_DEVID);
os_msgq_init(&gen420->msgq,MAX_GEN420_HARDWARE_RX);
os_event_init(&gen420->evt);
gen420_open(gen420->gen420_dev);
gen420_request_irq(gen420->gen420_dev, GEN420_DONE_ISR, gen420_msi_isr, (uint32)gen420);
gen420_dst_h264_and_jpg(gen420->gen420_dev, 0);
INIT_LIST_HEAD((struct list_head *)&gen420_queue_head);
gen420wq_sema_init();
msi->enable = 1;
//创建线程
gen420_msgq = &gen420->msgq;
OS_TASK_INIT("gen420_s", &gen420->task, gen420_hardware_thread, (void*)msi, OS_TASK_PRIORITY_ABOVE_NORMAL+0xf, NULL, 768);
}
return msi;
}