refactor(app, drv): 移植下位机的应用程序到新的通信协议

1. 应用程序实现了心跳包
2. 应用程序实现了4个相机的单独设置
3. 应用程序去除了有关喷阀、接收处理mask和硬件fifo相关的代码
4. 删除了fifo相关驱动程序
5. 修正了encoder驱动程序中的清除缓存逻辑

Co-authored-by: lyz <1942503466@qq.com>
This commit is contained in:
Miaow 2023-05-27 23:01:10 +08:00
parent fe7b3308bc
commit 6449ebeeac
14 changed files with 210 additions and 498 deletions

View File

@ -307,10 +307,11 @@ $ make CROSS_COMPILE=交叉编译工具链前缀
8. 安装编译得到的驱动文件`encode.ko`,并设置自动加载,对应自启脚本可以如下方式写入,也可以直接上传[script/loadencoder.sh](../script/loadencoder.sh)ssh方式`root`登录:
```shell
上传encoder.ko到/lib/modules/[内核版本]/kernel/drivers/
$ cd /lib/modules/[内核版本]; depmod
上传encoder.ko到/lib/modules/[内核版本]/extra/
$ cd /lib/modules/[内核版本]/extra/; depmod
$ set +H
$ echo -e "#!/bin/sh\nmodprobe encoder" > /etc/init.d/loadencoder.sh
$ chmod 755 /etc/init.d/loadencoder.sh
$ cd /etc/rc5.d
$ ln -s ../init.d/loadencoder.sh S20loadencoder.sh
```

View File

@ -1 +1 @@
1.5
1.6

View File

