小猫爪:AWR294x学习笔记02-AWR294x之DPM,IPC和Mailbox

  • 1 前言
  • 2 结构关系
  • 3 MailBox简介
  • 4 IPC简介
  • 5 DPM详解
    • 5.1 三种工作模式
      • 5.1.1 Local Domain
      • 5.1.2 Remote Domain
      • 5.1.3 Distributed Domain
    • 5.2 DPM流程的实现
    • 5.3 DPM的函数
    • 5.4 DPM的应用
  • END

1 前言

  这一章稍来微介绍一下AWR294x的核间通信,即DPM,IPC以及Mailbox。

2 结构关系

  首先得搞清楚DPM,IPC和Mailbox三者关系,如下图:

  其中Mailbox很好理解,它其实就是一个专门实现核间通信的硬件外设;而IPC也很容易理解,它其实就是Mailbox的驱动软件;至于DPM它则是基于IPC搭建的一个可执行的软件架构,基于DPM则可以很轻松的实现核间通信管理。

3 MailBox简介

  MailBox是AWR294x的一个硬件外设,它的原理也是非常的简单,其结构如下图:

  通信原理为:每两个核之间都有两块专属RAM,其实一块用来核A读,核B写,而另外一块则是核A写,核B读,因为AWR294x里面有三个独立运行的核,所以这样的RAM共有6块。如果一个核需要给另外一个核发送信息的时候,那么发送核只需要在两个核的专属RAM中事先准备好需要传输的数据,然后再主动发送一个可以触发接收核RECEIVER中断的信号告知接收核有新数据需要读取,接收核读取完RAM中的数据后,则发送一个可以触发发送核Acknowledgment中断的信号告知发送核消息已读取,至此一次完整的核间通信完成。

4 IPC简介

  IPC其实就是MailBox的底层驱动,,打开mmWave的SDK包,可以发现IPC分为了ipc_notify和ipc_rpmsg,其中ipc_notify实现了发送信号量,而ipc_rpmsg则是在ipc_notify的基础上实现了发送数据包。

  在这里就不多说什么了,感兴趣的小伙伴可以去翻看一下源码了解一下。

5 DPM详解

  DPM(Data Path Manager)是一个完整的软件架构,或者说是一个软件服务,只需要将其移植进软件中,就可以在这个软件架构上实现我们想要的功能,接下来看看它的架构是怎样的。

5.1 三种工作模式

  首先DPM规定了其工作的三种模式,分别是Local Domian,Remote Domain,Distributed Domain,这三种的区别在于其在DPM架构中为控制端还是执行端。每个核可以给本身发送命令,也可以给其他核发送命令,当然也可以接收命令并执行,可以向另一个核发送命令的一端称为控制端,而接收另外一个核的命令并执行的一端被称为执行端。

5.1.1 Local Domain

  这种模式下,只有一个核具有DPM服务,如下所示:

  如上图,DPM工作在Local Domain模式下,MSS端本身不仅作为控制端,也作为执行端,MSS端只能给自己发送命令,并且自己解析命令并执行。在这个模式下,并没有第二个核来参与。

5.1.2 Remote Domain

  这种模式下,需要两个核来运行DPM服务,举个例子如下:

  如上图,DPM工作在Remote Domain模式下,MSS端作为控制端,而DSS端作为执行端,此时MSS端可以给DSS发送命令,而DSS作为执行端,接收MSS的命令并执行。

5.1.3 Distributed Domain

  这种模式下,需要两个核来运行DPM服务,举个例子如下:


  如上图,DPM工作在Distributed Domain模式下,MSS端作为控制端的同时也作为执行端,而DSS端也是同样如此,两者互相发送和接收MSS的命令并执行。

5.2 DPM流程的实现

  那DPM建立了一个什么样的软件机制来实现核间通信的呢?

  DPM服务本身具有一个操作解释器,不管是控制端还是执行端,为了完成一次行为都需要发起或者接收一个或者多个操作,然后去执行,比如说有初始化操作,开始服务操作以及停止服务操作等。为此DPM定义了一个操作队列,DPM在运行时会根据目的需求往这个操作队列里面插入操作元素从而来发起操作,然后DPM就会从队列中读取操作并执行。DPM中定义了如下操作类型:

