From 2be2a26602e80acf949f653cca30332749bbfa8c Mon Sep 17 00:00:00 2001 From: "William.Wu" Date: Fri, 11 Dec 2015 14:46:14 +0800 Subject: [PATCH] Update available Library fos 2.3 SDK --- lib/doc/img/LibV2_3Structure.jpg | Bin 0 -> 161745 bytes lib/inc/DJI_API.h | 190 ++++++++------------ lib/inc/DJI_App.h | 66 ++----- lib/inc/DJI_Camera.h | 48 +++++ lib/inc/DJI_Config.h | 15 +- lib/inc/DJI_Flight.h | 45 +++++ lib/inc/DJI_HardDriver.h | 86 +++++++-- lib/inc/DJI_Link.h | 37 ++-- lib/inc/DJI_Memory.h | 6 +- lib/inc/DJI_Type.h | 233 +++++++++++++++--------- lib/inc/DJI_Version.h | 21 +++ lib/src/DJI_API.cpp | 293 +++++++++++++++---------------- lib/src/DJI_App.cpp | 167 ++++++++---------- lib/src/DJI_Camera.cpp | 57 ++++++ lib/src/DJI_Codec.cpp | 48 ++++- lib/src/DJI_Flight.cpp | 85 ++++++++- lib/src/DJI_HardDriver.cpp | 27 ++- lib/src/DJI_Link.cpp | 93 +++++++--- lib/src/DJI_Memory.cpp | 12 +- 19 files changed, 949 insertions(+), 580 deletions(-) create mode 100644 lib/doc/img/LibV2_3Structure.jpg create mode 100644 lib/inc/DJI_Camera.h create mode 100644 lib/inc/DJI_Flight.h create mode 100644 lib/inc/DJI_Version.h create mode 100644 lib/src/DJI_Camera.cpp diff --git a/lib/doc/img/LibV2_3Structure.jpg b/lib/doc/img/LibV2_3Structure.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f1c0b9d297e04824ea626e1ddb638e25b533cb7 GIT binary patch literal 161745 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

