转:Receiving Module Data Flow .

本文概述了基本的收货流程,包括针对库存目的地、批次控制物品及序列号控制物品的采购订单收货等场景,并提供了RCV与INV模块表的缩写对照表,有助于理解相关业务操作。

Basic Data Flow in Receiving


PO Receipt for Inventory destination


PO Receipt for lot controlled items


PO Receipt for serial controlled items


Interorg Transfer Receipt – In transit Shipment


Interorg Transfer Receipt – In transit Shipment for lot controlled items

Interorg Transfer Receipt – In transit Shipment for serial controlled items

Internal Sales Order – In transit Shipment



Abbr.

RCV模块表的缩写对照表
RHI - Rcv_Headers_Interface
RTI – Rcv_Transactions_Interface
RTP – Receiving Transaction Processor
RSH – Rcv_Shipment_Headers
RSL – Rcv_Shipment_Lines
RT  – Rcv_Transactions
RLT – Rcv_Lot_Transactions
RLS – Rcv_Lots_Supply
RSS – Rcv_Serials_Supply


INV模块表的缩写对照表
MTLI – Mtl_Transactions_Lot_Interface
MSNI – Mtl_Serial_Numbers_Interface
MTLT – Mtl_Transaction_Lots_Temp
MSNT – Mtl_Serial_Number_Temp
MTLN – Mtl_Transaction_Lot_Numbers
MUT  – Mtl_Unit_Transactions
MSN  – Mtl_Serial_Numbers
MMT  – Mtl_Material_Transactions
MMTT – Mtl_Material_Transactions_Temp

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/12122734/viewspace-759856/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/12122734/viewspace-759856/