操作类型 描述 操作端
DPM_MessageId_START 启动DPM服务 控制端和执行端分别发起和执行
DPM_MessageId_STOP 停止DPM服务 控制端和执行端分别发起和执行
DPM_MessageId_DPC_CFG DPC配置,可自定义子类型,通常用其从控制端向执行端传输信息 控制端发起,执行端执行
DPM_MessageId_BSS_FAULT CPU/ESM错误报告 控制端发起,执行端执行
DPM_MessageId_DPC_ASSERT ASSERT报告 控制端和执行端分别发起和执行
DPM_MessageId_RESULT 结果反馈,执行端执行操作后向控制端反馈执行结果 执行端发起和控制端执行
DPM_MessageId_DPC_INFO 输出DPC信息 控制端和执行端分别发起和执行
DPM_MessageId_RESPONSE 操作响应,控制端和执行端执行操作后的响应 控制端和执行端分别发起和执行

  如果想要实现一个行为的话就需要单个或者多个操作相互组合才能实现,这样说可能比较抽象,接下来举个非常通用的例子就是,如果想实现从MSS端给DSS端发送命令或者数据的功能,那么在DPM中是怎样的一个过程呢?首先需要使用DPC配置操作来传输数据或者命令,流程如下图:

#mermaid-svg-UJvNPZmjH4ScLclN {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-UJvNPZmjH4ScLclN .error-icon{fill:#552222;}#mermaid-svg-UJvNPZmjH4ScLclN .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UJvNPZmjH4ScLclN .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-UJvNPZmjH4ScLclN .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UJvNPZmjH4ScLclN .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UJvNPZmjH4ScLclN .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UJvNPZmjH4ScLclN .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UJvNPZmjH4ScLclN .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UJvNPZmjH4ScLclN .marker.cross{stroke:#333333;}#mermaid-svg-UJvNPZmjH4ScLclN svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UJvNPZmjH4ScLclN .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UJvNPZmjH4ScLclN text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-UJvNPZmjH4ScLclN .actor-line{stroke:grey;}#mermaid-svg-UJvNPZmjH4ScLclN .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-UJvNPZmjH4ScLclN .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-UJvNPZmjH4ScLclN #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-UJvNPZmjH4ScLclN .sequenceNumber{fill:white;}#mermaid-svg-UJvNPZmjH4ScLclN #sequencenumber{fill:#333;}#mermaid-svg-UJvNPZmjH4ScLclN #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-UJvNPZmjH4ScLclN .messageText{fill:#333;stroke:#333;}#mermaid-svg-UJvNPZmjH4ScLclN .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UJvNPZmjH4ScLclN .labelText,#mermaid-svg-UJvNPZmjH4ScLclN .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-UJvNPZmjH4ScLclN .loopText,#mermaid-svg-UJvNPZmjH4ScLclN .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-UJvNPZmjH4ScLclN .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-UJvNPZmjH4ScLclN .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-UJvNPZmjH4ScLclN .noteText,#mermaid-svg-UJvNPZmjH4ScLclN .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-UJvNPZmjH4ScLclN .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UJvNPZmjH4ScLclN .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UJvNPZmjH4ScLclN .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-UJvNPZmjH4ScLclN .actorPopupMenu{position:absolute;}#mermaid-svg-UJvNPZmjH4ScLclN .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-UJvNPZmjH4ScLclN .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-UJvNPZmjH4ScLclN .actor-man circle,#mermaid-svg-UJvNPZmjH4ScLclN line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-UJvNPZmjH4ScLclN :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}MSS(控制端)DSS(执行端)发起启动DPM服务操作并执行发起启动DPM服务操作并执行发起DPC配置操作发起操作响应操作并执行接收并执行DPC配置操作发起操作响应并执行MSS(控制端)DSS(执行端)

5.3 DPM的函数

  DPM可供外部调用的函数如下:

名称 描述
DPM_execute 操作解释器,从操作队列中获取操作并执行,需周期性调用,操作队列为空时,其内的信号量堵塞
DPM_ioctl 发起操作,包括DPC_CFG,DPC_CFG,BSS_FAULT,DPC_INFO,按需调用
DPM_start 启动DPM服务,start-up时调用一次
DPM_sendResult 用于执行端向控制端发送执行结果
DPM_relayResult 用于执行端向控制端发送执行结果,只能在Distributed Domain模式中使用
DPM_stop 停止DPM服务
DPM_notifyExecute post信号量,让DPM_execute执行一次,其实是执行执行端的executeFxn
DPM_synch 完成DPM同步,start-up时在DPM_init后调用一次
DPM_init 初始化DPM,start-up时调用一次
DPM_deinit 复位DPM相关配置

  所以结合DPM的函数,以非Local Domain模式为例,DPM运行Flow如下:

