eric2013 发表于 2017-6-1 14:56:08

【原创开源】极具可玩性的高端玩法,使用F429外接32位SDRAM虚拟VNC桌面,无需显示屏

1. 原创开源VNC综合Demo说明:
(1).操作这个例子前,务必要看之前发布的综合Demo演示和使用说明:http://www.armbbs.cn/forum.php?mod=viewthread&tid=17330 ,这个例子是由其修改而来的。依然是采用的RTX系统及其所有中间件。
(2). 这个项目的可玩性极高,可以做很多有意思的应用。做一些远程智能控制尤其方便,省去了学习html,xml,js等麻烦,且无需显示屏。
(3).网络协议栈用的RL-TCPnet,而VNC Server是用的emWin自带的功能。这里是用的我们V6开发板带的32位SDRAM虚拟一个800*480分辨率的界面出来。底层已经全部采用F429的DMA2D进行了优化。手机端和电脑端都可以访问的,这样就省去了使用显示屏的繁琐,而且性能可以发挥到F429外接裸屏的30%-50%,即使是这样,比F407+RA8875还是强很多的。电脑端的VNC比较好用,手机端还没有找到好用的。
(4).我们的又一个史诗级网络协议栈教程正在如火如荼的进展中,初步今年9月份前发布:http://www.armbbs.cn/forum.php?mod=viewthread&tid=26034。
2.版本信息:
RTOS:         RL-RTX      V4.74
File System:RL-FlashFSV4.74
TCP/IP:         RL-TCPnet   V4.74
USB:             RL-USB      V4.74
CAN:            RL-CAN       V4.74
GUI:             emWin         V5.36
Modbus:   Designed by armfly
3.14个任务优先级配置
(1). os_idle_demon,      优先级0:系统空闲任务。
(2). AppTaskStatistic       优先级1:CPU利用率检测。
(3). AppTaskGUI,          优先级3:GUI主任务。
(4). _ServerTask,             优先级4:VNC Server
(5).AppTaskTCPMain,优先级5:TCPnet网络主任务。
(6). AppTaskStart,      优先级7:启动任务。
(7). AppTaskCAN,      优先级8:CAN总线任务。
(8). AppTaskModbus,优先级9:Modbus任务。
(9). AppTaskUSB,          优先级10:USB任务,
(10). AppTaskMusic,       优先级11:音乐任务,用于音乐播放器,视频播放器,录音机和收音机处理。
(11). AppTaskPinDetect, 优先级12:SD卡插拔检测任务。
(12). AppTaskTCPTimer, 优先级13:TCPnet网络定时更新任务。
USB在运行的过程中会创建2两个任务
(14). USBD_RTX_EndPoint0                   优先级2:USB设备端点0任务。
(15). USBD_RTX_MSC_EP_BULK_Event优先级2:USB BULK数据传输任务。
4.15个中断安排
NVIC优先级分组采用4,仅抢占优先级,范围0-15。
LTDC中断,                抢占优先级 0
ETH以太网中断,      抢占优先级 0
USB FS中断,             抢占优先级 0
CAN2 TX中断,          抢占优先级 1
CAN2 RX0中断,      抢占优先级 1
DMA2_Steam5中断,抢占优先级 1
DMA2_Steam1中断,抢占优先级 1
EXTI6中断,               抢占优先级 1
USART3中断,         抢占优先级 2
EXTI2中断,               抢占优先级 2
TIM2中断,                抢占优先级 4
USART1中断,         抢占优先级 13
RTC Alarm中断,       抢占优先级 13
SVC中断,                  抢占优先级 14
Systick中断,             抢占优先级 15
PendSV中断,            抢占优先级 15
5.内存安排
内部SRAM , CCM SRAM和SDRAM安排。
内部192KB SRAM       :80KB用于动态内存分配,其余用于任务堆栈,系统堆栈,文件系统,网络协议栈等。
内部64KB CCM SRAM:用于视频播放器时,JPEG解码。
外部16MB SDRAM   :前4MB用于SDRAM的虚部显示屏。
外部16MB SDRAM   :后12MB用于emWin动态内存。
6. RTX调试组件效果展示


