#pragma config(Sensor, S1, LLEADER, sensorI2CCustom9V)
#define MSLL_I2C_ADDR 0x02
#include "drivers/mindsensors-lineleader.h"
#define printXY nxtDisplayStringAt
#define println nxtDisplayTextLine
#define clearln nxtDisplayClearTextLine
#define DEFAULT_KP 5
#define DEFAULT_KI 0
#define DEFAULT_KD 30
#define DEFAULT_SP 50
#define LOGFILE "linelead.dat"
#define MENUITEMS 5
void doMainMenu();
void doMenuItem(int activeOption);
bool checkTimer(TTimers timer);
void doLineLead();
void writeParams();
string menuHeader;
string menuFooter;
const TTimers rightButtonTimer = T1;
const TTimers leftButtonTimer = T2;
const TTimers enterButtonTimer = T3;
int activeOption = 0;
int keep_running = 0;
byte sensor = 0;
const int default_params[4] = {
DEFAULT_KP,
DEFAULT_KI,
DEFAULT_KD,
DEFAULT_SP };
int params[4];
const string optionMainMenu[5] = {
"Kp",
"Ki",
"Kd",
"Sp",
"Run" };
const string optionMainMenuFooter[5] = {
"Ent=Edit",
"Ent=Edit",
"Ent=Edit",
"Ent=Edit",
"Ent=Run" };
tByteArray signalstr;
task drawSensors() {
while (keep_running == 1) {
nxtEraseRect(6,62, 91, 43);
for (int i = 0; i < 8; i++) {
nxtDrawRect(6+(i*11),62, 14+(i*11), 50);
nxtFillRect(6+(i*11),51+signalstr[i]/10, 14+(i*11), 50);
if ((sensor >> i) & 1) {
nxtFillRect(6+(i*11),48, 14+(i*11), 43);
} else {
nxtDrawRect(6+(i*11),48, 14+(i*11), 43);
}
}
wait1Msec(100);
}
}
task followTheYellowBrickRoad () {
int powerA = 0;
int powerC = 0;
byte steering = 0;
eraseDisplay();
nxtDisplayCenteredTextLine(3, "Running...");
nxtDisplayCenteredTextLine(5, "Press exit");
nxtDisplayCenteredTextLine(6, "to stop");
time1[T4] = 0;
while (keep_running == 1) {
steering = LLreadSteering(LLEADER);
sensor = LLreadResult(LLEADER);
LLreadSensorRaw(LLEADER, signalstr);
powerA = (params[3] + steering);
powerC = (params[3] - steering);
powerA = clip(powerA, -100, 100);
powerC = clip(powerC, -100, 100);
motor[motorA] = (byte)powerA;
motor[motorC] = (byte)powerC;
wait1Msec(1);
if (sensor != 0xFF) {
time1[T4] = 0;
} else if (time1[T4] > 500) {
keep_running = 0;
}
}
motor[motorA] = 0;
motor[motorC] = 0;
}
task redrawMenu() {
while(true) {
eraseDisplay();
println(0, menuHeader);
for (int i = 0; i < MENUITEMS; i++) {
clearln(i + 1);
if (i == activeOption) {
if (i < 4)
println(i + 1, "> %s [%3d] <", optionMainMenu[i], params[i]);
else
println(i + 1, "> %s <", optionMainMenu[i]);
println(7, menuFooter);
} else {
if (i < 4)
println(i + 1, " %s [%3d]", optionMainMenu[i], params[i]);
else
println(i + 1, " %s", optionMainMenu[i]);
}
}
wait1Msec(100);
}
}
task main () {
memcpy(params, default_params, sizeof(default_params));
writeParams();
nNxtButtonTask = -2;
nNxtExitClicks = 3;
StartTask(redrawMenu);
doMainMenu();
while(true)
wait1Msec(100);
}
void doMainMenu () {
while (true) {
menuHeader = "L/R to select";
menuFooter = optionMainMenuFooter[activeOption];
switch(nNxtButtonPressed) {
case kRightButton:
if (!checkTimer(rightButtonTimer)) {
break;
}
if (activeOption == (MENUITEMS - 1))
activeOption = 0;
else
activeOption++;
menuFooter = optionMainMenuFooter[activeOption];
wait1Msec(300);
break;
case kLeftButton:
if (!checkTimer(leftButtonTimer)) {
break;
}
if (activeOption == 0)
activeOption = (MENUITEMS - 1);
else
activeOption--;
menuFooter = optionMainMenuFooter[activeOption];
wait1Msec(300);
break;
case kEnterButton:
if (!checkTimer(rightButtonTimer)) {
break;
}
wait1Msec(600);
doMenuItem(activeOption);
break;
case kExitButton:
wait1Msec(500);
StopAllTasks();
}
}
}
void doMenuItem(int activeOption) {
PlaySound(soundBlip);
while(bSoundActive) EndTimeSlice();
if (activeOption == 4) {
doLineLead();
return;
}
while (true) {
menuHeader = "L/R to edit val";
menuFooter = "Ent=Save/Exit=Def";
switch(nNxtButtonPressed) {
case kRightButton:
if (!checkTimer(rightButtonTimer)) {
break;
}
if (params[activeOption] < 128)
params[activeOption]++;
break;
case kLeftButton:
if (!checkTimer(leftButtonTimer)) {
break;
}
if (params[activeOption] > 0)
params[activeOption]--;
break;
case kEnterButton:
if (!checkTimer(enterButtonTimer)) {
break;
}
writeParams();
wait1Msec(600);
return;
break;
case kExitButton:
params[activeOption] = default_params[activeOption];
writeParams();
wait1Msec(600);
break;
}
}
}
bool checkTimer(TTimers timer) {
if (time1[timer] < 300) {
return false;
} else {
time1[timer] = 0;
return true;
}
}
void doLineLead() {
sensor = 0;
StopTask(redrawMenu);
keep_running = 1;
for (int i = 0; i < 5; i++) {
PlaySound(soundBlip);
wait1Msec(600);
}
PlaySound(soundFastUpwardTones);
while(bSoundActive) EndTimeSlice();
StartTask(drawSensors);
StartTask(followTheYellowBrickRoad);
while(nNxtButtonPressed != kExitButton && keep_running != 0) {
wait1Msec(10);
}
keep_running = 0;
wait1Msec(1000);
StartTask(redrawMenu);
}
void writeParams() {
LLsetKp(LLEADER, params[0], 32);
LLsetKi(LLEADER, params[1], 32);
LLsetKd(LLEADER, params[2], 32);
}