基于Kithara应用程序开发

Kithara学习资料的获取

Kithara目前官方提供的学习资料主要有如下两个:

  1. 官方网站上的在线文档为了使用户能够迅速学会使用Kithara,Kithara官网上提供了相应的官方文档,以及所有Kithara API的说明,错误代码说明,结构体定义等((用户需要在官网上注册个账户,登录后才能看到))。文档所在官方页面如下: 1709367744441 1709367790791
  2. Kithara安装目录下的示例教程 Kithara安装目录下的示例教程 用户在开发机上安装完Kithara软件后,在安装目录 <Kithara>\smp文件夹下,有基本所有的Kithara功能测试示例程序,用户可以这这些测试程序进行学习。如“EtherCATSimple”例程就是用户学习Kithara EtherCAT主站用法的一个不错的例程。 1709367879621

Kithara软件架构分析

如下图所示,windows系统内存地址分为用户空间(普通Windows应用程序加载的内存空间),和内核空间(windows系统以及驱动加载的空间),这两个不同的内存空间是无法直接相互访问的。为了保证实时性能,Kithara在Windows内核空间构建了一个与windows并行运行的实时子系统,其实时应用程序也必须加载到该实时子系统中,也就是Windows内核空间中运行,才能保证实时性能。为了方便用户编写以及加载实时应用程序到内核,Kithara提供相应的API,从而实时应用程序可以以动态链接库(*.dll)的形式,通过调用Kithara提供的API的方式,加载到实时子系统中.

由于实时应用程序是在Kithara构建的实时子系统中运行,因此其代码(支持C/C++)无法调用Windows系统库,此外C/C++运行时库也不能直接调用。为了解决这个问题,Kithara构建了实时子系统下的系统库,其包括数学处理函数,字符串处理函数,内存处理函数等,能满足基本所有的工业应用程序需求。这些系统库函数在windows下基本都有与其对应的函数,如 KSRTL_sin()对应windows下的sin函数。Kithara内核系统库的详细信息见官网提供的在线文档.