7.开启MDK4.74最高的3级优化,同时开启相当给力的时间优化
https://img.anfulai.cn/dz/attachment/forum/pw/Fid_12/12_58_8c33af3c9f419c9.png?40
==============================================================
原创开源工程下载:

==============================================================
简易视频效果演示,手机简单拍了个,像素稍差些,主要看性能:
https://v.qq.com/x/page/u051675jkpv.html
==============================================================
电脑端使用VNC Client访问部分效果展示,具体可看上面的视频:
主界面效果:


视频播放器效果(GIF格式图片)


音乐播放器效果(GIF格式图片)



RL-TCPnet主界面:


CAN控制界面:


Modbus控制界面:


模拟U盘控制界面:


万年历:




最后来一张实际效果:

liangjn1984 发表于 2017-6-1 15:54:59

wcyingdream 发表于 2017-6-1 16:18:03

lewis 发表于 2017-6-1 17:16:44

学习 !

loliko 发表于 2017-6-2 08:42:18

支持老师

痞爷李 发表于 2017-6-2 09:13:10

这个太赞了

hqgboy 发表于 2017-6-7 15:04:46

好。。。。。。支持。。。。

star_66666 发表于 2017-6-7 15:31:16

太好了,,,,

myxiaonia 发表于 2017-6-9 08:48:40

强烈支持,用这个相当于在线调试了有没有。。。

片羽之神 发表于 2017-6-9 18:43:01

1024

eric2013 发表于 2017-6-18 15:47:51

今天开始加紧收尾,准备开源。

eric2013 发表于 2017-6-19 10:26:12

老虎的菜 发表于 2017-6-19 15:08:34

牛掰

wgh1990 发表于 2017-6-19 15:57:45

不忘初心713 发表于 2017-6-19 16:08:14

gdgn_526345 发表于 2017-6-19 16:33:02

顶顶顶    顶了再顶

xilinx 发表于 2017-6-19 16:56:34

简直吊炸天

qq792368480 发表于 2017-6-19 17:36:24

膜拜和感激

wcyingdream 发表于 2017-6-19 17:40:43

lewis 发表于 2017-6-19 20:27:18

老大牛逼啊

a20084666 发表于 2017-6-19 23:10:12

RL-CAN有那些功能 CANopen? ??

eric2013 发表于 2017-6-20 02:42:06

回 a20084666 的帖子

a20084666:RL-CAN  有那些功能 CANopen? ?? (2017-06-19 23:10) images/back.gif

没有哦,就是一个简单的CAN控制,方便使用了。

a20084666 发表于 2017-6-20 13:26:57

回 eric2013 的帖子

eric2013:没有哦,就是一个简单的CAN控制,方便使用了。 (2017-06-20 02:42) images/back.gif

有没有什么操作系统能够支持这个功能,对can的一些协议做些插件之类的

eric2013 发表于 2017-6-20 14:36:29

回 a20084666 的帖子

a20084666:有没有什么操作系统能够支持这个功能,对can的一些协议做些插件之类的 (2017-06-20 13:26) images/back.gif

可以看看这个两个:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=29575
http://www.armbbs.cn/forum.php?mod=viewthread&tid=19493

myxiaonia 发表于 2017-6-26 11:34:14

太赞了,以后开发带显示屏的程序都不用带屏了,基本类似于模拟器里完成啊,加快开发速度

我之前搞了个树莓派,都是用远程登录玩的

eric2013 发表于 2017-6-27 09:33:00

回 myxiaonia 的帖子

myxiaonia:太赞了,以后开发带显示屏的程序都不用带屏了,基本类似于模拟器里完成啊,加快开发速度

我之前搞了个树莓派,都是用远程登录玩的 (2017-06-26 11:34) images/back.gif

