diff --git a/Lua_scripts/DSM_AR636_TextGen.lua b/Lua_scripts/DSM_AR636_TextGen.lua new file mode 100644 index 0000000..726311e --- /dev/null +++ b/Lua_scripts/DSM_AR636_TextGen.lua @@ -0,0 +1,610 @@ +local toolName = "TNS|DSM AR636 Telemetry TextGen|TNE" +---- ######################################################################### # +---- # License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html # +---- # # +---- # This program is free software; you can redistribute it and/or modify # +---- # it under the terms of the GNU General Public License version 2 as # +---- # published by the Free Software Foundation. # +---- # # +---- # This program is distributed in the hope that it will be useful # +---- # but WITHOUT ANY WARRANTY; without even the implied warranty of # +---- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +---- # GNU General Public License for more details. # +---- # # +---- ######################################################################### + +------------------------------------------------------------------------------ +-- Developer: Francisco Arzu +-- Original idea taken from DsmPID.lua.. don't know who is the author +-- + +local DEBUG_ON = false +-- + +local TEXT_SIZE = 0 -- NORMAL +local X_COL1_HEADER = 6 +local X_COL1_DATA = 80 +local X_COL2_HEADER = 120 +local X_COL2_DATA = 190 +local Y_LINE_HEIGHT = 20 +local Y_HEADER = 0 +local Y_DATA = Y_HEADER + Y_LINE_HEIGHT + + + + +local function getPage(iParam) + -- get page from 0-based index + -- {0,1,2,3}: cyclic (1), {4,5,6,7}: tail (2) + local res = (math.floor(iParam/4)==0) and 0 or 1 + return res +end + +local function round(v) + -- round float + local factor = 100 + return math.floor(v * factor + 0.5) / factor +end + + +local function readValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + --v = round(v) + return v +end + +local function readValueById(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return nil end + + local v = getValue(i.id) + return v +end + + + +local function readBatValue(sensor) + -- read from sensor, round and return + local v = getValue(sensor) + if (v==nil) then return "-- V" end + + return string.format("%2.2f V",v) +end + +local function readActiveParamValue(sensor) + -- read and return a validated active parameter value + local v = getValue(sensor) + if (v<1 or v>8) then + return -1 + end + return v +end + + +local function drawPIDScreen() + -- draw labels and params on screen + + local pageId = getValue("FLss") + + lcd.clear() + -- if active gain does not validate then assume + -- Gain Adjustment Mode is disabled + if not (pageId==4401 or pageId==4402) then + lcd.drawText(0,0,"BLADE Gain Adjustment", TEXT_SIZE +INVERS) + lcd.drawText(20,Y_LINE_HEIGHT*1,"Please enter Gain Adjustment Mode",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*2,"Stk: Low/Righ + Low/Right + Panic (3 sec)",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*4,"Op: Right Stk: Up/Down to select, Left/Right change value",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE) + return + end + + local activePage = (pageId % 100)-1 --Last 2 digits, make it zero base + + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Cyclic (0-200)", TEXT_SIZE + INVERS) + lcd.drawText (X_COL2_HEADER, Y_HEADER, "Tail (0-200)", TEXT_SIZE + INVERS) + + + + local p = readValue("FdeA") + local i = readValue("FdeB") + local d = readValue("FdeL") + local r = readValue("FdeR") + + local titles = {[0]="P:", "I:", "D:", "Response:", "P:","I:","D:", "Filtering:"} + local values = {[0]=p,i,d,r,p,i,d,r} + + local activeParam = readActiveParamValue("Hold")-1 + + for iParam=0,7 do + -- highlight selected parameter + local attr = (activeParam==iParam) and INVERS or 0 + -- circular index (per page) + local perPageIndx = (iParam % 4) + + -- set y draw coord + local y = (perPageIndx+1)*Y_LINE_HEIGHT+Y_DATA + + -- check if displaying cyclic params. + local isCyclicPage = (getPage(iParam)==0) + + -- labels + local x = isCyclicPage and X_COL1_HEADER or X_COL2_HEADER + -- labels are P,I,D for both pages except for last param + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + -- gains + -- set all params for non-active page to '--' rather than 'last value' + val = (getPage(iParam)==activePage) and values[iParam] or '--' + x = isCyclicPage and X_COL1_DATA or X_COL2_DATA + + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + end +end + + +local function drawFlightLogScreen() + -- draw labels and params on screen + local h = getValue("Hold") + local activeParam = h-1 -- H + + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Flight Log", TEXT_SIZE + INVERS) + + -- read and return parameters + local a = getValue("FdeA") + local b = getValue("FdeB") + local l = getValue("FdeL") + local r = getValue("FdeR") + local f = getValue("FLss") + + local titles = {[0]="A:", "B:", "L:", "R:", "F:", "H:"} + local values = {[0]=a,b,l,r,f,h} + + for iParam=0,3 do -- A,B,L,R + -- highlight selected parameter (rund) + local attr = ((activeParam%4)==iParam) and INVERS or 0 + + -- set y draw coord + local y = iParam*Y_LINE_HEIGHT+Y_DATA + + -- labels + local x = X_COL1_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] + x = X_COL1_HEADER + 30 + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + end + + for iParam=4,5 do -- F, H + -- highlight selected parameter + local attr = 0 + -- set y draw coord + local perPageIndx = iParam % 4 + local y = perPageIndx*Y_LINE_HEIGHT+Y_DATA + + -- labels + local x = X_COL2_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE + BOLD) + + val = values[iParam] + x = X_COL2_HEADER + 30 + lcd.drawText (x, y, val, attr + TEXT_SIZE + BOLD) + end + + -- Bat + local bat = readBatValue("A2") + local y = (4)*Y_LINE_HEIGHT+Y_HEADER + lcd.drawText (X_COL2_HEADER, y, "Bat:", TEXT_SIZE) + lcd.drawText (X_COL2_HEADER+30, y, bat, TEXT_SIZE) + + +end + + + + +local function servoAdjustScreen() + -- draw labels and params on screen + local pageId = getValue("FLss") -- FLss + local activeParam = getValue("Hold")-1 -- Hold + + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "BLADE Servo SubTrim", TEXT_SIZE + INVERS) + + if pageId~=1234 then + lcd.drawText(20,Y_LINE_HEIGHT*1,"Please enter Servo Adjustment Mode",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*2,"Stk: Low/Left + Low/Right + Panic (3 sec)",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*4,"Op: R Stk: Up/Down to select, Left/Right change value",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*5,"Panic to exit",TEXT_SIZE) + return + end + + local a = getValue("FdeA") + local b = getValue("FdeB") + local l = getValue("FdeL") + + local titles = {[0]="Servo1:", "Servo2:", "Servo3:"} + local values = {[0]=a,b,l} + + for iParam=0,#values do -- S1,S2,S3 + -- highlight selected parameter + local attr = (activeParam==iParam) and INVERS or 0 + + -- set y draw coord + local y = (iParam+1)*Y_LINE_HEIGHT+Y_HEADER + + -- labels + local x = X_COL1_HEADER + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] + x = X_COL1_DATA + if (val~=16384) then -- Active value + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + end +end + +local function Unsigned_to_SInt16(value) + if value >= 0x8000 then -- Negative value?? + return value - 0x10000 + end + return value +end + +local function getDegreesValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%0.1f o",vs/10) +end + + +local function getDecHexValue(sensor) + local i = getFieldInfo(sensor) + if (i==nil) then return "-unk-" end + + local v = getValue(i.id) + if v==nil then return "---" end + local vs = Unsigned_to_SInt16(v) + + return string.format("%d (0x%04X)",vs,v) +end + + + + +local function drawVersionScreen() + local paramV = getValue("FdeA") + local B = getValue("FdeB") + local rxId = getValue("FdeL") + local firmware = getValue("FLss") + local prodId = getValue("Hold") + local bat = readBatValue("A2") + + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "BLADE Version", TEXT_SIZE + INVERS) + + lcd.drawText(20,Y_LINE_HEIGHT*7,"Please Press Panic for 3s",TEXT_SIZE) + lcd.drawText(20,Y_LINE_HEIGHT*8,"Usually Panic is Ch7 on a switch and Revesed",TEXT_SIZE) + + + --Product ID + local val = "ID_".. prodId + + if (prodId==243) then val = "Blade 230 V1" + elseif (prodId==250) then val = "Blade 230 V2 (not Smart)" + elseif (prodId==149) then val = "Blade 250 CFX" + end + + local y = Y_LINE_HEIGHT*1+Y_HEADER + lcd.drawText (X_COL1_HEADER, y, "Prod:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA, y, val, TEXT_SIZE) + + -- RX + val = "ID_"..rxId + if (rxId==1) then val = "AR636" + end + + local y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "RX:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA, y, val, TEXT_SIZE) + + -- Firmware + val = string.format("%0.2f",firmware/100) + local y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Firmware:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA, y, val, TEXT_SIZE) + + -- ParamV + local y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Params:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA, y, paramV, TEXT_SIZE) + + -- Vat + local y = y + Y_LINE_HEIGHT + lcd.drawText (X_COL1_HEADER, y, "Bat:", TEXT_SIZE) + lcd.drawText (X_COL1_DATA, y, bat, TEXT_SIZE) +end + +local function parseFlightMode(v) + -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0= off, 1=init, 2=Hold, 3=Running) GG=??? + if v==nil then return "---" end + local fm = bit32.rshift(v, 12) + local status = bit32.band(bit32.rshift(v, 8),0xF) + + local res = " "..fm.." " + + if (fm==0) then res = res .. " NORMAL" + elseif (fm==1) then res = res .. " INTERMEDIATE" + elseif (fm==2) then res = res .. " ADVANCED" + elseif (fm==5) then res = res .. " PANIC" + end + + if (status==2) then res=res .. " HOLD" end + + if (DEBUG_ON) then + res = res .. string.format(" (0x%04X)",v) + end + + return res +end + + +local function drawAlpha6Monitor() + lcd.clear() + + local RxStatus = readValueById("2402") -- FlightMode (Hex: MMSGG) MM=Flight Mode, S=Status (0=init, 2=Ready, 3=Sensor Fault) GG=??? + + local ARoll = getDegreesValue("2406") --Att Roll + local APitch = getDegreesValue("2408") --Att Pitch + local AYaw = getDegreesValue("240B") --Att Yaw + + + lcd.drawText (0,0, "BLADE AS3X/SAFE Monitor", TEXT_SIZE+INVERS) + + local y = Y_LINE_HEIGHT+Y_HEADER + -- Flight Mode + lcd.drawText (0,y, "F-Mode:"..parseFlightMode(RxStatus), TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText (100+5,y, "Attitude", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (150,y, "Gyro", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (200,y, "Gain", TEXT_SIZE+BOLD + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Rol:", TEXT_SIZE) + lcd.drawText (100-5,y, ARoll, TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Pitch:", TEXT_SIZE) + lcd.drawText (100-5,y, APitch, TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Yaw:", TEXT_SIZE) + lcd.drawText (100-5,y, AYaw, TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, "-", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, "-", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + Y_LINE_HEIGHT + lcd.drawText (0,y, "Bat: "..readBatValue("A2"), TEXT_SIZE) + + + -- Debug Values + if (DEBUG_ON) then + local s2400 = getDecHexValue("2400") + local s2402 = getDecHexValue("2402") + local s2404 = getDecHexValue("2404") + + local s240D = getDecHexValue("240D") + + local s1G00 = getDecHexValue("1G00") + local s1G02 = getDecHexValue("1G02") + local s1G04 = getDecHexValue("1G04") + local s1G06 = getDecHexValue("1G06") + local s1G08 = getDecHexValue("1G08") + local s1G0B = getDecHexValue("1G0B") + local s1G0D = getDecHexValue("1G0D") + + local titles = {[0]= + "2400","2402/FM-S-?", + "2404","240D", + "1G00","1G02","1G04", + "1G06","1G08","1G0B","1G0D"} + + local values = {[0]= + s2400,s2402,s2404,s240D, + s1G00,s1G02,s1G04, + s1G06,s1G08,s1G0B,s1G0D} + + + -- draw labels and params on screen + + y = Y_LINE_HEIGHT*2 + Y_HEADER + for iParam=0,#titles do -- ?? + -- labels + local x = X_COL1_HEADER+220 + local val = titles[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = values[iParam] + x = X_COL1_DATA+250 + lcd.drawText (x, y, val, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + end + end +end + +local function readAlpha3arameters() + +end + + + + +local function drawAS3XMonitor() + lcd.clear() + local s1G00 = getDecHexValue("1G00") + local s1G02 = getDecHexValue("1G02") + local s1G04 = getDecHexValue("1G04") + local s1G06 = getDecHexValue("1G06") + local s1G08 = getDecHexValue("1G08") + local s1G0B = getDecHexValue("1G0B") + local s1G0D = getDecHexValue("1G0D") + + local s6C00 = getDecHexValue("6C00") + local s6C02 = getDecHexValue("6C02") + local s6C04 = getDecHexValue("6C04") + + + + local RRoll = bit32.rshift(getValue("1G00") or 0,8) + local RPitch = bit32.band(getValue("1G00") or 0,0xFF) + local RYaw = bit32.rshift(getValue("1G02") or 0,8) + + local HRoll = bit32.band(getValue("1G02") or 0,0xFF) + local HPitch = bit32.rshift(getValue("1G04") or 0,8) + local HYaw = bit32.band(getValue("1G04") or 0,0xFF) + + local ARoll = bit32.rshift(getValue("1G06") or 0,8) + local APitch = bit32.band(getValue("1G06") or 0,0xFF) + local AYaw = bit32.rshift(getValue("1G08") or 0,8) + + + lcd.drawText (0,0, "Plane AR636 AS3X Gains", TEXT_SIZE+INVERS) + + local y = Y_LINE_HEIGHT+Y_HEADER + -- Flight Mode + --lcd.drawText (0,y, "F-Mode: "..(nil or "--"), TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + lcd.drawText (100-15,y, "Rate", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (150,y, "Heading", TEXT_SIZE+BOLD + RIGHT) + lcd.drawText (200,y, "Actual", TEXT_SIZE+BOLD + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Roll:", TEXT_SIZE) + lcd.drawText (100-5,y, RRoll.."%", TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, HRoll.."%", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, ARoll.."%", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Pitch:", TEXT_SIZE) + lcd.drawText (100-5,y, RPitch.."%", TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, HPitch.."%", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, APitch.."%", TEXT_SIZE + RIGHT) + + y = y + Y_LINE_HEIGHT + lcd.drawText (5,y, "Yaw:", TEXT_SIZE) + lcd.drawText (100-5,y, RYaw.."%", TEXT_SIZE + RIGHT) + lcd.drawText (150-5,y, HYaw.."%", TEXT_SIZE + RIGHT) + lcd.drawText (200-5,y, AYaw.."%", TEXT_SIZE + RIGHT) + + + -- Debug Values + if (DEBUG_ON) then + local Alpha3Tags = {[0]= + "1G00/RA+RE","1G02/RY+HA","1G04R HP+HY","1G06/AR+AP","1G08/AY+?","1G0B","1G0D","6C00","6C02","6C04"} + + local params = {[0]= + s1G00,s1G02,s1G04,s1G06,s1G08,s1G0B,s1G0D,s6C00,s6C02,s6C04 } + + y = Y_LINE_HEIGHT*2 + Y_HEADER + for iParam=0,#Alpha3Tags do -- ?? + -- labels + local x = X_COL1_HEADER+220 + local val = Alpha3Tags[iParam] + lcd.drawText (x, y, val, TEXT_SIZE) + + val = params[iParam] + x = X_COL1_DATA+250 + lcd.drawText (x, y, val, TEXT_SIZE) + + y = y + Y_LINE_HEIGHT + end + end +end + + +local telPage = 1 +local telPageSelected = 0 +local pageTitle = {[0]="Main", "Blade Version", "Blade Servo Adjust","Blade Gyro Adjust", "Blade AS3X Monitor", "Plane AS3X Monitor", "Flight Log"} + +local function drawMainScreen(event) + lcd.clear() + lcd.drawText (X_COL1_HEADER, Y_HEADER, "Main Telemetry TextGen (AR636)", TEXT_SIZE + INVERS) + + for iParam=1,#pageTitle do + -- highlight selected parameter + local attr = (telPage==iParam) and INVERS or 0 + + -- set y draw coord + local y = (iParam)*Y_LINE_HEIGHT+Y_DATA + + -- labels + local x = X_COL1_HEADER + local val = pageTitle[iParam] + lcd.drawText (x, y, val, attr + TEXT_SIZE) + end + + if event == EVT_VIRTUAL_PREV then + if (telPage>1) then telPage = telPage - 1 end + elseif event == EVT_VIRTUAL_NEXT then + if (telPage<#pageTitle) then telPage = telPage + 1 end + elseif event == EVT_VIRTUAL_ENTER then + telPageSelected = telPage + end +end + + +local pageDraw = {[0]=drawMainScreen, drawVersionScreen, servoAdjustScreen,drawPIDScreen, drawAlpha6Monitor, drawAS3XMonitor, drawFlightLogScreen} + +local function run_func(event) + if event == nil then + error("Cannot be run as a model script!") + return 2 + end + + if event == EVT_VIRTUAL_EXIT then + if (telPageSelected==0) then return 1 end -- on Main?? Exit Script + telPageSelected = 0 -- any page, return to Main + end + + -- draw specific page + pageDraw[telPageSelected](event) + + return 0 +end + +local function init_func() + + --if (LCD_W <= 128 or LCD_H <=64) then + -- TEXT_SIZE = SMLSIZE + -- X_COL1_HEADER = 6 + -- X_COL1_DATA = 70 + -- X_COL2_HEADER = 120 + -- X_COL2_DATA = 180 + -- Y_LINE_HEIGHT = 10 + --end +end + +return { run=run_func, init=init_func } diff --git a/Lua_scripts/MultiChan.txt b/Lua_scripts/MultiChan.txt index 95caf80..67af1b2 100644 --- a/Lua_scripts/MultiChan.txt +++ b/Lua_scripts/MultiChan.txt @@ -117,6 +117,7 @@ 71,1,JJRC345,SkyTmblr,1,Flip,HLess,RTH,LED,UNK1,UNK2,UNK3 49,0,KF606,KF606,1,Trim 49,1,KF606,MIG320,1,Trim,LED +49,2,KF606,ZCZ50,1,Trim,UNK 9,0,KN,WLToys,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim 9,1,KN,Feilun,0,DRate,THold,IdleUp,Gyro,Ttrim,Atrim,Etrim 73,0,Kyosho,Std,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14 diff --git a/Multiprotocol/FX_nrf24l01.ino b/Multiprotocol/FX_nrf24l01.ino index 512710f..3b2808e 100644 --- a/Multiprotocol/FX_nrf24l01.ino +++ b/Multiprotocol/FX_nrf24l01.ino @@ -33,7 +33,14 @@ Multiprotocol is distributed in the hope that it will be useful, #define FX620_PAYLOAD_SIZE 7 #define FX620_CH_OFFSET 1 +#define FX9630_PACKET_PERIOD 8124 +#define FX9630_BIND_PACKET_PERIOD 8124 +#define FX9630_BIND_CHANNEL 51 +#define FX9630_PAYLOAD_SIZE 8 +#define FX9630_NUM_CHANNELS 3 + //#define FORCE_FX620_ID +//#define FORCE_FX9630_ID static void __attribute__((unused)) FX_send_packet() { @@ -41,21 +48,44 @@ static void __attribute__((unused)) FX_send_packet() if(IS_BIND_DONE) { XN297_Hopping(hopping_frequency_no++); - hopping_frequency_no &= 0x03; + if(sub_protocol == FX9630) + { + XN297_SetTXAddr(rx_tx_addr, 4); + if (hopping_frequency_no > FX9630_NUM_CHANNELS) + hopping_frequency_no = 0; + } + else // FX816 and FX620 + { + hopping_frequency_no &= 0x03; + } } memset(packet,0x00,packet_length); //Channels - uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET; - uint8_t val=convert_channel_8b(AILERON); - if(val>127+FX_SWITCH) - packet[offset] = sub_protocol == FX816 ? 1:0xFF; - else if(val<127-FX_SWITCH) - packet[offset] = sub_protocol == FX816 ? 2:0x00; - else - packet[offset] = sub_protocol == FX816 ? 0:0x7F; - packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work + uint8_t val; + if (sub_protocol == FX9630) + { + packet[0] = convert_channel_8b(THROTTLE); + packet[1] = convert_channel_8b(AILERON); + packet[2] = 0xFF - convert_channel_8b(ELEVATOR); + packet[3] = convert_channel_8b(RUDDER); + packet[4] = 0x20; + packet[5] = GET_FLAG(CH5_SW, 0x01); // DR toggle swich: 0 small throw, 1 large throw + packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x00 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x02 : 0x01)) << 1; // Mode A(0) : 6D small throw, B(1) : 6D large throw, C(2) : 3D + } + else // FX816 and FX620 + { + uint8_t offset=sub_protocol == FX816 ? FX816_CH_OFFSET:FX620_CH_OFFSET; + val=convert_channel_8b(AILERON); + if(val>127+FX_SWITCH) + packet[offset] = sub_protocol == FX816 ? 1:0xFF; + else if(val<127-FX_SWITCH) + packet[offset] = sub_protocol == FX816 ? 2:0x00; + else + packet[offset] = sub_protocol == FX816 ? 0:0x7F; + packet[offset+1] = convert_channel_16b_limit(THROTTLE,0,100); //FX816:0x00..0x63, FX620:0x00..0x5E but that should work + } //Bind and specifics if(sub_protocol == FX816) @@ -67,7 +97,7 @@ static void __attribute__((unused)) FX_send_packet() packet[1] = rx_tx_addr[0]; packet[2] = rx_tx_addr[1]; } - else //FX620 + else if(sub_protocol == FX620) { if(IS_BIND_IN_PROGRESS) { @@ -82,12 +112,27 @@ static void __attribute__((unused)) FX_send_packet() packet[5] = 0xAB; // Is it based on ID?? } } + else // FX9630 + { + if(IS_BIND_IN_PROGRESS) + { + memcpy(packet,rx_tx_addr, 4); + packet[4] = hopping_frequency[1]; + packet[5] = hopping_frequency[2]; + packet[7] = 0x55; + } + } //Check + uint8_t last_packet_idx = packet_length-1; + if (sub_protocol == FX9630 && IS_BIND_IN_PROGRESS) + last_packet_idx--; val=0; - for(uint8_t i=0;i>3; // Drive trims for more aileron authority - if(packet[3] > 0x80) - packet[3] = 0x01; - else if(packet[3] > 0x1F) - packet[3] = 0x1F; - packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature + case KF606_KF606: + packet[2] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1 + packet[3] = convert_channel_16b_limit(CH5,0xC1,0xDF); // Aileron trim must be on a separated channel C1..D0..DF + break; + case KF606_MIG320: + packet[2] = convert_channel_8b_limit_deadband(AILERON,0x00,0x80,0xFF,40); // Aileron: High rate:2B..80..DA + packet[3] = convert_channel_16b_limit(CH5,0x01,0x1F); // Aileron trim must be on a separated channel 01..10..1F + packet[3] += (packet[2]-0x80)>>3; // Drive trims for more aileron authority + if(packet[3] > 0x80) + packet[3] = 0x01; + else if(packet[3] > 0x1F) + packet[3] = 0x1F; + packet[3] |= GET_FLAG(CH6_SW, 0xC0); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature + break; + case KF606_ZCZ50: + len--; // uses only 3 bytes of payload + packet[0] = packet[1]; // Throttle: 0x00..0xFF + packet[1] = convert_channel_8b_limit_deadband(AILERON,0x20,0x80,0xE0,40); // Aileron: Max values:20..80..E0, low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3. + packet[2] = convert_channel_16b_limit(CH5,0x01,0x1F); // Trim: 0x01..0x10..0x1F + packet[2] |= GET_FLAG(CH6_SW, 0xC0); // Unknown: 0x00 or 0xC0. Left top switch on original TX changes nothing on my plane. Maybe ON/OFF for main motor? + break; } } - uint8_t len = KF606_PAYLOAD_SIZE; if(sub_protocol == KF606_MIG320) { len++; @@ -107,6 +121,19 @@ static void __attribute__((unused)) KF606_initialize_txid() hopping_frequency[0]=68; hopping_frequency[1]=71; #endif + if(sub_protocol == KF606_ZCZ50) + { + rx_tx_addr[1] = rx_tx_addr[0]; + rx_tx_addr[0]=0xAA; + } + #ifdef FORCE_ZCZ50_ORIGINAL_ID + rx_tx_addr[0]=0xAA; + rx_tx_addr[1]=0x67; + rx_tx_addr[2]=0x64; + rx_tx_addr[3]=0x01; + hopping_frequency[0]=48; + hopping_frequency[1]=51; + #endif } static void __attribute__((unused)) KF606_RF_init() @@ -126,7 +153,7 @@ uint16_t KF606_callback() if(--bind_counter==0) { BIND_DONE; - XN297_SetTXAddr(rx_tx_addr, 3); + XN297_SetTXAddr(rx_tx_addr, sub_protocol != KF606_ZCZ50 ? 3 : 4); } KF606_send_packet(); return KF606_PACKET_PERIOD; @@ -153,3 +180,14 @@ void KF606_init() // P[2] = AIL 2B..80..DA // P[3] = TRIM 01..10..1F // channels 68=BB&3F+9 and 71 + + +// ZCZ50v2 protocol (with fake front propeller) +// Bind +// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(4)= AA 67 64 01 +// 3ms on ch7 +// Normal +// 250K C=48 S=Y A= AA 67 64 01 P(3)= 00 80 10 +// P[0] = THR 0x00..0xFF +// P[1] = AIL low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3 +// P[2] = TRIM 0x01..0x10..0x1F + UNKNOWN 0x00 or 0xC0 diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index a547ce5..848677c 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -46,7 +46,7 @@ 46,V911S,V911S,E119 47,GD00x,GD_V1,GD_V2 48,V761,3CH,4CH,TOPRC -49,KF606,KF606,MIG320 +49,KF606,KF606,MIG320,ZCZ50 50,Redpine,Fast,Slow 51,Potensic,A20 52,ZSX,280 @@ -55,7 +55,7 @@ 55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM 56,AFHDS2A_RX,Multi,CPPM 57,HoTT,Sync,No_Sync -58,FX,816,620 +58,FX,816,620,9630 59,Bayang_RX,Multi,CPPM 60,Pelikan,Pro,Lite,SCX24 61,Tiger diff --git a/Multiprotocol/Multi_Protos.ino b/Multiprotocol/Multi_Protos.ino index 9097782..daa3c87 100644 --- a/Multiprotocol/Multi_Protos.ino +++ b/Multiprotocol/Multi_Protos.ino @@ -171,9 +171,9 @@ const char STR_SUBTYPE_KYOSHO2[] = "\x05""KT-17"; const char STR_SUBTYPE_FUTABA[] = "\x05""SFHSS"; const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr"; const char STR_SUBTYPE_MOULKG[] = "\x06""Analog""Digit\0"; -const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320"; +const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0"; const char STR_SUBTYPE_E129[] = "\x04""E129""C186"; -const char STR_SUBTYPE_FX[] = "\x03""816""620"; +const char STR_SUBTYPE_FX[] = "\x04""816\0""620\0""9630"; #define NO_SUBTYPE nullptr #ifdef SEND_CPPM @@ -315,7 +315,7 @@ const mm_protocol_definition multi_protocols[] = { {PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback }, #endif #if defined(FX_NRF24L01_INO) - {PROTO_FX, STR_FX, STR_SUBTYPE_FX, 2, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback }, + {PROTO_FX, STR_FX, STR_SUBTYPE_FX, 3, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback }, #endif #if defined(FY326_NRF24L01_INO) {PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback }, @@ -360,7 +360,7 @@ const mm_protocol_definition multi_protocols[] = { {PROTO_JOYSWAY, STR_JOYSWAY, NO_SUBTYPE, 0, OPTION_NONE, 0, 0, SW_A7105, JOYSWAY_init, JOYSWAY_callback }, #endif #if defined(KF606_CCNRF_INO) - {PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 2, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback }, + {PROTO_KF606, STR_KF606, STR_SUBTYPE_KF606, 3, OPTION_RFTUNE, 0, 0, SW_NRF, KF606_init, KF606_callback }, #endif #if defined(KN_NRF24L01_INO) {PROTO_KN, STR_KN, STR_SUBTYPE_KN, 2, OPTION_NONE, 0, 0, SW_NRF, KN_init, KN_callback }, diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index d866fd0..939e7b4 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 3 #define VERSION_REVISION 3 -#define VERSION_PATCH_LEVEL 24 +#define VERSION_PATCH_LEVEL 25 #define MODE_SERIAL 0 @@ -450,6 +450,7 @@ enum KF606 { KF606_KF606 = 0, KF606_MIG320 = 1, + KF606_ZCZ50 = 2, }; enum E129 { @@ -460,6 +461,7 @@ enum FX { FX816 = 0, FX620 = 1, + FX9630 = 2, }; #define NONE 0 diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index c64a023..60e5d97 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -670,6 +670,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { PROTO_FX FX816 FX620 + FX9630 PROTO_FY326 FY326 FY319 @@ -717,6 +718,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { PROTO_KF606 KF606_KF606 KF606_MIG320 + KF606_ZCZ50 PROTO_KN WLTOYS FEILUN diff --git a/Protocols_Details.md b/Protocols_Details.md index 3608aee..29659aa 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -110,7 +110,7 @@ CFlie|38|CFlie||||||||NRF24L01| [J6Pro](Protocols_Details.md#J6Pro---22)|22|||||||||CYRF6936| [JJRC345](Protocols_Details.md#JJRC345---71)|71|JJRC345|SkyTmblr|||||||NRF24L01|XN297 [JOYSWAY](Protocols_Details.md#JOYSWAY---84)|84|||||||||NRF24L01|XN297 -[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|||||||NRF24L01|XN297 +[KF606](Protocols_Details.md#KF606---49)|49|KF606|MIG320|ZCZ50||||||NRF24L01|XN297 [KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01| [Kyosho](Protocols_Details.md#Kyosho---73)|73|FHSS|Hype|||||||A7105| [Kyosho2](Protocols_Details.md#Kyosho2---93)|93|KT-17||||||||NRF24L01| @@ -1049,6 +1049,15 @@ CH1|CH2|CH3|CH4|CH5|CH6 ---|---|---|---|---|--- A||T||TRIM|LED +### Sub_protocol ZCZ50v2 - *2* +Model: ZC-Z50 Cessna + +This might be newer version of the model. My plane does not have front propeller, but its just fake anyway (no motor in the front). + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A||T||TRIM|UNKNOWN + ## MJXQ - *18* Autobind protocol