导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页
    1. 主页
    2. bigfly
    B
    • 资料
    • 关注 0
    • 粉丝 0
    • 我的积分 2140
    • 主题 28
    • 帖子 39
    • 最佳 3
    • 群组 0

    bigflyLV 5

    @bigfly

    2140
    积分
    3
    声望
    29
    资料浏览
    39
    帖子
    0
    粉丝
    0
    关注
    注册时间 最后登录

    bigfly 取消关注 关注

    bigfly 发布的最佳帖子

    • Melis4.0测试cedar多媒体解码库,视频和lvgl混合显示

      1.测试audio_test命令播放mp3

      首先要把cedar模块编译进内核:在 melis 的根目录执行 make menuconfig 命令,选中 cedar 模块。

      Modules Setup
      	-->cedar module support
      

      9590f04e98624fe8a954fb1096b4c0d6.png

      测试命令也包含进来:

      Kernel Setup 
      	--> Drivers Test Sample
      		--> cedar Test
      

      1eca982f2a9d4243930a0147bff1214e.png

      编译,烧录,运行,输入help命令可以看到下面的命令:

      msh />help
      ......
      cedar_close      - cedar_close
      cedar_test       - cedar_test
      audio_close_test - audio_close_test
      audio_test       - audio_play_test
      ......
      

      1.1 finish命令中文件路径的写法(测试)

      audio_test命令的格式为:

      audio_test [文件名]
      

      我的sd卡目录下有个 mp3 文件夹,在finish中进入文件夹后的路径为:

      cd /mnt/F/mp3
      msh /mnt/F/mp3>ls
      1906.真的爱你-Beyond.mp3 1912.千千阙歌-陈慧娴.mp3 1916.红日-李克勤.mp3 1917.都是你的错-陈慧琳.mp3 1917.都是你的错65k.mp3
      distance.mp3
      

      这时,我要播放distance.mp3,我使用了下面4种路径:

      audio_test /mnt/F/mp3/distance.mp3           ------- 播放失败
      audio_test \\mnt\\F\\mp3\\distance.mp3		 ------- 播放失败
      audio_test F:\\mp3\\distance.mp3             ======= 播放成功
      audio_test F:/mp3/distance.mp3               ------- 播放失败
      

      只有一种路径是正确的:

      audio_test F:\\mp3\\distance.mp3
      

      测试播放纯音频文件不用考虑图层,比较简单。

      2.测试cedar_test命令播放mp4

      先禁止melis桌面加载,在《startup.sh》注释掉相关内容:

      packecho "Execute startup script begin.............."
      #insmod d:\mod\orange.mod
      #insmod d:\apps\desktop.mod
      echo "...............Execute startup script end"
      

      此时开机只显示全志logo。查询一下此时的图层信息:

      msh />disp
      screen 0:
      # allwinner logo使用 ch[0] lyr[0]图层,alpha_mode = 0 (pixel alpha),alpha = 255,zorder 为 0 
         BUF    enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[  0] fb[ 640, 480; 640, 480; 640, 480] crop[   0,   0, 640, 480] frame[  80,   0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x       0] trd[0,0]
      

      alpha = 255属于全覆盖,不和其他图层混合显示。zorder=0表示最底层,其他图层只要大于0就会覆盖它。当然,覆盖是在图层都是alpha=255的情况下。

      2.1 不清除logo图层,无法显示视频

      在这种情况下,使用cedar_test播放视频,只有声音,没有图像。

      msh />cedar_test  F:\\hanfu02.mp4
      

      这种情况下,查看一下图层信息(可以看到2个图层都属于ch[0],图层格式一个是RGB,一个是YUV):

      msh />disp
      screen 0:
         BUF    enable ch[0] lyr[0] z[0] prem[N] a[pixel 255] fmt[  0] fb[ 640, 480; 640, 480; 640, 480] crop[   0,   0, 640, 480] frame[  80,   0, 640, 480] addr[0x4132b000,0x00000000,0x00000000] flags[0x       0] trd[0,0]
         BUF    enable ch[0] lyr[1] z[1] prem[N] a[pixel   0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[   0,   0,1280, 720] frame[   0,  15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x       0] trd[0,0]
      

      be26c22eb1224acf8a17cb7814f06470.png
      这里是不是说同一通道的4图层,只能使用相同的格式?

      2.2 使用disp_layer_alpha_test命令清除logo图层,正常播放视频的disp_layer_alpha_test命令再修改一下:

      int disp_layer_alpha_test(int argc, char **argv)
      {
      	......
      	if (argc == 2) {		//	如果带有一个参数,不用理会参数是什么,清除所有图层		
      		disp_layer_clear_all(0);
      		return 0;
      	}else if(argc == 4){	//	带3个参数,分别是:   [1]=mode    [2]=alpha    [3]=zorder 
      		mode = atoi(argv[1]);
      		alpha = atoi(argv[2]);
      		i = atoi(argv[3]);
      		show_ui_layer(&test_cfg, 1, mode, alpha,(unsigned char)i);
      		return 0;
      	} else
      		g_screen_index = 0;
      	......
      }
      

      输入下面的命令,注意:只带一个参数。

      msh />disp_layer_alpha_test 0
      

      查询图层信息(可以看到没有图层信息):

      msh />disp
      screen 0:
      de_rate 300000000 hz, ref_fps:      59
      mgr0: 800x480 fmt[rgb] cs[0x204] range[full] eotf[0x4] bits[8bits] err[0] force_sync[0] unblank direct_show[false]
      dmabuf: cache[0] cache max[0] umap skip[0] overflow[0]
              lcd output      backlight(192)  fps:58.4         800x 480
              err:77961       skip:16 irq:124292      vsync:0 vsync_skip:0
      

      现在才可以正常播放视频。播放完毕后,查询图层信息:

      msh />disp
      screen 0:
      #	vi图层ch[0] lyr[1]是,alpha_mode = 0 (pixel alpha),alpha = 0,format = 72,zorder 为 1
         BUF    enable ch[0] lyr[1] z[1] prem[N] a[pixel   0] fmt[ 72] fb[1280, 720; 640, 360; 640, 360] crop[   0,   0,1280, 720] frame[   0,  15, 800, 450] addr[0x42b2d000,0x00000000,0x4273a000] flags[0x       0] trd[0,0]
      

      3. lvgl设置

      3.1 ui图层配置

      lvgl属于ui图层,所以使用ch[1] lyr[0] ,alpha_mode = 2 (global pixel alpha),alpha = 255,format = 0(ARGB),zorder 为 2(zorder可以改变,其他参数固定)。仿照 show_ui_layer() 写一个show_lvgl_layer() 的函数:

      int request_lvgl_layer(unsigned char  zorder)
      {
      	static int isMemInited=0;	//
      	struct test_layer_cfg test_cfg;
      	struct test_layer_cfg *cfg = &test_cfg;
      	memset(&test_cfg, 0, sizeof(struct test_layer_cfg));
      
      	printf("request mem_id 0,800, 480,\n");
      	//	第一次初始化,清除所有图层,申请内存;后面就不用了,只是改变zorder
      	if(isMemInited == 0){
      		disp_layer_clear_all(g_screen_index);
      		disp_mem(0, 800, 480, 0, "r");
      		memset(g_p_mem_base,0,800*480*4);
      	}
      	isMemInited = 1;
      	cfg->mem_id = 0;
      	cfg->screen_id = 0;
      	cfg->layer_cfg.channel = 1;
      	cfg->layer_id = 0;
      	cfg->layer_cfg.layer_id = 0;
      
      	cfg->layer_cfg.info.fb.format = 0;
      	cfg->layer_cfg.info.fb.size[0].width = 800;
      	cfg->layer_cfg.info.fb.size[0].height = 480;
      	cfg->layer_cfg.info.fb.crop.x = 0;
      	cfg->layer_cfg.info.fb.crop.y = 0;
      	cfg->layer_cfg.info.fb.crop.width = 800;
      	cfg->layer_cfg.info.fb.crop.height = 480;
      	cfg->layer_cfg.info.fb.align[0] = 4;
      	cfg->layer_cfg.info.mode = 0;
      	cfg->layer_cfg.info.alpha_mode = 2;
      	cfg->layer_cfg.info.alpha_value = 255;
      	cfg->layer_cfg.info.zorder = zorder;
      	cfg->layer_cfg.info.screen_win.x = 0;
      	cfg->layer_cfg.info.screen_win.y = 0;
      
      	return disp_layer_cfg(cfg);
      }
      

      3.2 lvgl本身配置

      参考文章《LVGL视频播放界面实现方法》。

      需要在lv_conf.h中设置参数:

      #define LV_COLOR_SCREEN_TRANSP 1
      

      然后设置界面背景色的透明度,LV_OPA_0 为透明,LV_OPA_COVER为覆盖,根据需要配置:

      /* init screen style */
          static lv_style_t style_scr_act;
              lv_style_init(&style_scr_act);
              /* set style to  LV_OPA_0 为透明,LV_OPA_COVER为覆盖*/
              lv_style_set_bg_opa(&style_scr_act, LV_OPA_0);
              lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
      

      测试界面源码:

      void lv_example_btn_1(void)
      {
          // 创建一个组,稍后将需要使用键盘或编码器或按钮控制的部件(对象)添加进去,并且将输入设备和组关联
          // 如果将这个组设置为默认组,那么对于那些在创建时会添加到默认组的部件(对象)就可以省略 lv_group_add_obj()
          lv_group_t * g = lv_group_create();
      
          // 将上面创建的组设置为默认组
          // 如果稍后创建的部件(对象),使用默认组那必须要在其创建之前设置好默认组,否则不生效
          lv_group_set_default(g);
      
          // 将输入设备和组关联(使用前先打开上面注释掉的头文件)
          lv_indev_set_group(g_keypad_device_object, g);     // 键盘
          //lv_indev_set_group(lv_win32_encoder_device_object, g);      // 鼠标上的滚轮(编码器)
      
          /* init screen style */
          static lv_style_t style_scr_act;
              lv_style_init(&style_scr_act);
              /* set style to  LV_OPA_0,no cover*/
              lv_style_set_bg_opa(&style_scr_act, LV_OPA_0);
              lv_obj_add_style(lv_scr_act(), &style_scr_act, 0);
      #define     RIGHT_OFFSET    40
          /* 创建一个btn部件(对象) */
          lv_obj_t * btn1 = lv_btn_create(lv_scr_act());       // 创建一个btn部件(对象),他的父对象是活动屏幕对象
          lv_obj_set_size(btn1, 100, 50);
          lv_obj_align(btn1, LV_ALIGN_LEFT_MID, 140, 165);
      
          lv_obj_t * btn2 = lv_btn_create(lv_scr_act());       // 创建一个btn部件(对象),他的父对象是活动屏幕对象
          lv_obj_set_size(btn2, 100, 50);
          lv_obj_align_to(btn2, btn1, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0);
      
          lv_obj_t * btn3 = lv_btn_create(lv_scr_act());       // 创建一个btn部件(对象),他的父对象是活动屏幕对象
          lv_obj_set_size(btn3, 100, 50);
          lv_obj_align_to(btn3, btn2, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0);
      
          lv_obj_t * btn4 = lv_btn_create(lv_scr_act());       // 创建一个btn部件(对象),他的父对象是活动屏幕对象
          lv_obj_set_size(btn4, 100, 50);
          lv_obj_align_to(btn4, btn3, LV_ALIGN_OUT_RIGHT_MID, RIGHT_OFFSET, 0);
      
          lv_obj_t * slider = lv_slider_create(lv_scr_act());
          lv_obj_align(slider,  LV_ALIGN_BOTTOM_MID, 0, -20);   
      }
      

      3.3 播放视频效果

      播放视频效果(按键切换):
      fd4d14bc5cc249dc9f0a38ad271c5859.gif

      原文链接:https://blog.csdn.net/hwd00001/article/details/130145030

      发布在 MR Series
      B
      bigfly
    • 【米尔MYD-YT507开发板试用】基于Fluter+Django+OpenCV的米尔行车记录仪

      经过充分的学习T507开发板,最终选择应用Fluter+Django+OpenCV架构,来实现了一款米尔行车记录仪,现将实现的具体内容,与大家分享。

      目录:

      • 行车记录仪业务逻辑规划
      • 硬件设备准备
      • 摄像头信息记录和实时画面播放服务开发
      • 摄像头视频信息记录
      • 摄像头服务的完整代码
      • 历史数据RestFul服务开发
      • Flutter Web界面开发
      • 整体运行效果
      • 车试
      • 实际代码使用
      • 感谢
      • 总结

      一、行车记录仪业务逻辑规划

      经过详细的分析,规划了如下的基本业务逻辑结构:

      poYBAGMTXJKAOfJOAAG8aeHxdnc436.png

      整体分为三个部分:

      • 记录服务:用于记录摄像头拍摄的视频信息,以及提供摄像头当前画面的实时播放服务。

      • Django服务:包括RestFul提供API接口获取历史数据信息,以及为Flutter的Web界面提供访问服务。

      • Flutter Web界面,用于实时画面播放、历史记录播放的界面。

      为了又快又好的开发行车记录仪的实际界面,以及后续进行各移动平台的App开发,选择了Flutter。事实证明,坑太多了。不过,跨平台特性,确实好。

      二、硬件设备准备:

      开发这款行车记录仪,实际使用到的硬件设备如下:

      1.主控板:米尔MYD-YT507开发板
      2.摄像头:海康威视DS-E11 720P USB摄像头
      3.存储卡:闪迪32GB高速MicroSD存储卡
      4.路由器:云来宝盒无线路由器

      pYYBAGMTXySAK85zAE2uYyvbG20799.png

      路由器没有拍照,用普通无线路由器即可,当然带宽越高越好。

      开发板上有两个USB3.0接口,选一个接上路由器即可。

      然后,将开发板使用网线连接到路由器,再上电,就可以进行实际的操作了。

      我这边实际使用中,电源接口有点松,容易突然断电,所以使用胶带进行了加固。

      三、摄像头实时画面播放服务开发

      在之前尝试MJPEG视频流直播的时候,使用了mjpeg_streamer,但不清楚如何进行视频的分割。

      因为行车记录仪,一般都是按照一定的时间进行视频的分割存放,避免单个视频过大。

      经过仔细的学习了解,OpenCV也可以获取摄像头的信息,并按照需要写入文件。

      最后,采用了Python+OpenCV的方案,有Python负责具体的逻辑,Python-OpenCV负责摄像头视频数据的采集。

      视频采集部分,包含的具体功能为:

      • 能够采集摄像头的数据
      • 能够提供实时视频查看
      • 能够按时间写入视频数据到文件,自动进行分割

      采集摄像头的数据,Python-opencv搞定。

      写入视频数据到文件,Python简单搞定。

      提供实时视频预览,这个花了不少功夫。

      因为同时要写入到文件,还要提供预览,数据需要复用。

      经过学习了解,可以将Python-opencv采集的画面,按帧在HTTP以JPEG数据发送,那么播放端,就能收到MJPEG数据流,进行播放了。

      因此,第一版,参考资料,实现了一个Python版的MJPEG播放服务,读取帧,写入临时文件,然后从临时文件读取数据返回。

      为了提高效率,还进行了优化,不写入临时文件,直接在内存中进行转换。

      最终形成的代码如下:

      # http服务器请求处理:网页、MJPEG数据流
      class CamHandler(BaseHTTPRequestHandler):
          def do_GET(self):
              # mjpeg推流
              if self.path.endswith('.mjpg'):
                  self.send_response(200)
                  self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
                  self.end_headers()
                  while True:
                      if is_stop:
                          break
                      try:
                          # rc,img = cameraCapture.read()
                          rc,img = success,frame
                          if not rc:
                              continue
                          if True:
                              imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
                              jpg = Image.fromarray(imgRGB)
                              tmpFile = BytesIO()
                              jpg.save(tmpFile,'JPEG')
                              self.wfile.write(b"--jpgboundary")
                              self.send_header(b'Content-type','image/jpeg')
                              self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes))
                              self.end_headers()
                              jpg.save(self.wfile,'JPEG')
                          else:
                              img_fps = JPEG_QUALITY_VALUE
                              img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps]
                              img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format
                              self.send_header('Content-type','image/jpeg')
                              self.end_headers()
                              self.wfile.write(img_str)
                              self.wfile.write(b"
      --jpgboundary
      ") # end of this part
                          time.sleep(0.033)
                      except KeyboardInterrupt:
                          self.wfile.write(b"
      --jpgboundary--
      ")
                          break
                      except BrokenPipeError:
                          continue
                  return
              # 网页
              if self.path == '/' or self.path.endswith('.html'):
                  self.send_response(200)
                  self.send_header('Content-type','text/html')
                  self.end_headers()
                  self.wfile.write(b'<html><head><title>Live video</title></head><body>')
                  self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode())
                  self.wfile.write(b'</body></html>')
                  return
      

      这段代码,提供了两个功能:

      • 如果通过浏览器访问http://ip:端口/index.html,就会返回包含MJPEG调用地址的网页

      • 如果通过浏览器访问http://ip:端口/live.mjpg,就会返回MJPEG流媒体数据,以便播放

      在开发过程中,运行该服务后,随时可以通过浏览器查看效果。

      其中涉及到opencv相关的知识,以及webserver相关的知识,大家可以了解相关的资料做基础,这里就不详细说了。

      本来以为提供了MJPEG服务,就能够在Flutter开发的Web界面中调用了。然而,实际使用时,发现坑来了。

      Flutter的公共库里面,有MJPEG的库,但是在目前的版本中,已经不能使用了。且官方认为用的人不多,在可预见的将来,不会修复。悲催啊!!!

      条条大道通罗马,此处不通开新路。

      经过再次的学习了解,Flutter的Video功能,支持Stream模式,其可以采用WebSocket的方式来获取数据,然后进行播放。

      那么,只要能够在服务端,将获取的帧数据,使用WebSocket提供,就能够正常播放了。

      最终,使用Python开发了能够提供实时视频数据的WebSocket服务,具体代码如下:

      # websocket服务请求处理
      async def CamTransmitHandler(websocket, path):
          print("Client Connected !")
          try :
              while True:
                  # rc,img = cameraCapture.read()
                  rc,img = success,frame
                  if not rc:
                      continue
      
                  img_fps = JPEG_QUALITY_VALUE
                  img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps]
                  encoded = cv2.imencode('.jpg', img, img_param)[1]
                  data = str(base64.b64encode(encoded))
                  data = data[2:len(data)-1]
                  await websocket.send(data)
      
                  # cv2.imshow("Transimission", frame)
                  # if cv2.waitKey(1) & 0xFF == ord('q'):
                  #     break
              # cap.release()
          except EXCEPTION_CONNECTION_CLOSE as e:
              print("Client Disconnected !")
              # cap.release()
          except:
              print("Someting went Wrong !")
      

      这个部分比之前的更简单,就是简单的转换数据,喂数据给WebSocket即可。

      上述的两部分代码中,都没有包含完整的逻辑处理过程,只有关键代码部分。

      各部分分别讲完以后,将提供完整的代码以供学习。

      到这里,实时流媒体功能就实现了。

      四、摄像头视频信息记录

      实际上,上一步的实时视频功能,也依赖于这一步,因为其需要共享实际获取的摄像头信息。
        
      其基本逻辑也比较简单,步骤如下:

      • 初始化opencv,开始摄像头数据帧的获取
      • 检测是否达到预定时间
      • 未达到时间,则继续写入当前视频
      • 达到时间了,则关闭当前视频,写入缩略图,并开启新的文件写入
          
        具体代码如下:
      # 捕获摄像头
      cameraCapture = cv2.VideoCapture(CAMERA_NO)
      
      # 摄像头参数设置
      cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
      cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240)
      cameraCapture.set(cv2.CAP_PROP_SATURATION, 135)
      
      fps = 30
      size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
      
      # 读取捕获的数据
      success,frame = cameraCapture.read()
      

      ...

      while True:
          if is_stop:
              success = False
              break;
      
          success,frame = cameraCapture.read()
          if not success:
              continue
      
          time_now = get_current_time()
          if time_now["time"] - time_record["time"] >= ROTATE_TIME:
              if time_record_prev:
                  thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg')
                  print("[Info] write to thumb: %s" % thubm_file)
                  if not os.path.isfile(thubm_file):
                      cv2.imwrite(thubm_file, frame)
      
              time_record = time_now
              time_record_prev = get_current_time()
              video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT)
              print("[Info] write to video: %s" % video_file)
      
          # encode = cv2.VideoWriter_fourcc(*"mp4v")
          encode = cv2.VideoWriter_fourcc(*'X264')
          # encode = cv2.VideoWriter_fourcc(*'AVC1')
          # encode = cv2.VideoWriter_fourcc(*'XVID')
          # encode = cv2.VideoWriter_fourcc(*'H264')
          videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4
          numFrameRemaining = ROTATE_TIME * fps    #摄像头捕获持续时间
          while success and numFrameRemaining > 0:
              videoWriter.write(frame)
              success,frame = cameraCapture.read()
              numFrameRemaining -= 1
      
      cameraCapture.release()
      

      上述代码的逻辑其实很清晰,有opencv的基础,一看就懂。

      有一个关键点需要注意的就是 encode = cv2.VideoWriter_fourcc(*'X264') ,在不同的环境下面,提供的编码方式不完全相同。

      在米尔MYD-YT507开发板的Ubuntu环境中,可以使用X264编码。

      上述代码,会持续不断的读取摄像头的数据帧,存放到frame变量中,然后写入到视频文件中。并进行时间判断,以确定是否需要写入到新的视频文件中。

      frame变量,在之前实时视频服务中,也会使用,相当于是共享了。

      五、摄像头服务的完整代码

      经过上面的两个部分,就完成了摄像头部分的服务代码。

      整体的代码如下:

      # -*- coding: utf-8 -*-
      import signal
      import cv2
      import time
      from PIL import Image
      from threading import Thread
      from http.server import BaseHTTPRequestHandler,HTTPServer
      from socketserver import ThreadingMixIn
      from io import BytesIO
      
      import os
      import sys
      import websockets
      import asyncio
      import base64
      import ctypes
      import inspect
      
      CAMERA_NO = 2
      ROTATE_TIME = 120
      MJPEG_ENABLE = 1
      WEBSOCKET_ENABLE = 1
      MJPEG_SERVER_PORT = 28888
      WEBSOCKET_PORT = 28889
      JPEG_QUALITY_VALUE = 65
      STORE_DIR = "./data/" if os.uname()[0] == 'Darwin' else "/sdcard/data/"
      MEDIA_EXT = "mkv"
      
      EXCEPTION_CONNECTION_CLOSE = websockets.exceptions.ConnectionClosed if sys.version[:3] == '3.6' else websockets.ConnectionClosed
      
      def _async_raise(tid, exctype):
          """raises the exception, performs cleanup if needed"""
          try:
              tid = ctypes.c_long(tid)
              if not inspect.isclass(exctype):
                  exctype = type(exctype)
              res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
              if res == 0:
                  # pass
                  raise ValueError("invalid thread id")
              elif res != 1:
                  # """if it returns a number greater than one, you're in trouble,
                  # and you should call it again with exc=NULL to revert the effect"""
                  ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
                  raise SystemError("PyThreadState_SetAsyncExc failed")
          except Exception as err:
              print(err)
      
      
      def stop_thread(thread):
          """终止线程"""
          _async_raise(thread.ident, SystemExit)
      
      # 信号处理回调
      def signal_handler(signum, frame):
          # global cameraCapture
          # global thread
          # global server
          # global is_stop
          # global success
          print('signal_handler: caught signal ' + str(signum))
          if signum == signal.SIGINT.value:
              print('stop server:')
              is_stop = True
              success = False
              print("mjpeg server.socket.close...")
              server.socket.close()
              print("mjpeg server.shutdown...")
              server.shutdown()
              print("ws server.socket.close...")
              server_ws.ws_server.close()
              time.sleep(1)
              # print("ws server.shutdown...")
              # await server_ws.ws_server.wait_closed()
              print("mjpeg thread.shutdown...")
              thread_mjpeg.join()
              print("ws loop.shutdown...")  
              # event_loop_ws.stop()
              event_loop_ws.call_soon_threadsafe(event_loop_ws.stop)
              time.sleep(1)
              # print("ws thread.shutdown...")  
              # stop_thread(thread_ws)
              # time.sleep(1)
              # print(server)
              # print(server_ws)
              print(thread_mjpeg.is_alive())
              print(thread_ws.is_alive())
              print(event_loop_ws.is_running())
              # thread_ws.join()
              print("cameraCapture.release...")
              cameraCapture.release()
              print("quit...")
              # print(server_ws)
              sys.exit(0)
      
      # http服务器请求处理:网页、MJPEG数据流
      class CamHandler(BaseHTTPRequestHandler):
          def do_GET(self):
              # mjpeg推流
              if self.path.endswith('.mjpg'):
                  self.send_response(200)
                  self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
                  self.end_headers()
                  while True:
                      if is_stop:
                          break
                      try:
                          # rc,img = cameraCapture.read()
                          rc,img = success,frame
                          if not rc:
                              continue
                          if True:
                              imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
                              jpg = Image.fromarray(imgRGB)
                              tmpFile = BytesIO()
                              jpg.save(tmpFile,'JPEG')
                              self.wfile.write(b"--jpgboundary")
                              self.send_header(b'Content-type','image/jpeg')
                              self.send_header(b'Content-length',str(tmpFile.getbuffer().nbytes))
                              self.end_headers()
                              jpg.save(self.wfile,'JPEG')
                          else:
                              img_fps = JPEG_QUALITY_VALUE
                              img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps]
                              img_str = cv2.imencode('.jpg', img, img_param)[1].tobytes() # change image to jpeg format
                              self.send_header('Content-type','image/jpeg')
                              self.end_headers()
                              self.wfile.write(img_str)
                              self.wfile.write(b"
      --jpgboundary
      ") # end of this part
                          time.sleep(0.033)
                      except KeyboardInterrupt:
                          self.wfile.write(b"
      --jpgboundary--
      ")
                          break
                      except BrokenPipeError:
                          continue
                  return
              # 网页
              if self.path == '/' or self.path.endswith('.html'):
                  self.send_response(200)
                  self.send_header('Content-type','text/html')
                  self.end_headers()
                  self.wfile.write(b'<html><head><title>Live video</title></head><body>')
                  self.wfile.write(('<img src="http://%s/live.mjpg"/>' % self.headers.get('Host')).encode())
                  self.wfile.write(b'</body></html>')
                  return
      
      class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
          """Handle requests in a separate thread."""
      
      # 启动MJPEG服务
      def mjpeg_server_star():
          global success
          global server
          global thread_mjpeg
      
          try:
              server = ThreadedHTTPServer(('0.0.0.0', MJPEG_SERVER_PORT), CamHandler)
              print("mjpeg server started: http://0.0.0.0:%d" % MJPEG_SERVER_PORT)
              # server.serve_forever()
              thread_mjpeg = Thread(target=server.serve_forever);
              thread_mjpeg.start()
          except KeyboardInterrupt:
              print("mjpeg server stoping...")
              server.socket.close()
              server.shutdown()
              print("mjpeg server stoped")
      
      # websocket服务请求处理
      async def CamTransmitHandler(websocket, path):
          print("Client Connected !")
          try :
              while True:
                  # rc,img = cameraCapture.read()
                  rc,img = success,frame
                  if not rc:
                      continue
      
                  img_fps = JPEG_QUALITY_VALUE
                  img_param = [int(cv2.IMWRITE_JPEG_QUALITY), img_fps]
                  encoded = cv2.imencode('.jpg', img, img_param)[1]
                  data = str(base64.b64encode(encoded))
                  data = data[2:len(data)-1]
                  await websocket.send(data)
      
                  # cv2.imshow("Transimission", frame)
                  # if cv2.waitKey(1) & 0xFF == ord('q'):
                  #     break
              # cap.release()
          except EXCEPTION_CONNECTION_CLOSE as e:
              print("Client Disconnected !")
              # cap.release()
          except:
              print("Someting went Wrong !")
      
      # websocket服务器启动
      def websocket_server_start():
          global thread_ws
          global server_ws
          global event_loop_ws
      
          event_loop_ws = asyncio.new_event_loop()
          def run_server():
              global server_ws
              print("websocket server started: ws://0.0.0.0:%d" % WEBSOCKET_PORT)
              server_ws = websockets.serve(CamTransmitHandler, port=WEBSOCKET_PORT, loop=event_loop_ws)
              event_loop_ws.run_until_complete(server_ws)
              event_loop_ws.run_forever()
      
          thread_ws = Thread(target=run_server)
          thread_ws.start()
          # try:
          #     yield
          # except e:
          #     print("An exception occurred")
          # finally:
          #     event_loop.call_soon_threadsafe(event_loop.stop)
      
      # 获取存储的文件名
      def get_file_name(time_obj, path, ext):
          file_name_time = "%04d-%02d-%02d_%02d-%02d-%02d" % (time_obj["year"], time_obj["month"], time_obj["day"], time_obj["hour"], time_obj["min"], 0)
          return '%s/%s/%s.%s' % (STORE_DIR, path, file_name_time, ext)
      
      # 获取当前整分时间
      def get_current_time():
          time_now = time.localtime()
          time_int = int(time.time())
          return {
              "year": time_now.tm_year,
              "month": time_now.tm_mon,
              "day": time_now.tm_mday,
              "hour": time_now.tm_hour,
              "min": time_now.tm_min,
              "sec": time_now.tm_sec,
              "time": time_int - time_now.tm_sec
          }
      
      # 设置信号回调
      signal.signal(signal.SIGINT, signal_handler)
      signal.signal(signal.SIGTERM, signal_handler)
      
      # 捕获摄像头
      cameraCapture = cv2.VideoCapture(CAMERA_NO)
      
      # 摄像头参数设置
      cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 320)
      cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 240)
      cameraCapture.set(cv2.CAP_PROP_SATURATION, 135)
      
      fps = 30
      size=(int(cameraCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),int(cameraCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
      
      # 读取捕获的数据
      success,frame = cameraCapture.read()
      
      if not success:
          print("camera start failed.")
          quit()
      
      is_stop = False
      server = None
      server_ws = None
      event_loop_ws = None
      thread_mjpeg = None
      thread_ws = None
      mjpeg_server_star()
      websocket_server_start()
      
      print("record server star:")
      
      thubm_file = None
      video_file = None
      time_start = int(time.time())
      time_record = {"time":0}
      time_record_prev = None
      
      while True:
          if is_stop:
              success = False
              break;
      
          success,frame = cameraCapture.read()
          if not success:
              continue
      
          time_now = get_current_time()
          if time_now["time"] - time_record["time"] >= ROTATE_TIME:
              if time_record_prev:
                  thubm_file = get_file_name(time_record_prev, 'thumbs', 'jpg')
                  print("[Info] write to thumb: %s" % thubm_file)
                  if not os.path.isfile(thubm_file):
                      cv2.imwrite(thubm_file, frame)
      
              time_record = time_now
              time_record_prev = get_current_time()
              video_file = get_file_name(time_record_prev, 'videos', MEDIA_EXT)
              print("[Info] write to video: %s" % video_file)
      
          # encode = cv2.VideoWriter_fourcc(*"mp4v")
          encode = cv2.VideoWriter_fourcc(*'X264')
          # encode = cv2.VideoWriter_fourcc(*'AVC1')
          # encode = cv2.VideoWriter_fourcc(*'XVID')
          # encode = cv2.VideoWriter_fourcc(*'H264')
          videoWriter=cv2.VideoWriter(video_file, encode,fps,size) # mp4
          numFrameRemaining = ROTATE_TIME * fps    #摄像头捕获持续时间
          while success and numFrameRemaining > 0:
              videoWriter.write(frame)
              success,frame = cameraCapture.read()
              numFrameRemaining -= 1
      
      cameraCapture.release()
      

      在上述代码中,除了前面说过的三个部分,还包括启动web和websocket线程的部分。因为核心逻辑为读取视频数据并写入文件,所以其他部分,以线程的模式启动,以便同时进行处理。

      将上述代码保存为DrivingRecorderAndMjpegServer.py,然后运行即可。(依赖包,见代码库中requirements.txt)

      poYBAGMTZ1WAItw5AAOg9WCVryc922.png

      实际访问效果如下:

      poYBAGMTZ2OAA5B3ABgiUZy_8es063.png

      六、历史数据RestFul服务开发

      历史数据服务,本来也可以使用Python直接手写,但考虑到可扩展性,使用Django来进行了编写。

      Djano服务,需要提供如下的功能:

      • 提供api接口,以便获取历史数据记录列表,便于前端界面呈现展示
      • 提供Flutter Web界面代码文件的托管,以便通过浏览器访问
      • 提供静态文件的访问,例如查看历史视频文件

      2和3本质都是一个问题,通过Django的static功能,就能实现。

      也就是在settings.py配置中,提供下面的配置即可:

      STATIC_URL = 'static/'
      
      STATICFILES_DIRS = [
          BASE_DIR / "static"
      ]
      

      1对外提供api服务,则需要设置对应的url接口,以及读取历史文件信息,生成前端需要的json数据结构,这部分的具体代码如下:

      # 媒体文件存放目录,以及缩略图和视频文件的后缀
      THUMB_HOME_DIR = "%s/%s/data/thumbs/" % (BASE_DIR, STATIC_URL)
      VIDEO_HOME_DIR = "%s/%s/data/videos/" % (BASE_DIR, STATIC_URL)
      
      IMG_FILTER = [".jpg"]
      MEDIA_FILTER = [ ".mkv"]
      
      import json
      from django.shortcuts import render, HttpResponse
      from rest_framework.response import Response
      from rest_framework.permissions import AllowAny
      from rest_framework.decorators import api_view, permission_classes
      import os
      from django.conf import settings
      
      THUMB_HOME_DIR = settings.THUMB_HOME_DIR
      VIDEO_HOME_DIR = settings.VIDEO_HOME_DIR
      IMG_FILTER = settings.IMG_FILTER
      MEDIA_FILTER = settings.MEDIA_FILTER
      
      # Create your views here.
      @api_view(['GET'],)
      @permission_classes([AllowAny],)
      def hello_django(request):
          str = '''[
        {
          "id": 1,
          "time": "2022-07-28 21:00",
          "title": "2022-07-28 21:00",
          "body": "videos/2022-07-28_2100.mp4"
        },
        {
          "id": 2,
          "time": "2022-07-28 23:00",
          "title": "2022-07-28 23:00",
          "body": "videos/2022-07-28_2300.mp4"
        },
        {
          "id": 3,
          "time": "2022-07-28 25:00",
          "title": "2022-07-28 25:00",
          "body": "videos/2022-07-28_2500.mp4"
        }
      ]'''
          _json = json.loads(str)
          return HttpResponse(json.dumps(_json), content_type='application/json')
      
      
      @api_view(['GET'],)
      @permission_classes([AllowAny],)
      def history_list(request):
          next = request.GET.get("next", '')
          print(f"thumb next = {next}")
          path = "/".join(request.path.split("/")[3:])
          print(f"thumb request.path= {request.path}")
          print(f"thumb path = {path}")
      
          #print os.listdir(FILE_HOME_DIR+".none/")
          data = {"files":[], "dirs":[]}
          print(data)
          child_path = THUMB_HOME_DIR+next
          print(f"child_path = {child_path}")
          data['cur_dir'] = path+next
          print(data)
          for dir in os.listdir(child_path):
              if os.path.isfile(child_path+"/"+dir):
                  if os.path.splitext(dir)[1] in IMG_FILTER:
                      data['files'].append(dir)
              else:
                  data['dirs'].append(dir)
      
          print(data)
          data['files']=sorted(data['files'])
          data['files'].reverse()
          data['infos'] = []
      
          for i in range(0,len(data['files'])):
              thumb_name = data['files'][i]
              video_name = thumb_name.replace('.jpg', MEDIA_FILTER[0])
              file_time = thumb_name.replace('.jpg', '').replace('_', ' ')
              data['infos'].append(
                {
                  "id": i,
                  "time": file_time,
                  "title": file_time,
                  "body": thumb_name,
                  'thumb': thumb_name, 
                  'video': video_name
                }
              )
          return Response(data['infos'], status = 200)
      

      其中有两个接口:

      hello_django是最开始学习使用的,返回写死的json数据。

      history_list,则是自动遍历缩略图文件夹,获取缩略图文件信息,并生成所需要的json数据格式。

      在对应的代码库文件中,也包含了requirements.txt,其中标明了实际需要的依赖库。

      下载代码,进入manage.py所在的目录后,执行下面的命令即可启动:

      pYYBAGMTagmAdvi-AAEU-8-u8-4912.png

      访问 192.168.1.15:8000/app/hellodjango :

      pYYBAGMTaq-AA0ClAAFIXozvPEg025.png

      访问:History List – Django REST framework

      poYBAGMTasKAWY3ZAAKGge6My1I001.png

      可以看到 history_list接口,已经可以提供实际需要的数据了。

      七、Flutter Web界面开发

      这个部分设计的代码比较多,所以只对关键部分的代码进行说明。

      开发的实际代码,位于lib目录,具体为:

      pYYBAGMTa32AOZqyAAEzENFc2kg639.png

      • globals.dart:全局变量定义
      • main.dart:程序入口
      • home_page.dart:首页
      • live_page.dart:实时播放
      • live_page_mp4.dart:测试播放mp4视频
      • history_page.dart:历史记录列表页面
      • video_detail.dart:单条历史记录详情
      • video_play.dart:播放具体的历史视频
      • video_model.dart:单条记录的数据模型
      • http_service.dart:请求RestFul接口
      • websocket.dart:实时视频的WebSocket请求

      整个界面,使用了Scaffold来模拟手机/Pad的操作界面,具体界面如下:

      poYBAGMTbWyAAzQWAAGRBvXHjAI107.png

      在实时画面界面中,使用了WebSocket监听,获取到信息,就使用Stream模式,推送给视频播放。

      在历史记录界面中,则通过RestFul请求列表数据,然后呈现。

      八、整体运行效果

      实际的运行效果,不用多说,看界面就成:

      实时画面:
      pYYBAGMTblGAc4mAABRLQVukNDU274.png

      历史记录列表:
      poYBAGMTbmOAXSMRAAK9lKwRUWc298.png

      历史记录播放:
      poYBAGMTbnGAYABlABkc5_TtrLw765.png

      九、车试:

      经过反复的测试验证,确保各项功能完整后,进行了上车实测。

      poYBAGMTbtWABcAWAE2YYb8NH3g757.png

      因为最近的疫情原因,所以只在村里转了一圈,进行了实际测试,可以查看最后的视频。后续有机会,再找个晴朗的天气,去环境优美的地方实际拍摄录制。

      十、实际代码说明:

      完整的代码,请通过 米尔行车记录仪: 米尔行车记录仪 (https://gitee.com/honestqiao/MYiR-Driving-Recorder) 获取。

      代码目录说明如下:

      • DrivingRecorder:摄像头服务
      • backend:RestFul服务
      • frontend:Flutter Web界面

      在以上仓库中,包含了详细的代码使用说明。

      在实际应用中,将记录视频的data目录与后端static/data目录关联,以便两者统一。

      十一、感谢

      在研究学习的过程中,参考了数十篇各类资料,先将部分列出如下。对所有学习过的资料的作者,表示深深的感谢。

      janakj/py-mjpeg: Python MJPEG streaming utilities (github.com)
      Simple Python Motion Jpeg (mjpeg server) from webcam. Using: OpenCV,BaseHTTPServer (github.com)
      Python 使用USB Camera录制MP4视频_Frank_Abagnale的博客-CSDN博客
      用 Python、nginx 搭建在线家庭影院 - 知乎 (zhihu.com)
      Django报错解决:RuntimeError: Model class ...apps... doesn't declare an explicit app_label and isn't in a_lyp039078的博客-CSDN博客
      Python OpenCV 调用摄像头并截图保存_Clannad_niu的博客-CSDN博客
      用 Python、nginx 搭建在线家庭影院mob604756e97f09的技术博客51CTO博客
      Python-OpenCV录制H264编码的MP4视频 - 掘金 (juejin.cn)
      [VideoWriter]保存H264/MPEG4格式MP4视频 - image processing (zj-image-processing.readthedocs.io)
      Manual USB camera settings in Linux | KUROKESU
      UVC Web Cameras (indilib.org)
      编写你的第一个 Flutter 网页应用 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      macOS install | Flutter
      [Django 設定 LANGUAGE_CODE 時所遇到的麻煩] OSError: No translation files found for default language zh-TW. (github.com)**
      Django And Flutter — 样板应用程序|的分步教程作者:Clever Tech Memes |中等 (medium.com)
      joke2k/django-environ: Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application. (github.com)
      django 之跨域访问问题解决 access-control-allow-origin - 腾讯云开发者社区-腾讯云 (tencent.com)
      django-cors-headers · PyPI
      Django项目解决跨域问题 - SegmentFault 思否
      video_player | Flutter Package (pub.dev)
      视频的播放和暂停 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      5.7 页面骨架(Scaffold) | 《Flutter实战·第二版》 (flutterchina.club)
      itfitness/BottomNavigationBarDemo - 码云 - 开源中国 (gitee.com)
      Flutter底部导航 - 简书 (jianshu.com)
      Flutter之自定义底部导航条以及页面切换实例——Flutter基础系列houruoyu3的博客-CSDN博客flutter 自定义底部导航
      How To Use HTTP Requests in Flutter | DigitalOcean
      在Flutter中发起HTTP网络请求 - Flutter中文网 (flutterchina.club)
      Fetch data from the internet | Flutter
      获取网络数据 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      深入理解 Function & Closure - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      Django And Flutter — A Step by Step Tutorial for a Boilerplate Application | by Clever Tech Memes | Medium
      multithreading - Multithreaded web server in python - Stack Overflow
      Simple Python HTTP Server with multi-threading and partial-content support (github.com)
      meska/mjpeg_stream_webcam: Webcam Streamer for Octoprint MacOs (github.com)
      blueimp/mjpeg-server: MJPEG Server implements MJPEG over HTTP using FFmpeg or any other input source capable of piping a multipart JPEG stream to stdout. Its primary use case is providing Webdriver screen recordings. (github.com)
      n3wtron/simple_mjpeg_streamer_http_server: simple python mjpeg streamer http server (github.com)
      Python3远程监控程序实现肥宅Sean的博客-CSDN博客
      opencv imencode跟imdecode函数jpg(python) - PythonTechWorld
      flutter_mjpeg | Flutter Package (pub.dev)
      Can't work on web platform. · Issue #13 · mylisabox/flutter_mjpeg (github.com)
      Consider if fetch is widely supported enough to use · Issue #595 · dart-lang/http (github.com)
      在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
      Python websockets.serve方法代碼示例 - 純淨天空 (vimsky.com)
      Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
      Bad State: Stream has already been listened to. · Issue #29105 · flutter/flutter (github.com)
      flutter - Streambuilder with WebSockets stream in TabBarView: Bad state: Stream has already been listened to - Stack Overflow
      使用WebSockets - Flutter中文网 (flutterchina.club)
      VideoStreaming.dart (github.com)
      在 Flutter | 中创建实时视频流应用程序作者:Mitrajeet Golsangi |开发人员学生社区 Vishwakarma 技术学院,浦那 |中等 (medium.com)
      Flutter:WebSocket封装-实现心跳、重连机制 - 让我留在你身边 (ricardolsw.github.io)
      2.3 状态管理 | 《Flutter实战·第二版》 (flutterchina.club)
      路由和导航 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter
      7.6 异步UI更新(FutureBuilder、StreamBuilder) | 《Flutter实战·第二版》 (flutterchina.club)
      Flutter 常用組件講解 | ImageWidget - iT 邦幫忙::一起幫忙解決難題,拯救 IT 人的一天 (ithome.com.tw)
      Step By Step Tutorial in Learning Flutter: Lesson 12 — Adding Image (Ice Pokemon) | by Misterflutter | Quick Code | Medium
      Django CORS on static asset - Stack Overflow
      配置 | Django 文档 | Django (djangoproject.com)
      Global Variables in Dart - Stack Overflow
      UVC - Community Help Wiki (ubuntu.com)
      利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
      Documentation for OPENCV_FFMPEG_WRITER_OPTIONS and OPENCV_FFMPEG_CAPTURE_OPTIONS · Issue #21155 · opencv/opencv (github.com)
      利用OpenCV进行H264视频编码的简易方式 - 知乎 (zhihu.com)
      FFmpeg概述及编码支持 - 知乎 (zhihu.com)
      Web 渲染器 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter

      十二、总结

      在研究学习的过程中,对Linux系统下的UVC框架有了进一步的了解,对Flutter进行应用开发有了实际的了解,对OpenCV的实际应用也有了具体的了解。

      在实际开发的过程中,遇到的最大的坑来自Flutter,因为变化太快,有一些功能可能兼容性没有跟上。不过更多是自己学艺不精导致的。

      另外,目前还只是V1.0版本,后续还存在较大的优化空间。例如对于OpenCV的应用,可以调整参数,优化获取的视频数据的指令和大小等。这些有待于进一步学习后进行。

      最主要的,对米尔MYD-YT507开发板有了深入的了解,进行了实际的应用。作为一款车规级处理器T507的开发板,名不虚传!

      原文链接:https://bbs.elecfans.com/jishu_2303715_1_1.html

      发布在 其它全志芯片讨论区
      B
      bigfly
    • 回复: RT-Thread on D1H. LCD work, USB in progress.

      @ylyamin 在 RT-Thread on D1H. LCD work, USB in progress. 中说:

      I’m writing a series of articles covering the knowledge and experience I’ve gained:

      D1-1. Introduction - Motivation and intention.
      D1-2. Boot process - Existing Allwinner D1H bootloaders best practice in example with booting Linux and RT-Thread, also JTAG and GDB.
      D1-3. RT-Thread overview and Build - Overview of RT-Thread structure and libraries. Compile RT-Thread for Allwinner D1H platform.
      D1-4. Makefile and Hardware changes - My repository structure, Makefile and Hardware changes was needed to be done.
      D1-5. LCD Display driver - Display driver for DevTerm R-01, uConsole R-01 and Sipeed Lichee RV.
      D1-6. USB Keyboard - USB Keyboard driver for ClockworkPi DevTerm, still not working.

      Detailed article,nice

      发布在 MR Series
      B
      bigfly

    bigfly 发布的最新帖子

    • 回复: 论坛的一个小小bug

      @zhoudaxia3000 这么看好像是8+1=9和11+1=12,有没有懂的老哥说一下什么情况

      发布在 灌水区
      B
      bigfly
    • 回复: RT-Thread on D1H. LCD work, USB in progress.

      @ylyamin 在 RT-Thread on D1H. LCD work, USB in progress. 中说:

      I’m writing a series of articles covering the knowledge and experience I’ve gained:

      D1-1. Introduction - Motivation and intention.
      D1-2. Boot process - Existing Allwinner D1H bootloaders best practice in example with booting Linux and RT-Thread, also JTAG and GDB.
      D1-3. RT-Thread overview and Build - Overview of RT-Thread structure and libraries. Compile RT-Thread for Allwinner D1H platform.
      D1-4. Makefile and Hardware changes - My repository structure, Makefile and Hardware changes was needed to be done.
      D1-5. LCD Display driver - Display driver for DevTerm R-01, uConsole R-01 and Sipeed Lichee RV.
      D1-6. USB Keyboard - USB Keyboard driver for ClockworkPi DevTerm, still not working.

      Detailed article,nice

      发布在 MR Series
      B
      bigfly
    • 回复: 更改分区

      @yyyyppppp Tina Linux 存储介质切换:eMMC,SPI NAND,SPI NOR,SD Card,SD NAND
      https://bbs.aw-ol.com/topic/1701/share/1

      发布在 其它全志芯片讨论区
      B
      bigfly
    • 回复: Openharmony D1编译下载代码失败

      是哪位大佬给D1移植了Openharmony吗

      发布在 MR Series
      B
      bigfly
    • T113-i RISC-V内核SDK公布了吗?

      T113-i RISC-V内核SDK公布了吗?

      发布在 创龙科技专区
      B
      bigfly
    • 回复: 请问D1-H的SDK是否完全开源免费试用的?

      @a5992230 2级了直接按文档步骤拉就可以用了

      发布在 MR Series
      B
      bigfly
    • 更换lcd屏幕

      我手上有一块480854的屏幕,现在想测试一下 在.fex文件中我发现,只要我把下面的这两个参数改成480854,在后面打包、烧录运行时就会出现问题

      fb0_width                = 480
      fb0_height               = 854
      

      问题如下:
      /etc/init.d/rcS: line 60: 1231 Segmentation fault insmod /system/vendor/modules/mali.ko
      挂载mali.ko文件显示段错误,具体打印消息如下:
      我这种情况是gpu不能用吗?我应该怎么解决这个问题

      [    4.223285] Mali: Enable gpu power successfully.
      [    4.223364] Mali: Set gpu frequency to 384 MHz
      [    4.223434] Mali: Mali GPU initialization finished.
      [    4.223881] Mali: ERR: /home/forlinx/work/lichee/linux-3.10/modules/gpu/mali400/kernel_mode/driver/src/devicedrv/mali/common/mali_mem_validation.c
      [    4.223892]            mali_mem_validation_add_range()  35
                                Failed to add frame buffer memory; incorrect alignment
      
      [    4.223906] Mali: ERR: /home/forlinx/work/lichee/linux-3.10/modules/gpu/mali400/kernel_mode/driver/src/devicedrv/mali/common/mali_kernel_core.c
      [    4.223912]            mali_parse_config_memory() 700
                                Failed to register frame buffer memory region
      
      [    4.224137] Unable to handle kernel paging request at virtual address 00100104
      [    4.224146] pgd = e1938000
      [    4.224152] [00100104] *pgd=6232e831, *pte=00000000, *ppte=00000000
      [    4.224169] Internal error: Oops: 817 [#1] PREEMPT SMP ARM
      [    4.224177] Modules linked in: mali(O+) gt9xxnew_ts
      [    4.224196] CPU: 0 PID: 1231 Comm: insmod Tainted: G        W  O 3.10.65 #446
      [    4.224205] task: e2f47a80 ti: e183a000 task.ti: e183a000
      [    4.224221] PC is at unregister_shrinker+0x30/0x5c
      [    4.224232] LR is at _raw_spin_unlock_irqrestore+0x38/0x58
      [    4.224241] pc : [<c00d4614>]    lr : [<c06ff900>]    psr: 40070013
                     sp : e183bc80  ip : e183bc20  fp : e183bc94
      [    4.224249] r10: e22a9664  r9 : 00000001  r8 : bf03f564
      [    4.224257] r7 : 00000000  r6 : e2e9d600  r5 : c0ad4eb0  r4 : bf03f364
      [    4.224264] r3 : 00200200  r2 : 00100100  r1 : 60070013  r0 : c0ad4eb0
      [    4.224273] Flags: nZcv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment user
      [    4.224280] Control: 10c53c7d  Table: 6193806a  DAC: 00000015
      [    4.224286]
                     PC: 0xc00d4594:
      [    4.224292] 4594  e24cb004 e52de004 e8bd4000 e3a03000 e1a05000 e59f4030 e5803014 e1a00004
      [    4.224316] 45b4  eb18a540 e5943014 e285200c e2841010 e5842014 e585100c e1a00004 e5853010
      [    4.224339] 45d4  e5832000 ebfdd6c9 e89da830 c0ad4eb0 e1a0c00d e92dd830 e24cb004 e52de004
      [    4.224362] 45f4  e8bd4000 e1a04000 e59f5030 e1a00005 eb18a52c e5943010 e1a00005 e594200c
      [    4.224385] 4614  e5823004 e5832000 e59f3014 e584300c e59f3010 e5843010 ebfdd6b4 e89da830
      [    4.224408] 4634  c0ad4eb0 00100100 00200200 e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000
      [    4.224431] 4654  e1a03001 e590214c e1a00003 e59f1004 eb014a32 e89da800 c00d4670 e1a0c00d
      [    4.224454] 4674  e92dd8f0 e24cb004 e24dd008 e52de004 e8bd4000 e59f5074 e3e03000 e50b3024
      [    4.224479]
                     LR: 0xc06ff880:
      [    4.224485] f880  e52de004 e8bd4000 f57ff05b e1d030b0 e2833001 e1c030b0 f57ff04f e320f004
      [    4.224508] f8a0  e3a00001 eb000a32 e1a0300d e3c33d7f e3c3303f e5933000 e3130002 089da800
      [    4.224531] f8c0  ebfffc6d e89da800 e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000 f57ff05b
      [    4.224554] f8e0  e1d030b0 e2833001 e1c030b0 f57ff04f e320f004 e121f001 e3a00001 eb000a1c
      [    4.224577] f900  e1a0300d e3c33d7f e3c3303f e5933000 e3130002 089da800 ebfffc57 e89da800
      [    4.224600] f920  e1a0c00d e92dd800 e24cb004 e52de004 e8bd4000 f57ff05b e1d030b0 e2833001
      [    4.224623] f940  e1c030b0 f57ff04f e320f004 f1080080 e3a00001 eb000a06 e1a0300d e3c33d7f
      [    4.224646] f960  e3c3303f e5933000 e3130002 089da800 ebfffc41 e89da800 e1a0c00d e92dd800
      [    4.224670]
                     SP: 0xe183bc00:
      [    4.224676] bc00  c003d4d0 c06ff4e0 e183bc2c c06ff900 e183bc2c e183bc20 c00d4614 40070013
      [    4.224699] bc20  ffffffff e183bc6c e183bc94 e183bc38 c0700098 c000a16c c0ad4eb0 60070013
      [    4.224722] bc40  00100100 00200200 bf03f364 c0ad4eb0 e2e9d600 00000000 bf03f564 00000001
      [    4.224744] bc60  e22a9664 e183bc94 e183bc20 e183bc80 c06ff900 c00d4614 40070013 ffffffff
      [    4.224767] bc80  bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000
      [    4.224790] bca0  e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8 bf0138a0 e183bcdc e183bcc8
      [    4.224813] bcc0  bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c e183bce0 bf01acc4 bf01aafc
      [    4.224836] bce0  00000001 bf03ff88 00000000 e2e9d600 00000000 bf03f564 00000001 e22a9664
      [    4.224859]
                     IP: 0xe183bba0:
      [    4.224865] bba0  00000000 c06ff958 e183bbc4 e1876b80 00000004 c0bec00c e183bc04 e183bbc8
      [    4.224888] bbc0  c003d04c c004dec8 e183bbfc 00000000 c00fcbb0 e1876b80 e23e75c0 e1876b80
      [    4.224910] bbe0  e183bc24 e183bc30 e1876bc0 e1876b90 00000005 c003d4d0 e183bc6c e183bc08
      [    4.224933] bc00  c003d4d0 c06ff4e0 e183bc2c c06ff900 e183bc2c e183bc20 c00d4614 40070013
      [    4.224956] bc20  ffffffff e183bc6c e183bc94 e183bc38 c0700098 c000a16c c0ad4eb0 60070013
      [    4.224979] bc40  00100100 00200200 bf03f364 c0ad4eb0 e2e9d600 00000000 bf03f564 00000001
      [    4.225001] bc60  e22a9664 e183bc94 e183bc20 e183bc80 c06ff900 c00d4614 40070013 ffffffff
      [    4.225024] bc80  bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000
      [    4.225048]
                     FP: 0xe183bc14:
      [    4.225054] bc14  e183bc20 c00d4614 40070013 ffffffff e183bc6c e183bc94 e183bc38 c0700098
      [    4.225077] bc34  c000a16c c0ad4eb0 60070013 00100100 00200200 bf03f364 c0ad4eb0 e2e9d600
      [    4.225100] bc54  00000000 bf03f564 00000001 e22a9664 e183bc94 e183bc20 e183bc80 c06ff900
      [    4.225122] bc74  c00d4614 40070013 ffffffff bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4
      [    4.225145] bc94  c00d45f0 bf040434 00000000 e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8
      [    4.225168] bcb4  bf0138a0 e183bcdc e183bcc8 bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c
      [    4.225191] bcd4  e183bce0 bf01acc4 bf01aafc 00000001 bf03ff88 00000000 e2e9d600 00000000
      [    4.225213] bcf4  bf03f564 00000001 e22a9664 e183bd2c e183bd10 bf01035c c0040e8c bf040468
      [    4.225237]
                     R0: 0xc0ad4e30:
      [    4.225243] 4e30  00000020 00000000 000001f4 0000000a 00000000 00000000 00000000 61666544
      [    4.225264] 4e50  00746c75 65646f4e 00000000 656e6f5a 00000000 00000001 00000000 c0ad4e6c
      [    4.225286] 4e70  c0ad4e6c 00000000 00000000 0000086f c0c1562c c0c1562c ffff8ca3 c0c15101
      [    4.225309] 4e90  c00ce330 00000000 ffffffff 00000014 0000000a 00000070 00000bb8 000001f4
      [    4.225331] 4eb0  ffffffff 003d003d c0ad4eb8 c0ad4eb8 e2c3ee64 e2030a64 0000003c c00d44f4
      [    4.225353] 4ed0  c00a708c c00a708c c00a708c c00d4444 c00a708c c00a708c c00a708c c00d4280
      [    4.225376] 4ef0  c00a708c c00a708c c00a708c c00d4208 c00a708c c00a708c c00a708c c00d4388
      [    4.225399] 4f10  c00a708c c00a708c c00a708c c00d41bc c00a708c c00a708c c00a708c c00d42f8
      [    4.225424]
                     R5: 0xc0ad4e30:
      [    4.225430] 4e30  00000020 00000000 000001f4 0000000a 00000000 00000000 00000000 61666544
      [    4.225452] 4e50  00746c75 65646f4e 00000000 656e6f5a 00000000 00000001 00000000 c0ad4e6c
      [    4.225473] 4e70  c0ad4e6c 00000000 00000000 0000086f c0c1562c c0c1562c ffff8ca3 c0c15101
      [    4.225496] 4e90  c00ce330 00000000 ffffffff 00000014 0000000a 00000070 00000bb8 000001f4
      [    4.225518] 4eb0  ffffffff 003d003d c0ad4eb8 c0ad4eb8 e2c3ee64 e2030a64 0000003c c00d44f4
      [    4.225541] 4ed0  c00a708c c00a708c c00a708c c00d4444 c00a708c c00a708c c00a708c c00d4280
      [    4.225564] 4ef0  c00a708c c00a708c c00a708c c00d4208 c00a708c c00a708c c00a708c c00d4388
      [    4.225587] 4f10  c00a708c c00a708c c00a708c c00d41bc c00a708c c00a708c c00a708c c00d42f8
      [    4.225611]
                     R6: 0xe2e9d580:
      [    4.225617] d580  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225638] d5a0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225658] d5c0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225679] d5e0  00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225700] d600  e2e9ec40 ffffffff 00000000 00000000 00000000 e2e97740 e2e9ec40 e2e9d41c
      [    4.225722] d620  e2e9d81c e2d0434c e2d04340 c0b9cfd8 e2da48c8 00000002 00000007 00000000
      [    4.225744] d640  00000000 00000000 00000000 e2e9d64c e2e9d64c e2f47a80 00000000 c0b9d290
      [    4.225766] d660  bf03f564 e20532c0 00000000 00000020 00050005 e2e9d474 e2e9d874 7fffffff
      [    4.225790]
                     R10: 0xe22a95e4:
      [    4.225796] 95e4  00000000 00000000 00000000 00000000 00000000 00000000 00000000 e22a95c0
      [    4.225817] 9604  e22a9604 e22a9604 bf03fe58 00000000 c0adf9c8 e219d3c8 00000001 00000003
      [    4.225839] 9624  00000000 00000000 00000000 00000000 00000000 00000000 00000000 e22a9600
      [    4.225861] 9644  00000001 e22a9d00 00000124 00000024 bf031518 c0078a5c 00000000 00000000
      [    4.225883] 9664  00000000 00000000 00000000 00000000 00000000 00000000 00000000 74636573
      [    4.225904] 9684  736e6f69 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225925] 96a4  00000000 00000000 00000000 00000000 00000000 00000000 00000000 7274732e
      [    4.225946] 96c4  00626174 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    4.225970] Process insmod (pid: 1231, stack limit = 0xe183a238)
      [    4.225978] Stack: (0xe183bc80 to 0xe183c000)
      [    4.225990] bc80: bf03f34c 00000000 e183bcb4 e183bc98 bf0138b4 c00d45f0 bf040434 00000000
      [    4.226002] bca0: e2e9d600 00000000 e183bcc4 e183bcb8 bf0124d8 bf0138a0 e183bcdc e183bcc8
      [    4.226014] bcc0: bf01aba4 bf0124c4 ffffffff bf040434 e183bd2c e183bce0 bf01acc4 bf01aafc
      [    4.226025] bce0: 00000001 bf03ff88 00000000 e2e9d600 00000000 bf03f564 00000001 e22a9664
      [    4.226037] bd00: e183bd2c e183bd10 bf01035c c0040e8c bf040468 bf040468 e2e9d600 00000000
      [    4.226048] bd20: e183bd4c e183bd30 bf01c390 bf01abcc e2e9d610 c0c5e31c 00000000 00000001
      [    4.226060] bd40: e183bd5c e183bd50 c0311a48 bf01c2e8 e183bd84 e183bd60 c031061c c0311a30
      [    4.226072] bd60: e2e9d610 e2e9d644 bf03f564 c0b9d290 00000000 00000001 e183bda4 e183bd88
      [    4.226084] bd80: c031082c c0310564 00000000 bf03f564 c03107b4 c0b9d290 e183bdcc e183bda8
      [    4.226095] bda0: c030eb1c c03107c0 e2d1e3dc e2e97774 c06ff8a8 bf03f564 00000000 e2782ac0
      [    4.226107] bdc0: e183bddc e183bdd0 c03100e4 c030eaac e183be04 e183bde0 c030fc80 c03100c8
      [    4.226119] bde0: bf034a1b e183bdf0 bf03f564 bf01c540 c0bf3700 bf03fe58 e183be24 e183be08
      [    4.226132] be00: c0310e3c c030fb98 e183a000 bf01c540 c0bf3700 bf03fe58 e183be34 e183be28
      [    4.226144] be20: c031203c c0310d9c e183be4c e183be38 bf01c55c c0311ff4 e183a000 bf01c540
      [    4.226156] be40: e183be8c e183be50 c000a4d8 bf01c54c c00f4e2c e183bf48 00000001 bf03fe10
      [    4.226167] be60: bf03fe58 e22a9640 e183be8c e183bf48 00000001 bf03fe10 bf03fe58 e22a9640
      [    4.226179] be80: e183bf44 e183be90 c007b3ec c000a43c bf03fe1c 00007fff c00772ec c0be8c40
      [    4.226191] bea0: 000ad8e5 bf03ff74 eb765f84 e183beb8 c0709f2c c0078b88 e22a9648 00000000
      [    4.226203] bec0: bf03fe1c e183a000 c00f5218 c00f49bc ffffffff c007b9f8 c007b9f8 bf03153c
      [    4.226213] bee0: 0000000b bf031594 00000003 00000000 00000000 00000000 00000000 00000000
      [    4.226224] bf00: 00000000 00000000 00000000 00000000 00000000 00000000 ffffffff b6952008
      [    4.226236] bf20: 000ad8e5 00442fd4 00000080 c000fac8 e183a000 00000000 e183bfa4 e183bf48
      [    4.226248] bf40: c007ba74 c0079e44 eb323000 00442fd4 eb7655ac eb65dc38 eb66a4dc 00030958
      [    4.226258] bf60: 0003b498 00000000 00000000 00000000 0000003f 00000040 00000028 00000000
      [    4.226270] bf80: 00000016 00000000 c0013994 00000000 00000069 bee8ede4 00000000 e183bfa8
      [    4.226281] bfa0: c000f880 c007b9ac 00000000 00000069 b6952008 00442fd4 000ad8e5 00000000
      [    4.226292] bfc0: 00000000 00000069 bee8ede4 00000080 00000001 bee8edec b6f20000 0009b9aa
      [    4.226304] bfe0: b6e29901 bee8ea98 0002810f b6e29908 80080030 b6952008 000027ff 00002800
      [    4.226421] [<c00d4614>] (unregister_shrinker+0x30/0x5c) from [<bf0138b4>] (mali_mem_os_term+0x20/0xd0 [mali])
      [    4.226574] [<bf0138b4>] (mali_mem_os_term+0x20/0xd0 [mali]) from [<bf0124d8>] (mali_memory_terminate+0x20/0x34 [mali])
      [    4.226733] [<bf0124d8>] (mali_memory_terminate+0x20/0x34 [mali]) from [<bf01aba4>] (mali_terminate_subsystems+0xb4/0xd0 [mali])
      [    4.226904] [<bf01aba4>] (mali_terminate_subsystems+0xb4/0xd0 [mali]) from [<bf01acc4>] (mali_initialize_subsystems+0x104/0x518 [mali])
      [    4.227076] [<bf01acc4>] (mali_initialize_subsystems+0x104/0x518 [mali]) from [<bf01c390>] (mali_probe+0xb4/0x220 [mali])
      [    4.227174] [<bf01c390>] (mali_probe+0xb4/0x220 [mali]) from [<c0311a48>] (platform_drv_probe+0x24/0x28)
      [    4.227191] [<c0311a48>] (platform_drv_probe+0x24/0x28) from [<c031061c>] (driver_probe_device+0xc4/0x208)
      [    4.227205] [<c031061c>] (driver_probe_device+0xc4/0x208) from [<c031082c>] (__driver_attach+0x78/0x9c)
      [    4.227219] [<c031082c>] (__driver_attach+0x78/0x9c) from [<c030eb1c>] (bus_for_each_dev+0x7c/0xa0)
      [    4.227233] [<c030eb1c>] (bus_for_each_dev+0x7c/0xa0) from [<c03100e4>] (driver_attach+0x28/0x30)
      [    4.227247] [<c03100e4>] (driver_attach+0x28/0x30) from [<c030fc80>] (bus_add_driver+0xf4/0x228)
      [    4.227261] [<c030fc80>] (bus_add_driver+0xf4/0x228) from [<c0310e3c>] (driver_register+0xac/0x130)
      [    4.227276] [<c0310e3c>] (driver_register+0xac/0x130) from [<c031203c>] (platform_driver_register+0x54/0x68)
      [    4.227370] [<c031203c>] (platform_driver_register+0x54/0x68) from [<bf01c55c>] (init_module+0x1c/0x64 [mali])
      [    4.227466] [<bf01c55c>] (init_module+0x1c/0x64 [mali]) from [<c000a4d8>] (do_one_initcall+0xa8/0x144)
      [    4.227483] [<c000a4d8>] (do_one_initcall+0xa8/0x144) from [<c007b3ec>] (load_module+0x15b4/0x1b68)
      [    4.227498] [<c007b3ec>] (load_module+0x15b4/0x1b68) from [<c007ba74>] (SyS_init_module+0xd4/0xdc)
      [    4.227512] [<c007ba74>] (SyS_init_module+0xd4/0xdc) from [<c000f880>] (ret_fast_syscall+0x0/0x30)
      [    4.227524] Code: eb18a52c e5943010 e1a00005 e594200c (e5823004)
      [    4.227534] ---[ end trace c57267c46477aee1 ]---
      [    4.420068]
                     insmod_device_driver
      
      [    4.577148]  fbid=0 uiid=0
      [    4.577166] [DISP] sunxi_fb_to_display,line:590:sunxi_fb_to_display fb0 UIid 0
      [    4.577179] [DISP] sunxi_fb_to_display,line:653:sunxi_fb_to_display set fb0 UIid 0 chan[1]lid[0]z[3]
      
      发布在 飞凌嵌入式专区
      B
      bigfly
    • 按照文档的教程用SPI驱动LCD屏幕初始化失败

      按照文档的教程,https://r128.docs.aw-ol.com/demo/spilcd/
      进行到这一步应该是有正确的输出

      微信图片_20231017100039.png

      但是我这里没有看到SPI初始化的相关内容,以下是我输出的内容

      微信图片_20231017100027.png 微信图片_20231017100035.png

      发布在 A Series
      B
      bigfly
    • R128开发板上的这个元件是啥

      请问模块的这个部分是什么?在线文档里的图片没有标注出来,看上去有点像麦克风

      9F1AFC23-CEB7-409f-8E70-4FD89F1EFFA5.png

      发布在 A Series
      B
      bigfly
    • 【XR806开发板试用】系列之二:出现已经成功编译,但是无法生成镜像文件的问题

      本文主要对于编译成功但是烧录出现问题进行解决,用Hello world 和LED点亮代码作为示范

      文章仅为参考网络资料和自身理解,如有不正确之处请多指正

      1、首先确定自己根目录在哪,我们都在根目录进行hb set和hb build -f,判断方法是寻找ohos_config.json文件所在目录。

      2425078455-65143105a4f77.png

      点开可以看见其中的配置信息,记录的信息都能与自身环境对应上

      1593018543-6514314d51268.png

      2、值得一提的是,我在按照官方步骤操作发现虽然源码已经编译成功但是无法成功烧录到板子上,我刚刚开始找到的原因是product_path下的BUILD.gn文件,官方说明如下,但是我的该目录下的BUILD.gn文件是空的。原来以为是这个的原因导致烧录不成功,经过试错和询问大佬后一直没解决,后面解决后也没有更改这个 BUILD.gn.,所以官方文档可能是想说的从device_path中寻找的BUILD.gn,很是避坑^_^

      851362203-6514328568e9d.png

      3、以下简单说明一下如何将自己的代码添加到编译系统进行编译,详细内容仍旧参考官方文档.

      首先进入 $(root_path)/device/xradio/xr806/ohosdemo,(root_path含义见第一点中提到的oho_config.json),再找到同目录下的BUILD.gn,将其中的依赖(deps)添加或者取消注释,使其加入编译系统的编译过程

      1950750716-651435df48cde.png

      -配置的含义是在相同目录下找到一个名为_hello_world和LED 或者 iot_peripheral/wlan_demo的文件夹,在去到该文件夹中寻找BUILD.gn获取相关源代码和包含头文件的信息,BUILD.gn看不懂不要紧,能够明白流程就够了。

      2964444481-6514379f82c76.png

      完成以上步骤理论上在根目录使用hb set& hb build -f再使用烧录工具就可以完成烧录,但是总会出现一些意外情况

      开始我由于看见了一篇博客【XR806开发板试用】编译中的几个问题以及hello跑起来,让我了解到生成可烧录的镜像文件,如何查找后缀为.a的文件用来链接生成镜像文件:$(root_path)/device/xradio/xr806/xr_skylark 目录下的ohos.mk记录了查找到的文件,果然,当时并没有显示我已经生成的.a文件。博客中说可以手动添加,但是我手动添加会报错,大家可以尝试一下。

      2368549074-65143c093b61d.png

      接下来,我们就要更改生成ohos.mk的配置文件,配置文件是$(root_path)/device/xradio/xr806 下的 libcopy.py

      1436004550-65143e4e3a0cb.png

      更改完成后,用file libcopy.py查看文件换行符的格式

      若显示结果中有with CRLF line terminators,则用dos2unix

      libcopy.py转化成Unix下的换行符格式,如果需要保留源格式,可加上参数-n libcopy_back将原来格式存为备份

      更改完成后,可以尝试在跟目录下重新hb build -f编译,如果没有报错,并且在ohos.mk中发现了正确的链接文件地址,那么恭喜你可以开始编写任何你想要的代码了。但是如果出现了这样的报错(注意观察是从哪开始报错的,并且检查error.log)

      [OHOS ERROR] [253/254] ACTION //device/xradio/xr806:libSDK(//build/lite/toolchain:arm-none-eabi-gcc)
      [OHOS ERROR] FAILED: obj/device/xradio/xr806/libSDK_build_ext_components.txt
      

      解决方法论坛原文:

      $(root_path)/device/xradio/xr806/xr_skylark/project/demo/wlan_ble_demo/image/xr806中的image_auto_cal.cfg复制一份粘贴到$(root_path)/device/xradio/xr806/xr_skylark/project/demo/audio_demo/image/xr806 下面替换掉image.cfg。
      原因可以在$(root_path)/device/xradio/xr806/xr_skylark/project/image_cfg/readme.md 中找到
      

      改完之后就可以通过烧录软件烧录到板子上了^_^ 😂

      发布在 Wireless & Analog Series
      B
      bigfly