基于DWC_ether_qos的以太网驱动开发-RTOS环境移植LWIP与性能测试

原创 嵌入式Lee 2023-09-10 07:31

一. 前言

前面我们基于无OS环境移植了LWIP,这一篇我们来基于RTOS移植LWIP,与无OS环境基本一致,只是需要实现一些系统组件的接口,信号量互斥量等。

二. 需要移植文件

我们参考lwip\contrib\ports\freertos下的移植进行修改,如果使用的是freertos的话直接参考即可。如果用的其他RTOS可以复制一份修改。

复制lwip\contrib\ports\freertos并添加cc.hlwipopts.h(这两个文件可以从contrib下其他样例代码中复制)

 

Cc.h

还是和无OS一样实现随机数函数

#ifndef LWIP_ARCH_CC_H#define LWIP_ARCH_CC_H
#include
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \ x, __LINE__, __FILE__);} while(0)
extern uint32_t lwip_port_rand(void);#define LWIP_RAND() (lwip_port_rand())
#endif

Sys_arch.h/sys_arch.c

如果使用的freertos直接使用即可,否则按需修改。

相关接口。

/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmdit  * */#ifndef LWIP_ARCH_SYS_ARCH_H#define LWIP_ARCH_SYS_ARCH_H
#include "lwip/opt.h"#include "lwip/arch.h"
/** This is returned by _fromisr() sys functions to tell the outermost function * that a higher priority task was woken and the scheduler needs to be invoked. */#define ERR_NEED_SCHED 123
/* This port includes FreeRTOS headers in sys_arch.c only. * FreeRTOS uses pointers as object types. We use wrapper structs instead of * void pointers directly to get a tiny bit of type safety. */
void sys_arch_msleep(u32_t delay_ms);#define sys_msleep(ms) sys_arch_msleep(ms)
#if SYS_LIGHTWEIGHT_PROTtypedef u32_t sys_prot_t;#endif /* SYS_LIGHTWEIGHT_PROT */
#if !LWIP_COMPAT_MUTEXstruct _sys_mut { void *mut;};typedef struct _sys_mut sys_mutex_t;#define sys_mutex_valid_val(mutex) ((mutex).mut != NULL)#define sys_mutex_valid(mutex) (((mutex) != NULL) && sys_mutex_valid_val(*(mutex)))#define sys_mutex_set_invalid(mutex) ((mutex)->mut = NULL)#endif /* !LWIP_COMPAT_MUTEX */
struct _sys_sem { void *sem;};typedef struct _sys_sem sys_sem_t;#define sys_sem_valid_val(sema) ((sema).sem != NULL)#define sys_sem_valid(sema) (((sema) != NULL) && sys_sem_valid_val(*(sema)))#define sys_sem_set_invalid(sema) ((sema)->sem = NULL)
struct _sys_mbox { void *mbx;};typedef struct _sys_mbox sys_mbox_t;#define sys_mbox_valid_val(mbox) ((mbox).mbx != NULL)#define sys_mbox_valid(mbox) (((mbox) != NULL) && sys_mbox_valid_val(*(mbox)))#define sys_mbox_set_invalid(mbox) ((mbox)->mbx = NULL)
struct _sys_thread { void *thread_handle;};typedef struct _sys_thread sys_thread_t;
#if LWIP_NETCONN_SEM_PER_THREADsys_sem_t* sys_arch_netconn_sem_get(void);void sys_arch_netconn_sem_alloc(void);void sys_arch_netconn_sem_free(void);#define LWIP_NETCONN_THREAD_SEM_GET() sys_arch_netconn_sem_get()#define LWIP_NETCONN_THREAD_SEM_ALLOC() sys_arch_netconn_sem_alloc()#define LWIP_NETCONN_THREAD_SEM_FREE() sys_arch_netconn_sem_free()#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#endif /* LWIP_ARCH_SYS_ARCH_H */


