Files
xu 8dd17a5b9a 修改:信号包独立发包,周期100ms;
布局切换按键,增加开机读取电平状态
2026-09-16 17:00:58 +08:00

405 lines
14 KiB
C
Raw Permalink 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 <stdio.h>
#include <stdlib.h>
#include <sys/time.h> // gettimeofday
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <time.h> /* 新增:clock_gettime / clock_nanosleep */
#include <pthread.h>
#include "serial.h"
#include "uartinf.h"
#include <stdbool.h>
#define RECV_PORT 12000 // UDP接收端口
#define SEND_PORT 12001 // 发送端口(UART转NET)
/* ===================== 网络帧协议定义 ===================== */
#define NET_FRAME_LEN 32 /* 收/发报文固定长度 */
#define NET_TAIL 0xBB /* 帧尾 */
#define PAYLOAD_LEN 30 /* 帧长度 byte0..29 */
#define BYTE_MODE 30 /* 接收帧 mode 字段偏移(0-4) */
#define BYTE_TAIL 31 /* 接收帧帧尾偏移 */
#define CHECKSUM_END 30 /* 校验和覆盖 byte0..byte30(含) */
#define NET_FRAME_MAX_LEN 256 /* recvfrom 缓冲大小 */
#define BYTE_NOSIG0 25 /* byte25 = 视频流0无信号标志(1=无信号,0=有信号) */
#define BYTE_NOSIG1 26 /* byte26 = 视频流1无信号标志(1=无信号,0=有信号) */
#define BYTE_RSSI1 28 /* 信号包=RSSI1;设备包=哨兵 */
#define BYTE_RSSI2 29 /* 信号包=RSSI2;设备包=哨兵 */
#define SIG_MARK 0x5A /* 设备包 byte28/29 哨兵值 */
#define SIGNAL_INTERVAL_MS 100 /* 独立信号包发送间隔(ms) */
#define FRAME_HEAD 0x11 /* 上行帧帧头(byte0),面板校验要求 */
#define FRAME_TAIL 0x22 /* 上行帧帧尾(byte30),面板校验要求 */
#define FRAME_HEAD_TX 0xAA /* 下行帧帧头(byte0),设备→面板 */
/* ===================== 共享内存 ===================== */
#define SHM_MSG_NAME "/video_switch"
#define SHM_MODE_IDX 0 /* switch_mode -> shm[0](即 switch_video[0]) */
static int *shm_msg = NULL;
static int *buffer_param = NULL; /* 新增:/param.txt 共享内存,供信号线程读 RSSI */
char _rx_data[200];
static int socket_descriptor;
static struct sockaddr_in address;
bool first = false;
int socket_descriptor_recv;
struct sockaddr_in address_recv;
pthread_attr_t attr;
pthread_t pkts_thread;
/* 打开共享内存 /param.txt(由 lc6600_uart 进程写入 RSSI) */
static int *param_memory_open(void) {
int fd = shm_open("/param.txt", O_RDWR, 0777);
if (fd < 0) {
fd = shm_open("/param.txt", O_RDWR | O_CREAT, 0777);
if (fd < 0) { perror("shm_open /param.txt"); return NULL; }
if (ftruncate(fd, 4096) == -1) { perror("ftruncate /param.txt"); return NULL; }
}
int *retval = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (retval == MAP_FAILED) { perror("mmap /param.txt"); return NULL; }
return retval;
}
static int *switch_memory_open(void) {
char buf[128];
int fd;
sprintf(buf, SHM_MSG_NAME);
fd = shm_open(buf, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if(fd < 0) { perror("shm_open"); exit(1); }
if (ftruncate(fd, 4096) == -1) { perror("ftruncate"); exit(1); }
int *retval = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return retval;
}
int init_net_recv(int port){
int i;
struct timeval tv;
bzero(&address_recv,sizeof(struct sockaddr_in));
address_recv.sin_family=AF_INET;
address_recv.sin_addr.s_addr=htonl(INADDR_ANY);
address_recv.sin_port=htons(port);
socket_descriptor_recv=socket(AF_INET,SOCK_DGRAM,0);//IPV4
tv.tv_sec = 2;
tv.tv_usec = 0;
if (setsockopt(socket_descriptor_recv, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
printf("socket option SO_RCVTIMEO not support\n");
return -1;
}
if (bind(socket_descriptor_recv, (struct sockaddr *)&address_recv, sizeof(struct sockaddr_in)) < 0)
{
perror("bind");
exit(1);
}
return 0;
}
int udp_init(char *ip, int port){
bzero(&address,sizeof(address));
address.sin_family=AF_INET;
address.sin_addr.s_addr=inet_addr(ip);
address.sin_port=htons(port);
socket_descriptor=socket(AF_INET,SOCK_DGRAM,0);//IPV4
return 0;
}
#if 0
void *net_recv(void *arg)
{
int i;
struct sockaddr_in clientAddr;
int len = sizeof(clientAddr);
int ret;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (setsockopt(socket_descriptor_recv, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
printf("socket option SO_RCVTIMEO not support\n");
//return -1;
}
char buffer_cmd[200];
while(1){
i = recvfrom(socket_descriptor_recv, buffer_cmd, 200, 0, (struct sockaddr*)&clientAddr, &len);
if(i>0){
uart_write_len(ROUTE_UART,buffer_cmd,i);
}
else{
printf(" time_out to receive data\n");
}
}
}
#endif
#if 1
void *net_recv(void *arg)
{
int i, k;
struct sockaddr_in clientAddr;
socklen_t len;
struct timeval tv;
char buffer_cmd[NET_FRAME_MAX_LEN];
char frame_out[NET_FRAME_MAX_LEN];
int sum;
unsigned char checksum;
tv.tv_sec = 5;
tv.tv_usec = 0;
if (setsockopt(socket_descriptor_recv, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
printf("socket option SO_RCVTIMEO not support\n");
while (1) {
len = sizeof(clientAddr); /* 每次循环重置,recvfrom 会改写 len */
i = recvfrom(socket_descriptor_recv, buffer_cmd, NET_FRAME_MAX_LEN, 0,
(struct sockaddr*)&clientAddr, &len);
if (i <= 0) {
printf(" time_out to receive data\n");
continue;
}
if (i != NET_FRAME_LEN) {
printf("bad frame len=%d\n", i);
continue;
}
/* 帧尾校验 */
if ((unsigned char)buffer_cmd[BYTE_TAIL] != NET_TAIL) {
printf("bad tail=%02x\n", (unsigned char)buffer_cmd[BYTE_TAIL]);
continue;
}
/* 解析 mode -> 写共享内存 */
if (shm_msg) {
static int last_mode = -1;
int mode = (unsigned char)buffer_cmd[BYTE_MODE];
if (mode <= 4) {
if (mode != last_mode) {
shm_msg[SHM_MODE_IDX] = mode; //写入共享内存 viode_switch
last_mode = mode;
printf("write shm: mode=%d\n", mode);
}
}
else {
printf("filed mode=%d\n", mode);
}
}
/* 构造下行帧:byte0=0xAA 帧头,byte1..29 原样,byte30=0xBB 帧尾 */
frame_out[0] = FRAME_HEAD_TX; /* [0] 帧头 0xAA */
memcpy(frame_out + 1, buffer_cmd + 1, PAYLOAD_LEN - 1); /* [1..29] 原样 */
frame_out[PAYLOAD_LEN] = NET_TAIL; /* [30] 帧尾 0xBB */
/* 校验和 = byte0..byte30 求和取低8位,写入 byte31 */
sum = 0;
for (k = 0; k <= CHECKSUM_END; k++)
sum += (unsigned char)frame_out[k];
checksum = sum & 0xFF;
frame_out[PAYLOAD_LEN + 1] = checksum; /* [31] 校验和 */
#if 0
/* 打印发出的包 */
printf(" send to uart %d bytes:", NET_FRAME_LEN);
for (k = 0; k < NET_FRAME_LEN; k++)
printf(" %02x", (unsigned char)frame_out[k]);
printf("\n");
#endif
uart_write_len(ROUTE_UART, frame_out, NET_FRAME_LEN); //发送给串口
}
return NULL;
}
#endif
/* 独立信号包线程:与串口收包完全解耦,固定 SIGNAL_INTERVAL_MS 周期发送。
* 用绝对时间 clock_nanosleep 对齐发送时刻,避免 sendto/printf 开销累积成漂移。 */
void *signal_send(void *arg)
{
char sig_frame[NET_FRAME_LEN];
struct timespec next;
int k, sum;
clock_gettime(CLOCK_MONOTONIC, &next);
while (1) {
memset(sig_frame, 0, NET_FRAME_LEN);
sig_frame[0] = (char)FRAME_HEAD; /* byte0 = 0x11 */
/* byte25/26 = 视频流0/1无信号,byte27 = 布局开关(light_pwm_lvds 的 0x68 按键) */
sig_frame[BYTE_NOSIG0] = (shm_msg && shm_msg[2] == 0x55) ? 1 : 0;
sig_frame[BYTE_NOSIG1] = (shm_msg && shm_msg[3] == 0x55) ? 1 : 0;
sig_frame[27] = (shm_msg && shm_msg[1]) ? 1 : 0;
printf("layout byte27 = %d\n", sig_frame[27]);
if (buffer_param) {
sig_frame[BYTE_RSSI1] = (char)buffer_param[1];
sig_frame[BYTE_RSSI2] = (char)buffer_param[2];
}
sig_frame[PAYLOAD_LEN] = (char)FRAME_TAIL; /* byte30 = 0x22 */
sum = 0;
for (k = 0; k <= CHECKSUM_END; k++)
sum += (unsigned char)sig_frame[k];
sig_frame[CHECKSUM_END + 1] = (char)(sum & 0xFF);
sendto(socket_descriptor, sig_frame, NET_FRAME_LEN, 0,
(struct sockaddr *)&address, sizeof(address));
/* 下一个发送时刻 = 本次时刻 + 周期,与实际执行耗时无关 */
next.tv_nsec += (long)SIGNAL_INTERVAL_MS * 1000000L;
while (next.tv_nsec >= 1000000000L) {
next.tv_sec++;
next.tv_nsec -= 1000000000L;
}
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL);
}
return NULL;
}
int pthread_init()
{
int ret;
pthread_t sig_thread;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
ret = pthread_create(&pkts_thread, &attr, net_recv, NULL);
if(ret){
printf("create pthread1 error\n");
pthread_attr_destroy(&attr);
return 1;
}
ret = pthread_create(&sig_thread, &attr, signal_send, NULL);
if(ret){
printf("create pthread2 error\n");
pthread_attr_destroy(&attr);
return 1;
}
pthread_attr_destroy(&attr);
return 0;
}
int main (int argc, char *argv[])
{
int n_read;
int i;
int count=0;
char buffer_send[100];
int buffer_len;
n_read = uart_init(ROUTE_UART, "/dev/ttyAMA4", 115200, 'N');
if(n_read <=0 ) {
printf("open /dev/ttyAMA4 failed\n");
return -1;
}
// udp_init(argv[1], atoi(argv[2]));
// init_net_recv(atoi(argv[3]));
udp_init("127.0.0.1", SEND_PORT); // 发送目标:本机回环 12001
init_net_recv(RECV_PORT); // 接收:0.0.0.0:12000(INADDR_ANY)
shm_msg = switch_memory_open();
buffer_param = param_memory_open();
if (pthread_init()) {
printf("pthread_init failed\n");
return -1;
}
while(1){
n_read = uart_read(ROUTE_UART, _rx_data);
if(n_read > 0 ){
int k, sum = 0;
/* 收包校验:完整 32 字节帧,帧头 0x11、帧尾 0x22、byte31 校验和正确,否则丢弃 */
if (n_read < NET_FRAME_LEN) {
printf("drop bad frame: len=%d\n", n_read);
continue;
}
if ((unsigned char)_rx_data[0] != FRAME_HEAD ||
(unsigned char)_rx_data[CHECKSUM_END] != FRAME_TAIL) {
printf("drop bad frame: head=%02x tail=%02x\n",
(unsigned char)_rx_data[0], (unsigned char)_rx_data[CHECKSUM_END]);
continue;
}
for (k = 0; k <= CHECKSUM_END; k++)
sum += (unsigned char)_rx_data[k];
if ((unsigned char)_rx_data[31] != (sum & 0xFF)) {
printf("drop bad frame: checksum=%02x expect=%02x\n",
(unsigned char)_rx_data[31], (unsigned char)(sum & 0xFF));
continue;
}
/* byte28/29 固定哨兵值,RSSI 改由独立信号包承载 */
_rx_data[BYTE_RSSI1] = (char)SIG_MARK;
_rx_data[BYTE_RSSI2] = (char)SIG_MARK;
/* 和校验:byte0..byte30 求和取低 8 位,写入 byte31 */
sum = 0;
for (k = 0; k <= CHECKSUM_END; k++)
sum += (unsigned char)_rx_data[k];
_rx_data[31] = (char)(sum & 0xFF);
sendto(socket_descriptor, _rx_data, NET_FRAME_LEN, 0, (struct sockaddr *)&address, sizeof(address));
}
}
}