#mermaid-svg-jHw73r6o1GMuDf9H {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-jHw73r6o1GMuDf9H .error-icon{fill:#552222;}#mermaid-svg-jHw73r6o1GMuDf9H .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-jHw73r6o1GMuDf9H .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-jHw73r6o1GMuDf9H .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-jHw73r6o1GMuDf9H .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-jHw73r6o1GMuDf9H .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-jHw73r6o1GMuDf9H .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-jHw73r6o1GMuDf9H .marker{fill:#333333;stroke:#333333;}#mermaid-svg-jHw73r6o1GMuDf9H .marker.cross{stroke:#333333;}#mermaid-svg-jHw73r6o1GMuDf9H svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-jHw73r6o1GMuDf9H .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jHw73r6o1GMuDf9H text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-jHw73r6o1GMuDf9H .actor-line{stroke:grey;}#mermaid-svg-jHw73r6o1GMuDf9H .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-jHw73r6o1GMuDf9H .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-jHw73r6o1GMuDf9H #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-jHw73r6o1GMuDf9H .sequenceNumber{fill:white;}#mermaid-svg-jHw73r6o1GMuDf9H #sequencenumber{fill:#333;}#mermaid-svg-jHw73r6o1GMuDf9H #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-jHw73r6o1GMuDf9H .messageText{fill:#333;stroke:#333;}#mermaid-svg-jHw73r6o1GMuDf9H .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jHw73r6o1GMuDf9H .labelText,#mermaid-svg-jHw73r6o1GMuDf9H .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-jHw73r6o1GMuDf9H .loopText,#mermaid-svg-jHw73r6o1GMuDf9H .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-jHw73r6o1GMuDf9H .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-jHw73r6o1GMuDf9H .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-jHw73r6o1GMuDf9H .noteText,#mermaid-svg-jHw73r6o1GMuDf9H .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-jHw73r6o1GMuDf9H .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jHw73r6o1GMuDf9H .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jHw73r6o1GMuDf9H .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-jHw73r6o1GMuDf9H .actorPopupMenu{position:absolute;}#mermaid-svg-jHw73r6o1GMuDf9H .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-jHw73r6o1GMuDf9H .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-jHw73r6o1GMuDf9H .actor-man circle,#mermaid-svg-jHw73r6o1GMuDf9H line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-jHw73r6o1GMuDf9H :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}MSSDSSDPM_initDPM_initDPM_synchDPM_synchDPM同步完成DPM_startDPM_startDPM_executeDPM_execute在loop期间,控制端根据应用需求调用DPM_ioctl 发起操作loop[DPM_Task]DPM_stopDPM_stopMSSDSS

5.4 DPM的应用

  经过上面的介绍,已经对DPM的软件架构已经有了一定的理解,接下就是怎样在DPM的软件架构中实现我们的应用。首先列举出TI的DPM的例子中对DPM初始化时的代码如下:

    /****************************************************************************** DPM Instance1:* - The DPM Instance is responsible for executing the LL & ML Profiles on the*   MSS and DSS so this is a multiple domain instance.*****************************************************************************/memset ((void *)&dpmInitCfg, 0, sizeof(DPM_InitCfg));/* Initialize the LL Processing Init Argument: */initArg = LL_INIT_ARGUMENT;/* Setup the configuration: */dpmInitCfg.arg              = (void *)&initArg;dpmInitCfg.argSize          = sizeof(initArg);dpmInitCfg.ptrProcChainCfg  = &gLLProfileCfg;dpmInitCfg.instanceId       = LL_DPM_INSTANCE_ID;dpmInitCfg.domain           = DPM_Domain_DISTRIBUTED;dpmInitCfg.reportFxn        = DPMTest_llReportFxn;/* Initialize the DPM Module: */gDPMTestMCB.llDPMHandle = DPM_init (&dpmInitCfg, &errCode);if (gDPMTestMCB.llDPMHandle == NULL){test_print ("Error: Unable to initialize the DPM Module [Error: %d]\n", errCode);MCPI_setFeatureTestResult ("DPM Distributed Domain Initialization", MCPI_TestResult_FAIL);return;}

  对于DPM初始化结构体中的元素如下:

