19 Commits

Author SHA1 Message Date
4df18d88dd add:psdk重启后,通知ximeaAirborneSystem发送ximeaAirborneSystem的状态,以恢复psdk状态至重启前; 2023-10-25 15:16:09 +08:00
80159490e1 modify:修改dji日志输出路径 2023-09-16 19:30:05 +08:00
884cd90ac4 fix:卫星数显示异常(跳变); 2023-09-13 17:28:54 +08:00
1b12e68f84 add:高功率申请 2023-09-13 15:43:41 +08:00
db81ffe5cc 1.帧率变大时,最大曝光时间会变小
2.曝光时间使用微秒
3.预约采集
2023-09-07 15:24:51 +08:00
9f76699bc2 modify:
系统指令 整个挪到最上面 →  高级指令;
2023-09-01 15:28:25 +08:00
23153193a6 modify:
1. 删掉文本输入框,hz改为赫兹;
2. 曝光时间超过最大值后,设置为最大值:psdk取消曝光时间检测,让ximeaAirborneSystem设置曝光时间的最大值;
5. bin修改后,自动杀掉程序;
3. 去掉采集流程控制:高光谱采集提示请先设置曝光时间;
4. 去掉帧率完成和曝光完成,只保留连接成功;
2023-09-01 15:27:45 +08:00
47153346cd fix
1. 无法第二次启动,授时等待时间优化;
2. 遥控器界面显示:硬盘可用空间,当前帧率剩余飞行时间;
3. 帧率曝光时间和遥控器右侧边栏数字联动;
4. bin2后面加通道数,侧边栏显示bin和通道数;
5. 遥控器去掉惯导定位精度,改为显示full nav;
6. 其他界面改动;
2023-08-23 11:56:23 +08:00
699112b487 相机控制 2023-08-18 11:49:20 +08:00
4343500d70 推流 2023-08-18 10:50:41 +08:00
b2f2c17b7a DataTransmission 2023-08-18 10:45:06 +08:00
c2559f2bbc 电源管理 2023-08-16 18:36:23 +08:00
5938550032 推流:代码移植后,运行成功,但是遥控器无法正常显示摄像头画面; 2023-08-16 17:45:58 +08:00
bf32d053a6 xport
1、解决问题:飞机急停,俯仰角异常;
2、获取云台的姿态角,并显示到遥控器上;
2023-08-14 14:35:32 +08:00
6688d23e13 消息订阅 2023-08-14 11:40:53 +08:00
916a8d8fc9 遥控器界面 2023-08-07 13:34:12 +08:00
8c834c4884 add:填写硬件配置和app信息,成功运行示例程序 2023-08-04 11:04:28 +08:00
DJI
59b71864e4 Merge pull request #100 from dji-sdk/release/v3.5
FIX: fix the androideabi lib lost issue
2023-05-18 21:51:12 +08:00
758f1f3979 FIX: fix the androideabi lib lost issue
Signed-off-by: DJI-Martin <DJI-Martin@dji.com>
2023-05-18 21:49:24 +08:00
40 changed files with 2154 additions and 307 deletions

83
.gitignore vendored Normal file
View File

@ -0,0 +1,83 @@
# tc
/.idea/*
/build/*
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# AWS User-specific
.idea/**/aws.xml
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/artifacts
# .idea/compiler.xml
# .idea/jarRepositories.xml
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# *.iml
# *.ipr
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# SonarLint plugin
.idea/sonarlint/
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser

View File

@ -37,7 +37,7 @@ extern "C" {
#define DJI_VERSION_MINOR 5 /*!< DJI SDK minor version num, when add functionality in a backwards compatible manner changes. Range from 0 to 99. */
#define DJI_VERSION_MODIFY 0 /*!< DJI SDK modify version num, when have backwards compatible bug fixes changes. Range from 0 to 99. */
#define DJI_VERSION_BETA 0 /*!< DJI SDK version beta info, release version will be 0, when beta version release changes. Range from 0 to 255. */
#define DJI_VERSION_BUILD 1764 /*!< DJI SDK version build info, when jenkins trigger build changes. Range from 0 to 65535. */
#define DJI_VERSION_BUILD 1765 /*!< DJI SDK version build info, when jenkins trigger build changes. Range from 0 to 65535. */
/* Exported types ------------------------------------------------------------*/

Binary file not shown.

Binary file not shown.

View File

@ -93,11 +93,11 @@ bool DjiMediaFile_IsSupported(const char *filePath)
T_DjiReturnCode DjiMediaFile_CreateHandle(const char *filePath, T_DjiMediaFileHandle *pMediaFileHandle)
{
int optIndex;
int optIndex;//这个指数 指明了 filePath中的文件格式 处于数组s_mediaFileOpt中的哪一个元素
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
for (optIndex = 0; optIndex < s_mediaFileOptCount; optIndex++) {
if (s_mediaFileOpt[optIndex].isSupportedFunc(filePath) == true) {
if (s_mediaFileOpt[optIndex].isSupportedFunc(filePath) == true) {//查看filePath的格式是否 存在于 所有支持的格式中
break;
}
}
@ -116,7 +116,7 @@ T_DjiReturnCode DjiMediaFile_CreateHandle(const char *filePath, T_DjiMediaFileHa
return DJI_ERROR_SYSTEM_MODULE_CODE_MEMORY_ALLOC_FAILED;
}
(*pMediaFileHandle)->mediaFileOptItem = s_mediaFileOpt[optIndex];
(*pMediaFileHandle)->mediaFileOptItem = s_mediaFileOpt[optIndex];//为pMediaFileHandle(媒体文件句柄)添加处理函数
(*pMediaFileHandle)->mediaFileThm.privThm = NULL;
(*pMediaFileHandle)->mediaFileScr.privScr = NULL;

View File

@ -0,0 +1,176 @@
//
// Created by tangchao on 2021/11/16.
//
#include "ffmpeg_tc.h"
char *getsystemtime()
{
//获取系统时间
time_t timer;//time_t就是long int 类型
struct tm *tblock;
timer = time(NULL);//返回秒数(精度为秒)从1970-1-1,00:00:00 可以当成整型输出或用于其它函数
tblock = localtime(&timer);
//printf("Local time is: %s\n", asctime(tblock));
//格式化时间为需要的格式
char fileNameTmp[256] = { 0 };
char dirNameTmp[256] = { 0 };
strftime(fileNameTmp, sizeof(fileNameTmp), "%Y%m%d_%H%M%S", tblock);
return fileNameTmp;
}
AVFrame *get_video_frame(IntputDev* input)//tc改动
{
clock_t start,finish;
start = clock(); // 设置开始clock
int ret;
AVFrame * ret_frame=NULL;
if(av_read_frame(input->v_ifmtCtx, input->in_packet)>=0)
{
if(input->in_packet->stream_index==input->videoindex)
{
ret = avcodec_send_packet(input->pCodecCtx, input->in_packet);
if (ret < 0) {
fprintf(stderr, "Error sending a packet for decoding\n");
exit(1);
}
ret = avcodec_receive_frame(input->pCodecCtx, input->pFrame);
if(ret<0)
{
printf("Decode Error.\n");
av_packet_unref(input->in_packet);
return NULL;
}
sws_scale(input->img_convert_ctx, (const unsigned char* const*)input->pFrame->data, input->pFrame->linesize, 0, input->pCodecCtx->height, input->pFrameYUV->data, input->pFrameYUV->linesize);
input->pFrameYUV->pts=input->next_pts++;
ret_frame= input->pFrameYUV;
}
av_packet_unref(input->in_packet);
}
finish = clock();// 设置结束clock
double duration = (double)(finish - start) / CLOCKS_PER_SEC;//转换浮点型
// printf( "采集视频帧时间:%lf seconds\n", duration );
return ret_frame;
}
//
//static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt)
//{
// int ret;
//
// /* send the frame to the encoder */
// if (frame)
// printf("Send frame %3"PRId64"\n", frame->pts);
//
// ret = avcodec_send_frame(enc_ctx, frame);//返回-21?????????????????????????????????????????????
// if (ret < 0) {
// fprintf(stderr, "Error sending a frame for encoding\n");
// exit(1);
// }
//
// while (ret >= 0) {
// ret = avcodec_receive_packet(enc_ctx, pkt);
// if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
// return;
// else if (ret < 0) {
// fprintf(stderr, "Error during encoding\n");
// exit(1);
// }
//
//// printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
//// fwrite(pkt->data, 1, pkt->size, outfile);
// av_packet_unref(pkt);
// }
//}
void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt, char **data, int *datasize)
{
int ret;
/* send the frame to the encoder */
// if (frame)
// printf("Send frame %3"PRId64"\n", frame->pts);
ret = avcodec_send_frame(enc_ctx, frame);//返回-21?????????????????????????????????????????????
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
printf("11111111111111111111\n");
return;
}
else if (ret < 0) {
fprintf(stderr, "Error during encoding\n");
exit(1);
}
// printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
// fwrite(pkt->data, 1, pkt->size, outfile);
//tc
char *dataBuffer = calloc(pkt->size, 1);
memcpy(dataBuffer,pkt->data,pkt->size);
*data = dataBuffer;
*datasize = pkt->size;
av_packet_unref(pkt);
}
printf("22222222222222222\n");
}
char * encode2(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt, int *datasize)
{
clock_t start,finish;
start = clock(); // 设置开始clock
int ret;
char *dataBuffer;
ret = avcodec_send_frame(enc_ctx, frame);
if (ret < 0) {
fprintf(stderr, "Error sending a frame for encoding\n");
exit(1);
}
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
printf("11111111111111111111\n");
return NULL;
}
else if (ret < 0) {
fprintf(stderr, "Error during encoding\n");
exit(1);
}
// printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
// fwrite(pkt->data, 1, pkt->size, outfile);
//tc
dataBuffer = calloc(pkt->size, 1);
memcpy(dataBuffer,pkt->data,pkt->size);
*datasize = pkt->size;
av_packet_unref(pkt);
finish = clock();// 设置结束clock
double duration = (double)(finish - start) / CLOCKS_PER_SEC;//转换浮点型
// printf( "编码视频帧时间:%lf seconds\n", duration );
return dataBuffer;
}
}

View File

@ -0,0 +1,63 @@
//
// Created by tangchao on 2021/11/16.
//
#ifndef PSDK_DEMO_FFMPEG_TC_H
#define PSDK_DEMO_FFMPEG_TC_H
//tc开始
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include "libavdevice/avdevice.h"
#include <libavutil/imgutils.h>
#include <unistd.h>//usleep
#define STREAM_DURATION 50.0 /*录制视频的持续时间 秒*/
#define STREAM_FRAME_RATE 15 /* images/s 这里可以根据摄像头的采集速度来设置帧率 */
#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P /* default pix_fmt */
#define SCALE_FLAGS SWS_BICUBIC
//tc结束
//存放视频的宽度和高度
int video_width;
int video_height;
typedef struct IntputDev
{
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFormatContext *v_ifmtCtx;
int videoindex;
struct SwsContext *img_convert_ctx;
AVPacket *in_packet;
AVFrame *pFrame,*pFrameYUV;
/*下一帧的点数*/
int64_t next_pts;
}IntputDev;
char *getsystemtime();
AVFrame *get_video_frame(IntputDev* input);
//static void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt);
void encode(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt, char **data, int *datasize);
char * encode2(AVCodecContext *enc_ctx, AVFrame *frame, AVPacket *pkt, int *datasize);
#endif //PSDK_DEMO_FFMPEG_TC_H

View File