$M@{!i`xI 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 #include "DJI_Link.h" - -#define MY_DEV_ID 0x00 +#include "DJI_Type.h" #define API_VER_QUERY 0x00 #define API_CTRL_MANAGEMENT 0x00 @@ -56,19 +47,12 @@ #define YAW_GND 0x00 #define YAW_BODY 0x01 -#define MAKE_VERSION(a, b, c, d) \ - (((a << 24) & 0xff000000) | ((b << 16) & 0x00ff0000) | \ - ((c << 8) & 0x0000ff00) | (d & 0x000000ff)) -#define SDK_VERSION (MAKE_VERSION(2, 3, 10, 0)) - -// data_type - //---------------------------------------------------------------------- // uav std_msgs reciever //---------------------------------------------------------------------- #define MSG_ENABLE_FLAG_LEN 2 -#define ENABLE_MSG_TIME 0x0001 +#define HAS_TIME 0x0001 #define HAS_Q 0x0002 #define HAS_A 0x0004 #define HAS_V 0x0008 @@ -115,7 +99,7 @@ typedef struct { unsigned char cmd_sequence; unsigned char cmd_data; -} TaskData_t; +} TaskData; //---------------------------------------------------------------------- // for activation @@ -124,13 +108,6 @@ typedef struct /* * code re-construction according onboard api protocol */ - -#define SDK_ERR_SUCCESS 0x0000 -#define SDK_ERR_COMMAND_NOT_SUPPORTED 0xFF00 -#define SDK_ERR_NO_AUTHORIZED 0xFF01 -#define SDK_ERR_NO_RIGHTS 0xFF02 -#define SDK_ERR_NO_RESPONSE 0xFFFF - #define SDK_ACTIVATE_SUCCESS 0x0000 #define SDK_ACTIVATE_PARAM_ERROR 0x0001 #define SDK_ACTIVATE_DATA_ENC_ERROR 0x0002 @@ -141,54 +118,41 @@ typedef struct #define SDK_ACTIVATE_LEVEL_ERROR 0x0007 #define SDK_ACTIVATE_SDK_VERSION_ERROR 0x0008 - #pragma pack(1) -/* - *struct of activate data - */ - -typedef struct +typedef struct ActivateData { unsigned int app_id; unsigned int app_api_level; unsigned int app_ver; unsigned char app_bundle_id[32]; char *app_key; -} ActivateData_t; +} ActivateData; -/* - *struct of version query data - */ - -typedef struct +typedef struct VersionData { unsigned short version_ack; unsigned int version_crc; +#ifdef SDK_VERSION_3_1 + char version_ID[11]; +#endif //SDK_VERSION_3_1 char version_name[32]; -} VersionData_t; +} VersionData; -/* - *struct of attitude data - */ - -typedef struct +typedef struct FlightData { unsigned char ctrl_flag; float roll_or_x; float pitch_or_y; float thr_z; float yaw; -} AttitudeData_t; +} FlightData; #pragma pack() typedef void (*CommandResult)(unsigned short result); -typedef void (*Get_API_Version_Notify)(VersionData_t *); typedef void (*ReceiveHandler)(DJI::onboardSDK::Header *pHeader); typedef void (*BroadcastHandler)(void); typedef void (*TransparentHandler)(unsigned char *buf, unsigned char len); -typedef void (*ResultCallback)(DJI::onboardSDK::CoreAPI *); - -#endif +#endif // DJI_APP_H diff --git a/lib/inc/DJI_Camera.h b/lib/inc/DJI_Camera.h new file mode 100644 index 000000000..cfc29ddad --- /dev/null +++ b/lib/inc/DJI_Camera.h @@ -0,0 +1,48 @@ +#ifndef DJI_CAMERA_H +#define DJI_CAMERA_H + +#include "DJI_API.h" + +namespace DJI +{ +namespace onboardSDK +{ +class Camera +{ + public: + enum CAMERA_CODE + { + CODE_GIMBAL_SPEED = 0x1A, + CODE_GIMBAL_ANGLE = 0x1B, + CODE_CAMERA_SHOT = 0x20, + CODE_CAMERA_VIDEO_START = 0x21, + CODE_CAMERA_VIDEO_STOP = 0x22 + }; + + public: + Camera(CoreAPI *ContorlAPI = 0); + + //! @note all camera control functions are none-callback function. + void setCamera(CAMERA_CODE camera_cmd); + void setGimbalAngle(GimbalAngleData *data); + void setGimbalSpeed(GimbalSpeedData *data); + + GimbalData getGimbal() const; + float32_t getYaw() const; + float32_t getRoll() const; + float32_t getPitch() const; + bool isYawLimit() const; + bool isRollLimit() const; + bool isPitchLimit() const; + + public: //! @note Access method + CoreAPI *getApi() const; + void setApi(CoreAPI *value); + + private: + CoreAPI *api; +}; +} // namespace onboardSDK +} // namespace DJI + +#endif // DJI_CAMERA_H diff --git a/lib/inc/DJI_Config.h b/lib/inc/DJI_Config.h index 3cefeb7ca..c4d877518 100644 --- a/lib/inc/DJI_Config.h +++ b/lib/inc/DJI_Config.h @@ -1,13 +1,18 @@ -#ifndef __DJI_CONFIG_H__ -#define __DJI_CONFIG_H__ +#ifndef DJI_CONFIG_H +#define DJI_CONFIG_H #include -#define MEMORY_SIZE 1000 // unit is byte +#define MEMORY_SIZE 1024 // unit is byte #define BUFFER_SIZE 1024 #define ACK_SIZE 10 -#define API_DEBUG_DATA +//#define API_DEBUG_DATA #define API_ERROR_DATA #define API_STATUS_DATA -#endif //__DJI_CONFIG_H__ +#define SDK_VERSION_2_3 +//#define SDK_VERSION_3_0 +//#define SDK_VERSION_3_1 +#include + +#endif // DJI_CONFIG_H diff --git a/lib/inc/DJI_Flight.h b/lib/inc/DJI_Flight.h new file mode 100644 index 000000000..91053af6a --- /dev/null +++ b/lib/inc/DJI_Flight.h @@ -0,0 +1,45 @@ +#ifndef DJI_FLIGHT_H +#define DJI_FLIGHT_H + +#include "DJI_API.h" + +namespace DJI +{ +namespace onboardSDK +{ + +class Flight +{ +public: + + public: + Flight(CoreAPI *ContorlAPI = 0); + + void task(TASK taskname, CallBack TaskCallback = 0); + void setArm(bool enable, CallBack ArmCallback = 0); + void setFlight(FlightData *data); + + QuaternionData getQuaternion() const; + PossitionData getPossition()const; + VelocityData getVelocity() const; + CommonData getAcceleration() const; + CommonData getPalstance() const; + MagnetData getMagnet() const; + + public: //! @note callbacks + static void armCallback(CoreAPI *This, Header *header); + static void taskCallback(CoreAPI *This, Header *header); + + public: //! @note Access method + CoreAPI *getApi() const; + void setApi(CoreAPI *value); + + private: + CoreAPI *api; + TaskData taskData; +}; + +} // namespace onboardSDK +} // namespace DJI + +#endif // DJI_FLIGHT_H diff --git a/lib/inc/DJI_HardDriver.h b/lib/inc/DJI_HardDriver.h index ed32915af..2ca235df1 100644 --- a/lib/inc/DJI_HardDriver.h +++ b/lib/inc/DJI_HardDriver.h @@ -1,5 +1,23 @@ -#ifndef __DJI_PRO_HW_H__ -#define __DJI_PRO_HW_H__ +/*! @brief + * @file DJI_HardDriver.h + * @version 3.0 + * @date Dec 9, 2015 + * + * @abstract + * Hard ware level for DJI onboardSDK library + * + * @attention + * Project configuration: + * + * @version features: + * -* @version V3.0 + * -* DJI-onboard-SDK for Windows,QT,STM32,ROS,Cmake + * -* @date Dec 9, 2015 + * -* @author william.wu + * + * */ +#ifndef DJI_HARDDRIVER_H +#define DJI_HARDDRIVER_H #include #include "DJI_Type.h" @@ -11,28 +29,72 @@ namespace onboardSDK class HardDriver { -public: - HardDriver(); + public: + HardDriver() {} -public: + /*! @note How to use + * In order to provide platform crossable DJI onboardSDK library, + * we abstract this class as a hard ware level. + * + * @note function descriptions: + * + * void init(); + * @brief After calling this function, HardDriver should be able to + * read and send correctly, through a correct UART part + * + * unsigned int getTimeStamp(); + * @brief returns a TimeStamp data in unit msec. + * The difference between the return value of the function call two times + * is the excat time between them in msec. + * + * size_t send(const uint8_t *buf, size_t len); + * @brief return sent data length. + * + * size_t readall(uint8_t *buf, size_t maxlen) = 0; + * @brief return read data length. + * + * void lockMemory();/ void freeMemory(); + * @brief provide a mutex for multi-thread. when operating memory. + * + * void lockMSG();/ void freeMSG(); + * @brief provide a mutex for multi-thread. when operating messages. + * + * @attention + * when writting and reading data, there might have multi-thread problems. + * Abstract class HardDriver did not consider these issue. + * Please be careful when you are going to implement send and readall + *funtions. + * + * @note + * we strongly suggest you to inherit this class in your own file, not just + *implement + * it in DJI_HardDriver.cpp or inside this class + * + * */ + public: virtual void init() = 0; virtual unsigned int getTimeStamp() = 0; virtual size_t send(const uint8_t *buf, size_t len) = 0; virtual size_t readall(uint8_t *buf, size_t maxlen) = 0; -public: + public: virtual void lockMemory() = 0; virtual void freeMemory() = 0; virtual void lockMSG() = 0; virtual void freeMSG() = 0; + + public: + enum DisplayType + { + TYPE_STATUS, + TYPE_ERROR, + TYPE_DEBUG + }; + + virtual void displayLog(char *buf = 0); }; } // namespace onboardSDK } // namespace DJI -#ifdef V2_0 -extern void Get_Memory_Lock(void); -extern void Free_Memory_Lock(void); -#endif - -#endif // DJI_PRO_HW_H +#endif // DJI_HARDDRIVER_H diff --git a/lib/inc/DJI_Link.h b/lib/inc/DJI_Link.h index 0962a5167..4cbe2f610 100644 --- a/lib/inc/DJI_Link.h +++ b/lib/inc/DJI_Link.h @@ -1,16 +1,27 @@ -/* - * DJI_Pro_Link.h +/*! @brief + * @file DJI_Link.h + * @version 3.0 + * @date Dec 4, 2015 * - * Created on: Mar 12, 2015 - * Author: wuyuwei - * Modified on: Nov 11, 2015 - * by william.wu - */ - -#ifndef DJI_PRO_LINK_H_ -#define DJI_PRO_LINK_H_ - -#define DJI_SDK_PRO_VER 0 + * @abstract + * + * @attention + * Project configuration: + * + * @version features: + * -* @version V3.0 + * -* DJI-onboard-SDK for Windows,QT,STM32,ROS,Cmake + * -* @date Nov 15, 2015 + * -* @author william.wu + * -* + * -* @version V2.0 + * -* C-like DJI-onboard-SDK library + * -* @date Mar 12, 2015 + * -* @author wuyuwei + * + * */ +#ifndef DJI_LINK_H +#define DJI_LINK_H #define ACK_SESSION_IDLE 0 #define ACK_SESSION_PROCESS 1 @@ -20,4 +31,4 @@ #include "DJI_Type.h" -#endif /* DJI_PRO_LINK_H_ */ +#endif // DJI_LINK_H diff --git a/lib/inc/DJI_Memory.h b/lib/inc/DJI_Memory.h index 1e41d0604..61638ab2c 100644 --- a/lib/inc/DJI_Memory.h +++ b/lib/inc/DJI_Memory.h @@ -1,6 +1,6 @@ -#ifndef DJI_PRO_RMU_H_ -#define DJI_PRO_RMU_H_ +#ifndef DJI_MEMORY_H +#define DJI_MEMORY_H #include "DJI_Type.h" -#endif /* DJI_PRO_RMU_H_ */ +#endif // DJI_MEMORY_H diff --git a/lib/inc/DJI_Type.h b/lib/inc/DJI_Type.h index 86c39f3ce..5258399cd 100644 --- a/lib/inc/DJI_Type.h +++ b/lib/inc/DJI_Type.h @@ -1,38 +1,59 @@ -#ifndef DJI_PRO_TYPE -#define DJI_PRO_TYPE +#ifndef DJI_TYPE +#define DJI_TYPE #include "DJI_Config.h" +#include + +#ifdef __GNUC__ +#define __UNUSED __attribute__((__unused__)) +#else +#define __UNUSED +#endif //__GNUC__ #ifdef WIN32 #define __func__ __FUNCTION__ -#endif +#endif // WIN32 + +#define APIprintf(...) \ + sprintf_s(DJI::onboardSDK::buffer, bufsize, ##__VA_ARGS__) + +#define API_LOG(driver, title, fmt, ...) \ + { \ + if ((title)) \ + { \ + APIprintf("%s %s,line %d: " fmt, title, __func__, __LINE__, \ + ##__VA_ARGS__); \ + (driver)->displayLog(); \ + } \ + } #ifdef API_DEBUG_DATA -#define API_DEBUG(format, ...) \ - printf("DEBUG %s,line %d: " format, __func__, __LINE__, ##__VA_ARGS__) +#define DEBUG_LOG "DEBUG" #else -#define API_DEBUG(format, ...) 0 +#define DEBUG_LOG 0 #endif #ifdef API_ERROR_DATA -#define API_ERROR(format, ...) \ - printf("Error %s,line %d: " format, __func__, __LINE__, ##__VA_ARGS__) +#define ERROR_LOG "ERROR" #else -#define API_ERROR(format, ...) 0 +#define ERROR_LOG 0 #endif #ifdef API_STATUS_DATA -#define API_STATUS(format, ...) \ - printf("MSG %s,line %d: " format, __func__, __LINE__, ##__VA_ARGS__) +#define STATUS_LOG "STATUS" #else -#define API_STATUS(format, ...) 0 +#define STATUS_LOG 0 #endif namespace DJI { namespace onboardSDK { +const size_t bufsize = 1024; +extern char buffer[]; + const size_t SESSION_TABLE_NUM = 32; +const size_t CALLBACK_LIST_NUM = 10; class CoreAPI; typedef struct Header @@ -87,63 +108,52 @@ typedef struct MMU_Tab typedef struct CMDSession { - unsigned int sessionID : 5; - unsigned int usageFlag : 1; - unsigned int sent : 5; - unsigned int retry : 5; - unsigned int timeout : 16; + uint32_t sessionID : 5; + uint32_t usageFlag : 1; + uint32_t sent : 5; + uint32_t retry : 5; + uint32_t timeout : 16; MMU_Tab *mmu; CallBack callback; - unsigned int pre_seq_num; - unsigned int pre_timestamp; + uint32_t pre_seq_num; + uint32_t pre_timestamp; } CMDSession; typedef struct ACKSession { - unsigned int sessionID : 5; - unsigned int session_status : 2; - unsigned int res : 25; + uint32_t sessionID : 5; + uint32_t session_status : 2; + uint32_t res : 25; MMU_Tab *mmu; } ACKSession; typedef struct Ack { - unsigned short session_id : 8; - unsigned short need_encrypt : 8; - unsigned short seq_num; - unsigned int length; - unsigned char *buf; + uint16_t session_id : 8; + uint16_t need_encrypt : 8; + uint16_t seq_num; + uint32_t length; + uint8_t *buf; } Ack; -typedef uint8_t BatteryData; #pragma pack(1) +typedef uint8_t BatteryData; typedef struct GimbalAngleData { - signed short yaw_angle; - signed short roll_angle; - signed short pitch_angle; - struct - { - unsigned char base : 1; - unsigned char yaw_cmd_ignore : 1; - unsigned char roll_cmd_ignore : 1; - unsigned char pitch_cmd_ignore : 1; - unsigned char reserve : 4; - } ctrl_byte; - unsigned char duration; + int16_t yaw_angle; + int16_t roll_angle; + int16_t pitch_angle; + uint8_t ctrl_byte; + uint8_t duration; } GimbalAngleData; typedef struct GimbalSpeedData { - signed short yaw_angle_rate; - signed short roll_angle_rate; - signed short pitch_angle_rate; - struct ControlByte - { - unsigned char reserve : 7; - unsigned char ctrl_switch : 1; // decide increment mode or absolute mode - } ctrl_byte; + int16_t yaw_angle_rate; + int16_t roll_angle_rate; + int16_t pitch_angle_rate; + uint8_t reserved; // always 0x80; } GimbalSpeedData; typedef float float32_t; @@ -164,66 +174,125 @@ typedef struct float32_t z; } CommonData; -typedef struct SpeedData +typedef struct VelocityData { float32_t x; float32_t y; float32_t z; - unsigned char health_flag : 1; - unsigned char feedback_sensor_id : 4; - unsigned char reserve : 3; -} SpeedData; + uint8_t health_flag : 1; + uint8_t feedback_sensor_id : 4; + uint8_t reserve : 3; +} VelocityData; typedef struct { - float64_t lati; - float64_t longti; - float32_t alti; + float64_t latitude; + float64_t longtitude; + float32_t altitude; float32_t height; - unsigned char health_flag; -} PositionData_t; + uint8_t health; +} PossitionData; typedef struct { - signed short roll; - signed short pitch; - signed short yaw; - signed short throttle; - signed short mode; - signed short gear; -} RadioData_t; + int16_t roll; + int16_t pitch; + int16_t yaw; + int16_t throttle; + int16_t mode; + int16_t gear; +} RadioData; typedef struct { - signed short x; - signed short y; - signed short z; -} api_mag_data_t; + int16_t x; + int16_t y; + int16_t z; +} MagnetData; -typedef struct +typedef struct CtrlInfoData { - unsigned char cur_ctrl_dev_in_navi_mode : 3; /*0->rc 1->app 2->serial*/ - unsigned char serial_req_status : 1; /*1->opensd 0->close*/ - unsigned char reserved : 4; +#ifdef SDK_VERSION_3_0 + uint8_t data; +#endif + //! @todo mode remote to enums + uint8_t cur_ctrl_dev_in_navi_mode : 3; /*0->rc 1->app 2->serial*/ + uint8_t serial_req_status : 1; /*1->opensd 0->close*/ + uint8_t reserved : 4; } CtrlInfoData; -typedef struct +#ifdef SDK_VERSION_2_3 +typedef uint32_t TimeStampData; +#endif // SDK_VERSION_2_3 + +#ifdef SDK_VERSION_3_0 +typedef struct TimeStampData +{ + uint32_t time; + uint32_t asr_ts; + uint8_t sync_flag; +} TimeStampData; +#endif // SDK_VERSION_3_0 + +typedef struct GimbalData { - unsigned int timeStamp; + float32_t roll; + float32_t pitch; + float32_t yaw; +#ifdef SDK_VERSION_3_0 + uint8_t is_pitch_limit : 1; + uint8_t is_roll_limit : 1; + uint8_t is_yaw_limit : 1; + uint8_t reserved : 5; +#endif // SDK_VERSION_3_0 +} GimbalData; + +typedef uint8_t FlightStatus; + +typedef struct BroadcastData +{ + TimeStampData timeStamp; QuaternionData q; CommonData a; - SpeedData v; + VelocityData v; CommonData w; - PositionData_t pos; - api_mag_data_t mag; - RadioData_t rc; - CommonData gimbal; - unsigned char status; + PossitionData pos; + MagnetData mag; + RadioData rc; + GimbalData gimbal; + FlightStatus status; //! @todo define enum BatteryData capacity; CtrlInfoData ctrl_info; uint8_t activation; } BroadcastData; +typedef struct VirtualRCSetting +{ + uint8_t enable : 1; + uint8_t cutoff : 1; + uint8_t reserved : 6; +} VirtualRCSetting; + +typedef struct VirtualRCData +{ + uint32_t roll; + uint32_t pitch; + uint32_t throttle; + uint32_t yaw; + uint32_t gear; + uint32_t reserved; + uint32_t mode; + uint32_t Channel_07; + uint32_t Channel_08; + uint32_t Channel_09; + uint32_t Channel_10; + uint32_t Channel_11; + uint32_t Channel_12; + uint32_t Channel_13; + uint32_t Channel_14; + uint32_t Channel_15; +} VirtualRCData; + #pragma pack() } // namespace onboardSDK } // namespace DJI @@ -243,4 +312,4 @@ const size_t MMU_TABLE_NUM = 32; #define CMD_SESSION_1 1 #define CMD_SESSION_AUTO 32 -#endif // DJI_PRO_TYPE +#endif // DJI_TYPE diff --git a/lib/inc/DJI_Version.h b/lib/inc/DJI_Version.h new file mode 100644 index 000000000..5b8e254de --- /dev/null +++ b/lib/inc/DJI_Version.h @@ -0,0 +1,21 @@ +#ifndef DJI_VERSION_H +#define DJI_VERSION_H + +#define MAKE_VERSION(a, b, c, d) \ + (((a << 24) & 0xff000000) | ((b << 16) & 0x00ff0000) | \ + ((c << 8) & 0x0000ff00) | (d & 0x000000ff)) + +#ifdef SDK_VERSION_2_3 +#define SDK_VERSION (MAKE_VERSION(2, 3, 10, 0)) +#endif + +#ifdef SDK_VERSION_3_0 +#define SDK_VERSION (MAKE_VERSION(3, 0, 10, 0)) +#endif + +#ifdef SDK_VERSION_3_1 +#define SDK_VERSION (MAKE_VERSION(3, 1, 10, 0)) +#endif + +#endif // DJI_VERSION_H + diff --git a/lib/src/DJI_API.cpp b/lib/src/DJI_API.cpp index ddeff4a4f..9889a59e3 100644 --- a/lib/src/DJI_API.cpp +++ b/lib/src/DJI_API.cpp @@ -2,29 +2,39 @@ #include #include -DJI::onboardSDK::CoreAPI::CoreAPI(DJI::onboardSDK::HardDriver *Driver, - ReceiveHandler user_cmd_handler_entrance) +using namespace DJI::onboardSDK; + +CoreAPI::CoreAPI(HardDriver *Driver, bool useCallbackThread, + CallBack userRecvCallback) { driver = Driver; - // taskData = { 0, 0 }; + // driver->init(); + seq_num = 0; - // filter = { 0 }; - taskResult = 0; - activateResult = 0; - toMobileResult = 0; - setControlResult = 0; - broadcastHandler = 0; + filter.recv_index = 0; + filter.reuse_count = 0; + filter.reuse_index = 0; + filter.enc_enabled = 0; + broadcastCallback = 0; transparentHandler = 0; - recvHandler = user_cmd_handler_entrance ? user_cmd_handler_entrance : 0; +#ifndef SDK_VERSION_2_3 + broadcastData.timeStamp.time = 0; + broadcastData.timeStamp.asr_ts = 0; + broadcastData.timeStamp.sync_flag = 0; +#endif + + recvCallback = userRecvCallback ? userRecvCallback : 0; + + CallbackThread = useCallbackThread; setup(); + + getVersion(); } -void DJI::onboardSDK::CoreAPI::send(unsigned char session_mode, - unsigned char is_enc, CMD_SET cmd_set, - unsigned char cmd_id, unsigned char *pdata, - int len, CallBack ack_callback, int timeout, - int retry_time) +void CoreAPI::send(unsigned char session_mode, unsigned char is_enc, + CMD_SET cmd_set, unsigned char cmd_id, void *pdata, int len, + CallBack ack_callback, int timeout, int retry_time) { Command param; unsigned char *ptemp = (unsigned char *)encodeSendData; @@ -45,12 +55,9 @@ void DJI::onboardSDK::CoreAPI::send(unsigned char session_mode, sendInterface(¶m); } -void DJI::onboardSDK::CoreAPI::send(Command *parameter) -{ - sendInterface(parameter); -} +void CoreAPI::send(Command *parameter) { sendInterface(parameter); } -void DJI::onboardSDK::CoreAPI::ack(req_id_t req_id, unsigned char *ackdata, int len) +void CoreAPI::ack(req_id_t req_id, unsigned char *ackdata, int len) { Ack param; @@ -65,24 +72,9 @@ void DJI::onboardSDK::CoreAPI::ack(req_id_t req_id, unsigned char *ackdata, int this->ackInterface(¶m); } -void DJI::onboardSDK::CoreAPI::task(TASK taskname, - CommandResult user_notice_entrance) -{ - unsigned char cur_cmd = 0; - taskResult = user_notice_entrance; - cur_cmd = taskname; - - taskData.cmd_data = cur_cmd; - taskData.cmd_sequence++; - - send(2, 1, SET_CONTROL, API_CMD_REQUEST, (unsigned char *)&taskData, - sizeof(taskData), DJI::onboardSDK::CoreAPI::taskCallback, 100, 3); -} - -void DJI::onboardSDK::CoreAPI::getVersion( - Get_API_Version_Notify user_notice_entrance) +void CoreAPI::getVersion(CallBack callback) { - versionData.version_ack = 0xFFFF; + versionData.version_ack = ACK_NO_RESPONSE; versionData.version_crc = 0x0; versionData.version_name[0] = 0; @@ -90,126 +82,79 @@ void DJI::onboardSDK::CoreAPI::getVersion( unsigned retry_time = 3; unsigned char cmd_data = 0; - send(2, 1, SET_ACTIVATION, API_VER_QUERY, (unsigned char *)&cmd_data, 1, - DJI::onboardSDK::CoreAPI::getVersionCallback, cmd_timeout, retry_time); + send(2, 0, SET_ACTIVATION, CODE_GETVERSION, (unsigned char *)&cmd_data, 1, + callback ? callback : CoreAPI::getVersionCallback, cmd_timeout, + retry_time); } -void DJI::onboardSDK::CoreAPI::activate(ActivateData_t *p_user_data, - CommandResult user_notice_entrance) +void CoreAPI::activate(ActivateData *data, CallBack callback) { - activateResult = user_notice_entrance ? user_notice_entrance : 0; - accountData = *p_user_data; + accountData = *data; - send(2, 0, SET_ACTIVATION, API_USER_ACTIVATION, - (unsigned char *)&accountData, sizeof(accountData) - sizeof(char *), - DJI::onboardSDK::CoreAPI::activateCallback, 1000, 3); + send(2, 0, SET_ACTIVATION, CODE_ACTIVATE, (unsigned char *)&accountData, + sizeof(accountData) - sizeof(char *), + callback ? callback : CoreAPI::activateCallback, 1000, 3); } -void DJI::onboardSDK::CoreAPI::sendToMobile(unsigned char *data, unsigned char len, - CommandResult user_notice_entrance) +void CoreAPI::sendToMobile(uint8_t *data, uint8_t len, CallBack callback) { if (len > 100) { - API_ERROR("Too much data to send"); + API_LOG(driver,ERROR_LOG,"Too much data to send"); return; } - toMobileResult = user_notice_entrance ? user_notice_entrance : 0; - send(2, 0, SET_ACTIVATION, API_TRANSPARENT_DATA_TO_MOBILE, data, len, - DJI::onboardSDK::CoreAPI::sendToMobileCallback, 500, 2); + send(2, 0, SET_ACTIVATION, CODE_TOMOBILE, data, len, + callback ? callback : CoreAPI::sendToMobileCallback, 500, 2); } -void DJI::onboardSDK::CoreAPI::setControl(unsigned char cmd, - CommandResult user_notice_entrance) +void CoreAPI::setBroadcastFeq(uint8_t *data, CallBack callback) { - unsigned char data = cmd & 0x1; - setControlResult = user_notice_entrance ? user_notice_entrance : 0; - send(2, 1, SET_CONTROL, API_CTRL_MANAGEMENT, &data, 1, - DJI::onboardSDK::CoreAPI::setControlCallback, 500, 1); + send(2, 0, SET_ACTIVATION, CODE_FREQUENCY, data, 16, + callback ? callback : CoreAPI::setFrequencyCallback, 100, 1); } -void DJI::onboardSDK::CoreAPI::setAttitude(AttitudeData_t *p_user_data) -{ - send(0, 1, SET_CONTROL, API_CTRL_REQUEST, (unsigned char *)p_user_data, - sizeof(AttitudeData_t), 0, 0, 1); -} +TimeStampData CoreAPI::getTime() const { return broadcastData.timeStamp; } -void DJI::onboardSDK::CoreAPI::setGimbalAngle(GimbalAngleData *p_user_data) -{ - send(0, 1, SET_CONTROL, API_GIMBAL_CTRL_ANGLE_REQUEST, - (unsigned char *)p_user_data, sizeof(GimbalAngleData), 0, 0, 1); -} - -void DJI::onboardSDK::CoreAPI::setGimbalSpeed(GimbalSpeedData *p_user_data) -{ - send(0, 1, SET_CONTROL, API_GIMBAL_CTRL_SPEED_REQUEST, - (unsigned char *)p_user_data, sizeof(GimbalSpeedData), 0, 0, 1); -} +FlightStatus CoreAPI::getFlightStatus() const { return broadcastData.status; } +ActivateData CoreAPI::getAccountData() const { return accountData; } -void DJI::onboardSDK::CoreAPI::setCamera(DJI::onboardSDK::CAMERA camera_cmd) -{ - unsigned char send_data = 0; - send(0, 1, SET_CONTROL, camera_cmd, (unsigned char *)&send_data, - sizeof(send_data), 0, 0, 0); -} +void CoreAPI::setAccountData(const ActivateData &value) { accountData = value; } -DJI::onboardSDK::HardDriver *DJI::onboardSDK::CoreAPI::getDriver() const +void CoreAPI::setControl(bool enable, CallBack callback) { - return driver; + unsigned char data = enable ? 1 : 0; + send(2, 1, SET_CONTROL, CODE_SETCONTROL, &data, 1, + callback ? callback : CoreAPI::setControlCallback, 500, 2); } -void DJI::onboardSDK::CoreAPI::setDriver(HardDriver *value) { driver = value; } - -void DJI::onboardSDK::CoreAPI::taskCallback(DJI::onboardSDK::CoreAPI *This, - Header *header) -{ - unsigned short ack_data; - if (header->length - EXC_DATA_SIZE <= 2) - { - memcpy((unsigned char *)&ack_data, - ((unsigned char *)header) + sizeof(Header), - (header->length - EXC_DATA_SIZE)); - API_STATUS("task running successfully,%d\n", ack_data); - //! @todo +HardDriver *CoreAPI::getDriver() const { return driver; } - if (This->taskResult) - This->taskResult(ack_data); - } - else - { - API_ERROR("ACK is exception,seesion id %d,sequence %d\n", - header->sessionID, header->sequence_number); - } -} +void CoreAPI::setDriver(HardDriver *value) { driver = value; } -void DJI::onboardSDK::CoreAPI::getVersionCallback(DJI::onboardSDK::CoreAPI *This, - Header *header) +void CoreAPI::getVersionCallback(CoreAPI *This, Header *header) { unsigned char *ptemp = ((unsigned char *)header) + sizeof(Header); - char *ptemp2; - int count = 31; - VersionData_t *p_version_data = &This->versionData; - p_version_data->version_ack = ptemp[0] + (ptemp[1] << 8); + This->versionData.version_ack = ptemp[0] + (ptemp[1] << 8); ptemp += 2; - p_version_data->version_crc = + This->versionData.version_crc = ptemp[0] + (ptemp[1] << 8) + (ptemp[2] << 16) + (ptemp[3] << 24); ptemp += 4; - ptemp2 = p_version_data->version_name; - while (*ptemp && count) - { - *ptemp2++ = (char)*ptemp++; - count--; - } - *ptemp2 = 0; - - //! @todo - API_STATUS("version ack=%d\n", p_version_data->version_ack); - API_STATUS("version crc=0x%X\n", p_version_data->version_crc); - API_STATUS("version name=%s\n", p_version_data->version_name); +#ifdef SDK_VERSION_3_1 + memcpy(This->versionData.version_ID, ptemp, 11); + ptemp += 11; +#endif + memcpy(This->versionData.version_name, ptemp, 32); + + API_LOG(This->driver,STATUS_LOG,"version ack = %d", This->versionData.version_ack); + API_LOG(This->driver,STATUS_LOG,"version crc = 0x%X", This->versionData.version_crc); +#ifdef SDK_VERSION_3_1 + API_LOG(This->driver,STATUS_LOG,"version ID = %s\n", This->versionData.version_ID); +#endif + API_LOG(This->driver,STATUS_LOG,"version name = %s", This->versionData.version_name); } -void DJI::onboardSDK::CoreAPI::activateCallback(DJI::onboardSDK::CoreAPI *This, - Header *header) +void CoreAPI::activateCallback(CoreAPI *This, Header *header) { volatile unsigned short ack_data; if (header->length - EXC_DATA_SIZE <= 2) @@ -219,94 +164,132 @@ void DJI::onboardSDK::CoreAPI::activateCallback(DJI::onboardSDK::CoreAPI *This, (header->length - EXC_DATA_SIZE)); if (ack_data == SDK_ACTIVATE_NEW_DEVICE) { - API_STATUS("new device try again\n"); + API_LOG(This->driver,STATUS_LOG,"new device try again\n"); } else { if (ack_data == SDK_ACTIVATE_SUCCESS) { - API_STATUS("Activation Successfully\n"); + API_LOG(This->driver,STATUS_LOG,"Activation Successfully\n"); - This->driver->lockMSG(); + This->getDriver()->lockMSG(); This->broadcastData.activation = 1; - This->driver->freeMSG(); + This->getDriver()->freeMSG(); if (This->accountData.app_key) This->setKey(This->accountData.app_key); } else { - API_STATUS("activate code:0x%X\n", ack_data); - - This->driver->lockMSG(); + API_LOG(This->driver,ERROR_LOG,"activate code:0x%X\n", ack_data); + This->getDriver()->lockMSG(); This->broadcastData.activation = 0; - This->driver->freeMSG(); - } - if (This->activateResult) - { - This->activateResult(ack_data); + This->getDriver()->freeMSG(); } } } else { - API_ERROR("ACK is exception,seesion id %d,sequence %d\n", + API_LOG(This->driver,ERROR_LOG,"ACK is exception,seesion id %d,sequence %d\n", header->sessionID, header->sequence_number); } } -void DJI::onboardSDK::CoreAPI::sendToMobileCallback(DJI::onboardSDK::CoreAPI *This, - Header *header) +void CoreAPI::sendToMobileCallback(CoreAPI *This, Header *header) { - unsigned short ack_data = 0xFFFF; + unsigned short ack_data = ACK_NO_RESPONSE; if (header->length - EXC_DATA_SIZE <= 2) { memcpy((unsigned char *)&ack_data, ((unsigned char *)header) + sizeof(Header), (header->length - EXC_DATA_SIZE)); - if (This->toMobileResult) - This->toMobileResult(ack_data); + if (!This->decodeACKStatus(ack_data)) + { + API_LOG(This->driver,ERROR_LOG,"While calling this function"); + } } else - API_ERROR("ACK is exception,seesion id %d,sequence %d\n", + { + API_LOG(This->driver,ERROR_LOG,"ACK is exception,seesion id %d,sequence %d\n", header->sessionID, header->sequence_number); + } } -void DJI::onboardSDK::CoreAPI::setControlCallback(CoreAPI *This, Header *header) +void CoreAPI::setFrequencyCallback(CoreAPI *This __UNUSED, Header *header) { - unsigned short ack_data = 0xFFFF; + unsigned short ack_data = ACK_NO_RESPONSE; + + if (header->length - EXC_DATA_SIZE <= 2) + { + memcpy((unsigned char *)&ack_data, + ((unsigned char *)header) + sizeof(Header), + (header->length - EXC_DATA_SIZE)); + } + switch (ack_data) + { + case 0x0000: + API_LOG(This->driver,STATUS_LOG,"Frequency set success"); + break; + case 0x0001: + API_LOG(This->driver,ERROR_LOG,"Frequency parameter error"); + break; + default: + if (!This->decodeACKStatus(ack_data)) + { + API_LOG(This->driver,ERROR_LOG,"While calling this function"); + } + break; + } +} + +void CoreAPI::setControlCallback(CoreAPI *This, Header *header) +{ + unsigned short ack_data = ACK_NO_RESPONSE; + unsigned char data = 0x1; + if (header->length - EXC_DATA_SIZE <= 2) { memcpy((unsigned char *)&ack_data, ((unsigned char *)header) + sizeof(Header), (header->length - EXC_DATA_SIZE)); - if (This->setControlResult) - This->setControlResult(ack_data); } else - API_ERROR("ACK is exception,seesion id %d,sequence %d\n", + { + API_LOG(This->driver,ERROR_LOG,"ACK is exception,seesion id %d,sequence %d\n", header->sessionID, header->sequence_number); + } switch (ack_data) { case 0x0000: - API_STATUS("Obtain control failed, Conditions did not " + API_LOG(This->driver,STATUS_LOG,"Obtain control failed, Conditions did not " "satisfied"); break; case 0x0001: - API_STATUS("release control successfully\n"); + API_LOG(This->driver,STATUS_LOG,"release control successfully\n"); break; case 0x0002: - API_STATUS("obtain control successfully\n"); + API_LOG(This->driver,STATUS_LOG,"obtain control successfully\n"); break; case 0x0003: - API_STATUS("obtain control running\n"); + API_LOG(This->driver,STATUS_LOG,"obtain control running\n"); + This->send(2, 1, SET_CONTROL, CODE_SETCONTROL, &data, 1, + CoreAPI::setControlCallback, 500, 2); break; case 0x0004: - API_STATUS("control request already done"); + API_LOG(This->driver,STATUS_LOG,"release control running\n"); + data = 0; + This->send(2, 1, SET_CONTROL, CODE_SETCONTROL, &data, 1, + CoreAPI::setControlCallback, 500, 2); + break; + case 0x00C9: + API_LOG(This->driver,STATUS_LOG,"IOC mode opening can not obtain control\n"); break; default: - API_STATUS("there is unkown error,ack=0x%X\n", ack_data); + if (!This->decodeACKStatus(ack_data)) + { + API_LOG(This->driver,ERROR_LOG,"While calling this function"); + } break; } } diff --git a/lib/src/DJI_App.cpp b/lib/src/DJI_App.cpp index d5cba5c9f..a472a2c29 100644 --- a/lib/src/DJI_App.cpp +++ b/lib/src/DJI_App.cpp @@ -26,14 +26,14 @@ using namespace DJI::onboardSDK; -inline void passData(uint16_t _flag, uint16_t _enable, void *_data, - unsigned char *_buf, size_t _datalen) +inline void passData(uint16_t flag, uint16_t enable, void *data, + unsigned char *buf, size_t datalen, size_t &offset) { - if ((_flag & _enable)) + //! @todo new algorithm + if ((flag & enable)) { - memcpy((unsigned char *)&(_data), (unsigned char *)(_buf) + (_datalen), - sizeof(_data)); - _datalen += sizeof(_data); + memcpy((unsigned char *)data, (unsigned char *)buf + offset, datalen); + offset += datalen; } } @@ -60,21 +60,6 @@ BatteryData DJI::onboardSDK::CoreAPI::getBatteryCapacity() const return broadcastData.capacity; } -QuaternionData DJI::onboardSDK::CoreAPI::getQuaternion() const -{ - return broadcastData.q; -} - -CommonData DJI::onboardSDK::CoreAPI::getGroundAcc() const -{ - return broadcastData.a; -} - -SpeedData DJI::onboardSDK::CoreAPI::getGroundSpeed() const -{ - return broadcastData.v; -} - CtrlInfoData DJI::onboardSDK::CoreAPI::getCtrlInfo() const { return broadcastData.ctrl_info; @@ -84,87 +69,67 @@ void DJI::onboardSDK::CoreAPI::broadcast(Header *header) { unsigned char *pdata = ((unsigned char *)header) + sizeof(Header); unsigned short *enableFlag; - unsigned short len = MSG_ENABLE_FLAG_LEN; driver->lockMSG(); pdata += 2; enableFlag = (unsigned short *)pdata; - passData(*enableFlag, ENABLE_MSG_TIME, &broadcastData.timeStamp, pdata, + size_t len = MSG_ENABLE_FLAG_LEN; + + passData(*enableFlag, HAS_TIME, &broadcastData.timeStamp, pdata, + sizeof(TimeStampData), len); + passData(*enableFlag, HAS_Q, &broadcastData.q, pdata, + sizeof(QuaternionData), len); + passData(*enableFlag, HAS_A, &broadcastData.a, pdata, sizeof(CommonData), len); - passData(*enableFlag, HAS_Q, &broadcastData.q, pdata, len); - passData(*enableFlag, HAS_A, &broadcastData.a, pdata, len); - passData(*enableFlag, HAS_V, &broadcastData.v, pdata, len); - passData(*enableFlag, HAS_W, &broadcastData.w, pdata, len); - passData(*enableFlag, HAS_POS, &broadcastData.pos, pdata, len); - passData(*enableFlag, HAS_MAG, &broadcastData.mag, pdata, len); - passData(*enableFlag, HAS_RC, &broadcastData.rc, pdata, len); - passData(*enableFlag, HAS_GIMBAL, &broadcastData.gimbal, pdata, len); - passData(*enableFlag, HAS_STATUS, &broadcastData.status, pdata, len); - passData(*enableFlag, HAS_BATTERY, &broadcastData.capacity, pdata, len); - passData(*enableFlag, HAS_DEVICE, &broadcastData.ctrl_info, pdata, len); - driver->freeMSG(); + passData(*enableFlag, HAS_V, &broadcastData.v, pdata, sizeof(VelocityData), + len); + passData(*enableFlag, HAS_W, &broadcastData.w, pdata, sizeof(CommonData), + len); + passData(*enableFlag, HAS_POS, &broadcastData.pos, pdata, + sizeof(PossitionData), len); + passData(*enableFlag, HAS_MAG, &broadcastData.mag, pdata, + sizeof(MagnetData), len); + passData(*enableFlag, HAS_RC, &broadcastData.rc, pdata, sizeof(RadioData), + len); + passData(*enableFlag, HAS_GIMBAL, &broadcastData.gimbal, pdata, + sizeof(GimbalData), len); + passData(*enableFlag, HAS_STATUS, &broadcastData.status, pdata, + sizeof(uint8_t), len); + passData(*enableFlag, HAS_BATTERY, &broadcastData.capacity, pdata, + sizeof(BatteryData), len); + passData(*enableFlag, HAS_DEVICE, &broadcastData.ctrl_info, pdata, + sizeof(CtrlInfoData), len); - if (broadcastHandler) - broadcastHandler(); + driver->freeMSG(); - if (broadcastData.timeStamp % 600 == 0) - API_DEBUG("time: %d\n", broadcastData.timeStamp); + if (broadcastCallback) + broadcastCallback(this, header); } void DJI::onboardSDK::CoreAPI::recvReqData(Header *header) { unsigned char buf[100] = { 0, 0 }; unsigned char len = 0; - switch (header->sessionID) + + if (getCmdSet(header) == SET_BROADCAST) { - case 0: - if (getCmdSet(header) == SET_BROADCAST) - { - switch (getCmdCode(header)) - { - case CODE_BROADCAST: - broadcast(header); - break; - case CODE_FROMMOBILE: - if (transparentHandler) - { - len = (header->length - EXC_DATA_SIZE - 2) > 100 - ? 100 - : (header->length - EXC_DATA_SIZE - 2); - memcpy(buf, ((unsigned char *)header) + - sizeof(Header) + 2, - len); - transparentHandler(buf, len); - } - break; - case CODE_LOSTCTRL: - API_STATUS("onboardSDK lost contrl\n"); - break; - default: - API_STATUS( - "error, unknown BROADCAST command code 0x%X\n", - getCmdCode(header)); - break; - } - } - else - { - API_DEBUG("receive unknown command\n"); - if (recvHandler) + switch (getCmdCode(header)) + { + case CODE_BROADCAST: + broadcast(header); + break; + case CODE_FROMMOBILE: + if (transparentHandler) { - recvHandler(header); + len = (header->length - EXC_DATA_SIZE - 2) > 100 + ? 100 + : (header->length - EXC_DATA_SIZE - 2); + memcpy(buf, ((unsigned char *)header) + sizeof(Header) + 2, + len); + transparentHandler(buf, len); } - } - break; - case 1: - case 2: - API_DEBUG("Recv request,session id=%d,seq_num=%d\n", - header->sessionID, header->sequence_number); - if (recvHandler) - { - recvHandler(header); - } - else - { + break; + case CODE_LOSTCTRL: + API_LOG(driver, STATUS_LOG, "onboardSDK lost contrl\n"); Ack param; if (header->sessionID > 0) { @@ -176,19 +141,35 @@ void DJI::onboardSDK::CoreAPI::recvReqData(Header *header) param.length = 2; ackInterface(¶m); } - } - break; + break; + case CODE_MISSION: + //! @todo add mission session decode + + API_LOG(driver, DEBUG_LOG, "%x", + *((unsigned char *)header + sizeof(Header) + 2)); + break; + case CODE_WAYPOINT: + //! @todo add waypoint session decode + break; + default: + API_LOG(driver, STATUS_LOG, + "error, unknown BROADCAST command code\n"); + break; + } } + else + API_LOG(driver, DEBUG_LOG, "receive unknown command\n"); + if (recvCallback) + recvCallback(this, header); } -void DJI::onboardSDK::CoreAPI::setTransparentTransmissionCallback( +void CoreAPI::setTransparentTransmissionCallback( TransparentHandler transparentHandlerEntrance) { transparentHandler = transparentHandlerEntrance; } -void DJI::onboardSDK::CoreAPI::setBroadcastCallback( - BroadcastHandler broadcastHandlerEntrance) +void CoreAPI::setBroadcastCallback(CallBack callback) { - broadcastHandler = broadcastHandlerEntrance; + broadcastCallback = callback; } diff --git a/lib/src/DJI_Camera.cpp b/lib/src/DJI_Camera.cpp new file mode 100644 index 000000000..195b8f6f3 --- /dev/null +++ b/lib/src/DJI_Camera.cpp @@ -0,0 +1,57 @@ +#include "DJI_Camera.h" + +using namespace DJI::onboardSDK; + +Camera::Camera(CoreAPI *ContorlAPI) { api = ContorlAPI; } + +void Camera::setCamera(Camera::CAMERA_CODE camera_cmd) +{ + unsigned char send_data = 0; + api->send(0, 1, SET_CONTROL, camera_cmd, &send_data, 1); +} + +void Camera::setGimbalAngle(GimbalAngleData *data) +{ + api->send(0, 1, SET_CONTROL, Camera::CODE_GIMBAL_ANGLE, + (unsigned char *)data, sizeof(GimbalAngleData)); +} + +void Camera::setGimbalSpeed(GimbalSpeedData *data) +{ + data->reserved = 0x80; + api->send(0, 1, SET_CONTROL, Camera::CODE_GIMBAL_SPEED, + (unsigned char *)data, sizeof(GimbalSpeedData)); +} + +GimbalData Camera::getGimbal() const { return api->getBroadcastData().gimbal; } + +float32_t Camera::getYaw() const { return api->getBroadcastData().gimbal.yaw; } + +float32_t Camera::getRoll() const +{ + return api->getBroadcastData().gimbal.roll; +} + +float32_t Camera::getPitch() const +{ + return api->getBroadcastData().gimbal.pitch; +} + +bool Camera::isYawLimit() const +{ + return api->getBroadcastData().gimbal.is_yaw_limit ? true : false; +} + +bool Camera::isRollLimit() const +{ + return api->getBroadcastData().gimbal.is_roll_limit ? true : false; +} + +bool Camera::isPitchLimit() const +{ + return api->getBroadcastData().gimbal.is_pitch_limit ? true : false; +} + +CoreAPI *Camera::getApi() const { return api; } + +void Camera::setApi(CoreAPI *value) { api = value; } diff --git a/lib/src/DJI_Codec.cpp b/lib/src/DJI_Codec.cpp index 7f731ee8d..b491cc8be 100644 --- a/lib/src/DJI_Codec.cpp +++ b/lib/src/DJI_Codec.cpp @@ -619,6 +619,32 @@ void DJI::onboardSDK::CoreAPI::callApp(SDKFilter *p_filter) sdk_stream_prepare_lambda(p_filter); } +bool CoreAPI::decodeACKStatus(unsigned short ack) +{ + switch (ack) + { + case ACK_SUCCESS: + API_LOG(driver, STATUS_LOG,"SUCCESS."); + return true; + case ACK_KEYERROR: + API_LOG(driver, ERROR_LOG, "Wrong encode Key, Activate again."); + return false; + case ACK_NO_AUTHORIZATION: + API_LOG(driver, ERROR_LOG, "Pleasd obtain control and retry."); + return false; + case ACK_NO_RIGHTS: + API_LOG(driver, ERROR_LOG, "Need higher Level access."); + return false; + case ACK_NO_RESPONSE: + API_LOG(driver, ERROR_LOG, + "Check your Hardware connection and retry."); + return false; + default: + API_LOG(driver, ERROR_LOG, "Unkown ACK code: 0x%x", ack); + return false; + } +} + void sdk_stream_shift_data_lambda(SDKFilter *p_filter) { if (p_filter->recv_index) @@ -632,8 +658,8 @@ void sdk_stream_shift_data_lambda(SDKFilter *p_filter) } } -// push data to filter buffer -void storeData(SDKFilter *p_filter, unsigned char in_data) +//! @note push data to filter buffer +void CoreAPI::storeData(SDKFilter *p_filter, unsigned char in_data) { if (p_filter->recv_index < _SDK_MAX_RECV_SIZE) { @@ -642,7 +668,7 @@ void storeData(SDKFilter *p_filter, unsigned char in_data) } else { - // Error, buffer overflow! Just clear and continue. + API_LOG(driver, ERROR_LOG, "buffer overflow"); memset(p_filter->comm_recv_buf, 0, p_filter->recv_index); p_filter->recv_index = 0; } @@ -698,7 +724,7 @@ void DJI::onboardSDK::CoreAPI::verifyData(SDKFilter *p_filter) } else { - // data crc fail, re-use the data part + //! @note data crc fail, re-use the data part sdk_stream_update_reuse_part_lambda(p_filter); } } @@ -745,7 +771,7 @@ void DJI::onboardSDK::CoreAPI::checkStream(SDKFilter *p_filter) } void DJI::onboardSDK::CoreAPI::streamHandler(SDKFilter *p_filter, - unsigned char in_data) + unsigned char in_data) { storeData(p_filter, in_data); checkStream(p_filter); @@ -795,6 +821,11 @@ void DJI::onboardSDK::CoreAPI::byteHandler(const uint8_t in_data) } } +void CoreAPI::byteStreamHandler(uint8_t *buffer __UNUSED, size_t size __UNUSED) +{ + //! @todo implement +} + void calculateCRC(void *p_data) { Header *p_head = (Header *)p_data; @@ -851,8 +882,11 @@ unsigned short DJI::onboardSDK::CoreAPI::encrypt( return 0; if (filter.enc_enabled == 0 && is_enc) + { + API_LOG(driver, ERROR_LOG, + "Can not send encode data, no available key"); return 0; - + } if (w_len == 0 || psrc == 0) data_len = (unsigned short)sizeof(Header); else @@ -861,6 +895,8 @@ unsigned short DJI::onboardSDK::CoreAPI::encrypt( if (is_enc) data_len = data_len + (16 - w_len % 16); + API_LOG(driver, DEBUG_LOG, "data len: %d\n", data_len); + p_head->sof = _SDK_SOF; p_head->length = data_len; p_head->version = 0; diff --git a/lib/src/DJI_Flight.cpp b/lib/src/DJI_Flight.cpp index a9cc4e74a..2cadb4458 100644 --- a/lib/src/DJI_Flight.cpp +++ b/lib/src/DJI_Flight.cpp @@ -1,9 +1,88 @@ -#include "DJI_API.h" +#include "DJI_Flight.h" +#include using namespace DJI::onboardSDK; -Flight::Flight(DJI::onboardSDK::CoreAPI *ContorlAPI) +Flight::Flight(DJI::onboardSDK::CoreAPI *ContorlAPI) { api = ContorlAPI; } + +CoreAPI *Flight::getApi() const { return api; } + +void Flight::setApi(CoreAPI *value) { api = value; } + +void Flight::task(TASK taskname, CallBack TaskCallback) +{ + taskData.cmd_data = taskname; + taskData.cmd_sequence++; + + api->send(2, 1, SET_CONTROL, API_CMD_REQUEST, (unsigned char *)&taskData, + sizeof(taskData), + TaskCallback ? TaskCallback : Flight::taskCallback, 100, 3); +} + +void Flight::setArm(bool enable, CallBack ArmCallback) +{ + uint8_t data = enable ? 1 : 0; + api->send(2, 1, SET_CONTROL, CODE_SETARM, &data, 1, + ArmCallback ? ArmCallback : Flight::armCallback, 0, 1); +} + +void Flight::setFlight(FlightData *data) +{ + api->send(0, 1, SET_CONTROL, CODE_CONTROL, (unsigned char *)data, + sizeof(FlightData)); +} + +QuaternionData Flight::getQuaternion() const { - api = ContorlAPI; + return api->getBroadcastData().q; } +PossitionData Flight::getPossition() const +{ + return api->getBroadcastData().pos; +} + +VelocityData Flight::getVelocity() const { return api->getBroadcastData().v; } + +CommonData Flight::getAcceleration() const { return api->getBroadcastData().a; } + +CommonData Flight::getPalstance() const { return api->getBroadcastData().w; } + +MagnetData Flight::getMagnet() const { return api->getBroadcastData().mag; } + +void Flight::armCallback(CoreAPI *This, Header *header) +{ + unsigned short ack_data; + if (header->length - EXC_DATA_SIZE <= 2) + { + memcpy((unsigned char *)&ack_data, + ((unsigned char *)header) + sizeof(Header), + (header->length - EXC_DATA_SIZE)); + API_LOG(This->getDriver(), STATUS_LOG, "Call back,0x%x\n", ack_data); + } + else + { + API_LOG(This->getDriver(), ERROR_LOG, + "ACK is exception,seesion id %d,sequence %d\n", + header->sessionID, header->sequence_number); + } +} + +void Flight::taskCallback(CoreAPI *This __UNUSED, Header *header) +{ + unsigned short ack_data; + if (header->length - EXC_DATA_SIZE <= 2) + { + memcpy((unsigned char *)&ack_data, + ((unsigned char *)header) + sizeof(Header), + (header->length - EXC_DATA_SIZE)); + API_LOG(This->getDriver(), STATUS_LOG, "task running successfully,%d\n", + ack_data); + } + else + { + API_LOG(This->getDriver(), ERROR_LOG, + "ACK is exception,seesion id %d,sequence %d\n", + header->sessionID, header->sequence_number); + } +} diff --git a/lib/src/DJI_HardDriver.cpp b/lib/src/DJI_HardDriver.cpp index b83c34fb3..be0722596 100644 --- a/lib/src/DJI_HardDriver.cpp +++ b/lib/src/DJI_HardDriver.cpp @@ -1,10 +1,21 @@ -/* - * DJI_Pro_Hw.cpp +#include "DJI_HardDriver.h" + +using namespace DJI::onboardSDK; + +char DJI::onboardSDK::buffer[DJI::onboardSDK::bufsize]; + +/*! @note in this file we will implement some common corss platform drivers + *later + * @todo implement * - * Created on: Aug 24, 2015 - * Author: wuyuwe * - * Modified on: Nov 11, 2015 - * by william.wu - */ -#include "DJI_HardDriver.h" + * + * */ + +void HardDriver::displayLog(char *buf) +{ + if (buf) + printf("%s", buf); + else + printf("%s", DJI::onboardSDK::buffer); +} diff --git a/lib/src/DJI_Link.cpp b/lib/src/DJI_Link.cpp index 3f64dc89a..d13f8fff4 100644 --- a/lib/src/DJI_Link.cpp +++ b/lib/src/DJI_Link.cpp @@ -36,8 +36,13 @@ using namespace DJI::onboardSDK; void DJI::onboardSDK::CoreAPI::sendData(unsigned char *buf) { + size_t ans; Header *pHeader = (Header *)buf; - driver->send(buf, pHeader->length); + ans = driver->send(buf, pHeader->length); + if (ans == 0) + API_LOG(driver, STATUS_LOG,"Port not send"); + if (ans == (size_t)-1) + API_LOG(driver, ERROR_LOG,"Port closed"); } void DJI::onboardSDK::CoreAPI::appHandler(Header *header) @@ -55,12 +60,15 @@ void DJI::onboardSDK::CoreAPI::appHandler(Header *header) if (p2header->sessionID == header->sessionID && p2header->sequence_number == header->sequence_number) { - API_DEBUG("Recv Session %d ACK\n", p2header->sessionID); + API_LOG(driver, DEBUG_LOG,"Recv Session %d ACK\n", p2header->sessionID); + callBack = CMDSessionTab[header->sessionID].callback; freeSession(&CMDSessionTab[header->sessionID]); driver->freeMemory(); if (callBack) - callBack(this, header); + callBack( + this, + header); //! @todo new algorithm call in a thread } else driver->freeMemory(); @@ -69,19 +77,23 @@ void DJI::onboardSDK::CoreAPI::appHandler(Header *header) } else { - // TODO,is a request package - + //! @todo request package + //! switch (header->sessionID) { case 0: recvReqData(header); break; case 1: - default: + //! @todo unnecessary ack in case 1. Maybe add code later + //! @todo check algorithm + default: //! @note session id is 2 + API_LOG(driver, STATUS_LOG,"ACK %d", header->sessionID); + if (ACKSessionTab[header->sessionID - 1].session_status == ACK_SESSION_PROCESS) { - API_DEBUG("This session is waiting for App ack:" + API_LOG(driver, DEBUG_LOG,"This session is waiting for App ack:" "session id=%d,seq_num=%d\n", header->sessionID, header->sequence_number); } @@ -102,7 +114,7 @@ void DJI::onboardSDK::CoreAPI::appHandler(Header *header) ACKSessionTab[header->sessionID - 1].mmu->pmem; if (p2header->sequence_number == header->sequence_number) { - API_DEBUG("repeat ACK to remote,session " + API_LOG(driver, DEBUG_LOG,"repeat ACK to remote,session " "id=%d,seq_num=%d\n", header->sessionID, header->sequence_number); sendData( @@ -111,7 +123,7 @@ void DJI::onboardSDK::CoreAPI::appHandler(Header *header) } else { - API_DEBUG( + API_LOG(driver, DEBUG_LOG, "same session,but new seq_num pkg,session id=%d," "pre seq_num=%d,cur seq_num=%d\n", header->sessionID, p2header->sequence_number, @@ -144,13 +156,14 @@ void DJI::onboardSDK::CoreAPI::sendPoll() { if (CMDSessionTab[i].sent >= CMDSessionTab[i].retry) { - API_DEBUG("Free ssion %d\n", + API_LOG(driver, DEBUG_LOG,"Free ssion %d\n", CMDSessionTab[i].sessionID); + freeSession(&CMDSessionTab[i]); } else { - API_DEBUG("Retry session %d\n", + API_LOG(driver, DEBUG_LOG,"Retry session %d\n", CMDSessionTab[i].sessionID); sendData(CMDSessionTab[i].mmu->pmem); CMDSessionTab[i].pre_timestamp = cur_timestamp; @@ -159,7 +172,7 @@ void DJI::onboardSDK::CoreAPI::sendPoll() } else { - API_DEBUG("send once %d", i); + API_LOG(driver, DEBUG_LOG,"send once %d", i); sendData(CMDSessionTab[i].mmu->pmem); CMDSessionTab[i].pre_timestamp = cur_timestamp; } @@ -174,7 +187,17 @@ void DJI::onboardSDK::CoreAPI::readPoll() int read_len; uint8_t buf[BUFFER_SIZE]; read_len = driver->readall(buf, BUFFER_SIZE); - for (int i = 0; i < read_len; i++) byteHandler(buf[i]); + for (int i = 0; i < read_len; i++) + { + byteHandler(buf[i]); + } +} + +void CoreAPI::callbackPoll() +{ + if (cblistTail != CALLBACK_LIST_NUM) + { + } } void DJI::onboardSDK::CoreAPI::setup() @@ -189,6 +212,14 @@ void DJI::onboardSDK::CoreAPI::setKey(const char *key) filter.enc_enabled = 1; } +void CoreAPI::setActivation(bool isActivated) +{ + if (isActivated) + broadcastData.activation = 1; + else + broadcastData.activation = 0; +} + unsigned short calculateLength(unsigned short size, unsigned short encrypt_flag) { unsigned short len; @@ -206,14 +237,14 @@ int DJI::onboardSDK::CoreAPI::ackInterface(Ack *parameter) if (parameter->length > PRO_PURE_DATA_MAX_SIZE) { - API_ERROR("length=%d is oversize\n", parameter->length); + API_LOG(driver, ERROR_LOG,"length=%d is oversize\n", parameter->length); return -1; } if (parameter->session_id == 0) { - //! @todo - ; + //! @note nothing todo session 0 is a nack session. + return 0; } else if (parameter->session_id > 0 && parameter->session_id < 32) { @@ -223,7 +254,7 @@ int DJI::onboardSDK::CoreAPI::ackInterface(Ack *parameter) calculateLength(parameter->length, parameter->need_encrypt)); if (ack_session == (ACKSession *)NULL) { - API_ERROR("there is not enough memory\n"); + API_LOG(driver, ERROR_LOG,"there is not enough memory\n"); driver->freeMemory(); return -1; } @@ -233,11 +264,12 @@ int DJI::onboardSDK::CoreAPI::ackInterface(Ack *parameter) parameter->seq_num); if (ret == 0) { - API_ERROR("encrypt ERROR\n"); + API_LOG(driver, ERROR_LOG,"encrypt ERROR\n"); driver->freeMemory(); return -1; } + API_LOG(driver, DEBUG_LOG,"Sending data!"); sendData(ack_session->mmu->pmem); driver->freeMemory(); ack_session->session_status = ACK_SESSION_USING; @@ -253,7 +285,7 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) CMDSession *cmd_session = (CMDSession *)NULL; if (parameter->length > PRO_PURE_DATA_MAX_SIZE) { - API_ERROR("ERROR,length=%d is oversize\n", parameter->length); + API_LOG(driver, ERROR_LOG,"ERROR,length=%d is oversize\n", parameter->length); return -1; } @@ -267,7 +299,7 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) if (cmd_session == (CMDSession *)NULL) { driver->freeMemory(); - API_ERROR("ERROR,there is not enough memory\n"); + API_LOG(driver, ERROR_LOG,"ERROR,there is not enough memory\n"); return -1; } ret = encrypt(cmd_session->mmu->pmem, parameter->buf, @@ -275,13 +307,13 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) cmd_session->sessionID, seq_num); if (ret == 0) { - API_ERROR("encrypt ERROR\n"); + API_LOG(driver, ERROR_LOG,"encrypt ERROR\n"); freeSession(cmd_session); driver->freeMemory(); return -1; } - API_DEBUG("send data in session mode 0\n"); + API_LOG(driver, DEBUG_LOG,"send data in session mode 0\n"); sendData(cmd_session->mmu->pmem); seq_num++; @@ -296,7 +328,7 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) if (cmd_session == (CMDSession *)NULL) { driver->freeMemory(); - API_ERROR("ERROR,there are not enough memory\n"); + API_LOG(driver, ERROR_LOG,"ERROR,there are not enough memory\n"); return -1; } if (seq_num == cmd_session->pre_seq_num) @@ -306,7 +338,7 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) cmd_session->sessionID, seq_num); if (ret == 0) { - API_ERROR("encrypt ERROR\n"); + API_LOG(driver, ERROR_LOG,"encrypt ERROR\n"); freeSession(cmd_session); driver->freeMemory(); return -1; @@ -319,7 +351,7 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) cmd_session->pre_timestamp = driver->getTimeStamp(); cmd_session->sent = 1; cmd_session->retry = 1; - API_DEBUG("sending session %d\n", cmd_session->sessionID); + API_LOG(driver, DEBUG_LOG,"sending session %d\n", cmd_session->sessionID); sendData(cmd_session->mmu->pmem); driver->freeMemory(); break; @@ -331,17 +363,20 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) if (cmd_session == (CMDSession *)NULL) { driver->freeMemory(); - API_ERROR("ERROR,there is not enough memory\n"); + API_LOG(driver, ERROR_LOG,"ERROR,there is not enough memory\n"); return -1; } if (seq_num == cmd_session->pre_seq_num) + { seq_num++; + } ret = encrypt(cmd_session->mmu->pmem, parameter->buf, parameter->length, 0, parameter->need_encrypt, cmd_session->sessionID, seq_num); + if (ret == 0) { - API_ERROR("encrypt ERROR\n"); + API_LOG(driver, ERROR_LOG,"encrypt ERROR"); freeSession(cmd_session); driver->freeMemory(); return -1; @@ -354,12 +389,12 @@ int DJI::onboardSDK::CoreAPI::sendInterface(Command *parameter) cmd_session->pre_timestamp = driver->getTimeStamp(); cmd_session->sent = 1; cmd_session->retry = parameter->retry_time; - API_DEBUG("Sending session %d\n", cmd_session->sessionID); + API_LOG(driver, DEBUG_LOG,"Sending session %d\n", cmd_session->sessionID); sendData(cmd_session->mmu->pmem); driver->freeMemory(); break; default: - API_ERROR("Unknown mode:%d\n", parameter->session_mode); + API_LOG(driver, ERROR_LOG,"Unknown mode:%d\n", parameter->session_mode); break; } return 0; diff --git a/lib/src/DJI_Memory.cpp b/lib/src/DJI_Memory.cpp index 83185d7b5..1e8f4b249 100644 --- a/lib/src/DJI_Memory.cpp +++ b/lib/src/DJI_Memory.cpp @@ -209,9 +209,10 @@ void DJI::onboardSDK::CoreAPI::setupSession() */ CMDSession *DJI::onboardSDK::CoreAPI::allocSession(unsigned short session_id, - unsigned short size) + unsigned short size) { unsigned int i; + API_LOG(driver, DEBUG_LOG,"Alloc size %d", size); MMU_Tab *mmu = NULL; if (session_id == 0 || session_id == 1) @@ -223,7 +224,7 @@ CMDSession *DJI::onboardSDK::CoreAPI::allocSession(unsigned short session_id, else { /* session is busy */ - API_ERROR("session %d is busy\n", session_id); + API_LOG(driver, ERROR_LOG,"session %d is busy\n", session_id); return NULL; } } @@ -258,25 +259,26 @@ void DJI::onboardSDK::CoreAPI::freeSession(CMDSession *session) { if (session->usageFlag == 1) { - API_DEBUG("session id %d\n", session->sessionID); + API_LOG(driver, DEBUG_LOG,"session id %d\n", session->sessionID); freeMemory(session->mmu); session->usageFlag = 0; } } ACKSession *DJI::onboardSDK::CoreAPI::allocACK(unsigned short session_id, - unsigned short size) + unsigned short size) { MMU_Tab *mmu = NULL; if (session_id > 0 && session_id < 32) { if (ACKSessionTab[session_id - 1].mmu) { - freeMemory(ACKSessionTab[session_id - 1].mmu); + freeACK(&ACKSessionTab[session_id - 1]); } mmu = allocMemory(size); if (mmu == NULL) { + //! @todo optmize } else {