#include <LiquidCrystal.h>
#include <TimerOne.h>
+#define MAX_INPUTS 8
+
// --------------- ADC related stuffs.... --------------------
-int maxval[8]; // Stores maximum values read during calibration, setup() sets 1024
-int minval[8]; // Stores minimum values read during calibration, setup() sets 0
-int rev[8];
-int dr[8]; // The Dual-rate array uses magic numbers :P
-/* dr[0] = Input channel #1 of 2 for D/R switch #1. 0 means off, 1-4 valid values.
- dr[1] = Input channel #2 of 2 for D/R switch #1. 0 means off, 1-4 valid values.
- dr[2] = Input channel #1 of 2 for D/R switch #2. 0 means off, 1-4 valid values.
- dr[3] = Input channel #2 of 2 for D/R switch #2. 0 means off, 1-4 valid values.
- dr[4] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5.
- dr[5] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5.
- dr[6] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5.
- dr[7] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5.
-*/
-
-volatile float channel[8];
+struct input_cal_t // Struct type for input calibration values
+{
+ int min[MAX_INPUTS];
+ int max[MAX_INPUTS];
+ int center[MAX_INPUTS];
+} ;
+input_cal_t input_cal;
+
+struct model_t
+{
+ int channels; // How many channels should PPM generate for this model ...
+ float stick[8]; // The (potentially recalc'ed) value of stick/input channel.
+ boolean rev[8];
+ int dr[8]; // The Dual-rate array uses magic numbers :P
+ /* dr[0] = Input channel #1 of 2 for D/R switch #1. 0 means off, 1-4 valid values.
+ dr[1] = Input channel #2 of 2 for D/R switch #1. 0 means off, 1-4 valid values.
+ dr[2] = Input channel #1 of 2 for D/R switch #2. 0 means off, 1-4 valid values.
+ dr[3] = Input channel #2 of 2 for D/R switch #2. 0 means off, 1-4 valid values.
+ dr[4] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5.
+ dr[5] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5.
+ dr[6] = D/R value for switch # 1 LOW(off). Value -100 to 100 in steps of 5.
+ dr[7] = D/R value for switch # 1 HIGH(on). Value -100 to 100 in steps of 5.
+ */
+};
+volatile model_t model;
// ----------------- Display related stuffs --------------------
LiquidCrystal lcd( 12, 11, 10, 6, 7, 8, 9);
// ----------------- PPM related stuffs ------------------------
// The PPM generation is handled by Timer0 interrupts, and needs
// all modifiable variables to be global and volatile...
-int max_channels = 6; // How many channels should PPM generate ...
+
+//int max_channels = 6; // How many channels should PPM generate ...
+// Moved to model_t struct...
+
volatile long sum = 0; // Frame-time spent so far
volatile int cchannel = 0; // Current channnel
volatile bool do_channel = true; // Is next operation a channel or a separator
+
// All time values in usecs
// TODO:
// The timing here (and/or in the ISR) needs to be tweaked to provide valid
// RC PPM signals accepted by standard RC RX'es and the Microcopter...
-long framelength = 21500; // Max length of frame
-long seplength = 400; // Lenght of a channel separator
-long chmax = 1700; // Max lenght of channel pulse
-long chmin = 600; // Min length of channel
-long chwidht = (chmax - chmin); // Useable time of channel pulse (1000)
+
+#define framelength 21500 // Max length of frame
+#define seplength 400 // Lenght of a channel separator
+#define chmax 1700 // Max lenght of channel pulse
+#define chmin 600 // Min length of channel
+#define chwidht (chmax - chmin)// Useable time of channel pulse
// ----------------- Menu/IU related stuffs --------------------
#define UI_INTERVAL 250
unsigned long last = 0;
-unsigned long timer_start = 0;
-unsigned long timer_init = 0;
-unsigned long timer_value = 0;
-boolean timer_running = false;
+struct clock_timer_t
+{
+ unsigned long start;
+ unsigned long init;
+ unsigned long value;
+ boolean running;
+} clock_timer;
// ----------------- DEBUG-STUFF --------------------
unsigned long prev_loop_time;
t = micros();
avg_loop_time = t;
prev_loop_time = t;
-
- dr[0] = dr[1] = dr[2] = dr[3] = 0;
- dr[4] = dr[5] = dr[6] = dr[7] = 100;
+ // Setting this here to be sure I do not forget to init' it....
+ // These initializations should be done by read_settings from eeprom,
+ // and this "default model values" should probably be moved
+ // out to a section of read_settings when handling "new model", or
+ // to a separate model_defaults function...
+ model.channels = 8;
+ model.rev[0] = model.rev[1] = model.rev[2] = model.rev[3] =
+ model.rev[4] = model.rev[5] = model.rev[6] = model.rev[7] = false;
+ model.dr[0] = model.dr[1] = model.dr[2] = model.dr[3] = 0;
+ model.dr[4] = model.dr[5] = model.dr[6] = model.dr[7] = 100;
+
+ // Initializing the stopwatch timer/clock values...
+ clock_timer = (clock_timer_t){0, 0, 0, false};
}
// ---------- Arduino main loop -----------------------
lcd.print("their extremes..");
Serial.print("Calibration. Move all controls to their extremes.");
- for (i=0; i<=7; i++) {
- minval[i] = 1024;
- maxval[i] = 0;
+ for (i=0; i< MAX_INPUTS; i++) {
+ input_cal.min[i] = 1024;
+ input_cal.max[i] = 0;
}
while ( calcount <= num_calibrations )
{
- for (i=0; i<=7; i++) {
+ for (i=0; i<=MAX_INPUTS; i++) {
mplx_select(i);
adc_in = analogRead(0);
// Naive min/max calibration
- if ( adc_in < minval[i] ) {
- minval[i] = adc_in;
+ if ( adc_in < input_cal.min[i] ) {
+ input_cal.min[i] = adc_in;
}
- if ( adc_in > maxval[i] ) {
- maxval[i] = adc_in;
+ if ( adc_in > input_cal.max[i] ) {
+ input_cal.max[i] = adc_in;
}
delay(10);
}
{
// Dummy. Will be modified to read model settings from EEPROM
for (int i=0; i<=7; i++) {
- minval[i] = 0;
- maxval[i] = 1024;
+ input_cal.min[i] = 0;
+ input_cal.center[i] = 512;
+ input_cal.max[i] = 1024;
}
}
mplx_select(current_input);
adc_in = analogRead(0);
- channel[current_input] = ((float)adc_in - (float)minval[current_input]) / (float)(maxval[current_input]-minval[current_input]);
- if ( rev[current_input] ) channel[current_input] = 1.0f - channel[current_input];
+ model.stick[current_input] = ((float)adc_in - (float)input_cal.min[current_input]) / (float)(input_cal.max[current_input]-input_cal.min[current_input]);
+ if ( model.rev[current_input] ) model.stick[current_input] = 1.0f - model.stick[current_input];
}
}
return;
}
- if ( cchannel >= max_channels )
+ if ( cchannel >= model.channels )
{
set_ppm_output( HIGH );
long framesep = framelength - sum;
if ( do_channel )
{
set_ppm_output( HIGH );
- long next_timer = (( chwidht * channel[cchannel] ) + chmin);
+ long next_timer = (( chwidht * model.stick[cchannel] ) + chmin);
// Do sanity-check of next_timer compared to chmax ...
while ( chmax < next_timer ) next_timer--;
sum += next_timer;
{
int current_input;
for (current_input=0; current_input<=7; current_input++) {
- int v = (int)(channel[current_input] * 100);
+ int v = (int)(model.stick[current_input] * 100);
Serial.print("Input #");
Serial.print(current_input);
Serial.print(" value: ");
- Serial.print(channel[current_input]);
+ Serial.print(model.stick[current_input]);
Serial.print(" pct: ");
Serial.print(v);
Serial.print(" min: ");
- Serial.print(minval[current_input]);
+ Serial.print(input_cal.min[current_input]);
Serial.print(" max: ");
- Serial.print(maxval[current_input]);
+ Serial.print(input_cal.max[current_input]);
Serial.println();
}
Serial.print("Battery level is: ");
}
void dr_inputselect( int no, int in )
{
- if ( dr[menu_substate] < 0 ) dr[menu_substate] = 4;
- if ( dr[menu_substate] > 4 ) dr[menu_substate] = 0;
+ if ( model.dr[menu_substate] < 0 ) model.dr[menu_substate] = 4;
+ if ( model.dr[menu_substate] > 4 ) model.dr[menu_substate] = 0;
lcd.setCursor(0 , 0);
lcd.print("D/R switch ");
lcd.print(in+1);
lcd.print(": ");
- if ( ! dr[menu_substate] ) lcd.print("Off");
- else lcd.print(dr[menu_substate]);
+ if ( ! model.dr[menu_substate] ) lcd.print("Off");
+ else lcd.print(model.dr[menu_substate]);
if ( check_key(KEY_INC) ) {
- dr[menu_substate]++;
+ model.dr[menu_substate]++;
return;
}
else if ( check_key(KEY_DEC) ) {
- dr[menu_substate]--;
+ model.dr[menu_substate]--;
return;
}
// Wrap around.
lcd.print( state ? "HI" : "LO" );
lcd.print(" Value :");
- lcd.print( dr[pos] );
+ lcd.print( model.dr[pos] );
if ( keys[KEY_INC] ) {
- if ( dr[pos] < 100) dr[pos] += 5;
+ if ( model.dr[pos] < 100) model.dr[pos] += 5;
return;
}
else if ( keys[KEY_DEC] ) {
- if ( dr[pos] > -100) dr[pos] -= 5;
+ if ( model.dr[pos] > -100) model.dr[pos] -= 5;
return;
}
lcd.print(" ");
lcd.setCursor(col, row);
// Display uses percents, while PPM uses ratio....
- int v = (int)(channel[current_input] * 100);
+ int v = (int)(model.stick[current_input] * 100);
lcd.print(v);
}
break;
lcd.clear();
lcd.print("Timer: ");
- lcd.print( timer_running ? "Running" : "Stopped" );
+ lcd.print( clock_timer.running ? "Running" : "Stopped" );
lcd.setCursor(5 , 1);
- if ( timer_running )
+ if ( clock_timer.running )
{
- timer_value = millis() - (timer_start + timer_init);
+ clock_timer.value = millis() - (clock_timer.start + clock_timer.init);
}
- hours = ( timer_value / 1000 ) / 3600;
- timer_value = timer_value % 3600000;
- minutes = ( timer_value / 1000 ) / 60;
- seconds = ( timer_value / 1000 ) % 60;
+ hours = ( clock_timer.value / 1000 ) / 3600;
+ clock_timer.value = clock_timer.value % 3600000;
+ minutes = ( clock_timer.value / 1000 ) / 60;
+ seconds = ( clock_timer.value / 1000 ) % 60;
if ( hours ) {
lcd.print(hours);
lcd.print(":");
lcd.print( seconds );
if ( check_key(KEY_INC) ) {
- if ( !timer_running && !timer_start )
+ if ( !clock_timer.running && !clock_timer.start )
{
- timer_start = millis();
- timer_value = 0;
- timer_running = true;
- } else if ( !timer_running && timer_start ) {
- timer_start = millis() - timer_value;
- timer_running = true;
- } else if ( timer_running ) {
- timer_running = false;
+ clock_timer.start = millis();
+ clock_timer.value = 0;
+ clock_timer.running = true;
+ } else if ( !clock_timer.running && clock_timer.start ) {
+ clock_timer.start = millis() - clock_timer.value;
+ clock_timer.running = true;
+ } else if ( clock_timer.running ) {
+ clock_timer.running = false;
}
return;
} else if ( check_key(KEY_DEC) ) {
- if ( !timer_running && timer_start ) {
- timer_value = 0;
- timer_start = 0;
- timer_init = 0;
+ if ( !clock_timer.running && clock_timer.start ) {
+ clock_timer.value = 0;
+ clock_timer.start = 0;
+ clock_timer.init = 0;
}
return;
}
case INVERTS:
- if ( menu_substate >= max_channels ) menu_substate = 0;
- if ( menu_substate < 0) menu_substate = (max_channels - 1);
+ if ( menu_substate >= model.channels ) menu_substate = 0;
+ if ( menu_substate < 0) menu_substate = (model.channels - 1);
lcd.print("Channel invert");
lcd.setCursor(0 , 1);
lcd.print("Ch ");
lcd.print(menu_substate+1);
- lcd.print( (rev[menu_substate] ? ": Invert" : ": Normal"));
+ lcd.print( (model.rev[menu_substate] ? ": Invert" : ": Normal"));
if ( check_key(KEY_UP) ) {
menu_mainstate = TOP;
return;
}
else if ( check_key(KEY_INC) || check_key(KEY_DEC) ) {
- rev[menu_substate] ^= 1;
+ model.rev[menu_substate] ^= 1;
return;
}
break;