├── .gitignore ├── README.md ├── browser.js ├── examples ├── DJIFlightRecord_2015-12-29_[19-05-48].txt ├── browser-example.html ├── example.js └── output.json ├── index.js ├── lib ├── djibuffer.js ├── index.js ├── keys.js └── model │ ├── app-gps.js │ ├── app-message.js │ ├── center-battery.js │ ├── custom.js │ ├── deform.js │ ├── details.js │ ├── gimbal.js │ ├── home.js │ ├── osd.js │ ├── rc-gps.js │ ├── rc.js │ ├── recover.js │ └── smart-battery.js ├── package.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dji-log-parser 2 | -------------------------------------------------------------------------------- /examples/DJIFlightRecord_2015-12-29_[19-05-48].txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikeemoo/dji-log-parser/5c58666caaeab827f7edfb37ba147a79a20d462c/examples/DJIFlightRecord_2015-12-29_[19-05-48].txt -------------------------------------------------------------------------------- /examples/browser-example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 41 | 42 | -------------------------------------------------------------------------------- /examples/example.js: -------------------------------------------------------------------------------- 1 | var DJIParser = require("../index"); 2 | var fs = require("fs"); 3 | 4 | var parser = new DJIParser(); 5 | var imageIndex = 1; 6 | 7 | parser.on("OSD", function(obj) { 8 | console.log(obj.getHeight()); 9 | }); 10 | 11 | parser.on("IMAGE", function(obj) { 12 | fs.writeFileSync("image"+(imageIndex++)+".jpg", obj.buffer, "binary"); 13 | }); 14 | 15 | parser.parse(fs.readFileSync("DJIFlightRecord_2015-12-29_[19-05-48].txt")); -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./lib"); -------------------------------------------------------------------------------- /lib/djibuffer.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var ByteBuffer = require("bytebuffer"); 4 | var tmpBuffer = new ByteBuffer(32, true); 5 | 6 | function DJIBuffer(buffer, index, key) { 7 | this.buffer = buffer; 8 | this.index = index; 9 | this.key = key || [0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0]; 10 | } 11 | 12 | DJIBuffer.prototype.clearCopyAndDecode = function(offset, length) { 13 | tmpBuffer.fill(0, 0, tmpBuffer.length); 14 | this.buffer.copyTo(tmpBuffer, 0, this.index + offset, this.index + offset + length); 15 | for(var i=0; i 6; 66 | // packets start at offset 12 67 | var offset = 12; 68 | 69 | // parse records are located before Details section 70 | while (offset < (detailsOffset || buffer.limit - 4)) { 71 | 72 | if (this.isFrame(buffer, offset)) { 73 | offset = this.extractFrame(buffer, offset, isEncrypted); 74 | continue; 75 | } 76 | 77 | if (this.isImage(buffer, offset)) { 78 | offset = this.extractImage(buffer, offset); 79 | continue; 80 | } 81 | offset++; 82 | } 83 | 84 | // parse Details 85 | if (detailsOffset > 0) { 86 | this.emit('DETAILS', new Details(buffer, detailsOffset)); 87 | } 88 | } 89 | 90 | DJIParser.prototype.isFrame = function(buffer, offset) { 91 | var tId = buffer.readUint8(offset++); 92 | var length = buffer.readUint8(offset++); 93 | if (offset + length > buffer.limit - 1) { 94 | return false; 95 | } 96 | 97 | var end = buffer.readUint8(offset + length); 98 | return tId != 0 && end == 0xFF; 99 | } 100 | 101 | DJIParser.prototype.isImage = function(buffer, offset) { 102 | var header = buffer.readUInt32(offset); 103 | return header == 3774863615; // JFIF header 0xFF 0xD8 0xFF 0xE0 104 | } 105 | 106 | DJIParser.prototype.extractFrame = function(buffer, offset, isEncrypted) { 107 | // first byte of a packet is 'type' 108 | var tId = buffer.readUint8(offset++); 109 | var type = types[tId]; 110 | 111 | // second byte is packet length 112 | var length = buffer.readUint8(offset++); 113 | 114 | var key; 115 | var dataOffset = offset; 116 | var dataLength = length; 117 | 118 | // Get key if frame is encrypted 119 | if (isEncrypted) { 120 | var byteKey = buffer.readUint8(offset); 121 | key = keys[((tId - 1) * 256) + byteKey]; 122 | dataOffset ++; 123 | dataLength -= 2; 124 | } 125 | 126 | var data = null; 127 | 128 | switch (type) { 129 | case "OSD": 130 | data = new OSD(buffer, dataOffset, key); 131 | break; 132 | case "DEFORM": 133 | data = new Deform(buffer, dataOffset, key); 134 | break; 135 | case "SMART_BATTERY": 136 | data = new SmartBattery(buffer, dataOffset, key); 137 | break; 138 | case "GIMBAL": 139 | data = new Gimbal(buffer, dataOffset, key); 140 | break; 141 | case "RC": 142 | data = new RC(buffer, dataOffset, key); 143 | break; 144 | case "CUSTOM": 145 | data = new Custom(buffer, dataOffset, key); 146 | break; 147 | case "RC_GPS": 148 | data = new RCGPS(buffer, dataOffset, key); 149 | break; 150 | case "CENTER_BATTERY": 151 | data = new CenterBattery(buffer, dataOffset, key); 152 | break; 153 | case "HOME": 154 | data = new Home(buffer, dataOffset, key); 155 | break; 156 | case "RECOVER": 157 | data = new Recover(buffer, dataOffset, key); 158 | break; 159 | case "APP_TIP": 160 | case "APP_WARN": 161 | data = new AppMessage(buffer, dataOffset, dataLength, key); 162 | break; 163 | case "APP_GPS": 164 | data = new AppGPS(buffer, dataOffset, key); 165 | break; 166 | } 167 | 168 | if (data !== null) { 169 | this.emit(type, data); 170 | this.lastMessages[type] = data; 171 | } 172 | 173 | return offset + length + 1; 174 | } 175 | 176 | DJIParser.prototype.extractImage = function(buffer, offset) { 177 | for (var endOffset = offset; endOffset < buffer.limit; endOffset++) { 178 | if (buffer.readUint16(endOffset) == 55807) { // End JFIF marker 0xFF 0xD9 179 | this.emit("IMAGE", buffer.copy(offset, endOffset + 2)); 180 | break; 181 | } 182 | } 183 | return endOffset + 2; 184 | } 185 | 186 | if (typeof window != "undefined") { 187 | window.DJIParser = DJIParser; 188 | } 189 | 190 | module.exports = DJIParser; 191 | -------------------------------------------------------------------------------- /lib/model/app-gps.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | function AppGPS(buffer, index, key) { 6 | DJIBuffer.call(this, buffer, index, key); 7 | } 8 | 9 | AppGPS.prototype = Object.create(DJIBuffer.prototype); 10 | 11 | AppGPS.prototype.getLongitude = function() { 12 | return this.readDouble(0, 8); 13 | } 14 | 15 | AppGPS.prototype.getLatitude = function() { 16 | return this.readDouble(8, 8); 17 | } 18 | 19 | AppGPS.prototype.getAccuracy = function() { 20 | return this.readFloat(16, 4); 21 | } 22 | 23 | module.exports = AppGPS; 24 | -------------------------------------------------------------------------------- /lib/model/app-message.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | function AppMessage(buffer, index, length, key) { 6 | DJIBuffer.call(this, buffer, index, key); 7 | this.length = length; 8 | } 9 | 10 | AppMessage.prototype = Object.create(DJIBuffer.prototype); 11 | 12 | AppMessage.prototype.getMessage = function() { 13 | return this.readString(0, this.length); 14 | } 15 | 16 | module.exports = AppMessage; -------------------------------------------------------------------------------- /lib/model/center-battery.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var CONN_STATUS = { 6 | 0: "NORMAL", 7 | 1: "INVALID", 8 | 2: "EXCEPTION", 9 | 100: "OTHER" 10 | }; 11 | 12 | function CenterBattery(buffer, index, key) { 13 | DJIBuffer.call(this, buffer, index, key); 14 | } 15 | 16 | CenterBattery.prototype = Object.create(DJIBuffer.prototype); 17 | 18 | CenterBattery.prototype.getRelativeCapacity = function() { 19 | return this.readInt(0, 1); 20 | } 21 | 22 | CenterBattery.prototype.getCurrentPV = function() { 23 | return this.readInt(1, 2); 24 | } 25 | 26 | CenterBattery.prototype.getCurrentCapacity = function() { 27 | return this.readInt(3, 2); 28 | } 29 | 30 | CenterBattery.prototype.getFullCapacity = function() { 31 | return this.readInt(5, 2); 32 | } 33 | 34 | CenterBattery.prototype.getLife = function() { 35 | return this.readInt(7, 1); 36 | } 37 | 38 | CenterBattery.prototype.getLoopNum = function() { 39 | return this.readInt(8, 2); 40 | } 41 | 42 | CenterBattery.prototype.getErrorType = function() { 43 | return this.readInt(10, 4); 44 | } 45 | 46 | CenterBattery.prototype.getCurrent = function() { 47 | return this.readInt(14, 2); 48 | } 49 | 50 | CenterBattery.prototype.getPartVoltages = function() { 51 | var voltages = []; 52 | for (var i = 0; i < 6; i++) { 53 | voltages[i] = this.readInt(16 + (i * 2), 2); 54 | } 55 | return voltages; 56 | } 57 | 58 | CenterBattery.prototype.getSerialNo = function() { 59 | return this.readInt(28, 2); 60 | } 61 | 62 | CenterBattery.prototype.getProductDate = function() { 63 | var n2 = this.readInt(30, 2); 64 | return [ 65 | ((n2 & 65024) >>> 9) + 1980, 66 | (n2 & 480) >>> 5, 67 | n2 & 31 68 | ]; 69 | } 70 | 71 | CenterBattery.prototype.getTemperature = function() { 72 | return this.readInt(32, 2); 73 | } 74 | 75 | CenterBattery.prototype.getConnStatus = function() { 76 | return CONN_STATUS[this.readInt(34, 1)]; 77 | } 78 | 79 | CenterBattery.prototype.totalStudyCycle = function() { 80 | return this.readInt(35, 2); 81 | } 82 | 83 | CenterBattery.prototype.lastStudyCycle = function() { 84 | return this.readInt(37, 2); 85 | } 86 | 87 | module.exports = CenterBattery; -------------------------------------------------------------------------------- /lib/model/custom.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | 6 | function Custom(buffer, index, key) { 7 | DJIBuffer.call(this, buffer, index, key); 8 | } 9 | 10 | Custom.prototype = Object.create(DJIBuffer.prototype); 11 | 12 | Custom.prototype.getDistance = function() { 13 | return this.readFloat(6,4); 14 | }; 15 | 16 | Custom.prototype.getHSpeed = function() { 17 | return this.readFloat(2,4); 18 | }; 19 | 20 | Custom.prototype.getDateTime = function() { 21 | return new Date(parseInt(this.readLong(10, 8).toString())).toISOString(); 22 | }; 23 | 24 | module.exports = Custom; -------------------------------------------------------------------------------- /lib/model/deform.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var DEFORM_MODE = { 6 | 0: "PACK", 7 | 1: "PROTECT", 8 | 2: "NORMAL", 9 | 3: "OTHER" 10 | }; 11 | 12 | var TRIPOD_STATUS = { 13 | 0: "UNKNOWN", 14 | 1: "FOLD_COMPLETE", 15 | 2: "FOLDING", 16 | 3: "STRETCH_COMPLETE", 17 | 4: "STRETCHING", 18 | 5: "STOP_DEFORMATION" 19 | }; 20 | 21 | function Deform(buffer, index, key) { 22 | DJIBuffer.call(this, buffer, index, key); 23 | } 24 | 25 | Deform.prototype = Object.create(DJIBuffer.prototype); 26 | 27 | Deform.prototype.getDeformMode = function() { 28 | return DEFORM_MODE[(this.readInt(0, 1) & 48) >>> 4] 29 | } 30 | 31 | Deform.prototype.getDeformStatus = function() { 32 | return TRIPOD_STATUS[(this.readInt(0, 1) & 14) >>> 1]; 33 | } 34 | 35 | Deform.prototype.isDeformProtected = function() { 36 | return (this.readInt(0, 1) & 1) != 0; 37 | } 38 | 39 | 40 | module.exports = Deform; -------------------------------------------------------------------------------- /lib/model/details.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var APP_TYPE = { 6 | 0: "UNKNOWN", 7 | 1: "IOS", 8 | 2: "ANDROID" 9 | }; 10 | 11 | function Details(buffer, index) { 12 | DJIBuffer.call(this, buffer, index); 13 | } 14 | 15 | Details.prototype = Object.create(DJIBuffer.prototype); 16 | 17 | Details.prototype.getSubStreet = function() { 18 | return this.buffer.toString("utf8", this.index, this.index+20); 19 | } 20 | 21 | Details.prototype.getStreet = function() { 22 | return this.buffer.toString("utf8", this.index+20, this.index+40); 23 | } 24 | 25 | Details.prototype.getCity = function() { 26 | return this.buffer.toString("utf8", this.index+40, this.index+60); 27 | } 28 | 29 | Details.prototype.getArea = function() { 30 | return this.buffer.toString("utf8", this.index+60, this.index+80); 31 | } 32 | 33 | Details.prototype.isFavorite = function() { 34 | return (this.readInt(80, 1) & 1) != 0; 35 | } 36 | 37 | Details.prototype.isNew = function() { 38 | return (this.readInt(81, 1) & 1) != 0; 39 | } 40 | 41 | Details.prototype.needsUpload = function() { 42 | return (this.readInt(82, 1) & 1) != 0; 43 | } 44 | 45 | Details.prototype.getRecordLineCount = function() { 46 | return this.readInt(83, 4); 47 | } 48 | 49 | Details.prototype.getUpdateTime = function() { 50 | return new Date(parseInt(this.readLong(91, 8).toString())).toISOString(); 51 | } 52 | 53 | Details.prototype.getLongitude = function() { 54 | return this.readDouble(99, 8); 55 | } 56 | 57 | Details.prototype.getLatitude = function() { 58 | return this.readDouble(107, 8); 59 | } 60 | 61 | Details.prototype.getTotalDistance = function() { 62 | return this.readFloat(115, 4); 63 | } 64 | 65 | Details.prototype.getTotalTime = function() { 66 | return this.readInt(119, 4); 67 | } 68 | 69 | Details.prototype.getMaxHeight = function() { 70 | return this.readFloat(123, 4); 71 | } 72 | 73 | Details.prototype.getMaxHSpeed = function() { 74 | return this.readFloat(127, 4); 75 | } 76 | 77 | Details.prototype.getMaxVSpeed = function() { 78 | return this.readFloat(131, 4); 79 | } 80 | 81 | Details.prototype.getPhotoNum = function() { 82 | return this.readInt(135, 4); 83 | } 84 | 85 | Details.prototype.getVideoTime = function() { 86 | return this.readInt(139, 4); 87 | } 88 | 89 | Details.prototype.getAircraftSn = function() { 90 | return this.buffer.toString("utf8", this.index+267, this.index+277); 91 | } 92 | 93 | Details.prototype.getAircraftName = function() { 94 | return this.buffer.toString("utf8", this.index+278, this.index+302); 95 | } 96 | 97 | Details.prototype.getActiveTimestamp = function() { 98 | return new Date(parseInt(this.readLong(310, 8).toString())).toISOString(); 99 | } 100 | 101 | Details.prototype.getCameraSn = function() { 102 | return this.buffer.toString("utf8", this.index+318, this.index+328); 103 | } 104 | 105 | Details.prototype.getRcSn = function() { 106 | return this.buffer.toString("utf8", this.index+328, this.index+338); 107 | } 108 | 109 | Details.prototype.getBatterySn = function() { 110 | return this.buffer.toString("utf8", this.index+338, this.index+348); 111 | } 112 | 113 | Details.prototype.getAppType = function() { 114 | return APP_TYPE[this.readInt(348, 1)]; 115 | } 116 | 117 | Details.prototype.getAppVersion = function() { 118 | return this.readInt(349, 1)+'.'+this.readInt(350, 1)+'.'+this.readInt(351, 1); 119 | } 120 | 121 | module.exports = Details; 122 | -------------------------------------------------------------------------------- /lib/model/gimbal.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var MODE = { 6 | 0: "YawNoFollow", 7 | 1: "FPV", 8 | 2: "YawFollow", 9 | 100: "OTHER" 10 | }; 11 | 12 | function Gimbal(buffer, index, key) { 13 | DJIBuffer.call(this, buffer, index, key); 14 | } 15 | 16 | Gimbal.prototype = Object.create(DJIBuffer.prototype); 17 | 18 | Gimbal.prototype.getPitch = function() { 19 | return this.readShort(0, 2); 20 | } 21 | 22 | Gimbal.prototype.getRoll = function() { 23 | return this.readShort(2, 2); 24 | } 25 | 26 | Gimbal.prototype.getYaw = function() { 27 | return this.readShort(4, 2); 28 | } 29 | 30 | Gimbal.prototype.getRollAdjust = function() { 31 | return this.readShort(7, 1); 32 | } 33 | 34 | Gimbal.prototype.getYawAngle = function() { 35 | return this.readShort(8, 2); 36 | } 37 | 38 | Gimbal.prototype.getJoystickVerDirection = function() { 39 | return this.readInt(8, 1) & 3; 40 | } 41 | 42 | Gimbal.prototype.getJoystickHorDirection = function() { 43 | return (this.readInt(8, 1) >> 2) & 3; 44 | } 45 | 46 | Gimbal.prototype.isAutoCalibration = function() { 47 | return (this.readInt(10, 1) & 8) != 0; 48 | } 49 | 50 | Gimbal.prototype.autoCalibrationResult = function() { 51 | return (this.readInt(10, 1) & 16) != 0; 52 | } 53 | 54 | Gimbal.prototype.isPitchInLimit = function() { 55 | return (this.readInt(10, 1) & 1) != 0; 56 | } 57 | 58 | Gimbal.prototype.isRollInLimit = function() { 59 | return (this.readInt(10, 1) & 2) != 0; 60 | } 61 | 62 | Gimbal.prototype.isYawInLimit = function() { 63 | return (this.readInt(10, 1) & 4) != 0; 64 | } 65 | 66 | Gimbal.prototype.isStuck = function() { 67 | return (this.readInt(10, 1) & 64) != 0; 68 | } 69 | 70 | Gimbal.prototype.getMode = function() { 71 | return MODE[this.readInt(6, 1) >>> 6]; 72 | } 73 | 74 | Gimbal.prototype.getSubMode = function() { 75 | return (this.readInt(6, 1) >> 5) & 1; 76 | } 77 | 78 | Gimbal.prototype.getVersion = function() { 79 | return this.readShort(11, 1) & 15; 80 | } 81 | 82 | Gimbal.prototype.isDoubleClick = function() { 83 | return (this.readShort(11, 1) & 32) != 0; 84 | } 85 | 86 | Gimbal.prototype.isTripleClick = function() { 87 | return (this.readShort(11, 1) & 64) != 0; 88 | } 89 | 90 | Gimbal.prototype.isSingleClick = function() { 91 | return (this.readShort(11, 1) & 128) != 0; 92 | } 93 | 94 | module.exports = Gimbal; -------------------------------------------------------------------------------- /lib/model/home.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var GOHOME_STATUS = { 6 | 0: "STANDBY", 7 | 1: "PREASCENDING", 8 | 2: "ALIGN", 9 | 3: "ASCENDING", 10 | 4: "CRUISE", 11 | 7: "OTHER" 12 | }; 13 | 14 | var IOC_MODE = { 15 | 1: "CourseLock", 16 | 2: "HomeLock", 17 | 3: "HotspotSurround", 18 | 100: "OTHER" 19 | } 20 | 21 | var MOTOR_ESCM_STATE = { 22 | 0: "NON_SMART", 23 | 1: "DISCONNECT", 24 | 2: "SIGNAL_ERROR", 25 | 3: "RESISTANCE_ERROR", 26 | 4: "BLOCK", 27 | 5: "NON_BALANCE", 28 | 6: "ESCM_ERROR", 29 | 7: "PROPELLER_OFF", 30 | 8: "MOTOR_IDLE", 31 | 9: "MOTOR_UP", 32 | 10: "MOTOR_OFF", 33 | 11: "NON_CONNECT", 34 | 100: "OTHER" 35 | }; 36 | 37 | function Home(buffer, index, key) { 38 | DJIBuffer.call(this, buffer, index, key); 39 | } 40 | 41 | Home.prototype = Object.create(DJIBuffer.prototype); 42 | 43 | Home.prototype.getLongitude = function() { 44 | return this.readDouble(0, 8) * 180 / Math.PI; 45 | } 46 | 47 | Home.prototype.getLatitude = function() { 48 | return this.readDouble(8, 8) * 180 / Math.PI; 49 | } 50 | 51 | Home.prototype.getHeight = function() { 52 | return this.readFloat(16, 4); 53 | } 54 | 55 | Home.prototype.getIOCMode = function() { 56 | return IOC_MODE[(this.readInt(20, 2) & 57344) >>> 13]; 57 | } 58 | 59 | Home.prototype.isIOCEnabled = function() { 60 | return ((this.readInt(20, 2) & 4096) >>> 12) != 0; 61 | } 62 | 63 | Home.prototype.isBeginnerMode = function() { 64 | return (this.readInt(20, 2) >> 11 & 1) != 0; 65 | } 66 | 67 | Home.prototype.isCompassCeleing = function() { 68 | return ((this.readInt(20, 2) & 1024) >>> 10) != 0; 69 | } 70 | 71 | Home.prototype.getCompassCeleStatus = function() { 72 | return (this.readInt(20, 2) & 768) >>> 8; 73 | } 74 | 75 | Home.prototype.hasGoHome = function() { 76 | return ((this.readInt(20, 2) & 128) >>> 7) != 0; 77 | } 78 | 79 | Home.prototype.getGoHomeStatus = function() { 80 | return GOHOME_STATUS[(this.readInt(20, 2) & 112) >>> 4]; 81 | } 82 | 83 | Home.prototype.isReachLimitHeight = function() { 84 | return ((this.readInt(20, 2) & 32) >>> 5) != 0; 85 | } 86 | 87 | Home.prototype.isReachLimitDistance = function() { 88 | return ((this.readInt(20, 2) & 16) >>> 4) != 0; 89 | } 90 | 91 | Home.prototype.isDynamicHomePointEnabled = function() { 92 | return ((this.readInt(20, 2) & 8) >>> 3) != 0; 93 | } 94 | 95 | Home.prototype.getAircraftHeadDirection = function() { 96 | return (this.readInt(20, 2) & 4) >>> 2; 97 | } 98 | 99 | Home.prototype.getGoHomeMode = function() { 100 | return (this.readInt(20, 2) & 2) >>> 1; 101 | } 102 | 103 | Home.prototype.isHomeRecord = function() { 104 | return (this.readInt(20, 2) & 1) != 0; 105 | } 106 | 107 | Home.prototype.getGoHomeHeight = function() { 108 | return this.readInt(22, 2); 109 | } 110 | 111 | Home.prototype.getCourseLockAngle = function () { 112 | return this.readShort(24, 2); 113 | } 114 | 115 | Home.prototype.getDataRecorderStatus = function() { 116 | return this.readInt(26, 1); 117 | } 118 | 119 | Home.prototype.getDataRecorderRemainCapacity = function() { 120 | return this.readInt(27, 1); 121 | } 122 | 123 | Home.prototype.getDataRecorderRemainTime = function() { 124 | return this.readInt(28, 2); 125 | } 126 | 127 | Home.prototype.getCurDataRecorderFileIndex = function() { 128 | return this.readInt(30, 2); 129 | } 130 | 131 | Home.prototype.isFlycInSimulationMode = function() { 132 | return (this.readInt(32, 1) & 1) != 0; 133 | } 134 | 135 | Home.prototype.isFlycInNavigationMode = function() { 136 | return ((this.readInt(32, 1) & 2) >>> 1) != 0; 137 | } 138 | 139 | Home.prototype.isWingBroken = function() { 140 | return (this.readInt(32, 1) & 4096) != 0; 141 | } 142 | 143 | Home.prototype.getMotorEscmState = function() { 144 | var state = []; 145 | var value = this.readInt(32, 1); 146 | for (var i = 0; i < 8; i++) { 147 | state.push(MOTOR_ESCM_STATE[(value >> (i * 4)) & 15]); 148 | } 149 | } 150 | 151 | Home.prototype.getForceLandingHeight = function() { 152 | return this.readInt(45, 1); 153 | } 154 | 155 | module.exports = Home; -------------------------------------------------------------------------------- /lib/model/osd.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var DRONE_TYPE = { 6 | 0: "Unknown", 7 | 1: "Inspire", 8 | 2: "P3S", 9 | 3: "P3X", 10 | 4: "P3C", 11 | 5: "OpenFrame", 12 | 6: "ACEONE", 13 | 7: "WKM", 14 | 8: "NAZA", 15 | 9: "A2", 16 | 10: "A3", 17 | 11: "P4", 18 | 13: "Mavic", 19 | 14: "PM820", 20 | 15: "P34K", 21 | 16: "wm220", 22 | 17: "Orange2", 23 | 18: "Pomato", 24 | 20: "N3", 25 | 23: "PM820PRO", 26 | 100: "None", 27 | 255: "NoFlyc", 28 | }; 29 | 30 | var FLYC_STATE = { 31 | 0: "MANUAL", 32 | 1: "ATTI", 33 | 2: "ATTI_COURSE_LOCK", 34 | 3: "ATTI_HOVER", 35 | 4: "HOVER", 36 | 5: "GSP_BLAKE", 37 | 6: "GPS_ATTI", 38 | 7: "GPS_COURSE_LOCK", 39 | 8: "GPS_HOME_LOCK", 40 | 9: "GPS_HOT_POINT", 41 | 10: "ASSISTED_TAKEOFF", 42 | 11: "AUTO_TAKEOFF", 43 | 12: "AUTO_LANDING", 44 | 13: "ATTI_LANDING", 45 | 14: "GPS_WAYPOINT", 46 | 15: "GO_HOME", 47 | 16: "CLICK_GO", 48 | 17: "JOYSTICK", 49 | 18: "GPS_ATTI_WRISTBAND", 50 | 19: "CINEMATIC", 51 | 23: "ATTI_LIMITED", 52 | 24: "DRAW", 53 | 25: "GPS_FOLLOW_ME", 54 | 26: "ACTIVE_TRACK", 55 | 27: "TAP_FLY", 56 | 28: "PANO", 57 | 29: "FARMING", 58 | 30: "FPV", 59 | 31: "GPS_SPORT", 60 | 32: "GPS_NOVICE", 61 | 33: "CONFIRM_LANDING", 62 | 35: "TERRAIN_FOLLOW", 63 | 36: "PALM_CONTROL", 64 | 37: "QUICK_SHOT", 65 | 38: "TRIPOD", 66 | 39: "TRACK_SPOTLIGHT", 67 | 41: "MOTORS_JUST_STARTED", 68 | 43: "GPS_GENTLE", 69 | 255: "UNKNOWN" 70 | }; 71 | 72 | var GOHOME_STATUS = { 73 | 0: "STANDBY", 74 | 1: "PREASCENDING", 75 | 2: "ALIGN", 76 | 3: "ASCENDING", 77 | 4: "CRUISE", 78 | 5: "BRAKING", 79 | 6: "BYPASSING", 80 | 7: "OTHER" 81 | }; 82 | 83 | var BATTERY_TYPE = { 84 | 0: "UNKNOWN", 85 | 1: "NONSMART", 86 | 2: "SMART" 87 | }; 88 | 89 | var MOTOR_START_FAILED_CAUSE = { 90 | 0: "None", 91 | 1: "CompassError", 92 | 2: "AssistantProtected", 93 | 3: "DeviceLocked", 94 | 4: "DistanceLimit", 95 | 5: "IMUNeedCalibration", 96 | 6: "IMUSNError", 97 | 7: "IMUWarning", 98 | 8: "CompassCalibrating", 99 | 9: "AttiError", 100 | 10: "NoviceProtected", 101 | 11: "BatteryCellError", 102 | 12: "BatteryCommuniteError", 103 | 13: "SeriouLowVoltage", 104 | 14: "SeriouLowPower", 105 | 15: "LowVoltage", 106 | 16: "TempureVolLow", 107 | 17: "SmartLowToLand", 108 | 18: "BatteryNotReady", 109 | 19: "SimulatorMode", 110 | 20: "PackMode", 111 | 21: "AttitudeAbNormal", 112 | 22: "UnActive", 113 | 23: "FlyForbiddenError", 114 | 24: "BiasError", 115 | 25: "EscError", 116 | 26: "ImuInitError", 117 | 27: "SystemUpgrade", 118 | 28: "SimulatorStarted", 119 | 29: "ImuingError", 120 | 30: "AttiAngleOver", 121 | 31: "GyroscopeError", 122 | 32: "AcceletorError", 123 | 33: "CompassFailed", 124 | 34: "BarometerError", 125 | 35: "BarometerNegative", 126 | 36: "CompassBig", 127 | 37: "GyroscopeBiasBig", 128 | 38: "AcceletorBiasBig", 129 | 39: "CompassNoiseBig", 130 | 40: "BarometerNoiseBig", 131 | 41: "InvalidSn", 132 | 44: "FLASH_OPERATING", 133 | 45: "GPS_DISCONNECT", 134 | 47: "SDCardException", 135 | 61: "IMUNoconnection", 136 | 62: "RCCalibration", 137 | 63: "RCCalibrationException", 138 | 64: "RCCalibrationUnfinished", 139 | 65: "RCCalibrationException2", 140 | 66: "RCCalibrationException3", 141 | 67: "AircraftTypeMismatch", 142 | 68: "FoundUnfinishedModule", 143 | 70: "CYRO_ABNORMAL", 144 | 71: "BARO_ABNORMAL", 145 | 72: "COMPASS_ABNORMAL", 146 | 73: "GPS_ABNORMAL", 147 | 74: "NS_ABNORMAL", 148 | 75: "TOPOLOGY_ABNORMAL", 149 | 76: "RC_NEED_CALI", 150 | 77: "INVALID_FLOAT", 151 | 78: "M600_BAT_TOO_LITTLE", 152 | 79: "M600_BAT_AUTH_ERR", 153 | 80: "M600_BAT_COMM_ERR", 154 | 81: "M600_BAT_DIF_VOLT_LARGE_1", 155 | 82: "M600_BAT_DIF_VOLT_LARGE_2", 156 | 83: "INVALID_VERSION", 157 | 84: "GimbalGyroError", 158 | 85: "GimbalPitchNoData", 159 | 86: "GimbalRollNoData", 160 | 87: "GimbalYawNoData", 161 | 88: "GimbalFirmIsUpdata", 162 | 89: "GimbalDisorder", 163 | 84: "GIMBAL_GYRO_ABNORMAL", 164 | 85: "GIMBAL_ESC_PITCH_NON_DATA", 165 | 86: "GIMBAL_ESC_ROLL_NON_DATA", 166 | 87: "GIMBAL_ESC_YAW_NON_DATA", 167 | 88: "GIMBAL_FIRM_IS_UPDATING", 168 | 89: "GIMBAL_DISORDER", 169 | 90: "GIMBAL_PITCH_SHOCK", 170 | 91: "GIMBAL_ROLL_SHOCK", 171 | 92: "GIMBAL_YAW_SHOCK", 172 | 90: "GimbalPitchShock", 173 | 91: "GimbalRollShock", 174 | 92: "GimbalYawShock", 175 | 93: "IMUcCalibrationFinished", 176 | 101: "BatVersionError", 177 | 102: "RTK_BAD_SIGNAL", 178 | 103: "RTK_DEVIATION_ERROR", 179 | 112: "ESC_CALIBRATING", 180 | 113: "GPS_SIGN_INVALID", 181 | 114: "GIMBAL_IS_CALIBRATING", 182 | 115: "LOCK_BY_APP", 183 | 116: "START_FLY_HEIGHT_ERROR", 184 | 117: "ESC_VERSION_NOT_MATCH", 185 | 118: "IMU_ORI_NOT_MATCH", 186 | 119: "STOP_BY_APP", 187 | 120: "COMPASS_IMU_ORI_NOT_MATCH", 188 | 256: "OTHER" 189 | }; 190 | 191 | var FLIGHT_ACTION = { 192 | 0: "NONE", 193 | 1: "WARNING_POWER_GOHOME", 194 | 2: "WARNING_POWER_LANDING", 195 | 3: "SMART_POWER_GOHOME", 196 | 4: "SMART_POWER_LANDING", 197 | 5: "LOW_VOLTAGE_LANDING", 198 | 6: "LOW_VOLTAGE_GOHOME", 199 | 7: "SERIOUS_LOW_VOLTAGE_LANDING", 200 | 8: "RC_ONEKEY_GOHOME", 201 | 9: "RC_ASSISTANT_TAKEOFF", 202 | 10: "RC_AUTO_TAKEOFF", 203 | 11: "RC_AUTO_LANDING", 204 | 12: "APP_AUTO_GOHOME", 205 | 13: "APP_AUTO_LANDING", 206 | 14: "APP_AUTO_TAKEOFF", 207 | 15: "OUTOF_CONTROL_GOHOME", 208 | 16: "API_AUTO_TAKEOFF", 209 | 17: "API_AUTO_LANDING", 210 | 18: "API_AUTO_GOHOME", 211 | 19: "AVOID_GROUND_LANDING", 212 | 20: "AIRPORT_AVOID_LANDING", 213 | 21: "TOO_CLOSE_GOHOME_LANDING", 214 | 22: "TOO_FAR_GOHOME_LANDING", 215 | 23: "APP_WP_MISSION", 216 | 24: "WP_AUTO_TAKEOFF", 217 | 25: "GOHOME_AVOID", 218 | 26: "GOHOME_FINISH", 219 | 27: "VERT_LOW_LIMIT_LANDING", 220 | 28: "BATTERY_FORCE_LANDING", 221 | 29: "MC_PROTECT_GOHOME" 222 | } 223 | 224 | var NON_GPS_CAUSE = { 225 | 0: "ALREADY", 226 | 1: "FORBIN", 227 | 2: "GPSNUM_NONENOUGH", 228 | 3: "GPS_HDOP_LARGE", 229 | 4: "GPS_POSITION_NONMATCH", 230 | 5: "SPEED_ERROR_LARGE", 231 | 6: "YAW_ERROR_LARGE", 232 | 7: "COMPASS_ERROR_LARGE", 233 | 8: "UNKNOWN" 234 | }; 235 | 236 | var IMU_INITFAIL_REASON = { 237 | 0: "MONITOR_ERROR", 238 | 1: "COLLECTING_DATA", 239 | 2: "GYRO_DEAD", 240 | 3: "ACCE_DEAD", 241 | 4: "COMPASS_DEAD", 242 | 5: "BAROMETER_DEAD", 243 | 6: "BAROMETER_NEGATIVE", 244 | 7: "COMPASS_MOD_TOO_LARGE", 245 | 8: "GYRO_BIAS_TOO_LARGE", 246 | 9: "ACCE_BIAS_TOO_LARGE", 247 | 10: "COMPASS_NOISE_TOO_LARGE", 248 | 11: "BAROMETER_NOISE_TOO_LARGE", 249 | 12: "WAITING_MC_STATIONARY", 250 | 13: "ACCE_MOVE_TOO_LARGE", 251 | 14: "MC_HEADER_MOVED", 252 | 15: "MC_VIBRATED", 253 | 16: "NONE" 254 | }; 255 | 256 | var MOTOR_FAIL_REASON = { 257 | 94: "TAKEOFF_EXCEPTION", 258 | 95: "ESC_STALL_NEAR_GROUND", 259 | 96: "ESC_UNBALANCE_ON_GRD", 260 | 97: "ESC_PART_EMPTY_ON_GRD", 261 | 98: "ENGINE_START_FAILED", 262 | 99: "AUTO_TAKEOFF_LANCH_FAILED", 263 | 100: "ROLL_OVER_ON_GRD", 264 | 128: "OTHER" 265 | } 266 | 267 | var SDK_CONTROL_DEVICE = { 268 | 0: "RC", 269 | 1: "APP", 270 | 2: "ONBOARD_DEVICE", 271 | 3: "CAMERA", 272 | 128: "OTHER" 273 | }; 274 | 275 | 276 | function OSD(buffer, index, key) { 277 | DJIBuffer.call(this, buffer, index, key); 278 | } 279 | 280 | OSD.prototype = Object.create(DJIBuffer.prototype); 281 | 282 | OSD.prototype.getLongitude = function() { 283 | return (this.readDouble(0, 8) * 180) / Math.PI; 284 | } 285 | 286 | OSD.prototype.getLatitude = function() { 287 | return (this.readDouble(8, 8) * 180) / Math.PI; 288 | } 289 | 290 | OSD.prototype.getHeight = function() { 291 | return this.readShort(16, 2) / 10; 292 | } 293 | 294 | OSD.prototype.getXSpeed = function() { 295 | return this.readShort(18, 2); 296 | } 297 | 298 | OSD.prototype.getYSpeed = function() { 299 | return this.readShort(20, 2); 300 | } 301 | 302 | OSD.prototype.getZSpeed = function() { 303 | return this.readShort(22, 2); 304 | } 305 | 306 | OSD.prototype.getPitch = function() { 307 | return this.readShort(24, 2); 308 | } 309 | 310 | OSD.prototype.getRoll = function() { 311 | return this.readShort(26, 2); 312 | } 313 | 314 | OSD.prototype.getYaw = function() { 315 | return this.readShort(28, 2); 316 | } 317 | 318 | OSD.prototype.getRcState = function() { 319 | return (this.readShort(30, 1) & 128) == 0; 320 | } 321 | 322 | OSD.prototype.getFlycState = function() { 323 | return FLYC_STATE[this.readShort(30, 1) & -129]; 324 | } 325 | 326 | OSD.prototype.getAppCommand = function() { 327 | return this.readShort(31, 1); 328 | } 329 | 330 | OSD.prototype.canIOCWork = function() { 331 | return (this.readInt(32, 4) & 1) == 1; 332 | } 333 | 334 | OSD.prototype.groundOrSky = function() { 335 | return this.readInt(32, 4) >> 1 & 3; 336 | } 337 | 338 | OSD.prototype.isMotorUp = function() { 339 | return (this.readInt(32, 4) >> 3 & 1) == 1 340 | } 341 | 342 | OSD.prototype.isSwaveWork = function() { 343 | return (this.readInt(32, 4) & 16) != 0; 344 | } 345 | 346 | OSD.prototype.getGohomeStatus = function() { 347 | return GOHOME_STATUS[this.readInt(32, 4) >> 5 & 7]; 348 | } 349 | 350 | OSD.prototype.isImuPreheated = function() { 351 | return (this.readInt(32, 4) & 4096) != 0; 352 | } 353 | 354 | OSD.prototype.isVisionUsed = function() { 355 | return (this.readInt(32, 4) & 256) != 0; 356 | } 357 | 358 | OSD.prototype.getVoltageWarning = function() { 359 | return (this.readInt(32, 4) & 1536) >>> 9; 360 | } 361 | 362 | OSD.prototype.getModeChannel = function() { 363 | return (this.readInt(32, 4) & 24576) >>> 13; 364 | } 365 | 366 | OSD.prototype.getCompassError = function() { 367 | return (this.readInt(32, 4) & 65536) != 0; 368 | } 369 | 370 | OSD.prototype.getWaveError = function() { 371 | return (this.readInt(32, 4) & 131072) != 0; 372 | } 373 | 374 | OSD.prototype.getGpsLevel = function() { 375 | return this.readInt(32, 4) >>> 18 & 15; 376 | } 377 | 378 | OSD.prototype.getBatteryType = function() { 379 | if (this.getDroneType() == "Unknown" || this.getDroneType() == "None") { 380 | return "SMART"; 381 | } 382 | return BATTERY_TYPE[this.readInt(32, 4) >>> 22 & 3]; 383 | } 384 | 385 | OSD.prototype.isAcceletorOverRange = function() { 386 | return (this.readInt(32, 4) >>> 24 & 1) != 0; 387 | } 388 | 389 | OSD.prototype.isVibrating = function() { 390 | return (this.readInt(32, 4) >>> 25 & 1) != 0; 391 | } 392 | 393 | OSD.prototype.isBarometerDeadInAir = function() { 394 | return (this.readInt(32, 4) >>> 26 & 1) != 0; 395 | } 396 | 397 | OSD.prototype.isMotorBlocked = function() { 398 | return (this.readInt(32, 4) >>> 27 & 1) != 0; 399 | } 400 | 401 | OSD.prototype.isNotEnoughForce = function() { 402 | return (this.readInt(32, 4) >>> 28 & 1) != 0; 403 | } 404 | 405 | OSD.prototype.isPropellerCatapult = function() { 406 | return (this.readInt(32, 4) >>> 29 & 1) != 0; 407 | } 408 | 409 | OSD.prototype.isGoHomeHeightModified = function() { 410 | return (this.readInt(32, 4) >>> 30 & 1) != 0; 411 | } 412 | 413 | OSD.prototype.isOutOfLimit = function() { 414 | return (this.readInt(32, 4) >>> 31 & 1) != 0; 415 | } 416 | 417 | OSD.prototype.getGpsNum = function() { 418 | return this.readShort(36, 1); 419 | } 420 | 421 | OSD.prototype.getFlightAction = function() { 422 | return FLIGHT_ACTION[this.readShort(37, 1)]; 423 | } 424 | 425 | OSD.prototype.getMotorFailedCause = function() { 426 | var s2 = this.readShort(38, 1); 427 | if (s2 >> 7 == 0) { 428 | return "NONE"; 429 | } 430 | return MOTOR_START_FAILED_CAUSE[this.readShort(38, 1) & 127]; 431 | } 432 | 433 | OSD.prototype.getNonGpsCause = function() { 434 | return NON_GPS_CAUSE[this.readInt(39, 1) & 15]; 435 | } 436 | 437 | OSD.prototype.getWaypointLimitMode = function() { 438 | return this.readInt(39, 1) & 16 == 16; 439 | } 440 | 441 | OSD.prototype.getBattery = function() { 442 | return this.readInt(40, 1); 443 | } 444 | 445 | OSD.prototype.getSwaveHeight = function() { 446 | return this.readShort(41, 1); 447 | } 448 | 449 | OSD.prototype.getFlyTime = function() { 450 | return this.readInt(42, 2) / 10; 451 | } 452 | 453 | OSD.prototype.getMotorRevolution = function() { 454 | return this.readShort(44, 1); 455 | } 456 | 457 | OSD.prototype.getFlycVersion = function() { 458 | return this.readInt(47, 1); 459 | } 460 | 461 | OSD.prototype.getDroneType = function() { 462 | return DRONE_TYPE[this.readInt(48, 1)]; 463 | } 464 | 465 | OSD.prototype.getIMUinitFailReason = function() { 466 | return IMU_INITFAIL_REASON[this.readInt(49, 1)]; 467 | } 468 | 469 | OSD.prototype.isImuInitError = function() { 470 | var reason = this.getIMUinitFailReason(); 471 | return reason != "None" && reason != "ColletingData" && reason != "MonitorError"; 472 | } 473 | 474 | OSD.prototype.getMotorFailReason = function() { 475 | return MOTOR_FAIL_REASON[this.readInt(50, 1)]; 476 | } 477 | 478 | OSD.prototype.getSDKCtrlDevice = function() { 479 | return SDK_CONTROL_DEVICE[this.readInt(52, 1)]; 480 | } 481 | 482 | module.exports = OSD; -------------------------------------------------------------------------------- /lib/model/rc-gps.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | function RCGPS(buffer, index, key) { 6 | DJIBuffer.call(this, buffer, index, key); 7 | } 8 | 9 | RCGPS.prototype = Object.create(DJIBuffer.prototype); 10 | 11 | RCGPS.prototype.getLatitude = function() { 12 | return this.readInt(7, 4); 13 | } 14 | 15 | RCGPS.prototype.getLongitude = function() { 16 | return this.readInt(11, 4); 17 | } 18 | 19 | RCGPS.prototype.getXSpeed = function() { 20 | return this.readInt(15, 4) / 1000; 21 | } 22 | 23 | RCGPS.prototype.getYSpeed = function() { 24 | return this.readInt(19, 4) / 1000; 25 | } 26 | 27 | RCGPS.prototype.getGpsNum = function() { 28 | return this.readShort(23, 1); 29 | } 30 | 31 | RCGPS.prototype.getGpsStatus = function() { 32 | return this.readShort(28, 2) == 1; 33 | } 34 | 35 | module.exports = RCGPS; -------------------------------------------------------------------------------- /lib/model/rc.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | function RC(buffer, index, key) { 6 | DJIBuffer.call(this, buffer, index, key); 7 | } 8 | 9 | RC.prototype = Object.create(DJIBuffer.prototype); 10 | 11 | RC.prototype.getAileron = function() { 12 | return this.readInt(0, 2); 13 | } 14 | 15 | RC.prototype.getElevator = function() { 16 | return this.readInt(2, 2); 17 | } 18 | 19 | RC.prototype.getThrottle = function() { 20 | return this.readInt(4, 2); 21 | } 22 | 23 | RC.prototype.getRudder = function() { 24 | return this.readInt(6, 2); 25 | } 26 | 27 | RC.prototype.getGyroValue = function() { 28 | return this.readInt(8, 2); 29 | } 30 | 31 | RC.prototype.getFootStool = function() { 32 | return (this.readInt(11, 1) >> 6 & 4) == 3; 33 | } 34 | 35 | RC.prototype.getMode = function() { 36 | return this.readInt(11, 1) >> 4 & 3; 37 | } 38 | 39 | RC.prototype.getGoHome = function() { 40 | return this.readInt(11, 1) >> 3 & 1; 41 | } 42 | 43 | RC.prototype.getCoronaChange = function() { 44 | return (this.readInt(10, 1) >> 7 & 1) == 1; 45 | } 46 | 47 | RC.prototype.getChangeDirection = function() { 48 | return this.readInt(10, 1) >> 6 & 1; 49 | } 50 | 51 | RC.prototype.getOffset = function() { 52 | return this.readInt(10, 1) >> 1 & 31; 53 | } 54 | 55 | RC.prototype.getIsPushCorona = function() { 56 | return this.readInt(10, 1) & 1; 57 | } 58 | 59 | RC.prototype.getRecordStatus = function() { 60 | return (this.readInt(12, 1) >> 7 & 1) == 1; 61 | } 62 | 63 | RC.prototype.getShutterStatus = function() { 64 | return (this.readInt(12, 1) >> 6 & 1) == 1; 65 | } 66 | 67 | RC.prototype.getPlayback = function() { 68 | return this.readInt(12, 1) >> 5 & 1; 69 | } 70 | 71 | RC.prototype.getCustom2 = function() { 72 | return this.readInt(12, 1) >> 3 & 1; 73 | } 74 | 75 | RC.prototype.getCustom1 = function() { 76 | return this.readInt(12, 1) >> 4 & 1; 77 | } 78 | 79 | RC.prototype.isGoHomeButtonPressed = function() { 80 | return ((this.readInt(11, 1) >> 3) & 1) != 0; 81 | } 82 | 83 | RC.prototype.getFootStool = function() { 84 | return ((this.readInt(11, 1) >> 6) & 3) == 3; 85 | } 86 | 87 | RC.prototype.getMode = function() { 88 | return (this.readInt(11, 1) >> 4) & 3; 89 | } 90 | 91 | RC.prototype.getBandWidth = function() { 92 | return this.readInt(13, 1); 93 | } 94 | 95 | module.exports = RC; -------------------------------------------------------------------------------- /lib/model/recover.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | function Recover(buffer, index, key) { 6 | DJIBuffer.call(this, buffer, index, key); 7 | } 8 | 9 | var DRONE_TYPE = { 10 | 0: "Unknown", 11 | 1: "Inspire", 12 | 2: "P3S", 13 | 3: "P3X", 14 | 4: "P3C", 15 | 5: "OpenFrame", 16 | 7: "P4", 17 | 13: "Mavic", 18 | 100: "None" 19 | }; 20 | 21 | var APP_TYPE = { 22 | 0: "UNKNOWN", 23 | 1: "IOS", 24 | 2: "ANDROID" 25 | }; 26 | 27 | Recover.prototype = Object.create(DJIBuffer.prototype); 28 | 29 | Recover.prototype.getDroneType = function() { 30 | return DRONE_TYPE[this.readInt(0, 1)]; 31 | } 32 | 33 | Recover.prototype.getAppType = function() { 34 | return APP_TYPE[this.readInt(1, 1)]; 35 | } 36 | 37 | Recover.prototype.getAppVersion = function() { 38 | return this.readInt(2, 1)+'.'+this.readInt(3, 1)+'.'+this.readInt(4, 1); 39 | } 40 | 41 | Recover.prototype.getAircraftSn = function() { 42 | return this.readString(5, 10); 43 | } 44 | 45 | Recover.prototype.getAircraftName = function() { 46 | return this.readString(15, 24); 47 | } 48 | 49 | Recover.prototype.getActiveTimestamp = function() { 50 | return new Date(parseInt(this.readLong(47, 8).toString())).toISOString(); 51 | } 52 | 53 | Recover.prototype.getCameraSn = function() { 54 | return this.readString(55, 10); 55 | } 56 | 57 | Recover.prototype.getRcSn = function() { 58 | return this.readString(65, 10); 59 | } 60 | 61 | Recover.prototype.getBatterySn = function() { 62 | return this.readString(75, 85); 63 | } 64 | 65 | module.exports = Recover; 66 | -------------------------------------------------------------------------------- /lib/model/smart-battery.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var DJIBuffer = require("../djibuffer"); 4 | 5 | var DJI_BATTERY_STATUS = { 6 | 0: "UserBatteryReqGoHome", 7 | 1: "UserBatteryReqLand", 8 | 4: "SmartBatteryReqGoHome", 9 | 8: "SmartBatteryReqLand", 10 | 16: "MainVoltageLowGoHOme", 11 | 32: "MainVoltageLowLand", 12 | 64: "BatteryCellError", 13 | 128: "BatteryCommunicateError", 14 | 256: "VoltageLowNeedLand", 15 | 512: "BatteryTempVoltageLow", 16 | 1024: "BatteryNotReady", 17 | 2048: "BatteryFirstChargeNotFull", 18 | 69905: "OTHER" 19 | }; 20 | 21 | function SmartBattery(buffer, index, key) { 22 | DJIBuffer.call(this, buffer, index, key); 23 | } 24 | 25 | SmartBattery.prototype = Object.create(DJIBuffer.prototype); 26 | 27 | SmartBattery.prototype.getUsefulTime = function() { 28 | return this.readInt(0, 2); 29 | } 30 | 31 | SmartBattery.prototype.getGoHomeTime = function() { 32 | return this.readInt(2, 2); 33 | } 34 | 35 | SmartBattery.prototype.getLandTime = function() { 36 | return this.readInt(4, 2); 37 | } 38 | 39 | SmartBattery.prototype.getGoHomeBattery = function() { 40 | return this.readInt(6, 2); 41 | } 42 | 43 | SmartBattery.prototype.getLandBattery = function() { 44 | return this.readInt(8, 2); 45 | } 46 | 47 | SmartBattery.prototype.getSafeFlyRadius = function() { 48 | return this.readFloat(10, 4); 49 | } 50 | 51 | SmartBattery.prototype.getVolumeConsume = function() { 52 | return this.readFloat(14, 4); 53 | } 54 | 55 | SmartBattery.prototype.getStatus = function() { 56 | return DJI_BATTERY_STATUS[this.readInt(18, 4)]; 57 | } 58 | 59 | SmartBattery.prototype.getGoHomeStatus = function() { 60 | return this.readInt(22, 1); 61 | } 62 | 63 | SmartBattery.prototype.getGoHomeCountDown = function() { 64 | return this.readInt(23, 1); 65 | } 66 | 67 | SmartBattery.prototype.getVoltage = function() { 68 | return this.readInt(24, 2); 69 | } 70 | 71 | //SmartBattery.prototype.getBattery 72 | 73 | SmartBattery.prototype.getLowWarning = function() { 74 | return this.readInt(27, 1) & 127; 75 | } 76 | 77 | SmartBattery.prototype.getLowWarningGoHome = function() { 78 | return (this.readInt(27, 1) & 128) != 0; 79 | } 80 | 81 | SmartBattery.prototype.getSeriousLowWarning = function() { 82 | return this.readInt(28, 1) & 127; 83 | } 84 | 85 | SmartBattery.prototype.getSeriousLowWarningLanding = function() { 86 | return (this.readInt(28, 1) & 128) != 0; 87 | } 88 | 89 | SmartBattery.prototype.getVoltagePercent = function() { 90 | return this.readInt(29, 1); 91 | } 92 | 93 | module.exports = SmartBattery; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dji-log-parser", 3 | "version": "0.0.4", 4 | "description": "", 5 | "author": "", 6 | "license": "MIT", 7 | "dependencies": { 8 | "bytebuffer": "^5.0.0", 9 | "long": "^3.0.1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/mikeemoo/dji-log-parser.git" 14 | }, 15 | "scripts": { 16 | "build": "webpack --config webpack.config.js" 17 | }, 18 | "devDependencies": { 19 | "uglifyjs-webpack-plugin": "^1.0.0-beta.3", 20 | "webpack": "^3.7.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 2 | 3 | module.exports = { 4 | entry: __dirname + "/lib", 5 | output: { 6 | path: __dirname, 7 | filename: "browser.js" 8 | }, 9 | plugins: [ 10 | new UglifyJSPlugin() 11 | ] 12 | }; --------------------------------------------------------------------------------