当前位置:网站首页>【Autosar 十四 启动流程详解】
【Autosar 十四 启动流程详解】
2022-07-05 18:25:00 【柯宇谦】
Autosar 十四 启动流程详解

链接文件:
1. vLinkGen_Template.lsl
这里注明了起始函数为:brsStartupEntry 函数;
"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函数如下,接下来我们来讲讲这个函数具体干了些什么:
2.1 配置的内存区域归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*/
代码很简单,最重要的就是 vLinkGen_ZeroInit_Early_GroupsSet 这个结构体了,定义在:
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
};
从这里可以看出启动流程最开始,只定义Core0内存的起始和结束地址,并将这片内存区域请0:
内存的起始地址和结束地址
- /* .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 设置栈指针
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))
},
...
}
在
Os_Link_Core0.lsl
也能找到各个核的内存地址分配
#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 设置PSW
Program Status Word(PSW)
BRS_MOVE_TO_CSFR(BRS_PSW_OFFSET, 0x00000B80UL);
2.4 配置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 配置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 中断向量表设置
/* 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();

这个函数中最主要的作用是对内存区域进行操作(清零与赋值)
然后进入main();函数中
4.BrsMain.c

在main()函数中首先初始化每个核的中断向量表
/* 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__));
紧接着初始化RTE
Os_InitMemory();
Os_Init();
然后EcuM模块接管系统
5.EcuM.c

5.1 设置ECU 启动模式
/* Set the current state of the EcuM to STARTUP */
EcuM_SetModuleState(ECUM_STATE_STARTUP); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.2 使能中断
/* #30 Set the interrupts on ECUs with programmable interrupts (EcuM_AL_SetProgrammableInterrupts). */
EcuM_AL_SetProgrammableInterrupts();
5.3 驱动链表清零
/* #31 Initialize BSW that do not use PostBuild parameters (DriverInitListZero). */
ECUM_DRIVERINITLIST_ZERO();
5.4 清除唤醒中断源
/* Clear wakeups from all sources */
EcuM_InternalClearWakeupEvent( ECUM_WKSOURCE_ALL_SOURCES);
5.5 重置超时唤醒
/* 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 设置EcuM模式
/* Set the current state of the EcuM */
EcuM_SetModuleState(ECUM_STATE_STARTUP_ONE); /* SBSW_ECUM_CSL_VAR_ACCESS */
5.7 启动OS
/* #51 Start the AUTOSAR OS with the corresponding default appMode. */
EcuM_StartOS( EcuM_GetDefaultAppMode());
6.EcuM_Callout_Stubs.c

EcuM接管OS 启动后 会根据核ID 依次启动除了启动核之外的核。
StartCore(coreId, &status);
最后 启动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. */
}
边栏推荐
- ConvMAE(2022-05)
- Let more young people from Hong Kong and Macao know about Nansha's characteristic cultural and creative products! "Nansha kylin" officially appeared
- 如何获取飞机穿过雷达两端的坐标
- Whether to take a duplicate subset with duplicate elements [how to take a subset? How to remove duplicates?]
- Can communication of nano
- 常见时间复杂度
- 金太阳开户安全吗?万一免5开户能办理吗?
- Reptile 01 basic principles of reptile
- websocket 工具的使用
- Xiaobai getting started with NAS - quick building private cloud tutorial series (I) [easy to understand]
猜你喜欢

解决 contents have differences only in line separators

About statistical power

How to automatically install pythn third-party libraries

记录Pytorch中的eval()和no_grad()

The 10th global Cloud Computing Conference | Huayun data won the "special contribution award for the 10th anniversary of 2013-2022"

第十一届中国云计算标准和应用大会 | 华云数据成为全国信标委云计算标准工作组云迁移专题组副组长单位副组长单位

Record a case of using WinDbg to analyze memory "leakage"

彻底理解为什么网络 I/O 会被阻塞?

Nacos distributed transactions Seata * * install JDK on Linux, mysql5.7 start Nacos configure ideal call interface coordination (nanny level detail tutorial)

Privacy computing helps secure data circulation and sharing
随机推荐
线性表——抽象数据类型
Vulnhub's darkhole_ two
node_exporter内存使用率不显示
The 10th global Cloud Computing Conference | Huayun data won the "special contribution award for the 10th anniversary of 2013-2022"
在通达信上做基金定投安全吗?
Exemple Quelle est la relation entre le taux d'échantillonnage, l'échantillon et la durée?
MYSQL中 find_in_set() 函数用法详解
Failed to virtualize table with JMeter
rust统计文件中单词出现的次数
分享:中兴 远航 30 pro root 解锁BL magisk ZTE 7532N 8040N 9041N 刷机 刷面具原厂刷机包 root方法下载
第十届全球云计算大会 | 华云数据荣获“2013-2022十周年特别贡献奖”
Use of websocket tool
Introduction to the development function of Hanlin Youshang system of Hansheng Youpin app
[use electron to develop desktop on youqilin]
How to obtain the coordinates of the aircraft passing through both ends of the radar
buuctf-pwn write-ups (9)
LeetCode 6111. Spiral matrix IV
英语句式参考
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!
ClickHouse(03)ClickHouse怎么安装和部署