@ -75,12 +75,12 @@ typedef struct {
/* Private variables ---------------------------------------------------------*/
static bool s_isCamInited = false;
static T_DjiCameraCommonHandler s_commonHandler;
static T_DjiCameraExposureMeteringHandler s_exposureMeteringHandler;
static T_DjiCameraFocusHandler s_focusHandler;
static T_DjiCameraDigitalZoomHandler s_digitalZoomHandler;
static T_DjiCameraOpticalZoomHandler s_opticalZoomHandler;
static T_DjiCameraTapZoomHandler s_tapZoomHandler;
static T_DjiCameraCommonHandler s_commonHandler;//注册相机类基础功能
static T_DjiCameraExposureMeteringHandler s_exposureMeteringHandler;//用于测光
static T_DjiCameraFocusHandler s_focusHandler;//设置对焦
static T_DjiCameraDigitalZoomHandler s_digitalZoomHandler;//数字变焦
static T_DjiCameraOpticalZoomHandler s_opticalZoomHandler;//光学变焦
static T_DjiCameraTapZoomHandler s_tapZoomHandler;//指点变焦功能
static T_DjiTaskHandle s_userCameraThread;
@ -96,8 +96,8 @@ static E_DjiCameraMeteringMode s_cameraMeteringMode = DJI_CAMERA_METERING_MODE_C
static T_DjiCameraSpotMeteringTarget s_cameraSpotMeteringTarget = {0};
static E_DjiCameraFocusMode s_cameraFocusMode = DJI_CAMERA_FOCUS_MODE_AUTO;
static T_DjiCameraPointInScreen s_cameraFocusTarget = {0};
static uint32_t s_cameraFocusRingValue = FOCUS_MID_RINGVALUE;
static T_DjiCameraPointInScreen s_cameraFocusTarget = {0};//对焦点
static uint32_t s_cameraFocusRingValue = FOCUS_MID_RINGVALUE;//对焦环
static T_DjiCameraFocusAssistantSettings s_cameraFocusAssistantSettings = {0};
static E_DjiCameraZoomDirection s_cameraZoomDirection = DJI_CAMERA_ZOOM_DIRECTION_OUT;
@ -120,6 +120,7 @@ static T_DjiMutexHandle s_tapZoomMutex = NULL;
static E_DjiCameraVideoStreamType s_cameraVideoStreamType;
/* Private functions declaration ---------------------------------------------*/
//用于s_commonHandler中的回调函数:相机类基础功能
static T_DjiReturnCode GetSystemState(T_DjiCameraSystemState *systemState);
static T_DjiReturnCode SetMode(E_DjiCameraMode mode);
static T_DjiReturnCode StartRecordVideo(void);
@ -135,11 +136,13 @@ static T_DjiReturnCode GetPhotoTimeIntervalSettings(T_DjiCameraPhotoTimeInterval
static T_DjiReturnCode GetSDCardState(T_DjiCameraSDCardState *sdCardState);
static T_DjiReturnCode FormatSDCard(void);
//用于s_exposureMeteringHandler中的回调函数:测光
static T_DjiReturnCode SetMeteringMode(E_DjiCameraMeteringMode mode);
static T_DjiReturnCode GetMeteringMode(E_DjiCameraMeteringMode *mode);
static T_DjiReturnCode SetSpotMeteringTarget(T_DjiCameraSpotMeteringTarget target);
static T_DjiReturnCode GetSpotMeteringTarget(T_DjiCameraSpotMeteringTarget *target);
//用于s_focusHandler中的回调函数:设置对焦功能
static T_DjiReturnCode SetFocusMode(E_DjiCameraFocusMode mode);
static T_DjiReturnCode GetFocusMode(E_DjiCameraFocusMode *mode);
static T_DjiReturnCode SetFocusTarget(T_DjiCameraPointInScreen target);
@ -150,18 +153,25 @@ static T_DjiReturnCode SetFocusRingValue(uint32_t value);
static T_DjiReturnCode GetFocusRingValue(uint32_t *value);
static T_DjiReturnCode GetFocusRingValueUpperBound(uint32_t *value);
//用于s_digitalZoomHandler的回调函数中:数字变焦功能
static T_DjiReturnCode SetDigitalZoomFactor(dji_f32_t factor);
//用于s_opticalZoomHandler的回调函数中:光学变焦功能
static T_DjiReturnCode SetOpticalZoomFocalLength(uint32_t focalLength);
static T_DjiReturnCode GetOpticalZoomFocalLength(uint32_t *focalLength);
static T_DjiReturnCode GetOpticalZoomSpec(T_DjiCameraOpticalZoomSpec *spec);
static T_DjiReturnCode StartContinuousOpticalZoom(E_DjiCameraZoomDirection direction, E_DjiCameraZoomSpeed speed);
static T_DjiReturnCode StopContinuousOpticalZoom(void);
//用于s_tapZoomHandler中的回调函数:指点变焦功能
static T_DjiReturnCode GetTapZoomState(T_DjiCameraTapZoomState *state);
static T_DjiReturnCode SetTapZoomEnabled(bool enabledFlag);
static T_DjiReturnCode GetTapZoomEnabled(bool *enabledFlag);
static T_DjiReturnCode SetTapZoomMultiplier(uint8_t multiplier);
static T_DjiReturnCode GetTapZoomMultiplier(uint8_t *multiplier);
static T_DjiReturnCode TapZoomAtTarget(T_DjiCameraPointInScreen target);
//
static T_DjiReturnCode DjiTest_CameraHybridZoom(uint32_t focalLength);
static T_DjiReturnCode DjiTest_CameraRotationGimbal(T_TestCameraGimbalRotationArgument gimbalRotationArgument);
@ -826,6 +836,7 @@ static T_DjiReturnCode TapZoomAtTarget(T_DjiCameraPointInScreen target)
return DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT_IN_CURRENT_STATE;
}
//设置云台相机指点变焦的模式
rotationMode = DJI_GIMBAL_ROTATION_MODE_RELATIVE_ANGLE;
rotationProperty.relativeAngleRotation.actionTime = TAP_ZOOM_DURATION / 10;
@ -938,8 +949,8 @@ static T_DjiReturnCode DjiTest_CameraRotationGimbal(T_TestCameraGimbalRotationAr
static void *UserCamera_Task(void *arg)
{
static uint32_t photoCnt = 0;
static uint32_t step = 0;
static uint32_t photoCnt = 0;//????????
static uint32_t step = 0;//控制任务的执行时间间隔
T_DjiReturnCode returnCode;
int32_t tempFocalLength = 0;
dji_f32_t tempDigitalFactor = 0.0f;
@ -950,7 +961,7 @@ static void *UserCamera_Task(void *arg)
USER_UTIL_UNUSED(arg);
while (1) {
osalHandler->TaskSleepMs(1000 / PAYLOAD_CAMERA_EMU_TASK_FREQ);
osalHandler->TaskSleepMs(1000 / PAYLOAD_CAMERA_EMU_TASK_FREQ);//睡眠10ms
step++;
returnCode = osalHandler->MutexLock(s_commonMutex);
@ -964,11 +975,13 @@ static void *UserCamera_Task(void *arg)
s_cameraSDCardState.availableCaptureCount = s_cameraSDCardState.remainSpaceInMB / SDCARD_PER_PHOTO_SPACE_IN_MB;
//realize your photo shoot and storage logic here
//1. 确认拍照状态使用PSDK 开发的相机类负载设备在执行完拍照动作后,需要获取负载设备的拍照状态。
if (s_cameraState.shootingState != DJI_CAMERA_SHOOTING_PHOTO_IDLE &&
photoCnt++ > TAKING_PHOTO_SPENT_TIME_MS_EMU / (1000 / PAYLOAD_CAMERA_EMU_TASK_FREQ)) {
photoCnt = 0;
//store the photo after shooting finished
//2. 存储照片相机类负载设备在执行完拍照后使用PSDK 开发的相机类负载设备将相机拍摄的照片存储在相机类负载设备上的内存卡中。
if (s_cameraShootPhotoMode == DJI_CAMERA_SHOOT_PHOTO_MODE_SINGLE) {
s_cameraSDCardState.remainSpaceInMB =
s_cameraSDCardState.remainSpaceInMB - SDCARD_PER_PHOTO_SPACE_IN_MB;
@ -989,6 +1002,7 @@ static void *UserCamera_Task(void *arg)
}
//check the remain space of sdcard
//3. 检查存储空间:
if (s_cameraSDCardState.remainSpaceInMB > SDCARD_TOTAL_SPACE_IN_MB) {
s_cameraSDCardState.remainSpaceInMB = 0;
s_cameraSDCardState.isFull = true;
@ -1025,6 +1039,8 @@ static void *UserCamera_Task(void *arg)
}
// 10Hz
// ! step%10相当于10毫秒执行一次tc → Add logic here for zoom camera
//没看关于这个if
if (USER_UTIL_IS_WORK_TURN(step, 10, PAYLOAD_CAMERA_EMU_TASK_FREQ)) {
returnCode = osalHandler->MutexLock(s_zoomMutex);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -1146,6 +1162,7 @@ out:
continue;
}
// 预估可拍照张数和可录像时长的功能。
if (s_cameraState.isRecording) {
s_cameraState.currentVideoRecordingTimeInSeconds++;
s_cameraSDCardState.remainSpaceInMB =
@ -1250,27 +1267,29 @@ T_DjiReturnCode DjiTest_CameraEmuBaseStartService(void)
SDCARD_TOTAL_SPACE_IN_MB / SDCARD_PER_SECONDS_RECORD_SPACE_IN_MB;
/* Register the camera common handler */
//注册相机类基础功能1SetMode设置相机工作模式照片/视频/回放2如果是photo模式使用SetShootPhotoMode设置照片拍照模式3StartShootPhoto开始拍摄照片
s_commonHandler.GetSystemState = GetSystemState;
s_commonHandler.SetMode = SetMode;
s_commonHandler.SetMode = SetMode;//设置相机模式:照片/视频/回放
s_commonHandler.GetMode = DjiTest_CameraGetMode;
s_commonHandler.StartRecordVideo = StartRecordVideo;
s_commonHandler.StartRecordVideo = StartRecordVideo;//控制相机录像s_cameraState.isRecording = true;
s_commonHandler.StopRecordVideo = StopRecordVideo;
s_commonHandler.StartShootPhoto = StartShootPhoto;
s_commonHandler.StartShootPhoto = StartShootPhoto;//控制相机拍摄照片:单拍/连拍/等时间间隔;只是改变了s_cameraState的状态
s_commonHandler.StopShootPhoto = StopShootPhoto;
s_commonHandler.SetShootPhotoMode = SetShootPhotoMode;
s_commonHandler.GetShootPhotoMode = GetShootPhotoMode;
s_commonHandler.SetPhotoBurstCount = SetPhotoBurstCount;
s_commonHandler.GetPhotoBurstCount = GetPhotoBurstCount;
s_commonHandler.SetPhotoTimeIntervalSettings = SetPhotoTimeIntervalSettings;
s_commonHandler.GetPhotoTimeIntervalSettings = GetPhotoTimeIntervalSettings;
s_commonHandler.GetSDCardState = GetSDCardState;
s_commonHandler.FormatSDCard = FormatSDCard;
s_commonHandler.SetShootPhotoMode = SetShootPhotoMode;//写入变量s_cameraShootPhotoMode设置相机类负载的拍照模式:单拍/连拍/等时间间隔
s_commonHandler.GetShootPhotoMode = GetShootPhotoMode;//读取变量s_cameraShootPhotoMode
s_commonHandler.SetPhotoBurstCount = SetPhotoBurstCount;//控制相机连拍写入变量s_cameraBurstCount
s_commonHandler.GetPhotoBurstCount = GetPhotoBurstCount;// 读取变量s_cameraBurstCount
s_commonHandler.SetPhotoTimeIntervalSettings = SetPhotoTimeIntervalSettings;//控制相机定时拍照变量s_cameraPhotoTimeIntervalSettings有啥用
s_commonHandler.GetPhotoTimeIntervalSettings = GetPhotoTimeIntervalSettings;// 读取变量s_cameraPhotoTimeIntervalSettings
s_commonHandler.GetSDCardState = GetSDCardState;//获取SD 卡的当前状态
s_commonHandler.FormatSDCard = FormatSDCard;//SD卡格式化
returnCode = DjiPayloadCamera_RegCommonHandler(&s_commonHandler);
returnCode = DjiPayloadCamera_RegCommonHandler(&s_commonHandler);//注册相机类基础功能
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("camera register common handler error:0x%08llX", returnCode);
}
//注册相机测光功能
/* Register the camera metering handler */
#if USER_CAMERA_EMU_METERING_ON
s_exposureMeteringHandler.SetMeteringMode = SetMeteringMode;
@ -1285,15 +1304,16 @@ T_DjiReturnCode DjiTest_CameraEmuBaseStartService(void)
}
#endif
//注册相机设置对焦功能
/* Register the camera focus handler */
#if USER_CAMERA_EMU_FOCUS_ON
s_focusHandler.SetFocusMode = SetFocusMode;
s_focusHandler.GetFocusMode = GetFocusMode;
s_focusHandler.SetFocusTarget = SetFocusTarget;
s_focusHandler.SetFocusTarget = SetFocusTarget;//设置对焦点
s_focusHandler.GetFocusTarget = GetFocusTarget;
s_focusHandler.SetFocusAssistantSettings = SetFocusAssistantSettings;
s_focusHandler.GetFocusAssistantSettings = GetFocusAssistantSettings;
s_focusHandler.SetFocusRingValue = SetFocusRingValue;
s_focusHandler.SetFocusRingValue = SetFocusRingValue;//设置对焦环
s_focusHandler.GetFocusRingValue = GetFocusRingValue;
s_focusHandler.GetFocusRingValueUpperBound = GetFocusRingValueUpperBound;
@ -1304,9 +1324,10 @@ T_DjiReturnCode DjiTest_CameraEmuBaseStartService(void)
}
#endif
//注册相机数字变焦功能
/* Register the camera digital zoom handler */
#if USER_CAMERA_EMU_HYBRID_ZOOM_ON
s_digitalZoomHandler.SetDigitalZoomFactor = SetDigitalZoomFactor;
s_digitalZoomHandler.SetDigitalZoomFactor = SetDigitalZoomFactor;//设置数字变焦因子
s_digitalZoomHandler.GetDigitalZoomFactor = DjiTest_CameraGetDigitalZoomFactor;
returnCode = DjiPayloadCamera_RegDigitalZoomHandler(&s_digitalZoomHandler);
@ -1315,12 +1336,13 @@ T_DjiReturnCode DjiTest_CameraEmuBaseStartService(void)
return returnCode;
}
//注册相机光学变焦功能
/* Register the camera optical zoom handler */
s_opticalZoomHandler.SetOpticalZoomFocalLength = SetOpticalZoomFocalLength;
s_opticalZoomHandler.SetOpticalZoomFocalLength = SetOpticalZoomFocalLength;//设置光学变焦相机的焦距
s_opticalZoomHandler.GetOpticalZoomFocalLength = GetOpticalZoomFocalLength;
s_opticalZoomHandler.GetOpticalZoomFactor = DjiTest_CameraGetOpticalZoomFactor;
s_opticalZoomHandler.GetOpticalZoomSpec = GetOpticalZoomSpec;
s_opticalZoomHandler.StartContinuousOpticalZoom = StartContinuousOpticalZoom;
s_opticalZoomHandler.GetOpticalZoomFactor = DjiTest_CameraGetOpticalZoomFactor;//获取相机类负载设备的变焦系数
s_opticalZoomHandler.GetOpticalZoomSpec = GetOpticalZoomSpec;//获取光学变焦的范围
s_opticalZoomHandler.StartContinuousOpticalZoom = StartContinuousOpticalZoom;//控制相机类负载设备开始变焦
s_opticalZoomHandler.StopContinuousOpticalZoom = StopContinuousOpticalZoom;
returnCode = DjiPayloadCamera_RegOpticalZoomHandler(&s_opticalZoomHandler);
@ -1330,6 +1352,7 @@ T_DjiReturnCode DjiTest_CameraEmuBaseStartService(void)
}
#endif
//注册指点变焦功能
/* Register the camera tap zoom handler */
#if USER_CAMERA_EMU_TAP_ZOOM_ON
s_tapZoomHandler.GetTapZoomState = GetTapZoomState;

View File

@ -92,6 +92,8 @@ static T_DjiReturnCode DjiPlayback_GetFrameRateOfVideoFile(const char *path, flo
static T_DjiReturnCode
DjiPlayback_GetFrameNumberByTime(T_TestPayloadCameraVideoFrameInfo *frameInfo, uint32_t frameCount,
uint32_t *frameNumber, uint32_t timeMs);
//用于s_psdkCameraMedia中的回调函数:相机类负载设备的下载回放功能
static T_DjiReturnCode GetMediaFileDir(char *dirPath);
static T_DjiReturnCode GetMediaFileOriginData(const char *filePath, uint32_t offset, uint32_t length,
uint8_t *data);
@ -120,12 +122,13 @@ static T_DjiReturnCode StartDownloadNotification(void);
static T_DjiReturnCode StopDownloadNotification(void);
_Noreturn static void *UserCameraMedia_SendVideoTask(void *arg);
static void *UserCameraMedia_SendVideoTask_tc(void *arg);
/* Private variables -------------------------------------------------------------*/
static T_DjiCameraMediaDownloadPlaybackHandler s_psdkCameraMedia = {0};
static T_DjiPlaybackInfo s_playbackInfo = {0};
static T_DjiCameraMediaDownloadPlaybackHandler s_psdkCameraMedia = {0};//控制相机类负载设备执行媒体文件下载回放功能
static T_DjiPlaybackInfo s_playbackInfo = {0};//非常重要的变量!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
static T_DjiTaskHandle s_userSendVideoThread;
static T_UtilBuffer s_mediaPlayCommandBufferHandler = {0};
static T_UtilBuffer s_mediaPlayCommandBufferHandler = {0};//非常重要的变量,用户自定义功能读取此变量中的命令执行相应的操作!!!!!!!!!!!!!!!!!!!
static T_DjiMutexHandle s_mediaPlayCommandBufferMutex = {0};
static uint8_t s_mediaPlayCommandBuffer[sizeof(T_TestPayloadCameraPlaybackCommand) * 32] = {0};
static const char *s_frameKeyChar = "[PACKET]";
@ -152,30 +155,36 @@ T_DjiReturnCode DjiTest_CameraEmuMediaStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
// 实现获取媒体文件信息的功能
s_psdkCameraMedia.GetMediaFileDir = GetMediaFileDir;
s_psdkCameraMedia.GetMediaFileOriginInfo = DjiTest_CameraMediaGetFileInfo;
s_psdkCameraMedia.GetMediaFileOriginData = GetMediaFileOriginData;
s_psdkCameraMedia.GetMediaFileOriginInfo = DjiTest_CameraMediaGetFileInfo;//非常重要!!!!!获取视频文件信息(类型、帧率、分辨率等)
s_psdkCameraMedia.GetMediaFileOriginData = GetMediaFileOriginData;//获取视频文件数据
// 实现获取媒体文件缩略图的功能
s_psdkCameraMedia.CreateMediaFileThumbNail = CreateMediaFileThumbNail;
s_psdkCameraMedia.GetMediaFileThumbNailInfo = GetMediaFileThumbNailInfo;
s_psdkCameraMedia.GetMediaFileThumbNailData = GetMediaFileThumbNailData;
s_psdkCameraMedia.DestroyMediaFileThumbNail = DestroyMediaFileThumbNail;
// 实现获取媒体文件截屏图的功能
s_psdkCameraMedia.CreateMediaFileScreenNail = CreateMediaFileScreenNail;
s_psdkCameraMedia.GetMediaFileScreenNailInfo = GetMediaFileScreenNailInfo;
s_psdkCameraMedia.GetMediaFileScreenNailData = GetMediaFileScreenNailData;
s_psdkCameraMedia.DestroyMediaFileScreenNail = DestroyMediaFileScreenNail;
// 实现删除媒体文件的功能
s_psdkCameraMedia.DeleteMediaFile = DeleteMediaFile;
// 实现控制媒体文件回放的功能
s_psdkCameraMedia.SetMediaPlaybackFile = SetMediaPlaybackFile;
s_psdkCameraMedia.StartMediaPlayback = StartMediaPlayback;
s_psdkCameraMedia.StopMediaPlayback = StopMediaPlayback;
s_psdkCameraMedia.PauseMediaPlayback = PauseMediaPlayback;
s_psdkCameraMedia.StartMediaPlayback = StartMediaPlayback;//主要作用是将命令写入到s_mediaPlayCommandBufferHandler
s_psdkCameraMedia.StopMediaPlayback = StopMediaPlayback;//主要作用是将命令写入到s_mediaPlayCommandBufferHandler
s_psdkCameraMedia.PauseMediaPlayback = PauseMediaPlayback;//主要作用是将命令写入到s_mediaPlayCommandBufferHandler
s_psdkCameraMedia.SeekMediaPlayback = SeekMediaPlayback;
s_psdkCameraMedia.GetMediaPlaybackStatus = GetMediaPlaybackStatus;
// 实现下载媒体文件的功能
s_psdkCameraMedia.StartDownloadNotification = StartDownloadNotification;
s_psdkCameraMedia.StopDownloadNotification = StopDownloadNotification;
@ -186,6 +195,7 @@ T_DjiReturnCode DjiTest_CameraEmuMediaStartService(void)
UtilBuffer_Init(&s_mediaPlayCommandBufferHandler, s_mediaPlayCommandBuffer, sizeof(s_mediaPlayCommandBuffer));
// 注册相机类负载设备的下载回放功能
if (aircraftInfoBaseInfo.aircraftType == DJI_AIRCRAFT_TYPE_M300_RTK ||
aircraftInfoBaseInfo.aircraftType == DJI_AIRCRAFT_TYPE_M350_RTK) {
returnCode = DjiPayloadCamera_RegMediaDownloadPlaybackHandler(&s_psdkCameraMedia);
@ -201,14 +211,15 @@ T_DjiReturnCode DjiTest_CameraEmuMediaStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
if (DjiPlatform_GetHalNetworkHandler() != NULL || DjiPlatform_GetHalUsbBulkHandler() != NULL) {
returnCode = osalHandler->TaskCreate("user_camera_media_task", UserCameraMedia_SendVideoTask, 2048,
NULL, &s_userSendVideoThread);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("user send video task create error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
}
// 创建线程执行用户自定义函数
// if (DjiPlatform_GetHalNetworkHandler() != NULL || DjiPlatform_GetHalUsbBulkHandler() != NULL) {
// returnCode = osalHandler->TaskCreate("user_camera_media_task", UserCameraMedia_SendVideoTask_tc, 2048,
// NULL, &s_userSendVideoThread);
// if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
// USER_LOG_ERROR("user send video task create error.");
// return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
// }
// }
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
@ -227,7 +238,7 @@ T_DjiReturnCode DjiTest_CameraMediaGetFileInfo(const char *filePath, T_DjiCamera
T_DjiReturnCode returnCode;
T_DjiMediaFileHandle mediaFileHandle;
returnCode = DjiMediaFile_CreateHandle(filePath, &mediaFileHandle);
returnCode = DjiMediaFile_CreateHandle(filePath, &mediaFileHandle);//mediaFileHandle是重点其中注册了很多处理媒体文件的函数
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Media file create handle error stat:0x%08llX", returnCode);
return returnCode;
@ -252,7 +263,7 @@ T_DjiReturnCode DjiTest_CameraMediaGetFileInfo(const char *filePath, T_DjiCamera
}
out:
returnCode = DjiMediaFile_DestroyHandle(mediaFileHandle);
returnCode = DjiMediaFile_DestroyHandle(mediaFileHandle);//释放内存空间
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Media file destroy handle error stat:0x%08llX", returnCode);
return returnCode;
@ -291,6 +302,7 @@ static T_DjiReturnCode DjiPlayback_PausePlay(T_DjiPlaybackInfo *playbackInfo)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//内存空间>=一个命令???????????????????????????????????????????????????????????????????????????
if (UtilBuffer_GetUnusedSize(&s_mediaPlayCommandBufferHandler) >= sizeof(T_TestPayloadCameraPlaybackCommand)) {
UtilBuffer_Put(&s_mediaPlayCommandBufferHandler, (const uint8_t *) &playbackCommand,
sizeof(T_TestPayloadCameraPlaybackCommand));
@ -336,12 +348,14 @@ static T_DjiReturnCode DjiPlayback_SeekPlay(T_DjiPlaybackInfo *playbackInfo, uin
T_DjiRunTimeStamps ti;
T_DjiReturnCode returnCode;
//先暂停播放
returnCode = DjiPlayback_PausePlay(playbackInfo);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("pause play error \n");
return returnCode;
}
//将需要播放的位置写入到变量playbackInfo中
playbackInfo->playPosMs = seekPos;
returnCode = DjiPlayback_StartPlayProcess(playbackInfo->filePath, playbackInfo->playPosMs);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -545,6 +559,7 @@ static T_DjiReturnCode DjiPlayback_VideoFileTranscode(const char *inPath, const
snprintf(ffmpegCmdStr, FFMPEG_CMD_BUF_SIZE,
"echo \"y\" | ffmpeg -i \"%s\" -codec copy -f \"%s\" \"%s\" 1>/dev/null 2>&1", inPath,
outFormat, outPath);
// printf(ffmpegCmdStr);
fpCommand = popen(ffmpegCmdStr, "r");
if (fpCommand == NULL) {
USER_LOG_ERROR("execute transcode command fail.");
@ -620,6 +635,7 @@ DjiPlayback_GetFrameInfoOfVideoFile(const char *path, T_TestPayloadCameraVideoFr
goto out1;
}
//%%表示这里就是一个“%”符,让程序不要理解成格式符
ret = snprintf(frameParameterFormat, sizeof(frameParameterFormat), "%s=%%f", s_frameDurationTimeKeyChar);
if (ret < 0) {
USER_LOG_ERROR("snprintf frameParameterFormat fail.");
@ -627,6 +643,7 @@ DjiPlayback_GetFrameInfoOfVideoFile(const char *path, T_TestPayloadCameraVideoFr
goto out1;
}
//将DurationTime从frameDurationTimeLocation读入到frameDurationTimeS
ret = sscanf(frameDurationTimeLocation, frameParameterFormat, &frameDurationTimeS);
if (ret <= 0) {
USER_LOG_ERROR("can not find pkt_duration_time.");
@ -681,7 +698,7 @@ DjiPlayback_GetFrameInfoOfVideoFile(const char *path, T_TestPayloadCameraVideoFr
}
frameInfo[frameNumber].size = frameSize;
frameLocation += strlen(s_frameKeyChar);
frameLocation += strlen(s_frameKeyChar);//排除已经找到的帧
frameNumber++;
(*frameCount)++;
@ -1020,6 +1037,7 @@ static T_DjiReturnCode SetMediaPlaybackFile(const char *filePath)
return returnCode;
}
//设置完成回放文件后,就开始回放(播放回放文件)
returnCode = DjiPlayback_StartPlay(&s_playbackInfo);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
return returnCode;
@ -1033,7 +1051,7 @@ static T_DjiReturnCode StartMediaPlayback(void)
T_DjiReturnCode returnCode;
USER_LOG_INFO("start media playback");
returnCode = DjiPlayback_StartPlay(&s_playbackInfo);
returnCode = DjiPlayback_StartPlay(&s_playbackInfo);//s_playbackInfo是哪里设置的????????????????????
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("start media playback status error, stat:0x%08llX", returnCode);
return returnCode;
@ -1149,6 +1167,7 @@ static T_DjiReturnCode StopDownloadNotification(void)
#pragma GCC diagnostic ignored "-Wreturn-type"
#endif
//https://developer.dji.com/doc/payload-sdk-tutorial/cn/function-set/advanced-function/camera-video-stream-transmission.html
static void *UserCameraMedia_SendVideoTask(void *arg)
{
int ret;
@ -1159,12 +1178,12 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
uint16_t lengthOfDataToBeSent = 0;
int lengthOfDataHaveBeenSent = 0;
char *dataBuffer = NULL;
T_TestPayloadCameraPlaybackCommand playbackCommand = {0};
T_TestPayloadCameraPlaybackCommand playbackCommand = {0};//??????????????????????
uint16_t bufferReadSize = 0;
char *videoFilePath = NULL;
char *transcodedFilePath = NULL;
char *transcodedFilePath = NULL;//转换视频编码后的文件路径
float frameRate = 1.0f;
T_TestPayloadCameraVideoFrameInfo *frameInfo = NULL;
T_TestPayloadCameraVideoFrameInfo *frameInfo = NULL;//时长,大小,此帧在文件中的位置
uint32_t frameNumber = 0;
uint32_t frameCount = 0;
uint32_t startTimeMs = 0;
@ -1180,6 +1199,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
USER_UTIL_UNUSED(arg);
//获取视频流文件信息(1)
returnCode = DjiUserUtil_GetCurrentFileDirPath(__FILE__, DJI_FILE_PATH_SIZE_MAX, curFileDirPath);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Get file current path error, stat = 0x%08llX", returnCode);
@ -1191,6 +1211,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
snprintf(tempPath, DJI_FILE_PATH_SIZE_MAX, "%smedia_file/PSDK_0005.h264", curFileDirPath);
}
//使用PSDK 开发的相机类负载设备在创建视频流处理线程后,需要先初始化线程状态并向相机类负载设备申请用于缓存视频流文件的内存空间。
videoFilePath = osalHandler->Malloc(DJI_FILE_PATH_SIZE_MAX);
if (videoFilePath == NULL) {
USER_LOG_ERROR("malloc memory for video file path fail.");
@ -1210,6 +1231,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
}
memset(frameInfo, 0, VIDEO_FRAME_MAX_COUNT * sizeof(T_TestPayloadCameraVideoFrameInfo));
//???????????????????????????????????????????????????????????????
returnCode = DjiPlayback_StopPlayProcess();
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("stop playback and start liveview error: 0x%08llX.", returnCode);
@ -1225,6 +1247,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
continue;
}
//将参数从s_mediaPlayCommandBufferHandler拷贝到playbackCommand
bufferReadSize = UtilBuffer_Get(&s_mediaPlayCommandBufferHandler, (uint8_t *) &playbackCommand,
sizeof(T_TestPayloadCameraPlaybackCommand));
@ -1233,10 +1256,10 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
continue;
}
if (bufferReadSize != sizeof(T_TestPayloadCameraPlaybackCommand))
if (bufferReadSize != sizeof(T_TestPayloadCameraPlaybackCommand))//?????????????????????????????
goto send;
switch (playbackCommand.command) {
switch (playbackCommand.command) {//测试开机后不做任何操作的情况下这个command是什么类型
case TEST_PAYLOAD_CAMERA_MEDIA_PLAY_COMMAND_STOP:
snprintf(videoFilePath, DJI_FILE_PATH_SIZE_MAX, "%s", tempPath);
startTimeMs = 0;
@ -1259,6 +1282,9 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
}
// video send preprocess
//获取视频流文件信息(2)
//获取H.264 文件的信息
//???????????????????????????????????????????????????????
returnCode = DjiPlayback_VideoFileTranscode(videoFilePath, "h264", transcodedFilePath,
DJI_FILE_PATH_SIZE_MAX);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -1272,6 +1298,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
continue;
}
//????????????????????????????????????????????????????????????????????
returnCode = DjiPlayback_GetFrameInfoOfVideoFile(transcodedFilePath, frameInfo, VIDEO_FRAME_MAX_COUNT,
&frameCount);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -1280,7 +1307,7 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
}
returnCode = DjiPlayback_GetFrameNumberByTime(frameInfo, frameCount, &frameNumber,
startTimeMs);
startTimeMs);//获取指定时间所在帧的位置(帧号)
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get start frame number error: 0x%08llX.", returnCode);
continue;
@ -1289,15 +1316,15 @@ static void *UserCameraMedia_SendVideoTask(void *arg)
if (fpFile != NULL)
fclose(fpFile);
fpFile = fopen(transcodedFilePath, "rb+");
fpFile = fopen(transcodedFilePath, "rb+");//打开编码后的文件
if (fpFile == NULL) {
USER_LOG_ERROR("open video file fail.");
USER_LOG_ERROR("open video file fail.111111111111111111111111");
continue;
}
send:
if (fpFile == NULL) {
USER_LOG_ERROR("open video file fail.");
USER_LOG_ERROR("open video file fail.222222222222222222222222222");
continue;
}
@ -1314,14 +1341,19 @@ send:
continue;
}
//????????????????????????????????
if (mode == DJI_CAMERA_MODE_PLAYBACK && s_playbackInfo.isInPlayProcess == false) {
continue;
}
//????????????????????????????????
if (!USER_UTIL_IS_WORK_TURN(sendVideoStep++, frameRate, SEND_VIDEO_TASK_FREQ))
continue;
frameBufSize = frameInfo[frameNumber].size;
//3. 解析视频流文件
//基于PSDK 开发的相机类负载设备获取视频流文件的信息后,将解析视频流文件的内容,识别视频流文件的帧头。
frameBufSize = frameInfo[frameNumber].size;//这行几行代码的意思:每一帧的大小不一样
if (videoStreamType == DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT) {
frameBufSize = frameBufSize + VIDEO_FRAME_AUD_LEN;
}
@ -1345,11 +1377,21 @@ send:
USER_LOG_DEBUG("read data from video file success, len = %d B\r\n", dataLength);
}
//4. 发送视频流数据
//基于PSDK 开发的相机类负载设备在解析视频流文件并识别视频流文件的帧头后调用视频流发送接口PsdkPayloadCamera_SendVideoStream,
//以逐帧的方式发送视频流数据。若视频流格式为DJI H264格式需要在每一帧的最后增加AUD信息用于标识一帧的结束。
if (videoStreamType == DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT) {
memcpy(&dataBuffer[frameInfo[frameNumber].size], s_frameAudInfo, VIDEO_FRAME_AUD_LEN);
dataLength = dataLength + VIDEO_FRAME_AUD_LEN;
}
// for(int i=0;i<dataLength - VIDEO_FRAME_AUD_LEN;i++)
// {
//// printf("%c",data[i]);
// printf("%02X ",dataBuffer[i]);
// }
// printf("\n");
lengthOfDataHaveBeenSent = 0;
while (dataLength - lengthOfDataHaveBeenSent) {
lengthOfDataToBeSent = USER_UTIL_MIN(DATA_SEND_FROM_VIDEO_STREAM_MAX_LEN,
@ -1370,6 +1412,8 @@ send:
sendVideoFlag = false;
}
//5. 获取视频流状态
//使用PSDK 开发的相机类负载设备能够获取视频流发送的实时状态,方便用户调整视频流的码率,确保图传画面的稳定显示。
returnCode = DjiPayloadCamera_GetVideoStreamState(&videoStreamState);
if (returnCode == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_DEBUG(
@ -1386,6 +1430,457 @@ free:
}
}
static void *UserCameraMedia_SendVideoTask_tc(void *arg)
{
int ret;
T_DjiReturnCode returnCode;
static uint32_t sendVideoStep = 0;
FILE *fpFile = NULL;
unsigned long dataLength = 0;
uint16_t lengthOfDataToBeSent = 0;
int lengthOfDataHaveBeenSent = 0;
char *dataBuffer = NULL;
T_TestPayloadCameraPlaybackCommand playbackCommand = {0};//??????????????????????
uint16_t bufferReadSize = 0;
char *videoFilePath = NULL;
char *transcodedFilePath = NULL;//转换视频编码后的文件路径
float frameRate = 1.0f;
T_TestPayloadCameraVideoFrameInfo *frameInfo = NULL;//时长,大小,此帧在文件中的位置
uint32_t frameNumber = 0;
uint32_t frameCount = 0;
uint32_t startTimeMs = 0;
bool sendVideoFlag = true;
bool sendOneTimeFlag = false;
T_DjiDataChannelState videoStreamState = {0};
E_DjiCameraMode mode = DJI_CAMERA_MODE_SHOOT_PHOTO;
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
uint32_t frameBufSize = 0;
E_DjiCameraVideoStreamType videoStreamType;
char curFileDirPath[DJI_FILE_PATH_SIZE_MAX];
char tempPath[DJI_FILE_PATH_SIZE_MAX];
USER_UTIL_UNUSED(arg);
//获取视频流文件信息(1)
returnCode = DjiUserUtil_GetCurrentFileDirPath(__FILE__, DJI_FILE_PATH_SIZE_MAX, curFileDirPath);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Get file current path error, stat = 0x%08llX", returnCode);
exit(1);
}
if (s_isMediaFileDirPathConfigured == true) {
snprintf(tempPath, DJI_FILE_PATH_SIZE_MAX, "%sPSDK_0005.h264", s_mediaFileDirPath);
} else {
snprintf(tempPath, DJI_FILE_PATH_SIZE_MAX, "%smedia_file/PSDK_0005.h264", curFileDirPath);
}
//使用PSDK 开发的相机类负载设备在创建视频流处理线程后,需要先初始化线程状态并向相机类负载设备申请用于缓存视频流文件的内存空间。
videoFilePath = osalHandler->Malloc(DJI_FILE_PATH_SIZE_MAX);
if (videoFilePath == NULL) {
USER_LOG_ERROR("malloc memory for video file path fail.");
exit(1);
}
transcodedFilePath = osalHandler->Malloc(DJI_FILE_PATH_SIZE_MAX);
if (transcodedFilePath == NULL) {
USER_LOG_ERROR("malloc memory for transcoded file path fail.");
exit(1);
}
frameInfo = osalHandler->Malloc(VIDEO_FRAME_MAX_COUNT * sizeof(T_TestPayloadCameraVideoFrameInfo));
if (frameInfo == NULL) {
USER_LOG_ERROR("malloc memory for frame info fail.");
exit(1);
}
memset(frameInfo, 0, VIDEO_FRAME_MAX_COUNT * sizeof(T_TestPayloadCameraVideoFrameInfo));
//???????????????????????????????????????????????????????????????
returnCode = DjiPlayback_StopPlayProcess();
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("stop playback and start liveview error: 0x%08llX.", returnCode);
exit(1);
}
/*tc111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111*/
// int ret;
int have_video = 0, have_audio = 0;
int encode_video = 0, encode_audio = 0;
AVDictionary *opt = NULL;
int i;
/*添加摄像头******************************************************************************************************************************/
char *dev_name = "/dev/video10";
//输入文件格式
AVFormatContext *v_ifmtCtx;
v_ifmtCtx = avformat_alloc_context();
AVInputFormat *ifmt=av_find_input_format("video4linux2");
avdevice_register_all();
ret = avformat_open_input(&v_ifmtCtx, dev_name, ifmt, NULL);//根据摄像头名字dev_name和格式ifmt 打开流摄像头v_ifmtCtx
if(ret!=0)
{
printf("无法打开摄像头输入流:%d\n",ret);
return -1;
}
// printf("摄像头输入流的封装格式为:%s\n",ifmt->name);//因为ifmt=null所以此行代码出现段错误
//input video initialize
if(avformat_find_stream_info(v_ifmtCtx,NULL)<0)//获取流(摄像头)的信息
{
printf("找不到流信息.\n");
return -1;
}
int videoindex = -1;
for (i = 0; i < v_ifmtCtx->nb_streams; i++)
{
if (v_ifmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoindex = i;
break;
}
}
if(videoindex==-1)
{
printf("找不到视频流。\n");
return -1;
}
//获取帧率信息
int aa = v_ifmtCtx->streams[videoindex]->r_frame_rate.num;
int bb = v_ifmtCtx->streams[videoindex]->r_frame_rate.den;
double dInputFps = v_ifmtCtx->streams[videoindex]->r_frame_rate.num*1.0 / v_ifmtCtx->streams[videoindex]->r_frame_rate.den;
printf("摄像头的帧率%d\n",(int)dInputFps);
//视频流的编解码器
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
pCodec=avcodec_find_decoder(v_ifmtCtx->streams[videoindex]->codecpar->codec_id);
printf("编码器名字:%%s\n",pCodec->name);
if(pCodec==NULL)
{
printf("找不到编解码器。\n");
return -1;
}
// pCodecCtx=v_ifmtCtx->streams[videoindex]->codecpar;//老版api方式新版放弃
// pCodecCtx=avcodec_alloc_context3(NULL);
pCodecCtx=avcodec_alloc_context3(pCodec);//tc
if (pCodecCtx == NULL)
{
printf("Could not allocate AVCodecContext\n");
return -1;
}
avcodec_parameters_to_context(pCodecCtx, v_ifmtCtx->streams[videoindex]->codecpar);
if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)
{
printf("无法打开编解码器。\n");
return -1;
}
AVFrame *pFrame,*pFrameYUV;
pFrame=av_frame_alloc();
pFrameYUV=av_frame_alloc();
unsigned char *out_buffer=(unsigned char *)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,16));
// av_image_fill_arrays((AVPicture *)pFrameYUV->data,(AVPicture *)pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,16);
av_image_fill_arrays(pFrameYUV->data,pFrameYUV->linesize, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height,16);
video_width=pCodecCtx->width;
video_height=pCodecCtx->height;
printf("摄像头尺寸(WxH): %d x %d \n",pCodecCtx->width, pCodecCtx->height);
//tc:
pFrameYUV->format = AV_PIX_FMT_YUV420P;
pFrameYUV->width = video_width;
pFrameYUV->height = video_height;
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
IntputDev video_input={0};
AVPacket *in_packet=(AVPacket *)av_malloc(sizeof(AVPacket));
video_input.img_convert_ctx=img_convert_ctx;
video_input.in_packet=in_packet;
video_input.pCodecCtx=pCodecCtx;
video_input.pCodec=pCodec;
video_input.v_ifmtCtx=v_ifmtCtx;
video_input.videoindex=videoindex;
video_input.pFrame=pFrame;
video_input.pFrameYUV=pFrameYUV;
/*添加摄像头结束*******************************************************************************************************************************************/
/*添加输出信息*******************************************************************************************************************************************/
// if (argc <= 2) {
// fprintf(stderr, "Usage: %s <output file> <codec name>\n", argv[0]);//libx264
// exit(0);
// }
const char *filename, *codec_name;
const AVCodec *codec;
AVCodecContext *c= NULL;
// int i, ret, x, y;
FILE *f;
AVFrame *frame;
AVPacket *pkt;
// filename = argv[1];
// codec_name = argv[2];
filename = "delete.h264";
codec_name = "libx264";
/* find the mpeg1video encoder */
codec = avcodec_find_encoder_by_name(codec_name);
if (!codec) {
fprintf(stderr, "Codec '%s' not found\n", codec_name);
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
pkt = av_packet_alloc();
if (!pkt)
exit(1);
c->codec_id = codec->id;
c->bit_rate = 400000; //平均比特率,例子代码默认值是400000
/* 分辨率必须是2的倍数。*/
c->width=video_width;
c->height=video_height;
/*时基:这是基本的时间单位(以秒为单位)
*表示其中的帧时间戳。 对于固定fps内容
*时基应为1 /framerate时间戳增量应为
*等于1。*/
c->time_base = (AVRational){1, 15};
c->framerate = (AVRational){15, 1};
c->gop_size = 15; /* emit one intra frame every twelve frames at most */
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->max_b_frames = 0;
av_opt_set(c->priv_data, "tune", "zerolatency", 0);//解决编码延时
av_opt_set(c->priv_data, "preset", "superfast", 0);
if(c->codec_id == AV_CODEC_ID_MPEG2VIDEO)
{
/* 只是为了测试我们还添加了B帧 */
c->max_b_frames = 2;
}
if(c->codec_id == AV_CODEC_ID_MPEG1VIDEO)
{
/*需要避免使用其中一些系数溢出的宏块。
*普通视频不会发生这种情况,因为
*色度平面的运动与亮度平面不匹配。 */
c->mb_decision = 2;
}
/* open it */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
fprintf(stderr, "Could not open codec: %s\n", av_err2str(ret));
exit(1);
}
AVFrame *frame_tmp;
char *data;
int datasize;
clock_t start,finish;
/*tc222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222*/
while (1) {
// response playback command
if (osalHandler->MutexLock(s_mediaPlayCommandBufferMutex) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("mutex lock error");
continue;
}
//将参数从s_mediaPlayCommandBufferHandler拷贝到playbackCommand
bufferReadSize = UtilBuffer_Get(&s_mediaPlayCommandBufferHandler, (uint8_t *) &playbackCommand,
sizeof(T_TestPayloadCameraPlaybackCommand));
if (osalHandler->MutexUnlock(s_mediaPlayCommandBufferMutex) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("mutex unlock error");
continue;
}
if (bufferReadSize != sizeof(T_TestPayloadCameraPlaybackCommand))//?????????????????????????????
goto send;
//1测试开机后不做任何操作的情况下这个command是什么类型2这个switch有啥用
switch (playbackCommand.command) {
case TEST_PAYLOAD_CAMERA_MEDIA_PLAY_COMMAND_STOP:
snprintf(videoFilePath, DJI_FILE_PATH_SIZE_MAX, "%s", tempPath);
startTimeMs = 0;
sendVideoFlag = true;
sendOneTimeFlag = false;
break;
case TEST_PAYLOAD_CAMERA_MEDIA_PLAY_COMMAND_PAUSE:
sendVideoFlag = false;
goto send;
case TEST_PAYLOAD_CAMERA_MEDIA_PLAY_COMMAND_START:
snprintf(videoFilePath, DJI_FILE_PATH_SIZE_MAX, "%s", playbackCommand.path);
startTimeMs = playbackCommand.timeMs;
sendVideoFlag = true;
sendOneTimeFlag = true;
break;
default:
USER_LOG_ERROR("playback command invalid: %d.", playbackCommand.command);
sendVideoFlag = false;
goto send;
}
// video send preprocess
//获取视频流文件信息(2)
//获取H.264 文件的信息
//将输入视频文件videoFilePath编码为h264并写到视频文件中transcodedFilePath
returnCode = DjiPlayback_VideoFileTranscode(videoFilePath, "h264", transcodedFilePath,
DJI_FILE_PATH_SIZE_MAX);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("transcode video file error: 0x%08llX.", returnCode);
continue;
}
returnCode = DjiPlayback_GetFrameRateOfVideoFile(transcodedFilePath, &frameRate);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get frame rate of video error: 0x%08llX.", returnCode);
continue;
}
//获取每一帧的信息并存入frameInfoframeCount代表此文件共有多少帧
returnCode = DjiPlayback_GetFrameInfoOfVideoFile(transcodedFilePath, frameInfo, VIDEO_FRAME_MAX_COUNT,
&frameCount);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get frame info of video error: 0x%08llX.", returnCode);
continue;
}
//获取指定时间所在帧的位置(帧号)
returnCode = DjiPlayback_GetFrameNumberByTime(frameInfo, frameCount, &frameNumber,
startTimeMs);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get start frame number error: 0x%08llX.", returnCode);
continue;
}
if (fpFile != NULL)
fclose(fpFile);
fpFile = fopen(transcodedFilePath, "rb+");//打开编码后的文件
if (fpFile == NULL) {
USER_LOG_ERROR("open video file fail.111111111111111111111111");
continue;
}
send:
frame_tmp=get_video_frame(&video_input);
// encode(c, frame_tmp, pkt, &data, &datasize);
data = encode2(c, frame_tmp, pkt, &datasize);
if(data == NULL)
{
// printf("编码后数据为空!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
continue;
}
//3. 解析视频流文件
//基于PSDK 开发的相机类负载设备获取视频流文件的信息后,将解析视频流文件的内容,识别视频流文件的帧头。
frameBufSize = datasize;
if (videoStreamType == DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT) {
frameBufSize = frameBufSize + VIDEO_FRAME_AUD_LEN;
}
dataBuffer = calloc(frameBufSize, 1);
if (dataBuffer == NULL) {
USER_LOG_ERROR("malloc fail.");
goto free;
}
memcpy(dataBuffer,data,datasize);
dataLength = datasize;
//4. 发送视频流数据
//基于PSDK 开发的相机类负载设备在解析视频流文件并识别视频流文件的帧头后调用视频流发送接口PsdkPayloadCamera_SendVideoStream,
//以逐帧的方式发送视频流数据。若视频流格式为DJI H264格式需要在每一帧的最后增加AUD信息用于标识一帧的结束。
if (videoStreamType == DJI_CAMERA_VIDEO_STREAM_TYPE_H264_DJI_FORMAT) {
memcpy(&dataBuffer[datasize], s_frameAudInfo, VIDEO_FRAME_AUD_LEN);
dataLength = dataLength + VIDEO_FRAME_AUD_LEN;
}
//tc将视频帧打印出来
// char *deletestr = calloc(dataLength+5,1);
// memcpy(deletestr, data, datasize);
// printf("正在显示的视频帧:%s\n", deletestr);
// free(deletestr);
//
// for(i=0;i<datasize;i++)
// {
//// printf("%c",data[i]);
// printf("%02X ",data[i]);
// }
// printf("\n");
start = clock(); // 设置开始clock
lengthOfDataHaveBeenSent = 0;
while (dataLength - lengthOfDataHaveBeenSent) {
lengthOfDataToBeSent = USER_UTIL_MIN(DATA_SEND_FROM_VIDEO_STREAM_MAX_LEN,
dataLength - lengthOfDataHaveBeenSent);
returnCode = DjiPayloadCamera_SendVideoStream((const uint8_t *) dataBuffer + lengthOfDataHaveBeenSent,
lengthOfDataToBeSent);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("send video stream error: 0x%08llX.", returnCode);
}
lengthOfDataHaveBeenSent += lengthOfDataToBeSent;
}
finish = clock();// 设置结束clock
double duration = (double)(finish - start) / CLOCKS_PER_SEC;//转换浮点型
// printf( "发送视频帧时间:%lf seconds\n", duration );
//5. 获取视频流状态
//使用PSDK 开发的相机类负载设备能够获取视频流发送的实时状态,方便用户调整视频流的码率,确保图传画面的稳定显示。
returnCode = DjiPayloadCamera_GetVideoStreamState(&videoStreamState);
if (returnCode == DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_DEBUG(
"video stream state: realtimeBandwidthLimit: %d, realtimeBandwidthBeforeFlowController: %d, realtimeBandwidthAfterFlowController:%d busyState: %d.",
videoStreamState.realtimeBandwidthLimit, videoStreamState.realtimeBandwidthBeforeFlowController,
videoStreamState.realtimeBandwidthAfterFlowController,
videoStreamState.busyState);
} else {
USER_LOG_ERROR("get video stream state error.");
}
free:
free(dataBuffer);
free(data);
}
}
#ifndef __CC_ARM
#pragma GCC diagnostic pop
#endif