tanic 发表于 2017-7-18 14:56:52

6666,想过把emwin底层驱动 用USB实现,直接打点到PC端虚拟器。
看到这个瞬间感觉想法太年轻了。

myxiaonia 发表于 2017-8-18 09:52:58

回 tanic 的帖子

tanic:6666,想过把emwin底层驱动 用USB实现,直接打点到PC端虚拟器。
看到这个瞬间感觉想法太年轻了。 (2017-07-18 14:56) images/back.gif

如果真这么做就麻烦了,比如linux的图形界面思路就和你类似,是一个cs结构,对于实现各种远程都很容易,糟糕的是本地性能不咋的

其实完全可以用vnc这种做法解决的呀,各司其职才是最好的

打洞者 发表于 2017-9-21 17:19:36

detective 发表于 2017-10-4 19:01:58

这个还会去做支持V5板子的部分吗?

eric2013 发表于 2017-10-4 21:34:05

回 detective 的帖子

detective:这个还会去做支持V5板子的部分吗? (2017-10-04 19:01) images/back.gif

V5性能不行,SRAM是16位接口的。

DAPAIBULO 发表于 2022-9-25 21:32:04

请教硬汉哥, STM32F429+16位SDRAM想实现emwin接RGB接口800*480或1024*600屏幕+VNC桌面可以吗?   另外请教VNC如果不用DM9000这类使用RJ45接口的,而是使用WIFI模块实现功能可以吗?

eric2013 发表于 2022-9-26 02:14:36

DAPAIBULO 发表于 2022-9-25 21:32
请教硬汉哥, STM32F429+16位SDRAM想实现emwin接RGB接口800*480或1024*600屏幕+VNC桌面可以吗?   另外请教 ...

可以,就是速度差些。

yelu 发表于 2024-3-26 22:04:20

eric2013 发表于 2022-9-26 02:14
可以,就是速度差些。

硬汉哥,有V7版本的例子吗,最近想使用VNC,但是连接不上

eric2013 发表于 2024-3-27 10:57:11

yelu 发表于 2024-3-26 22:04
硬汉哥,有V7版本的例子吗,最近想使用VNC,但是连接不上

V7还没弄,后面我搞个。

yelu 发表于 2024-3-27 15:48:34

eric2013 发表于 2024-3-27 10:57
V7还没弄,后面我搞个。

我用的keil的中间件,自动生成的代码没修改,第二张图,连接不上(图三),用wireshark抓包如下(图四,开发板地址是14,电脑是113),调试也发现连接后,GUI_VNC_Process函数立即返回1,然后关闭连接,整了几天了,找不到原因,硬汉哥给点思路

yelu 发表于 2024-3-27 16:35:31