@ -1,17 +1,19 @@
/**
* @file encoder_dev.c
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/06/11
* @author miaow, lyz (3703781@qq.com)
* @version 0.11
* @date 2022/04/26
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
*
* @copyright Copyright (c) 2023 miaow, lyz
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/04/11 <td>0.10 <td>lyz <td>Add seprate dividers up to 4 cameras
* <tr><td>2023/04/26 <td>0.11 <td>Miaow <td>Add Clear mode
* </table>
*/
@ -31,9 +33,13 @@
static int encoder_dev_fd = -1;
static char perror_buffer[128];
static struct {
unsigned int valve_divide_value;
unsigned int camera_divide_value;
static struct
{
uint32_t valve_divide_value;
uint32_t camera_a_divide_value;
uint32_t camera_b_divide_value;
uint32_t camera_c_divide_value;
uint32_t camera_d_divide_value;
} encoder_dev_divide_value_structure;
/**
@ -45,22 +51,37 @@ int encoder_dev_init()
{
encoder_dev_fd = open(ENCODER_DEV_PATH, O_RDWR);
ON_ERROR_RET(encoder_dev_fd, "", "", -1);
encoder_dev_set_divide( 100, 100, 100, 100);
return 0;
}
/**
* @brief Set the two divider in the hareware encoder unit.
* @param valve_divide the frequency division factor between the encoder signal and valve output
* @param camera_a_divide the frequency division factor between the encoder signal and camera a triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_divide the frequency division factor between the encoder signal and camera triggle signal
* @param camera_b_divide the frequency division factor between the encoder signal and camera b triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_c_divide the frequency division factor between the encoder signal and camera c triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_d_divide the frequency division factor between the encoder signal and camera d triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
*
* @return 0 - success, other - error
*/
int encoder_dev_set_divide(int valve_divide, int camera_divide)
int encoder_dev_set_divide(int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide)
{
encoder_dev_divide_value_structure.valve_divide_value = valve_divide;
encoder_dev_divide_value_structure.camera_divide_value = camera_divide;
encoder_dev_divide_value_structure.valve_divide_value = 2;
if (camera_a_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_a_divide_value = camera_a_divide;
if (camera_b_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_b_divide_value = camera_b_divide;
if (camera_c_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_c_divide_value = camera_c_divide;
if (camera_d_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_d_divide_value = camera_d_divide;
ssize_t size = write(encoder_dev_fd, &encoder_dev_divide_value_structure, sizeof(encoder_dev_divide_value_structure));
int res = -(size != sizeof(encoder_dev_divide_value_structure));
ON_ERROR_RET(res, "size=", "", -1);
@ -70,12 +91,12 @@ int encoder_dev_set_divide(int valve_divide, int camera_divide)
/**
* @brief Set the trig signal to internal or external.
* @param mode ENCODER_TRIG_MODE_EXTERNEL for externally trig, or ENCODER_TRIG_MODE_INTERNEL for internally trig
* @param count the count of virtual trig cycles.
* @return 0 - success, other - error
*/
int encoder_dev_virtual_trig(int count)
{
int res = ioctl(encoder_dev_fd, _IOW('D', ENCODER_CMD_FUNCTION_VIRT_INPUT, 4), count);
int res = ioctl(encoder_dev_fd, _IOW('D', ENCODER_CMD_FUNCTION_VIRT_INPUT, int), count);
ON_ERROR_RET(res, "", "", -1);
return 0;
}
@ -85,9 +106,20 @@ int encoder_dev_virtual_trig(int count)
* @param mode ENCODER_TRIG_MODE_EXTERNEL for externally trig, or ENCODER_TRIG_MODE_INTERNEL for internally trig
* @return 0 - success, other - error
*/
int encoder_dev_set_trigmod(int mode)
int encoder_dev_set_trigmod(encoder_dev_trig_mode_enum mode)
{
int res = ioctl(encoder_dev_fd, _IOW('D', mode, 0));
int res = ioctl(encoder_dev_fd, _IOW('D', mode, int));
ON_ERROR_RET(res, "", "", -1);
return 0;
}
/**
* @brief Set the clr signal to internal or both external and internal.
* @return 0 - success, other - error
*/
int encoder_dev_set_clrmod(encoder_dev_clear_mode_enum mode)
{
int res = ioctl(encoder_dev_fd, _IOW('D', mode, int));
ON_ERROR_RET(res, "", "", -1);
return 0;
}

View File

@ -1,16 +1,19 @@
/**
* @file encoder_dev.h
* @brief Manage the hardware encoder unit
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/06/11
*
* @copyright Copyright (c) 2022 miaow
*
* @author miaow, lzy (3703781@qq.com)
* @version 0.11
* @date 2022/04/26
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2023 miaow, lyz
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/06/11 <td>0.9 <td>Miaow <td>Write this module
* <tr><td>2022/04/11 <td>0.10 <td>lyz <td>Add seprate dividers up to 4 cameras
* <tr><td>2023/04/26 <td>0.11 <td>Miaow <td>Add Clear mode
* </table>
*/
#ifndef __ENCODER_DEV_H
@ -20,14 +23,27 @@
#define ENCODER_DEV_PATH "/dev/encoder"
#define ENCODER_DEV_DIVIDE_NOT_TO_SET 0
#define ENCODER_DEV_DIVIDE_NOT_TO_SET 0
#define ENCODER_TRIG_MODE_EXTERNEL 100
#define ENCODER_TRIG_MODE_INTERNEL 101
typedef enum
{
ENCODER_TRIG_MODE_EXTERNEL = 100,
ENCODER_TRIG_MODE_INTERNEL = 101
} encoder_dev_trig_mode_enum;
int encoder_dev_set_divide(int valve_divide, int camera_divide);
typedef enum
{
ENCODER_CLEAR_MODE_BOTH = 200,
ENCODER_CLEAR_MODE_INTERNAL = 201
} encoder_dev_clear_mode_enum;
int encoder_dev_set_divide(int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide);
int encoder_dev_flush(void);
int encoder_dev_set_trigmod(int mode);
int encoder_dev_set_trigmod(encoder_dev_trig_mode_enum mode);
int encoder_dev_set_clrmod(encoder_dev_clear_mode_enum mode);
int encoder_dev_virtual_trig(int count);
int encoder_dev_init(void);
int encoder_dev_deinit(void);

View File

@ -1,149 +0,0 @@
/**
* @file fifo_dev.c
* @brief Operate the hardware fifo with Linux application
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write_xxx() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @mainpage github.com/NanjingForestryUniversity
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/09 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/07 <td>1.1 <td>miaow <td>Add ignore_row_num to fifo_dev_write_frame
* </table>
*/
#include <fifo_dev.h>
#include <pthread.h>
#include <unistd.h>
#include <common.h>
#include <fcntl.h>
#include <host_computer.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <data_filter.h>
#define FIFO_CMD_FUNCTION_CLEAR 1
#define FIFO_CMD_FUNCTION_PADDING 2
#define FIFO_CMD_GET_EMPTYCOUNT 3
static int fifo_dev_fd = -1;
static char perror_buffer[128];
/**
* @brief Initialize the hardware fifo
* @note This function just open the file descriptor of the hardware fifo
* @return 0 - success, other - error
*/
int fifo_dev_init()
{
fifo_dev_fd = open(FIFO_DEV_PATH, O_RDWR);
ON_ERROR_RET(fifo_dev_fd, "", "", -1);
return 0;
}
/**
* @brief Get the count of read operation when the fifo is empty.
* @note The empty read count will be set to zero at fifo_dev_clear() only.
* @return >=0 - success, other - error
*/
int fifo_dev_get_emptycount()
{
int count;
int res = ioctl(fifo_dev_fd, _IOR('D', FIFO_CMD_GET_EMPTYCOUNT, 0), &count);
ON_ERROR_RET(res, "", "", -1);
return count;
}
/**
* @brief Set value to put of a frame.
* @param valve_data An array HOST_COMPUTER_PICTURE_COLUMN_BYTES bytes * HOST_COMPUTER_PICTURE_ROW_NUM rows.
* @param ignore_row_num Remove the ignore_row_num rows at the beginning of the frame. range: [0, HOST_COMPUTER_PICTURE_BYTES)
* @return 0 - success, other - error
*/
int fifo_dev_write_frame(void *valve_data, int ignore_row_num)
{
ssize_t size;
char *valve_to_write = (char *)valve_data + ignore_row_num * HOST_COMPUTER_PICTURE_COLUMN_BYTES;
int size_to_write = HOST_COMPUTER_PICTURE_COLUMN_BYTES * (HOST_COMPUTER_PICTURE_ROW_NUM - ignore_row_num);
size = write(fifo_dev_fd, valve_to_write, size_to_write);
int res = -(size < size_to_write);
ON_ERROR_RET(res, "size=", "", -1);
return 0;
}
/**
* @brief Set value to put of a row.
* @param valve_data An array 32bytes.
* @return 0 - success, other - error
*/
int fifo_dev_write_row(void *valve_data)
{
ssize_t size = write(fifo_dev_fd, valve_data, 32);
int res = -(size < 32);
ON_ERROR_RET(res, "size=", "", -1);
return 0;
}
/**
* @brief Flush and clear the hardware fifo.
* @return 0 - success, other - error
*/
int fifo_dev_clear()
{
int res = ioctl(fifo_dev_fd, _IOW('D', FIFO_CMD_FUNCTION_CLEAR, 0));
ON_ERROR_RET(res, "", "", -1);
return 0;
}
/**
* @brief Write `count` zero-items to the haredware fifo, which acts as delay time.
* @param count Count of zero-items to write.
* @return 0 - success, other - error
*/
int fifo_dev_write_delay(uint32_t count)
{
int res = ioctl(fifo_dev_fd, _IOW('D', FIFO_CMD_FUNCTION_PADDING, 0), count);
ON_ERROR_RET(res, "", "", -1);
return 0;
}
/**
* @brief Get the count of items in the hardware fifo.
* @note An item from hardware fifo is of 256 bits in size, aka. 32 bytes, 8 integers
* @return >=0 - success, other - error
*/
int fifo_dev_get_count()
{
uint32_t fifo_item_count;
ssize_t size = read(fifo_dev_fd, &fifo_item_count, sizeof(fifo_item_count));
if (size != sizeof(fifo_item_count))
ON_ERROR(-1, "size=", "");
return fifo_item_count;
}
/**
* @brief Deinitialize the hardware fifo.
* @note This function just close the file descriptor of the hardware fifo.
* @return 0 - success, -1 - error
*/
int fifo_dev_deinit()
{
int res = close(fifo_dev_fd);
ON_ERROR_RET(res, "", "", -1);
return 0;
}

View File

@ -1,37 +0,0 @@
/**
* @file fifo_dev.h
* @brief Operate the hardware fifo with Linux application
* @details Call fifo_dev_init() paired with fifo_dev_deinit() as their names imply, fifo_dev_write_xxx() can be executed several times to operate the hardware fifo between fifo_dev_init() and fifo_dev_deinit()
* @mainpage github.com/NanjingForestryUniversity
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/09 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/07 <td>1.1 <td>miaow <td>Add ignore_row_num to fifo_dev_write_frame
* </table>
*/
#ifndef __FIFO_DEV_H
#define __FIFO_DEV_H
#include <stdint.h>
#define FIFO_DEV_PATH "/dev/fifo"
int fifo_dev_init(void);
int fifo_dev_get_emptycount(void);
int fifo_dev_write_frame(void *valve_data, int ignore_row_num);
int fifo_dev_clear(void);
int fifo_dev_write_delay(uint32_t count);
int fifo_dev_write_row(void *valve_data);
int fifo_dev_get_count(void);
int fifo_dev_deinit(void);
#endif

View File

@ -1,18 +1,19 @@
/**
* @file host_computer.c
* @brief Commnunicate with host computer. Protocal is described in hostcomputer通信协议.md
* @brief Commnunicate with host computer. Protocal is described in V1.4
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/06
* @version 1.2
* @date 2023/05/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
* @copyright Copyright (c) 2023 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/01/16 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/06 <td>1.1 <td>miaow <td>Add fifob
* <tr><td>2023/05/07 <td>1.2 <td>miaow <td>Port to b03 branch
* </table>
*/
#include <host_computer.h>
@ -24,11 +25,14 @@
#include <pthread.h>
#include <common.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <fifo_dev.h>
#include <encoder_dev.h>
#include <data_filter.h>
#include <sys/time.h>
#include <time.h>
#include <signal.h>
static char perror_buffer[128];
/**
@ -41,33 +45,42 @@ typedef struct
int need_exit; // The flag variable to indicate whether to exit the loop_thread in this file
pthread_t loop_thread; // The main routine of this module, which parses commands and data from host, puts them into the queue
pthread_mutex_t loop_thread_mutex; // The mutex for loop_thread
pthread_mutex_t is_connected_mutex;
timer_t heartbeat_timer;
} hostcomputer_t;
static hostcomputer_t _global_structure;
void *loop_thread_func(void *param);
void heartbeat_timer_func(__sigval_t param);
/**
* @brief Pre initialize host computer module
* @param data_q A pointer to the queue storing the valve data from host computer
* @param cmd_q A pointer to the queue storing the cmd from host computer
* @param cmd_q A pointer#include <sys/time.h> to the queue storing the cmd from host computer
* @return 0 - success
*/
int hostcomputer_init(queue_uint64_msg_t *cmd_q)
{
struct sigevent evp;
struct itimerspec ts;
_global_structure.cmd_q = cmd_q;
pthread_mutex_init(&_global_structure.loop_thread_mutex, NULL);
pthread_mutex_init(&_global_structure.is_connected_mutex, NULL);
pthread_create(&_global_structure.loop_thread, NULL, loop_thread_func, NULL);
memset(&evp, 0, sizeof(evp));
evp.sigev_value.sival_ptr = &_global_structure.heartbeat_timer;
evp.sigev_notify = SIGEV_THREAD;
evp.sigev_notify_function = heartbeat_timer_func;
timer_create(CLOCK_REALTIME, &evp, &_global_structure.heartbeat_timer);
ts.it_interval.tv_sec = 3;
ts.it_interval.tv_nsec = 0;
ts.it_value.tv_sec = 3;
ts.it_value.tv_nsec = 0;
timer_settime(_global_structure.heartbeat_timer, TIMER_ABSTIME, &ts, NULL);
return 0;
}
static void send_error(int fd)
{
write(fd, "error", 5);
printf("\r\nerror sent\r\n");
}
/**
* @brief Receive `size` bytes from a socket. If no more bytes are available at the socket, this function return -1 when timeout reaches.
* @param fd The socket fd
@ -105,7 +118,9 @@ static int is_connected(int sock_fd)
{
struct tcp_info info;
int len = sizeof(info);
pthread_mutex_lock(&_global_structure.is_connected_mutex);
getsockopt(sock_fd, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *)&len);
pthread_mutex_unlock(&_global_structure.is_connected_mutex);
return info.tcpi_state == TCP_ESTABLISHED;
}
@ -117,16 +132,12 @@ static int is_connected(int sock_fd)
void *loop_thread_func(void *param)
{
// printf("loop thread in %s start\r\n", __FILE__);
int need_exit = 0, frame_count = 0, error_sent = 0;
int std_count, empty_packets_num = 0;
int empty_count_initial = 0;
int empty_count_processed = 0;
int need_exit = 0;
char pre;
uint16_t n_bytes;
uint32_t n_bytes;
char type[2];
char data[HOST_COMPUTER_PICTURE_BYTES + 1];
char data[20];
char check[2];
datafilter_typedef datafilter;
while (!need_exit)
{
@ -136,6 +147,7 @@ void *loop_thread_func(void *param)
// reconnect if not connected
if (!is_connected(_global_structure.socket_fd))
{
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_STOP);
_global_structure.socket_fd = socket(AF_INET, SOCK_STREAM, 0);
struct timeval timeout = {.tv_sec = 10, .tv_usec = 0};
setsockopt(_global_structure.socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
@ -158,7 +170,6 @@ void *loop_thread_func(void *param)
}
// =======================parse the protocol=========================================
if (recvn(_global_structure.socket_fd, (char *)&pre, 1) > 1)
{
// close(_global_structure.socket_fd);
@ -172,17 +183,17 @@ void *loop_thread_func(void *param)
// fflush(stdout);
continue;
}
if (recvn(_global_structure.socket_fd, (char *)&n_bytes, 2) != 2)
if (recvn(_global_structure.socket_fd, (char *)&n_bytes, 4) != 4)
{
// close(_global_structure.socket_fd);
printf("n_bytes_len!=2\r\n");
printf("n_bytes_len!=4\r\n");
continue;
}
n_bytes = ntohs(n_bytes);
if (n_bytes != HOST_COMPUTER_PICTURE_BYTES + 2 && n_bytes > 10)
n_bytes = ntohl(n_bytes);
if (n_bytes != 10 && n_bytes != 3)
{
// close(_global_structure.socket_fd);
printf("n_bytes> 10 and n_bytes!=HOST_COMPUTER_PICTURE_BYTES + 2\r\n");
printf("n_bytes is not 10 or 3\r\n");
continue;
}
if (recvn(_global_structure.socket_fd, (char *)type, 2) != 2)
@ -220,96 +231,9 @@ void *loop_thread_func(void *param)
// =======================parse the commands=========================================
// commands are reformed as an uint64_t, 0x--------xxxxxxxx, where `-` refers its paramter and `x` is HOSTCOMPUTER_CMD
if (type[0] == 'd' && type[1] == 'a')
{
/*
int current_count = fifo_dev_get_count();
int current_count_filtered = datafilter_calculate(&datafilter_a, current_count);
if (++frame_count_a > HOST_COMPUTER_BEGINNING_PICTURES_IGNORE_NUM)
{
fifo_dev_write_frame(data, 0);
}
int added_count = fifo_dev_get_count();
printf("before %d->after %d, diff %d, filter %d\r\n", current_count, added_count, added_count - current_count, current_count_filtered);
*/
//=================================================
int current_count, current_count_filtered, diff_count, empty_count_to_process;
if (n_bytes - 2 != HOST_COMPUTER_PICTURE_BYTES)
{
printf("n_bytes-2!=%d\r\n", HOST_COMPUTER_PICTURE_BYTES);
continue;
}
// get the item counts and its slide average value
current_count = fifo_dev_get_count();
current_count_filtered = datafilter_calculate(&datafilter, current_count);
frame_count++;
if (frame_count == HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM + 1)
{
empty_count_initial = fifo_dev_get_emptycount();
}
else if (frame_count == 100) // record the normal item counts in fifo
{
std_count = current_count_filtered;
}
if (frame_count > HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM)
{
// do nothing at first two frames, because that the first frame is set to zero and was concatenated to the delay frame before
// in case of late arrival of the first two frames.
empty_count_to_process = fifo_dev_get_emptycount() - empty_count_initial - empty_count_processed;
if (empty_count_to_process >= HOST_COMPUTER_PICTURE_ROW_NUM)
{
empty_count_processed += HOST_COMPUTER_PICTURE_ROW_NUM;
}
else
{
fifo_dev_write_frame(data, empty_count_to_process);
empty_count_processed += empty_count_to_process;
}
}
if (current_count == 0)
empty_packets_num++;
else
empty_packets_num = 0;
// print fifo status
printf("a ||| %d | cnt %d | avgcnt %d | stdcnt %d",
frame_count, current_count, current_count_filtered, std_count);
fflush(stdout);
// if (empty_count_to_process)
printf(" ||| initemp %d | toprc %d | prcd %d\r\n", empty_count_initial,
empty_count_to_process, empty_count_processed);
// else
// printf("\r\n");
// if the item counts changes a lot compared with normal counts,
// meaning something goes wrong, a message will send to the hostcomputer
diff_count = current_count_filtered - std_count;
int diff_cond = diff_count > 250 || diff_count < -250;
int frame_count_cond = frame_count > 100;
int empty_packets_cond = empty_packets_num >= 5;
if (((frame_count_cond && diff_cond) || empty_packets_cond) && !error_sent)
{
error_sent = 1;
printf("\r\na ||| avgcnt %d | %d larger", current_count_filtered, diff_count);
fflush(stdout);
send_error(_global_structure.socket_fd);
}
}
else if (type[0] == 's' && type[1] == 't')
if (type[0] == 's' && type[1] == 't')
{
// printf("Start put to cmd queue, param:%d\r\n", (int)atoll(data));
frame_count = 0;
error_sent = 0;
empty_packets_num = 0;
std_count = 0;
datafilter_deinit(&datafilter);
datafilter_init(&datafilter, 20);
empty_count_processed = 0;
empty_count_initial = 0;
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_START);
}
else if (type[0] == 's' && type[1] == 'p')
@ -317,47 +241,46 @@ void *loop_thread_func(void *param)
// printf("Stop put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_STOP);
}
else if (type[0] == 't' && type[1] == 'e')
{
// printf("Test put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_TEST);
}
else if (type[0] == 't' && type[1] == 't')
{
// printf("Test put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_STOP_TEST);
}
else if (type[0] == 'p' && type[1] == 'o')
{
// printf("Power on put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_POWERON);
}
else if (type[0] == 's' && type[1] == 'c')
else if (type[0] == 'p' && type[1] == 'a')
{
// printf("Set camera triggle pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT);
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_A);
}
else if (type[0] == 's' && type[1] == 'v')
else if (type[0] == 'p' && type[1] == 'b')
{
// printf("Set valve pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETVALVETRIGPULSECOUNT);
// printf("Set camera triggle pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_B);
}
else if ((type[0] == 's' && type[1] == 'd'))
else if (type[0] == 'p' && type[1] == 'c')
{
// printf("Set camera to valve pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATOVALVEPULSECOUNT);
// printf("Set camera triggle pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_C);
}
else if (type[0] == 'p' && type[1] == 'd')
{
// printf("Set camera triggle pulse count put to cmd queue, param:%d\r\n", (int)atoll(data));
queue_uint64_put(_global_structure.cmd_q, (atoll(data) << 32) | HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_D);
}
}
printf("loop thread in %s exit\r\n", __FILE__);
return NULL;
}
void heartbeat_timer_func(__sigval_t param)
{
static uint8_t heartbeat_packet[] = {0xaa, 0x00, 0x00, 0x00, 0x03, 'h', 'b', 0xff, 0xff, 0xff, 0xbb};
if (is_connected(_global_structure.socket_fd))
write(_global_structure.socket_fd, heartbeat_packet, sizeof(heartbeat_packet));
}
/**
* @brief Deinitialize and release resources used by host computer module
* @return int
*/
int hostcomputer_deinit()
{
timer_delete(_global_structure.heartbeat_timer);
pthread_mutex_lock(&_global_structure.loop_thread_mutex);
_global_structure.need_exit = 1;
pthread_mutex_unlock(&_global_structure.loop_thread_mutex);

View File

@ -1,17 +1,19 @@
/**
* @file host_computer.h
* @brief Commnunicate with host computer. Protocal is described in hostcomputer通信协议.md
* @brief Commnunicate with host computer. Protocal is described in V1.4
* @author miaow (3703781@qq.com)
* @version 1.1
* @date 2022/08/6
* @version 1.2
* @date 2023/05/07
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
* @copyright Copyright (c) 2023 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/01/16 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2022/08/06 <td>1.1 <td>miaow <td>Add fifob
* <tr><td>2023/05/07 <td>1.2 <td>miaow <td>Port to b03 branch
* </table>
*/
#ifndef __HOST_COMPUTER_H
@ -21,27 +23,20 @@
#include <pthread.h>
#include <stdint.h>
#define HOST_COMPUTER_IP "192.168.10.8"
#define HOST_COMPUTER_IP "192.168.2.125"
#define HOST_COMPUTER_PORT 13452
#define HOST_COMPUTER_PICTURE_ROW_NUM 1024
#define HOST_COMPUTER_PICTURE_COLUMN_NUM 256
#define HOST_COMPUTER_PICTURE_COLUMN_BYTES (HOST_COMPUTER_PICTURE_COLUMN_NUM / 8)
#define HOST_COMPUTER_PICTURE_BYTES (HOST_COMPUTER_PICTURE_COLUMN_BYTES * HOST_COMPUTER_PICTURE_ROW_NUM)
#define HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM 1
/**
* @brief The commonds, ref
* @brief The commonds, ref V1.4
*/
enum HOSTCOMPUTER_CMD
{
HOSTCOMPUTER_CMD_START = 2,
HOSTCOMPUTER_CMD_STOP = 3,
HOSTCOMPUTER_CMD_TEST = 4,
HOSTCOMPUTER_CMD_POWERON = 5,
HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT = 6,
HOSTCOMPUTER_CMD_SETVALVETRIGPULSECOUNT = 7,
HOSTCOMPUTER_CMD_SETCAMERATOVALVEPULSECOUNT = 8,
HOSTCOMPUTER_CMD_STOP_TEST = 9
HOSTCOMPUTER_CMD_START = 1,
HOSTCOMPUTER_CMD_STOP = 2,
HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_A = 3,
HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_B = 4,
HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_C = 5,
HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_D = 6,
};
int hostcomputer_init(queue_uint64_msg_t *cmd_q);

View File

@ -2,19 +2,20 @@
* @file main.c
* @brief Excute the commands from host_computer
* @author miaow (3703781@qq.com)
* @version 1.0
* @date 2022/06/12
* @version 1.2
* @date 2023/05/27
* @mainpage github.com/NanjingForestryUniversity
*
* @copyright Copyright (c) 2022 miaow
* @copyright Copyright (c) 2023 miaow
*
* @par Changelog:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2022/06/12 <td>1.0 <td>miaow <td>Write this file
* <tr><td>2023/05/07 <td>1.1 <td>miaow <td>Port to b03
* <tr><td>2023/05/27 <td>1.2 <td>miaow <td>Fix bug caused by the missing encoder_dev_set_clrmod()
* </table>
*/
#include <fifo_dev.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <math.h>
@ -25,12 +26,6 @@
#include <stdio.h>
#include <unistd.h>
#define SET_VALVE_ONLY_N_ON(u32_buf, n) \
bzero(u32_buf, sizeof(u32_buf)); \
SET_VALVE_N_ON(u32_buf, n)
#define SET_VALVE_N_ON(u32_buf, n) u32_buf[n / 32] = 1 << (n % 32)
/**
* @brief Value of state machine
*/
@ -43,9 +38,19 @@ typedef enum
queue_uint64_msg_t cmd_queue = {0};
static status_enum_t status = SLEEPING;
static int camera_trigger_pulse_count = 1200;
static int valve_trigger_pulse_count = 120;
static int camera_to_valve_pulse_count = 500;
typedef struct
{
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t d;
} camera_trigger_pulse_count_typedef;
camera_trigger_pulse_count_typedef camera_trigger_pulse_count = {
.a = 100,
.b = 100,
.c = 100,
.d = 100};
void process_cmd(uint64_t *cmd);
@ -57,51 +62,19 @@ void process_cmd(uint64_t *cmd);
*/
int main(int argc, char *argv[])
{
uint64_t cmd;
queue_uint64_init(&cmd_queue, 9999);
// Initialize drivers and clear all caches
encoder_dev_init();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(2, 8);
fifo_dev_init();
encoder_dev_set_divide(8, 8, 8, 8);
//==test encoder================================================================
// fifo_dev_init();
// encoder_dev_set_trigmod(ENCODER_TRIG_MODE_EXTERNEL);
// encoder_dev_set_divide(4, 8);
// int a = 1;
// while (a)
// {
// printf("input a\r\n");
// scanf("%d", &a);
// printf("a=%d\r\n\r\n\r\n", a);
// }
// encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
// encoder_dev_deinit();
// queue_uint64_deinit(&cmd_queue);
// return 0;
//==test fifo================================================================
// char data[HOST_COMPUTER_PICTURE_COLUMN_BYTES * HOST_COMPUTER_PICTURE_ROW_NUM + 1];
// fifo_dev_init();
// fifo_dev_write_frame(data);
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_write_frame(data);
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_clear();
// printf("%d\r\n", fifo_dev_get_count());
// fifo_dev_deinit();
// encoder_dev_deinit();
// return 0;
//==================================================================
fifo_dev_clear();
hostcomputer_init(&cmd_queue);
printf("\r\n>>>>>\r\nstatus==SLEEPING\r\n<<<<<\r\n\r\n");
uint64_t cmd;
int TRUE = 1;
// Read from the cmd_queue and excute the command every 100ms
while (TRUE)
while (1)
{
if (queue_uint64_get(&cmd_queue, &cmd) == 0)
process_cmd(&cmd);
@ -110,11 +83,9 @@ int main(int argc, char *argv[])
// Never run here
hostcomputer_deinit();
fifo_dev_clear();
encoder_dev_set_divide(2, 8);
encoder_dev_set_divide(100,100,100,100);
encoder_dev_virtual_trig(20);
fifo_dev_deinit();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_deinit();
queue_uint64_deinit(&cmd_queue);
@ -138,87 +109,51 @@ void process_cmd(uint64_t *cmd)
{
// Before running, clear the hardware fifo and hardware encoder. Then, the two dividers and delay value should be set.
// Also, the hareware encoder is expected to receiving pluse of encoder: the EXTERNAL mode
fifo_dev_clear();
encoder_dev_flush();
encoder_dev_set_divide(valve_trigger_pulse_count, camera_trigger_pulse_count);
fifo_dev_write_delay(camera_to_valve_pulse_count + HOST_COMPUTER_PICTURE_ROW_NUM * HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM);
encoder_dev_set_divide(camera_trigger_pulse_count.a,
camera_trigger_pulse_count.b,
camera_trigger_pulse_count.c,
camera_trigger_pulse_count.d);
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_EXTERNEL);
printf("\r\n>>>>>\r\nstatus==RUNNING\r\ncamera_trigger_pulse_count=%d\r\nvalve_trigger_pulse_count=%d\r\n"
"camera_to_valve_pulse_count=%d\r\n<<<<<\r\n\r\n", camera_trigger_pulse_count,
valve_trigger_pulse_count, camera_to_valve_pulse_count + HOST_COMPUTER_PICTURE_ROW_NUM * HOST_COMPUTER_PICTURES_BEGINNING_IGNORE_NUM);
encoder_dev_set_clrmod(ENCODER_CLEAR_MODE_BOTH);
printf("\r\n>>>>>\r\nstatus==RUNNING\r\ncamera_a=%d\r\ncamera_b=%d\r\ncamera_c=%d\r\ncamera_d=%d\r\n<<<<<\r\n\r\n",
camera_trigger_pulse_count.a,
camera_trigger_pulse_count.b,
camera_trigger_pulse_count.c,
camera_trigger_pulse_count.d);
status = RUNNING;
}
else if (tmp_cmd == HOSTCOMPUTER_CMD_TEST)
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_A)
{
uint32_t row_data[8] = {0};
// When to excute TEST cmd (aka testing the valve), hardware fifo and hardware encoder should be cleared.
// A new combination of divider is set: 2 for both valve and camera, for less virtual pluse is needed to triggle valve in INTERNAL mode.
// Note that camera can be triggled during testing.
fifo_dev_clear();
encoder_dev_flush();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(2, 8); // fifo out every 8/4=2 cycle, valveboard operate every 2 cycle
// A parameter below 256 represents a single shot, the value of parameter indicates the valve to triggle.
if (tmp_data < 256)
{
SET_VALVE_ONLY_N_ON(row_data, tmp_data);
fifo_dev_write_row(row_data);
// delay for 15000 us and turn off the valve
encoder_dev_virtual_trig(2);
usleep(15000);
encoder_dev_virtual_trig(2);
}
// 257 represents triggle valve from NO.1 to 256 sequenctially. This loop blocks for 25.7s.
else if (tmp_data == 257)
{
for (int i = 0; i < 256; i++)
{
SET_VALVE_ONLY_N_ON(row_data, i);
fifo_dev_write_row(row_data);
bzero(&row_data, sizeof(row_data));
fifo_dev_write_row(row_data);
// printf("%d,%d\r\n", fifo_dev_get_count(), fifob_dev_get_count());
}
for (int i = 0; i < 257; i++)
{
encoder_dev_virtual_trig(2);
usleep(15000);
encoder_dev_virtual_trig(2);
usleep(100000 - 15000);
// printf("%d,%d\r\n", fifo_dev_get_count(), fifob_dev_get_count());
}
}
camera_trigger_pulse_count.a = tmp_data;
}
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT)
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_B)
{
camera_trigger_pulse_count = tmp_data;
camera_trigger_pulse_count.b = tmp_data;
}
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETVALVETRIGPULSECOUNT)
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_C)
{
valve_trigger_pulse_count = tmp_data;
camera_trigger_pulse_count.c = tmp_data;
}
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATOVALVEPULSECOUNT)
else if (tmp_cmd == HOSTCOMPUTER_CMD_SETCAMERATRIGPULSECOUNT_D)
{
camera_to_valve_pulse_count = tmp_data;
camera_trigger_pulse_count.d = tmp_data;
}
}
// Only in RUNNING state, the lower machine responds to STOP command.
else if (status == RUNNING)
{
if (tmp_cmd == HOSTCOMPUTER_CMD_STOP)
{
// Clear hardware fifo.
// 10 virtual triggles in internal mode ensure valve is turned off.
{
// Hardware encoder is flushed for a fresh start.
fifo_dev_clear();
encoder_dev_set_trigmod(ENCODER_TRIG_MODE_INTERNEL);
encoder_dev_set_divide(4, 4);
encoder_dev_set_divide(4, 4, 4, 4);
encoder_dev_virtual_trig(20);
encoder_dev_flush();
status = SLEEPING;
printf("\r\n>>>>>\r\nstatus==SLEEPING\r\n<<<<<\r\n\r\n");
}
}
}
}