View File

@ -31,6 +31,8 @@
#include "dji_typedef.h"
#include "dji_payload_camera.h"
#include "ffmpeg_tc.h"
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -46,7 +46,7 @@ static T_DjiReturnCode ReceiveDataFromOnboardComputer(const uint8_t *data, uint1
static T_DjiReturnCode ReceiveDataFromPayload(const uint8_t *data, uint16_t len);
/* Private variables ---------------------------------------------------------*/
static T_DjiTaskHandle s_userDataTransmissionThread;
static T_DjiTaskHandle s_userDataTransmissionThread;//线程句柄
static T_DjiAircraftInfoBaseInfo s_aircraftInfoBaseInfo;
/* Exported functions definition ---------------------------------------------*/
@ -72,6 +72,7 @@ T_DjiReturnCode DjiTest_DataTransmissionStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
}
//函数ReceiveDataFromMobile能够获取用户在DJI Pilot "文本输入框控件" 中向负载设备发送的信息编码格式为UTF-8
channelAddress = DJI_CHANNEL_ADDRESS_MASTER_RC_APP;
djiStat = DjiLowSpeedDataChannel_RegRecvDataCallback(channelAddress, ReceiveDataFromMobile);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -113,6 +114,7 @@ T_DjiReturnCode DjiTest_DataTransmissionStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_NONSUPPORT;
}
//调用osal层中注册的创建任务的函数来 创建一个任务(在新线程中运行)
if (osalHandler->TaskCreate("user_transmission_task", UserDataTransmission_Task,
DATA_TRANSMISSION_TASK_STACK_SIZE, NULL, &s_userDataTransmissionThread) !=
DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {

View File

@ -41,6 +41,9 @@ static void *UserFcSubscription_Task(void *arg);
static T_DjiReturnCode DjiTest_FcSubscriptionReceiveQuaternionCallback(const uint8_t *data, uint16_t dataSize,
const T_DjiDataTimestamp *timestamp);
static char* uitoa(unsigned int n, char *s);
static int GMT_toLocalTime(unsigned long gmt_time,unsigned int* year,unsigned int* month,unsigned int* day,unsigned int* hour,unsigned int* minute,unsigned int* sec);
/* Private variables ---------------------------------------------------------*/
static T_DjiTaskHandle s_userFcSubscriptionThread;
static bool s_userFcSubscriptionDataShow = false;
@ -48,6 +51,7 @@ static uint8_t s_totalSatelliteNumberUsed = 0;
static uint32_t s_userFcSubscriptionDataCnt = 0;
/* Exported functions definition ---------------------------------------------*/
//要先订阅消息(DjiFcSubscription_SubscribeTopic),才能获取消息(DjiFcSubscription_GetLatestValueOfTopic)
T_DjiReturnCode DjiTest_FcSubscriptionStartService(void)
{
T_DjiReturnCode djiStat;
@ -60,6 +64,7 @@ T_DjiReturnCode DjiTest_FcSubscriptionStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//订阅姿态四元数
djiStat = DjiFcSubscription_SubscribeTopic(DJI_FC_SUBSCRIPTION_TOPIC_QUATERNION, DJI_DATA_SUBSCRIPTION_TOPIC_50_HZ,
DjiTest_FcSubscriptionReceiveQuaternionCallback);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -69,6 +74,7 @@ T_DjiReturnCode DjiTest_FcSubscriptionStartService(void)
USER_LOG_DEBUG("Subscribe topic quaternion success.");
}
//订阅无人机速度
djiStat = DjiFcSubscription_SubscribeTopic(DJI_FC_SUBSCRIPTION_TOPIC_VELOCITY, DJI_DATA_SUBSCRIPTION_TOPIC_1_HZ,
NULL);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -96,6 +102,21 @@ T_DjiReturnCode DjiTest_FcSubscriptionStartService(void)
USER_LOG_DEBUG("Subscribe topic gps details success.");
}
//订阅gps日期
djiStat = DjiFcSubscription_SubscribeTopic(DJI_FC_SUBSCRIPTION_TOPIC_GPS_DATE, 1,NULL);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Subscribe topic QUATERNION error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//订阅gps时间
djiStat = DjiFcSubscription_SubscribeTopic(DJI_FC_SUBSCRIPTION_TOPIC_GPS_TIME, 1,NULL);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Subscribe topic QUATERNION error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//创建用户任务
if (osalHandler->TaskCreate("user_subscription_task", UserFcSubscription_Task,
FC_SUBSCRIPTION_TASK_STACK_SIZE, NULL, &s_userFcSubscriptionThread) !=
DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -248,9 +269,14 @@ static void *UserFcSubscription_Task(void *arg)
T_DjiFcSubscriptionGpsDetails gpsDetails = {0};
T_DjiOsalHandler *osalHandler = NULL;
T_DjiFcSubscriptionGpsDate gpsDate={0};
T_DjiFcSubscriptionGpsTime gpsTime={0};
USER_UTIL_UNUSED(arg);
osalHandler = DjiPlatform_GetOsalHandler();
int counter = 0;
bool isGetGpsDate_time = true;
while (1) {
osalHandler->TaskSleepMs(1000 / FC_SUBSCRIPTION_TASK_FREQ);
@ -295,9 +321,192 @@ static void *UserFcSubscription_Task(void *arg)
s_totalSatelliteNumberUsed = gpsDetails.totalSatelliteNumberUsed;
}
djiStat = DjiFcSubscription_GetLatestValueOfTopic(DJI_FC_SUBSCRIPTION_TOPIC_GPS_DATE,
(uint8_t *) &gpsDate,
sizeof(T_DjiFcSubscriptionGpsDate),
&timestamp);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get value of topic gps DATE error.");
isGetGpsDate_time = false;
} else {
USER_LOG_DEBUG("timestamp: millisecond %u microsecond %u.", timestamp.millisecond,
timestamp.microsecond);
USER_LOG_DEBUG("gps DATE: %d.", gpsDate);
}//PsdkLogger_UserLogInfo
djiStat = DjiFcSubscription_GetLatestValueOfTopic(DJI_FC_SUBSCRIPTION_TOPIC_GPS_TIME,
(uint8_t *) &gpsTime,
sizeof(T_DjiFcSubscriptionGpsTime),
&timestamp);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get value of topic gps TIME error.");
isGetGpsDate_time = false;
} else {
USER_LOG_DEBUG("gps TIME: %d.", gpsTime);
}//PsdkLogger_UserLogInfo
if(counter>1 &&counter<3 && isGetGpsDate_time)//避免dji的bug第一次获取的gpsDate和gpsTime都为0
{
printf("开始设置时间\n");
system("date");
char *gpsDate_str = (char *)malloc(sizeof(char)*50);
char *gpsTime_str = (char *)malloc(sizeof(char)*20);
uitoa(gpsDate,gpsDate_str);
uitoa(gpsTime,gpsTime_str);
strcat(gpsDate_str, gpsTime_str);
// printf("pingjie----------------------------------------------:%s\n",gpsDate_str);
char *year = (char *)malloc(sizeof(char)*10);
char *mon = (char *)malloc(sizeof(char)*10);
char *mday = (char *)malloc(sizeof(char)*10);
char *hour = (char *)malloc(sizeof(char)*10);
char *min = (char *)malloc(sizeof(char)*10);
char *sec = (char *)malloc(sizeof(char)*10);
strncpy(year, gpsDate_str, 4);
strncpy(mon, gpsDate_str+4, 2);
strncpy(mday, gpsDate_str+6, 2);
if(gpsTime >= 100000)//dji时间格式为hhmmss但是当时间小于上午10点时小时位hh只有1位219232:19:23
{
strncpy(hour, gpsTime_str, 2);
strncpy(min, gpsTime_str+2, 2);
strncpy(sec, gpsTime_str+4, 2);
}
else
{
strncpy(hour, gpsTime_str, 1);
strncpy(min, gpsTime_str+1, 2);
strncpy(sec, gpsTime_str+3, 2);
}
// printf("year:%s\n",year);
// printf("mon:%s\n",mon);
// printf("mday:%s\n",mday);
// printf("hour:%s\n",hour);
// printf("min:%s\n",min);
// printf("sec:%s\n",sec);
struct tm info;
info.tm_year = atoi(year) - 1900;;
info.tm_mon = atoi(mon) - 1;
info.tm_mday = atoi(mday);
info.tm_hour = atoi(hour) + 8;
info.tm_min = atoi(min);
info.tm_sec = atoi(sec);
info.tm_isdst = -1;
int gmt_time = mktime(&info);
LocalTimeInfo LocalTime;
GMT_toLocalTime(gmt_time,&LocalTime.year,&LocalTime.month,&LocalTime.day,&LocalTime.hour,&LocalTime.minute,&LocalTime.second);
// printf("MyLocalTime=%d-%d-%d %d:%d:%d\n",LocalTime.year,LocalTime.month,LocalTime.day,LocalTime.hour,LocalTime.minute,LocalTime.second);
char *timeParam = (char *)malloc(sizeof(char)*500);
sprintf(timeParam,"%d-%d-%d %d:%d:%d",LocalTime.year,LocalTime.month,LocalTime.day,LocalTime.hour,LocalTime.minute,LocalTime.second);
// printf("----------: %s",timeParam);
char *command = (char *)malloc(sizeof(char)*100);
strcat(command, "date -s \"");
strcat(command, timeParam);
strcat(command, "\"");
// printf("command---:%s\n",command);
system(command);
system("echo \"1\" > /media/nvme/300TC/config/timesyncfromdji");
}
counter++;
}
}
char* uitoa(unsigned int n, char *s)
{
int i, j;
i = 0;
char buf[20];
memset(buf, 0, sizeof(buf));
do{
buf[i++] = n % 10 + '0';//取下一个数字
} while ((n /= 10)>0);//删除该数字
i -= 1;
for (j = 0; i >= 0; j++, i--)//生成的数字是逆序的,所以要逆序输出
s[j] = buf[i];
s[j] = '\0';
return s;
}
/*格林威治时间就是1970年01月01日00时00分00秒起至现在的总秒数*/
/*通过格林威治时间,计算本地时间*/
int GMT_toLocalTime(unsigned long gmt_time,unsigned int* year,unsigned int* month,unsigned int* day,unsigned int* hour,unsigned int* minute,unsigned int* sec)
{
int TIME_ZONE = 8;
unsigned long gmtTime = gmt_time + TIME_ZONE * 60 * 60;
int leap_years = 0;
int month_days[] = {31, 28, 31,30,31, 30,31,31, 30,31,30,31};
int i =0;
int days;
*sec = (int)(gmtTime%60);//秒钟数
gmtTime = gmtTime/60;//总共有多少分钟
*minute = (int)(gmtTime%60);
gmtTime = gmtTime/60;//总共有多少小时
*hour = (int)(gmtTime%24);
gmtTime = gmtTime/24;//总共有多少天
//去掉小时分钟秒钟后,转换成从公元元年开始到现在的天数
//不包括今天
gmtTime += 719162;
// 首先不考虑闰年计算年份和天数
// 计算年份
*year = (int)(gmtTime/365);
// days = 从公元元年开始到year的闰年个数 + 当前年份已经度过的天数除以365后的余数
days = (int)(gmtTime%365);
while(1)
{
//总共有多少个闰年,天数要相应的减去这些天数
leap_years = (*year)/4 - (*year)/100; //计算普通闰年
leap_years += (*year)/400; //加上世纪闰年
if(days < leap_years)
{
days+=365;
(*year)--;
}else break;
}
days -= leap_years;
(*year)++;
days++;
//计算今年总共度过了多少秒
if(((*year)%4 == 0 && (*year) % 100!=0) || (*year)%400==0) month_days[1] = 29;//今年是闰年,修改二月份为29天
*month = 1;
for(i=0;i<12;i++)
{
if(days <= month_days[i])
{
break;
}
else
{
days -=month_days[i];
(*month)++;
}
}
*day =days;
return 0;
}
#ifndef __CC_ARM
#pragma GCC diagnostic pop
#endif

