ring_buf 的实现

//test.c


#include "zkm_buf.h"
int main()
{
    zkm_buf_t zbuf;
    char str[10];
    zkm_motor_t zkm_motor_tmp,zkm_motor_in;
    zkm_buf_init(&zbuf);


    zkm_motor_in.actualPosition = 0x1111;
    zkm_buf_write(&zbuf, &zkm_motor_in);


    zkm_motor_in.actualPosition = 0x2222;
    zkm_buf_write(&zbuf, &zkm_motor_in);


    zkm_motor_in.actualPosition = 0x3333;
    zkm_buf_write(&zbuf, &zkm_motor_in);


    zkm_motor_in.actualPosition = 0x4444;
    zkm_buf_write(&zbuf, &zkm_motor_in);




    zkm_motor_in.actualPosition = 0x5555;
    zkm_buf_write(&zbuf, &zkm_motor_in);


    int k = 0;
    for (k = 0; k < 8; k++)
        if (zkm_buf_read(&zbuf, &zkm_motor_tmp))
            printf("0x%x\n", zkm_motor_tmp.actualPosition);


    return 0;
}


//zkm_buf.h
#ifndef _ZKM_BUF_H_  
#define _ZKM_BUF_H_  




#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>




#define IDX_MASK (SIZE_MAX>>1)  
#define MSB_MASK (~IDX_MASK)   /* also the maximum value of the buffer depth */


#define BUF_DEPTH 128   /* this value is used for buffer R/W balance */


struct zkm_motor  /* this struct is used to save the parameters to pass to hosts displaying in curve , to be extended*/
{
    int32_t actualPosition;  /*0x6064*/
    int32_t actualVelocity;  /*0x606c*/
    int16_t actualTorque;    /*0x6077*/




    int16_t ctrlWords;       /*0x6040*/
    int16_t statusWords;     /*0x6041*/
    int8_t  operModDis;      /*0x6061*/
};


typedef struct zkm_motor zkm_motor_t;
#define ZKM_SIZE sizeof(zkm_motor_t)
/* zkm buffer structure */
struct zkm_buf
{
    size_t rd_idx;             /* MSB is used for the 'mirror' flag */
    size_t wr_idx;             /* MSB is used for the 'mirror' flag */
    zkm_motor_t  buf[BUF_DEPTH]  ;
};


typedef struct zkm_buf  zkm_buf_t;
typedef struct zkm_buf* zkm_buf_p;


bool zkm_buf_init (zkm_buf_p zbuf);
void zkm_buf_clear(zkm_buf_p zbuf);


bool zkm_buf_full (zkm_buf_p zbuf);
bool zkm_buf_empty(zkm_buf_p zbuf);


bool zkm_buf_write(zkm_buf_p zbuf, void *wr_data);
bool zkm_buf_read (zkm_buf_p zbuf, void *rd_data);
#endif


//zkm_buf.c


#include "zkm_buf.h"
#include <stdlib.h>
#include <string.h>


bool zkm_buf_init(zkm_buf_p zbuf)
{
    zbuf->rd_idx = 0;
    zbuf->wr_idx = 0;
    memset(zbuf->buf, 0, sizeof(zbuf->buf));
    return true;
}


void zkm_buf_clear(zkm_buf_p zbuf)
{
    zbuf->rd_idx = 0;
    zbuf->wr_idx = 0;
}


bool zkm_buf_is_empty(zkm_buf_p zbuf)
{
    return zbuf->rd_idx == zbuf->wr_idx;
}


bool zkm_buf_is_full(zkm_buf_p zbuf)
{
    return (zbuf->rd_idx & IDX_MASK) == (zbuf->wr_idx & IDX_MASK) &&
           (zbuf->rd_idx & MSB_MASK) != (zbuf->wr_idx & MSB_MASK);
}


inline void zkm_buf_incr(zkm_buf_p rbuf, size_t *p_idx)
{
    size_t idx = *p_idx & IDX_MASK;
    size_t msb = *p_idx & MSB_MASK;




    if (++idx == BUF_DEPTH) {
        msb ^= MSB_MASK;
        idx = 0;
    }
    *p_idx = msb | idx;
}


bool zkm_buf_write(zkm_buf_p zbuf, void *wr_data)
{
    if (zkm_buf_is_full(zbuf))
        return false;
    else {
        memcpy(zbuf->buf + zbuf->wr_idx * ZKM_SIZE, wr_data, ZKM_SIZE);
        zkm_buf_incr(zbuf, &zbuf->wr_idx);
        return true;
    }
}


bool zkm_buf_read(zkm_buf_p zbuf, void *rd_data)
{
    if (zkm_buf_is_empty(zbuf))
        return false;
    else {
        memcpy(rd_data, zbuf->buf + zbuf->rd_idx * ZKM_SIZE, ZKM_SIZE);
        zkm_buf_incr(zbuf, &zbuf->rd_idx);
        return true;
    }
}