/* * Copyright (c) 2017 Simon Goldschmidt * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, *    this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products *    derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Simon Goldschmidt  * */
/* lwIP includes. */#include "lwip/debug.h"#include "lwip/def.h"#include "lwip/sys.h"#include "lwip/mem.h"#include "lwip/stats.h"#include "lwip/tcpip.h"#include "FreeRTOS.h"#include "semphr.h"#include "task.h"
/** Set this to 1 if you want the stack size passed to sys_thread_new() to be * interpreted as number of stack words (FreeRTOS-like). * Default is that they are interpreted as byte count (lwIP-like). */#ifndef LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS#define LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS 0#endif
/** Set this to 1 to use a mutex for SYS_ARCH_PROTECT() critical regions. * Default is 0 and locks interrupts/scheduler for SYS_ARCH_PROTECT(). */#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX#define LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX 0#endif
/** Set this to 1 to include a sanity check that SYS_ARCH_PROTECT() and * SYS_ARCH_UNPROTECT() are called matching. */#ifndef LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK#define LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK 0#endif
/** Set this to 1 to let sys_mbox_free check that queues are empty when freed */#ifndef LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE#define LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE 0#endif
/** Set this to 1 to enable core locking check functions in this port. * For this to work, you'll have to define LWIP_ASSERT_CORE_LOCKED() * and LWIP_MARK_TCPIP_THREAD() correctly in your lwipopts.h! */#ifndef LWIP_FREERTOS_CHECK_CORE_LOCKING#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1#endif
/** Set this to 0 to implement sys_now() yourself, e.g. using a hw timer. * Default is 1, where FreeRTOS ticks are used to calculate back to ms. */#ifndef LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS#define LWIP_FREERTOS_SYS_NOW_FROM_FREERTOS 1#endif
#if !configSUPPORT_DYNAMIC_ALLOCATION# error "lwIP FreeRTOS port requires configSUPPORT_DYNAMIC_ALLOCATION"#endif#if !INCLUDE_vTaskDelay# error "lwIP FreeRTOS port requires INCLUDE_vTaskDelay"#endif#if !INCLUDE_vTaskSuspend# error "lwIP FreeRTOS port requires INCLUDE_vTaskSuspend"#endif#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX || !LWIP_COMPAT_MUTEX#if !configUSE_MUTEXES# error "lwIP FreeRTOS port requires configUSE_MUTEXES"#endif#endif
#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEXstatic SemaphoreHandle_t sys_arch_protect_mutex;#endif#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECKstatic sys_prot_t sys_arch_protect_nesting;#endif
/* Initialize this module (see description in sys.h) */voidsys_init(void){#if SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX /* initialize sys_arch_protect global mutex */ sys_arch_protect_mutex = xSemaphoreCreateRecursiveMutex(); LWIP_ASSERT("failed to create sys_arch_protect mutex", sys_arch_protect_mutex != NULL);#endif /* SYS_LIGHTWEIGHT_PROT && LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */}
#if configUSE_16_BIT_TICKS == 1#error This port requires 32 bit ticks or timer overflow will fail#endif
#if LWIP_FREERTOS_SYS_NOW_FROM_FREERTOSu32_tsys_now(void){ return xTaskGetTickCount() * portTICK_PERIOD_MS;}#endif
u32_tsys_jiffies(void){ return xTaskGetTickCount();}
#if SYS_LIGHTWEIGHT_PROT
sys_prot_tsys_arch_protect(void){#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret; LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreTakeRecursive(sys_arch_protect_mutex, portMAX_DELAY); LWIP_ASSERT("sys_arch_protect failed to take the mutex", ret == pdTRUE);#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskENTER_CRITICAL();#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK { /* every nested call to sys_arch_protect() returns an increased number */ sys_prot_t ret = sys_arch_protect_nesting; sys_arch_protect_nesting++; LWIP_ASSERT("sys_arch_protect overflow", sys_arch_protect_nesting > ret); return ret; }#else return 1;#endif}
voidsys_arch_unprotect(sys_prot_t pval){#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX BaseType_t ret;#endif#if LWIP_FREERTOS_SYS_ARCH_PROTECT_SANITY_CHECK LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting > 0); sys_arch_protect_nesting--; LWIP_ASSERT("unexpected sys_arch_protect_nesting", sys_arch_protect_nesting == pval);#endif
#if LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX LWIP_ASSERT("sys_arch_protect_mutex != NULL", sys_arch_protect_mutex != NULL);
ret = xSemaphoreGiveRecursive(sys_arch_protect_mutex); LWIP_ASSERT("sys_arch_unprotect failed to give the mutex", ret == pdTRUE);#else /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ taskEXIT_CRITICAL();#endif /* LWIP_FREERTOS_SYS_ARCH_PROTECT_USES_MUTEX */ LWIP_UNUSED_ARG(pval);}
#endif /* SYS_LIGHTWEIGHT_PROT */
voidsys_arch_msleep(u32_t delay_ms){ TickType_t delay_ticks = delay_ms / portTICK_RATE_MS; vTaskDelay(delay_ticks);}
#if !LWIP_COMPAT_MUTEX
/* Create a new mutex*/err_tsys_mutex_new(sys_mutex_t *mutex){ LWIP_ASSERT("mutex != NULL", mutex != NULL);
mutex->mut = xSemaphoreCreateRecursiveMutex(); if(mutex->mut == NULL) { SYS_STATS_INC(mutex.err); return ERR_MEM; } SYS_STATS_INC_USED(mutex); return ERR_OK;}
voidsys_mutex_lock(sys_mutex_t *mutex){ BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
ret = xSemaphoreTakeRecursive(mutex->mut, portMAX_DELAY); LWIP_ASSERT("failed to take the mutex", ret == pdTRUE);}
voidsys_mutex_unlock(sys_mutex_t *mutex){ BaseType_t ret; LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
ret = xSemaphoreGiveRecursive(mutex->mut); LWIP_ASSERT("failed to give the mutex", ret == pdTRUE);}
voidsys_mutex_free(sys_mutex_t *mutex){ LWIP_ASSERT("mutex != NULL", mutex != NULL); LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
SYS_STATS_DEC(mutex.used); vSemaphoreDelete(mutex->mut); mutex->mut = NULL;}
#endif /* !LWIP_COMPAT_MUTEX */
err_tsys_sem_new(sys_sem_t *sem, u8_t initial_count){ LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("initial_count invalid (not 0 or 1)", (initial_count == 0) || (initial_count == 1));
sem->sem = xSemaphoreCreateBinary(); if(sem->sem == NULL) { SYS_STATS_INC(sem.err); return ERR_MEM; } SYS_STATS_INC_USED(sem);
if(initial_count == 1) { BaseType_t ret = xSemaphoreGive(sem->sem); LWIP_ASSERT("sys_sem_new: initial give failed", ret == pdTRUE); } return ERR_OK;}
voidsys_sem_signal(sys_sem_t *sem){ BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
ret = xSemaphoreGive(sem->sem); /* queue full is OK, this is a signal only... */ LWIP_ASSERT("sys_sem_signal: sane return value", (ret == pdTRUE) || (ret == errQUEUE_FULL));}
u32_tsys_arch_sem_wait(sys_sem_t *sem, u32_t timeout_ms){ BaseType_t ret; LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
if(!timeout_ms) { /* wait infinite */ ret = xSemaphoreTake(sem->sem, portMAX_DELAY); LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xSemaphoreTake(sem->sem, timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("taking semaphore failed", ret == pdTRUE); }
/* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1;}
voidsys_sem_free(sys_sem_t *sem){ LWIP_ASSERT("sem != NULL", sem != NULL); LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
SYS_STATS_DEC(sem.used); vSemaphoreDelete(sem->sem); sem->sem = NULL;}
err_tsys_mbox_new(sys_mbox_t *mbox, int size){ LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("size > 0", size > 0);
mbox->mbx = xQueueCreate((UBaseType_t)size, sizeof(void *)); if(mbox->mbx == NULL) { SYS_STATS_INC(mbox.err); return ERR_MEM; } SYS_STATS_INC_USED(mbox); return ERR_OK;}
voidsys_mbox_post(sys_mbox_t *mbox, void *msg){ BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBack(mbox->mbx, &msg, portMAX_DELAY); LWIP_ASSERT("mbox post failed", ret == pdTRUE);}
err_tsys_mbox_trypost(sys_mbox_t *mbox, void *msg){ BaseType_t ret; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBack(mbox->mbx, &msg, 0); if (ret == pdTRUE) { return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; }}
err_tsys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg){ BaseType_t ret; BaseType_t xHigherPriorityTaskWoken = pdFALSE; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
ret = xQueueSendToBackFromISR(mbox->mbx, &msg, &xHigherPriorityTaskWoken); if (ret == pdTRUE) { if (xHigherPriorityTaskWoken == pdTRUE) { return ERR_NEED_SCHED; } return ERR_OK; } else { LWIP_ASSERT("mbox trypost failed", ret == errQUEUE_FULL); SYS_STATS_INC(mbox.err); return ERR_MEM; }}
u32_tsys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout_ms){ BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
if (!msg) { msg = &msg_dummy; }
if (!timeout_ms) { /* wait infinite */ ret = xQueueReceive(mbox->mbx, &(*msg), portMAX_DELAY); LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); } else { TickType_t timeout_ticks = timeout_ms / portTICK_RATE_MS; ret = xQueueReceive(mbox->mbx, &(*msg), timeout_ticks); if (ret == errQUEUE_EMPTY) { /* timed out */ *msg = NULL; return SYS_ARCH_TIMEOUT; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE); }
/* Old versions of lwIP required us to return the time waited. This is not the case any more. Just returning != SYS_ARCH_TIMEOUT here is enough. */ return 1;}
u32_tsys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg){ BaseType_t ret; void *msg_dummy; LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
if (!msg) { msg = &msg_dummy; }
ret = xQueueReceive(mbox->mbx, &(*msg), 0); if (ret == errQUEUE_EMPTY) { *msg = NULL; return SYS_MBOX_EMPTY; } LWIP_ASSERT("mbox fetch failed", ret == pdTRUE);
return 0;}
voidsys_mbox_free(sys_mbox_t *mbox){ LWIP_ASSERT("mbox != NULL", mbox != NULL); LWIP_ASSERT("mbox->mbx != NULL", mbox->mbx != NULL);
#if LWIP_FREERTOS_CHECK_QUEUE_EMPTY_ON_FREE { UBaseType_t msgs_waiting = uxQueueMessagesWaiting(mbox->mbx); LWIP_ASSERT("mbox quence not empty", msgs_waiting == 0);
if (msgs_waiting != 0) { SYS_STATS_INC(mbox.err); } }#endif
vQueueDelete(mbox->mbx);
SYS_STATS_DEC(mbox.used);}
sys_thread_tsys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio){ TaskHandle_t rtos_task; BaseType_t ret; sys_thread_t lwip_thread; size_t rtos_stacksize;
LWIP_ASSERT("invalid stacksize", stacksize > 0);#if LWIP_FREERTOS_THREAD_STACKSIZE_IS_STACKWORDS rtos_stacksize = (size_t)stacksize;#else rtos_stacksize = (size_t)stacksize / sizeof(StackType_t);#endif
/* lwIP's lwip_thread_fn matches FreeRTOS' TaskFunction_t, so we can pass the thread function without adaption here. */ ret = xTaskCreate(thread, name, (configSTACK_DEPTH_TYPE)rtos_stacksize, arg, prio, &rtos_task); LWIP_ASSERT("task creation failed", ret == pdTRUE);
lwip_thread.thread_handle = rtos_task; return lwip_thread;}
#if LWIP_NETCONN_SEM_PER_THREAD#if configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0
sys_sem_t *sys_arch_netconn_sem_get(void){ void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); return ret;}
voidsys_arch_netconn_sem_alloc(void){ void *ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret == NULL) { sys_sem_t *sem; err_t err; /* need to allocate the memory for this semaphore */ sem = mem_malloc(sizeof(sys_sem_t)); LWIP_ASSERT("sem != NULL", sem != NULL); err = sys_sem_new(sem, 0); LWIP_ASSERT("err == ERR_OK", err == ERR_OK); LWIP_ASSERT("sem invalid", sys_sem_valid(sem)); vTaskSetThreadLocalStoragePointer(task, 0, sem); }}
void sys_arch_netconn_sem_free(void){ void* ret; TaskHandle_t task = xTaskGetCurrentTaskHandle(); LWIP_ASSERT("task != NULL", task != NULL);
ret = pvTaskGetThreadLocalStoragePointer(task, 0); if(ret != NULL) { sys_sem_t *sem = ret; sys_sem_free(sem); mem_free(sem); vTaskSetThreadLocalStoragePointer(task, 0, NULL); }}
#else /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */#error LWIP_NETCONN_SEM_PER_THREAD needs configNUM_THREAD_LOCAL_STORAGE_POINTERS#endif /* configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 */
#endif /* LWIP_NETCONN_SEM_PER_THREAD */
#if LWIP_FREERTOS_CHECK_CORE_LOCKING#if LWIP_TCPIP_CORE_LOCKING
/** Flag the core lock held. A counter for recursive locks. */static u8_t lwip_core_lock_count;static TaskHandle_t lwip_core_lock_holder_thread;
voidsys_lock_tcpip_core(void){ sys_mutex_lock(&lock_tcpip_core); if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = xTaskGetCurrentTaskHandle(); } lwip_core_lock_count++;}
voidsys_unlock_tcpip_core(void){ lwip_core_lock_count--; if (lwip_core_lock_count == 0) { lwip_core_lock_holder_thread = 0; } sys_mutex_unlock(&lock_tcpip_core);}
#endif /* LWIP_TCPIP_CORE_LOCKING */
#if !NO_SYSstatic TaskHandle_t lwip_tcpip_thread;#endif
voidsys_mark_tcpip_thread(void){#if !NO_SYS lwip_tcpip_thread = xTaskGetCurrentTaskHandle();#endif}
voidsys_check_core_locking(void){ /* Embedded systems should check we are NOT in an interrupt context here */ /* E.g. core Cortex-M3/M4 ports: configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
Instead, we use more generic FreeRTOS functions here, which should fail from ISR: */ taskENTER_CRITICAL(); taskEXIT_CRITICAL();
#if !NO_SYS if (lwip_tcpip_thread != 0) { TaskHandle_t current_thread = xTaskGetCurrentTaskHandle();
#if LWIP_TCPIP_CORE_LOCKING LWIP_ASSERT("Function called without core lock", current_thread == lwip_core_lock_holder_thread && lwip_core_lock_count > 0);#else /* LWIP_TCPIP_CORE_LOCKING */ LWIP_ASSERT("Function called from wrong thread", current_thread == lwip_tcpip_thread);#endif /* LWIP_TCPIP_CORE_LOCKING */ }#endif /* !NO_SYS */}
#endif /* LWIP_FREERTOS_CHECK_CORE_LOCKING*/

Lwipopts.h

配置

/** * @file * * lwIP Options Configuration */
/* * Copyright (c) 2001-2004 Swedish Institute of Computer Science. * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY * OF SUCH DAMAGE. * * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels * */#ifndef LWIP_LWIPOPTS_H#define LWIP_LWIPOPTS_H
/* * Include user defined options first. Anything not defined in these files * will be set to standard values. Override anything you don't like! */#include "lwipopts.h"#include "lwip/debug.h"#include "os_mem.h"
#define LWIP_PROVIDE_ERRNO 1#define LWIP_COMPAT_MUTEX 0#define LWIP_DEBUG 1
#define DEFAULT_THREAD_PRIO 7#define DEFAULT_THREAD_STACKSIZE 1024#define TCPIP_THREAD_STACKSIZE 1024#define TCPIP_THREAD_PRIO 7#define SNMP_STACK_SIZE 1024#define SNMP_THREAD_PRIO 7#define SLIPIF_THREAD_STACKSIZE 1024#define SLIPIF_THREAD_PRIO 7
#define MEMP_MEM_MALLOC 1#define MEM_LIBC_MALLOC 1#define mem_clib_malloc(size) os_mem_malloc(0,size)#define mem_clib_free os_mem_free#define mem_clib_calloc(cnt,size) os_mem_calloc(0,(cnt)*(size))
#define DEFAULT_RAW_RECVMBOX_SIZE 10#define DEFAULT_UDP_RECVMBOX_SIZE 10#define DEFAULT_TCP_RECVMBOX_SIZE 10#define TCPIP_MBOX_SIZE 10#define DEFAULT_ACCEPTMBOX_SIZE 10
#define TCP_MSS (1500 - 40)
#define TCP_SND_BUF (11*TCP_MSS)#define TCP_WND (11*TCP_MSS)/* ----------------------------------------------- ---------- Platform specific locking ---------- -----------------------------------------------*/
/** * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain * critical regions during buffer allocation, deallocation and memory * allocation and deallocation. */#define SYS_LIGHTWEIGHT_PROT 0
/** * NO_SYS==1: Provides VERY minimal functionality. Otherwise, * use lwIP facilities. */#define NO_SYS 0
/* ------------------------------------ ---------- Memory options ---------- ------------------------------------*/
/** * MEM_ALIGNMENT: should be set to the alignment of the CPU * 4 byte alignment -> #define MEM_ALIGNMENT 4 * 2 byte alignment -> #define MEM_ALIGNMENT 2 */#define MEM_ALIGNMENT 4U
/** * MEM_SIZE: the size of the heap memory. If the application will send * a lot of data that needs to be copied, this should be set high. */#define MEM_SIZE 1600
/* ------------------------------------------------ ---------- Internal Memory Pool Sizes ---------- ------------------------------------------------*//** * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). * If the application sends a lot of data out of ROM (or other static memory), * this should be set high. */#define MEMP_NUM_PBUF 160
/** * MEMP_NUM_RAW_PCB: Number of raw connection PCBs * (requires the LWIP_RAW option) */#define MEMP_NUM_RAW_PCB 4
/** * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One * per active UDP "connection". * (requires the LWIP_UDP option) */#define MEMP_NUM_UDP_PCB 4
/** * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_PCB 4
/** * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_PCB_LISTEN 4
/** * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. * (requires the LWIP_TCP option) */#define MEMP_NUM_TCP_SEG 160
/** * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for * reassembly (whole packets, not fragments!) */#define MEMP_NUM_REASSDATA 1
/** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. * (requires the ARP_QUEUEING option) */#define MEMP_NUM_ARP_QUEUE 2
/** * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. * (requires NO_SYS==0) */#define MEMP_NUM_SYS_TIMEOUT 8
/** * MEMP_NUM_NETBUF: the number of struct netbufs. * (only needed if you use the sequential API, like api_lib.c) */#define MEMP_NUM_NETBUF 2
/** * MEMP_NUM_NETCONN: the number of struct netconns. * (only needed if you use the sequential API, like api_lib.c) */#define MEMP_NUM_NETCONN 32
/** * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used * for callback/timeout API communication. * (only needed if you use tcpip.c) */#define MEMP_NUM_TCPIP_MSG_API 8
/** * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used * for incoming packets. * (only needed if you use tcpip.c) */#define MEMP_NUM_TCPIP_MSG_INPKT 8
/** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */#define PBUF_POOL_SIZE 64
/* --------------------------------- ---------- ARP options ---------- ---------------------------------*//** * LWIP_ARP==1: Enable ARP functionality. */#define LWIP_ARP 1
/* -------------------------------- ---------- IP options ---------- --------------------------------*//** * IP_FORWARD==1: Enables the ability to forward IP packets across network * interfaces. If you are going to run lwIP on a device with only one network * interface, define this to 0. */#define IP_FORWARD 0
/** * IP_OPTIONS: Defines the behavior for IP options. * IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. * IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). */#define IP_OPTIONS_ALLOWED 1
/** * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that * this option does not affect outgoing packet sizes, which can be controlled * via IP_FRAG. */#define IP_REASSEMBLY 1
/** * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note * that this option does not affect incoming packet sizes, which can be * controlled via IP_REASSEMBLY. */#define IP_FRAG 1
/** * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived * in this time, the whole packet is discarded. */#define IP_REASS_MAXAGE 3
/** * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. * Since the received pbufs are enqueued, be sure to configure * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive * packets even if the maximum amount of fragments is enqueued for reassembly! */#define IP_REASS_MAX_PBUFS 4
/** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original * packet data to be fragmented.*/#define IP_FRAG_USES_STATIC_BUF 0
/** * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. */#define IP_DEFAULT_TTL 255
/* ---------------------------------- ---------- ICMP options ---------- ----------------------------------*//** * LWIP_ICMP==1: Enable ICMP module inside the IP stack. * Be careful, disable that make your product non-compliant to RFC1122 */#define LWIP_ICMP 1
/* --------------------------------- ---------- RAW options ---------- ---------------------------------*//** * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. */#define LWIP_RAW 1
/* ---------------------------------- ---------- DHCP options ---------- ----------------------------------*//** * LWIP_DHCP==1: Enable DHCP module. */#define LWIP_DHCP 0

/* ------------------------------------ ---------- AUTOIP options ---------- ------------------------------------*//** * LWIP_AUTOIP==1: Enable AUTOIP module. */#define LWIP_AUTOIP 0
/* ---------------------------------- ---------- SNMP options ---------- ----------------------------------*//** * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP * transport. */#define LWIP_SNMP 0
/* ---------------------------------- ---------- IGMP options ---------- ----------------------------------*//** * LWIP_IGMP==1: Turn on IGMP module. */#define LWIP_IGMP 0
/* ---------------------------------- ---------- DNS options ----------- ----------------------------------*//** * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS * transport. */#define LWIP_DNS 0
/* --------------------------------- ---------- UDP options ---------- ---------------------------------*//** * LWIP_UDP==1: Turn on UDP. */#define LWIP_UDP 1
/* --------------------------------- ---------- TCP options ---------- ---------------------------------*//** * LWIP_TCP==1: Turn on TCP. */#define LWIP_TCP 1
#define LWIP_LISTEN_BACKLOG 0
/* ---------------------------------- ---------- Pbuf options ---------- ----------------------------------*//** * PBUF_LINK_HLEN: the number of bytes that should be allocated for a * link level header. The default is 14, the standard value for * Ethernet. */#define PBUF_LINK_HLEN 16
/** * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is * designed to accommodate single full size TCP frame in one pbuf, including * TCP_MSS, IP header, and link header.* */#define PBUF_POOL_BUFSIZE LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)
/* ------------------------------------ ---------- LOOPIF options ---------- ------------------------------------*//** * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c */#define LWIP_HAVE_LOOPIF 0
/* ---------------------------------------------- ---------- Sequential layer options ---------- ----------------------------------------------*/
/** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */#define LWIP_NETCONN 1
/* ------------------------------------ ---------- Socket options ---------- ------------------------------------*//** * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) */#define LWIP_SOCKET 1
/** * SO_REUSE==1: Enable SO_REUSEADDR */#define SO_REUSE 1
/* ---------------------------------------- ---------- Statistics options ---------- ----------------------------------------*//** * LWIP_STATS==1: Enable statistics collection in lwip_stats. */#define LWIP_STATS 0/* --------------------------------- ---------- PPP options ---------- ---------------------------------*//** * PPP_SUPPORT==1: Enable PPP. */#define PPP_SUPPORT 0


/* --------------------------------------- ---------- Threading options ---------- ---------------------------------------*/
#define LWIP_TCPIP_CORE_LOCKING 0
#if !NO_SYSvoid sys_check_core_locking(void);#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking()#endif
#endif /* LWIP_LWIPOPTS_H */

Perf.c/h

#ifndef LWIP_ARCH_PERF_H#define LWIP_ARCH_PERF_H
#include
struct tms { uint32_t tms_utime; /* user time */ uint32_t tms_stime; /* system time */ uint32_t tms_cutime; /* user time, children */ uint32_t tms_cstime; /* system time, children */};
void perf_times(struct tms *t);void perf_print_times(struct tms *start, struct tms *end, char *key);
//#define PERF 1
#ifdef PERF#define PERF_START struct tms __perf_start;\ struct tms __perf_end; \ perf_times(&__perf_start)#define PERF_STOP(x) perf_times(&__perf_end); \ perf_print_times(&__perf_start, &__perf_end, x);#else /* PERF */#define PERF_START /* null definition */#define PERF_STOP(x) /* null definition */#endif /* PERF */
#endif /* LWIP_ARCH_PERF_H */
#include 
#include "arch/perf.h"
extern uint32_t sys_now(void);void perf_times(struct tms *t){ t->tms_stime = sys_now();}
void perf_print_times(struct tms *start, struct tms *end, char *key){ printf("%s: %lumS\n", key, end->tms_stime - start->tms_stime);}

Portethif.c/f

#ifndef LWIP_ARCH_PERF_H#define LWIP_ARCH_PERF_H
#include
struct tms { uint32_t tms_utime; /* user time */ uint32_t tms_stime; /* system time */ uint32_t tms_cutime; /* user time, children */ uint32_t tms_cstime; /* system time, children */};
void perf_times(struct tms *t);void perf_print_times(struct tms *start, struct tms *end, char *key);
//#define PERF 1
#ifdef PERF#define PERF_START struct tms __perf_start;\ struct tms __perf_end; \ perf_times(&__perf_start)#define PERF_STOP(x) perf_times(&__perf_end); \ perf_print_times(&__perf_start, &__perf_end, x);#else /* PERF */#define PERF_START /* null definition */#define PERF_STOP(x) /* null definition */#endif /* PERF */
#endif /* LWIP_ARCH_PERF_H */
#include 
#include "arch/perf.h"
extern uint32_t sys_now(void);void perf_times(struct tms *t){ t->tms_stime = sys_now();}
void perf_print_times(struct tms *start, struct tms *end, char *key){ printf("%s: %lumS\n", key, end->tms_stime - start->tms_stime);}

系统接口

Lwipopts.h

OSNO_SYS配置为0

#define NO_SYS 0

此时Sys_arch.h/sys_arch.c需要实现以下接口

sys_init

sys_now 获取ms

sys_jiffies获取滴答值

sys_arch_msleep

sys_sem_new

sys_sem_signal

sys_arch_sem_wait

sys_sem_free

LWIP_COMPAT_MUTEX0时实现以下互斥量接口,否则自动使用信号量实现

sys_mutex_new

sys_mutex_lock

sys_mutex_unlock

sys_mutex_free

sys_mbox_new

sys_mbox_post

sys_mbox_trypost

sys_mbox_trypost_fromisr

sys_arch_mbox_fetch

sys_arch_mbox_tryfetch

sys_mbox_free

需要设置消息邮箱的大小

#define DEFAULT_RAW_RECVMBOX_SIZE 10
#define DEFAULT_UDP_RECVMBOX_SIZE 10
#define DEFAULT_TCP_RECVMBOX_SIZE 10
#define TCPIP_MBOX_SIZE 10

sys_thread_new

配置默认线程栈大小和优先级

#define DEFAULT_THREAD_PRIO 7
#define DEFAULT_THREAD_STACKSIZE 1024
#define TCPIP_THREAD_STACKSIZE 1024
#define TCPIP_THREAD_PRIO 7
#define SNMP_STACK_SIZE 1024
#define SNMP_THREAD_PRIO 7
#define SLIPIF_THREAD_STACKSIZE 1024
#define SLIPIF_THREAD_PRIO 7

如果使能LWIP_NETCONN_SEM_PER_THREAD

sys_arch_netconn_sem_get

sys_arch_netconn_sem_alloc

sys_arch_netconn_sem_free

如果使能LWIP_FREERTOS_CHECK_CORE_LOCKING

LWIP_TCPIP_CORE_LOCKING

sys_lock_tcpip_core

sys_unlock_tcpip_core

sys_mark_tcpip_thread

sys_check_core_locking

SYS_LIGHTWEIGHT_PROT使能时

sys_arch_protect

sys_arch_unprotect

错误码处理

Lwipopts.h

#define LWIP_PROVIDE_ERRNO 1

则使用LWIP自己实现的errno.h相关错误码和接口。

互斥量使用

如果有互斥量则

Lwipopts.h

#define LWIP_COMPAT_MUTEX 0

如果定义为1则使用信号量替代互斥量

Sys.h

#define sys_mutex_t                   sys_sem_t
#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
#define sys_mutex_free(mutex) sys_sem_free(mutex)
#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex)

LOCK Check

Sys_arch.c

#define LWIP_FREERTOS_CHECK_CORE_LOCKING 1

Lwipopts.h

#define LWIP_TCPIP_CORE_LOCKING 1

堆配置

OS了我们可以直接使用OS提供的堆管理,LWIP的堆和内存池参见前两篇文章分析。

Lwipopts.h

配置内存池memp.c使用堆实现mem_malloc,mem_free

#define MEMP_MEM_MALLOC 1

配置使用系统的堆管理

#define MEM_LIBC_MALLOC 1

此时MEM_USE_POOLS必须为0

实现以下几个接口

mem_clib_free

mem_clib_malloc

mem_clib_calloc

另外就是配置使用内存池的各个组建的内存池大小

MEMP_NUM_xxx

时间

在系统接口中实现

sys_now

sys_jiffies

断言

不定义LWIP_ASSERT

debug.h

#ifndef LWIP_NOASSERT
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \
LWIP_PLATFORM_ASSERT(message); }} while(0)
#else /* LWIP_NOASSERT */
#define LWIP_ASSERT(message, assertion)
#endif /* LWIP_NOASSERT */

