当前位置:网站首页>[detailed explanation of AUTOSAR 14 startup process]
[detailed explanation of AUTOSAR 14 startup process]
2022-07-05 18:43:00 【Ke Yuqian】
Autosar fourteen Start up process details

Link to the file :
1. vLinkGen_Template.lsl
It is noted here that the starting function is :brsStartupEntry function ;
"StartupEntry" = "brsStartupEntry";
"_start_tc0_asr" = "brsStartupEntry";
"_start_tc1_asr" = "brsStartupEntry";
"_start_tc2_asr" = "brsStartupEntry";
"_start_tc3_asr" = "brsStartupEntry";
"_start_tc4_asr" = "brsStartupEntry";
"_start_tc5_asr" = "brsStartupEntry";
2. BrsHwStartup.c
brsStartupEntry Function as follows , Next, let's talk about what this function does :
2.1 The configured memory area belongs to 0
#if defined (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS)
# if (VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL)
/* Loop over all entries of vLinkGen_ZeroInit_Early_Groups and zero the configured memory areas. */
volatile uint32 *memPtr2;
uint8 areaNum;
for(areaNum = 0; areaNum < vLinkGen_ZeroInit_Early_GroupsSet.Num; areaNum++)
{
if(vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Core == CurrentCoreId &&
(vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].End - vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Start) > 0)
{
memPtr2 = (volatile uint32 *)vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].Start;
while((uint32)memPtr2 < vLinkGen_ZeroInit_Early_GroupsSet.Areas[areaNum].End)
{
*memPtr2 = 0x0;
memPtr2++;
}
}
}
# endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS>1uL*/
#else
#error "Mandatory define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS missing within vLinkGen configuration!"
#endif /*VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS*/
The code is simple , The most important thing is vLinkGen_ZeroInit_Early_GroupsSet This structure , It's defined in :
vLinkGen_Lcfg.c
vLinkGen_Cfg.h
typedef struct
{
/*! Start address of the memory area. */
uint32 Start;
/*! End address of the memory area. */
uint32 End;
/*! Core ID to perform the initialization. */
uint32 Core;
/*! ECC alignment of memory area in bytes. */
uint32 Alignment;
} vLinkGen_MemArea;
typedef struct
{
/*! Number of memory areas in this set. */
uint32 Num;
/*! Table of generic memory areas. */
const vLinkGen_MemArea *Areas;
} vLinkGen_MemAreaSet;
# define VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS 2uL
const vLinkGen_MemArea vLinkGen_ZeroInit_Early_Groups[VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS] =
{
{
/* Brs_Shared_Var */
/* .Start */ (uint32)_Brs_Shared_Var_START,
/* .End */ (uint32)_lc_ge_Brs_Shared_Var,
/* .Core */ 0uL,
/* .Alignment */ 0uL
},
{
0uL,
0uL,
0uL,
0uL
}
};
const vLinkGen_MemAreaSet vLinkGen_ZeroInit_Early_GroupsSet =
{
VLINKGEN_CFG_NUM_ZERO_INIT_EARLY_GROUPS,
vLinkGen_ZeroInit_Early_Groups
};
It can be seen from here that the starting process starts , Define only Core0 Start and end addresses of memory , And send this memory area to 0:
Start address and end address of memory
- /* .Start */ (uint32)_Brs_Shared_Var_START,
- /* .End */ (uint32)_lc_ge_Brs_Shared_Var,
vLinkGen_Template.lsl
group Brs_Shared_Var_PAD (align = 4)
{
reserved "Brs_Shared_Var_PAD" (size = 0);
}
"_Brs_Shared_Var_START" = "_lc_gb_Brs_Shared_Var";
"_Brs_Shared_Var_END" = ("_lc_ge_Brs_Shared_Var" == 0) ? 0 : "_lc_ge_Brs_Shared_Var" - 1;
"_Brs_Shared_Var_LIMIT" = "_lc_ge_Brs_Shared_Var";
"_Brs_Shared_Var_ALL_START" = "_Brs_Shared_Var_START";
"_Brs_Shared_Var_ALL_END" = "_Brs_Shared_Var_END";
"_Brs_Shared_Var_ALL_LIMIT" = "_Brs_Shared_Var_LIMIT";
}
xxx.mapxml
<row>0x7002f920;_lc_gb_Brs_Shared_Var_GROUP;mpe:vtc:linear</row>
<row>0x7002f920;_lc_gb_Brs_Shared_Var;mpe:vtc:linear</row>
...
<row>0x7002f922;_lc_ge_Brs_Shared_Var;mpe:vtc:linear</row>
<row>0x7002f922;_lc_ge_Brs_Shared_Var_GROUP;mpe:vtc:linear</row>
2.2 Set the stack pointer
uint32 CurrentCoreConfig = 0;
uint32 i;
for (i=0; i<BrsMain_CoreConfig_Size; i++)
{
if (BrsMain_CoreConfig[i].PhysicalCoreId == CurrentCoreId)
{
CurrentCoreConfig = i;
i=BrsMain_CoreConfig_Size+1;
}
}
/* Check, if no valid core config was found */
if (i==BrsMain_CoreConfig_Size)
BrsMainExceptionStartup();
BRS_SET_SP(BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel);
typedef struct
{
/* Logical Id of configured core. */
uint32 LogicalCoreId;
/* Phyiscal Id of configured core. */
uint32 PhysicalCoreId;
/* End label of the startup stack. */
Brs_AddressOfConstType StartupStackEndLabel;
/* startup stack size */
uint32 StartupStackSize;
/* Reflects if core is an AUTOSAR core. */
brsCoreAsrType CoreIsAsr;
/* Start label of the exception vector table. */
Brs_AddressOfConstType ExcVecLabel;
/* Start label of the interrupt vector table. */
Brs_AddressOfConstType IntVecLabel;
}brsMain_CoreType;
const brsMain_CoreType BrsMain_CoreConfig[6u] =
{
{
/* .LogicalCoreId = */ 0u,
/* .PhysicalCoreId = */ 0u,
/* .StartupStackEndLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_STARTUP_STACK(0)),
/* .StartupStackSize = */ 10240u,
/* .CoreIsAsr = */ ASR,
/* .ExcVecLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_EXCVEC(0)),
/* .IntVecLabel = */ (Brs_AddressOfConstType)(&BRSHW_DEFINE_INTVEC(0))
},
...
}
stay
Os_Link_Core0.lsl
You can also find the memory address allocation of each core
#if defined ( OS_LINK_EXCVEC_CODE )
if (exists(".text.OS_EXCVEC_CORE0_CODE"))
{
group OS_EXCVEC_CORE0_CODE_GROUP(align=256)
{
select "[.]text.OS_EXCVEC_CORE0_CODE";
}
"_OS_EXCVEC_CORE0_CODE_START" = "_lc_gb_OS_EXCVEC_CORE0_CODE_GROUP";
"_OS_EXCVEC_CORE0_CODE_END" = "_lc_ge_OS_EXCVEC_CORE0_CODE_GROUP" - 1;
"_OS_EXCVEC_CORE0_CODE_LIMIT" = "_lc_ge_OS_EXCVEC_CORE0_CODE_GROUP";
}
else
{
"_OS_EXCVEC_CORE0_CODE_START" = 0;
"_OS_EXCVEC_CORE0_CODE_END" = 0;
"_OS_EXCVEC_CORE0_CODE_LIMIT" = 0;
}
#endif
2.3 Set up PSW
Program Status Word(PSW)
BRS_MOVE_TO_CSFR(BRS_PSW_OFFSET, 0x00000B80UL);
2.4 To configure PCIX
CPUx Previous Context Information Register(PCIX)
AuxVariable = BRS_MOVE_FROM_CSFR(BRS_PCXI_OFFSET);
AuxVariable &= 0xfff00000UL;
BRS_MOVE_TO_CSFR(BRS_PCXI_OFFSET, AuxVariable);
2.5 To configure CSA
The Context Save Areas (CSA)
/* =========================================================================== */
/* initialize the CSAs (inlined function) */
/* aftwerwards function calls are possible */
/* =========================================================================== */
BRS_CSA_Element* CSA;
uint32 NumberOfCSA;
uint32 pcxi_val = 0; /* the last PCXI has to point to 0 */
uint32 CSAReserve = 20; /* the LCX will be initalized to point to 20 CSAs before the very last CSA */
uint32 seg_nr, seg_idx; /* auxiliary variables to assemble the PCXI value */
BRS_CSA_Element* CSAAddress = (BRS_CSA_Element*)((uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel - (uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackSize);
uint32 CSA_Numbers = ((uint32)BrsMain_CoreConfig[CurrentCoreConfig].StartupStackEndLabel - 1024 - (uint32)CSAAddress) / 64;
if (CSA_Numbers<512)
{
/* The configured stack size is smaller than the recommended one! * Beginning with vBaseEnv 2.17, the startup stack setup was harmonized and the stack sizes are configured automatically via the vBRS generator * (vBRS/vBRSGeneral/vBRSEnableCoreSpecificVLinkGenConfig). * The recommended default for the Aurix platforms is 33792 Byte, listed in vBaseEnv/vBaseEnvGeneral/vBaseEnvStartupStackSettings/vBaseEnvStackSize. * This means, 1024 Byte for the startup stack and 512 CSA list entries (64 Byte each). There is no separated section for the CSAs anymory, * they are placed in STACK_Cx, together with the startup stack. Be aware, that the CSAs are shared across all execution instances * (vBRS/vBRSGeneral/vBRSExecutionInstance). All instances inherit it from the first execution instance (vBRS/vBRSGeneral/vBRSFirstInstance). * Uncomment this loop, if you intentionally reduced the size of STACK_Cx and ensure it is suitable for your project. * Otherwise, please increase the size of STACK_Cx to at least 33792 (vLinkGenVarSectionGroup/vLinkGenVarSectionGroupSize). */
// while (1);
}
if(CSAAddress != 0)
{
CSA = CSAAddress;
for (NumberOfCSA=0; NumberOfCSA < CSA_Numbers; NumberOfCSA++) /* loop over all CSA elements */
{
*CSA[0] = pcxi_val; /* *CSA is equal to CSA[0] is equal to CSA.PCXI (it holds the PCXI value and has to point to the next PCXI) */
/* now translate the current CSA address to a valid PCXI value which is used within the AURIX registers */
seg_nr = (((unsigned int)CSA >> 28) & 0xf) << 16;
seg_idx = (((unsigned int)CSA >> 6) & 0xffff);
pcxi_val = seg_nr | seg_idx;
if (NumberOfCSA == CSAReserve) /* reserve CSAs for exception handling */
{
BRS_MOVE_TO_CSFR(BRS_LCX_OFFSET, pcxi_val);
}
CSA++; /* point to the next CSA */
}
BRS_MOVE_TO_CSFR(BRS_FCX_OFFSET, pcxi_val);
}
2.6 Interrupt vector table settings
/* Program the brs default vector table base addresses to handle exceptions during startup */
BrsHw_ExceptionTable_Init((Brs_AddressOfConstType)&_Brs_ExcVect_START, BRS_DEFINE_ADDRESS_UNUSED);
3.BrsMainStartup.c
Brs_ApplicationEntry();

The main function of this function is to operate on the memory area ( Clear and assign )
Then enter main(); Function
4.BrsMain.c

stay main() Function, first initialize the interrupt vector table of each core
/* Search for valid Exception- and Interrupt Table in BrsMain_CoreConfig[] (vBRS generated into vBrs_Lcfg.c) */
for (i=0; i<BrsMain_CoreConfig_Size; i++)
{
if (BrsMain_CoreConfig[i].PhysicalCoreId == coreID)
{
BrsHw_ExceptionTable_Init(BrsMain_CoreConfig[i].ExcVecLabel, BrsMain_CoreConfig[i].IntVecLabel);
i=BrsMain_CoreConfig_Size+1;
}
}
/* Check, if no valid core config was found */
if (i==BrsMain_CoreConfig_Size)
BrsMainExceptionHandler(kBrsInvalidCoreConfig, BRSERROR_MODULE_BRSMAIN, (uint16)(__LINE__));
And then initialization RTE
Os_InitMemory();
Os_Init();
then EcuM The module takes over the system
5.EcuM.c

5.1 Set up ECU Boot mode
/* Set the current state of the EcuM to STARTUP */
EcuM_SetModuleState(ECUM_STATE_STARTUP); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.2 To interrupt
/* #30 Set the interrupts on ECUs with programmable interrupts (EcuM_AL_SetProgrammableInterrupts). */
EcuM_AL_SetProgrammableInterrupts();
5.3 Drive list reset
/* #31 Initialize BSW that do not use PostBuild parameters (DriverInitListZero). */
ECUM_DRIVERINITLIST_ZERO();
5.4 Clear the wake-up interrupt source
/* Clear wakeups from all sources */
EcuM_InternalClearWakeupEvent( ECUM_WKSOURCE_ALL_SOURCES);
5.5 Reset timeout wake
/* Reset all wakeup validation timeouts */
for (loopCount = 0u; loopCount < EcuM_GetSizeOfWakeupSourceList(); loopCount++) /* PRQA S 2812 */ /* MD_EcuM_2812 */
{
EcuM_SetValidationTimeoutTable(loopCount, ECUM_NO_VALIDATION_TIMEOUT); /* SBSW_ECUM_ACCESSVALTABLE */
}
5.6 Set up EcuM Pattern
/* Set the current state of the EcuM */
EcuM_SetModuleState(ECUM_STATE_STARTUP_ONE); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.7 start-up OS
/* #51 Start the AUTOSAR OS with the corresponding default appMode. */
EcuM_StartOS( EcuM_GetDefaultAppMode());
6.EcuM_Callout_Stubs.c

EcuM To take over OS After starting According to the nuclear ID Start the cores other than the startup core in turn .
StartCore(coreId, &status);
Last start-up OS
StartOS(appMode);
7.Os_Trap.c
StartCore(coreId, &status);
FUNC(void, OS_CODE) StartCore /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
(
CoreIdType CoreID,
StatusType *Status
)
{
/* #10 If the given status pointer is valid: */
if(OS_UNLIKELY(Os_ErrCheckPointerIsNotNull(Status) != OS_CHECK_FAILED)) /* PRQA S 0315 */ /* MD_Os_Dir1.1_0315 */ /* SBSW_OS_TRAP_ERRCHECKPOINTERISNOTNULL_001 */
{
/* #20 Caller (startup code) is privileged. Call API directly. */
Os_TrapCallStartCore(CoreID, Status); /* SBSW_OS_TRAP_API_USERPOINTER_001 */
}
/* else * Do NOT write the error code to the Status pointer, as it is a NULL_PTR! */
}
OS_FUNC_ATTRIBUTE_DEFINITION(OS_LOCAL_INLINE void, OS_CODE, /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
OS_ALWAYS_INLINE, Os_TrapCallStartCore,
(
CoreIdType CoreID,
StatusType *Status
)) /* COV_OS_HALPLATFORMTESTEDASMULTICORE */
{
/* #10 Inform the trace module on service function entry. */
Os_TraceOrtiApiEntry(OsOrtiApiIdStartCore);
/* #20 Call the API. */
Os_Api_StartCore(CoreID, Status); /* SBSW_OS_FC_PRECONDITION */
/* #30 Inform the trace module on service function exit. */
Os_TraceOrtiApiExit(OsOrtiApiIdStartCore);
}
FUNC(void, OS_CODE) Os_Api_StartCore /* COV_OS_HALPLATFORMMULTICOREUNSUPPORTED */
(
CoreIdType CoreID,
StatusType *Status
)
{
*Status = E_OK; /* PRQA S 2982 */ /* MD_Os_Rule2.2_2982_Config */ /* SBSW_OS_PWA_PRECONDITION */
/* #10 Perform error checks. */
if(Os_CoreIsSingleCoreOs() != 0u) /* COV_OS_TESTSUITERESTRICTIONCORECOUNT */ /* PRQA S 2991, 2992, 2995, 2996 */ /* MD_Os_Rule14.3_2991, MD_Os_Rule14.3_2992, MD_Os_Rule2.2_2995, MD_Os_Rule2.2_2996 */
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else if(OS_UNLIKELY(Os_CoreCheckId(CoreID) == OS_CHECK_FAILED ))
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) core;
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) currentCore;
core = Os_CoreId2Core(CoreID);
currentCore = Os_CoreGetCurrentCore();
if(OS_UNLIKELY(Os_CoreCheckIsAsrCore(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKISASRCORE_001 */
{
*Status = E_OS_ID; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
if(OS_UNLIKELY(Os_CoreCheckCoreIsInactive(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKCOREISINACTIVE_001 */
{
*Status = E_OS_STATE; /* SBSW_OS_PWA_PRECONDITION */
}
else
{
if(Os_CoreIsAsrCore(currentCore) != 0u) /* SBSW_OS_CORE_COREISASRCORE_002 */
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) currentCoreAsr;
currentCoreAsr = Os_Core2AsrCore(currentCore); /* SBSW_OS_CORE_CORE2ASRCORE_002 */
if(OS_UNLIKELY(Os_CoreCheckOsIsNotStarted(currentCoreAsr) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKOSISNOTSTARTED_001 */
{
*Status = E_OS_ACCESS; /* SBSW_OS_PWA_PRECONDITION */
}
}
}
if(OS_LIKELY(*Status == E_OK))
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) coreAsr;
/* #20 Set the core activation request. */
Os_CoreGetStatus(currentCore)->CoreStartRequests[CoreID] = OS_CORESTATE_ACTIVATED_ASR; /* PRQA S 2842 */ /* MD_Os_Rule18.1_2842_Check */ /* SBSW_OS_CORE_COREGETSTATUS_003 */ /* SBSW_OS_CORE_CORESTARTREQUESTS_001 */
coreAsr = Os_Core2AsrCore(core); /* SBSW_OS_CORE_CORE2ASRCORE_001 */
/* #30 Attach to synchronization barrier. */
Os_BarrierAttach(coreAsr->Barrier); /* SBSW_OS_CORE_BARRIERATTACH_001 */
if(core->IsAutostart == TRUE) /* COV_OS_HALPLATFORMNONAUTOSTARTCORE */
{
/* #40 If the core is an auto-start core (already booted), just set the waiting signal. */
OsCfg_CoreBootBarrierRefs[CoreID]->WaitingSign = OS_CORE_BOOTBARRIER_STARTCORE; /* SBSW_OS_CORE_COREBOOTBARRIERREFS_001 */
}
else
{
/* #50 Otherwise start the core through hardware registers. */
Os_Hal_CoreStart(core->HwConfig); /* SBSW_OS_CORE_HAL_CORESTART_001 */
}
}
}
}
}
StartOS(appMode);
FUNC(void, OS_CODE) StartOS
(
AppModeType Mode
)
{
/* #10 Caller (startup code) is privileged. Call API directly. */
Os_TrapCallStartOS(Mode);
}
FUNC(void, OS_CODE) Os_Api_StartOS(AppModeType Mode)
{
/* #10 If the OS is not configured for the interrupt only use case: */
if(Os_CoreIsInterruptOnlyOs() == 0u ) /* PRQA S 2991, 2992, 2995, 2996 */ /* MD_Os_Rule14.3_2991, MD_Os_Rule14.3_2992, MD_Os_Rule2.2_2995, MD_Os_Rule2.2_2996 */
{
P2CONST(Os_CoreConfigType, AUTOMATIC, OS_CONST) core;
core = Os_CoreGetCurrentCore();
/* #10 Check that the core has been started as an AUTOSAR core. */
if(OS_UNLIKELY(Os_CoreCheckStartedAsAsr(core) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKSTARTEDASASR_001 */ /* COV_OS_INVSTATE */
{
Os_ErrKernelPanic();
}
else
{
P2CONST(Os_CoreAsrConfigType, AUTOMATIC, OS_CONST) coreAsr;
coreAsr = Os_Core2AsrCore(core); /* SBSW_OS_CORE_CORE2ASRCORE_002 */
/* #20 Check that StartOS() was not called before. */
if(OS_UNLIKELY(Os_CoreCheckOsIsNotStarted(coreAsr) == OS_CHECK_FAILED)) /* SBSW_OS_CORE_CORECHECKOSISNOTSTARTED_001 */ /* COV_OS_INVSTATE */
{
Os_ErrKernelPanic();
}
else
{
/* #30 Enter the core's Init Hook. */
Os_HookCallOs_CoreInitHook(Os_CoreGetInitHook(coreAsr), Mode); /* SBSW_OS_CORE_COREGETINITHOOK_001 */ /* SBSW_OS_CORE_HOOKCALLOS_COREINITHOOK_001 */
}
}
}
/* #50 Else ignore the call. */
}
边栏推荐
- RPC协议详解
- Rse2020/ cloud detection: accurate cloud detection of high-resolution remote sensing images based on weak supervision and deep learning
- 进程间通信(IPC):共享内存
- sample_rate(采样率),sample(采样),duration(时长)是什么关系
- node_exporter内存使用率不显示
- 7-2 保持链表有序
- rust统计文件中单词出现的次数
- Introduction to Resampling
- ROS安装报错 sudo: rosdep:找不到命令
- Pytorch yolov5 training custom data
猜你喜欢

Use QT to traverse JSON documents and search sub objects

The 11th China cloud computing standards and Applications Conference | cloud computing national standards and white paper series release, and Huayun data fully participated in the preparation

LeetCode 6109. 知道秘密的人数

企业数字化转型之路,从这里开始

Trust counts the number of occurrences of words in the file

技术分享 | 接口测试价值与体系

FCN: Fully Convolutional Networks for Semantic Segmentation

LeetCode 6111. 螺旋矩阵 IV

达梦数据库udf实现

AI金榜题名时,MLPerf榜单的份量究竟有多重?
随机推荐
IDEA配置npm启动
一文读懂简单查询代价估算
Insufficient picture data? I made a free image enhancement software
The worse the AI performance, the higher the bonus? Doctor of New York University offered a reward for the task of making the big model perform poorly
sample_ What is the relationship between rate, sample and duration
MySQL优化六个点的总结
Reading notes of Clickhouse principle analysis and Application Practice (5)
Introduction to Resampling
JDBC reads a large amount of data, resulting in memory overflow
The main thread anr exception is caused by too many binder development threads
紧固件行业供应商绩效考核繁琐?选对工具才能轻松逆袭!
Is it safe for Apple mobile phone to speculate in stocks? Is it a fraud to get new debts?
Is it safe to make fund fixed investment on access letter?
The 2022 China Xinchuang Ecological Market Research and model selection evaluation report released that Huayun data was selected as the mainstream manufacturer of Xinchuang IT infrastructure!
rust统计文件中单词出现的次数
Precautions for RTD temperature measurement of max31865 module
U-Net: Convolutional Networks for Biomedical Images Segmentation
Idea configuring NPM startup
如何获取飞机穿过雷达两端的坐标
RPC协议详解