#include "gd32f4xx.h" #include <string.h> #define RX_BUF_SIZE 256 // 接收缓冲区大小 // 环形缓冲区结构体 typedef struct { uint8_t buffer[RX_BUF_SIZE]; volatile uint16_t head; volatile uint16_t tail; } ring_buf_t; ring_buf_t usart_rx_buf; // USART接收缓冲区 volatile uint8_t packet_ready = 0; // 数据包就绪标志 // 初始化USART1 void usart_init(void) { rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_USART1); // 配置TX(PA9)/RX(PA10)引脚 gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9 | GPIO_PIN_10); gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9 | GPIO_PIN_10); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9 | GPIO_PIN_10); // USART参数配置 usart_deinit(USART1); usart_baudrate_set(USART1, 115200U); usart_word_length_set(USART1, USART_WL_8BIT); usart_stop_bit_set(USART1, USART_STB_1BIT); usart_parity_config(USART1, USART_PM_NONE); usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE); usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE); // 使能接收和空闲中断 usart_interrupt_enable(USART1, USART_INT_RBNE | USART_INT_IDLE); usart_receive_config(USART1, USART_RECEIVE_ENABLE); usart_transmit_config(USART1, USART_TRANSMIT_ENABLE); nvic_irq_enable(USART1_IRQn, 0, 0); usart_enable(USART1); } // USART1中断服务函数 void USART1_IRQHandler(void) { if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) { // 接收数据中断 uint8_t data = usart_data_receive(USART1); uint16_t next = (usart_rx_buf.head + 1) % RX_BUF_SIZE; if(next != usart_rx_buf.tail) { // 缓冲区未满 usart_rx_buf.buffer[usart_rx_buf.head] = data; usart_rx_buf.head = next; } } if(usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) { // 空闲中断 - 数据包结束 usart_data_receive(USART1); // 清除空闲中断标志 packet_ready = 1; // 设置数据包就绪标志 } } // 主循环处理 int main(void) { usart_init(); memset(&usart_rx_buf, 0, sizeof(ring_buf_t)); while(1) { if(packet_ready) { packet_ready = 0; // 计算包长度 uint16_t len = (usart_rx_buf.head >= usart_rx_buf.tail) ? (usart_rx_buf.head - usart_rx_buf.tail) : (RX_BUF_SIZE - usart_rx_buf.tail + usart_rx_buf.head); if(len > 0) { uint8_t packet[len + 1]; // 从缓冲区提取数据 for(int i=0; i<len; i++) { packet[i] = usart_rx_buf.buffer[usart_rx_buf.tail]; usart_rx_buf.tail = (usart_rx_buf.tail + 1) % RX_BUF_SIZE; } packet[len] = '\0'; // 添加字符串结束符 // 此处处理接收到的文本数据包 // 例如: printf("Received: %s\n", packet); } } // 其他任务... } } 在你给我的以上代码中,printf("Received: %s\n", packet);是错误的,packet不是字符型数组,我想要将packet中的hex格式译码成为字符型,请你做更改
06-17
/* line discipline 示例 * * 目标/场景: * - 你的 4G LTE 模组通过 USB 枚举为 ttyACM(x),通常默认使用 N_TTY 行规程(用户态 read/poll 循环) * - 本示例提供一个可加载的内核模块,实现自定义行规程,把收发与缓冲放到内核中: * - 用户态对 /dev/ttyACM0 的 read/write 将走本行规程的 .read/.write * - 驱动收到的下行数据通过 .receive_buf(或 .receive_buf2)进入内核环形队列,用户 read 阻塞等待,避免忙轮询 * - 上行数据通过 .write 根据底层 write_room 进行发送,不足时阻塞等待 write_wakeup * * 仅包含行规程实现(不创建额外字符设备),按需由用户加载并附着到 tty。 * * 重要说明: * - 该实现偏“直通+缓冲”,不做协议解析(比如 AT/PPP 等),你可以在 .receive_buf/.write 中自由插入解析或打包逻辑 * - 行规程编号需要选择一个空闲的 ID,默认使用 29(很多发行版常为空闲),可通过模块参数 ldisc_num=xx 修改 * - 当前系统已注册的行规程可通过:cat /proc/tty/ldiscs 查看 * - 附着到某个 ttyACM 的方法(示例): * 1) insmod n_lteacm_ldisc.ko ldisc_num=29 * 2) 在用户态用 ioctl(TIOCSETD) 设置行规程号码为 29 * 样例 C 代码: * int ldisc = 29; * int fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY); * ioctl(fd, TIOCSETD, &ldisc); * 3) 之后对该 fd 的 read/write 将走本行规程;poll/epoll 也可用 * - 卸载模块前,应先确保所有使用该行规程的 tty 已切回其它行规程(例如 N_TTY),否则 tty_unregister_ldisc 会返回 -EBUSY * * 兼容性: * - 主要针对 Linux 4.14+ ~ 6.x * - 不同内核版本 .receive_buf 与 .receive_buf2 原型略有差异,下面做了简单版本判断 * * 调试: * - dmesg 中会打印关键日志 * - 可以通过模块参数开启更详细日志:debug=1 */ #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/tty.h> #include <linux/tty_driver.h> #include <linux/tty_ldisc.h> #include <linux/kfifo.h> #include <linux/wait.h> #include <linux/uaccess.h> #include <linux/poll.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/version.h> #include <linux/sockios.h> #include "asm/string.h" #include "linux/bpf.h" #include "lte_driver.h" #define CLOUD_STATUS_CLIENT_INFO_PATH "/cloud_status/client_info" #define DMS_MSG_RESERVED 0x20 /* [1, 32]为系统保留消息,不允许用户使用; */ #define MSGID_GLOBAL_BASE (DMS_MSG_RESERVED + 1) #define DMS_MSG_LOCAL_BASE 0x5001 #define CAP_MID_BASE 0x7000 /* 为避免冲突,CAP子系统消息编码从0x7000开始。 */ #define NSD_MID_BASE 0x5001 #define CLOUD_SDK_MSG_ID (NSD_MID_BASE + 9) #define DEV_SERVICE_TOKEN_UPDATE_MSG_ID (NSD_MID_BASE + 29) #define VALIDATE_TOKEN_UPDATE_MSG_ID (NSD_MID_BASE + 28) #define BC_RING_WIFI_PUSH_MSG_ID (CAP_MID_BASE + 118) /* wifi事件推送消息 */ #define LOW_POWER_CLOUD_MSG_IN_MID (MSGID_GLOBAL_BASE + 41) /* 基础云相关消息 */ #define LTE_DRIVER_MSG_ID (MSGID_GLOBAL_BASE + 128) /* lte driver msg */ #define DMS_MSG_IS_GLOBAL(mid) (((mid) > DMS_MSG_RESERVED) && ((mid) < DMS_MSG_LOCAL_BASE)) #define SHARD_MSG_LEN (8 * 1024) #define OUT 1 #define IN 0 /* 模块参数:行规程编号、接收缓冲大小、是否打印调试日志 */ static int ldisc_num = 29; /* 默认 29,可通过 insmod n_lteacm_ldisc.ko ldisc_num=xx 指定 */ module_param(ldisc_num, int, 0444); MODULE_PARM_DESC(ldisc_num, "Line discipline number to register (check /proc/tty/ldiscs)"); static int rx_buf_kb = 4; /* 接收缓冲区大小(KB) */ module_param(rx_buf_kb, int, 0644); MODULE_PARM_DESC(rx_buf_kb, "RX ring buffer size in KB (default 64KB)"); static int event_rx_buf_cnt = 4; /* event 事件处理队列 */ module_param(event_rx_buf_cnt, int, 0644); MODULE_PARM_DESC(event_rx_buf_cnt, "IO_BUF_T.cmd_type == BC_CMD_TYPE_EVENT from lte buffer."); static int debug = 1; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Enable debug logs (0=off, 1=on)"); /* 行规程的私有状态 */ struct lte_ldisc { struct tty_struct *tty; /* 数据接收缓存,收到完整的IO_BUF_T时拷贝数据到 rx_fifo 或 event_rx_fifio */ IO_BUF_T *io_buf; int io_buf_recved; /* 已经缓存到io_buf中的字节数 */ spinlock_t io_buf_lock; /* IO_BUF_T.cmd_type != BC_CMD_TYPE_EVENT 转发到用户空间 */ struct kfifo rx_fifo; /* IO_BUF_T.cmd_type == BC_CMD_TYPE_EVENT 数据缓存 直接由内核转发 */ struct kfifo event_rx_fifo; spinlock_t rx_lock; /* 保护 rx_fifo 的自旋锁 */ spinlock_t event_rx_lock; /* 保护 event_rx_fifo 的自旋锁 */ wait_queue_head_t read_wq; /* 用户空间 read 等待队列 */ /* 发送等待(当底层无空间时等待 write_wakeup) */ wait_queue_head_t write_wq; struct work_struct irq_work; /* 内核对模组事件处理的中断下半部 */ bool rx_overflow_once; /* 仅打印一次溢出提示,避免刷屏 */ /* 状态 */ bool opened; int cloud_msg_local_len; unsigned char *cloud_shard_message; }; /* * \brief __io_buf_avail, 构建一个完整IO_BUF_T还需要的字节数 */ static unsigned int __io_buf_avail(struct lte_ldisc *ld) { unsigned int result_len = 0; if(ld->io_buf_recved < MAX_IOCTL_CMD) { return sizeof(IO_BUF_T); } result_len = MAX_IOCTL_CMD + ld->io_buf->cmd_dlen - ld->io_buf_recved; if(ld->io_buf_recved > ld->io_buf->cmd_dlen + MAX_IOCTL_CMD) { LTE_ERR("[ERROR] dlen:<%d> recv<%d>", ld->io_buf->cmd_dlen, ld->io_buf_recved); return 0; } return MAX_IOCTL_CMD + ld->io_buf->cmd_dlen - ld->io_buf_recved; } static int __io_buf_size(struct lte_ldisc *ld) { return ld->io_buf_recved; } /* * \param dir, 1: out, 0: in * * */ static void print_hex(const unsigned char *data, int len, int dir) { int i = 0; if(NULL == data || 0 == debug) { return; } if(dir) { LTE_INFO("<<["); } else { LTE_INFO(">>["); } for(i = 0; i < len; ++i) { if((i % 10) == 0) { printk(KERN_INFO "\n"); } if (data[i] >= 0x20 && data[i] <= 0x7E) { // 可打印字符,直接显示字符 printk(KERN_CONT "%c ", data[i]); } else { // 不可打印字符,显示十六进制 printk(KERN_CONT "%02x ", data[i]); } } LTE_INFO("]"); } /* 工具函数:安全获取/设置 tty->disc_data */ static inline struct lte_ldisc *ldisc_get(struct tty_struct *tty) { return tty ? (struct lte_ldisc *)tty->disc_data : NULL; } static inline void ldisc_set(struct tty_struct *tty, struct lte_ldisc *ld) { if (tty) tty->disc_data = ld; } static void lte_ldisc_close(struct tty_struct *tty) { struct lte_ldisc *ld = ldisc_get(tty); if (!ld) return; ld->opened = false; /* 唤醒可能阻塞的读写 */ wake_up_interruptible_all(&ld->read_wq); wake_up_interruptible_all(&ld->write_wq); /* 释放 FIFO */ kfifo_free(&ld->rx_fifo); kfifo_free(&ld->event_rx_fifo); /* 释放 接收缓存 */ kfree(ld->io_buf); kfree(ld->cloud_shard_message); ldisc_set(tty, NULL); kfree(ld); LTE_INFO("closed on %s\n", tty ? tty_name(tty) : "(null)"); } static int lte_ldisc_hangup(struct tty_struct *tty) { /* 按惯例等价于 close,TTY 层会确保序列 */ lte_ldisc_close(tty); LTE_INFO("hangup on %s\n", tty ? tty_name(tty) : "(null)"); return 0; } /* 注意:底层驱动/软中断调用,务必使用不可睡眠的同步原语(自旋锁等) */ static void lte_driver_recv_irq(struct tty_struct *tty, const unsigned char *data, char *fp, int count) { struct lte_ldisc *ld = NULL; unsigned int need_notify = 0; /* 是否通知应用程序 */ unsigned int need_schedule = 0; /* 是否调度中断下半部 */ unsigned int avail = 0; /* IO_BUF所需空间 */ unsigned int kavail = 0; /* FIFO剩余空间 */ unsigned long io_buf_irqf = 0; unsigned int io_buf_remain = 0; if(NULL == tty) { LTE_INFO("tty is null."); return; } ld = ldisc_get(tty); LTE_INFO("<<========================="); if (!ld || !ld->opened || count <= 0 || !data) { LTE_ERR("param check fail."); return; } spin_lock_irqsave(&ld->io_buf_lock, io_buf_irqf); avail = __io_buf_avail(ld); if ((unsigned int)count <= avail) /* 未构成一个完整数据包 */ { LTE_INFO("cp to io_buf: (c:<%d> + r:<%d>)/<%u>", count, ld->io_buf_recved,avail); memcpy(ld->io_buf + ld->io_buf_recved, data, count); ld->io_buf_recved += count; } else { if (avail) /* 构成完整的包 */ { LTE_WARN("Some Data May Not Trans By IO_BUF_T Nerver Run Here."); memcpy(ld->io_buf->data + ld->io_buf_recved, data, avail); ld->io_buf_recved += avail; io_buf_remain = count - avail; } } avail = __io_buf_avail(ld); if(0 != avail) /* 未获取到完整的数据包 */ { LTE_INFO("irq once io_buf: recv:<%d>/allNeed:<%u> avail:<%u>", ld->io_buf_recved, MAX_IOCTL_CMD + ld->io_buf->cmd_dlen, avail); spin_unlock_irqrestore(&ld->io_buf_lock, io_buf_irqf); return; } /* 分析数据包,根据cmd_type字段放入不同fifo */ if(BC_CMD_TYPE_EVENT == ld->io_buf->cmd_type) { /* 只有EVENT字段才需要内核处理 */ LTE_INFO("recv BC_CMD_TYPE_EVENT msg dlen:<%d>!!!!!!!!!!", __io_buf_size(ld) - MAX_IOCTL_CMD); print_hex(ld->io_buf->cmd_data, ld->io_buf->cmd_dlen, OUT); spin_lock(&ld->event_rx_lock); kavail = kfifo_avail(&ld->event_rx_fifo); if(kavail >= __io_buf_size(ld)) { LTE_INFO("Msg push to event_rx_fifo"); need_schedule = kfifo_in(&ld->event_rx_fifo, ld->io_buf->data, ld->io_buf_recved); } else { LTE_WARN("event_rx_fifo size need bigger, data overflow, this package may drop."); } spin_unlock(&ld->event_rx_lock); } else { LTE_INFO("recv msg<%d> len:<%d>", ld->io_buf->cmd_type, __io_buf_size(ld)); print_hex(ld->io_buf->cmd_data, ld->io_buf->cmd_dlen, OUT); /* 通知应用程序收包 */ spin_lock(&ld->rx_lock); kavail = kfifo_avail(&ld->rx_fifo); if(kavail >= __io_buf_size(ld)) { LTE_INFO("Msg push to rx_fifo"); need_notify = kfifo_in(&ld->rx_fifo, ld->io_buf->data, ld->io_buf_recved); } else { LTE_WARN("rx_fifo size need bigger, data overflow, this package may drop."); } /* 更新 receive_room,给驱动一个“还剩多少余量”的提示 */ tty->receive_room = kfifo_avail(&ld->rx_fifo); spin_unlock(&ld->rx_lock); } memset(ld->io_buf->data, 0, sizeof(IO_BUF_T)); ld->io_buf_recved = 0; if(io_buf_remain > 0) { memcpy(ld->io_buf->data, data + count - io_buf_remain, io_buf_remain); ld->io_buf_recved = io_buf_remain; } spin_unlock_irqrestore(&ld->io_buf_lock, io_buf_irqf); /* 通知等待进程 */ if (need_notify) { wake_up_interruptible(&ld->read_wq); } /* 调度工作队列 */ if (need_schedule) { schedule_work(&ld->irq_work); } } /* ========== 行规程回调:写可用通知 write_wakeup(底层有空间时调用) ========== */ static void lte_ldisc_write_wakeup(struct tty_struct *tty) { struct lte_ldisc *ld = ldisc_get(tty); if (!ld || !ld->opened) return; wake_up_interruptible(&ld->write_wq); } extern uint32_t msg_send(uint32_t mid, uint8_t *mbuf, uint32_t mlen); /* * \brief lte_msg_send, if(mid > DMS_MSG_RESERVED && mid < DMS_MSG_LOCAL_BASE) * Send directly. * else * Send LTE_DRIVER_MSG_ID msg. */ static uint32_t lte_msg_send(uint32_t mid, uint8_t *mbuf, uint32_t mlen) { LTE_DRIVER_MSG msg; if(DMS_MSG_IS_GLOBAL(mid)) { LTE_INFO("Send global msg:<%u>, len:<%u>", mid, mlen); return msg_send(mid, mbuf, mlen); } msg.mid = mid; msg.mbuf = mbuf; msg.mlen = mlen; LTE_INFO("Send LTE_DRIVER_MSG:<%u>, len:<%u>", mid, mlen); return msg_send(LTE_DRIVER_MSG_ID, (uint8_t*)&msg, sizeof(LTE_DRIVER_MSG)); } static int send_to_mqtt_proxy(uint8_t *payload, int payload_len) { if (payload == NULL){ return -1; } return lte_msg_send(LOW_POWER_CLOUD_MSG_IN_MID, (uint8_t *)payload, payload_len); } static void broadcast_cloud_connect_status(int conn_status, int last_conn_status) { CLOUD_SDK_MSG conn_status_msg = {0}; memset(&conn_status_msg, 0, sizeof(conn_status_msg)); conn_status_msg.conn_status = conn_status > 0 ? 1 : 0; conn_status_msg.last_conn_status = last_conn_status; lte_msg_send(CLOUD_SDK_MSG_ID, (u8 *)&conn_status_msg, sizeof(conn_status_msg)); return; } static void lte_ioctl_cb(struct lte_ldisc *ld, IO_BUF_T *cmd_buf) { static unsigned char piece = 0; static unsigned char shard_id = 0; if(NULL == ld || NULL == cmd_buf) { return; } switch (cmd_buf->cmd_type) { case BC_CMD_TYPE_PUBLISH: case BC_CMD_TYPE_GET: case BC_CMD_TYPE_SET: case BC_CMD_TYPE_ACK: LTE_WARN("Message:<%d> distribution error.", cmd_buf->cmd_type); break; case BC_CMD_TYPE_EVENT: LTE_INFO("recv event name:%d, dlen:%d\n", cmd_buf->cmd_name, cmd_buf->cmd_dlen); print_hex(cmd_buf->cmd_data, cmd_buf->cmd_dlen, OUT); switch(cmd_buf->cmd_name) { case BC_EVENT_CLOUD_CONNECT: LTE_INFO(">>>>>>>>>>>>>>>>>> connect cloud connect <<<<<<<<<<<<<<<<<<\n"); broadcast_cloud_connect_status(1, -1); break; case BC_EVENT_CLOUD_DISCONNECT: broadcast_cloud_connect_status(0, -1); break; case BC_EVENT_VALIDATE_TOKEN_UPDATE: lte_msg_send(VALIDATE_TOKEN_UPDATE_MSG_ID, NULL, 0); break; case BC_EVENT_DEV_TOKEN_UPDATE: lte_msg_send(DEV_SERVICE_TOKEN_UPDATE_MSG_ID, NULL, 0); break; case BC_EVENT_IOT_CHIP_LOG: LTE_INFO("SHIP2LOG %s\n", cmd_buf->cmd_data + 1); break; case BC_EVENT_RING_MSG: lte_msg_send(BC_RING_WIFI_PUSH_MSG_ID, cmd_buf->cmd_data + 1, cmd_buf->cmd_dlen - 1); break; #ifdef BATTERY_STATISTIC_SUPPORT case BC_EVENT_BAT_DATA_PREPARE: LTE_INFO("date ok,get bat_stat_data"); send_bat_stat_data(); break; #endif case BC_EVENT_CLOUD_MESSAGE: // cmd_data首字节是事件计数,实际长度是cmd_dlen - 1 LTE_ERR("CLOUD MSG EVENT, len=%d\n", cmd_buf->cmd_dlen - 1); if (cmd_buf->cmd_dlen - 1 < (sizeof(cmd_buf->cmd_data) - 1)) { cmd_buf->cmd_data[cmd_buf->cmd_dlen] = 0; send_to_mqtt_proxy(&cmd_buf->cmd_data[1], cmd_buf->cmd_dlen); } else { LTE_ERR("buf->cmd_dlen too long:%d", cmd_buf->cmd_dlen); send_to_mqtt_proxy(&cmd_buf->cmd_data[1], cmd_buf->cmd_dlen - 1); } break; // TODO: 补充其他事件处理 case BC_EVENT_CLOUD_MESSAGE_PORTION: if (piece == 0) { shard_id = cmd_buf->cmd_data[2]; } if ((piece == cmd_buf->cmd_data[1]) && (ld->cloud_msg_local_len + cmd_buf->cmd_dlen - 3 <= SHARD_MSG_LEN) && (shard_id == cmd_buf->cmd_data[2])) { memcpy(ld->cloud_shard_message + ld->cloud_msg_local_len, &cmd_buf->cmd_data[3], cmd_buf->cmd_dlen - 3); ld->cloud_msg_local_len += cmd_buf->cmd_dlen - 3; piece++; } else { piece = 0; ld->cloud_msg_local_len = 0; memset(ld->cloud_shard_message, 0, SHARD_MSG_LEN); } break; case BC_EVENT_CLOUD_MESSAGE_FINAL: if ((piece == cmd_buf->cmd_data[1]) && (ld->cloud_msg_local_len + cmd_buf->cmd_dlen - 2 <= SHARD_MSG_LEN) && (shard_id == cmd_buf->cmd_data[2])) { memcpy(ld->cloud_shard_message + ld->cloud_msg_local_len, &cmd_buf->cmd_data[3], cmd_buf->cmd_dlen - 3); ld->cloud_msg_local_len += cmd_buf->cmd_dlen - 3; send_to_mqtt_proxy(ld->cloud_shard_message, ld->cloud_msg_local_len); } piece = 0; ld->cloud_msg_local_len = 0; memset(ld->cloud_shard_message, 0, SHARD_MSG_LEN); break; case BC_EVENT_WIFI_WATCHDOG: LTE_INFO("[CB]WIFI WATCHDOG EVENT :%d\n", cmd_buf->cmd_data[1]); //add wdt? break; default: break; } break; default: LTE_ERR("unknown type:%d cmd:%d\n", cmd_buf->cmd_type, cmd_buf->cmd_name); break; } } static void irq_work_handler(struct work_struct *work) { struct lte_ldisc *ld = container_of(work, struct lte_ldisc, irq_work); unsigned long event_rx_buf_irqf = 0; int fifo_len = 0, read_len; IO_BUF_T io_buf; memset(&io_buf, 0, sizeof(IO_BUF_T)); LTE_INFO("handler irq"); spin_lock_irqsave(&ld->event_rx_lock, event_rx_buf_irqf); fifo_len = kfifo_len(&ld->event_rx_fifo); if(0 == fifo_len || fifo_len < MAX_IOCTL_CMD) { LTE_WARN("event_rx_fifo empty but wake up handler."); return; } read_len = kfifo_out(&ld->event_rx_fifo, &io_buf.data, MAX_IOCTL_CMD); if(io_buf.cmd_dlen > kfifo_len(&ld->event_rx_fifo)) { LTE_WARN("event_rx_fifo data unparse fail."); kfifo_reset(&ld->event_rx_fifo); return; } kfifo_out(&ld->event_rx_fifo, &io_buf.cmd_data, io_buf.cmd_dlen); spin_unlock_irqrestore(&ld->event_rx_lock, event_rx_buf_irqf); /* 开始协议解析部分 */ lte_ioctl_cb(ld, &io_buf); } static ssize_t lte_ioctl_read(struct tty_struct *tty, unsigned char __user *buf) { struct lte_ldisc *ld = ldisc_get(tty); unsigned int copied_total = 0; IO_BUF_T cmd_header; unsigned int fifo_len = 0; unsigned long irqf = 0; int ret = 0; if (!ld || !ld->opened) { LTE_ERR("param check fail."); return -EIO; } LTE_INFO("read data from ioctl cb."); spin_lock_irqsave(&ld->rx_lock, irqf); fifo_len = kfifo_len(&ld->rx_fifo); if(fifo_len < MAX_IOCTL_CMD) { spin_unlock_irqrestore(&ld->rx_lock, irqf); /* 阻塞等待 receive_buf 唤醒,期间可被信号中断 */ ret = wait_event_interruptible(ld->read_wq, ({ unsigned int l; unsigned long f; spin_lock_irqsave(&ld->rx_lock, f); l = kfifo_len(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, f); l >= MAX_IOCTL_CMD || !ld->opened; })); if (ret) return -1; if (!ld->opened) { return -EIO; } spin_lock_irqsave(&ld->rx_lock, irqf); } fifo_len = kfifo_len(&ld->rx_fifo); if(fifo_len < MAX_IOCTL_CMD) { spin_unlock_irqrestore(&ld->rx_lock, irqf); LTE_ERR("False wake-up"); return -1; } memset(&cmd_header, 0, sizeof(IO_BUF_T)); kfifo_out_peek(&ld->rx_fifo, cmd_header.data, MAX_IOCTL_CMD); if(fifo_len < cmd_header.cmd_dlen + MAX_IOCTL_CMD) { spin_unlock_irqrestore(&ld->rx_lock, irqf); LTE_ERR("False wake-up"); return -1; } kfifo_out(&ld->rx_fifo, cmd_header.data, MAX_IOCTL_CMD + cmd_header.cmd_dlen); copy_to_user(buf, cmd_header.data, MAX_IOCTL_CMD + cmd_header.cmd_dlen); tty->receive_room = kfifo_avail(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, irqf); LTE_INFO("read <%d> bytes success.", MAX_IOCTL_CMD + cmd_header.cmd_dlen); return copied_total; } /* ========== 行规程回调:用户态 read/write/poll ========== */ static ssize_t lte_ldisc_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr, void **cookie, unsigned long offset) { struct lte_ldisc *ld = ldisc_get(tty); ssize_t copied_total = 0; int ret = 0; LTE_ERR("Warning This method should not be Called."); if (!ld || !ld->opened) { LTE_ERR("param check fail."); return -EIO; } if (nr == 0) { return 0; } /* 循环直到满足用户请求或遇到阻塞条件 */ while (nr) { size_t to_copy; unsigned int fifo_len; unsigned long irqf; unsigned char *tmp; /* 尝试从 FIFO 拿数据,如果没有则根据 O_NONBLOCK 决定是否睡眠等待 */ spin_lock_irqsave(&ld->rx_lock, irqf); fifo_len = kfifo_len(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, irqf); if (fifo_len == 0) { /* 若已有部分数据,先返回(避免读到部分就阻塞) */ if (copied_total > 0) break; if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } /* 阻塞等待 receive_buf 唤醒,期间可被信号中断 */ ret = wait_event_interruptible(ld->read_wq, ({ unsigned int l; unsigned long f; spin_lock_irqsave(&ld->rx_lock, f); l = kfifo_len(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, f); l > 0 || !ld->opened; })); if (ret) break; /* -ERESTARTSYS 等,用户态可重试 */ if (!ld->opened) { ret = -EIO; break; } continue; } /* 本次最多读取 nr 与 fifo_len 中较小的数量 */ to_copy = min_t(size_t, nr, fifo_len); /* 为了避免在持有自旋锁时 copy_to_user(可能睡眠),先把数据出队到临时缓冲 */ tmp = kmalloc(to_copy, GFP_KERNEL); if (!tmp) { ret = -ENOMEM; break; } spin_lock_irqsave(&ld->rx_lock, irqf); to_copy = kfifo_out(&ld->rx_fifo, tmp, to_copy); tty->receive_room = kfifo_avail(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, irqf); /* 复制到用户空间 */ memcpy(buf, tmp, to_copy); print_hex(tmp, to_copy, OUT); kfree(tmp); buf += to_copy; nr -= to_copy; copied_total += to_copy; /* 一次读够了,返回 */ if (nr == 0) break; /* FIFO 可能还有数据,继续下一轮;也可能为空,需要等待 */ } /* 若已读出部分数据,优先返回字节数;否则返回错误码 */ return (copied_total > 0) ? copied_total : ret; } static ssize_t lte_ldisc_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr) { struct lte_ldisc *ld = NULL; ssize_t written_total = 0; unsigned char *kbuf = NULL; int ret = 0; if(NULL == tty) { LTE_ERR("tty is null."); return -ENOENT; } ld = ldisc_get(tty); if(NULL == ld) { LTE_ERR("tty is not set lte_ldisc private."); return -1; } if(buf == NULL) { LTE_ERR("user buf is null."); return -1; } LTE_INFO("Call lte_ldisc_write with: nr<%u>", nr); if (!ld || !ld->opened) { LTE_ERR("param check fail."); return -EIO; } if (nr == 0) return 0; kbuf = kmalloc(nr, GFP_KERNEL); if (!kbuf) { LTE_ERR("kbuf malloc error request:<%d> bytes.", nr); return -ENOMEM; } memcpy(kbuf, buf, nr); LTE_INFO("Write Bytes:<%d>", nr); print_hex(kbuf, nr, IN); while (written_total < nr) { int room = 0; int to_send = 0; int sent = 0; /* 查询底层可写空间 */ room = tty_write_room(tty); LTE_INFO("tty_write_room: %d.", room); if (room <= 0) { LTE_WARN("Write Buffer is empty!!!"); /* 若已写出部分,先返回;否则根据是否非阻塞确定是否等待 */ if (written_total > 0) { break; } if (file->f_flags & O_NONBLOCK) { LTE_INFO("O_NONBLOCK EAGAIN."); ret = -EAGAIN; break; } /* 阻塞等待底层 write_wakeup */ ret = wait_event_interruptible(ld->write_wq, ({ int r = tty_write_room(tty); r > 0 || !ld->opened; })); if (ret) break; if (!ld->opened) { LTE_ERR("Write but tty is closed."); ret = -EIO; break; } continue; } /* 按底层空间发送 */ to_send = min_t(int, room, (int)(nr - written_total)); sent = tty->ops->write(tty, kbuf + written_total, to_send); if (sent < 0) { LTE_ERR("tty write fail with:<%d>", ret); ret = sent; break; } else if (sent == 0) { LTE_WARN("tty write return 0"); /* 某些驱动可能短暂返回 0,避免忙等稍作让步或等待 */ if (file->f_flags & O_NONBLOCK) { ret = (written_total > 0) ? written_total : -EAGAIN; break; } /* 轻微让步,或等待 write_wakeup */ schedule_timeout_interruptible(msecs_to_jiffies(5)); continue; } written_total += sent; } kfree(kbuf); LTE_INFO("write finished, write total:<%d> ret:<%d>", written_total, ret); return (written_total > 0) ? written_total : ret; } static __poll_t lte_ldisc_poll(struct tty_struct *tty, struct file *file, poll_table *wait) { struct lte_ldisc *ld = ldisc_get(tty); __poll_t mask = 0; unsigned long irqf; unsigned int fifo_len; if (!ld || !ld->opened) return EPOLLERR | EPOLLHUP; /* 将等待队列加入到轮询表中,以支持 select/poll/epoll */ poll_wait(file, &ld->read_wq, wait); poll_wait(file, &ld->write_wq, wait); /* 可读? */ spin_lock_irqsave(&ld->rx_lock, irqf); fifo_len = kfifo_len(&ld->rx_fifo); spin_unlock_irqrestore(&ld->rx_lock, irqf); if (fifo_len > 0) mask |= EPOLLIN | EPOLLRDNORM; /* 可写? */ if (tty_write_room(tty) > 0) { mask |= EPOLLOUT | EPOLLWRNORM; } return mask; } static int lte_ldisc_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { int ret = -1; IO_BUF_T tmp_buffer; /* 透传未知命令给用户态(返回 -ENOIOCTLCMD 让 TTY 栈尝试其它处理) */ LTE_INFO("lte_ldisc_ioctl called cmd:<%u>", cmd); switch(cmd) { case SIOCDEVPRIVATE: memset(&tmp_buffer, 0, sizeof(IO_BUF_T)); if(copy_from_user(&tmp_buffer.data, (void*)arg, MAX_IOCTL_CMD)) { LTE_ERR("ioctl user buffer can't access."); break; } if(copy_from_user(&tmp_buffer.cmd_data, (char*)arg + MAX_IOCTL_CMD, tmp_buffer.cmd_dlen)) { LTE_ERR("ioctl user buffer can't access."); break; } LTE_INFO("receive ioctl cmd_type:<%d> cmd_name:<%d> cmd_length:<%u> cmd_data:", tmp_buffer.cmd_type, tmp_buffer.cmd_name, tmp_buffer.cmd_dlen); ret = lte_ldisc_write(tty, file, (unsigned char*)&tmp_buffer.data, tmp_buffer.cmd_dlen + MAX_IOCTL_CMD); break; default: LTE_INFO("lte_ldisc not support cmd:<%u>.", cmd); ret = -ENOIOCTLCMD; break; } ret = lte_ioctl_read(tty, (void*)arg); LTE_INFO("lte_ioctl_read ret:<%d>", ret); return ret >= 0 ? 0 : -1; } static int lte_ldisc_open(struct tty_struct *tty) { struct lte_ldisc *ld = NULL; int ret = -EINVAL; LTE_INFO("open tty <%s>", tty_name(tty)); if (!tty) { LTE_ERR("tty is null."); return -EINVAL; } ld = kzalloc(sizeof(*ld), GFP_KERNEL); if (!ld) { LTE_ERR("kzalloc empty."); return -ENOMEM; } /* 分配接收缓存 */ ld->io_buf = kzalloc(sizeof(IO_BUF_T), GFP_KERNEL); if(NULL == ld->io_buf) { LTE_ERR("kzalloc io_buf empty."); goto err_rx_fifo; } ld->tty = tty; spin_lock_init(&ld->rx_lock); spin_lock_init(&ld->event_rx_lock); spin_lock_init(&ld->io_buf_lock); init_waitqueue_head(&ld->read_wq); init_waitqueue_head(&ld->write_wq); INIT_WORK(&ld->irq_work, irq_work_handler); /* 分配接收环形缓冲区 */ ret = kfifo_alloc(&ld->rx_fifo, rx_buf_kb * 1024, GFP_KERNEL); if (ret) { LTE_ERR("kfifo_alloc(%dKB) failed: %d\n", rx_buf_kb, ret); goto err_rx_fifo; } ret = kfifo_alloc(&ld->event_rx_fifo, event_rx_buf_cnt * sizeof(IO_BUF_T), GFP_KERNEL); if (ret) { LTE_ERR("kfifo_alloc(%dKB) failed: %d\n", event_rx_buf_cnt * sizeof(IO_BUF_T), ret); goto err_event_tx_fifo; } ld->cloud_shard_message = kzalloc(SHARD_MSG_LEN, GFP_KERNEL); if(!ld->cloud_shard_message) { LTE_ERR("alloc cloud_shard_message fail."); goto err_cloud_shard_message; } /* 告诉底层驱动我们目前能接收的空间 */ tty->receive_room = kfifo_avail(&ld->rx_fifo); ldisc_set(tty, ld); ld->opened = true; LTE_INFO("opened on %s (RX %dKB), (TX %dKB), ldisc=%d\n", tty_name(tty), rx_buf_kb, event_rx_buf_cnt * sizeof(IO_BUF_T), ldisc_num); return 0; err_cloud_shard_message: kfifo_free(&ld->event_rx_fifo); err_event_tx_fifo: kfifo_free(&ld->rx_fifo); err_rx_fifo: kfree(ld); ld = NULL; return ret; } /* ========== 行规程 ops 描述符 ========== */ static struct tty_ldisc_ops lte_ldisc_ops = { .owner = THIS_MODULE, .name = "n_lteacm", .open = lte_ldisc_open, .close = lte_ldisc_close, .hangup = lte_ldisc_hangup, .read = lte_ldisc_read, .write = lte_ldisc_write, .poll = lte_ldisc_poll, .ioctl = lte_ldisc_ioctl, .receive_buf = lte_driver_recv_irq, .write_wakeup = lte_ldisc_write_wakeup, /* 暂时不处理这些接口 * .set_termios = NULL, * .flush_buffer = NULL, * .throttle = NULL, * .unthrottle = NULL, */ }; /* ========== 模块加载/卸载 ========== */ static int __init lte_ldisc_init(void) { int ret = -EINVAL; if (ldisc_num < 0 || ldisc_num >= NR_LDISCS) { LTE_ERR("invalid ldisc_num=%d, valid range [0, %d)\n", ldisc_num, NR_LDISCS); return -EINVAL; } ret = tty_register_ldisc(ldisc_num, &lte_ldisc_ops); if (ret) { LTE_ERR("tty_register_ldisc(%d) failed: %d\n", ldisc_num, ret); return ret; } LTE_INFO("registered ldisc=%d, RX=%dKB, debug=%d, version=%s\n", ldisc_num, rx_buf_kb, debug, DRV_VERSION); LTE_INFO("Attach with TIOCSETD(%d) on your /dev/ttyACM*\n", ldisc_num); return 0; } static void __exit lte_ldisc_exit(void) { int ret = 0; ret = tty_unregister_ldisc(ldisc_num); if (ret) { /* 若返回 -EBUSY,说明仍有 tty 使用该行规程,需先切回其它行规程再卸载模块 */ LTE_ERR("tty_unregister_ldisc(%d) failed: %d (busy?)\n", ldisc_num, ret); /* 通常此时 rmmod 会失败,因为模块被引用;用户需先 detach 然后重试卸载 */ } else { LTE_INFO("unregistered ldisc=%d\n", ldisc_num); } } module_init(lte_ldisc_init); module_exit(lte_ldisc_exit); MODULE_AUTHOR("liujiarui <liujiarui@tp-link.com.hk>"); MODULE_DESCRIPTION(DRV_DESC); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); 这段代码中可能到只Kernel panic的地方
09-05
STATUS write_data(LAYOUT_TP_FS_VER ver, U8 disk_id, const char * path, WRITE_ZONE_PARAM* p_write_param ) { S32 fd = INVALID_FD; int ret = OK; int j; return_val_if_fail(STG_DBG_ERROR, NULL != p_write_param, ERROR); U8 data_type = p_write_param->p_layout_in->data_type; S32 zone_id = p_write_param->p_zone->zone_id; S8 blk_id = p_write_param->p_zone->blk_id; S8* p_data = NULL; U32 data_len = 0; U32 offset = ALIGN(p_write_param->offset, g_lay_info[disk_id]->data_align_size); #ifdef ENABLE_PWRITEV struct iovec data_iov[IOV_CNT_MAX] = {{0}}; int iovcnt = 0; #endif #if FD_WITH_ZONE fd = p_write_param->fd; #else return_val_if_fail(STG_DBG_ERROR, OK == (ret = open_zone_file(ver, path, zone_id, &fd)),ret); #endif return_val_if_fail(STG_DBG_ERROR, INVALID_FD != fd, ERROR); if(STG_DATA_TYPE_PIC == data_type) { offset += (BLOCK_CNT_IN_ZONE*blk_id); } if (OK != (ret = check_zone_file_size(ver, disk_id, path,zone_id, ZONE_SIZE + 1))) { #if FD_WITH_ZONE #else layout_fs_close(ver, fd); #endif STG_ERROR( "zone:%d size error\r\n",zone_id); return ret; } #ifdef DISK_WRITER_THREAD int pack_id = disk_pack[disk_id]; struct writer_manager *p_wm; struct io_buffer_manager *p_io_bm; p_wm = &(wm[pack_id]); p_io_bm = p_wm->io_bm; pthread_mutex_lock(&(p_wm->fill_mutex)); j = 0; while (j < p_write_param->p_layout_in->in_cnt) { int io_buf_wnum = p_wm->io_buf_wnum; pthread_mutex_lock(&(p_io_bm[io_buf_wnum].mutex)); while (p_io_bm[io_buf_wnum].status) { pthread_cond_wait( &(p_io_bm[io_buf_wnum].empty_cond), &(p_io_bm[io_buf_wnum].mutex)); } p_io_bm[io_buf_wnum].z_offset = offset; p_io_bm[io_buf_wnum].len = 0; p_io_bm[io_buf_wnum].disk_id = disk_id; p_io_bm[io_buf_wnum].fd = fd; memset(p_io_bm[io_buf_wnum].pdata, 0, p_io_bm[io_buf_wnum].total_len); while (j < p_write_param->p_layout_in->in_cnt) { data_len = ALIGN(p_write_param->p_layout_in->data_len[j], g_lay_info[disk_id]->data_align_size); p_data = p_write_param->p_layout_in->p_data[j]; if (offset - p_io_bm[io_buf_wnum].z_offset + data_len > p_io_bm[io_buf_wnum].total_len) break; p_io_bm[io_buf_wnum].len = offset - p_io_bm[io_buf_wnum].z_offset + data_len; #ifdef RECORD_MEMORY_POOL_SIZE if (p_write_param->p_layout_in->p_flag_mempool[j]) { memory_manager_get_content( p_io_bm[io_buf_wnum].pdata + (offset - p_io_bm[io_buf_wnum].z_offset), p_write_param->p_layout_in->data_len[j], p_write_param->p_layout_in->p_mempool_block_list[j]); } else #endif { memcpy(p_io_bm[io_buf_wnum].pdata + (offset - p_io_bm[io_buf_wnum].z_offset), p_data, p_write_param->p_layout_in->data_len[j]); } offset += data_len; j++; } p_io_bm[io_buf_wnum].status = 1; pthread_cond_signal(&(p_io_bm[io_buf_wnum].fill_cond)); pthread_mutex_unlock(&(p_io_bm[io_buf_wnum].mutex)); p_wm->io_buf_wnum = (io_buf_wnum + 1) % DISK_WRITER_THREAD_BUFFER_CNT; } pthread_mutex_unlock(&wm[disk_pack[disk_id]].fill_mutex);解释这段代码
09-18
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值