### Basic Usage Basic usage is largely derived from package `@ui-tars/sdk`, here's a basic example of using the SDK: > Note: Using `nut-js`(cross-platform computer control tool) as the operator, you can also use or customize other operators. NutJS operator that supports common desktop automation actions: > - Mouse actions: click, double click, right click, drag, hover > - Keyboard input: typing, hotkeys > - Scrolling > - Screenshot capture ```ts import { GUIAgent } from '@ui-tars/sdk'; import { NutJSOperator } from '@ui-tars/operator-nut-js'; const guiAgent = new GUIAgent({ model: { baseURL: config.baseURL, apiKey: config.apiKey, model: config.model, }, operator: new NutJSOperator(), onData: ({ data }) => { console.log(data) }, onError: ({ data, error }) => { console.error(error, data); }, }); await guiAgent.run('send "hello world" to x.com'); ``` ### Handling Abort Signals You can abort the agent by passing a `AbortSignal` to the GUIAgent `signal` option. ```ts const abortController = new AbortController(); const guiAgent = new GUIAgent({ // ... other config signal: abortController.signal, }); // ctrl/cmd + c to cancel operation process.on('SIGINT', () => { abortController.abort(); }); ``` ## Configuration Options The `GUIAgent` constructor accepts the following configuration options: - `model`: Model configuration(OpenAI-compatible API) or custom model instance - `baseURL`: API endpoint URL - `apiKey`: API authentication key - `model`: Model name to use - more options see [OpenAI API](https://platform.openai.com/docs/guides/vision/uploading-base-64-encoded-images) - `operator`: Instance of an operator class that implements the required interface - `signal`: AbortController signal for canceling operations - `onData`: Callback for receiving agent data/status updates - `data.conversations` is an array of objects, **IMPORTANT: is delta, not the whole conversation history**, each object contains: - `from`: The role of the message, it can be one of the following: - `human`: Human message - `gpt`: Agent response - `screenshotBase64`: Screenshot base64 - `value`: The content of the message - `data.status` is the current status of the agent, it can be one of the following: - `StatusEnum.INIT`: Initial state - `StatusEnum.RUNNING`: Agent is actively executing - `StatusEnum.END`: Operation completed - `StatusEnum.MAX_LOOP`: Maximum loop count reached - `onError`: Callback for error handling - `systemPrompt`: Optional custom system prompt - `maxLoopCount`: Maximum number of interaction loops (default: 25) ### Status flow ```mermaid stateDiagram-v2 [*] --> INIT INIT --> RUNNING RUNNING --> RUNNING: Execute Actions RUNNING --> END: Task Complete RUNNING --> MAX_LOOP: Loop Limit Reached END --> [*] MAX_LOOP --> [*] ``` ## Advanced Usage ### Operator Interface When implementing a custom operator, you need to implement two core methods: `screenshot()` and `execute()`. #### Initialize `npm init` to create a new operator package, configuration is as follows: ```json { "name": "your-operator-tool", "version": "1.0.0", "main": "./dist/index.js", "module": "./dist/index.mjs", "types": "./dist/index.d.ts", "scripts": { "dev": "rslib build --watch", "prepare": "npm run build", "build": "rsbuild", "test": "vitest" }, "files": [ "dist" ], "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" }, "dependencies": { "jimp": "^1.6.0" }, "peerDependencies": { "@ui-tars/sdk": "^1.2.0-beta.17" }, "devDependencies": { "@ui-tars/sdk": "^1.2.0-beta.17", "@rslib/core": "^0.5.4", "typescript": "^5.7.2", "vitest": "^3.0.2" } } ``` #### screenshot() This method captures the current screen state and returns a `ScreenshotOutput`: ```typescript interface ScreenshotOutput { // Base64 encoded image string base64: string; // Device pixel ratio (DPR) scaleFactor: number; } ``` #### execute() This method performs actions based on model predictions. It receives an `ExecuteParams` object: ```typescript interface ExecuteParams { /** Raw prediction string from the model */ prediction: string; /** Parsed prediction object */ parsedPrediction: { action_type: string; action_inputs: Record<string, any>; reflection: string | null; thought: string; }; /** Device Physical Resolution */ screenWidth: number; /** Device Physical Resolution */ screenHeight: number; /** Device DPR */ scaleFactor: number; /** model coordinates scaling factor [widthFactor, heightFactor] */ factors: Factors; } ``` Advanced sdk usage is largely derived from package `@ui-tars/sdk/core`, you can create custom operators by extending the base `Operator` class: ```typescript import { Operator, type ScreenshotOutput, type ExecuteParams type ExecuteOutput, } from '@ui-tars/sdk/core'; import { Jimp } from 'jimp'; export class CustomOperator extends Operator { // Define the action spaces and description for UI-TARS System Prompt splice static MANUAL = { ACTION_SPACES: [ 'click(start_box="") # click on the element at the specified coordinates', 'type(content="") # type the specified content into the current input field', 'scroll(direction="") # scroll the page in the specified direction', 'finished() # finish the task', // ...more_actions ], }; public async screenshot(): Promise<ScreenshotOutput> { // Implement screenshot functionality const base64 = 'base64-encoded-image'; const buffer = Buffer.from(base64, 'base64'); const image = await sharp(buffer).toBuffer(); return { base64: 'base64-encoded-image', scaleFactor: 1 }; } async execute(params: ExecuteParams): Promise<ExecuteOutput> { const { parsedPrediction, screenWidth, screenHeight, scaleFactor } = params; // Implement action execution logic // if click action, get coordinates from parsedPrediction const [startX, startY] = parsedPrediction?.action_inputs?.start_coords || ''; if (parsedPrediction?.action_type === 'finished') { // finish the GUIAgent task return { status: StatusEnum.END }; } } } ``` Required methods: - `screenshot()`: Captures the current screen state - `execute()`: Performs the requested action based on model predictions Optional static properties: - `MANUAL`: Define the action spaces and description for UI-TARS Model understanding - `ACTION_SPACES`: Define the action spaces and description for UI-TARS Model understanding Loaded into `GUIAgent`: ```ts const guiAgent = new GUIAgent({ // ... other config systemPrompt: ` // ... other system prompt ${CustomOperator.MANUAL.ACTION_SPACES.join('\n')} `, operator: new CustomOperator(), }); ``` ### Custom Model Implementation You can implement custom model logic by extending the `UITarsModel` class: ```typescript class CustomUITarsModel extends UITarsModel { constructor(modelConfig: { model: string }) { super(modelConfig); } async invoke(params: any) { // Implement custom model logic return { prediction: 'action description', parsedPredictions: [{ action_type: 'click', action_inputs: { /* ... */ }, reflection: null, thought: 'reasoning' }] }; } } const agent = new GUIAgent({ model: new CustomUITarsModel({ model: 'custom-model' }), // ... other config }); ``` > Note: However, it is not recommended to implement a custom model because it contains a lot of data processing logic (including image transformations, scaling factors, etc.). ### Planning You can combine planning/reasoning models (such as OpenAI-o1, DeepSeek-R1) to implement complex GUIAgent logic for planning, reasoning, and execution: ```ts const guiAgent = new GUIAgent({ // ... other config }); const planningList = await reasoningModel.invoke({ conversations: [ { role: 'user', content: 'buy a ticket from beijing to shanghai', } ] }) /** * [ * 'open chrome', * 'open trip.com', * 'click "search" button', * 'select "beijing" in "from" input', * 'select "shanghai" in "to" input', * 'click "search" button', * ] */ for (const planning of planningList) { await guiAgent.run(planning); } ```
最新发布
08-21
#pragma once #include <zephyr/kernel.h> // 批量发送配置 #define UART_BUF_SIZE 255 extern uint8_t rs485_rx_buf[UART_BUF_SIZE][8]; #define BATCH_SIZE 32 #define MAX_BATCH_TIMEOUT 10 // 秒 typedef struct { int32_t timestamp; // 时间戳 (ms) int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } sensor_data_point_t; typedef struct { sensor_data_point_t data[BATCH_SIZE]; uint16_t count; int64_t start_timestamp; // 批次起始时间 (ms) bool ready; // 批次就绪标志 } sensor_batch_t; typedef struct { float a0; // 常数项系数 float a1; // 一次项系数 float a2; // 二次项系数 float b; // 压力项系数 int32_t ref_temp; // 参考温度 (centi-°C) } temp_comp_coeff_t; extern sensor_batch_t sensor_batch; extern struct k_mutex data_mutex; extern struct k_sem batch_ready_sem; extern sensor_data_point_t sensor_data_rs485;#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/uart.h> #include <string.h> #include "GVL.h" #define LOG_MODULE_NAME rs485_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG); #define RS485_DIR_PIN_DELAY_US 100 #define UART_RX_TIMEOUT_MS 100 #define MAX_RETRIES 3 #define COMMAND_TIMEOUT_MS 500 // 获取设备树节点 #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // 声明设备 static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // 双缓冲结构 static sensor_batch_t tx_buffers[2]; static sensor_batch_t *current_tx_buffer = &tx_buffers[0]; static sensor_batch_t *pending_tx_buffer = &tx_buffers[1]; static bool buffer_ready = false; // RS485发送函数 // static int rs485_send_batch(const sensor_batch_t *batch) // { // if (batch->count == 0) { // return 0; // } // // 切换到发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // // 计算实际数据长度 // size_t data_size = sizeof(sensor_data_point_t) * batch->count; // LOG_INF("Sending batch of %d points (%u bytes)", batch->count, data_size); // // 发送数据 // int retry_count = 0; // int err = -EAGAIN; // while (retry_count < MAX_RETRIES && err != 0) { // err = uart_tx(rs485_uart, (const uint8_t *)batch->data, data_size, SYS_FOREVER_MS); // if (err) { // LOG_ERR("UART TX error (attempt %d): %d", retry_count + 1, err); // retry_count++; // k_msleep(10); // } // } // if (err) { // LOG_ERR("Failed to send after %d attempts", MAX_RETRIES); // } // return err; // } static int rs485_send_batch(const sensor_data_point_t *sensor_data) { // if (batch->count == 0) { // return 0; // } // 切换到发送模式 gpio_pin_set_dt(&direct_pin, 1); k_busy_wait(RS485_DIR_PIN_DELAY_US); // 计算实际数据长度 size_t data_size = sizeof(sensor_data_point_t); LOG_INF("rs485 Sending (%u bytes)", data_size); // 发送数据 int retry_count = 0; int err = -EAGAIN; while (retry_count < MAX_RETRIES && err != 0) { err = uart_tx(rs485_uart, sensor_data, data_size, SYS_FOREVER_MS); if (err) { LOG_ERR("UART TX error (attempt %d): %d", retry_count + 1, err); retry_count++; k_msleep(10); } } if (err) { LOG_ERR("Failed to send after %d attempts", MAX_RETRIES); } return err; } // 处理接收到的命令 static void process_command(const uint8_t *data, size_t len) { if (len < 1) return; // 空命令 switch (data[0]) { case 0x01: // 请求传感器数据 LOG_DBG("Received data request command"); k_sem_give(&batch_ready_sem); break; case 0x02: // 设置采样率 if (len >= 2) { uint16_t new_rate = data[1] << 8 | data[2]; LOG_INF("Setting new sample rate: %d ms", new_rate); // 这里可以添加设置采样率的逻辑 } break; case 0x03: // 设备状态查询 LOG_DBG("Received status query"); // 这里可以添加状态响应逻辑 break; default: LOG_WRN("Unknown command: 0x%02X", data[0]); break; } } // UART接收回调 static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { static uint8_t rx_buffer[128]; static size_t rx_index = 0; static int64_t last_rx_time = 0; switch (evt->type) { case UART_RX_RDY: // 检查是否新数据包 int64_t now = k_uptime_get(); if ((now - last_rx_time) > COMMAND_TIMEOUT_MS || (rx_index + evt->data.rx.len) > sizeof(rx_buffer)) { rx_index = 0; // 重置缓冲区 } // 复制数据到缓冲区 size_t to_copy = MIN(evt->data.rx.len, sizeof(rx_buffer) - rx_index); memcpy(&rx_buffer[rx_index], evt->data.rx.buf, to_copy); rx_index += to_copy; last_rx_time = now; break; case UART_RX_DISABLED: // 处理缓冲区中的数据 if (rx_index > 0) { process_command(rx_buffer, rx_index); rx_index = 0; } // 重新启用接收 uart_rx_enable(rs485_uart, rs485_rx_buf, sizeof(rs485_rx_buf), UART_RX_TIMEOUT_MS); break; case UART_RX_BUF_RELEASED: // 可以在这里释放缓冲区 break; case UART_TX_DONE: LOG_DBG("TX complete"); //发送完成后切换回接收模式 gpio_pin_set_dt(&direct_pin, 0); break; case UART_TX_ABORTED: LOG_WRN("TX aborted"); break; default: break; } } // 初始化RS485模块 static int rs485_init(void) { int ret; // 检查设备是否就绪 if (!device_is_ready(rs485_uart)) { LOG_ERR("UART device not ready"); return -ENODEV; } if (!device_is_ready(direct_pin.port)) { LOG_ERR("GPIO device not ready"); return -ENODEV; } // 配置方向控制引脚 ret = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); if (ret) { LOG_ERR("GPIO config error: %d", ret); return ret; } // 配置UART回调 ret = uart_callback_set(rs485_uart, uart_cb, NULL); if (ret) { LOG_ERR("UART callback set error: %d", ret); return ret; } // 初始化双缓冲 memset(tx_buffers, 0, sizeof(tx_buffers)); // 启用接收 ret = uart_rx_enable(rs485_uart, rs485_rx_buf, sizeof(rs485_rx_buf), UART_RX_TIMEOUT_MS); if (ret) { LOG_ERR("UART RX enable error: %d", ret); return ret; } LOG_INF("RS485 initialized"); return 0; } void rs485_thread(void) { if (rs485_init() != 0) { LOG_ERR("RS485 initialization failed"); return; } LOG_INF("RS485 thread started"); while (1) { // // 等待批次数据就绪信号 // if (k_sem_take(&batch_ready_sem, K_FOREVER) == 0) { // // 安全地获取批次数据 // k_mutex_lock(&data_mutex, K_FOREVER); // // 检查是否有待处理数据 // if (buffer_ready) { // LOG_WRN("Previous buffer not sent, overwriting"); // } // // 复制数据到待发送缓冲区 // *pending_tx_buffer = sensor_batch; // // 重置主批次 // sensor_batch.count = 0; // sensor_batch.start_timestamp = 0; // sensor_batch.ready = false; // // 标记缓冲区就绪 // buffer_ready = true; // k_mutex_unlock(&data_mutex); // } // // 检查是否有数据需要发送 // if (buffer_ready) { // // 交换缓冲区指针 // sensor_batch_t *send_buffer = pending_tx_buffer; // pending_tx_buffer = current_tx_buffer; // current_tx_buffer = send_buffer; // // 发送数据 // rs485_send_batch(send_buffer); // // 重置缓冲区 // send_buffer->count = 0; // buffer_ready = false; // } sensor_data_point_t *send_buffer = &sensor_data_rs485; rs485_send_batch(send_buffer); // 处理超时命令 k_sleep(K_MSEC(1000)); } } K_THREAD_DEFINE(rs485_thread_id, 4096, rs485_thread, NULL, NULL, NULL, 5, 0, 0); rs485发送数据// GVL.h #pragma once #include <zephyr/kernel.h> // 批量发送配置 #define BATCH_SIZE 32 #define MAX_BATCH_TIMEOUT_MS 10000 #define UART_BUF_SIZE 256 #define MEM_POOL_SIZE 8 #define RS485_DIR_PIN_DELAY_US 100 #define UART_RX_TIMEOUT_MS 100 #define MAX_RETRIES 3 #define COMMAND_TIMEOUT_MS 500 #define UART_WAIT_FOR_RX 50000 #define DATA_POINT_SIZE 37 // unified_data_point_t大小(字节) #define MAX_POINTS_PER_PACKET 6 // 每个包最大数据点数(根据MTU计算) typedef struct { int32_t timestamp; // 时间戳 (ms) int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } sensor_data_point_t; // 批处理包头(用于蓝牙传输) typedef struct __attribute__((packed)) { uint16_t item_count; // 批处理中数据点数量 int64_t batch_timestamp; // 批处理开始时间戳 uint32_t data_size; // 数据部分总大小(字节) } batch_header_t; // 统一的数据点结构 typedef struct { int32_t timestamp; // 时间戳 (ms) // 传感器数据 int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) // IMU数据 (来自RS485) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) // 数据来源标识 uint8_t data_source; // 1:本地传感器, 2:RS485设备 } unified_data_point_t; // 蓝牙数据包结构 - 确保每个包包含完整数据点 typedef struct __attribute__((packed)) { uint16_t packet_index; // 包序号 uint16_t total_packets; // 总包数 uint16_t points_in_packet; // 本包数据点数 unified_data_point_t data_points[MAX_POINTS_PER_PACKET]; // 数据点数组 } ble_packet_t; extern struct k_mem_slab uart_tx_pool; extern struct k_mem_slab batch_pool; // 批处理容器 typedef struct { unified_data_point_t data[BATCH_SIZE]; uint16_t count; int64_t start_timestamp; bool ready; } batch_container_t; typedef struct __attribute__((packed)) { int32_t pressure; // 压力 (milli-kPa) int32_t temp; // 温度 (centi-°C) int32_t acc_x; // X加速度 (milli-g) int32_t acc_y; // Y加速度 (milli-g) int32_t acc_z; // Z加速度 (milli-g) int32_t gyro_x; // X陀螺仪 (milli-dps) int32_t gyro_y; // Y陀螺仪 (milli-dps) int32_t gyro_z; // Z陀螺仪 (milli-dps) } rs485_raw_data_t; // 双缓冲批处理 extern batch_container_t data_batches[2]; extern uint8_t active_batch_index; // 同步信号量 extern struct k_sem ble_data_ready_sem; // 自旋锁保护批处理缓冲区 extern struct k_spinlock batch_lock; static double atmospheric_pressure; // #include <zephyr/kernel.h> // #include <zephyr/device.h> // #include <zephyr/devicetree.h> // #include <zephyr/drivers/gpio.h> // #include <zephyr/logging/log.h> // #include <zephyr/drivers/uart.h> // #include "GVL.h" // #define LOG_MODULE_NAME rs485_thread // LOG_MODULE_REGISTER(LOG_MODULE_NAME); // // 获取设备树节点 // #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // // 声明设备 // static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); // static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // // 延时工作 // static struct k_work_delayable uart_work; // struct uart_data_t { // void *fifo_reserved; // uint8_t data[UART_BUF_SIZE]; // uint16_t len; // }; // static K_FIFO_DEFINE(fifo_uart_tx_data); // // RS485接收状态机 // enum rx_state { // STATE_IDLE, // STATE_GOT_AA, // STATE_RECEIVING // }; // static struct { // enum rx_state state; // uint8_t buffer[sizeof(rs485_raw_data_t) + 3]; // AA + BB + payload + CRC // size_t index; // } rx_state_machine; // // CRC校验函数 // static uint8_t calculate_crc(const uint8_t *data, size_t len) // { // uint8_t crc = 0; // for (size_t i = 0; i < len; i++) { // crc ^= data[i]; // } // return crc; // } // static void process_rs485_packet(uint8_t *packet, size_t len) // { // // CRC校验 (最后1字节是CRC) // if (calculate_crc(packet, len - 1) != packet[len - 1]) { // LOG_WRN("Invalid RS485 packet CRC"); // return; // } // // 解析RS485原始数据(跳过包头AA BB) // rs485_raw_data_t raw_data; // memcpy(&raw_data, packet + 2, sizeof(raw_data)); // // 换为统一数据结构 // unified_data_point_t data_point = { // .timestamp = k_uptime_get_32(), // .pressure = raw_data.pressure, // .temp = raw_data.temp, // .acc_x = raw_data.acc_x, // .acc_y = raw_data.acc_y, // .acc_z = raw_data.acc_z, // .gyro_x = raw_data.gyro_x, // .gyro_y = raw_data.gyro_y, // .gyro_z = raw_data.gyro_z, // .data_source = 2 // 标记为RS485设备数据 // }; // LOG_INF("sensor module : pressure %.4f,temp %.2f",data_point.pressure,data_point.temp); // // k_spinlock_key_t key = k_spin_lock(&batch_lock); // // batch_container_t *batch = &data_batches[active_batch_index]; // // if (batch->count == 0) { // // batch->start_timestamp = k_uptime_get(); // // } // // if (batch->count < BATCH_SIZE) { // // batch->data[batch->count++] = data_point; // // bool batch_ready = false; // // if (batch->count >= BATCH_SIZE) { // // batch_ready = true; // // } else if (batch->count > 0 && // // (k_uptime_get() - batch->start_timestamp) >= MAX_BATCH_TIMEOUT_MS) { // // batch_ready = true; // // } // // if (batch_ready) { // // batch->ready = true; // 只设置就绪标志 // // active_batch_index = (active_batch_index + 1) % 2; // 切换到另一个缓冲区 // // k_sem_give(&ble_data_ready_sem); // 通知BLE线程 // // } // // } else { // // LOG_WRN("Batch buffer overflow"); // // } // // k_spin_unlock(&batch_lock, key); // } // static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) // { // static size_t aborted_len; // struct uart_data_t *buf; // static uint8_t *aborted_buf; // static bool disable_req; // switch (evt->type) { // case UART_TX_DONE: // LOG_DBG("UART_TX_DONE"); // // 设置方向为接收模式 // gpio_pin_set_dt(&direct_pin, 0); // if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) { // return; // } // if (aborted_buf) { // buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data[0]); // aborted_buf = NULL; // aborted_len = 0; // k_free(buf); // } else { // buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data[0]); // k_free(buf); // } // // 发送下一个数据包 // buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); // if (buf) { // // 设置方向为发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // if (uart_tx(rs485_uart, buf->data, buf->len, SYS_FOREVER_MS)) { // LOG_WRN("Failed to send data over UART"); // gpio_pin_set_dt(&direct_pin, 0); // 确保切换回接收模式 // k_free(buf); // } // } // break; // case UART_RX_RDY: // const uint8_t *data = evt->data.rx.buf; // size_t len = evt->data.rx.len; // for (size_t i = 0; i < len; i++) { // uint8_t byte = data[i]; // switch (rx_state_machine.state) { // case STATE_IDLE: // if (byte == 0xAA) { // rx_state_machine.state = STATE_GOT_AA; // } // break; // case STATE_GOT_AA: // if (byte == 0xBB) { // rx_state_machine.state = STATE_RECEIVING; // rx_state_machine.index = 0; // rx_state_machine.buffer[rx_state_machine.index++] = 0xAA; // rx_state_machine.buffer[rx_state_machine.index++] = 0xBB; // } else { // rx_state_machine.state = (byte == 0xAA) ? STATE_GOT_AA : STATE_IDLE; // } // break; // case STATE_RECEIVING: // rx_state_machine.buffer[rx_state_machine.index++] = byte; // // 检查完整数据包 (AA + BB + payload + CRC) // if (rx_state_machine.index >= sizeof(rx_state_machine.buffer)) { // process_rs485_packet(rx_state_machine.buffer, rx_state_machine.index); // rx_state_machine.state = STATE_IDLE; // } // break; // } // } // break; // case UART_RX_DISABLED: // LOG_DBG("UART_RX_DISABLED"); // disable_req = false; // buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); // } // break; // case UART_RX_BUF_REQUEST: // LOG_DBG("UART_RX_BUF_REQUEST"); // buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_buf_rsp(rs485_uart, buf->data, sizeof(buf->data)); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // } // break; // case UART_RX_BUF_RELEASED: // LOG_DBG("UART_RX_BUF_RELEASED"); // buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data[0]); // k_free(buf); // break; // case UART_TX_ABORTED: // LOG_DBG("UART_TX_ABORTED"); // gpio_pin_set_dt(&direct_pin, 0); // 确保切换回接收模式 // if (!aborted_buf) { // aborted_buf = (uint8_t *)evt->data.tx.buf; // aborted_len = evt->data.tx.len; // } // struct uart_data_t *tx_buf = (struct uart_data_t *)aborted_buf; // size_t remaining = tx_buf->len - aborted_len; // if (remaining > 0) { // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // uart_tx(rs485_uart, &tx_buf->data[aborted_len], remaining, SYS_FOREVER_MS); // } // break; // default: // break; // } // } // static void uart_work_handler(struct k_work *item) // { // struct uart_data_t *buf = k_malloc(sizeof(*buf)); // if (buf) { // buf->len = 0; // uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); // } else { // LOG_WRN("Not able to allocate UART receive buffer"); // k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); // } // } // static int rs485_init(void) // { // int err; // if (!device_is_ready(rs485_uart)) { // LOG_ERR("UART device not ready"); // return -ENODEV; // } // // 初始化方向控制引脚 // if (!device_is_ready(direct_pin.port)) { // LOG_ERR("GPIO device not ready"); // return -ENODEV; // } // err = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); // if (err) { // LOG_ERR("GPIO config error: %d", err); // return err; // } // // 初始化引脚为接收 // gpio_pin_set_dt(&direct_pin, 0); // // 初始化接收状态机 // rx_state_machine.state = STATE_IDLE; // rx_state_machine.index = 0; // // 初始化UART // k_work_init_delayable(&uart_work, uart_work_handler); // err = uart_callback_set(rs485_uart, uart_cb, NULL); // if (err) { // LOG_ERR("Cannot set UART callback: %d", err); // return err; // } // // 启动接收 // k_work_schedule(&uart_work, K_NO_WAIT); // return 0; // } // void rs485_send(const uint8_t *data, size_t len) // { // struct uart_data_t *tx = k_malloc(sizeof(*tx) + len); // if (!tx) { // LOG_ERR("Not enough memory for UART send"); // return; // } // memcpy(tx->data, data, len); // tx->len = len; // // 如果发送队列为空,直接发送,否则加入队列 // if (k_fifo_is_empty(&fifo_uart_tx_data)) { // // 设置方向为发送模式 // gpio_pin_set_dt(&direct_pin, 1); // k_busy_wait(RS485_DIR_PIN_DELAY_US); // if (uart_tx(rs485_uart, tx->data, tx->len, SYS_FOREVER_MS)) { // LOG_WRN("Failed to start UART send"); // gpio_pin_set_dt(&direct_pin, 0); // 切换回接收模式 // k_free(tx); // } // } else { // k_fifo_put(&fifo_uart_tx_data, tx); // } // } // void rs485_thread(void) // { // if (rs485_init() != 0) { // LOG_ERR("RS485 initialization failed"); // return; // } // LOG_INF("RS485 thread started"); // // 线程主循环 // while (1) { // LOG_INF("rs485 thread"); // k_sleep(K_FOREVER); // } // } // K_THREAD_DEFINE(rs485_thread_id, 2048, rs485_thread, NULL, NULL, NULL, 5, 0, 0); #include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/gpio.h> #include <zephyr/logging/log.h> #include <zephyr/drivers/uart.h> #include "GVL.h" #define LOG_MODULE_NAME rs485_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME); // 获取设备树节点 #define ZEPHYR_USER_NODE DT_PATH(zephyr_user) // 声明设备 static const struct device *const rs485_uart = DEVICE_DT_GET(DT_ALIAS(myuart)); static const struct gpio_dt_spec direct_pin = GPIO_DT_SPEC_GET(ZEPHYR_USER_NODE, rs485_gpios); // 延时工作 static struct k_work_delayable uart_work; struct uart_data_t { void *fifo_reserved; uint8_t data[UART_BUF_SIZE]; uint16_t len; }; static K_FIFO_DEFINE(fifo_uart_tx_data); // 定义RS485数据包结构 typedef struct { uint8_t header[2]; // 0xAA, 0xBB rs485_raw_data_t payload; uint8_t crc; } rs485_packet_t; #define RS485_PACKET_SIZE sizeof(rs485_packet_t) // CRC校验函数 static uint8_t calculate_crc(const uint8_t *data, size_t len) { uint8_t crc = 0; for (size_t i = 0; i < len; i++) { crc ^= data[i]; } return crc; } static void process_rs485_packet(const uint8_t *packet) { const rs485_packet_t *pkt = (const rs485_packet_t *)packet; // 检查包头 if (pkt->header[0] != 0xAA || pkt->header[1] != 0xBB) { LOG_WRN("Invalid packet header: 0x%02X%02X", pkt->header[0], pkt->header[1]); return; } // 计算并验证CRC (不包括CRC自身) uint8_t crc = calculate_crc(packet, RS485_PACKET_SIZE - 1); if (crc != pkt->crc) { LOG_WRN("Invalid CRC: expected 0x%02X, got 0x%02X", crc, pkt->crc); return; } // 换为统一数据结构 unified_data_point_t data_point = { .timestamp = k_uptime_get_32(), .pressure = pkt->payload.pressure, .temp = pkt->payload.temp, .acc_x = pkt->payload.acc_x, .acc_y = pkt->payload.acc_y, .acc_z = pkt->payload.acc_z, .gyro_x = pkt->payload.gyro_x, .gyro_y = pkt->payload.gyro_y, .gyro_z = pkt->payload.gyro_z, .data_source = 2 // 标记为RS485设备数据 }; LOG_INF("RS485 sensor: pressure %.4f, temp %.2f", data_point.pressure, data_point.temp); // // 添加数据到批处理 // k_spinlock_key_t key = k_spin_lock(&batch_lock); // batch_container_t *batch = &data_batches[active_batch_index]; // if (batch->count == 0) { // batch->start_timestamp = k_uptime_get(); // } // if (batch->count < BATCH_SIZE) { // batch->data[batch->count++] = data_point; // bool batch_ready = false; // if (batch->count >= BATCH_SIZE) { // batch_ready = true; // } else if (batch->count > 0 && // (k_uptime_get() - batch->start_timestamp) >= MAX_BATCH_TIMEOUT_MS) { // batch_ready = true; // } // if (batch_ready) { // batch->ready = true; // active_batch_index = (active_batch_index + 1) % 2; // k_sem_give(&ble_data_ready_sem); // } // } else { // LOG_WRN("Batch buffer overflow"); // } // k_spin_unlock(&batch_lock, key); } static void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { static size_t aborted_len; struct uart_data_t *buf; static uint8_t *aborted_buf; static bool disable_req; switch (evt->type) { case UART_TX_DONE: LOG_DBG("UART_TX_DONE"); gpio_pin_set_dt(&direct_pin, 0); // 切换回接收模式 if ((evt->data.tx.len == 0) || (!evt->data.tx.buf)) { return; } if (aborted_buf) { buf = CONTAINER_OF(aborted_buf, struct uart_data_t, data[0]); aborted_buf = NULL; aborted_len = 0; k_free(buf); } else { buf = CONTAINER_OF(evt->data.tx.buf, struct uart_data_t, data[0]); k_free(buf); } // 发送下一个数据包 buf = k_fifo_get(&fifo_uart_tx_data, K_NO_WAIT); if (buf) { gpio_pin_set_dt(&direct_pin, 1); // 切换到发送模式 k_busy_wait(RS485_DIR_PIN_DELAY_US); if (uart_tx(rs485_uart, buf->data, buf->len, SYS_FOREVER_MS)) { LOG_WRN("Failed to send data over UART"); gpio_pin_set_dt(&direct_pin, 0); k_free(buf); } } break; case UART_RX_RDY: // 直接处理接收到的数据 if (evt->data.rx.len == RS485_PACKET_SIZE) { // 检查包头 if (evt->data.rx.buf[0] == 0xAA && evt->data.rx.buf[1] == 0xBB) { process_rs485_packet(evt->data.rx.buf); } else { LOG_WRN("Invalid packet header"); } } else if (evt->data.rx.len > 0) { LOG_WRN("Received unexpected length: %d (expected %d)", evt->data.rx.len, RS485_PACKET_SIZE); } break; case UART_RX_DISABLED: LOG_DBG("UART_RX_DISABLED"); disable_req = false; buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); } break; case UART_RX_BUF_REQUEST: LOG_DBG("UART_RX_BUF_REQUEST"); buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_buf_rsp(rs485_uart, buf->data, sizeof(buf->data)); } else { LOG_WRN("Not able to allocate UART receive buffer"); } break; case UART_RX_BUF_RELEASED: LOG_DBG("UART_RX_BUF_RELEASED"); buf = CONTAINER_OF(evt->data.rx_buf.buf, struct uart_data_t, data[0]); k_free(buf); break; case UART_TX_ABORTED: LOG_DBG("UART_TX_ABORTED"); gpio_pin_set_dt(&direct_pin, 0); if (!aborted_buf) { aborted_buf = (uint8_t *)evt->data.tx.buf; aborted_len = evt->data.tx.len; } struct uart_data_t *tx_buf = (struct uart_data_t *)aborted_buf; size_t remaining = tx_buf->len - aborted_len; if (remaining > 0) { gpio_pin_set_dt(&direct_pin, 1); k_busy_wait(RS485_DIR_PIN_DELAY_US); uart_tx(rs485_uart, &tx_buf->data[aborted_len], remaining, SYS_FOREVER_MS); } break; default: break; } } static void uart_work_handler(struct k_work *item) { struct uart_data_t *buf = k_malloc(sizeof(*buf)); if (buf) { buf->len = 0; uart_rx_enable(rs485_uart, buf->data, sizeof(buf->data), UART_RX_TIMEOUT_MS); } else { LOG_WRN("Not able to allocate UART receive buffer"); k_work_reschedule(&uart_work, K_MSEC(UART_WAIT_FOR_RX)); } } static int rs485_init(void) { int err; if (!device_is_ready(rs485_uart)) { LOG_ERR("UART device not ready"); return -ENODEV; } // 初始化方向控制引脚 if (!device_is_ready(direct_pin.port)) { LOG_ERR("GPIO device not ready"); return -ENODEV; } err = gpio_pin_configure_dt(&direct_pin, GPIO_OUTPUT_INACTIVE); if (err) { LOG_ERR("GPIO config error: %d", err); return err; } // 初始化引脚为接收模式 gpio_pin_set_dt(&direct_pin, 0); // 初始化UART k_work_init_delayable(&uart_work, uart_work_handler); err = uart_callback_set(rs485_uart, uart_cb, NULL); if (err) { LOG_ERR("Cannot set UART callback: %d", err); return err; } // 启动接收 k_work_schedule(&uart_work, K_NO_WAIT); return 0; } void rs485_send(const uint8_t *data, size_t len) { struct uart_data_t *tx = k_malloc(sizeof(*tx) + len); if (!tx) { LOG_ERR("Not enough memory for UART send"); return; } memcpy(tx->data, data, len); tx->len = len; if (k_fifo_is_empty(&fifo_uart_tx_data)) { gpio_pin_set_dt(&direct_pin, 1); // 切换到发送模式 k_busy_wait(RS485_DIR_PIN_DELAY_US); if (uart_tx(rs485_uart, tx->data, tx->len, SYS_FOREVER_MS)) { LOG_WRN("Failed to start UART send"); gpio_pin_set_dt(&direct_pin, 0); k_free(tx); } } else { k_fifo_put(&fifo_uart_tx_data, tx); } } void rs485_thread(void) { if (rs485_init() != 0) { LOG_ERR("RS485 initialization failed"); return; } LOG_INF("RS485 thread started"); while (1) { k_sleep(K_FOREVER); } } K_THREAD_DEFINE(rs485_thread_id, 2048, rs485_thread, NULL, NULL, NULL, 5, 0, 0);rs485接收数据[00:49:12.400,446] <wrn> rs485_thread: Received unexpected length: 3 (expected 35) [00:49:12.401,129] <wrn> rs485_thread: Received unexpected length: 2 (expected 35) [00:49:12.402,071] <wrn> rs485_thread: Received unexpected length: 3 (expected 35)接收数据时报错,不使用状态机
07-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值