#endif
enum {
- VALUES,
- BATTERY,
- TIMER,
- CURMODEL,
- MENU
+ VALUES,
+ BATTERY,
+ TIMER,
+ CURMODEL,
+ MENU
}
displaystate;
enum {
- TOP,
- INVERTS,
- DUALRATES,
- EXPOS, // Some radios have "drawn curves", i.e. loopup tables stored in external EEPROM ...
- DEBUG_DUMP,
- SAVE
+ TOP,
+ INVERTS,
+ DUALRATES,
+ EXPOS, // Some radios have "drawn curves", i.e. loopup tables stored in external EEPROM ...
+ DEBUG_DUMP,
+ SAVE
}
menu_mainstate;
int menu_substate;
// ---------- Arduino SETUP code ----------------------
void setup(){
- pinMode(13, OUTPUT); // led
+ pinMode(13, OUTPUT); // led
- pinMode(2, OUTPUT); // s0
- pinMode(3, OUTPUT); // s1
- pinMode(4, OUTPUT); // s2
- pinMode(5, OUTPUT); // e
+ pinMode(2, OUTPUT); // s0
+ pinMode(3, OUTPUT); // s1
+ pinMode(4, OUTPUT); // s2
+ pinMode(5, OUTPUT); // e
- lcd.begin(84, 48);
- lcd.print("Starting....");
+ lcd.begin(84, 48);
+ lcd.print("Starting....");
#ifdef DEBUG
- Serial.begin(9600);
- Serial.println("Starting....");
+ Serial.begin(9600);
+ Serial.println("Starting....");
#endif
- delay(500);
-
- model_defaults();
- read_settings();
+ delay(500);
+
+ model_defaults();
+ read_settings();
- displaystate = VALUES;
+ displaystate = VALUES;
- // Arduino believes all pins on Port C are Analog.
- // In reality they are tri-purpose; ADC, Digital, Digital Interrupts
- // Unfortunately the interrupt mode is unusable in this scenario, but digital I/O works :P
- pinMode(A2, INPUT);
- digitalWrite(A2, HIGH);
- scan_keys();
- if ( !keys[KEY_UP])
- calibrate();
+ // Arduino believes all pins on Port C are Analog.
+ // In reality they are tri-purpose; ADC, Digital, Digital Interrupts
+ // Unfortunately the interrupt mode is unusable in this scenario, but digital I/O works :P
+ pinMode(A2, INPUT);
+ digitalWrite(A2, HIGH);
+ scan_keys();
+ if ( !keys[KEY_UP])
+ calibrate();
#ifdef DEBUG
- // Debugging: how long does the main loop take on avg...
- t = micros();
- avg_loop_time = t;
- prev_loop_time = t;
+ // Debugging: how long does the main loop take on avg...
+ t = micros();
+ avg_loop_time = t;
+ prev_loop_time = t;
#endif
-
- // Initializing the stopwatch timer/clock values...
- clock_timer = (clock_timer_t){0, 0, 0, false};
- pinMode(A5, OUTPUT); // PPM output pin
- do_channel = false;
- set_timer( seplength );
- Timer1.initialize(framelength);
- Timer1.attachInterrupt(ISR_timer);
+ // Initializing the stopwatch timer/clock values...
+ clock_timer = (clock_timer_t){0, 0, 0, false};
- lcd.clear();
-
+ pinMode(A5, OUTPUT); // PPM output pin
+ do_channel = false;
+ set_timer( seplength );
+ Timer1.initialize(framelength);
+ Timer1.attachInterrupt(ISR_timer);
+
+ lcd.clear();
}
void model_defaults( void )
{
- // This function provides default values for model data
- // that is not a result of stick input, or in other words:
- // provides defautls for all user-configurable model options.
-
- // Remember to update this when a new option/element is added
- // to the model_t struct (preferably before implementing the
- // menu code that sets those options ...)
-
- // This is used when a user wants a new, blank model, a reset
- // of a configured model, and (most important) when EEPROM
- // data format changes.
- // NOTE: This means that stored model conficuration is reset
- // to defaults when the EEPROM version/format changes.
- 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;
-
+ // This function provides default values for model data
+ // that is not a result of stick input, or in other words:
+ // provides defautls for all user-configurable model options.
+
+ // Remember to update this when a new option/element is added
+ // to the model_t struct (preferably before implementing the
+ // menu code that sets those options ...)
+
+ // This is used when a user wants a new, blank model, a reset
+ // of a configured model, and (most important) when EEPROM
+ // data format changes.
+ // NOTE: This means that stored model conficuration is reset
+ // to defaults when the EEPROM version/format changes.
+ 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;
}
// ---------- Arduino main loop -----------------------
void loop ()
{
+ process_inputs();
+
+ // Wasting a full I/O pin on battery status monitoring!
+ battery_val = analogRead(1) * BATTERY_CONV;
+ if ( battery_val < BATTERY_LOW )
+ digitalWrite(13, 1); // Simulate alarm :P
- process_inputs();
-
- // Wasting a full I/O pin on battery status monitoring!
- battery_val = analogRead(1) * BATTERY_CONV;
- if ( battery_val < BATTERY_LOW ) {
- digitalWrite(13, 1); // Simulate alarm :P
- }
- if ( battery_val < BATTERY_CRITICAL ) {
- displaystate = BATTERY;
- }
-
- if ( millis() - last > UI_INTERVAL )
- {
- last = millis();
- ui_handler();
- }
+ if ( battery_val < BATTERY_CRITICAL )
+ displaystate = BATTERY;
+
+ if ( millis() - last > UI_INTERVAL )
+ {
+ last = millis();
+ ui_handler();
+ }
#ifdef DEBUG
- if ( displaystate != MENU )
- {
- // Debugging: how long does the main loop take on avg,
- // when not handling the UI...
- t = micros();
- avg_loop_time = ( t - prev_loop_time + avg_loop_time ) / 2;
- prev_loop_time = t;
- }
+ if ( displaystate != MENU )
+ {
+ // Debugging: how long does the main loop take on avg,
+ // when not handling the UI...
+ t = micros();
+ avg_loop_time = ( t - prev_loop_time + avg_loop_time ) / 2;
+ prev_loop_time = t;
+ }
#endif
- // Whoa! Slow down partner! Let everything settle down before proceeding.
- delay(5);
+ // Whoa! Slow down partner! Let everything settle down before proceeding.
+ delay(5);
}
// ----- Simple support functions used by more complex functions ----
void set_ppm_output( bool state )
{
- digitalWrite(A5, state); // Hard coded PPM output
+ digitalWrite(A5, state); // Hard coded PPM output
}
void set_timer(long time)
{
- Timer1.detachInterrupt();
- Timer1.attachInterrupt(ISR_timer, time);
+ Timer1.detachInterrupt();
+ Timer1.attachInterrupt(ISR_timer, time);
}
boolean check_key( int key)
{
- return ( !keys[key] && prev_keys[key] );
+ return ( !keys[key] && prev_keys[key] );
}
void mplx_select(int pin)
{
- digitalWrite(5, 1);
- delayMicroseconds(24);
+ digitalWrite(5, 1);
+ delayMicroseconds(24);
- digitalWrite(2, bitRead(pin,0)); // Arduino alias for non-modifying bitshift operation
- digitalWrite(3, bitRead(pin,1)); // us used to extract individual bits from the int (0..7)
- digitalWrite(4, bitRead(pin,2)); // Select the appropriate input by setting s1,s2,s3 and e
- digitalWrite(5, 0); // on the 4051 multiplexer.
+ digitalWrite(2, bitRead(pin,0)); // Arduino alias for non-modifying bitshift operation
+ digitalWrite(3, bitRead(pin,1)); // us used to extract individual bits from the int (0..7)
+ digitalWrite(4, bitRead(pin,2)); // Select the appropriate input by setting s1,s2,s3 and e
+ digitalWrite(5, 0); // on the 4051 multiplexer.
- // May need to slow the following read down to be able to
- // get fully reliable values from the 4051 multiplex.
- delayMicroseconds(24);
+ // May need to slow the following read down to be able to
+ // get fully reliable values from the 4051 multiplex.
+ delayMicroseconds(24);
}
void calibrate()
{
- int i, adc_in;
- int num_calibrations = 200;
-
- lcd.clear();
- lcd.print("Move controls to");
- lcd.setCursor(0,1);
- lcd.print("their extremes..");
- Serial.print("Calibration. Move all controls to their extremes.");
-
- for (i=0; i<MAX_INPUTS; i++) {
- input_cal.min[i] = 1024;
- input_cal.center[i] = 512;
- input_cal.max[i] = 0;
- }
-
- while ( num_calibrations-- )
- {
- for (i=0; i<MAX_INPUTS; i++) {
- mplx_select(i);
- adc_in = analogRead(0);
-
- // Naive min/max calibration
- if ( adc_in < input_cal.min[i] ) {
- input_cal.min[i] = adc_in;
- }
- if ( adc_in > input_cal.max[i] ) {
- input_cal.max[i] = adc_in;
- }
- delay(10);
- }
- }
-
- // TODO: WILL need to do center-point calibration after min-max...
-
- lcd.clear();
- lcd.print("Saving to EEPROM");
- write_calibration();
- lcd.setCursor(0 , 1);
- lcd.print("Done calibrating");
-
- Serial.print("Done calibrating");
- delay(2000);
+ int i, adc_in;
+ int num_calibrations = 200;
+
+ lcd.clear();
+ lcd.print("Move controls to");
+ lcd.setCursor(0,1);
+ lcd.print("their extremes..");
+ Serial.print("Calibration. Move all controls to their extremes.");
+
+ for (i=0; i<MAX_INPUTS; i++)
+ {
+ input_cal.min[i] = 1024;
+ input_cal.center[i] = 512;
+ input_cal.max[i] = 0;
+ }
+
+ while ( num_calibrations-- )
+ {
+ for (i=0; i<MAX_INPUTS; i++)
+ {
+ mplx_select(i);
+ adc_in = analogRead(0);
+
+ // Naive min/max calibration
+ if ( adc_in < input_cal.min[i] )
+ input_cal.min[i] = adc_in;
+
+ if ( adc_in > input_cal.max[i] )
+ input_cal.max[i] = adc_in;
+
+ delay(10);
+ }
+ }
+
+ // TODO: WILL need to do center-point calibration after min-max...
+
+ lcd.clear();
+ lcd.print("Saving to EEPROM");
+ write_calibration();
+ lcd.setCursor(0 , 1);
+ lcd.print("Done calibrating");
+
+ Serial.print("Done calibrating");
+ delay(2000);
}
void write_calibration(void)
{
- int i;
- unsigned char v;
- const byte *p;
-
- // Set p to be a pointer to the start of the input calibration struct.
- p = (const byte*)(const void*)&input_cal;
-
- // Iterate through the bytes of the struct...
- for (i = 0; i < sizeof(input_cal_t); i++)
- {
- // Get a byte of data from the struct...
- v = (unsigned char) *p;
- // write it to EEPROM
- EEPROM.write( EE_BASE_ADDR + i, v);
- // and move the pointer to the next byte in the struct.
- *p++;
- }
+ int i;
+ unsigned char v;
+ const byte *p;
+
+ // Set p to be a pointer to the start of the input calibration struct.
+ p = (const byte*)(const void*)&input_cal;
+
+ // Iterate through the bytes of the struct...
+ for (i = 0; i < sizeof(input_cal_t); i++)
+ {
+ // Get a byte of data from the struct...
+ v = (unsigned char) *p;
+ // write it to EEPROM
+ EEPROM.write( EE_BASE_ADDR + i, v);
+ // and move the pointer to the next byte in the struct.
+ *p++;
+ }
}
void read_settings(void)
{
- int i;
- unsigned char v;
- byte *p;
-
- v = EEPROM.read(0);
- if ( v != EEPROM_VERSION )
- {
- // All models have been reset. Set the current model to 0
- current_model = 0;
- EEPROM.write(1, current_model);
-
- calibrate();
- model_defaults();
- // The following does not yet work...
- for ( i = 0; i < MAX_MODELS; i++)
- write_model_settings(i);
+ int i;
+ unsigned char v;
+ byte *p;
+
+ v = EEPROM.read(0);
+ if ( v != EEPROM_VERSION )
+ {
+ // All models have been reset. Set the current model to 0
+ current_model = 0;
+ EEPROM.write(1, current_model);
+
+ calibrate();
+ model_defaults();
+ // The following does not yet work...
+ for ( i = 0; i < MAX_MODELS; i++)
+ write_model_settings(i);
+
+
+ // After saving calibration data and model defaults,
+ // update the saved version-identifier to the current ver.
+ EEPROM.write(0, EEPROM_VERSION);
+ }
-
- // After saving calibration data and model defaults,
- // update the saved version-identifier to the current ver.
- EEPROM.write(0, EEPROM_VERSION);
- }
-
- // Read calibration values from EEPROM.
- // This uses simple pointer-arithmetic and byte-by-byte
- // to put bytes read from EEPROM to the data-struct.
- p = (byte*)(void*)&input_cal;
- for (i = 0; i < sizeof(input_cal_t); i++)
+ // Read calibration values from EEPROM.
+ // This uses simple pointer-arithmetic and byte-by-byte
+ // to put bytes read from EEPROM to the data-struct.
+ p = (byte*)(void*)&input_cal;
+ for (i = 0; i < sizeof(input_cal_t); i++)
*p++ = EEPROM.read( EE_BASE_ADDR + i);
- // Get the previously selected model from EEPROM.
- current_model = EEPROM.read(1);
- read_model_settings( current_model );
+ // Get the previously selected model from EEPROM.
+ current_model = EEPROM.read(1);
+ read_model_settings( current_model );
}
void read_model_settings(unsigned char mod_no)
{
- int model_address;
- int i;
- unsigned char v;
- byte *p;
-
- // Calculate the EEPROM start adress for the given model (mod_no)
- model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
-
- // Do not try to write the model to EEPROM if it won't fit.
- if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
- {
- lcd.clear();
- lcd.print("Aborting READ");
- lcd.setCursor(0 , 1);
- lcd.print("Invalid location");
- delay(2000);
- return;
- }
-
- lcd.clear();
- lcd.print("Reading model ");
- lcd.print( (int)mod_no );
+ int model_address;
+ int i;
+ unsigned char v;
+ byte *p;
+
+ // Calculate the EEPROM start adress for the given model (mod_no)
+ model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+
+ // Do not try to write the model to EEPROM if it won't fit.
+ if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
+ {
+ lcd.clear();
+ lcd.print("Aborting READ");
+ lcd.setCursor(0 , 1);
+ lcd.print("Invalid location");
+ delay(2000);
+ return;
+ }
- // Pointer to the start of the model_t data struct,
- // used for byte-by-byte reading of data...
- p = (byte*)(void*)&model;
- for (i = 0; i < sizeof(model_t); i++)
+ lcd.clear();
+ lcd.print("Reading model ");
+ lcd.print( (int)mod_no );
+
+ // Pointer to the start of the model_t data struct,
+ // used for byte-by-byte reading of data...
+ p = (byte*)(void*)&model;
+ for (i = 0; i < sizeof(model_t); i++)
*p++ = EEPROM.read( model_address++ );
#ifdef DEBUG
- serial_dump_model();
+ serial_dump_model();
#endif
- lcd.setCursor(0 , 1);
- lcd.print("... Loaded.");
- delay(1000);
+ lcd.setCursor(0 , 1);
+ lcd.print("... Loaded.");
+ delay(1000);
}
void write_model_settings(unsigned char mod_no)
{
- int model_address;
- int i;
- unsigned char v;
- byte *p;
-
- // Calculate the EEPROM start adress for the given model (mod_no)
- model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+ int model_address;
+ int i;
+ unsigned char v;
+ byte *p;
+
+ // Calculate the EEPROM start adress for the given model (mod_no)
+ model_address = EE_MDL_BASE_ADDR + (mod_no * sizeof(model_t));
+
+ // Do not try to write the model to EEPROM if it won't fit.
+ if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
+ {
+ lcd.clear();
+ lcd.print("Aborting SAVE");
+ lcd.setCursor(0 , 1);
+ lcd.print("No room for data");
+ delay(2000);
+ return;
+ }
- // Do not try to write the model to EEPROM if it won't fit.
- if ( INT_EEPROM_SIZE < (model_address + sizeof(model_t)) )
- {
lcd.clear();
- lcd.print("Aborting SAVE");
- lcd.setCursor(0 , 1);
- lcd.print("No room for data");
- delay(2000);
- return;
- }
-
- lcd.clear();
- lcd.print("Saving model ");
- lcd.print( (int)mod_no);
+ lcd.print("Saving model ");
+ lcd.print( (int)mod_no);
- // Pointer to the start of the model_t data struct,
- // used for byte-by-byte reading of data...
- p = (byte*)(void*)&model;
-
- // Write/serialize the model data struct to EEPROM...
- for (i = 0; i < sizeof(model_t); i++)
+ // Pointer to the start of the model_t data struct,
+ // used for byte-by-byte reading of data...
+ p = (byte*)(void*)&model;
+
+ // Write/serialize the model data struct to EEPROM...
+ for (i = 0; i < sizeof(model_t); i++)
EEPROM.write( model_address++, *p++);
- lcd.setCursor(0 , 1);
- lcd.print(".. done saving.");
- delay(200);
+ lcd.setCursor(0 , 1);
+ lcd.print(".. done saving.");
+ delay(200);
}
#ifdef DEBUG
void serial_dump_model ( void )
{
- int i;
- int model_address;
- // Calculate the EEPROM start adress for the given model (mod_no)
- model_address = EE_MDL_BASE_ADDR + (current_model * sizeof(model_t));
- Serial.print("Current model: ");
- Serial.println( (int)current_model );
- Serial.print("Models base addr: ");
- Serial.println( EE_MDL_BASE_ADDR );
- Serial.print("Model no: ");
- Serial.println( current_model, 10 );
- Serial.print("Size of struct: ");
- Serial.println( sizeof( model_t) );
- Serial.print("Model address: ");
- Serial.println( model_address );
- Serial.print("End of model: ");
- Serial.println( model_address + sizeof(model_t) );
-
- Serial.println();
-
- Serial.print("Channel reversions: ");
- for ( i = 0; i<8; i++)
- {
- Serial.print(i);
- Serial.print("=");
- Serial.print(model.rev[i], 10);
- Serial.print(" ");
- }
- Serial.println();
-
- Serial.print("DR1 inp 0: ");
- Serial.println(model.dr[0]);
- Serial.print("DR1 inp 1: ");
- Serial.println(model.dr[1]);
- Serial.print("DR1 LO val: ");
- Serial.println(model.dr[4]);
- Serial.print("DR1 HI val: ");
- Serial.println(model.dr[5]);
- Serial.print("DR2 inp 0: ");
- Serial.println(model.dr[2]);
- Serial.print("DR2 inp 1: ");
- Serial.println(model.dr[3]);
- Serial.print("DR2 LO val: ");
- Serial.println(model.dr[6]);
- Serial.print("DR2 HI val: ");
- Serial.println(model.dr[7]);
+ int i;
+ int model_address;
+ // Calculate the EEPROM start adress for the given model (mod_no)
+ model_address = EE_MDL_BASE_ADDR + (current_model * sizeof(model_t));
+ Serial.print("Current model: ");
+ Serial.println( (int)current_model );
+ Serial.print("Models base addr: ");
+ Serial.println( EE_MDL_BASE_ADDR );
+ Serial.print("Model no: ");
+ Serial.println( current_model, 10 );
+ Serial.print("Size of struct: ");
+ Serial.println( sizeof( model_t) );
+ Serial.print("Model address: ");
+ Serial.println( model_address );
+ Serial.print("End of model: ");
+ Serial.println( model_address + sizeof(model_t) );
+
+ Serial.println();
+
+ Serial.print("Channel reversions: ");
+ for ( i = 0; i<8; i++)
+ {
+ Serial.print(i);
+ Serial.print("=");
+ Serial.print(model.rev[i], 10);
+ Serial.print(" ");
+ }
+ Serial.println();
+
+ Serial.print("DR1 inp 0: ");
+ Serial.println(model.dr[0]);
+ Serial.print("DR1 inp 1: ");
+ Serial.println(model.dr[1]);
+ Serial.print("DR1 LO val: ");
+ Serial.println(model.dr[4]);
+ Serial.print("DR1 HI val: ");
+ Serial.println(model.dr[5]);
+ Serial.print("DR2 inp 0: ");
+ Serial.println(model.dr[2]);
+ Serial.print("DR2 inp 1: ");
+ Serial.println(model.dr[3]);
+ Serial.print("DR2 LO val: ");
+ Serial.println(model.dr[6]);
+ Serial.print("DR2 HI val: ");
+ Serial.println(model.dr[7]);
- for (i=0; i<MAX_INPUTS; i++) {
- Serial.print("Input #");
- Serial.print(i);
- Serial.print(" pct: ");
- Serial.print(model.stick[i]);
- Serial.print(" min: ");
- Serial.print(input_cal.min[i]);
- Serial.print(" max: ");
- Serial.print(input_cal.max[i]);
- Serial.println();
- }
+ for (i=0; i<MAX_INPUTS; i++)
+ {
+ Serial.print("Input #");
+ Serial.print(i);
+ Serial.print(" pct: ");
+ Serial.print(model.stick[i]);
+ Serial.print(" min: ");
+ Serial.print(input_cal.min[i]);
+ Serial.print(" max: ");
+ Serial.print(input_cal.max[i]);
+ Serial.println();
+ }
}
#endif
void scan_keys ( void )
{
- boolean key_in;
-
- // To get more inputs, another 4051 analog multiplexer is used,
- // but this time it is used for digital inputs. 8 digital inputs
- // on one input line, as long as proper debouncing and filtering
- // is done in hardware :P
- for (int i=0; i<=7; i++) {
- // To be able to detect that a key has changed state, preserve the previous..
- prev_keys[i] = keys[i];
-
- // Select and read input.
- mplx_select(i);
- keys[i] = digitalRead(A2);
- delay(2);
- }
+ boolean key_in;
+
+ // To get more inputs, another 4051 analog multiplexer is used,
+ // but this time it is used for digital inputs. 8 digital inputs
+ // on one input line, as long as proper debouncing and filtering
+ // is done in hardware :P
+ for (int i=0; i<=7; i++)
+ {
+ // To be able to detect that a key has changed state, preserve the previous..
+ prev_keys[i] = keys[i];
+
+ // Select and read input.
+ mplx_select(i);
+ keys[i] = digitalRead(A2);
+ delay(2);
+ }
}
void process_inputs(void )
{
- int current_input, adc_in, fact;
- float min, max;
+ int current_input, adc_in, fact;
+ float min, max;
- for (current_input=0; current_input<MAX_INPUTS; current_input++) {
+ for (current_input=0; current_input<MAX_INPUTS; current_input++)
+ {
- mplx_select(current_input);
- adc_in = analogRead(0);
+ mplx_select(current_input);
+ adc_in = analogRead(0);
- model.raw[current_input] = adc_in;
- // New format on stick values
- // The calculations happen around the center point, the values
- // need to arrive at 0...100 of the range "center-to-edge",
- // and must end up as negative on the ... negative side of center.
-
- if ( adc_in < input_cal.center[current_input] )
- {
- // The stick is on the negative side, so the range is
- // from the lowest possible value to center, and we must
- // make this a negative percentage value.
- max = input_cal.min[current_input];
- min = input_cal.center[current_input];
- fact = -100;
- }
- else
- {
- // The stick is at center, or on the positive side.
- // Thus, the range is from center to max, and
- // we need positive percentages.
- min = input_cal.center[current_input];
- max = input_cal.max[current_input];
- fact = 100;
- }
- // Calculate the percentage that the current stick position is at
- // in the given range, referenced to or from center, depending :P
- model.stick[current_input] = fact * ((float)adc_in - min ) / (max - min);
-
- // If this input is configured to be reversed, simply do a sign-flip :D
- if ( model.rev[current_input] ) model.stick[current_input] *= -1;
-
- // Dual-rate calculation :D
- // This is very repetitive code. It should be fast, but it may waste code-space.
- float dr_val;
- // Test to see if dualrate-switch #1 applies to channel...
- if ( ( current_input == ( model.dr[0]-1) ) || ( current_input == ( model.dr[1]-1) ) )
- {
- if ( !keys[KEY_DR1] )
- dr_val = ((float)model.dr[4])/100.0;
- else
- dr_val = ((float)model.dr[5])/100.0;
-
- model.stick[current_input] *= dr_val;
- }
- else
- // Test to see if dualrate-switch #1 applies to channel...
- if ( ( current_input == ( model.dr[2]-1) ) || ( current_input == ( model.dr[3]-1) ) )
- {
- if ( !keys[KEY_DR2] )
- dr_val = ((float)model.dr[6])/100.0;
- else
- dr_val = ((float)model.dr[7])/100.0;
-
- model.stick[current_input] *= dr_val;
- }
- }
+ model.raw[current_input] = adc_in;
+ // New format on stick values
+ // The calculations happen around the center point, the values
+ // need to arrive at 0...100 of the range "center-to-edge",
+ // and must end up as negative on the ... negative side of center.
+
+ if ( adc_in < input_cal.center[current_input] )
+ {
+ // The stick is on the negative side, so the range is
+ // from the lowest possible value to center, and we must
+ // make this a negative percentage value.
+ max = input_cal.min[current_input];
+ min = input_cal.center[current_input];
+ fact = -100;
+ }
+ else
+ {
+ // The stick is at center, or on the positive side.
+ // Thus, the range is from center to max, and
+ // we need positive percentages.
+ min = input_cal.center[current_input];
+ max = input_cal.max[current_input];
+ fact = 100;
+ }
+ // Calculate the percentage that the current stick position is at
+ // in the given range, referenced to or from center, depending :P
+ model.stick[current_input] = fact * ((float)adc_in - min ) / (max - min);
+
+ // If this input is configured to be reversed, simply do a sign-flip :D
+ if ( model.rev[current_input] ) model.stick[current_input] *= -1;
+
+ // Dual-rate calculation :D
+ // This is very repetitive code. It should be fast, but it may waste code-space.
+ float dr_val;
+ // Test to see if dualrate-switch #1 applies to channel...
+ if ( ( current_input == ( model.dr[0]-1) ) || ( current_input == ( model.dr[1]-1) ) )
+ {
+ if ( !keys[KEY_DR1] )
+ dr_val = ((float)model.dr[4])/100.0;
+ else
+ dr_val = ((float)model.dr[5])/100.0;
+
+ model.stick[current_input] *= dr_val;
+ }
+ else
+ // Test to see if dualrate-switch #1 applies to channel...
+ if ( ( current_input == ( model.dr[2]-1) ) || ( current_input == ( model.dr[3]-1) ) )
+ {
+ if ( !keys[KEY_DR2] )
+ dr_val = ((float)model.dr[6])/100.0;
+ else
+ dr_val = ((float)model.dr[7])/100.0;
+
+ model.stick[current_input] *= dr_val;
+ }
+ }
}
void ISR_timer(void)
{
- Timer1.stop(); // Make sure we do not run twice while working :P
-
- if ( !do_channel )
- {
- set_ppm_output( LOW );
- sum += seplength;
- do_channel = true;
- set_timer(seplength);
- return;
- }
-
- if ( cchannel >= model.channels )
- {
- set_ppm_output( HIGH );
- long framesep = framelength - sum;
-
- sum = 0;
- do_channel = false;
- cchannel = 0;
- set_timer ( framesep );
- return;
- }
-
- if ( do_channel )
- {
- set_ppm_output( HIGH );
-
- // New format on stick values
- // model.stick contains percentages, -100% to 100% in float. To make the timer-handling
- // here as simple as possible. We want to calc the channel value as a "ratio-value",
- // a float in the range 0..1.0. So, by moving the lower bound to 0, then cutting the
- // range in half, and finally dividing by 100, we should get the ratio value.
- // Some loss of presicion occurs, perhaps the algo' should be reconsidered :P
- long next_timer = (( chwidht * ((model.stick[cchannel]+100)/200) ) + chmin);
- // Do sanity-check of next_timer compared to chmax and chmin...
- while ( chmax < next_timer ) next_timer--;
- while ( next_timer < chmin ) next_timer++;
-
- // Update the sum of elapsed time
- sum += next_timer;
-
- // Done with channel separator and value,
- // prepare for next channel...
- cchannel++;
- do_channel = false;
- set_timer ( next_timer );
- return;
- }
+ Timer1.stop(); // Make sure we do not run twice while working :P
+
+ if ( !do_channel )
+ {
+ set_ppm_output( LOW );
+ sum += seplength;
+ do_channel = true;
+ set_timer(seplength);
+ return;
+ }
+
+ if ( cchannel >= model.channels )
+ {
+ set_ppm_output( HIGH );
+ long framesep = framelength - sum;
+
+ sum = 0;
+ do_channel = false;
+ cchannel = 0;
+ set_timer ( framesep );
+ return;
+ }
+
+ if ( do_channel )
+ {
+ set_ppm_output( HIGH );
+
+ // New format on stick values
+ // model.stick contains percentages, -100% to 100% in float. To make the timer-handling
+ // here as simple as possible. We want to calc the channel value as a "ratio-value",
+ // a float in the range 0..1.0. So, by moving the lower bound to 0, then cutting the
+ // range in half, and finally dividing by 100, we should get the ratio value.
+ // Some loss of presicion occurs, perhaps the algo' should be reconsidered :P
+ long next_timer = (( chwidht * ((model.stick[cchannel]+100)/200) ) + chmin);
+
+ // Do sanity-check of next_timer compared to chmax and chmin...
+ while ( chmax < next_timer ) next_timer--;
+ while ( next_timer < chmin ) next_timer++;
+
+ // Update the sum of elapsed time
+ sum += next_timer;
+
+ // Done with channel separator and value,
+ // prepare for next channel...
+ cchannel++;
+ do_channel = false;
+ set_timer ( next_timer );
+ return;
+ }
}
#ifdef DEBUG
void serial_debug()
{
- int current_input;
- for (current_input=0; current_input<MAX_INPUTS; current_input++) {
-
- Serial.print("Input #");
- Serial.print(current_input);
- Serial.print(" pct: ");
- Serial.print(model.stick[current_input]);
- Serial.print(" raw value: ");
- Serial.print(model.raw[current_input]);
- Serial.print(" min: ");
- Serial.print(input_cal.min[current_input]);
- Serial.print(" max: ");
- Serial.print(input_cal.max[current_input]);
- Serial.println();
- }
- Serial.print("Battery level is: ");
- Serial.println(battery_val);
-
- Serial.print("Average loop time:");
- Serial.println(avg_loop_time);
-
- Serial.print("Free RAM:");
- Serial.print( FreeRam() );
- Serial.println();
+ int current_input;
+ for (current_input=0; current_input<MAX_INPUTS; current_input++)
+ {
+ Serial.print("Input #");
+ Serial.print(current_input);
+ Serial.print(" pct: ");
+ Serial.print(model.stick[current_input]);
+ Serial.print(" raw value: ");
+ Serial.print(model.raw[current_input]);
+ Serial.print(" min: ");
+ Serial.print(input_cal.min[current_input]);
+ Serial.print(" max: ");
+ Serial.print(input_cal.max[current_input]);
+ Serial.println();
+ }
+ Serial.print("Battery level is: ");
+ Serial.println(battery_val);
+
+ Serial.print("Average loop time:");
+ Serial.println(avg_loop_time);
+
+ Serial.print("Free RAM:");
+ Serial.print( FreeRam() );
+ Serial.println();
}
#endif
}
void ui_handler()
{
- int row;
- int col;
- scan_keys();
-
- if ( check_key( KEY_UP) || check_key(KEY_DOWN))
- lcd.clear();
+ int row;
+ int col;
+ scan_keys();
+
+ if ( check_key( KEY_UP) || check_key(KEY_DOWN))
+ lcd.clear();
+
+ if ( displaystate != MENU )
+ {
+ menu_substate = 0;
+ if ( check_key(KEY_UP) && displaystate == VALUES ) {
+ displaystate = BATTERY;
+ return;
+ }
+ else if ( check_key(KEY_UP) && displaystate == BATTERY ) {
+ displaystate = TIMER;
+ return;
+ }
+ else if ( check_key(KEY_UP) && displaystate == TIMER ) {
+ displaystate = CURMODEL;
+ return;
+ }
+ else if ( check_key(KEY_UP) && displaystate == CURMODEL ) {
+ displaystate = VALUES;
+ return;
+ }
- if ( displaystate != MENU )
- {
- menu_substate = 0;
- if ( check_key(KEY_UP) && displaystate == VALUES ) {
- displaystate = BATTERY;
- return;
- }
- else if ( check_key(KEY_UP) && displaystate == BATTERY ) {
- displaystate = TIMER;
- return;
- }
- else if ( check_key(KEY_UP) && displaystate == TIMER ) {
- displaystate = CURMODEL;
- return;
- }
- else if ( check_key(KEY_UP) && displaystate == CURMODEL ) {
- displaystate = VALUES;
- return;
- }
-
- else if ( check_key(KEY_DOWN) ) {
- displaystate = MENU;
- return;
- }
- }
-
- digitalWrite(13, digitalRead(13) ^ 1 );
+ else if ( check_key(KEY_DOWN) ) {
+ displaystate = MENU;
+ return;
+ }
+ }
+
+ digitalWrite(13, digitalRead(13) ^ 1 );
- switch ( displaystate )
- {
- case VALUES:
+ switch ( displaystate )
+ {
+ case VALUES:
int current_input;
row = 0; col = 0;
break;
case BATTERY:
- lcd.setCursor(0 , 0);
- lcd.print("Battery level: ");
- lcd.setCursor(0 , 1);
- lcd.print( " ");
- lcd.setCursor(0 , 1);
- lcd.print( (float)battery_val/10);
- lcd.print("V");
- if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING");
- else lcd.print(" - OK");
- break;
+ lcd.setCursor(0 , 0);
+ lcd.print("Battery level: ");
+ lcd.setCursor(0 , 1);
+ lcd.print( " ");
+ lcd.setCursor(0 , 1);
+ lcd.print( (float)battery_val/10);
+ lcd.print("V");
+ if ( battery_val < BATTERY_LOW ) lcd.print(" - WARNING");
+ else lcd.print(" - OK");
+ break;
clock_timer.value = clock_timer.value % 3600000;
minutes = ( clock_timer.value / 1000 ) / 60;
seconds = ( clock_timer.value / 1000 ) % 60;
- if ( hours ) {
+ if ( hours )
+ {
lcd.print(hours);
lcd.print(":");
}
if ( seconds < 10 ) lcd.print("0");
lcd.print( seconds );
- if ( check_key(KEY_INC) ) {
+ if ( check_key(KEY_INC) )
+ {
if ( !clock_timer.running && !clock_timer.start )
{
clock_timer.start = millis();
clock_timer.value = 0;
clock_timer.running = true;
- } else if ( !clock_timer.running && clock_timer.start ) {
+ }
+ else if ( !clock_timer.running && clock_timer.start )
+ {
clock_timer.start = millis() - clock_timer.value;
clock_timer.running = true;
- } else if ( clock_timer.running ) {
+ }
+ else if ( clock_timer.running )
clock_timer.running = false;
- }
+
return;
- } else if ( check_key(KEY_DEC) ) {
- if ( !clock_timer.running && clock_timer.start ) {
+
+ }
+ else if ( check_key(KEY_DEC) )
+ {
+ if ( !clock_timer.running && clock_timer.start )
+ {
clock_timer.value = 0;
clock_timer.start = 0;
clock_timer.init = 0;
}
break;
-
case CURMODEL:
- lcd.setCursor(0 , 0);
- lcd.print("Model #: ");
- lcd.print( (int)current_model );
- lcd.setCursor(0 , 1);
- lcd.print("NAME (not impl)");
- break;
+ lcd.setCursor(0 , 0);
+ lcd.print("Model #: ");
+ lcd.print( (int)current_model );
+ lcd.setCursor(0 , 1);
+ lcd.print("NAME (not impl)");
+ break;
case MENU:
- lcd.setCursor(0 , 0);
- switch ( menu_mainstate )
- {
- case TOP:
- lcd.setCursor(0 , 0);
- lcd.print("In MENU mode!");
- lcd.setCursor(0 , 1);
- lcd.print("UP to quit.");
- lcd.setCursor(0 , 2);
- lcd.print("DOWN to scroll");
-
- menu_substate = 0;
- if ( check_key(KEY_UP) ) {
- displaystate = VALUES;
- lcd.clear();
- return;
- }
- else if ( check_key(KEY_DOWN) ) {
- lcd.clear();
- menu_mainstate = INVERTS;
- return;
- }
- break;
+ lcd.setCursor(0 , 0);
+ switch ( menu_mainstate )
+ {
+ case TOP:
+ lcd.setCursor(0 , 0);
+ lcd.print("In MENU mode!");
+ lcd.setCursor(0 , 1);
+ lcd.print("UP to quit.");
+ lcd.setCursor(0 , 2);
+ lcd.print("DOWN to scroll");
+
+ menu_substate = 0;
+ if ( check_key(KEY_UP) )
+ {
+ displaystate = VALUES;
+ lcd.clear();
+ return;
+ }
+ else if ( check_key(KEY_DOWN) )
+ {
+ lcd.clear();
+ menu_mainstate = INVERTS;
+ return;
+ }
+ break;
- case INVERTS:
- 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( (model.rev[menu_substate] ? ": Invert" : ": Normal"));
-
- if ( check_key(KEY_UP) ) {
- menu_mainstate = TOP;
- lcd.clear();
- return;
- }
- else if ( check_key(KEY_DOWN) ) {
- menu_mainstate = DUALRATES;
- lcd.clear();
- return;
- }
-
- if ( check_key(KEY_RIGHT) ) {
- menu_substate++;
- return;
- }
- else if ( check_key(KEY_LEFT) ) {
- menu_substate--;
- return;
- }
- else if ( check_key(KEY_INC) || check_key(KEY_DEC) ) {
- model.rev[menu_substate] ^= 1;
- return;
- }
- break;
+ case INVERTS:
+ 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( (model.rev[menu_substate] ? ": Invert" : ": Normal"));
+
+ if ( check_key(KEY_UP) )
+ {
+ menu_mainstate = TOP;
+ lcd.clear();
+ return;
+ }
+ else if ( check_key(KEY_DOWN) )
+ {
+ menu_mainstate = DUALRATES;
+ lcd.clear();
+ return;
+ }
+
+ if ( check_key(KEY_RIGHT) )
+ {
+ menu_substate++;
+ return;
+ }
+ else if ( check_key(KEY_LEFT) )
+ {
+ menu_substate--;
+ return;
+ }
+ else if ( check_key(KEY_INC) || check_key(KEY_DEC) )
+ {
+ model.rev[menu_substate] ^= 1;
+ return;
+ }
+ break;
case DUALRATES:
- if ( menu_substate > 5 ) menu_substate = 0;
- if ( menu_substate < 0) menu_substate = 5;
+ if ( menu_substate > 5 ) menu_substate = 0;
+ if ( menu_substate < 0) menu_substate = 5;
- if ( check_key(KEY_UP) ) {
- menu_mainstate = INVERTS;
- lcd.clear();
- return;
- }
- if ( check_key(KEY_DOWN) ) {
- menu_mainstate = EXPOS;
- lcd.clear();
- return;
- }
- if ( check_key(KEY_RIGHT) ) {
- menu_substate++;
- return;
- }
- else if ( check_key(KEY_LEFT) ) {
- menu_substate--;
- return;
- }
- switch (menu_substate)
- {
+ if ( check_key(KEY_UP) )
+ {
+ menu_mainstate = INVERTS;
+ lcd.clear();
+ return;
+ }
+ if ( check_key(KEY_DOWN) )
+ {
+ menu_mainstate = EXPOS;
+ lcd.clear();
+ return;
+ }
+ if ( check_key(KEY_RIGHT) )
+ {
+ menu_substate++;
+ return;
+ }
+ else if ( check_key(KEY_LEFT) )
+ {
+ menu_substate--;
+ return;
+ }
+
+ switch (menu_substate)
+ {
case 0:
dr_inputselect(0, 0);
return;
default:
menu_substate = 0;
break;
- }
- break;
+ }
+ break;
case EXPOS:
- //________________
- lcd.print("Input expo curve");
- lcd.setCursor(0 , 1);
- lcd.print("Not implemented");
- // Possible, if input values are mapped to +/- 100 rather than 0..1 ..
- // plot ( x*(1 - 1.0*cos (x/(20*PI)) )) 0 to 100
- // Run in wolfram to see result, adjust the 1.0 factor to inc/red effect.
- // Problem: -100 to 100 is terribly bad presicion, esp. considering that
- // the values started as 0...1024, and we have 1000usec to "spend" on channels.
-
- // NEW IDEA provided my ivarf @ hig: use bezier curves og hermite curves!
- // Looks like a promising idea, but the implementation is still a bitt off
- // on the time-horizon :P
- if ( check_key(KEY_UP ) ) {
- menu_mainstate = DUALRATES;
- lcd.clear();
- return;
- }
+ //________________
+ lcd.print("Input expo curve");
+ lcd.setCursor(0 , 1);
+ lcd.print("Not implemented");
+ // Possible, if input values are mapped to +/- 100 rather than 0..1 ..
+ // plot ( x*(1 - 1.0*cos (x/(20*PI)) )) 0 to 100
+ // Run in wolfram to see result, adjust the 1.0 factor to inc/red effect.
+ // Problem: -100 to 100 is terribly bad presicion, esp. considering that
+ // the values started as 0...1024, and we have 1000usec to "spend" on channels.
+
+ // NEW IDEA provided my ivarf @ hig: use bezier curves og hermite curves!
+ // Looks like a promising idea, but the implementation is still a bitt off
+ // on the time-horizon :P
+ if ( check_key(KEY_UP ) )
+ {
+ menu_mainstate = DUALRATES;
+ lcd.clear();
+ return;
+ }
#ifdef DEBUG
- if ( check_key(KEY_DOWN ) ) {
- menu_mainstate = DEBUG_DUMP;
- lcd.clear();
- return;
- }
+ if ( check_key(KEY_DOWN ) )
+ {
+ menu_mainstate = DEBUG_DUMP;
+ lcd.clear();
+ return;
+ }
#else
- if ( check_key(KEY_DOWN ) ) {
- menu_mainstate = TOP;
- lcd.clear();
- return;
- }
+ if ( check_key(KEY_DOWN ) )
+ {
+ menu_mainstate = TOP;
+ lcd.clear();
+ return;
+ }
#endif
- break;
+ break;
#ifdef DEBUG
- case DEBUG_DUMP:
- lcd.setCursor(0 , 0);
- lcd.print("Dumping debug to");
- lcd.setCursor(0 , 1);
- lcd.print("serial port 0");
- serial_debug();
- if ( check_key(KEY_UP ) ) {
- // FIXME: Remember to update the "Scroll up" state!
- menu_mainstate = EXPOS;
- lcd.clear();
- return;
- } else if ( check_key(KEY_DOWN ) ) {
- menu_mainstate = SAVE;
- lcd.clear();
- return;
- }
- break;
+ case DEBUG_DUMP:
+ lcd.setCursor(0 , 0);
+ lcd.print("Dumping debug to");
+ lcd.setCursor(0 , 1);
+ lcd.print("serial port 0");
+ serial_debug();
+ if ( check_key(KEY_UP ) )
+ {
+ // FIXME: Remember to update the "Scroll up" state!
+ menu_mainstate = EXPOS;
+ lcd.clear();
+ return;
+ } else if ( check_key(KEY_DOWN ) )
+ {
+ menu_mainstate = SAVE;
+ lcd.clear();
+ return;
+ }
+ break;
#endif
- default:
- lcd.print("Not implemented");
- lcd.setCursor(0 , 1);
- lcd.print("Press DOWN...");
- if ( check_key(KEY_DOWN ) ) menu_mainstate = TOP;
- }
- break;
-
-
- default:
- // Invalid
- return;
- }
+ default:
+ lcd.print("Not implemented");
+ lcd.setCursor(0 , 1);
+ lcd.print("Press DOWN...");
+ if ( check_key(KEY_DOWN ) ) menu_mainstate = TOP;
+
+ } // End of settings menu / MENU
+ break;
- return;
+
+ default:
+ // Invalid
+ return;
+ } // End of main UI switch
+ return;
}
#ifdef DEBUG
so contacting the author may give us the option of relicencing just this bit...
*/
static int FreeRam(void) {
- extern int __bss_end;
- extern int* __brkval;
- int free_memory;
- if (reinterpret_cast<int>(__brkval) == 0) {
- // if no heap use from end of bss section
- free_memory = reinterpret_cast<int>(&free_memory)
- - reinterpret_cast<int>(&__bss_end);
- } else {
- // use from top of stack to heap
- free_memory = reinterpret_cast<int>(&free_memory)
- - reinterpret_cast<int>(__brkval);
- }
- return free_memory;
+ extern int __bss_end;
+ extern int* __brkval;
+ int free_memory;
+ if (reinterpret_cast<int>(__brkval) == 0)
+ {
+ // if no heap use from end of bss section
+ free_memory = reinterpret_cast<int>(&free_memory)
+ - reinterpret_cast<int>(&__bss_end);
+ }
+ else
+ {
+ // use from top of stack to heap
+ free_memory = reinterpret_cast<int>(&free_memory)
+ - reinterpret_cast<int>(__brkval);
+ }
+ return free_memory;
}
#endif