在Kithara实时子系统中,任务(Task,如基于优先级的普通任务、定时器任务、事件触发任务),回调函数(CallBack),共享内存(Share Memory)),事件(Event)),管道(Pipe)),互斥体(Mutex),信号量(Semaphore))等都属于内核资源。为方便用户管理Kithara内核实时应用程序,Kithara提供了一系列API供用户使用。这些API可以在windows普通应用用,目前支持(C/C++,C#Delphi))三种语言。通过这些API用户可以方便的创建并使用这些内核资源,如创建一个内核实时任务,并控制该任务的启停.1709368302265 说明:

  1. 为了实现实时应用程序和windows普通应用程序之间的数据通信和同步,Kithara提供了共享内存、管道、Socket、事件和信号量等资源给用户使用,通过调用其提供的相应的API,用户就可以方便的创建、使用以及销毁这些资源.
  2. 在Kithara内核中,EtherCAT主站任务逻辑还可以使用IEC61131-3规定的ST或IL语言编写后,编译并载入到内核中运行.
  3. EtherCAT总线是工业实时以太网总线的一种,Kithara在内核中实现了EtherCAT主站,从而用户可以非常方便的开发基于EtherCAT总线的运动控制系统。此外用户还可以基于Kithara提供的实时以太网功能模块,自己开发任何需要的基于实时以太网的总线主站.
  4. 在Kithara实时核中可以接收USB3.0或GIGE接口相机采集的图像,并可以在实时核中使用Halcon或OpenCV图像处理库进行处理.
  5. Kithara实时子系统提供了基于优先级,可抢占式的实时多任务运行环境,为了实现更加稳定的实时性能,Kithara还支持用户把指定任务分配在指定的CPU核下,这样通过合理的分配系统的CPU核,既能保证关键任务极其苛刻的实时性要求,也能保证系统的吞吐量,从而能够更加充分利用系统计算性能.

基于Kithara应用编写的一些基本概念

  1. Windows用户层和内核层Windows用户层可以运行普通的windows应用程序,该应用程序可以通过调用Kithara API以及Kithara提供的内核层资源来管理Kithara内核实时应用程序,该程序中使用的指针都是用户层指针。Windows内核层中可以运动Kithara实时应用程序,该程序中使用的指针全部为内核层指针.注意:
  2. 如果在内核层的实时应用中使用用户层指针,可能会导致Windows系统直接蓝屏.
  3. Windows用户层应用程序和内核层实时应用程序不能像普通windows应用程序一样直接相互交互,只能通过Kithara提供的API或内核资源,如共享内存进行交互.
  4. 内核层代码在编写的时候若出现一些错误,如野指针,调用不支持的C/C++运行时库,可能会导致系统蓝屏(绝大部分不会出现蓝屏).
  5. Kithara内核资源 任务:
内核资源名称 说明 部分相关Kithara API
回调函数
(CallBack)
用户可以直接执行内核回调函数,
也可以把回调函数的执行和特定事件绑定
KS_createKernelCallBack
KS_removeCallBack
KS_execKernelFunction
KS_installEcatHandler
KS_installNetworkHandler
普通任务
(Task)
基于优先级(0~255,越大优先级越高),
可抢占式的实时任务.
KS_createTask
KS_triggerTask
KS_killTask
KS_sleepTask
KS_getTaskState
KS_removeTask

数据通讯

内核资源名称 说明 部分相关Kithara API
共享内存
(Share memory)
可实现windows普通应用和内核实时应用数据共享 KS_createSharedMem
KS_freeSharedMem
管道(Pipe) 一种简单且安全的数据通信方案,
可用于普通应用程序和内核实时应用程序之间通信
KS_createPipe
KS_putPipe
KS_getPipe
KS_removePipe
Socket 在Kithara内核层支持Socket KS_openSocket
KS_closeSocket
KS_recvFromSocket
KS_sendToSocket
KS_recvSocket
KS_sendSocket
KS_installSocketHandler
KS_connectSocket
KS_acceptSocket
KS_execSocketCommand

同步

内核资源名称 说明 部分相关Kithara API
事件
(Event)
一种常用的多任务同步方式 KS_createEvent
KS_setEvent
KS_waitForEvent
KS_closeEvent
互斥体
(QuickMutex)
一种常用的数据同步方式 KS_createQuickMutex
KS_requestQuickMutex
KS_releaseQuickMutex
KS_removeQuickMutex
信号量
(Semaphore)
一种多任务之间同步方式 KS_createSemaphore
KS_requestSemaphore
KS_releaseSemaphore
KS_removeSemaphore

详细的Kithara内核资源说明请查看官方在线文档

  1. Kithara API Kithara的所有功能,其都以API的形式提供给用户使用,这些API中有些能在内核实时层中调用,而有些只能在非实时层(即普通windows应用程序)。掌握Kithara API的用法是使用Kithara的基础。按照API的功能其可分为如下三大类型: [1] 实时套件功能模块相关API(KS_XXX()) 其一般在普通windows应用程序中调用(部分也支持在内核实时代码中调用),其都提供三种言语(C/C++、Delphi和C#)的API接口。如,对于打开驱动的API其API接口形式分别如下:
    c/c++
Error KS_openDriver(const char* customerNumber);

Delphi

function KS_openDriver(customerNumber: PAnsiChar): Error;

C#

int KS_openDriver(string customerNumber);

[2] Kithara实时子系统运行时库API(KSRTL_XXX()) 主要有数学计算、字符串处理、内存操作相关API。在Kithara内核实时应用程序中调用。 [3] 用户硬件驱动开发API(KSDRV_XXX()) 用于用户自定义驱动的实现。

基于Kithara应用程序架构

一个基于Kithara的应用工程至少需要一个Kithara内核管理应用程序,以及一个载入到Kithara实时应用程序。 1709369961169 1. 内核管理应用程序
该程序理论上可以是任何一个windows普通应用程序,如Windows C#窗口应用工程,qt工程,MFC工程,windows控制台工程等。其通过调用Kithara提供的API,以及Kithara提供的资源,如共享内存,对以动态连接块形式,对载入到Kithara内核的实时应用程序进行管理,数据通信,同步控制等。
2. Kithara内核的实时应用程序
Kithara内核的实时应用程序,是以动态链接库(*.dll)的形式加载到Kithara实时子系统中。该内核dll模块和Windows普通dll模块相比基本没有什么区别,但需要注意一下几点:
1. 其主入口函数不会调用,但为了dll能够正常编译在程序结构上其还是需要有.

    #include <windows.h>
    // 入口函数在kithara内核中不会调用,但是为了不影响编译,程序结构上需要该函数
    BOOL QINAPI DllMain(HINSTANCE hInstDll, DWORD reson, LPVOID pReserved) {
        return 1;
    }
2. 在dll中,一般要有Kithara内核回调函数,其类似dll导出函数,形式如下:
extern "C" _declspec(dllexport) Error _stdcall _Routine_ExecInitial(void* pArgs, void* pContext) {
        gpSharedMemEcat = (ShareMem_Ecat *)pArgs
        return 0;
}
3. 由于dll载入到windows内核空间,因此其在运行时指针的地址指向windows内核层,因此其创建的指针在普通windows应用中不可以范问.   
4. 无法调用windows系统提供的库,以及C/C++运行时库,只能使用Kithara提供的系统库函数.

Kithara实时应用程序调试方法

应用程序的开发都离不开调试。对于Kithara实时应用程序的调试目前主要有两种方法.
1. 采用普通windows调试器调试程序
为了调试Kithara实时应用程序代码,可以把实时代码加载到windows用户层空间。调试加载到windows用户层空间的Kithara实时代码可以像普通windows应用程序一样,例如用户可以使用Visual studio工具进行单步调试,添加断点等。但是由于实时代码加载到windows用户层空间,因此其与加载到windows内核层空间的代码有如下几个不同:
1. 代码的运行不再具有实时性
2. Kithara实时代码中使用的内核层指针也要变成相应的用户层指针。对于EtherCAT主站,区分用户层指针和内核层指针的,主要是共享内存指针和PDO数据指针,如下:
1. 共享内存指针

CallBackData* pAppPtr;  //应用层数据接口
CallBackData* pSysPtr;  //内核层数据接口
ksError = KS createSharedMem(   
    reinterpret_cast<void**>(&pAppPtr),  reinterpret_cast<void**>(&pSysPtr),   
    NULL,   
    sizeof(CallBackData),   
    0);   
    if (ksError != KS Ok) {
        Demo_OutputKrtsError("Failed to allocate shared memory",ksError);
        return;
    }
  2. PDO数据接口指针
//获职控制字PD0数据接口指针
ksError = KS_getEcatDataObjAddress(   
    pAppPtr->hDataset,   
    pAppPtr->hSlave[index],   
    0x1600,   
    1,   
    (void**)&pAppPtr->slavePDOData_user[index]ptrlWord,   
    (void**)&pAppPtr->slavePDOData_sys[index]ptrlWord,    
    NULL,   
    NULL,   
    0);   
if (ksError != KS_OK) {
    Demo_OutputKrtsError("KS_getEcatDataObjAddress Error",ksError);
    return;
}
  1. Kithara实时代码使用的资源(如网卡、事件、回调函数、定时器等)也必须是用户层的资源
    Kithara很多API都有个flags参数,其不同的数值表示代码在相应层次运行,或资源在相应层次创建。如下KS_LoadKernel()函数所示,当代码在实时核下正常运行时,flags参数必须和KSF_KERNEL_EXEC相或,当需要像普通应用程序一样调试实时代码时,该flag必须是0.
    1709371451006
    同样对于像打开网卡(KS_openAdapter),创建Event(KS_createEvent),创建回调函数(KS_createKernelCallBack),创建定时器(KS_createTimer),执行内核回调函数(KS_execKernelFunction)等,Kithara API 为了在不同模式下切换,也需要设置不同的flags参数

  2. 通过kithara提供的“Kithara Kernel Tracer”工具进行调试
    对于windows调试器,其对于调试普通的单线程任务特别合适。但是对于多线程,多处理器的系统,采用这种方式调试一般会遇到如下几个常见问题.

    1. 系统的多个任务之间的同步关系,或时序关系被打乱,导致可能调试的时候没问题,但真正运行的时候却出现了问题.
    2. 系统的多个线程混合在一起,导致无法调试.
    3. 无法在实时的模式下进行调试.
      因此,为了解决这个问题,Kithara就开发了一个“Kithara kernel tracer”工具,供用户调试内核实时代码使用。该工具的界面如下所示,其在windows下是一个可执行程序,用户在运行Kithara应用程序前,运行该工具,系统就能把调试信息(包括Kithara函数的调用,Kithara内核提示、警告及错误信息,用户自定义信息)按照其真实的执行顺序,动态的打印到该工具相应页面中。此外该工具还提供了信息的筛选,过滤等功能,从而方便用户快速找到需要的信息.
      1709371605098
      对于用户自定义的调试信息,用户可以把Kithara安装目录/dev下的Kithara.cpp文件到工程中,而后就能够调用KS_printk()函数,打印需要的信息。其主要能够打印文本数据和int型数据,用法如下:
int intData = 0;
KS_printK("User debug text infomation");
KS_printK("User debug int data value %d", intData);

为了打印浮点数据,用户可以把浮点数,根据精度要求乘以一个整数,如1000,转换成整数后在打印出来.