为了更好的封装,这个模块使用class封装。
class Cheetah
{
public:
Cheetah(struct UartLiteDev* uart, struct StampTimerDev* timer);
int set_value(u16 addr, u32 value, int timeout = 1000);
int get_value(u16 addr, u32* value, int timeout = 1000);
int set_value_retry(u16 addr, u32 value, int timeout = 1000, int count = 5) {
while(count--)
{
int ret = set_value(addr, value, timeout);
if (ret == 0)
return 0;
}
return -1;
}
int get_value_retry(u16 addr, u32* value, int timeout = 1000, int count = 5) {
while(count--)
{
int ret = get_value(addr, value, timeout);
if (ret == 0)
return 0;
}
return -1;
}
...
protected:
struct UartLiteDev* uart_;
struct StampTimerDev* timer_;
};
这个class里,定义了几个基础的方法,用来获取值或者设置值,这些值都是通过串口进行收发的,所以这里需要关联到一个串口结构体,这是整板的一个硬件资源,所以不使用内嵌,而使用指针关联。
另外,发送过程中,需要用到时间戳,所以,这个需要关联到一个TIMER,这也是整板的一个硬件资源,所以不使用内嵌,而使用指针关联。
其他的特定的函数,都是基于基础方法获取特定的值或者设置特定的值,为了便于使用,增加可读性,所以封装成独立的函数。
例如:
int get_current_hsize(u32* value) {
u32 data = 0;
int ret = get_value_retry(0x6090, &data);
if (ret < 0)
return -1;
*value = data;
return 0;
}
int get_exp_time_limit(u32* max_value, u32* min_value) {
u32 data = 0;
int ret = get_value_retry(0x6088, &data);
if (ret < 0)
return -1;
*max_value = data & 0xffffff;
*min_value = data >> 24;
return 0;
}
int get_cam_attri(u32* paio_en, u32* aec_en, u32* agc_en) {
u32 data = 0;
int ret = get_value_retry(0x60AC, &data);
if (ret < 0)
return -1;
plog("%x\r\n", data);
*paio_en = (data >> 29) & 0x1;
*aec_en = (data >> 30) & 0x1;
*agc_en = (data >> 31) & 0x1;
return 0;
}
int get_current_exp_time(u32* value) {
return get_value_retry(0x6080, value);
}
...
int set_software_reset() {
return set_value_retry(0x601c, 0xDEADBEEF);
}
int set_exposure_mode(u8 value) {
//0x0 – Off (Free Running)
//0x1 – Trigger Pulse Width (Duration of selected trigger pulse determines exposure time)
//0x2 – Internal (Exposure Time register sets exposure time in microseconds)
//0x3 – Reserved
return set_value_retry(0x0720, value);
}
int set_exposure_time(u32 value, int timeout = 1000) {
return set_value_retry(0x0728, value, timeout);
}
int set_digital_gain(u32 value, int timeout = 1000) {
return set_value_retry(0x0438, value, timeout);
}
...
来看看几个基础函数的实现,在CPP文件中,
首先是构建函数,
Cheetah::Cheetah(struct UartLiteDev* uart, struct StampTimerDev* timer) : uart_(uart), timer_(timer)
{
}
并没有做特殊的处理,只是在构建时进行了成员的初始化。
将传入的参数,即两个资源结构体的指针,赋值给成员变量uart_和timer_。
再来看get
int Cheetah::get_value(u16 addr, u32* value, int timeout)
{
struct RingBuffer* ring = &uart_->recv_buff;
u8 data = 0;
ring_buffer_clear(ring);
struct SensorReadCommand cmd = {0};
cmd.data[0] = 0x52;
cmd.data[1] = (addr >> 8) & 0xff;
cmd.data[2] = addr & 0xff;
uart_lite_send(uart_, (u8*)&cmd.data[0], sizeof(cmd.data));
struct SensorReadAck ack = {0};
u32 action_time = get_timestamp_ms(timer_);
while(ring_buffer_valid_len(ring) < sizeof(ack.data))
{
u32 now_time = get_timestamp_ms(timer_);
u32 dlt_time = ABS_DEC(now_time, action_time);
if (dlt_time > (u32)timeout) {
plog("Cheetah get_value:0x%x timeout!\r\n", addr);
return -1;
}
}
u8* rptr = (u8*)&ack.data[0];
for (int i = 0; i < sizeof(ack.data); i++)
{
ring_buffer_pop(ring, &rptr[i]);
}
if (ack.data[0] == 0x06) {
u32 val = (((u32)ack.data[1]) << 24) | (((u32)ack.data[2]) << 16) | (((u32)ack.data[3]) << 8) | (((u32)ack.data[4]) << 0);
*value = val;
return 0;
} else {
plog("Cheetah get_value:0x%x error!\r\n", addr);
return -1;
}
}
按照协议要求,
先发命令,
然后等待ACK,这里等待是定时等待的,如果不定时,则可能出现卡死,
然后取出ACK,并分析,并从ACK的数组中,取出所需要的数据。
这里,使用了几个结构体对data数组进行封装,是为了增加可读性。
struct SensorWriteCommand
{
u8 data[7];
};
struct SensorWriteAck
{
u8 data[2];
};
struct SensorReadCommand
{
u8 data[3];
};
struct SensorReadAck
{
u8 data[5];
};
再来看set
int Cheetah::set_value(u16 addr, u32 value, int timeout)
{
struct RingBuffer* ring = &uart_->recv_buff;
u8 data = 0;
//while(ring_buffer_pop(ring, &data) == 0);
ring_buffer_clear(ring);
struct SensorWriteCommand cmd = {0};
cmd.data[0] = 0x57;
cmd.data[1] = (addr >> 8) & 0xff;
cmd.data[2] = addr & 0xff;
cmd.data[3] = (value >> 24) & 0xff;
cmd.data[4] = (value >> 16) & 0xff;
cmd.data[5] = (value >> 8) & 0xff;
cmd.data[6] = value & 0xff;
uart_lite_send(uart_, (u8*)&cmd.data[0], sizeof(cmd.data));
if (timeout <= 0)
return 0;
struct SensorWriteAck ack = {0};
u32 action_time = get_timestamp_ms(timer_);
while(ring_buffer_valid_len(ring) < 1)
{
u32 now_time = get_timestamp_ms(timer_);
u32 dlt_time = ABS_DEC(now_time, action_time);
if (dlt_time > (u32)timeout) {
plog("Cheetah set_value:0x%x 0x%x timeout!!!\r\n", addr, value);
return -1;
}
}
ring_buffer_pop(ring, &ack.data[0]);
if (ack.data[0] == 0x15) {
action_time = get_timestamp_ms(timer_);
while(ring_buffer_valid_len(ring) < 1)
{
u32 now_time = get_timestamp_ms(timer_);
u32 dlt_time = ABS_DEC(now_time, action_time);
if (dlt_time > (u32)timeout) {
plog("Cheetah set_value:0x%x 0x%x timeout!!!\r\n", addr, value);
return -1;
}
}
ring_buffer_pop(ring, &ack.data[1]);
}
if (ack.data[0] == 0x06) {
return 0;
} else {
if (ack.data[0] == 0x15) {
if (ack.data[1] == 0x00) {
return 0;
}
else {
plog("Cheetah set_value:0x%x 0x%x error, ", addr, value);
if (ack.data[1] == 0x01) {
plog("Error Code: Invalid command\r\n");
} else if (ack.data[1] == 0x02) {
plog("Error Code: Time out\r\n");
} else if (ack.data[1] == 0x03) {
plog("Error Code: Checksum error\r\n");
} else if (ack.data[1] == 0x04) {
plog("Error Code: Value less then minimum\r\n");
} else if (ack.data[1] == 0x05) {
plog("Error Code: Value higher than maximum\r\n");
} else if (ack.data[1] == 0x06) {
plog("Error Code: AGC error\r\n");
} else if (ack.data[1] == 0x07) {
plog("Error Code: Supervisor mode error\r\n");
} else if (ack.data[1] == 0x07) {
plog("Error Code: Mode not supported error\r\n");
} else {
plog("Error Code: 0x%x: ack=0x%x 0x%x\r\n", addr, ack.data[0], ack.data[1]);
}
}
}
return -1;
}
}
按照协议要求,
先发命令,
然后等待ACK,这里等待是定时等待的,如果不定时,则可能出现卡死,
然后取出ACK,并分析,并从ACK的数组中,取出所需要的数据。