Files
AC707N/SDK/apps/watch/video/camera/camera_manager.c
T

621 lines
16 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "system/includes.h"
#include "app_config.h"
#include "software_jpegenc.h"
#include "spi.h"
#include "generic/lbuf.h"
#include "camera_queue_buf.h"
#include "camera_manager.h"
#include "bf30a2_cfg.h"
#include "avilib.h"
#include "asm/dma_copy.h"
#define LOG_TAG_CONST CAMERA_MANAGER
#define LOG_TAG "[CAMERA_MANAGER]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CHAR_ENABLE //log_char enable
#define LOG_CLI_ENABLE
#include "debug.h"
#define offsetof(type, memb) \
((unsigned long)(&((type *)0)->memb))
// SPI
#define SPI_FEND_SIZE 4 // 包头
#define SPI_LEND_SIZE 4 // 包尾
#define SPI_FHEAD_SIZE 4 // 行头
#define SPI_LHEAD_SIZE 4 // 行尾
#define SPI_ID HW_SPI1 // SPI ID号,spi2可能用于nandflash
#define QBUF_EXT_SIZE 4//qbuf拓展数据
// 接收队列BUF总大小 DMA_REVC_SIZE * DMA_REVC_BUF_NUM
#define INPUT_WIDTH 240
#define OUTPUT_HEIGHT 320
#define DMA_LINE_SIZE ( INPUT_WIDTH* 2 + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE) // 摄像头一行大小 格式:YUVY
#define DMA_CAMERA_SIZE (16) // 一次SPI DMA接收的行数
#define DMA_REVC_SIZE (DMA_LINE_SIZE * DMA_CAMERA_SIZE + SPI_FEND_SIZE) // 一次SPI DMA接收的大小,帧头、帧尾会多四个字节
#define DMA_REVC_BUF_NUM (20) // 接收BUF的数量
// JPEG缓存
#define JPEG_LBUF_SIZE (100 * 1024) // LBUF总大小,编码出的jpeg存放在lbuf中
#define ONE_JPEG_MAX_SIZE (10 * 1024) // 单张JPEG的大小,申请LBUF缓存时用到,可根据情况调整
#define JPEG_QVAL 50 // jpeg编码默认Q值(0-100)
enum {
SPI_NEW_CHUNK = 1,
SPI_DROP_FRAME,
JPEG_TASK_KILL,
};
struct lbuf_data_head {
int len;
u8 data[0];
};
struct camera_handle {
//设备驱动
struct camera_device *dev;
// JPEG 编码线程
char task_name[32];
u8 task_runing;
u8 task_stoping;
OS_SEM task_kill_sem;
// SPI接收行数统计
int spi_recv_line_cnt;
// jpeg lbuf
u8 *lbuf_ptr;
struct lbuff_head *lbuf_handle;
// yuv buf 队列
struct queue_buf *qbuf;
// SPI DMA 接收buf,中转buf,接收完后拷贝到队列buf
u8 *dma_recv_buf[2];
int dma_recv_buf_index;
};
static struct camera_handle *camera_hdl;
#define __this (camera_hdl)
AT(.spi.text.cache.L1)
__attribute__((interrupt("")))
static void camera_hw_spi_isr()
{
/*
在不可屏蔽中断调用,此函数及调用的子函数均需要放ram
特别注意打印。
否则在写flash的时候,会触发死机
*/
JL_SPI_TypeDef *SPI_REG = (SPI_ID == HW_SPI1) ? JL_SPI1 : JL_SPI2;
//clr pnd
SPI_REG->CON |= BIT(14);
if (SPI_REG->CON & BIT(21)) {
// slave rx dma overflow
SPI_REG->CON &= ~BIT(20); // clr
/* log_char('O'); */
}
if (SPI_REG->CON & BIT(18)) {
// slave tx dma underflow
SPI_REG->CON &= ~BIT(17); // clr
/* log_char('U'); */
}
// dma copy buf
u8 *recv_done_buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
u8 *chunk = queue_buf_get_isr(__this->qbuf);
if (chunk) {
dma_memcpy_async_inirq(chunk, recv_done_buf, DMA_REVC_SIZE);
//标记行号
chunk[DMA_REVC_SIZE + 0] = 0x55;
chunk[DMA_REVC_SIZE + 1] = 0xaa;
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
*chunk_rec_line = __this->spi_recv_line_cnt;
queue_buf_push_isr(__this->qbuf);
}
/* memcpy(chunk, recv_done_buf, DMA_REVC_SIZE); */
__this->dma_recv_buf_index = (__this->dma_recv_buf_index + 1) % ARRAY_SIZE(__this->dma_recv_buf);
__this->spi_recv_line_cnt = (DMA_CAMERA_SIZE + __this->spi_recv_line_cnt) % (__this->dev->height);
// 帧中间,减去帧头or帧尾的长度
u32 recv_cnt = DMA_REVC_SIZE - SPI_LEND_SIZE;
if (__this->spi_recv_line_cnt == 0 || __this->spi_recv_line_cnt == (__this->dev->height - DMA_CAMERA_SIZE)) {
recv_cnt = DMA_REVC_SIZE;
}
u8 *buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
SPI_REG->CON |= BIT(12);
SPI_REG->ADR = (u32)buf;
SPI_REG->CNT = recv_cnt;
}
static void camera_jpeg_dec_task(void *priv)
{
log_debug("%s enter>>>>>>>>>>>>>>>>>!\n", __func__);
struct camera_handle *hdl = (struct camera_handle *)priv;
u8 jpeg_qval = JPEG_QVAL;
log_debug("%s dev:%x", __func__, (u32)__this->dev);
void *jpegenc_hdl = software_jpegenc_init(
__this->dev->width,
__this->dev->height,
__this->dev->width + SPI_FHEAD_SIZE,
jpeg_qval);
if (!jpegenc_hdl) {
log_error("software jpegenc init err \n");
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
struct lbuf_data_head *lbuf_data = NULL;
int ret = 0;
int jpeg_buf_size = ONE_JPEG_MAX_SIZE;
int line_cnt = 0;
u8 *cur_bits = NULL;
int total_bits = 0;
u8 fps = 0;
u32 fps_time = jiffies_msec();
u32 enc_time;
while (hdl->task_runing) {
if (hdl->task_stoping) {
log_char('L');
os_time_dly(1);
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
}
line_cnt = 0;
continue;
}
u8 *chunk = NULL;
/* dma_memcpy_wait_idle(); */
chunk = queue_buf_pop(__this->qbuf);
if (!chunk) {//pass
log_char('P');
os_time_dly(1);
continue;
}
if ((chunk[DMA_REVC_SIZE + 0]) == 0x55 && (chunk[DMA_REVC_SIZE + 1] == 0xaa)) {
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
if (*chunk_rec_line == line_cnt) {
//正常执行
} else {
//pass当前帧
queue_buf_reset(__this->qbuf);
line_cnt = 0;
log_warn("pop[c:%d l:%d]", (*chunk_rec_line), line_cnt);
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
os_time_dly(1);
continue;
}
}
} else {
log_error("%s line_cnt:%d", __func__, line_cnt);
put_buf(chunk + DMA_CAMERA_SIZE, 4);
}
//帧首,申请jpeg lbuf
if (line_cnt == 0) {
while (!lbuf_data) {
lbuf_data = lbuf_alloc(__this->lbuf_handle, jpeg_buf_size);
if (!lbuf_data) {
log_char('L');
lbuf_data = lbuf_pop(__this->lbuf_handle, BIT(0));
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
}
continue;
}
}
total_bits = 0;
enc_time = jiffies_msec();
}
cur_bits = lbuf_data->data + total_bits;
int remain_size = jpeg_buf_size - total_bits;
int out_bits_size = 0;
u8 *in_buf = line_cnt ? chunk + SPI_FHEAD_SIZE :
chunk + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE;
if (software_jpegenc_line(jpegenc_hdl, cur_bits, remain_size,
in_buf, DMA_CAMERA_SIZE, line_cnt, &out_bits_size)) {
log_error("software jpgenc line err \n");
printf("jpeg enc err,reset !!!\n");
//pass当前帧
queue_buf_reset(__this->qbuf);
line_cnt = 0;
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
/* os_time_dly(1); */
/* continue; */
}
//reset jpg_hd
software_jpegenc_exit(jpegenc_hdl);
jpegenc_hdl = software_jpegenc_init(
__this->dev->width,
__this->dev->height,
__this->dev->width + SPI_FHEAD_SIZE,
jpeg_qval);
if (!jpegenc_hdl) {
log_error("software jpegenc init err \n");
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
continue;
}
total_bits += out_bits_size;
line_cnt += DMA_CAMERA_SIZE;
queue_buf_release(__this->qbuf);
//帧尾 push jpeg_buf
if (line_cnt == __this->dev->height) {
lbuf_data->len = total_bits;
lbuf_push(lbuf_data, BIT(0));
lbuf_data = NULL;
line_cnt = 0;
//fps info
fps++;
if ((jiffies_msec() - fps_time) > 1000) {
log_info("jpeg fps:%d enc_time:%lu \n", fps, jiffies_msec() - enc_time);
fps = 0;
fps_time = jiffies_msec();
}
}
}
log_debug("%s exit>>>>>>>>>>>>>>>>!\n", __func__);
software_jpegenc_exit(jpegenc_hdl);
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
int camera_spi_init()
{
int ret = 0;
hw_spi_dev spi = SPI_ID;
struct spi_platform_data spix_p_data = {
.port = {
IO_PORTC_01, // clk any io
IO_PORTC_02, // do any io
IO_PORTC_02, // di any io
0xff, // d2 any io
0xff, // d3 any io
0xff, // cs any io(主机不操作cs)
},
.role = SPI_ROLE_SLAVE,
.mode = SPI_MODE_BIDIR_1BIT, // SPI_MODE_UNIDIR_2BIT,//SPI_MODE_BIDIR_1BIT,
.bit_mode = SPI_FIRST_BIT_MSB,
.cpol = 0, // clk level in idle state:0:low, 1:high
.cpha = 0, // sampling edge:0:first, 1:second
.ie_en = 0, // ie enbale:0:disable, 1:enable
.irq_priority = 3,
.spi_isr_callback = NULL,
.clk = 24000000L,
};
ret = spi_open(spi, &spix_p_data);
if (ret < 0) {
log_error("spi master init error(%d)!", ret);
return ret;
}
spi_set_ie(spi, 1);
if (spi == HW_SPI1) {
request_irq(IRQ_SPI1_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI1_IDX, 0, 0);
} else {
request_irq(IRQ_SPI2_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI2_IDX, 0, 0);
}
os_time_dly(2);
u8 *buf = __this->dma_recv_buf[0];
spi_dma_transmit_for_isr(spi, (void *)buf, DMA_REVC_SIZE, 1);
return 0;
}
int camera_spi_deinit()
{
hw_spi_dev spi = SPI_ID;
spi_deinit(spi);
return 0;
}
int camera_manager_start(void)
{
if (!__this) {
return -1;
}
int ret = 0;
mem_stats();
struct camera_device *dev = __this->dev;
memset(__this, 0x00, sizeof(struct camera_handle));
__this->dev = dev;
__this->qbuf = queue_buf_create(DMA_REVC_SIZE + QBUF_EXT_SIZE, DMA_REVC_BUF_NUM);
if (!__this->qbuf) {
return -1;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
__this->dma_recv_buf[i] = malloc(DMA_REVC_SIZE);
if (!__this->dma_recv_buf[i]) {
log_error("dma recv buf malloc fail \n");
goto __err;
}
}
__this->lbuf_ptr = malloc_psram(JPEG_LBUF_SIZE);
if (!__this->lbuf_ptr) {
log_error("jpeg lbuf_ptr malloc fail \n");
goto __err;
}
__this->lbuf_handle = lbuf_init(__this->lbuf_ptr, JPEG_LBUF_SIZE, 4, sizeof(struct lbuf_data_head));
os_sem_create(&__this->task_kill_sem, 0);
__this->task_runing = 1;
snprintf(__this->task_name, sizeof(__this->task_name), "camera_jpeg_task");
if (os_task_create(camera_jpeg_dec_task, __this, 10, 1024, 1024, __this->task_name)) {
log_error(" read task create fail \n");
__this->task_runing = 0;
goto __err;
}
if (camera_spi_init()) {
goto __err;
}
camera_manager_resume();
return 0;
__err:
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return -1;
}
int camera_manager_stop(void)
{
if (!__this) {
return -1;
}
camera_manager_suspend();
camera_spi_deinit();
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return 0;
}
void camera_manager_resume(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->resume) {
return ;
}
__this->dev->resume();
}
void camera_manager_suspend(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->supend) {
return ;
}
__this->dev->supend();
}
void camera_manager_deep_resume(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
queue_buf_reset(__this->qbuf);
__this->dma_recv_buf_index = 0;
__this->spi_recv_line_cnt = 0;
if (__this->dev->init) {
__this->dev->init();
}
camera_spi_init();
camera_manager_resume();
__this->task_stoping = 0;
}
void camera_manager_deep_suspend(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
__this->task_stoping = 1;
camera_spi_deinit();
if (__this->dev->deinit) {
__this->dev->deinit();
}
}
static int camera_manager_dev_check(void)
{
struct camera_device *dev = NULL;
list_for_each_camera_device_module(dev) {
if (dev->check) {
if (!dev->check()) {
log_debug("%s find device:%x\n", __func__, (u32)dev);
__this->dev = dev;
return 0;
}
}
}
return -1;
}
int camera_manager_init(void)
{
ASSERT(!__this);
__this = malloc(sizeof(struct camera_handle));
memset(__this, 0, sizeof(struct camera_handle));
camera_manager_dev_check();
if (!__this->dev) {
return -1;
}
if (!__this->dev->init) {
return -1;
}
return __this->dev->init();
}
int camera_manager_deinit(void)
{
int ret = -1;
if (!__this) {
return -1;
}
if (!__this->dev) {
goto __err;
}
if (!__this->dev->deinit) {
goto __err;
}
ret = __this->dev->deinit();
__err:
if (__this) {
free(__this);
__this = NULL;
}
return ret;
}
int camera_manager_data_read(u8 **pp_data, int *p_len)
{
struct lbuf_data_head *node;
if (!pp_data || !p_len) {
log_error("camera read ptr err \n");
return -1;
}
node = lbuf_pop(__this->lbuf_handle, BIT(0));
if (!node) {
return -2;
}
*pp_data = node->data;
*p_len = node->len;
return 0;
}
int camera_manager_read_done(u8 *data_buf)
{
struct lbuf_data_head *node;
if (!data_buf) {
log_error("camera read done ptr err \n");
return -1;
}
node = (struct lbuf_data_head *)((u8 *)data_buf - offsetof(struct lbuf_data_head, data));
lbuf_free(node);
return 0;
}
int camera_manager_get_dev_width_height(int *width, int *height)
{
if (__this && __this->dev) {
*width = __this->dev->width;
*height = __this->dev->height;
return 0;
}
return -1;
}
int camera_manager_get_dev_fps(int *fps)
{
if (__this && __this->dev) {
*fps = __this->dev->fps;
return 0;
}
return -1;
}