项目 Value
domain 指定DPM的工作模式,Local,Remoted,Distributed
instanceId ID,用来区分不同的DPM服务
arg 初始化处理链的参数
argSize 处理链初始化结构体大小
ptrProcChainCfg 处理链配置指针
reportFxn DPM事件callback函数

  在上面的表格中出现了一个名词叫做处理链(processing chain),这个东西其实就是执行端基于DPM架构建立的执行应用,是执行端对执行行为的具象化,当控制端发出控制命令后,执行端就需要使用处理链对控制端的命令进行执行。

  对于一个完整的DPM应用来说,有两个元素的具象化至关重要,分别是ptrProcChainCfgreportFxn,其中reportFxn相关于DPM的回调函数,当DPM执行完一个操作后都会使用该回调函数报告,对照着源码这个还是很好理解的。

  而另外一个则是ptrProcChainCfg元素,它是一个完整处理链的具象化,处理链是执行端特有的,只有当前核在DPM的角色为执行端,那么才需要具象化这个元素。那么一个完整的处理链需要实现哪些函数呢?查看ptrProcChainCfg的定义如下:

类型 名称 描述
DPM_ProcChainInitFx initFxn 初始化处理链相关配置,在DPM_init中被调用
DPM_ProcChainStartFxn startFxn 开始处理链,在DPM_start发起启动DPM服务操作后被调用
DPM_ProcChainExecuteFxn executeFxn 处理链执行函数, 执行端调用DPM_notifyExecute后在DPM_execute中被调用,并返回处理结果
DPM_ProcChainIoctlFxn ioctlFxn 当控制端发出DPM_ioctl后触发DPC_CFG操作后,执行端接收DPC_CFG操作命令被调用
DPM_ProcChainStopFxn stopFxn 停止处理链,DPM_stop发起停止DPM服务操作后被调用
DPM_ProcChainDeinitFxn deinitFxn 复位处理链配置,在DPM_deinit中被调用
DPM_ProcChainInjectDataFxn injectDataFxn 注入数据操作执行函数,在DPM_ioctl触发DPM_CMD_INJECT_DATA类型命令时被调用
DPM_ProcChainChirpAvailableCallbackFxn chirpAvailableFxn chirp event 回调函数,在DPM_chirpISR中断中被调用
DPM_ProcChainFrameStartCallbackFxn frameStartFxn frame event 回调函数,在DPM_frameStartISR中断中被调用

  以上所有处理链的函数并不是完全都是需要的,有些函数是专门针对雷达ADC事件的,如果你只想通过DPM实现简单的核间通讯,只需要完成其中几个函数即可,这些可参考mmWave SDK中的DPM的样例函数,位置处于C:\ti\mmwave_mcuplus_sdk_04_02_00_03\mmwave_mcuplus_sdk_04_02_00_03\ti\control\dpm\test。

END