未定义LWIP_PLATFORM_ASSERT

#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__); fflush(NULL); abort();} while(0)
#include
#include
#endif

如果有printf可以cc.h中定义为

#define LWIP_PLATFORM_ASSERT(x) do {printf("Assertion \"%s\" failed at line %d in %s\n", \
x, __LINE__, __FILE__);} while(0)

调试

使能配置LWIP_DEBUG

实现LWIP_PLATFORM_DIAG

arch.h中默认是

#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#include
#include
#endif

LWIP_DBG_ON 

LWIP_DBG_TYPES_ON

LWIP_DBG_MASK_LEVEL

三. tcp测试

复制\contrib\apps\tcpecho下的tcpeco.c/h到自己工程中

调用

tcpecho_init

初始化

关键初始化过程

tcpip_init(0,0);

netif_add(&netif, (const ip_addr_t *)&ipaddr, (const ip_addr_t *)&netmask, (const ip_addr_t *)&gw, NULL, &lwip_port_eth_init, ðernet_input);

netif_set_default(&netif);

if (netif_is_link_up(&netif))

{

netif_set_up(&netif);

}

else

{

netif_set_down(&netif);

}

tcpecho_init(); //port 7

PC作为客户端

 

四. tcp性能测试

添加以下代码到自己的工程

