2018-03-22 07:57:53 +00:00
//STM32F103C, 64k flash
//upload method: serial (A9 to RX, A10 to TX)
//To upload set Boot0 jumper to 1 (the one further away from reset btn) and press reset (stm will boot from flash wich contains uart to flash uploader)
//upload via arduino IDE
//To boot program after restart set Boot0 jumper to 0
//Letters 5x7 at Size 1
2018-04-15 10:13:08 +00:00
# include <math.h>
2018-03-22 07:57:53 +00:00
//#include <SPI.h>
# include <Wire.h>
# include <Adafruit_GFX.h>
# include <Adafruit_SSD1306.h> // http://www.instructables.com/id/Monochrome-096-i2c-OLED-display-with-arduino-SSD13/
//128 x 64 px
2018-03-26 15:55:17 +00:00
# define WIDTH 128
# define HEIGHT 64
2018-04-14 11:56:49 +00:00
# include <EEPROM.h>
2018-03-22 07:57:53 +00:00
# include <BH1750.h> //from: https://github.com/mysensors/MySensorsArduinoExamples/tree/master/libraries/BH1750
BH1750 lightMeter ;
2018-04-14 11:56:49 +00:00
# define INCIDENT_CORRECTION_FACTOR 1.17
//with 1125 25 225 2465 120
//wihtout 1335 32 265 2865 145
/*1,186666667
1 , 28
1 , 177777778
1 , 162271805
1 , 208333333 */
2018-03-22 07:57:53 +00:00
# define PIN_LDR 0 //A0
# define PIN_BRIGHTMODE 1 //A1
# define PIN_VBAT 2 //A2
2018-04-14 11:56:49 +00:00
# define PIN_LED 8 //White status led A8
2018-03-22 07:57:53 +00:00
# define PIN_TRIGGER PB8
# define PIN_BTNLEFT PA15
# define PIN_BTNCENTER PB4
# define PIN_BTNRIGHT PB5
2018-04-14 11:56:49 +00:00
# define PIN_ON PB9 //pin for hardware latch
2018-03-22 07:57:53 +00:00
# define TIME_AUTOPOWEROFF 120000
2018-04-14 11:56:49 +00:00
# define TIME_METERINGMODESELECTION_CLOSE 60000
2018-04-16 09:08:12 +00:00
# define TIME_METERINGMODESELECTION_SHUTDOWN_SHORTCUT 500
2018-04-14 11:56:49 +00:00
# define LDRDELAY 100 //delay between ldr switches. New analog_high or low reading after that time. Transistor for lower value pulldown resistor switches in between
# define LDRFILTERDELAY 1 //delay in ms between readings sequent readings for smoothing . LDRFILTERDELAY*64 > LDRDELAY
# define LDRSWITCHDELAY 30 //time to wait after transistor switched
2018-03-23 19:21:27 +00:00
# define INCIDENTDELAY 100 //minimum delay between incident sensor (BH1750) readings
2018-04-09 09:45:18 +00:00
# define DEBOUNCETIME 20 //time to not check for inputs after key press
2018-03-23 19:21:27 +00:00
# define BUTTONTIMEHOLD 750 //time for button hold
2018-05-03 08:01:41 +00:00
# define BUTTONTIMEHOLDLONG 3000 //time for button long hold
2018-03-22 07:57:53 +00:00
2018-04-14 11:56:49 +00:00
# define VOLTAGE_WARN 3.4 //voltage per cell //TODO implement warning
2018-03-22 07:57:53 +00:00
//float shuttertimes1[]={1,1.0/2, 1.0/4, 1.0/8, 1.0/15, 1.0/30, 1.0/60, 1.0/125, 1.0/250, 1.0/500, 1.0/1000, 1.0/2000, 1.0/4000, 1.0/8000};
float shuttertimes1 [ ] = { 64 , 32 , 16 , 8 , 4 , 2 , 1 , 1.0 / 2 , 1.0 / 4 , 1.0 / 8 , 1.0 / 15 , 1.0 / 30 , 1.0 / 60 , 1.0 / 125 , 1.0 / 250 , 1.0 / 500 , 1.0 / 1000 , 1.0 / 2000 , 1.0 / 4000 , 1.0 / 8000 } ;
2018-03-23 19:21:27 +00:00
# define SHUTTERTIMES1_MAXINDEX 19
2018-04-15 10:13:08 +00:00
float shuttertimes2 [ ] = { 30 , 25 , 20 , 15 , 13 , 10 , 8 , 6 , 5 , 4 , 3.2 , 2.5 , 2 , 1.6 , 1.3 , 1 , 0.8 , 0.6 , 0.5 , 0.4 , 0.3 , 1.0 / 4 , 1.0 / 5 , 1.0 / 6 , 1.0 / 8 , 1.0 / 10 , 1.0 / 13 , 1.0 / 15 , 1.0 / 20 , 1.0 / 25 , 1.0 / 30 , 1.0 / 40 , 1.0 / 50 , 1.0 / 60 , 1.0 / 80 , 1.0 / 100 , 1.0 / 125 , 1.0 / 160 , 1.0 / 200 , 1.0 / 250 , 1.0 / 320 , 1.0 / 400 , 1.0 / 500 , 1.0 / 640 , 1.0 / 800 , 1.0 / 1000 , 1.0 / 1250 , 1.0 / 1600 , 1.0 / 2000 , 1.0 / 2500 , 1.0 / 3200 , 1.0 / 4000 } ;
# define SHUTTERTIMES2_MAXINDEX 51
2018-05-03 13:53:37 +00:00
float shuttertimes3 [ ] = { 3600 , 2400 , 1800 , 1200 , 900 , 600 , 420 , 300 , 210 , 150 , 100 , 60 , 45 , 30 , 20 , 16 , 10 , 8 , 6 , 4 , 3 , 2 , 1.5 , 1 , 0.5 , 0.25 , 0.125 , 1.0 / 16 } ;
# define SHUTTERTIMES3_MAXINDEX 27
String settingsnameShutterSelectionMode [ ] = { " Analog " , " Digital " , " Pinhole " } ; //names for tables
# define MAXIMUM_SHUTTERSELECTIONMODES 3
//Aperature numbers https://en.wikipedia.org/wiki/F-number
float aperaturesFull [ ] = { 1 , 1.4 , 2 , 2.8 , 4 , 5.6 , 8 , 11 , 16 , 22 , 32 , 45 } ;
# define APERATURESFULL_MAXINDEX 11
float aperaturesHalf [ ] = { 1 , 1.2 , 1.4 , 1.7 , 2 , 2.4 , 2.8 , 3.4 , 4 , 4.8 , 5.6 , 6.7 , 8 , 9.5 , 11 , 13 , 16 , 19 , 22 , 27 , 32 , 38 , 45 } ;
# define APERATURESHALF_MAXINDEX 22
2018-03-22 07:57:53 +00:00
float aperaturesThird [ ] = { 1 , 1.1 , 1.2 , 1.4 , 1.6 , 1.8 , 2 , 2.2 , 2.5 , 2.8 , 3.2 , 3.5 , 4 , 4.5 , 5.0 , 5.6 , 6.3 , 7.1 , 8 , 9 , 10 , 11 , 13 , 14 , 16 , 18 , 20 , 22 , 25 , 29 , 32 , 36 , 40 , 45 } ;
2018-03-23 19:21:27 +00:00
# define APERATURESTHIRD_MAXINDEX 33
2018-03-22 07:57:53 +00:00
String settingsnameAperatureSelectionMode [ ] = { " Full " , " Half " , " Third " } ; //names for tables
# define MAXIMUM_APERATURESELECTIONMODES 3
2018-05-03 13:53:37 +00:00
float isoFull [ ] = { 0.78 , 1.56 , 3.13 , 6.25 , 12.5 , 25 , 50 , 100 , 200 , 400 , 800 , 1600 , 3200 , 6400 , 12500 , 25600 } ;
uint8_t isoFullDIN [ ] = { 0 , 3 , 6 , 9 , 12 , 15 , 18 , 21 , 24 , 27 , 30 , 33 , 36 , 39 , 42 , 45 } ;
float isoThird [ ] = { 0.78 , 0.98 , 1.24 , 1.56 , 1.97 , 2.48 , 3.13 , 3.93 , 4.96 , 6.25 , 7.87 , 9.92 , 12.5 , 16 , 20 , 25 , 32 , 40 , 50 , 64 , 80 , 100 , 125 , 160 , 200 , 250 , 320 , 400 , 500 , 640 , 800 , 1000 , 1250 , 1600 , 2000 , 2500 , 3200 , 4000 , 5000 , 6400 , 8000 , 10000 , 12500 , 16000 , 20000 , 25600 } ;
uint8_t isoThirdDIN [ ] = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , 26 , 27 , 28 , 29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 56 } ;
2018-03-22 07:57:53 +00:00
long loopmillis = 0 ; //only use one millis reading each loop
long last_ldrReading = 0 ;
2018-04-14 11:56:49 +00:00
long last_ldrReadingFilter = 0 ;
2018-03-23 19:21:27 +00:00
long last_incidentReading = 0 ;
2018-03-22 07:57:53 +00:00
long millis_lastchange = 0 ;
long millis_lastinput = 0 ;
2018-04-14 11:56:49 +00:00
long millis_ledoff = 0 ; //for led blink
long millis_opened_meteringmodeselection = 0 ; //time when meteringmodeselecten was opened (for led flashlight timing)
# define DELAY_METERINGMODESELECTION_FLASHLIGHT 2000
2018-03-22 07:57:53 +00:00
2018-03-26 15:55:17 +00:00
2018-03-22 07:57:53 +00:00
long timebuttonpressed_trigger ;
long timebuttonpressed_left ;
long timebuttonpressed_center ;
long timebuttonpressed_right ;
//Short press (true when button short pressed, on release)
boolean button_trigger = false ;
boolean button_left = false ;
boolean button_center = false ;
boolean button_right = false ;
//long press (true when button is held down for BUTTONTIMEHOLD, on time elapsed)
boolean button_hold_trigger = false ;
boolean button_hold_left = false ;
boolean button_hold_center = false ;
boolean button_hold_right = false ;
2018-05-03 08:01:41 +00:00
//even longer press
boolean button_hold_long_trigger = false ;
long timebuttonpressed_trigger_long = 0 ;
2018-04-15 10:13:08 +00:00
float vbat = 100 ;
2018-03-22 07:57:53 +00:00
struct Settings {
uint8_t minimumAperatureIndex ; //see corresponding aperatures table
uint8_t aperatureSelectionMode ; //1=Full, 2=Half, 3=Third
uint8_t shutterSelectionMode ; //index for which shuttertimes table to use
uint8_t ISOSelectionMode ; //1=Full, 2=Thirds
2018-04-17 09:36:19 +00:00
uint8_t manualev_moveamount_frac ; // 1=1ev, 2=1/2ev, 3=1/3 ev
2018-03-22 07:57:53 +00:00
} ;
2018-04-17 09:36:19 +00:00
# define MAXIMUM_MANUAL_EV_MOVEAMOUNT_FRAC 3
2018-03-22 07:57:53 +00:00
2018-04-14 11:56:49 +00:00
bool settingsStructEqual ( Settings a , Settings b ) {
if ( a . minimumAperatureIndex ! = b . minimumAperatureIndex | | a . aperatureSelectionMode ! = b . aperatureSelectionMode | | a . shutterSelectionMode ! = b . shutterSelectionMode | | a . ISOSelectionMode ! = b . ISOSelectionMode ) {
return false ;
}
return true ;
}
2018-04-17 09:36:19 +00:00
Settings userSettings = { 1 , 1 , 1 , 2 , 1 } ;
2018-04-14 11:56:49 +00:00
Settings eeprom_userSettings ; //to store current eeprom status
2018-03-22 07:57:53 +00:00
# define OLED_RESET 4
Adafruit_SSD1306 display ( OLED_RESET ) ;
2018-04-14 11:56:49 +00:00
2018-03-23 19:21:27 +00:00
uint16_t incident = 0 ; //incident reading from bh1750
2018-03-22 07:57:53 +00:00
uint16_t analog_low = 0 ; //better for low light
uint16_t analog_high = 0 ; //better for bright light (higher pulldown resistor for ldr)
2018-04-14 11:56:49 +00:00
uint16_t analog_reading_filtering = 0 ;
uint8_t analog_reading_count = 0 ;
2018-03-22 07:57:53 +00:00
float ev = 0 ; //calculated EV from LDR readings (reflected) or from Luxmeter (incident)
2018-04-16 09:08:12 +00:00
float ev_min = - 255 , ev_max = - 255 , ev_last = - 255 ;
2018-03-22 07:57:53 +00:00
float showAperature = 0 ;
float showShutter = 0 ;
2018-04-16 09:08:12 +00:00
bool manualev_mode = false ; //manual ev change by left/right
2018-03-22 07:57:53 +00:00
//Usersettings
float setAperature = 8 ; //set to use aperature. 0 for auto
float setShutter = 0 ; //set to use shutter time, 0 for auto
2018-05-03 13:53:37 +00:00
float setISO = 100 ; //set to ISO
2018-03-22 07:57:53 +00:00
2018-04-14 11:56:49 +00:00
float eeprom_setAperature = 0 ; //set to use aperature. 0 for auto
float eeprom_setShutter = 0 ; //set to use shutter time, 0 for auto
uint16_t eeprom_setISO = 0 ; //set to ISO
# define EEPROMADDRESS_APERATURE 0x801F000 //float = 32bit = 4byte
# define EEPROMADDRESS_SHUTTER 0x801F004 //float = 32bit = 4byte
# define EEPROMADDRESS_ISO 0x801F008 //uint16_T 16bit = 2byte
# define EEPROMADDRESS_METERINGMODE 0x801F00A //uint8_t 1byte
# define EEPROMADDRESS_USERSETTINGS 0x801F00B //Settings struct
2018-03-22 07:57:53 +00:00
enum displaymode {
lightmeter ,
2018-03-26 15:55:17 +00:00
settings ,
meteringmodeselection
2018-03-22 07:57:53 +00:00
} ;
displaymode displaymode = lightmeter ;
uint8_t settings_selectedItem = 0 ; //in settings display
2018-04-17 09:36:19 +00:00
String settingStrings [ ] = { " ISO: " , " F-Stops: " , " Timetable: " , " EV Step: " , " Turn Off " } ;
# define SETTINGS_SELECTEDITEM_MAX 4 //inclusive. 2 means 3 items available
2018-03-22 07:57:53 +00:00
boolean settings_itemActive = false ; //item in settings selected to change value
2018-04-14 11:56:49 +00:00
# define DISPLAY_UPDATEDELAY 200
long last_displayupdate = 0 ;
2018-03-22 07:57:53 +00:00
2018-03-23 19:21:27 +00:00
# define METERINGMODE_REFLECTIVE 0
# define METERINGMODE_INCIDENT 1
uint8_t meteringmode = METERINGMODE_REFLECTIVE ;
2018-04-14 11:56:49 +00:00
uint8_t eeprom_meteringmode = 0 ;
2018-03-23 19:21:27 +00:00
2018-04-14 11:56:49 +00:00
bool eeprom_red = false ; //false, if eeprom need to be red
2018-03-22 07:57:53 +00:00
2018-03-26 15:55:17 +00:00
2018-04-14 11:56:49 +00:00
bool debug_printreadings = false ;
uint16_t debug_analog_high = 0 ;
uint16_t debug_analog_low = 0 ;
2018-03-26 15:55:17 +00:00
2018-03-22 07:57:53 +00:00
char tempstring [ 16 ] ; //for dtostrf //dtostrf(modefactor,1,3,tempstring);
# if (SSD1306_LCDHEIGHT != 64)
# error("Height incorrect, please fix Adafruit_SSD1306.h!");
# endif
2018-03-26 15:55:17 +00:00
//Icons. Exported as .xbm from gimp and renamed to .c
# include "icon_incident.c"
# include "icon_spot.c"
2018-03-25 19:20:39 +00:00
2018-03-26 15:55:17 +00:00
# include "icon_arrow.c"
# include "icon_one_third.c"
# include "icon_one_half.c"
# include "icon_two_third.c"
2018-03-25 19:20:39 +00:00
2018-03-26 15:55:17 +00:00
void setup ( ) {
2018-04-14 11:56:49 +00:00
Serial . begin ( 115200 ) ;
2018-03-22 07:57:53 +00:00
Serial . println ( " Started " ) ;
2018-03-23 19:21:27 +00:00
Serial . println ( " Init Display " ) ;
2018-03-22 07:57:53 +00:00
display . begin ( SSD1306_SWITCHCAPVCC , 0x3C ) ;
display . clearDisplay ( ) ;
display . display ( ) ;
2018-03-23 19:21:27 +00:00
Serial . println ( " Init BH1750 " ) ;
lightMeter . begin ( BH1750_CONTINUOUS_HIGH_RES_MODE_2 ) ; //max reading=54612
2018-03-22 07:57:53 +00:00
//set measurement time (for higher resolution) http://www.raspberry-pi-geek.de/Magazin/2015/04/Digital-Light-Sensor-BH1750-am-Raspberry-Pi
//lightMeter.write8(71); //01000111 //high bit: 01000xxx bits 7,6,5
//lightMeter.write8(126); //01111110 //log bit: 011xxxxx bits 4,3,2,1,0
pinMode ( PIN_LDR , INPUT_ANALOG ) ;
pinMode ( PIN_VBAT , INPUT_ANALOG ) ;
pinMode ( PIN_TRIGGER , INPUT_PULLUP ) ;
pinMode ( PIN_BTNLEFT , INPUT_PULLUP ) ;
pinMode ( PIN_BTNCENTER , INPUT_PULLUP ) ;
pinMode ( PIN_BTNRIGHT , INPUT_PULLUP ) ;
pinMode ( PIN_BRIGHTMODE , OUTPUT ) ;
digitalWrite ( PIN_BRIGHTMODE , LOW ) ;
pinMode ( PIN_ON , OUTPUT ) ;
digitalWrite ( PIN_ON , HIGH ) ;
2018-04-14 11:56:49 +00:00
pinMode ( PIN_LED , OUTPUT ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ; //blink led on
2018-04-14 11:56:49 +00:00
delay ( 50 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ; //LED OFF //blink led off
2018-03-22 07:57:53 +00:00
millis_lastchange = millis ( ) ;
Serial . println ( " Initialized " ) ;
2018-04-14 11:56:49 +00:00
if ( ! digitalRead ( PIN_TRIGGER ) ) { //hold trigger button during power on activates serial debug printing
debug_printreadings = true ;
}
2018-03-22 07:57:53 +00:00
2018-04-15 10:13:08 +00:00
2018-03-22 07:57:53 +00:00
}
2018-04-14 11:56:49 +00:00
bool saveSettingsToEEPROM ( bool force ) {
bool _eepromwritten = false ;
//checks and writes changes to eeprom
if ( eeprom_setAperature ! = setAperature | | force ) { //value change or write forced
EEPROM_writeAnything ( EEPROMADDRESS_APERATURE , setAperature ) ;
_eepromwritten = true ;
}
if ( eeprom_setShutter ! = setShutter | | force ) { //value change or write forced
EEPROM_writeAnything ( EEPROMADDRESS_SHUTTER , setShutter ) ;
_eepromwritten = true ;
}
if ( eeprom_setISO ! = setISO | | force ) { //value change or write forced
EEPROM_writeAnything ( EEPROMADDRESS_ISO , setISO ) ;
_eepromwritten = true ;
}
if ( eeprom_meteringmode ! = meteringmode | | force ) { //one of the values change or write forced
EEPROM_writeAnything ( EEPROMADDRESS_METERINGMODE , meteringmode ) ;
_eepromwritten = true ;
}
if ( ! settingsStructEqual ( eeprom_userSettings , userSettings ) | | force ) { //one of the values change or write forced
EEPROM_writeAnything ( EEPROMADDRESS_USERSETTINGS , userSettings ) ;
_eepromwritten = true ;
}
return _eepromwritten ;
}
2018-03-22 07:57:53 +00:00
void loop ( ) {
loopmillis = millis ( ) ; //read millis for this cycle
2018-04-14 11:56:49 +00:00
if ( ! eeprom_red ) { //only executed one time
eeprom_red = true ;
readEEPROM ( ) ;
}
2018-03-22 07:57:53 +00:00
handleInputs ( ) ;
2018-03-26 15:55:17 +00:00
calculateFromEV ( ) ;
2018-03-22 07:57:53 +00:00
updateDisplay ( ) ;
2018-04-14 11:56:49 +00:00
checkLED ( ) ;
}
void readEEPROM ( ) {
2018-03-22 07:57:53 +00:00
2018-04-14 11:56:49 +00:00
if ( ! digitalRead ( PIN_BTNLEFT ) & & ! digitalRead ( PIN_BTNCENTER ) & & ! digitalRead ( PIN_BTNRIGHT ) ) { //push all front buttons (left, center, right) to restore default settings
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ;
2018-04-14 11:56:49 +00:00
delay ( 1000 ) ; //1s led on confirmation
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ; //LED OFF
2018-04-14 11:56:49 +00:00
saveSettingsToEEPROM ( true ) ; //force writing. userSettings contains the default values at this point
delay ( 200 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ;
2018-04-14 11:56:49 +00:00
delay ( 200 ) ; //1s led on confirmation
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ; //LED OFF
2018-04-14 11:56:49 +00:00
delay ( 200 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ;
2018-04-14 11:56:49 +00:00
delay ( 200 ) ; //1s led on confirmation
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ; //LED OFF
2018-04-14 11:56:49 +00:00
delay ( 1000 ) ;
}
2018-03-22 07:57:53 +00:00
2018-04-14 11:56:49 +00:00
//read current eeprom
EEPROM_readAnything ( EEPROMADDRESS_APERATURE , eeprom_setAperature ) ;
EEPROM_readAnything ( EEPROMADDRESS_SHUTTER , eeprom_setShutter ) ;
EEPROM_readAnything ( EEPROMADDRESS_ISO , eeprom_setISO ) ;
EEPROM_readAnything ( EEPROMADDRESS_METERINGMODE , eeprom_meteringmode ) ;
EEPROM_readAnything ( EEPROMADDRESS_USERSETTINGS , eeprom_userSettings ) ;
Serial . println ( " " ) ;
Serial . println ( " EEPROM eeprom settings " ) ;
Serial . println ( eeprom_setAperature ) ;
Serial . println ( eeprom_setShutter ) ;
Serial . println ( eeprom_setISO ) ;
Serial . println ( " EEPROM eeprom_userSettings " ) ;
Serial . println ( eeprom_userSettings . minimumAperatureIndex ) ;
Serial . println ( eeprom_userSettings . aperatureSelectionMode ) ;
Serial . println ( eeprom_userSettings . shutterSelectionMode ) ;
Serial . println ( eeprom_userSettings . ISOSelectionMode ) ;
Serial . println ( " " ) ;
if ( eeprom_userSettings . minimumAperatureIndex = = 255 ) { //after flashing eeprom contains FF.., check one value
for ( int i = 0 ; i < 10 ; i + + ) { //blink a few times to show that eeprom was clean
delay ( 50 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ;
2018-04-14 11:56:49 +00:00
delay ( 50 ) ; //1s led on confirmation
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ;
2018-04-14 11:56:49 +00:00
}
} else { //
//apply
setAperature = eeprom_setAperature ;
setShutter = eeprom_setShutter ;
setISO = eeprom_setISO ;
meteringmode = eeprom_meteringmode ;
userSettings = eeprom_userSettings ;
}
2018-03-22 07:57:53 +00:00
}
2018-04-14 11:56:49 +00:00
2018-03-22 07:57:53 +00:00
void handleInputs ( )
{
//Short press (true when button short pressed, on release)
button_trigger = false ;
button_left = false ;
button_center = false ;
button_right = false ;
//long press (true when button is held down for BUTTONTIMEHOLD, on time elapsed)
button_hold_trigger = false ;
button_hold_left = false ;
button_hold_center = false ;
button_hold_right = false ;
2018-05-03 08:01:41 +00:00
//even longer press
button_hold_long_trigger = false ;
2018-03-22 07:57:53 +00:00
if ( millis ( ) - millis_lastinput > DEBOUNCETIME ) //Button debouncing
{
//Trigger
if ( timebuttonpressed_trigger = = 0 & & ! digitalRead ( PIN_TRIGGER ) ) { //first time pressed down. (low when pressed)
timebuttonpressed_trigger = loopmillis ; //set time of button press
2018-05-03 08:01:41 +00:00
timebuttonpressed_trigger_long = loopmillis ; //set time of button press, for long hold timing
2018-03-22 07:57:53 +00:00
} else if ( timebuttonpressed_trigger ! = 0 & & digitalRead ( PIN_TRIGGER ) ) { //button released (was pressed)
if ( loopmillis - timebuttonpressed_trigger < BUTTONTIMEHOLD ) { //short press
button_trigger = true ;
}
timebuttonpressed_trigger = 0 ; //re-enable after short press and release from hold
} else if ( loopmillis - timebuttonpressed_trigger > = BUTTONTIMEHOLD & & timebuttonpressed_trigger > 0 ) { //held down long enough and not already hold triggered
button_hold_trigger = true ;
timebuttonpressed_trigger = - 1 ; //-1 as flag for hold triggered
}
2018-05-03 08:01:41 +00:00
if ( timebuttonpressed_trigger_long > 0 & & loopmillis - timebuttonpressed_trigger_long > = BUTTONTIMEHOLDLONG & & ! digitalRead ( PIN_TRIGGER ) ) { //button held down even longer, set hold long flag for as long as button is down
button_hold_long_trigger = true ;
} else if ( timebuttonpressed_trigger_long > 0 & & digitalRead ( PIN_TRIGGER ) ) { //released
timebuttonpressed_trigger_long = 0 ; //reset long hold timing
}
2018-03-22 07:57:53 +00:00
//Left
if ( timebuttonpressed_left = = 0 & & ! digitalRead ( PIN_BTNLEFT ) ) { //first time pressed down. (low when pressed)
timebuttonpressed_left = loopmillis ; //set time of button press
} else if ( timebuttonpressed_left ! = 0 & & digitalRead ( PIN_BTNLEFT ) ) { //button released (was pressed)
if ( loopmillis - timebuttonpressed_left < BUTTONTIMEHOLD ) { //short press
button_left = true ;
}
timebuttonpressed_left = 0 ; //re-enable after short press and release from hold
} else if ( loopmillis - timebuttonpressed_left > = BUTTONTIMEHOLD & & timebuttonpressed_left > 0 ) { //held down long enough and not already hold triggered
button_hold_left = true ;
timebuttonpressed_left = - 1 ; //-1 as flag for hold triggered
}
//Center
if ( timebuttonpressed_center = = 0 & & ! digitalRead ( PIN_BTNCENTER ) ) { //first time pressed down. (low when pressed)
timebuttonpressed_center = loopmillis ; //set time of button press
} else if ( timebuttonpressed_center ! = 0 & & digitalRead ( PIN_BTNCENTER ) ) { //button released (was pressed)
if ( loopmillis - timebuttonpressed_center < BUTTONTIMEHOLD ) { //short press
button_center = true ;
}
timebuttonpressed_center = 0 ; //re-enable after short press and release from hold
} else if ( loopmillis - timebuttonpressed_center > = BUTTONTIMEHOLD & & timebuttonpressed_center > 0 ) { //held down long enough and not already hold triggered
button_hold_center = true ;
timebuttonpressed_center = - 1 ; //-1 as flag for hold triggered
}
//Right
if ( timebuttonpressed_right = = 0 & & ! digitalRead ( PIN_BTNRIGHT ) ) { //first time pressed down. (low when pressed)
timebuttonpressed_right = loopmillis ; //set time of button press
} else if ( timebuttonpressed_right ! = 0 & & digitalRead ( PIN_BTNRIGHT ) ) { //button released (was pressed)
if ( loopmillis - timebuttonpressed_right < BUTTONTIMEHOLD ) { //short press
button_right = true ;
}
timebuttonpressed_right = 0 ; //re-enable after short press and release from hold
} else if ( loopmillis - timebuttonpressed_right > = BUTTONTIMEHOLD & & timebuttonpressed_right > 0 ) { //held down long enough and not already hold triggered
button_hold_right = true ;
timebuttonpressed_right = - 1 ; //-1 as flag for hold triggered
}
}
/*
if ( button_trigger | | button_left | | button_center | | button_right ) {
Serial . println ( " Buttons short: " ) ;
Serial . print ( button_trigger ) ;
Serial . print ( button_left ) ;
Serial . print ( button_center ) ;
Serial . println ( button_right ) ;
}
if ( button_hold_trigger | | button_hold_left | | button_hold_center | | button_hold_right ) {
Serial . println ( " Buttons long: " ) ;
Serial . print ( button_hold_trigger ) ;
Serial . print ( button_hold_left ) ;
Serial . print ( button_hold_center ) ;
Serial . println ( button_hold_right ) ;
}
*/
//Voltage
2018-04-15 10:13:08 +00:00
float _vbat = map ( analogRead ( PIN_VBAT ) , 0 , 3560 , 0 , 8200 ) / 1000.0 ; //180k and 300k voltage divider. 8,4V -> 3,15V=3910
if ( _vbat < vbat ) {
vbat = _vbat ; //voltage can only decrease
}
2018-03-22 07:57:53 +00:00
2018-03-23 19:21:27 +00:00
//LDR
2018-04-14 11:56:49 +00:00
if ( loopmillis - last_ldrReadingFilter > LDRFILTERDELAY & & loopmillis - last_ldrReading > LDRSWITCHDELAY ) //multiple successive reading for filtering. each LDRFILTERDELAY ms and wait LDRSWITCHDELAY for first reading
{
analog_reading_filtering + = analogRead ( PIN_LDR ) ;
analog_reading_count + + ;
last_ldrReadingFilter = loopmillis ;
}
if ( loopmillis - last_ldrReading > LDRDELAY ) //time over for one reading (low or high)
2018-03-22 07:57:53 +00:00
{
if ( ! digitalRead ( PIN_BRIGHTMODE ) ) {
2018-04-14 11:56:49 +00:00
analog_low = analog_reading_filtering / analog_reading_count ;
2018-03-22 07:57:53 +00:00
} else {
2018-04-14 11:56:49 +00:00
analog_high = analog_reading_filtering / analog_reading_count ;
if ( debug_printreadings ) {
Serial . print ( analog_low ) ; //for calibration output
Serial . print ( " ; " ) ;
Serial . println ( analog_high ) ;
}
2018-03-22 07:57:53 +00:00
}
2018-04-14 11:56:49 +00:00
/*Serial.print(analog_reading_count);
Serial . print ( " value= " ) ;
Serial . println ( analog_reading_filtering ) ; */
analog_reading_count = 0 ; //reset
analog_reading_filtering = 0 ; //reset
2018-03-22 07:57:53 +00:00
digitalWrite ( PIN_BRIGHTMODE , ! digitalRead ( PIN_BRIGHTMODE ) ) ; //switch modes
last_ldrReading = loopmillis ;
}
2018-03-23 19:21:27 +00:00
//Lightsensor BH1750
if ( loopmillis - last_incidentReading > INCIDENTDELAY )
{
incident = lightMeter . readLightLevel ( ) ; //value in lux from sensor
last_incidentReading = loopmillis ;
}
2018-03-22 07:57:53 +00:00
//Test asdf
/*
if ( ! digitalRead ( PIN_TRIGGER ) ) {
Serial . println ( " roundAperature " ) ;
for ( float i = 0.1 ; i < 30 ; i + = 0.5 ) {
Serial . print ( i ) ;
Serial . print ( " -> " ) ;
Serial . println ( roundAperature ( i , 1 ) ) ;
}
Serial . println ( " roundShutter " ) ;
for ( float i = 1.0 / 8000 ; i < 32 ; i * = 2 ) {
Serial . print ( i , 6 ) ;
Serial . print ( " -> " ) ;
2018-04-15 10:13:08 +00:00
Serial . print ( roundShutter ( i , 2 ) , 6 ) ;
2018-03-22 07:57:53 +00:00
Serial . print ( " -- " ) ;
2018-04-15 10:13:08 +00:00
Serial . println ( reciprocFloat ( roundShutter ( i , 2 ) ) ) ;
}
2018-03-22 07:57:53 +00:00
}
2018-04-15 10:13:08 +00:00
2018-03-22 07:57:53 +00:00
2018-04-15 10:13:08 +00:00
Serial . println ( " calculateShutter at iso 100 f2.8 " ) ;
for ( float i = - 2 ; i < 18 ; i + = 0.25 ) {
2018-03-22 07:57:53 +00:00
Serial . print ( i ) ;
Serial . print ( " -> " ) ;
2018-04-15 10:13:08 +00:00
float test_calcshutter = calculateShutter ( i , ( uint16_t ) 100 , 2.8 ) ;
//Serial.println(test_calcshutter,6);
float test_showShutter = roundShutter ( test_calcshutter , 2 ) ;
Serial . print ( " rounded Shutter from " ) ; Serial . print ( test_calcshutter , 6 ) ; Serial . print ( " to " ) ; Serial . println ( test_showShutter , 6 ) ; //asdf
if ( test_showShutter > 0.25 ) //check shuttertime
{ //show full seconds
Serial . print ( " int= " ) ;
Serial . print ( int ( test_showShutter ) ) ;
if ( test_showShutter - int ( test_showShutter ) > 0 ) { //has decimals
Serial . print ( " , " ) ;
Serial . print ( ( int ) round ( ( test_showShutter - int ( test_showShutter ) ) * 10 ) ) ; //show one decimal
}
Serial . println ( " " ) ;
} else { //show fraction of a second
Serial . print ( " frac= 1/ " ) ;
int _frac_showShutter = ( int ) ( ( 1.0f / ( ( int ) ( test_showShutter * 1000000 ) ) ) * 1000000 ) ;
Serial . print ( _frac_showShutter ) ;
Serial . println ( " " ) ;
}
2018-03-22 07:57:53 +00:00
}
2018-04-15 10:13:08 +00:00
Serial . println ( " calculateAperature at iso 100 1/250s " ) ;
for ( float i = - 2 ; i < 18 ; i + = 0.25 ) {
2018-03-22 07:57:53 +00:00
Serial . print ( i ) ;
Serial . print ( " -> " ) ;
2018-04-15 10:13:08 +00:00
Serial . println ( calculateAperature ( i , ( uint16_t ) 100 , 1.0 / 250 ) , 6 ) ;
2018-03-22 07:57:53 +00:00
}
2018-04-15 10:13:08 +00:00
} */
2018-03-22 07:57:53 +00:00
switch ( displaymode ) {
case lightmeter :
handleInputs_Lightmeter ( ) ;
break ;
case settings :
handleInputs_Settings ( ) ;
break ;
2018-03-26 15:55:17 +00:00
case meteringmodeselection :
handleInputs_Meteringmodeselection ( ) ;
break ;
2018-03-22 07:57:53 +00:00
}
if ( millis ( ) - millis_lastchange > TIME_AUTOPOWEROFF ) {
2018-04-14 11:56:49 +00:00
poweroff ( ) ;
2018-03-22 07:57:53 +00:00
}
if ( button_trigger | | button_left | | button_center | | button_right ) {
2018-03-26 15:55:17 +00:00
millis_lastchange = millis ( ) ; //for auto poweroff and auto closes
2018-03-22 07:57:53 +00:00
millis_lastinput = millis ( ) ; //for debouncing
}
}
2018-04-14 11:56:49 +00:00
void poweroff ( ) {
bool _eepromwritten = saveSettingsToEEPROM ( false ) ; //save only changes to eeprom
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ; //Blink led
2018-04-14 11:56:49 +00:00
delay ( 100 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ;
2018-04-14 11:56:49 +00:00
if ( _eepromwritten ) {
delay ( 100 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 255 ) ;
2018-04-14 11:56:49 +00:00
delay ( 100 ) ;
2018-04-16 09:08:12 +00:00
analogWrite ( PIN_LED , 0 ) ;
2018-04-14 11:56:49 +00:00
}
digitalWrite ( PIN_ON , LOW ) ; //Turn off hardware latch
}
2018-03-22 07:57:53 +00:00
void handleInputs_Lightmeter ( )
{
2018-03-26 15:55:17 +00:00
if ( button_center ) { //open meteringmode selection
displaymode = meteringmodeselection ;
2018-04-14 11:56:49 +00:00
millis_opened_meteringmodeselection = loopmillis ;
2018-03-26 15:55:17 +00:00
}
2018-03-22 07:57:53 +00:00
if ( button_hold_center ) { //Go to Settings
displaymode = settings ;
}
2018-03-26 15:55:17 +00:00
2018-03-22 07:57:53 +00:00
2018-04-16 09:08:12 +00:00
if ( manualev_mode ) { //Manual Ev
2018-03-22 07:57:53 +00:00
//Value Change
if ( button_left ) {
2018-04-17 09:36:19 +00:00
ev - = 1.0 / userSettings . manualev_moveamount_frac ;
2018-03-22 07:57:53 +00:00
}
if ( button_right ) {
2018-04-17 09:36:19 +00:00
ev + = 1.0 / userSettings . manualev_moveamount_frac ;
2018-03-22 07:57:53 +00:00
}
//Change Mode
2018-04-16 09:08:12 +00:00
if ( button_hold_left ) { // Manual Ev -> Av
2018-03-22 07:57:53 +00:00
setAperature = showAperature ;
setShutter = 0 ;
2018-04-16 09:08:12 +00:00
manualev_mode = false ;
}
if ( button_hold_right ) { // Manual Ev -> T
setShutter = showShutter ;
setAperature = 0 ;
manualev_mode = false ;
2018-03-22 07:57:53 +00:00
}
} else if ( setShutter = = 0 ) { //Aperature Priority
2018-04-16 09:08:12 +00:00
manualev_mode = false ;
2018-03-22 07:57:53 +00:00
//Value Change
if ( button_left ) {
changeAperature ( 1 ) ; //Decrement Aperature
}
if ( button_right ) {
changeAperature ( - 1 ) ; //Increment Aperature
}
//Change Mode
2018-04-16 09:08:12 +00:00
if ( button_hold_left ) { //Av -> Manual Ev
manualev_mode = true ;
2018-03-22 07:57:53 +00:00
}
if ( button_hold_right ) { //Av -> T
setShutter = showShutter ;
setAperature = 0 ;
}
} else if ( setAperature = = 0 ) { //Shutter Priority
2018-04-16 09:08:12 +00:00
manualev_mode = false ;
2018-03-22 07:57:53 +00:00
//Value Change
if ( button_left ) {
changeShutter ( 1 ) ; //Decrement Aperature
}
if ( button_right ) {
changeShutter ( - 1 ) ; //Increment Aperature
}
//Change Mode
if ( button_hold_left ) { //T -> Av
setAperature = showAperature ;
setShutter = 0 ;
}
2018-04-16 09:08:12 +00:00
if ( button_hold_right ) { //T -> Manual Ev
manualev_mode = true ;
2018-03-22 07:57:53 +00:00
}
}
2018-05-03 08:01:41 +00:00
if ( button_trigger | | button_hold_long_trigger ) { //Trigger or very long hold
2018-04-16 09:08:12 +00:00
ev_last = ev ;
2018-03-26 15:55:17 +00:00
ev = getEV ( ) ; //set ev to current measurement by selected mode
2018-04-16 09:08:12 +00:00
if ( ev < ev_min | | ev_min < - 254 ) { //new ev is smaller than last or ev_min wasn set
ev_min = ev ;
2018-04-17 09:36:19 +00:00
}
if ( ev > ev_max ) { //new ev is greater
2018-04-16 09:08:12 +00:00
ev_max = ev ;
}
2018-04-14 11:56:49 +00:00
debug_analog_high = analog_high ;
debug_analog_low = analog_low ;
2018-04-16 09:08:12 +00:00
//LED Brightness on trigger
uint8_t triggerblinkbrightness = 255 ;
if ( ev < 4 ) { //dim led when dark
2018-05-03 08:01:41 +00:00
triggerblinkbrightness = map ( ev , 2 , 4 , 5 , 255 ) ;
2018-04-17 09:36:19 +00:00
}
if ( ev < 2 ) {
2018-05-03 08:01:41 +00:00
triggerblinkbrightness = 5 ;
}
if ( button_hold_long_trigger ) { //low brightness on long hold
triggerblinkbrightness = 5 ;
2018-04-16 09:08:12 +00:00
}
blinkLED ( 20 , triggerblinkbrightness ) ;
}
if ( button_hold_trigger ) { //Trigger hold, resets ev_min,max and last
ev_min = - 255 ; //placeholder for "not set"
ev_max = - 255 ;
ev_last = - 255 ;
//LED Brightness on trigger
uint8_t triggerblinkbrightness = 255 ;
if ( ev < 4 ) { //dim led when dark
triggerblinkbrightness = map ( ev , 4 , 0 , 255 , 50 ) ;
}
blinkLED ( 400 , triggerblinkbrightness ) ;
2018-03-26 15:55:17 +00:00
}
2018-05-03 08:01:41 +00:00
2018-03-22 07:57:53 +00:00
}
2018-04-14 11:56:49 +00:00
2018-03-22 07:57:53 +00:00
void handleInputs_Settings ( )
{
if ( button_hold_center ) { //Go to Lightmeter
2018-04-15 10:13:08 +00:00
settings_itemActive = false ; //deselect item
2018-03-22 07:57:53 +00:00
displaymode = lightmeter ;
}
if ( ! settings_itemActive ) { //select items
if ( button_left ) {
if ( settings_selectedItem > 0 ) { //not first item
settings_selectedItem - = 1 ;
}
}
if ( button_right ) {
if ( settings_selectedItem < SETTINGS_SELECTEDITEM_MAX ) { //not last item
settings_selectedItem + = 1 ;
}
}
if ( button_center ) {
settings_itemActive = true ; //select item to change value
}
} else { //item selected to change value
switch ( settings_selectedItem )
{
case 0 : //ISO
if ( button_left ) {
changeISO ( - 1 ) ;
}
if ( button_right ) {
changeISO ( 1 ) ;
}
break ;
case 1 : //Aperature Selection Mode
if ( button_left ) {
if ( userSettings . aperatureSelectionMode > 1 ) {
userSettings . aperatureSelectionMode - = 1 ;
}
}
if ( button_right ) {
if ( userSettings . aperatureSelectionMode < MAXIMUM_APERATURESELECTIONMODES ) {
userSettings . aperatureSelectionMode + = 1 ;
}
}
break ;
case 2 : //Shutter Selection Mode
if ( button_left ) {
if ( userSettings . shutterSelectionMode > 1 ) {
userSettings . shutterSelectionMode - = 1 ;
}
}
if ( button_right ) {
if ( userSettings . shutterSelectionMode < MAXIMUM_SHUTTERSELECTIONMODES ) {
userSettings . shutterSelectionMode + = 1 ;
}
}
break ;
2018-04-17 09:36:19 +00:00
case 3 : //manual ev moveamount
if ( button_left ) {
if ( userSettings . manualev_moveamount_frac > 1 ) {
userSettings . manualev_moveamount_frac - = 1 ;
}
}
if ( button_right ) {
if ( userSettings . manualev_moveamount_frac < MAXIMUM_MANUAL_EV_MOVEAMOUNT_FRAC ) {
userSettings . manualev_moveamount_frac + = 1 ;
}
}
break ;
case 4 : //Turn Off
2018-04-14 11:56:49 +00:00
poweroff ( ) ;
2018-03-22 07:57:53 +00:00
break ;
}
if ( button_center ) {
settings_itemActive = false ; //return to item selection
}
}
}
2018-03-26 15:55:17 +00:00
void handleInputs_Meteringmodeselection ( )
{
if ( button_center ) { //next or back to main screen
2018-04-16 09:08:12 +00:00
if ( millis ( ) - millis_lastchange < TIME_METERINGMODESELECTION_SHUTDOWN_SHORTCUT ) { //double press select (center) to poweroff
poweroff ( ) ; //Turn off
}
2018-03-26 15:55:17 +00:00
displaymode = lightmeter ;
}
if ( button_left ) {
meteringmode = METERINGMODE_REFLECTIVE ;
displaymode = lightmeter ; // and close
}
if ( button_right ) {
meteringmode = METERINGMODE_INCIDENT ;
displaymode = lightmeter ; // and close
}
if ( millis ( ) - millis_lastchange > TIME_METERINGMODESELECTION_CLOSE ) { //Automatic close
displaymode = lightmeter ;
}
}
2018-03-22 07:57:53 +00:00
float reciprocFloat ( float p ) {
if ( p < 1 ) {
return ( 1.0f / ( ( int ) ( p * 1000000 ) ) ) * 1000000 ;
} else {
return ( 1 / p ) ;
}
}
2018-03-26 15:55:17 +00:00
float getEV ( ) {
float _ev = 0 ;
if ( meteringmode = = METERINGMODE_REFLECTIVE ) { //### SPOT
2018-03-23 19:21:27 +00:00
//ev=map(analog_low,500, 3500 ,500, 1400)/100.0; //for testing
2018-04-14 11:56:49 +00:00
2018-04-14 15:02:00 +00:00
//first prototype.
//double highev=11.7400532 + 0.000216655133*analog_high + 0.00000111372253*pow(analog_high,2) + -0.000000000163800818 *pow(analog_high,3);
//double lowev=-0.763427709 + 0.0138031137*analog_low + -0.00000576990095*pow(analog_low,2) + 0.000000000871611285*pow(analog_low,3);
//calibration 20180413
2018-04-15 10:13:08 +00:00
//polynomial only
//double highev=4.76455098 + 0.00961533698*analog_high - 0.00000399325586*pow(analog_high,2) + 0.000000000654378697 *pow(analog_high,3);
//double lowev=-38.9534785 + 0.310426970*analog_low - 0.000769939297*pow(analog_low,2) + 0.000000639458491*pow(analog_low,3);
double log_low = log ( analog_low ) ;
//[-2.47999992e+02 5.59942657e+03 -4.74076773e+04 1.78389539e+05 -2.51728845e+05]
double lowev = - 251728.845 + 178389.539 * log_low - 47407.6773 * pow ( log_low , 2 ) + 5599.42657 * pow ( log_low , 3 ) - 247.999992 * pow ( log_low , 4 ) ;
double log_high = log ( analog_high ) ;
//[7.27310051e-02 -2.02919373e+00 2.23823220e+01 -1.22121768e+02 3.32574527e+02 -3.60445720e+02]
double highev = - 360.445720 + 332.574527 * log_high - 122.121768 * pow ( log_high , 2 ) + 22.3823220 * pow ( log_high , 3 ) - 2.02919373 * pow ( log_high , 4 ) + 0.0727310051 * pow ( log_high , 5 ) ;
/*Serial.print("analog_low="); //asdf
Serial . print ( analog_low ) ;
Serial . print ( " log_low= " ) ;
Serial . print ( log_low ) ;
Serial . print ( " lowev= " ) ;
Serial . println ( lowev ) ;
Serial . print ( " analog_high= " ) ;
Serial . print ( analog_high ) ;
Serial . print ( " log_high= " ) ;
Serial . print ( log_high ) ;
Serial . print ( " highev= " ) ;
Serial . println ( highev ) ; */
2018-04-14 11:56:49 +00:00
2018-03-23 19:21:27 +00:00
2018-04-15 10:13:08 +00:00
if ( highev > 2 ) {
2018-03-26 15:55:17 +00:00
_ev = highev ;
2018-04-15 10:13:08 +00:00
Serial . println ( " using high ev " ) ;
} else if ( lowev < 1 ) {
2018-03-26 15:55:17 +00:00
_ev = lowev ;
2018-04-15 10:13:08 +00:00
Serial . println ( " using low ev " ) ;
2018-03-23 19:21:27 +00:00
} else { //mix of both
2018-04-15 10:13:08 +00:00
float mix = min ( 1.0 , max ( 0.0 , ( lowev - 1 ) / ( 2 - 1 ) ) ) ; //0 to 1, 0-> use only lowev, 1-> use only highev
2018-03-26 15:55:17 +00:00
_ev = lowev * ( 1 - mix ) + highev * mix ;
2018-04-15 10:13:08 +00:00
Serial . print ( " mixing mix= " ) ;
Serial . println ( mix ) ;
2018-03-23 19:21:27 +00:00
}
2018-04-15 10:13:08 +00:00
Serial . print ( " EV= " ) ;
Serial . println ( _ev ) ;
2018-03-26 15:55:17 +00:00
} else if ( meteringmode = = METERINGMODE_INCIDENT ) { //### INCIDENT
2018-04-14 11:56:49 +00:00
_ev = luxToEv ( incident * INCIDENT_CORRECTION_FACTOR ) ;
2018-03-22 07:57:53 +00:00
}
2018-03-26 15:55:17 +00:00
return _ev ;
}
void calculateFromEV ( )
{
2018-03-22 07:57:53 +00:00
if ( setAperature > 0 ) { //Aperature Priority
showAperature = setAperature ; //use user set Aperature
showShutter = calculateShutter ( ev , setISO , setAperature ) ;
} else if ( setShutter > 0 ) { //Shutter Priority
showShutter = setShutter ; //use user set Shutter
showAperature = calculateAperature ( ev , setISO , setShutter ) ;
}
}
2018-03-23 19:21:27 +00:00
double evToLux ( double ev ) {
return pow ( 2 , ev ) * 2.5 ;
}
double luxToEv ( uint16_t lux ) {
if ( lux < = 2 ) {
return 0 ;
}
return log ( lux / 2.5 ) / log ( 2 ) ;
}
2018-04-15 10:13:08 +00:00
float calculateShutter ( float pEv , uint16_t pIso , float pAperature ) //returns calculated Shutter speed given Ev, ISO and Aperature
2018-03-22 07:57:53 +00:00
{
//EV = log2 ( 100* Aperature^2 / (ISO * Time ))
//100* Aperature^2 / (2^EV * ISO) = Time
return ( 100.0 * pow ( pAperature , 2 ) ) / ( pow ( 2 , pEv ) * pIso ) ;
}
float calculateAperature ( float pEv , uint16_t pIso , float pShutter ) //returns mathematical aperature in x1
{
//EV = log2 ( 100* Aperature^2 / (ISO * Time ))
// sqrt( 2^EV *(ISO * Time ) /100 ) = Aperature
return sqrt ( pow ( 2 , pEv ) * pIso * pShutter / 100.0 ) ;
}
float roundShutter ( float pShutter , uint8_t pMethod ) //round shutter to typical values
{
uint8_t _index = findShutterIndex ( pShutter , pMethod ) ;
//use closest shutter value
switch ( pMethod ) {
case 1 : //
return shuttertimes1 [ _index ] ;
break ;
2018-04-15 10:13:08 +00:00
case 2 : //
return shuttertimes2 [ _index ] ;
break ;
2018-05-03 13:53:37 +00:00
case 3 : //
return shuttertimes3 [ _index ] ;
break ;
2018-03-22 07:57:53 +00:00
}
}
float roundAperature ( float pAperature , uint8_t pMethod ) //round Aperature (x1) to typical values. method=0 -> leave, 1=full stops, 2=half stops, 3=third stops
{
if ( pMethod = = 0 ) {
return pAperature ;
}
uint8_t closest_index = findAperatureIndex ( pAperature , pMethod ) ;
//use closest aperature value
switch ( pMethod ) {
case 1 : //full stops
return aperaturesFull [ closest_index ] ;
break ;
case 2 : //half stops
//return float ( pow(sqrt(sqrt(2)), _index-2) );
return aperaturesHalf [ closest_index ] ;
break ;
case 3 : //third stops
return aperaturesThird [ closest_index ] ;
//return float ( pow(cbrt(sqrt(2)), _index-2) );
break ;
}
}
void changeAperature ( int8_t pchange ) { //pchange>0 means more light exposure (brighter image)
uint8_t _newAperatureIndex = findAperatureIndex ( setAperature , userSettings . aperatureSelectionMode ) ;
uint8_t _maximumAperatureIndex = 0 ;
switch ( userSettings . aperatureSelectionMode ) { //check max
case 1 : //full stops
_maximumAperatureIndex = sizeof ( aperaturesFull ) / sizeof ( float ) ;
break ;
case 2 : //half stops
_maximumAperatureIndex = sizeof ( aperaturesHalf ) / sizeof ( float ) ;
break ;
case 3 : //third stops
_maximumAperatureIndex = sizeof ( aperaturesThird ) / sizeof ( float ) ;
break ;
}
_newAperatureIndex - = pchange ; //change aperature
_newAperatureIndex = min ( _newAperatureIndex , _maximumAperatureIndex - 1 ) ; //maximum limit
_newAperatureIndex = max ( _newAperatureIndex , userSettings . minimumAperatureIndex ) ; //minimum limit
switch ( userSettings . aperatureSelectionMode ) {
case 1 : //full stops
setAperature = aperaturesFull [ _newAperatureIndex ] ;
break ;
case 2 : //half stops
setAperature = aperaturesHalf [ _newAperatureIndex ] ;
break ;
case 3 : //third stops
setAperature = aperaturesThird [ _newAperatureIndex ] ;
break ;
}
}
uint8_t findAperatureIndex ( float pAperature , uint8_t pMethod ) //find index of closest aperature from given aperature tables (pMethod
{
float _minDistance = 90000 ;
float _lastminDistance = 100000 ;
uint8_t _index = userSettings . minimumAperatureIndex ;
2018-03-23 19:21:27 +00:00
uint8_t _maxindexpossible = 0 ;
switch ( pMethod ) {
case 1 :
_maxindexpossible = APERATURESFULL_MAXINDEX ;
break ;
case 2 :
_maxindexpossible = APERATURESHALF_MAXINDEX ;
break ;
case 3 :
_maxindexpossible = APERATURESTHIRD_MAXINDEX ;
break ;
}
2018-03-22 07:57:53 +00:00
while ( _lastminDistance > _minDistance ) //until distance increases
{
2018-03-23 19:21:27 +00:00
if ( _index > _maxindexpossible ) { //this index will be out of bounds
return _maxindexpossible ;
}
2018-03-22 07:57:53 +00:00
_lastminDistance = _minDistance ;
switch ( pMethod ) {
case 1 : //full stops
_minDistance = abs ( pAperature - aperaturesFull [ _index ] ) ;
break ;
case 2 : //half stops
_minDistance = abs ( pAperature - aperaturesHalf [ _index ] ) ;
break ;
case 3 : //third stops
_minDistance = abs ( pAperature - aperaturesThird [ _index ] ) ;
break ;
}
_index + + ; //next
}
2018-03-23 19:21:27 +00:00
return _index - 2 ; //use index with closest value
2018-03-22 07:57:53 +00:00
}
void changeShutter ( int8_t pchange ) { //pchange>0 means more light exposure (brighter image)
uint8_t _newShutterIndex = findShutterIndex ( setShutter , userSettings . shutterSelectionMode ) ;
uint8_t _maximumShutterIndex = 0 ;
switch ( userSettings . shutterSelectionMode ) { //get max index from array
case 1 :
_maximumShutterIndex = sizeof ( shuttertimes1 ) / sizeof ( float ) ;
break ;
2018-04-15 10:13:08 +00:00
case 2 :
_maximumShutterIndex = sizeof ( shuttertimes2 ) / sizeof ( float ) ;
break ;
2018-05-03 13:53:37 +00:00
case 3 :
_maximumShutterIndex = sizeof ( shuttertimes3 ) / sizeof ( float ) ;
break ;
2018-03-22 07:57:53 +00:00
}
if ( ! ( - pchange < 0 & & _newShutterIndex = = 0 ) ) { //changed value would not yield negative index
_newShutterIndex - = pchange ; //change aperature
_newShutterIndex = min ( _newShutterIndex , _maximumShutterIndex - 1 ) ; //maximum limit from array
//_newShutterIndex=min(_newShutterIndex,maximumShutterIndex); //maximum limit from user settings
}
switch ( userSettings . shutterSelectionMode ) {
case 1 : //
setShutter = shuttertimes1 [ _newShutterIndex ] ;
break ;
2018-04-15 10:13:08 +00:00
case 2 : //
setShutter = shuttertimes2 [ _newShutterIndex ] ;
break ;
2018-05-03 13:53:37 +00:00
case 3 : //
setShutter = shuttertimes3 [ _newShutterIndex ] ;
break ;
2018-03-22 07:57:53 +00:00
}
}
uint8_t findShutterIndex ( float pShutter , uint8_t pMethod ) //find index of closest aperature from given aperature tables (pMethod
{
2018-05-03 13:53:37 +00:00
float _minDistance = 0 ;
switch ( userSettings . shutterSelectionMode ) {
case 1 : //
_minDistance = abs ( pShutter - shuttertimes1 [ 0 ] ) ;
break ;
case 2 : //
_minDistance = abs ( pShutter - shuttertimes2 [ 0 ] ) ;
break ;
case 3 : //
_minDistance = abs ( pShutter - shuttertimes3 [ 0 ] ) ;
break ;
}
2018-03-22 07:57:53 +00:00
float _lastminDistance = _minDistance ;
uint8_t _index = 0 ;
2018-03-23 19:21:27 +00:00
uint8_t _maxindexpossible = 0 ;
switch ( pMethod ) {
case 1 :
_maxindexpossible = SHUTTERTIMES1_MAXINDEX ;
break ;
2018-04-15 10:13:08 +00:00
case 2 :
_maxindexpossible = SHUTTERTIMES2_MAXINDEX ;
break ;
2018-05-03 13:53:37 +00:00
case 3 :
_maxindexpossible = SHUTTERTIMES3_MAXINDEX ;
break ;
2018-03-23 19:21:27 +00:00
}
2018-03-22 07:57:53 +00:00
while ( _lastminDistance > = _minDistance ) //until distance increases
{
2018-03-23 19:21:27 +00:00
if ( _index > _maxindexpossible ) { //this index will be out of bounds
return _maxindexpossible ;
}
2018-03-22 07:57:53 +00:00
_lastminDistance = _minDistance ;
switch ( pMethod ) {
case 1 :
_minDistance = abs ( pShutter - shuttertimes1 [ _index ] ) ;
break ;
2018-04-15 10:13:08 +00:00
case 2 :
_minDistance = abs ( pShutter - shuttertimes2 [ _index ] ) ;
break ;
2018-05-03 13:53:37 +00:00
case 3 :
_minDistance = abs ( pShutter - shuttertimes3 [ _index ] ) ;
break ;
2018-03-22 07:57:53 +00:00
}
_index + + ; //next
}
2018-03-23 19:21:27 +00:00
return _index - 2 ; //use index with closest value
2018-03-22 07:57:53 +00:00
}
void changeISO ( int8_t pchange ) { //pchange>0 means more light exposure (brighter image), higher iso
uint8_t _newISOIndex = findISOIndex ( setISO , userSettings . ISOSelectionMode ) ;
uint8_t _maximumISOIndex = 0 ;
switch ( userSettings . ISOSelectionMode ) { //get max index from array
case 1 :
_maximumISOIndex = sizeof ( isoFull ) / sizeof ( float ) ;
break ;
case 2 :
_maximumISOIndex = sizeof ( isoThird ) / sizeof ( float ) ;
break ;
}
if ( ! ( pchange < 0 & & _newISOIndex = = 0 ) ) { //changed value would not yield negative index
_newISOIndex + = pchange ; //change iso
_newISOIndex = min ( _newISOIndex , _maximumISOIndex - 1 ) ; //maximum limit from array
//_newISOIndex=min(_newISOIndex,maximumISOIndex); //maximum limit from user settings
}
switch ( userSettings . ISOSelectionMode ) {
case 1 : //
setISO = isoFull [ _newISOIndex ] ;
break ;
case 2 : //
setISO = isoThird [ _newISOIndex ] ;
break ;
}
}
uint8_t findISOIndex ( float pISO , uint8_t pMethod ) //find index of closest iso from given iso table (pMethod)
{
float _minDistance = abs ( pISO - isoFull [ 0 ] ) ;
float _lastminDistance = _minDistance ;
uint8_t _index = 0 ;
while ( _lastminDistance > = _minDistance ) //until distance increases
{
_lastminDistance = _minDistance ;
switch ( pMethod ) {
case 1 :
_minDistance = abs ( pISO - isoFull [ _index ] ) ;
break ;
case 2 :
_minDistance = abs ( pISO - isoThird [ _index ] ) ;
break ;
}
_index + + ; //next
}
return _index - 2 ;
}
2018-05-03 13:53:37 +00:00
int isoToDIN ( float pISO , uint8_t pMethod ) {
uint8_t _isoIndex = findISOIndex ( pISO , pMethod ) ;
switch ( pMethod ) {
case 1 :
return isoFullDIN [ _isoIndex ] ;
break ;
case 2 :
return isoThirdDIN [ _isoIndex ] ;
break ;
}
}
void displayPrintISO ( float pISO , bool pDisplayBoth ) { //for lower iso values use din notation
if ( pISO > = 25 | | pDisplayBoth ) {
if ( pDisplayBoth ) {
display . print ( pISO , 2 ) ;
} else {
display . print ( pISO , 0 ) ;
}
}
if ( pDisplayBoth ) {
display . print ( " / " ) ;
}
if ( pISO < 25 | | pDisplayBoth ) {
display . print ( isoToDIN ( pISO , userSettings . ISOSelectionMode ) ) ;
display . write ( 0xF7 ) ; //degree char
}
}
float calculateEV ( float pISO , float pShutter , float pAperature )
{ //EV = log2 ( 100* Aperature^2 / (ISO * Time ))
return log ( 100 * pow ( pAperature , 2 ) / ( pISO * pShutter ) ) / log ( 2 ) ;
}
2018-03-22 07:57:53 +00:00
void updateDisplay ( )
{
2018-04-14 11:56:49 +00:00
if ( loopmillis - last_displayupdate > = DISPLAY_UPDATEDELAY ) {
switch ( displaymode ) {
case lightmeter :
updateDisplay_Lightmeter ( ) ;
break ;
case settings :
updateDisplay_Settings ( ) ;
break ;
case meteringmodeselection :
updateDisplay_Meteringmodeselection ( ) ;
break ;
}
last_displayupdate = loopmillis ;
display . display ( ) ;
2018-03-22 07:57:53 +00:00
}
2018-04-14 11:56:49 +00:00
2018-03-22 07:57:53 +00:00
}
void updateDisplay_Lightmeter ( ) //Lightmeter display
{
# define xpos_aperature 2
# define ypos_aperature 29
2018-03-26 15:55:17 +00:00
# define xpos_shutter 50
2018-03-22 07:57:53 +00:00
# define ypos_shutter 29
2018-03-25 19:20:39 +00:00
# define xpos_icon 112 //128-16
# define ypos_icon 29
2018-03-22 07:57:53 +00:00
# define xpos_debug 0
# define ypos_debug 63-7
# define xpos_iso 2
# define ypos_iso 63-7-9
display . clearDisplay ( ) ;
display . setTextColor ( WHITE ) ;
2018-04-14 11:56:49 +00:00
2018-03-22 07:57:53 +00:00
//Aperature
float _showAperature = roundAperature ( showAperature , userSettings . aperatureSelectionMode ) ;
display . setTextSize ( 1 ) ;
display . setCursor ( xpos_aperature , ypos_aperature ) ; display . print ( " F " ) ;
display . setTextSize ( 2 ) ;
display . setCursor ( display . getCursorX ( ) , display . getCursorY ( ) ) ; display . print ( int ( _showAperature ) ) ;
if ( int ( ( _showAperature - int ( _showAperature ) ) * 10 ) ! = 0 ) { //has a decimal
display . setTextSize ( 1 ) ;
display . setCursor ( display . getCursorX ( ) - 2 , display . getCursorY ( ) + 7 ) ; display . print ( " . " ) ; display . setCursor ( display . getCursorX ( ) + 1 , display . getCursorY ( ) - 7 ) ;
display . setTextSize ( 2 ) ;
display . setCursor ( display . getCursorX ( ) - 2 , display . getCursorY ( ) ) ;
display . print ( ( int ) round ( ( _showAperature - int ( _showAperature ) ) * 10 ) ) ;
}
//Aperature border
if ( setAperature > 0 ) { //Aperature Priority Mode
2018-04-16 09:08:12 +00:00
if ( ! manualev_mode ) { //selection
display . drawRect ( xpos_aperature - 2 , ypos_aperature - 2 , 40 , 18 , WHITE ) ; //normal border
} else { //manual ev selection
drawRectCorners ( xpos_aperature - 2 , ypos_aperature - 2 , 40 , 18 , 5 , WHITE ) ; //alternative border
}
2018-03-22 07:57:53 +00:00
}
//Shutter
display . setCursor ( xpos_shutter , ypos_shutter ) ;
float _showShutter = roundShutter ( showShutter , userSettings . shutterSelectionMode ) ;
//Serial.print("rounded Shutter from "); Serial.print(showShutter); Serial.print(" to "); Serial.println(_showShutter); //asdf
2018-04-15 10:13:08 +00:00
if ( _showShutter > 0.25 ) //check shuttertime
2018-03-22 07:57:53 +00:00
{ //show full seconds
display . print ( int ( _showShutter ) ) ;
if ( _showShutter - int ( _showShutter ) > 0 ) { //has decimals
display . setTextSize ( 1 ) ;
display . setCursor ( display . getCursorX ( ) - 2 , display . getCursorY ( ) + 7 ) ; display . print ( " . " ) ; display . setCursor ( display . getCursorX ( ) + 1 , display . getCursorY ( ) - 7 ) ;
display . setTextSize ( 2 ) ;
display . setCursor ( display . getCursorX ( ) - 2 , display . getCursorY ( ) ) ;
display . print ( ( int ) round ( ( _showShutter - int ( _showShutter ) ) * 10 ) ) ; //show one decimal
}
display . setTextSize ( 1 ) ; display . setCursor ( display . getCursorX ( ) , display . getCursorY ( ) + 7 ) ;
display . print ( " s " ) ;
} else { //show fraction of a second
display . setTextSize ( 1 ) ; display . print ( " 1 " ) ;
display . drawLine ( display . getCursorX ( ) + 1 , display . getCursorY ( ) , display . getCursorX ( ) - 1 , display . getCursorY ( ) + 9 , WHITE ) ;
display . setTextSize ( 2 ) ; display . setCursor ( display . getCursorX ( ) + 2 , display . getCursorY ( ) ) ;
int _frac_showShutter = ( int ) ( ( 1.0f / ( ( int ) ( _showShutter * 1000000 ) ) ) * 1000000 ) ;
display . print ( _frac_showShutter ) ;
display . setTextSize ( 1 ) ; display . setCursor ( display . getCursorX ( ) , display . getCursorY ( ) + 7 ) ;
display . print ( " s " ) ;
}
//Shutter border
if ( setShutter > 0 ) { //Shutter Priority Mode
2018-04-16 09:08:12 +00:00
if ( ! manualev_mode ) { //selection
display . drawRect ( xpos_shutter - 2 , ypos_shutter - 2 , 60 , 18 , WHITE ) ; //normal border
} else { //manual ev selection
drawRectCorners ( xpos_shutter - 2 , ypos_shutter - 2 , 60 , 18 , 5 , WHITE ) ; //alternative border
}
2018-03-22 07:57:53 +00:00
}
2018-03-25 19:20:39 +00:00
2018-05-03 13:53:37 +00:00
//Draw line for ev error
float _actualEV = calculateEV ( setISO , _showShutter , _showAperature ) ;
float _evError = _actualEV - ev ; //Line on the right means suggested values will overexpose the image
uint8_t evErrorX = 0 ;
uint8_t evErrorY = ypos_aperature + 16 ;
if ( setAperature > 0 ) { //Aperature Priority Mode
evErrorX = xpos_shutter + 20 ;
evErrorY = ypos_shutter + 16 ;
} else if ( setShutter > 0 ) { //Shutter Priority Mode
evErrorX = xpos_aperature + 20 ;
evErrorY = ypos_aperature + 16 ;
}
uint8_t everrorpixels_per_ev = 20 ;
if ( _evError > 1 | | _evError < 1 ) { //scale smaller if error greater 1 EV
everrorpixels_per_ev = 10 ;
}
display . drawLine ( evErrorX , evErrorY , evErrorX , evErrorY + 1 , WHITE ) ; //center line
display . drawLine ( evErrorX - everrorpixels_per_ev , evErrorY , evErrorX - everrorpixels_per_ev , evErrorY + 1 , WHITE ) ; //-1 ev
display . drawLine ( evErrorX + everrorpixels_per_ev , evErrorY , evErrorX + everrorpixels_per_ev , evErrorY + 1 , WHITE ) ; //+1ev
if ( _evError > 1 | | _evError < 1 ) { //scale smaller if error greater 1 EV
display . drawLine ( evErrorX - 2 * everrorpixels_per_ev , evErrorY , evErrorX - 2 * everrorpixels_per_ev , evErrorY + 1 , WHITE ) ; //-1 ev
display . drawLine ( evErrorX + 2 * everrorpixels_per_ev , evErrorY , evErrorX + 2 * everrorpixels_per_ev , evErrorY + 1 , WHITE ) ; //+1ev
}
display . drawLine ( evErrorX , evErrorY , evErrorX + ( everrorpixels_per_ev * _evError + 0.5 ) , evErrorY , WHITE ) ; //Draw ev error line
//Meteringmode Icon
2018-03-25 19:20:39 +00:00
if ( meteringmode = = METERINGMODE_REFLECTIVE ) {
2018-03-26 15:55:17 +00:00
display . drawXBitmap ( xpos_icon , ypos_icon , icon_spot_bits , icon_spot_width , icon_spot_height , WHITE ) ;
2018-03-25 19:20:39 +00:00
} else if ( meteringmode = = METERINGMODE_INCIDENT ) {
2018-03-26 15:55:17 +00:00
display . drawXBitmap ( xpos_icon , ypos_icon , icon_incident_bits , icon_incident_width , icon_incident_height , WHITE ) ;
2018-03-25 19:20:39 +00:00
}
2018-03-22 07:57:53 +00:00
//ISO
2018-05-03 13:53:37 +00:00
display . setCursor ( xpos_iso , ypos_iso ) ; display . setTextSize ( 1 ) ;
if ( setISO < 25 ) {
display . print ( " DIN " ) ; //below iso 25 only din value is shown here
} else {
display . print ( " ISO " ) ;
}
displayPrintISO ( setISO , false ) ; //display.print(formatISO(setISO,false));
2018-04-14 11:56:49 +00:00
2018-03-26 15:55:17 +00:00
//EV Scale
2018-05-02 08:41:24 +00:00
uint8_t _evrangedisplay = 10 ; //which range to display. Default value
if ( ev_min > - 254 & & ev_max > - 254 ) { //values set
_evrangedisplay = ev_max - ev_min ;
2018-04-15 10:13:08 +00:00
}
2018-05-02 08:41:24 +00:00
if ( _evrangedisplay < 6 ) { //minimum range
_evrangedisplay = 6 ;
2018-04-09 09:45:18 +00:00
}
2018-03-26 15:55:17 +00:00
2018-05-02 08:41:24 +00:00
//#define FULLEVLINEDISTANCE 9
//#define THIRDEVLINEDISTANCE 3
uint8_t FULLEVLINEDISTANCE = ( ( int ) ( WIDTH / ( _evrangedisplay + 2 ) ) / 3 ) * 3 ; //scale distance to fit evrange_display with safety margin, floor to multiples of 3
uint8_t THIRDEVLINEDISTANCE = FULLEVLINEDISTANCE / 3 ;
uint8_t _max_evvalues_displayed = ( WIDTH / ( FULLEVLINEDISTANCE ) ) ;
2018-03-26 15:55:17 +00:00
# define ypos_evtext 7
# define ypos_icon_arrow 6
2018-05-02 08:41:24 +00:00
int8_t _startev = - 5 ; //first ev to display, 13 ev values can fit on screen
/*if (ev>2 && (ev_min<-254 || ev_min>2)){ //TODO make ev scale start better
_startev = 0 ;
}
if ( ev > _max_ev_displayed - 2 | | ev_max > _max_ev_displayed - 2 ) {
_startev = 5 + ev - ( _max_ev_displayed - 2 ) ;
} */
float _evrangemargin = ( _max_evvalues_displayed - _evrangedisplay ) / 2.0 ; //space left on both sides between evnrange (min to max) and display width
if ( _evrangemargin < 0 ) { //bound
_evrangemargin = 0 ;
}
if ( ev_min > - 254 & & ev_max > - 254 ) { //minmax values set
if ( ev > = ev_min & & ev < = ev_max ) { //arrow between min and max
_startev = ( ev_max - ev_min ) / 2 + ev_min - _max_evvalues_displayed / 2 ; //center of evmin and max at display center
} else { //arrow outside of ev min max range
if ( ev < ev_min ) { //on the left
_startev = ev - _evrangemargin - 2 ;
} else if ( ev > ev_max ) { //on the right
_startev = ev + _evrangemargin - _evrangedisplay ;
}
}
} else { //ev min max values not set yet
_startev = ev - _max_evvalues_displayed / 2 ; //center
_startev = ( int ( _startev / ( _max_evvalues_displayed / 2 ) ) ) * ( _max_evvalues_displayed / 2 ) ; //floor to multiples of (_evrangedisplay/2)
}
uint8_t xpos_arrow = ( ev - _startev * 1.0 ) * FULLEVLINEDISTANCE + 1 ; //calculate display position for ev
2018-03-26 15:55:17 +00:00
display . setTextSize ( 1 ) ;
display . drawLine ( THIRDEVLINEDISTANCE , 0 , THIRDEVLINEDISTANCE , 0 , WHITE ) ; //first third line
display . drawLine ( THIRDEVLINEDISTANCE + THIRDEVLINEDISTANCE , 0 , THIRDEVLINEDISTANCE + THIRDEVLINEDISTANCE , 0 , WHITE ) ; //second third line
2018-05-02 08:41:24 +00:00
for ( uint8_t _fullevline = 1 ; _fullevline < = _max_evvalues_displayed ; _fullevline + + ) { //with fullevlindistance=9 and WIDTH=128 -> <=13
2018-04-15 10:13:08 +00:00
int8_t _current_evvalue = _fullevline + _startev ;
2018-03-26 15:55:17 +00:00
uint8_t _xpos_center_evtext = _fullevline * FULLEVLINEDISTANCE ; //center of current ev line x pos
display . drawLine ( _xpos_center_evtext , 0 , _xpos_center_evtext , 2 , WHITE ) ;
display . drawLine ( _xpos_center_evtext + THIRDEVLINEDISTANCE , 0 , _xpos_center_evtext + THIRDEVLINEDISTANCE , 0 , WHITE ) ;
display . drawLine ( _xpos_center_evtext + THIRDEVLINEDISTANCE + THIRDEVLINEDISTANCE , 0 , _xpos_center_evtext + THIRDEVLINEDISTANCE + THIRDEVLINEDISTANCE , 0 , WHITE ) ;
2018-05-02 08:41:24 +00:00
if ( ( FULLEVLINEDISTANCE > 9 & & _current_evvalue < 10 & & _current_evvalue > = 0 ) | | ( FULLEVLINEDISTANCE > 12 ) | | _fullevline % 2 = = 1 ) { //display every single digit ev if distance greater 9 OR if dist. gr. 12 OTHERWISE only every second digit
2018-03-26 15:55:17 +00:00
uint8_t _evtextmove = 2 ; //movement of left point of text to the left. Compensation for center position
2018-04-16 09:08:12 +00:00
if ( _current_evvalue > 9 | | _current_evvalue < 0 ) { //text has two digits
2018-03-26 15:55:17 +00:00
_evtextmove = 5 ;
}
if ( ( xpos_arrow - 7 > _xpos_center_evtext ) | | ( xpos_arrow + 7 < _xpos_center_evtext ) ) { //drawn arrow not too close to ev text
2018-04-16 09:08:12 +00:00
display . setCursor ( _xpos_center_evtext - _evtextmove , ypos_evtext ) ; display . print ( _current_evvalue ) ; //EV Text at scale line
2018-03-26 15:55:17 +00:00
}
}
}
//Arrow at current ev
2018-04-16 09:08:12 +00:00
float _ev_decimals = abs ( ev - ( ( int ) ev ) ) ;
2018-03-26 15:55:17 +00:00
display . drawXBitmap ( xpos_arrow - icon_arrow_width / 2.0 , ypos_icon_arrow , icon_arrow_bits , icon_arrow_width , icon_arrow_height , WHITE ) ; //arrow icon
2018-04-16 09:08:12 +00:00
if ( manualev_mode ) { //in manual ev mode
display . drawXBitmap ( xpos_arrow - icon_arrow_width / 2.0 - 1 , ypos_icon_arrow , icon_arrow_bits , icon_arrow_width , icon_arrow_height , WHITE ) ; //arrow icon //draw bold
display . drawXBitmap ( xpos_arrow - icon_arrow_width / 2.0 + 1 , ypos_icon_arrow , icon_arrow_bits , icon_arrow_width , icon_arrow_height , WHITE ) ; //arrow icon //draw bold
2018-04-17 09:36:19 +00:00
display . drawXBitmap ( xpos_arrow - icon_arrow_width / 2.0 , ypos_icon_arrow - 1 , icon_arrow_bits , icon_arrow_width , icon_arrow_height , WHITE ) ; //arrow icon //draw bold
2018-04-16 09:08:12 +00:00
}
2018-03-26 15:55:17 +00:00
uint8_t _xpos_current_evtext_move = 5 ; //for text centering
if ( _ev_decimals < = 0.1666 | | _ev_decimals > 0.8333 ) { //without fraction displayed
_xpos_current_evtext_move = 2 ;
}
2018-04-09 09:45:18 +00:00
int _displayev = ( int ) ev ;
2018-03-26 15:55:17 +00:00
if ( _ev_decimals > 0.8333 ) {
2018-04-16 09:08:12 +00:00
if ( ev > = 0 ) { //ev is positive
_displayev = ( int ) ( ev + 1 ) ; //EV Value under arrow. Ceil
} else if ( ev < 0 ) { //ev is negative
_displayev = ( int ) ( ev - 1 ) ; //EV Value under arrow. Ceil (negative)
}
2018-03-26 15:55:17 +00:00
}
2018-04-16 09:08:12 +00:00
//int _xpos_current_fraction_move=0; //move fraction icon
if ( _displayev > = 10 | | ev < - 0.1666 ) { //displayev is two digits long (>=10 or negative sign)
2018-04-14 11:56:49 +00:00
_xpos_current_evtext_move + = 6 ; //move digits to left. positive means left
2018-04-16 09:08:12 +00:00
2018-04-09 09:45:18 +00:00
}
display . setCursor ( xpos_arrow - _xpos_current_evtext_move , ypos_icon_arrow + icon_arrow_height + 2 ) ; //current ev text position
2018-04-16 09:08:12 +00:00
if ( ev < 0 & & _displayev = = 0 ) { //ev is negative but displayev is zero
display . print ( " - " ) ; // add minus in front
}
2018-04-09 09:45:18 +00:00
display . print ( _displayev ) ; //EV Value under arrow
2018-03-26 15:55:17 +00:00
if ( _ev_decimals > 0.1666 & & _ev_decimals < = 0.4166 ) {
display . drawXBitmap ( xpos_arrow , ypos_icon_arrow + icon_arrow_height - ( icon_one_third_height - 8 ) / 2 + 2 , icon_one_third_bits , icon_one_third_width , icon_one_third_height , WHITE ) ; //one third
} else if ( _ev_decimals > 0.4166 & & _ev_decimals < = 0.5833 ) {
display . drawXBitmap ( xpos_arrow , ypos_icon_arrow + icon_arrow_height - ( icon_one_half_height - 8 ) / 2 + 2 , icon_one_half_bits , icon_one_half_width , icon_one_half_height , WHITE ) ; //one half
} else if ( _ev_decimals > 0.5833 & & _ev_decimals < = 0.8333 ) {
display . drawXBitmap ( xpos_arrow , ypos_icon_arrow + icon_arrow_height - ( icon_two_third_height - 8 ) / 2 + 2 , icon_two_third_bits , icon_two_third_width , icon_two_third_height , WHITE ) ; //two third
}
2018-04-16 09:08:12 +00:00
//ev min & max
2018-05-02 09:27:10 +00:00
int16_t xpos_ev_min = ( ev_min - _startev * 1.0 ) * FULLEVLINEDISTANCE ; //calculate display position for ev
int16_t xpos_ev_max = ( ev_max - _startev * 1.0 ) * FULLEVLINEDISTANCE ; //calculate display position for ev
2018-04-16 09:08:12 +00:00
bool arrow_is_between_minmax = true ;
2018-05-02 08:41:24 +00:00
if ( xpos_arrow < = xpos_ev_min | | xpos_arrow > = xpos_ev_max ) {
2018-04-16 09:08:12 +00:00
arrow_is_between_minmax = false ; //selected ev is not between min and max ev
}
2018-05-02 08:41:24 +00:00
if ( ev_min > - 254 & & xpos_ev_min > = 0 & & xpos_ev_min < WIDTH ) { //ev_min is set (-255 is placeholder for "not set")
2018-04-16 09:08:12 +00:00
display . drawLine ( xpos_ev_min , 2 , xpos_ev_min , 5 , WHITE ) ;
if ( ( xpos_arrow - xpos_ev_min ) > 3 & & arrow_is_between_minmax ) { //arrow is not overlaying line and is in between min and max
2018-05-02 08:41:24 +00:00
//display.drawLine(xpos_ev_min,4,xpos_arrow ,4,WHITE); //line from left horizontally to arrow
2018-04-16 09:08:12 +00:00
display . drawLine ( xpos_ev_min , 5 , xpos_arrow - 4 , 5 , WHITE ) ; //line from left horizontally to arrow
}
}
2018-05-02 08:41:24 +00:00
if ( ev_max > - 254 & & xpos_ev_max > = 0 & & xpos_ev_max < WIDTH ) { //ev_min is set (-255 is placeholder for "not set")
2018-04-16 09:08:12 +00:00
display . drawLine ( xpos_ev_max , 2 , xpos_ev_max , 5 , WHITE ) ;
if ( ( xpos_ev_max - xpos_arrow ) > 3 & & arrow_is_between_minmax ) { //arrow is not overlaying line and is in between min and max
2018-05-02 08:41:24 +00:00
//display.drawLine(xpos_ev_max,4,xpos_arrow ,4,WHITE); //line from right horizontally to arrow
2018-04-17 09:36:19 +00:00
display . drawLine ( xpos_ev_max , 5 , xpos_arrow + 2 , 5 , WHITE ) ; //line from right horizontally to arrow
2018-04-16 09:08:12 +00:00
}
}
2018-05-02 08:41:24 +00:00
if ( ev_min > - 254 & & ev_max > - 254 ) { //evmin and max are set
2018-05-02 09:27:10 +00:00
uint8_t _xpos_ev_min_line = xpos_ev_min ;
uint8_t _xpos_ev_max_line = xpos_ev_max ;
if ( xpos_ev_min < 0 ) {
_xpos_ev_min_line = 0 ;
} else if ( xpos_ev_min > = WIDTH - 1 ) {
_xpos_ev_min_line = WIDTH - 1 ;
}
if ( xpos_ev_max < 0 ) {
_xpos_ev_max_line = 0 ;
} else if ( xpos_ev_max > = WIDTH - 1 ) {
_xpos_ev_max_line = WIDTH - 1 ;
}
display . drawLine ( _xpos_ev_min_line , 4 , _xpos_ev_max_line , 4 , WHITE ) ; //draw single line between them
2018-05-02 08:41:24 +00:00
}
2018-04-17 09:36:19 +00:00
for ( int8_t i = - ( xpos_arrow - xpos_ev_min ) / FULLEVLINEDISTANCE ; i < ( xpos_ev_max - xpos_arrow ) / FULLEVLINEDISTANCE ; i + + ) { //draw black lines for every zone border
display . drawLine ( xpos_arrow + i * FULLEVLINEDISTANCE + FULLEVLINEDISTANCE / 2 , 4 , xpos_arrow + i * FULLEVLINEDISTANCE + FULLEVLINEDISTANCE / 2 , 5 , BLACK ) ; //erase part of horizontal line
}
2018-04-14 11:56:49 +00:00
2018-03-26 15:55:17 +00:00
2018-03-22 07:57:53 +00:00
//DEBUG Message
display . setTextSize ( 1 ) ;
display . setCursor ( xpos_debug , ypos_debug ) ;
2018-04-15 10:13:08 +00:00
display . print ( vbat , 2 ) ;
2018-03-22 07:57:53 +00:00
display . print ( " V " ) ;
2018-04-15 10:13:08 +00:00
/*display.print("Ev=");
2018-03-22 07:57:53 +00:00
display . print ( ev ) ;
2018-03-23 19:21:27 +00:00
display . print ( " | " ) ;
2018-04-14 11:56:49 +00:00
display . print ( incident ) ; */
2018-04-16 09:08:12 +00:00
/*display.print(debug_analog_low);
2018-04-14 11:56:49 +00:00
display . print ( " : " ) ;
2018-04-16 09:08:12 +00:00
display . print ( debug_analog_high ) ; */
2018-05-02 09:05:19 +00:00
/*display.print(ev_min,1);
2018-04-17 09:36:19 +00:00
display . print ( " < " ) ;
display . print ( ev , 1 ) ;
display . print ( " < " ) ;
2018-05-02 09:05:19 +00:00
display . print ( ev_max , 1 ) ; */
display . setCursor ( xpos_debug + 50 , ypos_debug - 5 ) ;
2018-05-03 08:01:41 +00:00
if ( ev_min > - 254 & & ev > = ev_min ) { //ev min set
2018-05-02 09:05:19 +00:00
display . print ( " - " ) ;
display . print ( ev - ev_min , 1 ) ;
} else {
display . print ( " / " ) ;
}
display . print ( " <> " ) ;
2018-05-03 08:01:41 +00:00
if ( ev_max > - 254 & & ev < = ev_max ) {
2018-05-02 09:05:19 +00:00
display . print ( " + " ) ;
display . print ( ev_max - ev , 1 ) ;
} else {
display . print ( " / " ) ;
}
2018-03-23 19:21:27 +00:00
2018-03-22 07:57:53 +00:00
}
void updateDisplay_Settings ( )
{
display . clearDisplay ( ) ;
display . setTextColor ( WHITE ) ;
display . setTextSize ( 1 ) ;
# define SETTINGS_YPOS_INCREMENT 9
# define SETTINGS_XPOS_OFFSET 1
display . setCursor ( SETTINGS_XPOS_OFFSET , 0 ) ; //absolute position for first item
for ( uint8_t _currentItemIndex = 0 ; _currentItemIndex < = SETTINGS_SELECTEDITEM_MAX ; _currentItemIndex + + )
{
if ( settings_selectedItem = = _currentItemIndex ) {
if ( settings_itemActive ) {
display . drawRect ( 0 , display . getCursorY ( ) - 2 , 126 , 11 , WHITE ) ;
} else {
display . fillCircle ( 2 , display . getCursorY ( ) + 3 , 2 , WHITE ) ; //x,y,r,color
}
display . setCursor ( display . getCursorX ( ) + 5 , display . getCursorY ( ) ) ; //move text to the right
}
display . print ( settingStrings [ _currentItemIndex ] ) ;
switch ( _currentItemIndex ) { //if values need to be shown
2018-05-03 13:53:37 +00:00
case 0 : displayPrintISO ( setISO , true ) ; //display.print(formatISO(setISO,true));
2018-03-22 07:57:53 +00:00
break ;
case 1 : display . print ( settingsnameAperatureSelectionMode [ userSettings . aperatureSelectionMode - 1 ] ) ;
break ;
case 2 : display . print ( settingsnameShutterSelectionMode [ userSettings . shutterSelectionMode - 1 ] ) ;
break ;
2018-04-17 09:36:19 +00:00
case 3 : display . print ( " 1/ " ) ; display . print ( userSettings . manualev_moveamount_frac ) ; display . print ( " EV " ) ;
break ;
//case 4 is power off, no value to display here
2018-03-22 07:57:53 +00:00
}
display . setCursor ( SETTINGS_XPOS_OFFSET , display . getCursorY ( ) + SETTINGS_YPOS_INCREMENT ) ; //move cursor to next entry
}
2018-03-26 15:55:17 +00:00
}
2018-03-22 07:57:53 +00:00
2018-03-26 15:55:17 +00:00
void updateDisplay_Meteringmodeselection ( )
{
display . clearDisplay ( ) ;
display . setTextColor ( WHITE ) ;
# define xpos_center_icon_spot 30
# define ypos_icon_spot 20
# define xpos_center_icon_incident 97
# define ypos_icon_incident 20
2018-03-22 07:57:53 +00:00
2018-03-26 15:55:17 +00:00
display . drawXBitmap ( xpos_center_icon_spot - icon_spot_width / 2 , ypos_icon_spot , icon_spot_bits , icon_spot_width , icon_spot_height , WHITE ) ; //Spot icon
display . drawRect ( xpos_center_icon_spot - icon_spot_width / 2 - 2 , ypos_icon_spot - 2 , icon_spot_width + 4 , icon_spot_height + 4 , WHITE ) ;
display . drawXBitmap ( xpos_center_icon_incident - icon_incident_width / 2 , ypos_icon_incident , icon_incident_bits , icon_incident_width , icon_incident_height , WHITE ) ; //incident icon
display . drawRect ( xpos_center_icon_incident - icon_incident_width / 2 - 2 , ypos_icon_incident - 2 , icon_incident_width + 4 , icon_incident_height + 4 , WHITE ) ;
2018-03-22 07:57:53 +00:00
2018-03-26 15:55:17 +00:00
display . setTextSize ( 1 ) ;
display . setCursor ( xpos_center_icon_spot - 10 , ypos_icon_spot + icon_spot_height + 6 ) ; //text position upper left
display . print ( " SPOT " ) ; //7x5 characters, xpos_center_icon_spot-(5*#chars /2)
display . setCursor ( xpos_center_icon_incident - 20 , ypos_icon_incident + icon_incident_height + 6 ) ; //text position upper left
display . print ( " INCIDENT " ) ;
2018-04-14 11:56:49 +00:00
if ( loopmillis - millis_opened_meteringmodeselection > = DELAY_METERINGMODESELECTION_FLASHLIGHT ) {
blinkLED ( 500 ) ; //turn led on continously
}
2018-03-22 07:57:53 +00:00
}
2018-04-16 09:08:12 +00:00
void drawRectCorners ( uint8_t px , uint8_t py , uint8_t pw , uint8_t ph , uint8_t pcornerlength , uint8_t pc ) {
//px py are top left
display . drawLine ( px , py , px + pcornerlength , py , pc ) ;
display . drawLine ( px , py , px , py + pcornerlength , pc ) ;
display . drawLine ( px + pw , py , px + pw - pcornerlength , py , pc ) ;
display . drawLine ( px + pw , py , px + pw , py + pcornerlength , pc ) ;
display . drawLine ( px + pw , py + ph , px + pw - pcornerlength , py + ph , pc ) ;
display . drawLine ( px + pw , py + ph , px + pw , py + ph - pcornerlength , pc ) ;
display . drawLine ( px , py + ph , px + pcornerlength , py + ph , pc ) ;
display . drawLine ( px , py + ph , px , py + ph - pcornerlength , pc ) ;
}
2018-04-14 11:56:49 +00:00
void blinkLED ( long duration ) {
2018-04-16 09:08:12 +00:00
blinkLED ( duration , 255 ) ;
}
void blinkLED ( long duration , uint8_t brightness ) {
//digitalWrite(PIN_LED,HIGH);
analogWrite ( PIN_LED , brightness ) ;
2018-04-14 11:56:49 +00:00
millis_ledoff = loopmillis + duration ;
}
void checkLED ( ) {
if ( loopmillis > = millis_ledoff & & digitalRead ( PIN_LED ) ) {
2018-04-16 09:08:12 +00:00
//digitalWrite(PIN_LED,LOW);
analogWrite ( PIN_LED , 0 ) ; //LED OFF
2018-04-14 11:56:49 +00:00
}
}
template < class T > int EEPROM_writeAnything ( int ee , const T & value )
{ //from http://www.stm32duino.com/viewtopic.php?t=1576
const byte * p = ( const byte * ) ( const void * ) & value ;
unsigned int i ;
for ( i = 0 ; i < sizeof ( value ) ; i + + )
EEPROM . write ( ee + + , * p + + ) ;
return i ;
}
template < class T > int EEPROM_readAnything ( int ee , T & value )
{
byte * p = ( byte * ) ( void * ) & value ;
unsigned int i ;
for ( i = 0 ; i < sizeof ( value ) ; i + + )
* p + + = EEPROM . read ( ee + + ) ;
return i ;
}