View File

@ -1 +1 @@
1.2
1.3

View File

@ -188,12 +188,12 @@ static long encoder_ioctl(struct file *fp, unsigned int cmd, unsigned long tmp)
// 3. 恢复为原来的状态和模式
writel(data, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_INTERNAL)
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_BOTH)
{
// 设为允许内部和外部信号清除缓存
writel(data & ~ENCODER_CR_ICO_MASK, encoder_cr_addr);
}
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_BOTH)
else if (cmd_parsed == ENCODER_CMD_CLEAR_MODE_INTERNAL)
{
// 设为仅允许内部清除缓存
writel(data | ENCODER_CR_ICO_MASK, encoder_cr_addr);

View File

@ -57,8 +57,6 @@ int encoder_dev_init()
/**
* @brief Set the two divider in the hareware encoder unit.
* @param valve_divide the frequency division factor between the encoder signal and valve output
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_a_divide the frequency division factor between the encoder signal and camera a triggle signal
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @param camera_b_divide the frequency division factor between the encoder signal and camera b triggle signal
@ -69,14 +67,13 @@ int encoder_dev_init()
* Set ENCODER_DEV_DIVIDE_NOT_TO_SET to skip changing the division facter
* @return 0 - success, other - error
*/
int encoder_dev_set_divide(int valve_divide,
int camera_a_divide,
int encoder_dev_set_divide(int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide)
{
if (valve_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.valve_divide_value = valve_divide;
encoder_dev_divide_value_structure.valve_divide_value = 100;
if (camera_a_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)
encoder_dev_divide_value_structure.camera_a_divide_value = camera_a_divide;
if (camera_b_divide != ENCODER_DEV_DIVIDE_NOT_TO_SET)

View File

@ -37,8 +37,7 @@ typedef enum
ENCODER_CLEAR_MODE_INTERNAL = 201
} encoder_dev_clear_mode_enum;
int encoder_dev_set_divide(int valve_divide,
int camera_a_divide,
int encoder_dev_set_divide(int camera_a_divide,
int camera_b_divide,
int camera_c_divide,
int camera_d_divide);

View File

@ -1 +1 @@
1.5
1.6