src\apps\lwiperf\lwiperf.c

src\include\lwip\apps\lwiperf.h

contrib\examples\lwiperf\lwiperf_example.c/h

端口为lwiperf.h中定义

#define LWIPERF_TCP_PORT_DEFAULT 5001

调用

lwiperf_example_init();

初始化

使用Jperf

PCclient模式

 


评论 (0)
  •   电磁数据管理系统深度解析   北京华盛恒辉电磁数据管理系统作为专业的数据处理平台,旨在提升电磁数据的处理效率、安全性与可靠性。以下从功能架构、核心特性、应用场景及技术实现展开分析:   应用案例   目前,已有多个电磁数据管理系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁数据管理系统。这些成功案例为电磁数据管理系统的推广和应用提供了有力支持。   一、核心功能模块   数据采集与接入:实时接收天线、频谱仪等设备数据,兼容多协议接口,确保数据采集的全面性与实时性
    华盛恒辉l58ll334744 2025-05-13 10:59 51浏览
  •   定制软件开发公司推荐清单   在企业数字化转型加速的2025年,定制软件开发需求愈发多元复杂。不同行业、技术偏好与服务模式的企业,对开发公司的要求大相径庭。以下从技术赛道、服务模式及行业场景出发,为您提供适配的定制软件开发公司推荐及选择建议。   华盛恒辉科技有限公司:是一家专注于高端软件定制开发服务和高端建设的服务机构,致力于为企业提供全面、系统的开发制作方案。在部队政企开发、建设到运营推广领域拥有丰富经验,在教育,工业,医疗,APP,管理,商城,人工智能,部队软件、工业软件、数字化转
    华盛恒辉l58ll334744 2025-05-12 15:55 222浏览
  • 在全球供应链紧张和国产替代需求推动下,国产存储芯片产业快速发展,形成设计到封测一体化的完整生态。北京君正、兆易创新、紫光国芯、东芯股份、普冉股份和佰维存储等六大上市公司在NOR/NAND Flash、DRAM、嵌入式存储等领域布局各具特色,推动国产替代提速。贞光科技代理的品牌紫光国芯,专注DRAM技术,覆盖嵌入式存储与模组解决方案,为多领域客户提供高可靠性产品。随着AI、5G等新兴应用兴起,国产存储厂商有望迎来新一轮增长。存储芯片分类与应用易失性与非易失性存储芯片易失性存储芯片(Volatile
    贞光科技 2025-05-12 16:05 86浏览
  •         信创产业含义的“信息技术应用创新”一词,最早公开信息见于2019年3月26日,在江苏南京召开的信息技术应用创新研讨会。本次大会主办单位为江苏省工业和信息化厅和中国电子工业标准化技术协会安全可靠工作委员会。        2019年5月16日,美国将华为列入实体清单,在未获得美国商务部许可的情况下,美国企业将无法向华为供应产品。       2019年6
    天涯书生 2025-05-11 10:41 164浏览
  • 递交招股书近一年后,曹操出行 IPO 进程终于迎来关键节点。从 2024 年 4 月首次递表,到 2025 年 4 月顺利通过中国证监会境外发行上市备案,并迅速更新招股书。而通过上市备案也标志着其赴港IPO进程进入实质性推进阶段,曹操出行最快有望于2025年内完成港股上市,成为李书福商业版图中又一关键落子。行路至此,曹操出行面临的挑战依然不容忽视。当下的网约车赛道,早已不是当年群雄逐鹿的草莽时代,市场渐趋饱和,竞争近乎白热化。曹操出行此时冲刺上市,既是背水一战,也是谋篇布局。其招股书中披露的资金
    用户1742991715177 2025-05-10 21:18 86浏览
  • ‌磁光克尔效应(Magneto-Optic Kerr Effect, MOKE)‌ 是指当线偏振光入射到磁性材料表面并反射后,其偏振状态(偏振面旋转角度和椭偏率)因材料的磁化强度或方向发生改变的现象。具体表现为:1、‌偏振面旋转‌:反射光的偏振方向相对于入射光发生偏转(克尔旋转角 θK)。2、‌椭偏率变化‌:反射光由线偏振变为椭圆偏振(克尔椭偏率 εK)。这一效应直接关联材料的磁化状态,是表征磁性材料(如铁磁体、反铁磁体)磁学性质的重要非接触式光学探测手段,广泛用于
    锦正茂科技 2025-05-12 11:02 198浏览
  •   电磁数据展示系统平台解析   北京华盛恒辉电磁数据展示系统平台是实现电磁数据高效展示、分析与管理的综合性软件体系,以下从核心功能、技术特性、应用场景及发展趋势展开解读:   应用案例   目前,已有多个电磁数据展示系统在实际应用中取得了显著成效。例如,北京华盛恒辉和北京五木恒润电磁数据展示系统。这些成功案例为电磁数据展示系统的推广和应用提供了有力支持。   一、核心功能模块   数据采集与预处理   智能分析处理   集成频谱分析、时频变换等信号处理算法,自动提取时域频域特征;
    华盛恒辉l58ll334744 2025-05-13 10:20 50浏览
  • 在 AI 浪潮席卷下,厨电行业正经历着深刻变革。AWE 2025期间,万得厨对外首次发布了wan AiOS 1.0组织体超智能系统——通过AI技术能够帮助全球家庭实现从健康检测、膳食推荐,到食材即时配送,再到一步烹饪、营养总结的个性化健康膳食管理。这一创新之举并非偶然的个案,而是整个厨电行业大步迈向智能化、数字化转型浪潮的一个关键注脚,折射出全行业对 AI 赋能的热切渴求。前有标兵后有追兵,万得厨面临着高昂的研发成本与技术迭代压力,稍有懈怠便可能被后来者赶
    用户1742991715177 2025-05-11 22:44 124浏览
  •   基于 2025 年行业权威性与时效性,以下梳理国内知名软件定制开发企业,涵盖综合型、垂直领域及特色技术服务商:   华盛恒辉科技有限公司:是一家专注于高端软件定制开发服务和高端建设的服务机构,致力于为企业提供全面、系统的开发制作方案。在部队政企开发、建设到运营推广领域拥有丰富经验,在教育,工业,医疗,APP,管理,商城,人工智能,部队软件、工业软件、数字化转型、新能源软件、光伏软件、汽车软件,ERP,系统二次开发,CRM等领域有很多成功案例。   五木恒润科技有限公司:是一家专业的部队信
    华盛恒辉l58ll334744 2025-05-12 16:13 178浏览
  • 在印度与巴基斯坦的军事对峙情境下,歼10C的出色表现如同一颗投入平静湖面的巨石,激起层层涟漪,深刻印证了“质量大于数量”这一铁律。军事领域,技术优势就是决定胜负的关键钥匙。歼10C凭借先进的航电系统、强大的武器挂载能力以及卓越的机动性能,在战场上大放异彩。它能够精准捕捉目标,迅速发动攻击,以一敌多却毫不逊色。与之形成鲜明对比的是,单纯依靠数量堆砌的军事力量,在面对先进技术装备时,往往显得力不从心。这一现象绝非局限于军事范畴,在当今社会的各个领域,“质量大于数量”都已成为不可逆转的趋势。在科技行业
    curton 2025-05-11 19:09 197浏览
  • 【拆解】+CamFi卡菲单反无线传输器拆解 对于单反爱好者,想要通过远程控制自拍怎么办呢。一个远程连接,远程控制相机拍摄的工具再合适不过了。今天给大伙介绍的是CamFi卡菲单反无线传输器。 CamFi 是专为数码单反相机打造的无线传输控制器,自带的 WiFi 功能(无需手机流量),不但可通过手机、平板、电脑等设备远程连接操作单反相机进行拍摄,而且还可实时传输相机拍摄的照片到 iPad 和电视等大屏设备进行查看和分享。 CamFi 支持大部分佳能和尼康单反相机,内置可充电锂离子电池,无需相机供电。
    zhusx123 2025-05-11 14:14 203浏览
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