yelu 发表于 2024-3-27 15:48
我用的keil的中间件,自动生成的代码没修改,第二张图,连接不上(图三),用wireshark抓包如下(图四, ...

截图清晰点

eric2013 发表于 2024-3-28 09:46:19

yelu 发表于 2024-3-27 16:35
截图清晰点

这个功能在H7下是一定可以使用的。

yelu 发表于 2024-3-31 20:33:43

eric2013 发表于 2024-3-28 09:46
这个功能在H7下是一定可以使用的。

是的,现在可以使用了
主要是多了一个缓冲区,之前我的例子是和例程一样的,连上就断开,找了新版本的例程就可以使用了
static GUI_VNC_CONTEXT    _Context;
static struct sockaddr_in _Addr;
static U8               _acBuffer;    //多了这个缓冲区

yelu 发表于 2024-3-31 20:49:45

eric2013 发表于 2024-3-28 09:46
这个功能在H7下是一定可以使用的。

但是现在又有一个新的问题,热插拔的问题,现在采用的方案是在检测到linkdown之后重新初始化网络协议栈,就是硬汉哥推荐的方式;但是对于这个VNC的例程插拔网线再重新连接有时候连接上会是黑屏,代码如下:

//检测到 linkdown 之后的重新初始化流程
1. linkdown的时候先 GUI_VNC_X_StopServer
2. 重新初始化网络协议栈
3. GUI_VNC_X_ReStartServer

为什么不直接再次调用函数 GUI_VNC_X_StartServer,实际测试的过程中,发现直接调用该函数的话重新连接就是黑屏,最终通过屏蔽代码的方式发现是 GUI_VNC_AttachToLayer 函数的问题,只要不再次调用 GUI_VNC_AttachToLayer 函数,再次连接可以成功。
但是现在还有一个问题,按照上面所写的流程,大部分的时候是能够连接上的,而且画面都是正常的,但是反复测试(拔网线,重新连接)偶尔会连上就黑屏,而且一旦黑屏后面再连接就一直是黑屏,但是此时网络是能够正常通信的,重启一下,然后再连接画面就正常了,唯一的区别就是GUI也重新初始化了一下。
目前还在看这个问题,硬汉哥有测试这样的情况吗

/*********************************************************************
*                  SEGGER Microcontroller GmbH                     *
*      Solutions for real time microcontroller applications      *
**********************************************************************
*                                                                  *
*      (c) 1996 - 2022SEGGER Microcontroller GmbH                *
*                                                                  *
*      Internet: www.segger.com    Support:support@segger.com    *
*                                                                  *
**********************************************************************

** emWin V6.30 - Graphical user interface for embedded applications **
AllIntellectual Property rightsin the Software belongs toSEGGER.
emWin is protected byinternational copyright laws.Knowledge of the
source code may not be used to write a similar product.This file may
only be used in accordance with the following terms:

The software has been licensed toARM LIMITED whose registered office
is situated at110 Fulbourn Road,Cambridge CB1 9NJ,England solely
forthepurposesofcreatinglibrariesforARM7, ARM9, Cortex-M
series,and   Cortex-R4   processor-baseddevices,sublicensedand
distributed as part of theMDK-ARMProfessionalunder the terms and
conditionsofthe   EndUserLicensesuppliedwiththeMDK-ARM
Professional.
Full source code is available at: www.segger.com

We appreciate your understanding and fairness.
----------------------------------------------------------------------
Licensing information
Licensor:               SEGGER Software GmbH
Licensed to:            ARM Ltd, 110 Fulbourn Road, CB1 9NJ Cambridge, UK
Licensed SEGGER software: emWin
License number:         GUI-00181
License model:            LES-SLA-20007, Agreement, effective since October 1st 2011
Licensed product:         MDK-ARM Professional
Licensed platform:      ARM7/9, Cortex-M/R4
Licensed number of seats: -
-------------------------- END-OF-HEADER -----------------------------

File    : GUI_VNC_X_Keil.c
Purpose : Starts the VNC server via TCP/IP.
          This version works with the Keil MDK-Pro TCP/IP stack.

          Enable the BSD socket component.
          Start by calling GUI_VNC_X_StartServer.

          _ServerTask requires 4096 Bytes of private stack.
          Only 1 client is supported.
*/

#include <stdlib.h>
#include <string.h>

#include "RTE_Components.h"             // Component selection

#ifdef RTE_CMSIS_RTOS2
#include "cmsis_os2.h"                  // ::CMSIS:RTOS2
#else
#include "cmsis_os.h"                   // ::CMSIS:RTOS
#endif

#include "rl_net.h"                     // Keil::Network:CORE
#include "GUI.h"
#include "GUI_VNC.h"

/*********************************************************************
*
*       Defines, configurable
*
**********************************************************************
*/

//
// Define maximum number of VNC clients that can connect
//
#define VNC_MAX_CLIENTS1


/*********************************************************************
*
*       Static data
*
**********************************************************************
*/
static GUI_VNC_CONTEXT    _Context;
static struct sockaddr_in _Addr;
static U8               _acBuffer;


/*********************************************************************
*
*       Local functions
*
**********************************************************************
*/

/*********************************************************************
*
*       _cbVNC_Recv()
*
*Function description
*    This function is called indirectly by the server; it's address
*    is passed to the actual server code as function pointer. It is
*    needed because the server is independent of the TCP/IP stack
*    implementation, so details for the TCP/IP stack can be placed
*    here.
*
*Parameters
*    pData      : Where to store the received data.
*    NumBytes   : Maximum amount of data to receive.
*    pConnection: Connection handle (WebSocket context).
*
*Return value
*    Amount of data received: >0
*    Connection closed      : == 0
*    Error                  : <0
*/
static int _cbVNC_Recv(U8* pData, int NumBytes, void* pConnection) {
return recv((long)pConnection, (char*)pData, NumBytes, 0);
}

/*********************************************************************
*
*       _cbVNC_Send()
*
*Function description
*    This function is called indirectly by the server; it's address
*    is passed to the actual server code as function pointer. It is
*    needed because the server is independent of the TCP/IP stack
*    implementation, so details for the TCP/IP stack can be placed
*    here.
*
*Parameters
*    pData      : Data to send.
*    NumBytes   : Amount of data to send.
*    pConnection: Connection handle.
*
*Return value
*    Amount of data sent: >0
*    Connection closed: == 0
*    Error            : <0
*/
static int _cbVNC_Send(const U8* pData, int NumBytes, void* pConnection) {
return send((long)pConnection, (const char*)pData, NumBytes, 0);
}

/*********************************************************************
*
*       _ListenAtTCPAddr()
*
*Function description
*    Creates a non-blocking socket for accepting a VNC connection.
*
*Parameters
*    Port: Port to use for accepting connections.
*
*Return value
*    Parent socket handle.
*/
static int _ListenAtTCPAddr(U16 Port) {
         int         hSock;
struct sockaddr_in InAddr;

hSock = socket(AF_INET, SOCK_STREAM, 0);
if (hSock <= 0) {
    while (1);// Should not happen.
}
memset(&InAddr, 0, sizeof(InAddr));
InAddr.sin_family      = AF_INET;
InAddr.sin_port      = htons(Port);
InAddr.sin_addr.s_addr = INADDR_ANY;
bind(hSock, (struct sockaddr*)&InAddr, sizeof(InAddr));
listen(hSock, 1);

return hSock;
}


/*********************************************************************
*
*       _ServerTask
*
*Function description
*    This routine is the actual server task.
*    It executes some one-time init code, then runs in an ednless loop.
*    It therefore does not terminate.
*    In the endless loop it
*      - Waits for a conection from a client
*      - Runs the server code
*      - Closes the connection
*/
#ifdef RTE_CMSIS_RTOS2
__NO_RETURN static void _ServerTask(void *arguments) {
#else
__NO_RETURN static void _ServerTask(void const *arguments) {
#endif
int s, Sock, AddrLen;
U16 Port;

(void)arguments;

//
// Prepare socket (one time setup)
//
Port = 5900 + _Context.ServerIndex; // Default port for VNC is is 590x, where x is the 0-based layer index
//
// Loop until we get a socket into listening state
//
do {
    s = _ListenAtTCPAddr(Port);
    if (s != -1) {
      break;
    }
    osDelay(100); // Try again
} while (1);
//
// Loop once per client and create a thread for the actual server
//
while (1) {
    //
    // Wait for an incoming connection
    //
    AddrLen = sizeof(_Addr);
    if ((Sock = accept(s, (struct sockaddr*)&_Addr, &AddrLen)) < 0) {
      continue; // Error
    }
    //
    // Run the actual server
    //
    GUI_VNC_Process(&_Context, _cbVNC_Send, _cbVNC_Recv, (void *)Sock);
    //
    // Close the connection
    //
    closesocket(Sock);
    memset(&_Addr, 0, sizeof(struct sockaddr_in));
}
}

#ifdef RTE_CMSIS_RTOS2
static osThreadId_t s_vncTsakId = NULL;
static uint64_t _ServerTask_stk;
static const osThreadAttr_t _ServerTask_attr = {
.stack_mem= &_ServerTask_stk,
.stack_size = sizeof(_ServerTask_stk)
};
#else
static osThreadDef(_ServerTask, osPriorityNormal, 0, 4096);
#endif

/*********************************************************************
*
*       Global functions
*
**********************************************************************
*/
/*********************************************************************
*
*       GUI_VNC_X_StartServer()
*
*Function description
*    This routine starts a separate task for the VNC server. It
*    requires that the OS and TCP/IP stack are already initialized.
*
*Parameters
*    LayerIndex : Index of the GUI layer that is shown via VNC.
*    ServerIndex: Zero-based server index.
*
*Return value
*    O.K.: 0
*
*Additional information
*    This sample is intended to be used for starting one VNC server.
*    In case multiple layers shall be accessed by different server
*    instances (ServerIndex) this sample needs to be modified.
*/
int GUI_VNC_X_StartServer(int LayerIndex, int ServerIndex) {
//
// Check if maximum number of VNC clients is not exceeded.
//
if (ServerIndex >= VNC_MAX_CLIENTS) {
    return -1;
}
//
// Init VNC context and attach to layer (so context is
// updated if the display-layer-contents change).
//
GUI_VNC_AttachToLayer(&_Context, LayerIndex);
_Context.ServerIndex = (uint16_t)ServerIndex;
//
// Set up pointer to RFB buffer.
//
_Context.pBuffer      = _acBuffer;
_Context.SizeOfBuffer = GUI_VNC_BUFFER_SIZE;
//
// Create task for VNC Server
//
#ifdef RTE_CMSIS_RTOS2
s_vncTsakId = osThreadNew(_ServerTask, NULL, &_ServerTask_attr);
#else
osThreadCreate(osThread(_ServerTask),NULL);
#endif
//
// O.k., server has been started
//

return 0;
}

/*********************************************************************
*
*       void GUI_VNC_X_StopServer(void)
*       重启服务线程
*/
extern int GUI_VNC_X_ReStartServer(int LayerIndex, int ServerIndex);
int GUI_VNC_X_ReStartServer(int LayerIndex, int ServerIndex) {
(void)LayerIndex;
(void)ServerIndex;

#ifdef RTE_CMSIS_RTOS2
s_vncTsakId = osThreadNew(_ServerTask, NULL, &_ServerTask_attr);
#else
osThreadCreate(osThread(_ServerTask),NULL);
#endif
//
// O.k., server has been started
//

return 0;
}

/*********************************************************************
*
*       void GUI_VNC_X_StopServer(void)
*       关掉服务线程
*/
extern void GUI_VNC_X_StopServer(void);
void GUI_VNC_X_StopServer(void)
{
    osThreadTerminate(s_vncTsakId);
    memset(&_Addr, 0, sizeof(struct sockaddr_in));
    memset(_acBuffer,0,sizeof(_acBuffer));
}

/*********************************************************************
*
*       GUI_VNC_X_getpeername()
*
*Function description
*    Retrieves the IP addr. of the currently connected VNC client.
*
*Parameters
*    ServerIndex: Index of server instance.
*    pIPAddr: VNC client connected: U32 IP addr. in network endianess.
*                  No client connected : 0
*/
void GUI_VNC_X_getpeername(int ServerIndex, U32 * pIPAddr) {
struct sockaddr_in Client;
int                Len;
void             * pConnection;

if ((ServerIndex >= VNC_MAX_CLIENTS) || (ServerIndex < 0)) {
    return;
}
if (pIPAddr) {
    *pIPAddr = _Addr.sin_addr.s_addr;
}
}

/*************************** End of file ****************************/
页: [1] 2
查看完整版本: 【原创开源】极具可玩性的高端玩法,使用F429外接32位SDRAM虚拟VNC桌面,无需显示屏