View File

@ -31,6 +31,20 @@
#include "dji_typedef.h"
#include "dji_fc_subscription.h"
#include <malloc.h>
#include <stdlib.h>
#include <time.h>
typedef struct LocalTimeInformation
{
unsigned int year;
unsigned int month;
unsigned int day;
unsigned int hour;
unsigned int minute;
unsigned int second;
}LocalTimeInfo;
#ifdef __cplusplus
extern "C" {
#endif

View File

@ -33,9 +33,12 @@
/* Private types -------------------------------------------------------------*/
/* Private functions declaration ---------------------------------------------*/
//需要自己写的函数:功能是负载设备关机前需要执行的命令
//https://developer.dji.com/doc/payload-sdk-tutorial/cn/function-set/basic-function/power-management.html
static T_DjiReturnCode DjiTest_PowerOffNotificationCallback(bool *powerOffPreparationFlag);
/* Private variables ---------------------------------------------------------*/
//此变量是函数DjiTest_RegApplyHighPowerHandler先判断然后内存拷贝过来的
static T_DjiTestApplyHighPowerHandler s_applyHighPowerHandler;
/* Exported functions definition ---------------------------------------------*/
@ -48,6 +51,9 @@ static T_DjiTestApplyHighPowerHandler s_applyHighPowerHandler;
*/
T_DjiReturnCode DjiTest_RegApplyHighPowerHandler(T_DjiTestApplyHighPowerHandler *applyHighPowerHandler)
{
//此函数的功能:验证这两个函数指针指向的函数是否可用 → 结构体T_PsdkTestApplyHighPowerHandler中有两个函数指针分别为pinInit和pinWrite
//1、先判断两个函数指针是否为空如果为空就报错
if (applyHighPowerHandler->pinInit == NULL) {
USER_LOG_ERROR("reg apply high power handler pinInit error");
return DJI_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
@ -58,6 +64,7 @@ T_DjiReturnCode DjiTest_RegApplyHighPowerHandler(T_DjiTestApplyHighPowerHandler
return DJI_ERROR_SYSTEM_MODULE_CODE_INVALID_PARAMETER;
}
//2、如果不为空就内存拷贝到本文件的静态变量中
memcpy(&s_applyHighPowerHandler, applyHighPowerHandler, sizeof(T_DjiTestApplyHighPowerHandler));
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
@ -72,6 +79,10 @@ T_DjiReturnCode DjiTest_RegApplyHighPowerHandler(T_DjiTestApplyHighPowerHandler
*/
T_DjiReturnCode DjiTest_PowerManagementStartService(void)
{
//此函数的功能:
//1、申请高功率。如果要申请高功率需要在执行本函数前先执行DjiTest_RegApplyHighPowerHandler函数
//2、负载设备关机前需要执行的操作
T_DjiReturnCode returnCode;
T_DjiAircraftInfoBaseInfo baseInfo = {0};
@ -92,6 +103,7 @@ T_DjiReturnCode DjiTest_PowerManagementStartService(void)
(baseInfo.djiAdapterType == DJI_SDK_ADAPTER_TYPE_SKYPORT_V2 ||
baseInfo.djiAdapterType == DJI_SDK_ADAPTER_TYPE_XPORT)) {
// apply high power
//如果函数指针为空没有指向函数就返回错误代码DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN
if (s_applyHighPowerHandler.pinInit == NULL) {
USER_LOG_ERROR("apply high power pin init interface is NULL error");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
@ -102,18 +114,21 @@ T_DjiReturnCode DjiTest_PowerManagementStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//如果函数指针不为空(指向了一个函数),就执行函数,并根据返回值判断是否成功
returnCode = s_applyHighPowerHandler.pinInit();
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("apply high power pin init error");
return returnCode;
}
//注册高电压返回函数
returnCode = DjiPowerManagement_RegWriteHighPowerApplyPinCallback(s_applyHighPowerHandler.pinWrite);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register WriteHighPowerApplyPinCallback error.");
return returnCode;
}
//执行高电压请求
returnCode = DjiPowerManagement_ApplyHighPowerSync();
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("apply high power error");
@ -122,6 +137,7 @@ T_DjiReturnCode DjiTest_PowerManagementStartService(void)
}
// register power off notification callback function
//负载设备关机前需要执行的操作
returnCode = DjiPowerManagement_RegPowerOffNotificationCallback(DjiTest_PowerOffNotificationCallback);
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register power off notification callback function error");
@ -145,6 +161,7 @@ T_DjiReturnCode DjiTest_PowerManagementStopService(void)
}
/* Private functions definition-----------------------------------------------*/
//详细说明见函数申明处
static T_DjiReturnCode DjiTest_PowerOffNotificationCallback(bool *powerOffPreparationFlag)
{
USER_LOG_INFO("aircraft will power off soon.");

View File

@ -30,6 +30,9 @@
/* Includes ------------------------------------------------------------------*/
#include "dji_typedef.h"
#include "dji_power_management.h"
#include <wiringPi.h>
#define HIGH_POWER_APPLY_PIN 11
#ifdef __cplusplus
extern "C" {
@ -39,6 +42,8 @@ extern "C" {
/* Exported types ------------------------------------------------------------*/
//里面的两个函数指针例子见下方网页中PsdkTest_HighPowerApplyPinInit + PsdkTest_WriteHighPowerApplyPin
//https://developer.dji.com/doc/payload-sdk-tutorial/cn/function-set/basic-function/power-management.html
typedef struct {
T_DjiReturnCode (*pinInit)(void);
T_DjiReturnCode (*pinWrite)(E_DjiPowerManagementPinState pinState);

View File

@ -44,7 +44,7 @@ T_DjiRunTimeStamps DjiUtilTime_GetRunTimeStamps(void)
struct rusage rusage;
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
clock_gettime(CLOCK_MONOTONIC, &ts);//系统的启动时间,不能被设置:https://blog.csdn.net/liu44235/article/details/37692635
timeStamps.realUsec = (uint64_t) ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
getrusage(RUSAGE_SELF, &rusage);

View File

@ -32,6 +32,10 @@
#include "dji_sdk_config.h"
#include "file_binary_array_list_en.h"
//sbg
#include <stdlib.h>
#include <string.h>
/* Private constants ---------------------------------------------------------*/
#define WIDGET_DIR_PATH_LEN_MAX (256)
#define WIDGET_TASK_STACK_SIZE (2048)
@ -45,21 +49,77 @@ static T_DjiReturnCode DjiTestWidget_SetWidgetValue(E_DjiWidgetType widgetType,
static T_DjiReturnCode DjiTestWidget_GetWidgetValue(E_DjiWidgetType widgetType, uint32_t index, int32_t *value,
void *userData);
static T_DjiReturnCode PsdkTestWidget_SetWidgetValue_StartRecord(E_DjiWidgetType widgetType, uint32_t index, int32_t value,
void *userData);
static void *PsdkTest_IrisRecordSystemChanged(void *arg);
static void extractSpectralBinAndBandnumber(bool isModifyBin);
static void closeXimeaRecordSystem();
/* Private values ------------------------------------------------------------*/
static T_DjiTaskHandle s_widgetTestThread;
static bool s_isWidgetFileDirPathConfigured = false;
static char s_widgetFileDirPath[DJI_FILE_PATH_SIZE_MAX] = {0};
static T_DjiTaskHandle s_widgetSbgThread;
static T_DjiTaskHandle s_widgetXimeaThread;
int SbgRecordCondition=0;
static int s_sbgMagState=0;
static int s_stateOfXimea=100;
static int s_stateOfSbg=0;
static int s_stateOfFile=0;
//0ximeaAirborneSystem系统未就绪不可启动1ximeaAirborneSystem系统就绪可以启动
//2ximeaAirborneSystem系统正在启动3ximeaAirborneSystem系统启动成功4系统已经关闭
int systemON_Control = 0;
char s_strUIMessage[100]=" ";
static char * s_strStateOfSbg=" ";
char s_strSbgSatelliteCounter[100]=" ";
char s_strSbgAccuracy[100]=" ";
char XimeaFramerate[100]=" ";
int framerate = 0;
char XimeaExposeTime[100]=" ";
int exposeTimeInt = 0;
char XimeaExposeMaxValue[100]=" ";
char s_spectralBin[100]=" ";
int spectralBinInt = 0;
static char * s_strSbgSolutionMode=" ";
static char * s_strStateOfXimea=" ";
char * s_strPitch=" ";
char * s_strRoll=" ";
char * s_strYaw=" ";
char * s_remainingTime=" ";
char * remainingTimeTmp[10];
char * s_remainingSpace=" ";
char * remainingSpaceTmp[10];
char jsonPathCn[WIDGET_DIR_PATH_LEN_MAX];
char jsonPathEn[WIDGET_DIR_PATH_LEN_MAX];
static int s_sockfd;
static struct sockaddr_in s_server;
static const T_DjiWidgetHandlerListItem s_widgetHandlerList[] = {
{0, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{1, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{2, DJI_WIDGET_TYPE_SWITCH, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{3, DJI_WIDGET_TYPE_SCALE, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{4, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{5, DJI_WIDGET_TYPE_SCALE, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{6, DJI_WIDGET_TYPE_INT_INPUT_BOX, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{7, DJI_WIDGET_TYPE_SWITCH, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{8, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{0, DJI_WIDGET_TYPE_BUTTON, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{1, DJI_WIDGET_TYPE_LIST, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{2, DJI_WIDGET_TYPE_SWITCH, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{3, DJI_WIDGET_TYPE_SCALE, DjiTestWidget_SetWidgetValue, DjiTestWidget_GetWidgetValue, NULL},
{4, DJI_WIDGET_TYPE_LIST, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{5, DJI_WIDGET_TYPE_SWITCH, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{6, DJI_WIDGET_TYPE_INT_INPUT_BOX, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{7, DJI_WIDGET_TYPE_BUTTON, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{8, DJI_WIDGET_TYPE_INT_INPUT_BOX, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{9, DJI_WIDGET_TYPE_SWITCH, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},
{10, DJI_WIDGET_TYPE_LIST, PsdkTestWidget_SetWidgetValue_StartRecord, DjiTestWidget_GetWidgetValue, NULL},//PsdkTestWidget_SetWidgetValue
};
static const char *s_widgetTypeNameArray[] = {
@ -89,6 +149,9 @@ T_DjiReturnCode DjiTest_WidgetStartService(void)
#ifdef SYSTEM_ARCH_LINUX
//Step 2 : Set UI Config (Linux environment)
//获取控件图像和UI配置文件所在文件夹
USER_LOG_INFO("验证是否定义了宏PSDK_ARCH_SYS_LINUX:是!--------------------------------------------------------------------------------------------------------------------------");
char curFileDirPath[WIDGET_DIR_PATH_LEN_MAX];
char tempPath[WIDGET_DIR_PATH_LEN_MAX];
djiStat = DjiUserUtil_GetCurrentFileDirPath(__FILE__, WIDGET_DIR_PATH_LEN_MAX, curFileDirPath);
@ -101,6 +164,7 @@ T_DjiReturnCode DjiTest_WidgetStartService(void)
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/en_big_screen", s_widgetFileDirPath);
} else {
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/en_big_screen", curFileDirPath);
snprintf(jsonPathEn, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/en_big_screen/widget_config.json", curFileDirPath);
}
//set default ui config path
@ -111,6 +175,7 @@ T_DjiReturnCode DjiTest_WidgetStartService(void)
}
//set ui config for English language
//设置系统语言为英文时控件配置文件的路径
djiStat = DjiWidget_RegUiConfigByDirPath(DJI_MOBILE_APP_LANGUAGE_ENGLISH,
DJI_MOBILE_APP_SCREEN_TYPE_BIG_SCREEN,
tempPath);
@ -124,6 +189,7 @@ T_DjiReturnCode DjiTest_WidgetStartService(void)
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/cn_big_screen", s_widgetFileDirPath);
} else {
snprintf(tempPath, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/cn_big_screen", curFileDirPath);
snprintf(jsonPathCn, WIDGET_DIR_PATH_LEN_MAX, "%swidget_file/cn_big_screen/widget_config.json", curFileDirPath);
}
djiStat = DjiWidget_RegUiConfigByDirPath(DJI_MOBILE_APP_LANGUAGE_CHINESE,
@ -161,6 +227,28 @@ T_DjiReturnCode DjiTest_WidgetStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
//Step 5 : Run ximea task
if (osalHandler->TaskCreate("ximea", PsdkTest_IrisRecordSystemChanged, WIDGET_TASK_STACK_SIZE, NULL,
&s_widgetXimeaThread) != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Psdk widget test task(ximea) create error.");
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
/* tc-----------------------------------------------*/
struct hostent *he;
he=gethostbyname("127.0.0.1");
s_sockfd=socket(AF_INET, SOCK_DGRAM,0);
bzero(&s_server,sizeof(s_server));
s_server.sin_family = AF_INET;
s_server.sin_port = htons(PORT);
s_server.sin_addr= *((struct in_addr *)he->h_addr);
system("/home/300tc/projects/udpClient/udpClient 127.0.0.1 10");
/* tc-----------------------------------------------*/
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
@ -186,6 +274,13 @@ __attribute__((weak)) void DjiTest_WidgetLogAppend(const char *fmt, ...)
#endif
/* Private functions definition-----------------------------------------------*/
//在DJI pilot的浮窗上显示系统时间
int messageTimeCounter = 0;
int messageTimespan = 10;
int XimeaAirborneSystemSurvival_Counter = 1;
int ximeaAirborneSystemSurvivalTime = 0;
int ximeaAirborneSystemSurvivalTime_Temp = 0;
static void *DjiTest_WidgetTask(void *arg)
{
char message[DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN];
@ -195,14 +290,23 @@ static void *DjiTest_WidgetTask(void *arg)
USER_UTIL_UNUSED(arg);
while (1) {
while (1)
{
s_widgetValueList[6] = framerate;
s_widgetValueList[8] = exposeTimeInt;
if (systemON_Control == 4)
{
s_widgetValueList[5] = 0;
}
djiStat = osalHandler->GetTimeMs(&sysTimeMs);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("Get system time ms error, stat = 0x%08llX", djiStat);
}
#ifndef USER_FIRMWARE_MAJOR_VERSION
snprintf(message, DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN, "System time : %u ms", sysTimeMs);
snprintf(message, DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN, "%s\n高光谱: %s 惯导: %s\n卫星: %s 惯导状态: %s\n帧率: %s 曝光: %s μs %s \nP: %s R: %s Y: %s \n光谱bin: %s \n时间: %s min 空间: %s G\n",
s_strUIMessage, s_strStateOfXimea, s_strStateOfSbg, s_strSbgSatelliteCounter, s_strSbgSolutionMode, XimeaFramerate, XimeaExposeTime, XimeaExposeMaxValue, s_strPitch, s_strRoll, s_strYaw, s_spectralBin, s_remainingTime, s_remainingSpace);
#else
snprintf(message, DJI_WIDGET_FLOATING_WINDOW_MSG_MAX_LEN,
"System time : %u ms\r\nVersion: v%02d.%02d.%02d.%02d\r\nBuild time: %s %s", sysTimeMs,
@ -217,10 +321,332 @@ static void *DjiTest_WidgetTask(void *arg)
USER_LOG_ERROR("Floating window show message error, stat = 0x%08llX", djiStat);
}
messageTimeCounter++;
if (messageTimeCounter % messageTimespan == 0)
{
strcpy(s_strUIMessage," ");
}
char buffer[128];
FILE *fp;
// 获取剩余硬盘空间和剩余采集时间
fp = popen("df --output=avail --block-size=1 /media/nvme | tail -n 1", "r");
if (fp == NULL) {
perror("popen");
}
// 读取输出并处理
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
// printf("当前字符串-----: %s \n", buffer);
// 将输出转换为数值
unsigned long long availableBytes = strtoull(buffer, NULL, 10);
// 转换为MB
double availableMB = availableBytes / (1024.0 * 1024.0);
sprintf(remainingSpaceTmp, "%.2f", availableMB/1024);
s_remainingSpace = remainingSpaceTmp;
if (spectralBinInt!=0 && framerate!=0)
{
double frameSize;
if (spectralBinInt==1)
{
frameSize = 0.783;
}
else
{
frameSize = 0.783/2;
}
double minTemp = availableMB / (frameSize * framerate * 60);
sprintf(remainingTimeTmp, "%.2f", minTemp);
s_remainingTime = remainingTimeTmp;
// 打印结果
// printf("Available space: %.2f MB;\n", availableMB);
// printf("remainint time of record:%.2f;\n", temp);
}
}
// 关闭文件指针
pclose(fp);
extractSpectralBinAndBandnumber(false);
//判断ximeaAirborneSystem系统是否存活
// if(ximeaAirborneSystemSurvivalTime > 10)
// {
// if (XimeaAirborneSystemSurvival_Counter % 10 ==0)
// {
// if (ximeaAirborneSystemSurvivalTime - ximeaAirborneSystemSurvivalTime_Temp == 0)
// {
// strcpy(s_strUIMessage,"采集系统无响应,请重启!");
// messageTimeCounter = 0;
// messageTimespan = 10;
// }
//
// XimeaAirborneSystemSurvival_Counter = 1;
// ximeaAirborneSystemSurvivalTime_Temp = ximeaAirborneSystemSurvivalTime;
// }
//
// XimeaAirborneSystemSurvival_Counter++;
// }
osalHandler->TaskSleepMs(1000);
}
}
static void *PsdkTest_IrisRecordSystemChanged(void *arg)//
{
// FILE * fp;
// char buffer[80];
// fp = popen("/home/iris-xport/cpp_qtcreator/ximeaImageRecorder-Release/ximeaImageRecorder", "r");ss
// fgets(buffer, sizeof(buffer), fp);
// printf("%s", buffer);
// pclose(fp);
int sockfd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t addrlen;
int num;
char buf[MAXDATASIZE];
if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
{
perror("Creatingsocket failed.");
}
bzero(&server,sizeof(server));
server.sin_family=AF_INET;
server.sin_port=htons(PORT+1);
server.sin_addr.s_addr= htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
perror("Bind()error.");
}
addrlen=sizeof(client);
while (1)
{
//printf("PsdkTest_IrisRecordSystemChanged: record system status change! 8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888\n");
num =recvfrom(sockfd,buf,MAXDATASIZE,0,(struct sockaddr*)&client,&addrlen);
if (num < 0)
{
perror("recvfrom() error\n");
continue;
}
buf[num] = '\0';
printf("You got a message (%s) from client.\n",buf);
//printf("You got a message (%s%) from client.\nIt's ip is%s, port is %d.\n",buf,inet_ntoa(client.sin_addr),htons(client.sin_port));
char * result[5];
result[0] = strtok( buf, "," );
result[1] = strtok( NULL, "," );
result[2] = strtok( NULL, "," );
result[3] = strtok( NULL, "," );
result[4] = strtok( NULL, "," );
printf("result[0]: %s\n", result[0]);
printf("result[1]: %s\n\n", result[1]);
printf("result[2]: %s\n\n", result[2]);
printf("result[3]: %s\n\n", result[3]);
printf("result[4]: %s\n\n", result[4]);
if (strcmp(result[0],"sbg") == 0)
{
s_stateOfSbg = atoi(result[1]);
printf("sbg的状态为: %d\n\n", atoi(result[1]));
switch (s_stateOfSbg)
{
case 0:
s_strStateOfSbg="未打开";
strcpy(s_strUIMessage,"系统已就绪!");
messageTimeCounter = 0;
messageTimespan = 1000;
systemON_Control = 1;//ximeaAirborneSystem系统一启动就会发送此信息 → 代表采集系统就绪;
break;
case 1:
s_strStateOfSbg="波特率设置失败";
break;
case 2:
s_strStateOfSbg="打开成功";
break;
case 3:
s_strStateOfSbg="采集中";
s_widgetValueList[5] = 1;
break;
default:
break;
}
}
else if (strcmp(result[0],"Accuracy") == 0)
{
// printf("惯导定位精度为: %s\n\n", result[1]);
// printf("卫星数为: %s\n\n", result[2]);
strcpy(s_strSbgAccuracy,result[1]);
strcpy(s_strSbgSatelliteCounter,result[2]);
ximeaAirborneSystemSurvivalTime++;
// s_sbgMagState = atoi(result[1]);
// switch (s_sbgMagState)
// {
// case 0:
// s_strSbgAccuracy="false";
// break;
// case 1:
// s_strSbgAccuracy="true";
// break;
// default:
// break;
// }
}
else if (strcmp(result[0],"SolutionMode") == 0)
{
s_sbgMagState = atoi(result[1]);
switch (s_sbgMagState)
{
case 0:
s_strSbgSolutionMode="dis_UNINIT";//UNINITIALIZED
break;
case 1:
s_strSbgSolutionMode="dis_GYRO";//VERTICAL_GYRO
break;
case 2:
s_strSbgSolutionMode="dis_AHRS";
break;
case 3:
s_strSbgSolutionMode="dis_VELOCITY";//NAV_VELOCITY
break;
case 4:
s_strSbgSolutionMode="en_FULL";//NAV_POSITION
break;
default:
break;
}
}
else if (strcmp(result[0],"ximea") == 0)
{
s_stateOfXimea = atoi(result[1]);
printf("ximea的状态为: %d\n\n", atoi(result[1]));
switch (s_stateOfXimea)//0-61ximea官方错误代码99发生的ximea官方错误代码没有处理100未打开101打开102设置帧率103自动曝光104采集中
{
case 10:
s_strStateOfXimea="10";
strcpy(s_strUIMessage,"相机timeout请重启");
messageTimeCounter = 0;
messageTimespan = 200;
break;
case 11:
s_strStateOfXimea="11";
strcpy(s_strUIMessage,"相机Invalid arguments supplied");
messageTimeCounter = 0;
messageTimespan = 200;
break;
case 57:
s_strStateOfXimea="57";
strcpy(s_strUIMessage,"相机被占用!");
messageTimeCounter = 0;
messageTimespan = 200;
break;
case 99:
s_strStateOfXimea="99";
strcpy(s_strUIMessage,"相机异常,错误码见日志!");
messageTimeCounter = 0;
messageTimespan = 200;
break;
case 100:
s_strStateOfXimea="未连接";
break;
case 101:
s_strStateOfXimea="连接成功";
if(s_stateOfXimea == 100)
{
strcpy(s_strUIMessage,"系统启动成功!");
messageTimeCounter = 0;
messageTimespan = 20;
}
systemON_Control = 3;
break;
case 102:
s_strStateOfXimea="连接成功";
break;
case 103:
s_strStateOfXimea="连接成功";
break;
case 104:
s_strStateOfXimea="采集中";
s_widgetValueList[9] = 1;
break;
default:
break;
}
}
else if (strcmp(result[0],"XimeaAutoExpose") == 0)
{
strcpy(XimeaExposeMaxValue, result[1]);
exposeTimeInt = atoi(result[2]);
sprintf(XimeaExposeTime,"%d",exposeTimeInt);
s_widgetValueList[8] = exposeTimeInt;
strcpy(s_strUIMessage,"曝光时间设置成功!");
messageTimeCounter = 0;
messageTimespan = 10;
}
else if (strcmp(result[0],"XimeaFrameRate") == 0)
{
framerate = atoi(result[1]);
s_widgetValueList[6] = framerate;
sprintf(XimeaFramerate,"%d",framerate);
// strcpy(XimeaFramerate,result[1]);
strcpy(s_strUIMessage,"帧率设置成功!");
messageTimeCounter = 0;
messageTimespan = 10;
}
else if (strcmp(result[0],"bin") == 0)
{
spectralBinInt = atoi(result[2]);
}
}
}
#ifndef __CC_ARM
#pragma GCC diagnostic pop
#endif
@ -248,4 +674,370 @@ static T_DjiReturnCode DjiTestWidget_GetWidgetValue(E_DjiWidgetType widgetType,
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
static T_DjiReturnCode PsdkTestWidget_SetWidgetValue_StartRecord(E_DjiWidgetType widgetType, uint32_t index, int32_t value,
void *userData)
{
USER_UTIL_UNUSED(userData);
USER_LOG_INFO("Set widget value, widgetType = %s, widgetIndex = %d ,widgetValue = %d",
s_widgetTypeNameArray[widgetType], index, value);
int32_t valueTmp = s_widgetValueList[index];
s_widgetValueList[index] = value;
switch (index)
{
case 4:
if (value==0)//等待指令
{
}
if (value==1)
{
system("reboot");
}
else if (value==2)
{
system("shutdown now");
}
else if (value==3)
{
system("/home/300tc/projects/udpClient/udpClient 127.0.0.1 9,1");
}
else if (value==4)
{
system("/home/300tc/projects/udpClient/udpClient 127.0.0.1 9,0");
}
else if (value==5)
{
strcpy(s_strUIMessage,"系统正在更新,稍后会自动重启!");
messageTimeCounter = 0;
messageTimespan = 10000;
system("/home/pi/tc_ShellScripts/update0.sh &> /media/nvme/300TC/update/log");
}
break;
case 5://系统启动关闭
if (value==0)//系统关闭
{
printf("systemON_Control的值为%d\n", systemON_Control);
if (0 <= systemON_Control && systemON_Control <= 4)
{
strcpy(s_strUIMessage,"系统正在关闭!");
messageTimeCounter = 0;
messageTimespan = 1000;
char* command = "2";
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
systemON_Control = 4;
// sleep(1);//此线程不能睡眠,否则会报很多错误
// char *commandtmp = (char *)malloc(sizeof(char)*100);
// strcat(commandtmp, "kill $(ps aux | grep ximeaAirborneSystem | grep -v grep | awk \'{print $2}\')");
// printf("命令行指令为:%s\n",commandtmp);
// system(commandtmp);
closeXimeaRecordSystem();
}
}
else if (value==1)//系统启动
{
printf("systemON_Control的值为%d\n", systemON_Control);
if (systemON_Control == 4)
{
strcpy(s_strUIMessage,"请等待系统初始化!");
messageTimeCounter = 0;
messageTimespan = 1000;
}
else if (systemON_Control == 0 || systemON_Control == 1)
{
strcpy(s_strUIMessage,"系统启动中,请等待!");
messageTimeCounter = 0;
messageTimespan = 1000;
char* command = "1";
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
systemON_Control = 2;
}
else if (systemON_Control == 2)
{
strcpy(s_strUIMessage,"系统启动中,请等待!");
messageTimeCounter = 0;
messageTimespan = 1000;
}
else if (systemON_Control == 3)
{
strcpy(s_strUIMessage,"系统已经启动!");
messageTimeCounter = 0;
messageTimespan = 1000;
}
}
break;
case 6://设置帧率
{
if (s_stateOfXimea < 101)
{
strcpy(s_strUIMessage,"请先启动系统!");
messageTimeCounter = 0;
messageTimespan = 10;
// printf("index-------:%d\n", index);
// printf("valueTmp-------:%d\n", valueTmp);
//下面的代码没有作用无法恢复界面的值为默认值valueTmp
// DjiTestWidget_SetWidgetValue(widgetType, index, valueTmp, userData);
// s_widgetValueList[index] = valueTmp;
break;
}
else if (s_stateOfXimea > 103)
{
strcpy(s_strUIMessage,"相机采集中,此操作无效!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
// 控制帧率范围
if(value > 250)
{
strcpy(s_strUIMessage,"帧率不可超过250");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
else if(value == 0)
{
strcpy(s_strUIMessage,"帧率无效!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
//
char command[50] = "5,";
char framerate_str[20];
sprintf(framerate_str,"%d",value);
strcat(command,framerate_str);
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
break;
}
case 7://自动曝光
if (value==0)
{
;
}
else if (value==1)
{
if (s_stateOfXimea < 101)
{
strcpy(s_strUIMessage,"请先启动系统!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
else if (s_stateOfXimea > 103)
{
strcpy(s_strUIMessage,"相机采集中,此操作无效!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
strcpy(s_strUIMessage,"正在自动曝光,请稍等!");
messageTimeCounter = 0;
messageTimespan = 1000;
char* command = "6";
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
}
break;
case 8://手动设置曝光时间
{
if (s_stateOfXimea < 101)
{
strcpy(s_strUIMessage,"请先启动系统!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
else if (s_stateOfXimea > 103)
{
strcpy(s_strUIMessage,"相机采集中,此操作无效!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
//曝光时间有效性判断
float maxExposureTime = 1 / (float)framerate * 1000 * 1000;//单位是μs
if(value > maxExposureTime)
{
strcpy(s_strUIMessage,"曝光时间已设置为最大!");
messageTimeCounter = 0;
messageTimespan = 10;
}
else if(value == 0)
{
strcpy(s_strUIMessage,"曝光时间无效!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
//
char command[50] = "7,";
char exposureTime[20];
sprintf(exposureTime,"%d",(value));
strcat(command,exposureTime);
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
break;
}
case 9:
if (value==0)//停止采集
{
if (s_stateOfXimea != 104)
{
s_strStateOfXimea="连接成功";
}
char* command = "4";
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
}
else if (value==1)//开始采集
{
if (s_stateOfXimea < 101)
{
strcpy(s_strUIMessage,"请先启动系统!");
messageTimeCounter = 0;
messageTimespan = 10;
break;
}
s_strStateOfXimea="预约采集";
char* command = "3";
sendto(s_sockfd, command,strlen(command),0,(struct sockaddr *)&s_server,sizeof(s_server));
}
break;
case 10:
if (value==0)//等待指令
{
}
if (value==1)
{
system("sudo sed -i 's/spectralBin =.*/spectralBin = 1;/g' /media/nvme/300TC/config/ximea.cfg");
}
else if (value==2)
{
system("sudo sed -i 's/spectralBin =.*/spectralBin = 2;/g' /media/nvme/300TC/config/ximea.cfg");
}
closeXimeaRecordSystem();
extractSpectralBinAndBandnumber(true);
strcpy(s_strUIMessage,"请等待采集系统重启!");
messageTimeCounter = 0;
messageTimespan = 10000;
break;
default:
break;
}
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
static void closeXimeaRecordSystem()
{
FILE *fp;
fp = popen("kill $(ps aux | grep ximeaAirborneSystem | grep -v grep | awk \'{print $2}\')", "r");
if (fp == NULL)
{
perror("popen");
}
s_strStateOfXimea=" ";
s_strStateOfSbg=" ";
sprintf(s_strSbgSatelliteCounter,"%s"," ");
s_strSbgSolutionMode=" ";
sprintf(XimeaFramerate,"%s"," ");
sprintf(XimeaExposeTime,"%s"," ");
sprintf(XimeaExposeMaxValue,"%s"," ");
sprintf(s_spectralBin,"%s"," ");
s_remainingTime=" ";
s_widgetValueList[5] = 0;
// s_widgetValueList[6] = 0;
// s_widgetValueList[8] = 0;
framerate = 0;
exposeTimeInt = 0;
system("sudo gpio write 10 0");
}
static void extractSpectralBinAndBandnumber(bool isModifyBin)
{
unsigned long long spectralBin, height;
char buffer[128];
FILE *fp;
fp = popen("grep \"spectralBin = \" /media/nvme/300TC/config/ximea.cfg | awk '{print $3}' | tr -d ';'", "r");
if (fp == NULL) {
perror("popen");
}
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
// printf("当前字符串-----: %s \n", buffer);
spectralBin = strtoull(buffer, NULL, 10);
}
pclose(fp);
if (spectralBin == 1)
{
fp = popen("grep \"height\" /media/nvme/300TC/config/ximea.cfg | head -n 1 | awk '{print $3}' | tr -d ';'", "r");
if (fp == NULL) {
perror("popen");
}
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
// printf("当前字符串-----: %s \n", buffer);
height = strtoull(buffer, NULL, 10);
}
pclose(fp);
}
else if(spectralBin == 2)
{
fp = popen("grep \"height\" /media/nvme/300TC/config/ximea.cfg | head -n 2 | tail -n 1 | awk '{print $3}' | tr -d ';'", "r");
if (fp == NULL) {
perror("popen");
}
if (fgets(buffer, sizeof(buffer), fp) != NULL)
{
// printf("当前字符串-----: %s \n", buffer);
height = strtoull(buffer, NULL, 10);
}
pclose(fp);
}
s_widgetValueList[10] = spectralBin;
spectralBinInt = spectralBin;
if (!isModifyBin)
{
sprintf(s_spectralBin,"%d_%d", spectralBin, height);
}
}
/****************** (C) COPYRIGHT DJI Innovations *****END OF FILE****/

View File

@ -34,6 +34,21 @@
extern "C" {
#endif
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 45454
#define MAXDATASIZE 100
/* Exported constants --------------------------------------------------------*/
/* Exported types ------------------------------------------------------------*/

View File

@ -8,140 +8,81 @@
"is_enable": true
},
"speaker": {
"is_enable_tts": true,
"is_enable_voice": true
"is_enable_tts": false,
"is_enable_voice": false
},
"widget_list": [
{
"widget_index": 0,
"widget_type": "button",
"widget_name": "按钮",
"icon_file_set": {
"icon_file_name_selected": "icon_button1.png",
"icon_file_name_unselected": "icon_button1.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 0
}
},
{
"widget_index": 1,
"widget_type": "list",
"widget_name": "列表",
"list_item": [
{
"item_name": "选项_1",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item1.png",
"icon_file_name_unselected": "icon_list_item1.png"
}
},
{
"item_name": "选项_2",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item2.png",
"icon_file_name_unselected": "icon_list_item2.png"
}
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 1
}
},
{
"widget_index": 2,
"widget_type": "switch",
"widget_name": "开关",
"icon_file_set": {
"icon_file_name_selected": "icon_switch_select.png",
"icon_file_name_unselected": "icon_switch_unselect.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 2
}
},
{
"widget_index": 3,
"widget_type": "scale",
"widget_name": "范围条",
"icon_file_set": {
"icon_file_name_selected": "icon_scale.png",
"icon_file_name_unselected": "icon_scale.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 3,
"button_value_step_length": 5
}
}
]
},
"config_interface": {
"text_input_box": {
"widget_name": "文本输入框",
"placeholder_text": "请输入消息",
"is_enable": true
},
"widget_list": [
{
"widget_index": 4,
"widget_type": "button",
"widget_name": "按钮 4",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 4
}
"widget_type": "list",
"widget_name": "高级指令",
"list_item": [
{
"item_name": "其他"
},
{
"item_name": "重启"
},
{
"item_name": "关机"
},
{
"item_name": "测试采集"
},
{
"item_name": "停止采集"
},
{
"item_name": "更新"
}
]
},
{
"widget_index": 5,
"widget_type": "scale",
"widget_name": "范围条 5",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 5,
"button_value_step_length": 5
}
"widget_type": "switch",
"widget_name": "系统启动"
},
{
"widget_index": 6,
"widget_type": "int_input_box",
"widget_name": "整形值输入框 6",
"int_input_box_hint": "unit:s"
"widget_name": "帧率",
"int_input_box_hint": "单位:赫兹"
},
{
"widget_index": 7,
"widget_type": "switch",
"widget_name": "开关 7",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 7
}
"widget_type": "button",
"widget_name": "自动曝光"
},
{
"widget_index": 8,
"widget_type": "int_input_box",
"widget_name": "曝光时间",
"int_input_box_hint": "单位:微秒"
},
{
"widget_index": 9,
"widget_type": "switch",
"widget_name": "高光谱采集"
},
{
"widget_index": 10,
"widget_type": "list",
"widget_name": "列表 8",
"widget_name": "bin",
"list_item": [
{
"item_name": "选项 1"
"item_name": "其他"
},
{
"item_name": "选项 2"
"item_name": "光谱1"
},
{
"item_name": "选项 3"
},
{
"item_name": "选项 4"
"item_name": "光谱2"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 8
}
]
}
]
}

View File

@ -8,140 +8,81 @@
"is_enable": true
},
"speaker": {
"is_enable_tts": true,
"is_enable_voice": true
"is_enable_tts": false,
"is_enable_voice": false
},
"widget_list": [
{
"widget_index": 0,
"widget_type": "button",
"widget_name": "Button",
"icon_file_set": {
"icon_file_name_selected": "icon_button1.png",
"icon_file_name_unselected": "icon_button1.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 0
}
},
{
"widget_index": 1,
"widget_type": "list",
"widget_name": "List",
"list_item": [
{
"item_name": "Item_1",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item1.png",
"icon_file_name_unselected": "icon_list_item1.png"
}
},
{
"item_name": "Item_2",
"icon_file_set": {
"icon_file_name_selected": "icon_list_item2.png",
"icon_file_name_unselected": "icon_list_item2.png"
}
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 1
}
},
{
"widget_index": 2,
"widget_type": "switch",
"widget_name": "Switch",
"icon_file_set": {
"icon_file_name_selected": "icon_switch_select.png",
"icon_file_name_unselected": "icon_switch_unselect.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 2
}
},
{
"widget_index": 3,
"widget_type": "scale",
"widget_name": "Scale",
"icon_file_set": {
"icon_file_name_selected": "icon_scale.png",
"icon_file_name_unselected": "icon_scale.png"
},
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 3,
"button_value_step_length": 5
}
}
]
},
"config_interface": {
"text_input_box": {
"widget_name": "TextInputBox",
"placeholder_text": "Please input message",
"is_enable": true
},
"widget_list": [
{
"widget_index": 4,
"widget_type": "button",
"widget_name": "Button 4",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 4
}
"widget_type": "list",
"widget_name": "高级指令",
"list_item": [
{
"item_name": "其他"
},
{
"item_name": "重启"
},
{
"item_name": "关机"
},
{
"item_name": "测试采集"
},
{
"item_name": "停止采集"
},
{
"item_name": "更新"
}
]
},
{
"widget_index": 5,
"widget_type": "scale",
"widget_name": "Scale 5",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 5,
"button_value_step_length": 5
}
"widget_type": "switch",
"widget_name": "系统启动"
},
{
"widget_index": 6,
"widget_type": "int_input_box",
"widget_name": "Integer Input Box 6",
"int_input_box_hint": "unit:s"
"widget_name": "帧率",
"int_input_box_hint": "单位:赫兹"
},
{
"widget_index": 7,
"widget_type": "switch",
"widget_name": "Switch 7",
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 7
}
"widget_type": "button",
"widget_name": "自动曝光"
},
{
"widget_index": 8,
"widget_type": "int_input_box",
"widget_name": "曝光时间",
"int_input_box_hint": "单位:微秒"
},
{
"widget_index": 9,
"widget_type": "switch",
"widget_name": "高光谱采集"
},
{
"widget_index": 10,
"widget_type": "list",
"widget_name": "List 8",
"widget_name": "bin",
"list_item": [
{
"item_name": "Item 1"
"item_name": "其他"
},
{
"item_name": "Item 2"
"item_name": "光谱1"
},
{
"item_name": "Item 3"
},
{
"item_name": "Item 4"
"item_name": "光谱2"
}
],
"customize_rc_buttons_config": {
"is_enable": true,
"mapping_config_display_order": 8
}
]
}
]
}

View File

@ -40,9 +40,9 @@
/* Private functions declaration ---------------------------------------------*/
static void *UserXPort_Task(void *arg);
static T_DjiReturnCode ReceiveXPortSystemState(T_DjiGimbalSystemState systemState);
static T_DjiReturnCode ReceiveXPortAttitudeInformation(T_DjiGimbalAttitudeInformation attitudeInformation);
static void *UserXPort_Task(void *arg);//用户自定义xport任务
static T_DjiReturnCode ReceiveXPortSystemState(T_DjiGimbalSystemState systemState);//通过构造回调函数接受xport的状态信息
static T_DjiReturnCode ReceiveXPortAttitudeInformation(T_DjiGimbalAttitudeInformation attitudeInformation);//构造回调函数获取X-Port 的姿态在回调函数中打印X-Port 的姿态信息。
/* Private variables ---------------------------------------------------------*/
static T_DjiTaskHandle s_userXPortThread;
@ -51,6 +51,10 @@ static T_DjiGimbalSystemState s_userXPortSystemState = {0};
static bool s_isUserXPortInited = false;
static bool s_isUserXPortSystemStateVaild = false;
extern char * s_strPitch;
extern char * s_strRoll;
extern char * s_strYaw;
/* Exported functions definition ---------------------------------------------*/
T_DjiReturnCode DjiTest_XPortStartService(void)
{
@ -59,6 +63,7 @@ T_DjiReturnCode DjiTest_XPortStartService(void)
T_DjiAircraftInfoBaseInfo aircraftInfoBaseInfo = {0};
T_DjiOsalHandler *osalHandler = DjiPlatform_GetOsalHandler();
//X-Port 功能模块初始化
djiStat = DjiXPort_Init();
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("XPort init error: 0x%08llX.", djiStat);
@ -73,12 +78,14 @@ T_DjiReturnCode DjiTest_XPortStartService(void)
return djiStat;
}
//通过注册回调函数接收X-Port 的状态信息。注册后,回调函数将会被自动调用,调用频率为
djiStat = DjiXPort_RegReceiveSystemStateCallback(ReceiveXPortSystemState);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register receive XPort system state callback function error: 0x%08llX.", djiStat);
return djiStat;
}
//通过注册回调函数获取X-Port 的姿态信息.注册后回调函数将会被自动调用调用频率为10hz
djiStat = DjiXPort_RegReceiveAttitudeInformationCallback(ReceiveXPortAttitudeInformation);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("register receive XPort attitude information callback function error: 0x%08llX.",
@ -86,22 +93,28 @@ T_DjiReturnCode DjiTest_XPortStartService(void)
return djiStat;
}
//配置xport信息开始------------------------------------------------------------------------------------------------------
//下述代码中X-Port 的角度单位为0.1度
//设置俯仰轴关节角PITCH_JOINT_ANGLE限位
limitAngle.upperLimit = 300;
limitAngle.lowerLimit = -1000;
limitAngle.lowerLimit = -1200;
djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_JOINT_ANGLE, limitAngle);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("set pitch joint angle limit angle for XPort error: 0x%08llX.", djiStat);
return djiStat;
}
//设置俯仰轴欧拉角PITCH_EULER_ANGLE限位
limitAngle.upperLimit = 300;
limitAngle.lowerLimit = -800;
limitAngle.lowerLimit = -1200;
djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_EULER_ANGLE, limitAngle);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("set pitch euler angle limit angle for XPort error: 0x%08llX.", djiStat);
return djiStat;
}
//设置扩展俯仰轴欧拉角PITCH_EULER_ANGLE_EXTENSION限位
limitAngle.upperLimit = 300;
limitAngle.lowerLimit = -1000;
djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_PITCH_EULER_ANGLE_EXTENSION, limitAngle);
@ -110,6 +123,7 @@ T_DjiReturnCode DjiTest_XPortStartService(void)
return djiStat;
}
//设置航向轴关节角YAW_JOINT_ANGLE限位1、获取飞机信息 → 判断云台在飞机上的挂载点
djiStat = DjiAircraftInfo_GetBaseInfo(&aircraftInfoBaseInfo);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("get aircraft base information error: 0x%08llX.", djiStat);
@ -130,24 +144,28 @@ T_DjiReturnCode DjiTest_XPortStartService(void)
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
}
//设置航向轴关节角YAW_JOINT_ANGLE限位2、
djiStat = DjiXPort_SetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_YAW_JOINT_ANGLE, limitAngle);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("set yaw joint angle limit angle for XPort error: 0x%08llX.", djiStat);
return djiStat;
}
djiStat = DjiXPort_SetGimbalModeSync(DJI_GIMBAL_MODE_FREE);
//设置X-Port 工作模式
djiStat = DjiXPort_SetGimbalModeSync(DJI_GIMBAL_MODE_YAW_FOLLOW);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("set XPort gimbal mode error: 0x%08llX.", djiStat);
return djiStat;
}
//使用X-Port 复位功能
djiStat = DjiXPort_ResetSync(DJI_GIMBAL_RESET_MODE_PITCH_AND_YAW);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("reset XPort gimbal error: 0x%08llX.", djiStat);
return djiStat;
}
//用户自定义xport功能
if (osalHandler->TaskCreate("user_xport_task", UserXPort_Task, XPORT_TASK_STACK_SIZE, NULL, &s_userXPortThread) !=
DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("user XPort task create error.");
@ -219,6 +237,7 @@ T_DjiReturnCode DjiTest_XPortGetSystemState(T_DjiGimbalSystemState *systemState)
#pragma GCC diagnostic ignored "-Wreturn-type"
#endif
//用户自定义xport功能函数实现
static void *UserXPort_Task(void *arg)
{
T_DjiReturnCode djiStat;
@ -234,6 +253,7 @@ static void *UserXPort_Task(void *arg)
osalHandler->TaskSleepMs(1000 / XPORT_TASK_FREQ);
step++;
//XPORT_TASK_FREQ10的整数才执行if后面的代码获取xport限位角并打印出来
if (USER_UTIL_IS_WORK_TURN(step, 1, XPORT_TASK_FREQ)) {
djiStat = DjiXPort_GetLimitAngleSync(DJI_XPORT_LIMIT_ANGLE_CATEGORY_ROLL_JOINT_ANGLE, &limitAngle);
if (djiStat != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
@ -283,6 +303,7 @@ static void *UserXPort_Task(void *arg)
limitAngle.upperLimit, limitAngle.lowerLimit);
}
//XPORT_TASK_FREQ1的整数才执行if后面的代码设置xport速度转换系数
if (USER_UTIL_IS_WORK_TURN(step, 10, XPORT_TASK_FREQ)) {
if (DjiTest_CameraIsInited()) {
djiStat = DjiTest_CameraGetOpticalZoomFactor(&opticalZoomFactor);
@ -340,12 +361,22 @@ static T_DjiReturnCode ReceiveXPortSystemState(T_DjiGimbalSystemState systemStat
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
char * pitchTmp[10];
char * rollTmp[10];
char * yawTmp[10];
static T_DjiReturnCode ReceiveXPortAttitudeInformation(T_DjiGimbalAttitudeInformation attitudeInformation)
{
USER_LOG_DEBUG("receive XPort attitude information:");
USER_LOG_DEBUG("XPort attitude: pitch %d, roll %d, yaw %d.", attitudeInformation.attitude.pitch,
attitudeInformation.attitude.roll, attitudeInformation.attitude.yaw);
sprintf(pitchTmp, "%d", attitudeInformation.attitude.pitch);
sprintf(rollTmp, "%d", attitudeInformation.attitude.roll);
sprintf(yawTmp, "%d", attitudeInformation.attitude.yaw);
s_strPitch = pitchTmp;
s_strRoll = rollTmp;
s_strYaw = yawTmp;
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.5)
project(dji_sdk_demo_linux C)
project(dji_300tc C)
set(CMAKE_C_FLAGS "-pthread -std=gnu99")
set(CMAKE_EXE_LINKER_FLAGS "-pthread")
@ -40,10 +40,12 @@ file(GLOB_RECURSE MODULE_SAMPLE_SRC ../../../module_sample/*.c)
include_directories(../../../module_sample)
include_directories(../common)
include_directories(../manifold2/application)
include_directories(/home/300tc/library/ffmpeg_build/include)
include_directories(../../../../../psdk_lib/include)
link_directories(../../../../../psdk_lib/lib/${TOOLCHAIN_NAME})
link_libraries(${CMAKE_CURRENT_LIST_DIR}/../../../../../psdk_lib/lib/${TOOLCHAIN_NAME}/lib${PACKAGE_NAME}.a)
link_directories(/home/300tc/library/ffmpeg_build/lib)
if (NOT EXECUTABLE_OUTPUT_PATH)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}/bin)
@ -80,7 +82,23 @@ else ()
message(STATUS "Cannot Find LIBUSB")
endif (LIBUSB_FOUND)
target_link_libraries(${PROJECT_NAME} m)
target_link_libraries(${PROJECT_NAME}
avformat
avfilter
avcodec
swscale
avutil
swresample
avdevice
avutil
postproc
z
m
pthread
rt
crypt
wiringPi
)
add_custom_command(TARGET ${PROJECT_NAME}
PRE_LINK COMMAND cmake ..

View File

@ -35,12 +35,12 @@ extern "C" {
/* Exported constants --------------------------------------------------------*/
// ATTENTION: User must goto https://developer.dji.com/user/apps/#all to create your own dji sdk application, get dji sdk application
// information then fill in the application information here.
#define USER_APP_NAME "your_app_name"
#define USER_APP_ID "your_app_id"
#define USER_APP_KEY "your_app_key"
#define USER_APP_LICENSE "your_app_license"
#define USER_DEVELOPER_ACCOUNT "your_developer_account"
#define USER_BAUD_RATE "460800"
#define USER_APP_NAME "imager"
#define USER_APP_ID "90210"
#define USER_APP_KEY "2c309ca22fb1e67cc166ccc9dc261f4"
#define USER_APP_LICENSE "JYdEUQRW5lsZANuJnMr9qGsD/1I3KyJL+es97f0qkC4QuCITbCjTIzQNkjk63nuShBtjtC4cCf9PdlLfGCGQWQ5rJDBURg9JbotJEXejpXJgTV/1Jq3ZAp9Jp7ajOhvClcKDzfOllPj/216BtYrC7G92CED39p4iUec5p4cG/ClHYAEKys+1cyHWufcV3COgqqCdxlveY0LlWXP44Q1e4vcFMfo4AqN4LghOO7fMdqsN6CLWNN0WEZu8GnU1TWzXAUE9uLjzqxH8WJLDJChBQvXdsxm/RTuER2mCu8NflMNDhnl+sWASiqTXJyZwN8gdu2fuDkU8umlhxQP+1Gk8ig=="
#define USER_DEVELOPER_ACCOUNT "735056338@qq.com"
#define USER_BAUD_RATE "115200"
/* Exported types ------------------------------------------------------------*/

View File

@ -56,9 +56,9 @@
#include "dji_sdk_config.h"
/* Private constants ---------------------------------------------------------*/
#define DJI_LOG_PATH "Logs/DJI"
#define DJI_LOG_INDEX_FILE_NAME "Logs/latest"
#define DJI_LOG_FOLDER_NAME "Logs"
#define DJI_LOG_PATH "/media/nvme/300TC/programRunLog/djiLog/DJI"
#define DJI_LOG_INDEX_FILE_NAME "/media/nvme/300TC/programRunLog/djiLog/latest"
#define DJI_LOG_FOLDER_NAME "/media/nvme/300TC/programRunLog/djiLog"
#define DJI_LOG_PATH_MAX_SIZE (128)
#define DJI_LOG_FOLDER_NAME_MAX_SIZE (32)
#define DJI_LOG_MAX_COUNT (10)
@ -137,7 +137,7 @@ int main(int argc, char **argv)
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
}
returnCode = DjiCore_SetAlias("PSDK_APPALIAS");
returnCode = DjiCore_SetAlias("300TC_3.35.40.21");
if (returnCode != DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS) {
USER_LOG_ERROR("set alias error");
return DJI_ERROR_SYSTEM_MODULE_CODE_SYSTEM_ERROR;
@ -721,12 +721,32 @@ delay:
static T_DjiReturnCode DjiTest_HighPowerApplyPinInit()
{
wiringPiSetup(); // 初始化WiringPi库
pinMode(HIGH_POWER_APPLY_PIN, OUTPUT); // 配置引脚为输出模式
pullUpDnControl(HIGH_POWER_APPLY_PIN, PUD_DOWN); // 启用下拉电阻,使引脚默认为低电平
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}
static T_DjiReturnCode DjiTest_WriteHighPowerApplyPin(E_DjiPowerManagementPinState pinState)
{
//attention: please pull up the HWPR pin state by hardware.
int wiringPiState;
switch (pinState) {
case DJI_POWER_MANAGEMENT_PIN_STATE_RESET:
wiringPiState = LOW; // WiringPi库中LOW表示低电平
break;
case DJI_POWER_MANAGEMENT_PIN_STATE_SET:
wiringPiState = HIGH; // WiringPi库中HIGH表示高电平
break;
default:
USER_LOG_ERROR("pin state unknown: %d.", pinState);
return DJI_ERROR_SYSTEM_MODULE_CODE_UNKNOWN;
}
digitalWrite(HIGH_POWER_APPLY_PIN, wiringPiState); // 使用WiringPi库设置引脚状态
return DJI_ERROR_SYSTEM_MODULE_CODE_SUCCESS;
}

View File

@ -42,7 +42,7 @@ extern "C" {
#ifdef PLATFORM_ARCH_x86_64
#define LINUX_NETWORK_DEV "enxf8e43b7bbc2c"
#else
#define LINUX_NETWORK_DEV "l4tbr0"
#define LINUX_NETWORK_DEV "eth1"
#endif
/**
* @attention

View File

@ -45,7 +45,7 @@ extern "C" {
/* Exported constants --------------------------------------------------------*/
//User can config dev based on there environmental conditions
#define LINUX_UART_DEV1 "/dev/ttyUSB0"
#define LINUX_UART_DEV1 "/dev/ttyUSB1"
#define LINUX_UART_DEV2 "/dev/ttyACM0"
/* Exported types ------------------------------------------------------------*/