diff --git a/radio/wizard/multi-pitch.bmp b/radio/wizard/multi-pitch.bmp new file mode 100644 index 000000000..5ec154330 Binary files /dev/null and b/radio/wizard/multi-pitch.bmp differ diff --git a/radio/wizard/multi-roll.bmp b/radio/wizard/multi-roll.bmp new file mode 100644 index 000000000..6d033dddb Binary files /dev/null and b/radio/wizard/multi-roll.bmp differ diff --git a/radio/wizard/multi-thr.bmp b/radio/wizard/multi-thr.bmp new file mode 100644 index 000000000..6547592d6 Binary files /dev/null and b/radio/wizard/multi-thr.bmp differ diff --git a/radio/wizard/multi-yaw.bmp b/radio/wizard/multi-yaw.bmp new file mode 100644 index 000000000..91978cd0f Binary files /dev/null and b/radio/wizard/multi-yaw.bmp differ diff --git a/radio/wizard/multi.lua b/radio/wizard/multi.lua new file mode 100755 index 000000000..176ef8297 --- /dev/null +++ b/radio/wizard/multi.lua @@ -0,0 +1,306 @@ +-- Multicopter Wizard pages +local THROTTLE_PAGE = 0 +local ROLL_PAGE = 1 +local PITCH_PAGE = 2 +local YAW_PAGE = 3 +local CONFIRMATION_PAGE = 4 + +-- Navigation variables +local page = THROTTLE_PAGE +local dirty = true +local edit = false +local field = 0 +local fieldsMax = 0 +local comboBoxMode = 0 -- Scrap variable + +-- Model settings +local thrCH1 = 0 +local rollCH1 = 0 +local yawCH1 = 0 +local pitchCH1 = 0 + +-- Common functions +local lastBlink = 0 +local function blinkChanged() + local time = getTime() % 128 + local blink = (time - time % 64) / 64 + if blink ~= lastBlink then + lastBlink = blink + return true + else + return false + end +end + +local function fieldIncDec(event, value, max, force) + if edit or force==true then + if event == EVT_PLUS_BREAK then + value = (value + max) + dirty = true + elseif event == EVT_MINUS_BREAK then + value = (value + max + 2) + dirty = true + end + value = (value % (max+1)) + end + return value +end + +local function valueIncDec(event, value, min, max) + if edit then + if event == EVT_PLUS_FIRST or event == EVT_PLUS_REPT then + if value < max then + value = (value + 1) + dirty = true + end + elseif event == EVT_MINUS_FIRST or event == EVT_MINUS_REPT then + if value > min then + value = (value - 1) + dirty = true + end + end + end + return value +end + +local function navigate(event, fieldMax, prevPage, nextPage) + if event == EVT_ENTER_BREAK then + edit = not edit + dirty = true + elseif edit then + if event == EVT_EXIT_BREAK then + edit = false + dirty = true + elseif not dirty then + dirty = blinkChanged() + end + else + if event == EVT_PAGE_BREAK then + page = nextPage + field = 0 + dirty = true + elseif event == EVT_PAGE_LONG then + page = prevPage + field = 0 + killEvents(event); + dirty = true + else + field = fieldIncDec(event, field, fieldMax, true) + end + end +end + +local function getFieldFlags(position) + flags = 0 + if field == position then + flags = INVERS + if edit then + flags = INVERS + BLINK + end + end + return flags +end + +local function channelIncDec(event, value) + if not edit and event==EVT_MENU_BREAK then + servoPage = value + dirty = true + else + value = valueIncDec(event, value, 0, 15) + end + return value +end + +-- Init function +local function init() + thrCH1 = defaultChannel(2) + rollCH1 = defaultChannel(3) + yawCH1 = defaultChannel(0) + pitchCH1 = defaultChannel(1) +end + +-- Throttle Menu +local function drawThrottleMenu() + lcd.clear() + lcd.drawText(1, 0, "Select multicopter throttle channel", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1)) + lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H, DOTTED, 0) + lcd.drawPixmap(132, 18, "multi-thr.bmp") + lcd.drawText(20, LCD_H-16, "Assign Throttle", 0); + lcd.drawText(20, LCD_H-8, "Channel", 0); + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+thrCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function throttleMenu(event) + if dirty then + dirty = false + drawThrottleMenu() + end + navigate(event, fieldsMax, page, page+1) + thrCH1 = channelIncDec(event, thrCH1) +end + +-- Roll Menu +local function drawRollMenu() + lcd.clear() + lcd.drawText(1, 0, "Select multicopter roll channel", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1)) + lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H, DOTTED, 0) + lcd.drawPixmap(132, 18, "multi-roll.bmp") + lcd.drawText(20, LCD_H-16, "Assign Roll", 0); + lcd.drawText(20, LCD_H-8, "Channel", 0); + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+rollCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function rollMenu(event) + if dirty then + dirty = false + drawRollMenu() + end + navigate(event, fieldsMax, page-1, page+1) + rollCH1 = channelIncDec(event, rollCH1) +end + +-- Pitch Menu +local function drawPitchMenu() + lcd.clear() + lcd.drawText(1, 0, "Select multicopter pitch channel", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1)) + lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H, DOTTED, 0) + lcd.drawPixmap(132, 18, "multi-pitch.bmp") + lcd.drawText(20, LCD_H-16, "Assign Pitch", 0); + lcd.drawText(20, LCD_H-8, "Channel", 0); + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+pitchCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function pitchMenu(event) + if dirty then + dirty = false + drawPitchMenu() + end + navigate(event, fieldsMax, page-1, page+1) + pitchCH1 = channelIncDec(event, pitchCH1) +end + +-- Yaw Menu +local function drawYawMenu() + lcd.clear() + lcd.drawText(1, 0, "Select multicopter yaw channel", 0) + lcd.drawFilledRectangle(0, 0, LCD_W, 8, GREY_DEFAULT+FILL_WHITE) + lcd.drawCombobox(0, 8, LCD_W/2, {"..."}, comboBoxMode, getFieldFlags(1)) + lcd.drawLine(LCD_W/2-1, 18, LCD_W/2-1, LCD_H, DOTTED, 0) + lcd.drawPixmap(132, 18, "multi-yaw.bmp") + lcd.drawText(20, LCD_H-16, "Assign Yaw", 0); + lcd.drawText(20, LCD_H-8, "Channel", 0); + lcd.drawText(LCD_W/2-19, LCD_H-8, ">>>", 0); + lcd.drawSource(113, LCD_H-8, MIXSRC_CH1+yawCH1, getFieldFlags(0)) + fieldsMax = 0 +end + +local function yawMenu(event) + if dirty then + dirty = false + drawYawMenu() + end + navigate(event, fieldsMax, page-1, page+1) + yawCH1 = channelIncDec(event, yawCH1) +end + +-- Confirmation Menu +local function drawNextLine(x, y, label, channel) + lcd.drawText(x, y, label, 0); + lcd.drawSource(x+52, y, MIXSRC_CH1+channel, 0) + y = y + 8 + if y > 50 then + y = 12 + x = 120 + end + return x, y +end + +local function drawConfirmationMenu() + local x = 22 + local y = 12 + lcd.clear() + lcd.drawText(48, 1, "Ready to go?", 0); + lcd.drawFilledRectangle(0, 0, LCD_W, 9, 0) + x, y = drawNextLine(x, y, "Throttle:", thrCH1) + x, y = drawNextLine(x, y, "Roll:", rollCH1) + x, y = drawNextLine(x, y, "Pitch:", pitchCH1) + x, y = drawNextLine(x, y, "Yaw:", yawCH1) + lcd.drawText(48, LCD_H-8, "[Enter Long] to confirm", 0); + lcd.drawFilledRectangle(0, LCD_H-9, LCD_W, 9, 0) + lcd.drawPixmap(LCD_W-18, 0, "confirm-tick.bmp") + lcd.drawPixmap(0, LCD_H-17, "confirm-plane.bmp") + fieldsMax = 0 +end + +local function addMix(channel, input, name, weight, index) + local mix = { source=input, name=name } + if weight ~= nil then + mix.weight = weight + end + if index == nil then + index = 0 + end + model.insertMix(channel, index, mix) +end + +local function applySettings() + model.defaultInputs() + model.deleteMixes() + addMix(thrCH1, MIXSRC_FIRST_INPUT+defaultChannel(2), "Throttle") + addMix(rollCH1, MIXSRC_FIRST_INPUT+defaultChannel(3), "Roll") + addMix(yawCH1, MIXSRC_FIRST_INPUT+defaultChannel(0), "Yaw") + addMix(pitchCH1, MIXSRC_FIRST_INPUT+defaultChannel(1), "Pitch") +end + +local function confirmationMenu(event) + if dirty then + dirty = false + drawConfirmationMenu() + end + + navigate(event, fieldsMax, YAW_PAGE, page) + + if event == EVT_EXIT_BREAK then + return 2 + elseif event == EVT_ENTER_LONG then + killEvents(event) + applySettings() + return 2 + else + return 0 + end +end + +-- Main +local function run(event) + if event == nil then + error("Cannot be run as a model script!") + end + lcd.lock() + if page == THROTTLE_PAGE then + throttleMenu(event) + elseif page == ROLL_PAGE then + rollMenu(event) + elseif page == YAW_PAGE then + yawMenu(event) + elseif page == PITCH_PAGE then + pitchMenu(event) + elseif page == CONFIRMATION_PAGE then + return confirmationMenu(event) + end + return 0 +end + +return { init=init, run=run } diff --git a/radio/wizard/wizard.lua b/radio/wizard/wizard.lua index 3d6345134..22ac3db46 100755 --- a/radio/wizard/wizard.lua +++ b/radio/wizard/wizard.lua @@ -50,6 +50,7 @@ local function modelTypeMenu(event) elseif modelType == MODELTYPE_DELTA then return "delta.lua" elseif modelType == MODELTYPE_QUAD then + return "multi.lua" end dirty = true else