小猫爪:AWR294x学习笔记02-AWR294x之DPMIPC相关推荐

  1. 小猫爪:AWR294x学习笔记04-AWR294x之ePWM

    小猫爪:AWR294x学习笔记04-AWR294x之ePWM 1 前言 2 框架简介 3 子模块简介 3.1 Time-Base (TB) 3.2 Counter-compare (CC) 3.3 A ...

  2. 小猫爪:AWR294x学习笔记01-AWR294x之MCAN

    小猫爪:AWR294x学习笔记01-AWR294x之MCAN 1 前言 2 MCAN简介 3 Feature描述 3.1 MCAN的工作模式 3.2 Timer Counter 3.3 ECC检测 3 ...

  3. JavaWeb黑马旅游网-学习笔记02【注册功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb黑马旅游网-学习笔记01[准备工作] JavaWeb黑马旅游网-学习笔记02[注册功能] JavaWeb黑马旅游网-学习笔记03[登陆和 ...

  4. JavaWeb-综合案例(用户信息)-学习笔记02【登录功能】

    Java后端 学习路线 笔记汇总表[黑马程序员] JavaWeb-综合案例(用户信息)-学习笔记01[列表查询] JavaWeb-综合案例(用户信息)-学习笔记02[登录功能] JavaWeb-综合案 ...

  5. openCVPracticalExercise学习笔记02

    原创:openCVPracticalExercise学习笔记02 10使用Hu矩进行形状匹配 Hu矩(或者更确切地说是Hu矩不变量)是使用对图像变换不变的中心矩计算的一组7个变量.事实证明,前6个矩不 ...

  6. opencv学习笔记02

    原创博文地址:opencv学习笔记02 OpenCV-Python教程:11.图片阈值 https://www.jianshu.com/p/267a32ad0a23 cv2阈值处理:https://b ...

  7. 【计算机网络学习笔记02】计算机网络概述(中)

    [计算机网络学习笔记02]计算机网络概述(中) 计算机网络的定义.组成与分类 1计算机网络的定义 1.1 简单定义: 一些相互连接的.以共享资源为目的的.自治的计算机的集合. 1.2 通用定义: 利用 ...

  8. 大数据Hadoop教程-学习笔记02【Apache Hadoop、HDFS】

    视频教程:哔哩哔哩网站:黑马大数据Hadoop入门视频教程 教程资源:https://pan.baidu.com/s/1WYgyI3KgbzKzFD639lA-_g 提取码: 6666 [P001-P ...

  9. MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02

    MySQL技术内幕-InnoDB存储引擎第2版-学习笔记-02 6. 锁 ​ 人们认为行级锁总会增加开销.实际上,只有当实现本身会增加开销时,行级锁才会增加开销.InnoDB 存储引擎不需要锁升级,因 ...

  10. Servlet和HTTP请求协议-学习笔记02【Servlet_体系结构与urlpartten配置、HTTP请求协议】

    Java后端 学习路线 笔记汇总表[黑马程序员] Servlet和HTTP请求协议-学习笔记01[Servlet_快速入门-生命周期方法.Servlet_3.0注解配置.IDEA与tomcat相关配置 ...

最新文章

  1. Java使用Optional与Stream来取代if判空逻辑(JDK8以上)
  2. Java与嵌入式数据库SQLite的结合
  3. gorm 返回多条数据_如何优雅的操作数据库?
  4. 【HDU - 2093】 考试排名(排序+格式输出)
  5. 收藏 | 在算法工程师的道路上,你掌握了什么概念或技术使你感觉自我提升突飞猛进?...
  6. vue请求数据传给子组件_vue.js基础,父组件如何向子组件传递数据「607」
  7. [Leetcode] Populating next right pointer in each node ii 填充每个节点的右指针
  8. oracle select输出dbms,PLSQL 中如何使用 dbms_output 输出结果
  9. pdf密码强制解除软件下载 | 专业PDF解密软件 | PDF Decrypter Pro
  10. 如何解决ueditor乱码问题
  11. android系统体系结构,Android系统的五层体系结构解析
  12. 地质勘查土质分类图片_收藏必备!自然资源部:岩石、砾质、土质、泥质统一这样划分!...
  13. 三分钟极速搭建LP框架{{1019}}
  14. UE4C++设置Actor与父Actor的相对位置和相对旋转
  15. flash与PHP的交互技巧
  16. 如何做一个小程序商城,需要多少钱
  17. 空气污染指数API的计算方法
  18. python3爬虫进阶之自动登录网易云音乐并爬取指定歌曲评论
  19. 单片机0 10秒计时C语言,基于单片机的秒,分,时的精确计时实现
  20. 大四阶段的社会实践的主要目的是_大四寒假社会实践报告

热门文章

  1. java自动拼图_java 拼图游戏完整源码,图片剪切,包含拼图自动还原功能
  2. lightoj1138
  3. 人工智能--启发性信息和估价函数
  4. Layui多文件上传,java后台(servlet实现)
  5. 深入理解 Laravel Eloquent(一)——基本概念及用法
  6. Matlab识别拨号音,电话拨号音识别全解.ppt
  7. 超速判断java_汽车超速到底是如何判定的?
  8. Python爬取拉钩招聘网,用数据告诉你这类程序员最赚钱
  9. 如何记忆和使用PNP和NPN?
  10. 关于Binder (AIDL)的 oneway 机制