/* * MonkeyUI.c * * Created: 2016-01-10 22:37:51 * Author : Ted */ #define F_CPU 16000000UL #include #include #include #include #include #include #include #include #define SPEED_LIMIT 25 //25 kmh.. ;( #define MAGNET_WIDTH 0 //mm #define WHEEL_CIRCUMFERENCE 1364 //mm #define TRIGGERS_PER_MAGNET 2 #define PASSPHRASE 0b0000010110111011 //UP UP DOWN DOWN LEFT RIGHT LEFT RIGHT #define RELEASE 126 #define PRESS (1 << 3) #define DOWN (1 << 2) #define RIGHT (1 << 4) #define UP (1 << 0) #define LEFT (1 << 1) #define OdometerStringlength 7 #define Odometer2Stringlength 7 #define BoxesH 4 #define BoxesV -4 #define PAGE_TIME 3 #define PAGE_GENERAL 1 #define PAGE_GENERAL_TWO 2 #define PAGE_LOCK 4 #define PAGE_TIME_setclock 0 #define PAGE_GENERAL_throttleofftime 1 #define PAGE_GENERAL_setmagnets 2 #define PAGE_GENERAL_setsleepdelay 3 #define PAGE_GENERAL_setlockonsleep 4 #define PAGE_GENERAL_triggerpermagnet 5 #define PAGE_GENERAL_wheelcircum 6 #define PAGE_GENERAL_magnetwidth 7 #define PAGE_GENERAL_topspeed 8 #define RELAY_DELAY 5 //2ms is enough says data sheet #define ThrottleOffTimeMultiplier 12 #define SleepDelayMultiplier 1 /* const u8g_fntpgm_uint8_t rothman[1737] U8G_FONT_SECTION("rothman") = { 0,21,82,0,8,83,0,0,0,0,48,57,0,91,0,83, 0,15,83,166,17,1,8,7,224,28,112,56,56,120,28,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,112,28,120,60,120,56,60,120,31,240,7,192,8,83,83, 10,1,8,7,63,255,255,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,83,166,17,1,8,31,240,124,60, 248,30,240,30,240,30,240,30,240,30,240,30,240,30,240,30, 240,30,240,30,240,30,240,30,240,30,240,30,240,30,240,30, 240,30,240,30,240,30,240,30,240,30,240,30,0,30,0,30, 0,30,0,30,0,30,0,30,0,30,0,30,0,30,0,30, 0,30,0,62,0,60,0,60,0,124,0,120,0,120,0,248, 0,240,1,240,1,224,3,224,3,224,7,192,7,192,7,128, 15,128,15,0,31,0,30,0,62,0,60,0,60,0,124,0, 120,0,120,0,248,0,240,0,240,0,240,0,240,0,240,0, 240,30,240,30,240,30,240,30,240,30,240,30,240,30,240,30, 240,30,240,30,240,30,240,30,240,30,240,30,255,254,255,254, 255,254,15,83,166,18,1,8,7,240,60,56,56,28,120,30, 120,30,120,30,120,30,120,30,120,30,120,30,120,30,120,30, 120,30,120,30,120,30,120,30,120,30,120,30,120,30,120,30, 120,30,120,30,120,30,120,30,0,30,0,30,0,30,0,30, 0,30,0,30,0,30,0,30,0,30,0,30,0,30,0,28, 0,60,1,248,31,240,0,248,0,60,0,28,0,30,0,30, 0,30,0,30,0,30,0,30,0,30,0,30,0,30,0,30, 0,30,0,30,0,30,0,30,248,30,248,30,248,30,248,30, 248,30,248,30,248,30,248,30,248,30,248,30,248,30,248,30, 248,30,248,30,248,30,248,30,248,30,248,30,248,30,248,30, 248,30,248,30,248,30,248,30,120,60,124,120,31,224,19,83, 249,21,1,8,0,2,0,0,2,0,0,6,0,0,6,0, 0,6,0,0,6,0,0,14,0,0,14,0,0,14,0,0, 14,0,0,30,0,0,30,0,0,30,0,0,30,0,0,62, 0,0,62,0,0,62,0,0,62,0,0,62,0,0,94,0, 0,94,0,0,94,0,0,94,0,0,158,0,0,158,0,0, 158,0,0,158,0,1,30,0,1,30,0,1,30,0,1,30, 0,2,30,0,2,30,0,2,30,0,2,30,0,4,30,0, 4,30,0,4,30,0,4,30,0,8,30,0,8,30,0,8, 30,0,8,30,0,24,30,0,16,30,0,16,30,0,16,30, 0,16,30,0,32,30,0,32,30,0,32,30,0,32,30,0, 64,30,0,64,30,0,64,30,0,127,255,224,255,255,224,255, 255,224,0,30,0,0,30,0,0,30,0,0,30,0,0,30, 0,0,30,0,0,30,0,0,30,0,0,30,0,0,30,0, 0,30,0,0,30,0,0,30,0,0,30,0,0,30,0,0, 30,0,0,30,0,0,30,0,0,30,0,0,30,0,0,30, 0,0,30,0,0,30,0,0,30,0,0,30,0,15,83,166, 17,1,8,255,248,240,0,240,0,240,0,240,0,240,0,240, 0,240,0,240,0,240,0,240,0,240,0,240,0,240,0,240, 0,240,0,240,0,240,0,240,0,240,0,240,0,240,0,240, 0,240,0,255,224,240,120,128,60,0,28,0,30,0,30,0, 30,0,30,0,30,0,30,0,30,0,30,0,30,0,30,0, 30,0,30,0,30,0,30,0,30,0,30,0,30,0,30,0, 30,0,30,0,30,0,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,28,112,60,120,120,31,192,16,83,166,17,1,8,15, 240,124,60,120,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 0,240,0,240,0,240,0,240,0,240,0,240,0,240,0,240, 0,240,0,240,0,240,0,240,0,241,240,247,248,255,252,252, 62,248,30,248,31,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,112,14,120, 28,60,56,15,224,15,83,166,17,1,8,255,254,224,30,224, 30,224,30,224,30,224,30,224,28,224,28,224,28,224,60,0, 60,0,60,0,60,0,60,0,60,0,56,0,120,0,120,0, 120,0,120,0,120,0,120,0,120,0,120,0,240,0,240,0, 240,0,240,0,240,0,240,0,240,0,240,1,240,1,224,1, 224,1,224,1,224,1,224,1,224,1,224,3,224,3,224,3, 192,3,192,3,192,3,192,3,192,3,192,7,192,7,192,7, 192,7,128,7,128,7,128,7,128,15,128,15,128,15,128,15, 128,15,128,15,0,15,0,15,0,31,0,31,0,31,0,31, 0,31,0,31,0,30,0,30,0,62,0,62,0,62,0,62, 0,62,0,62,0,62,0,60,0,124,0,124,0,124,0,124, 0,15,83,166,17,1,8,15,224,120,56,240,28,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,248,60,124, 120,63,240,7,192,31,240,124,120,248,60,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,240,30,240,30,240,30,240,30,240,30,240, 30,240,30,240,30,120,60,120,56,60,112,15,192,16,83,166, 17,1,8,7,240,28,28,56,30,112,14,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,240,15,240,15,240,15,240,15,240,15,240,15,240, 15,240,15,248,31,120,31,124,63,63,255,63,239,15,143,0, 15,0,15,0,15,0,15,0,15,0,15,0,15,0,15,0, 15,0,15,0,15,0,15,0,15,120,15,120,15,120,15,120, 15,120,15,120,15,120,15,120,15,120,15,120,15,120,15,120, 15,120,15,120,15,120,15,120,15,120,15,120,15,120,15,120, 15,120,15,120,30,60,62,15,240}; */ const u8g_fntpgm_uint8_t speed[1637] U8G_FONT_SECTION("speed") = { 0,32,39,0,0,40,0,0,0,0,48,57,0,40,0,40, 0,30,40,160,31,0,0,0,3,254,0,0,15,255,208,0, 31,255,232,0,63,255,212,0,127,255,244,0,255,255,236,1, 252,15,236,1,255,135,236,3,245,7,244,3,246,7,212,3, 250,15,212,3,234,15,216,7,234,15,232,7,236,15,168,7, 244,31,176,7,212,31,208,15,212,31,80,15,216,63,80,15, 232,63,96,15,168,63,160,31,176,62,160,31,208,126,160,31, 80,126,192,63,80,127,64,63,96,125,64,63,160,253,64,62, 160,253,128,126,160,254,128,126,193,250,128,127,65,251,0,125, 65,253,0,253,129,245,0,253,131,245,0,254,71,250,0,255, 255,234,0,255,255,212,0,127,255,168,0,127,255,80,0,63, 255,224,0,15,248,0,0,23,40,120,24,0,0,0,7,238, 0,15,244,0,31,212,0,31,212,0,63,216,0,127,232,0, 255,168,0,255,168,1,255,176,3,255,208,7,255,80,0,63, 96,0,63,160,0,62,160,0,126,160,0,126,192,0,127,64, 0,125,64,0,253,64,0,253,128,0,254,128,0,250,128,1, 251,0,1,251,0,1,245,0,3,245,0,3,246,0,3,250, 0,3,234,0,7,234,0,7,236,0,7,244,0,7,212,0, 15,192,0,127,255,0,127,245,0,127,245,0,255,246,0,255, 250,0,255,234,0,31,40,160,32,0,0,0,0,255,128,0, 3,255,244,0,7,255,250,0,15,255,244,0,31,255,252,0, 63,255,250,0,127,3,250,0,127,225,250,0,125,65,252,0, 253,129,244,0,254,131,244,0,250,131,246,1,250,131,250,1, 251,3,234,0,0,7,234,0,0,7,236,0,0,7,244,0, 0,15,212,0,0,31,216,0,0,63,168,0,127,255,176,1, 255,255,96,3,255,254,192,7,255,255,128,7,255,245,0,15, 255,194,0,15,224,0,0,15,252,0,0,31,168,0,0,31, 208,0,0,31,80,0,0,63,96,0,0,63,160,0,0,62, 0,0,0,127,255,254,128,127,255,250,128,127,255,250,128,127, 255,251,0,255,255,253,0,255,255,245,0,30,40,160,31,0, 0,0,3,254,0,0,15,255,208,0,31,255,232,0,127,255, 212,0,127,255,244,0,255,255,236,1,252,15,236,1,251,135, 236,3,245,7,244,3,246,7,212,3,250,15,212,0,0,15, 216,0,0,15,232,0,0,15,168,0,0,31,176,0,0,31, 80,0,0,127,160,0,63,255,64,0,63,254,128,0,127,245, 0,0,127,245,0,0,127,251,0,0,127,250,128,0,129,254, 128,0,0,253,128,0,0,253,128,0,0,254,128,0,0,250, 128,0,1,250,128,127,193,251,0,125,65,253,0,253,65,245, 0,253,131,245,0,254,71,250,0,255,255,236,0,255,255,212, 0,127,255,168,0,127,255,80,0,63,255,224,0,15,240,0, 0,26,40,160,27,0,0,3,250,0,0,7,234,0,0,7, 236,0,0,7,244,0,0,7,212,0,0,15,212,0,0,15, 216,0,0,15,232,0,0,15,168,0,0,31,176,0,0,31, 208,0,0,31,80,126,192,63,80,127,64,63,96,125,64,63, 160,253,128,62,160,254,128,126,0,250,128,127,255,250,128,127, 255,251,0,127,255,253,0,255,255,245,0,255,255,245,0,255, 255,246,0,0,3,250,0,0,3,234,0,0,7,234,0,0, 7,236,0,0,7,244,0,0,7,212,0,0,15,216,0,0, 15,232,0,0,15,168,0,0,31,168,0,0,31,176,0,0, 31,208,0,0,31,80,0,0,63,80,0,0,63,96,0,0, 63,160,0,0,126,160,0,31,40,160,32,0,0,0,127,255, 250,0,255,255,252,0,255,255,244,0,255,255,246,0,255,255, 246,1,255,255,250,1,248,0,0,1,255,0,0,3,245,0, 0,3,246,0,0,3,250,0,0,3,234,0,0,7,234,0, 0,7,236,0,0,7,255,224,0,7,255,253,0,15,255,254, 128,15,255,253,64,15,255,255,64,15,255,254,192,31,192,254, 192,31,168,126,224,31,80,126,192,0,0,127,64,0,0,125, 64,0,0,253,128,0,0,254,128,0,0,250,128,0,1,250, 128,127,193,251,0,125,65,253,0,253,129,245,0,253,131,245, 0,252,71,250,0,255,255,236,0,255,255,212,0,127,255,168, 0,127,255,80,0,63,255,224,0,15,240,0,0,30,40,160, 31,0,0,0,3,254,0,0,15,255,208,0,31,255,232,0, 127,255,212,0,127,255,244,0,255,255,236,1,252,15,236,1, 255,135,236,3,245,7,244,3,246,7,212,3,250,15,212,3, 234,0,8,7,234,0,0,7,236,0,0,7,255,224,0,7, 255,253,0,15,255,254,128,15,255,253,64,15,255,254,192,15, 255,254,192,31,192,126,160,31,168,126,192,31,80,126,192,63, 80,127,64,63,96,125,64,63,160,253,128,62,160,254,128,126, 160,250,128,126,193,250,128,127,65,251,0,125,65,253,0,253, 129,245,0,253,131,246,0,254,71,250,0,255,255,236,0,255, 255,212,0,127,255,168,0,127,255,80,0,63,255,224,0,15, 240,0,0,31,40,160,32,0,0,0,31,255,254,0,63,255, 254,0,63,255,252,0,63,255,252,0,63,255,254,0,127,255, 250,0,0,1,250,0,0,3,252,0,0,7,244,0,0,7, 234,0,0,15,236,0,0,31,212,0,0,31,168,0,0,63, 176,0,0,127,80,0,0,126,160,0,0,254,0,3,255,255, 212,3,255,255,216,7,255,255,232,7,255,255,168,7,255,255, 168,7,255,255,176,0,31,192,0,0,63,168,0,0,63,208, 0,0,127,96,0,0,254,160,0,0,253,64,0,1,254,128, 0,3,250,128,0,3,245,0,0,7,250,0,0,15,234,0, 0,15,212,0,0,31,232,0,0,63,176,0,0,63,80,0, 0,127,160,0,0,254,192,0,0,30,40,160,31,0,0,0, 1,254,0,0,15,255,208,0,31,255,232,0,63,255,212,0, 127,255,244,0,255,31,236,1,252,7,236,1,255,135,236,1, 245,7,244,3,246,7,212,3,250,15,212,3,234,15,216,7, 234,15,232,7,236,31,168,7,244,31,176,7,244,31,80,7, 232,127,160,3,255,255,64,3,255,254,128,1,255,245,0,1, 255,245,0,7,255,251,0,15,227,250,128,31,128,254,128,31, 120,253,128,63,160,253,128,62,160,254,128,126,160,250,128,126, 193,250,128,125,65,251,0,125,65,253,0,253,129,245,0,253, 131,245,0,254,71,250,0,255,255,236,0,255,255,212,0,127, 255,168,0,127,255,80,0,63,255,224,0,15,240,0,0,30, 40,160,31,0,0,0,3,254,0,0,15,255,240,0,31,255, 216,0,63,255,212,0,127,255,244,0,255,255,236,1,252,15, 236,1,255,135,236,1,245,7,244,3,246,7,212,3,250,15, 212,3,234,15,216,7,234,15,232,7,236,15,168,7,244,31, 176,7,212,31,208,15,212,31,80,15,216,63,80,15,216,63, 96,15,192,127,160,15,255,254,160,15,255,254,160,15,255,254, 192,7,255,255,64,3,255,253,64,0,255,253,64,0,0,253, 128,0,0,254,128,0,0,250,128,127,193,251,0,125,65,253, 0,253,129,245,0,253,131,245,0,254,71,250,0,255,255,234, 0,255,255,212,0,127,255,168,0,127,255,80,0,63,254,224, 0,15,249,0,0}; const u8g_fntpgm_uint8_t symbols[177] U8G_FONT_SECTION("symbols") = { 0,13,17,0,238,18,0,0,0,0,48,57,0,0,238,18, 0,6,18,18,13,0,238,12,12,28,28,60,60,124,124,252, 252,252,124,124,60,60,28,28,12,6,18,18,13,7,238,192, 192,224,224,240,240,248,248,252,252,252,248,248,240,240,224,224, 192,9,16,32,13,1,239,28,0,32,0,32,0,64,0,64, 0,64,0,64,0,128,0,255,128,255,128,255,128,255,128,255, 128,255,128,255,128,255,0,9,16,32,13,2,239,4,0,62, 0,38,0,67,0,67,0,67,0,67,0,255,128,0,128,0, 128,0,128,0,128,0,128,0,128,0,128,1,128,0,0,0, 13,0,0,0,0,0,13,0,0,0,0,0,13,0,0,0, 0,0,13,0,0,0,0,0,13,0,0,0,0,0,13,0, 0}; const u8g_fntpgm_uint8_t dax[1316] U8G_FONT_SECTION("dax") = { 0,25,60,0,195,25,0,0,0,0,48,59,0,0,195,25, 0,20,50,150,24,4,195,16,0,0,31,128,0,15,248,0, 7,255,240,1,255,240,1,255,240,1,255,240,1,255,240,1, 255,240,1,255,240,0,127,240,0,15,240,0,0,240,0,0, 0,0,128,0,1,252,0,1,255,224,3,255,240,1,255,240, 0,255,240,0,15,240,0,0,240,0,0,192,0,0,0,0, 255,224,1,255,240,7,255,240,15,255,240,31,195,240,31,7, 48,62,7,16,124,7,0,120,7,0,120,14,0,240,30,0, 240,31,240,240,31,240,240,1,240,240,0,0,240,0,0,120, 0,0,120,0,0,124,0,0,62,0,16,31,0,48,31,192, 240,15,255,240,3,255,240,1,255,240,0,63,128,23,25,75, 24,1,211,7,128,0,7,240,0,7,254,0,7,255,224,7, 255,254,7,239,254,7,192,126,7,192,2,7,128,0,7,192, 0,7,224,0,14,30,0,12,7,224,24,0,0,24,7,248, 48,32,2,32,64,0,65,0,0,194,0,0,128,0,0,4, 0,0,8,0,0,0,0,0,0,0,0,16,0,0,23,37, 111,24,1,199,8,0,0,56,0,0,56,0,0,56,0,0, 24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,8,0,0,0,0,0,16,0,0,0,0,0,32,0, 0,0,0,0,64,0,0,128,0,0,0,0,0,0,7,128, 0,31,24,0,63,28,0,124,30,0,251,30,0,254,54,1, 252,58,1,236,0,1,204,0,1,207,192,1,239,254,1,239, 254,0,255,246,0,255,198,0,126,30,0,63,252,0,31,248, 0,7,224,24,45,135,24,0,197,255,255,248,255,255,252,255, 255,252,255,255,248,255,255,248,255,255,240,255,255,224,255,255, 192,255,255,128,255,255,0,63,252,0,0,0,0,0,0,0, 0,0,0,240,0,0,255,128,0,255,254,0,255,255,255,255, 255,255,63,255,255,1,255,255,0,0,31,0,0,15,192,0, 3,224,0,0,240,0,0,192,0,0,192,0,0,224,0,0, 113,0,0,127,0,0,62,0,0,252,0,0,252,0,1,188, 0,3,60,0,254,60,0,128,127,255,0,127,255,0,252,0, 0,248,0,0,240,0,0,240,0,0,224,0,0,128,0,0, 24,28,84,24,0,207,0,0,15,0,0,127,0,0,255,192, 3,255,255,255,255,255,255,255,255,255,255,15,255,255,0,127, 252,0,1,248,0,0,0,0,0,0,0,0,0,0,0,0, 0,127,224,128,127,240,32,127,240,16,255,192,0,255,128,0, 255,128,0,31,0,0,15,0,0,2,0,0,0,0,0,0, 6,0,1,28,0,1,60,0,1,252,24,16,48,24,0,203, 0,0,12,0,0,63,3,0,127,63,0,127,63,224,255,31, 240,255,142,253,255,128,255,255,193,255,249,3,254,227,3,254, 194,67,254,0,195,255,0,195,255,0,128,0,0,128,0,0, 24,29,87,24,0,199,0,0,1,0,0,1,224,0,0,252, 0,0,254,0,0,255,128,0,255,192,0,255,240,0,255,248, 0,255,252,0,255,252,0,15,254,0,15,254,0,15,254,0, 15,252,0,7,252,1,9,224,1,24,192,15,56,64,15,224, 0,15,192,0,15,0,0,15,0,0,15,0,0,7,0,0, 7,0,0,7,0,0,3,0,0,1,0,0,1,24,51,153, 24,0,205,0,31,0,0,63,192,0,127,224,0,127,224,0, 63,224,0,3,224,0,1,240,0,0,248,0,0,124,0,0, 60,0,0,60,0,0,124,0,7,252,0,7,252,0,0,255, 0,0,255,0,0,255,0,0,255,0,1,255,0,7,255,0, 31,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, 255,255,224,127,254,0,63,224,0,6,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,1,0,0,3,0,0,7,0,0,7,0,0, 7,0,0,15,0,0,14,0,0,30,0,0,16,0,0,16, 0,0,16,0,0,16,0,0,48,0,0,32,24,11,33,24, 0,209,0,0,1,0,0,2,0,0,4,240,0,0,240,0, 0,240,0,8,240,0,0,248,0,16,240,0,0,224,0,0, 192,0,0,23,47,141,24,0,195,4,0,0,4,0,0,6, 0,0,2,0,0,2,0,0,2,0,0,6,0,0,4,0, 0,4,0,0,28,0,0,24,0,0,24,0,0,0,0,0, 224,0,0,224,0,0,224,0,0,224,0,0,224,0,0,112, 0,0,112,0,0,56,0,0,57,252,0,31,255,128,31,255, 192,31,255,224,62,7,240,127,1,248,243,0,252,227,128,124, 193,128,60,193,192,62,128,224,30,128,240,30,128,112,30,128, 96,30,128,0,30,128,0,30,192,0,60,192,0,60,224,0, 124,240,0,248,248,1,240,254,7,240,255,255,224,63,255,128, 31,255,0,3,248,0,22,27,81,24,0,215,248,0,0,248, 0,0,248,0,0,252,0,0,252,0,0,252,0,0,248,0, 0,248,0,0,248,0,0,224,0,0,224,0,0,224,0,0, 192,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,15,254,0,15,255,0,7,255,128,70,3,192,224,0, 96,224,0,48,224,0,24,192,0,12,128,0,4,19,43,129, 24,0,199,3,0,0,3,0,0,1,128,0,1,128,0,1, 128,0,1,128,0,1,128,0,3,0,0,3,0,0,3,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, 0,0,128,0,0,0,0,0,0,0,0,0,0,0,1,248, 0,0,254,0,12,255,0,28,31,128,62,127,192,62,61,192, 127,28,224,127,14,224,127,142,224,123,159,224,123,255,224,121, 255,224,61,249,192,63,227,192,31,207,128,15,255,0,7,254, 0,1,248,0}; const u8g_fntpgm_uint8_t frame[513] U8G_FONT_SECTION("frame") = { 0,33,31,0,248,29,0,0,0,0,48,54,0,24,248,29, 0,29,29,116,32,3,248,0,0,0,24,0,0,0,96,0, 0,1,192,0,0,6,224,0,0,24,96,0,0,32,48,0, 0,192,48,0,1,0,24,0,2,0,0,0,4,0,0,0, 8,0,0,0,24,0,0,0,60,0,0,0,78,0,0,0, 135,0,0,1,3,128,0,2,1,0,0,2,0,0,0,4, 0,0,0,8,0,0,0,8,0,0,0,16,0,0,0,16, 0,0,0,32,0,0,0,48,0,0,0,120,0,0,0,78, 0,0,0,135,0,0,0,129,0,0,0,29,29,116,32,3, 251,129,0,0,0,135,0,0,0,78,0,0,0,120,0,0, 0,48,0,0,0,32,0,0,0,16,0,0,0,16,0,0, 0,8,0,0,0,8,0,0,0,4,0,0,0,2,0,0, 0,2,1,0,0,1,3,128,0,0,135,0,0,0,78,0, 0,0,60,0,0,0,24,0,0,0,8,0,0,0,4,0, 0,0,2,0,0,0,1,0,24,0,0,192,48,0,0,32, 48,0,0,24,96,0,0,6,224,0,0,1,192,0,0,0, 96,0,0,0,24,29,29,116,32,0,248,192,0,0,0,48, 0,0,0,28,0,0,0,59,0,0,0,48,192,0,0,96, 32,0,0,96,24,0,0,192,4,0,0,0,2,0,0,0, 1,0,0,0,0,128,0,0,0,192,0,0,1,224,0,0, 3,144,0,0,7,8,0,0,14,4,0,0,4,2,0,0, 0,2,0,0,0,1,0,0,0,0,128,0,0,0,128,0, 0,0,64,0,0,0,64,0,0,0,32,0,0,0,96,0, 0,0,240,0,0,3,144,0,0,7,8,0,0,4,8,8, 32,32,8,0,248,16,32,32,32,64,64,64,64,64,128,128, 128,128,128,254,129,129,254,128,128,128,128,128,64,64,64,64, 64,32,32,32,16,32,8,32,32,0,16,0,127,254,0,15, 130,65,240,112,2,64,14,128,2,64,1,0,2,64,0,0, 2,64,0,0,2,64,0,0,1,128,0,18,8,24,18,0, 16,0,1,128,0,2,64,0,2,64,0,2,64,128,2,64, 112,2,64,15,130,64,0,127,192,8,18,18,8,0,6,8, 4,4,4,2,2,2,2,2,1,1,1,1,1,127,129,129, 127}; //Todo: //Top speed reached <> u8g_t u8g; u8g_t *u8gpointer = &u8g; uint16_t Tacho1 = 0; uint8_t TachoAt = 0; uint8_t debugRelayStatus = 0; uint8_t breakMainLoop = 0; uint8_t bootfirstsecond = 1; // ensures we don't go to sleep before we start uint8_t RTCseconds = 50; uint8_t RTCminutes = 19; uint8_t RTChours = 11; char RTCstring[9]; //00:00:00N seems to work with 8 length but one extra for end byte anyways char RTCstringsec[3]; uint8_t RTCinterrupt = 0; uint32_t OdometerKilometersLastSaved = 0; uint32_t EEMEM OdoKm = 0; //Default 500km uint32_t OdometerKilometers = 0; // 1 = 1 meter. 4 million kilometers max val. uint8_t OdometerYpos = 0; uint8_t OdometerGenerated = 0; char OdometerOutputstr[OdometerStringlength+4]; //NULL + km uint32_t Odometer2Kilometers = 0; //1 = 1 meter. uint32_t EEMEM Odo2Km = 0; uint8_t Odometer2Ypos = 0; uint8_t Odometer2Generated = 0; char Odometer2Outputstr[Odometer2Stringlength+4]; //NULL + km uint16_t tachoTick = 0; //10,000 of a second. 0.0001s. uint8_t generatedKMH = 0; uint8_t DAXkmh = 0; uint8_t DAXkmhHistory = 0; //1 = debug set this to 0 to not store EEPROM directly after boot up uint8_t DAXkmhStopTimeMinutes = 0; uint8_t DAXkmhStopTimeHours = 0; uint16_t C_DistBetweenMagnets = 0; uint16_t RelayOffTimeCounter = 0; //10,000 of a second (6s max) char DAXkmhstring[4]; uint8_t ThrottleActive = 1; //uint8_t ThrottlePressStartSecond = 0; uint8_t lockedbike = 1; uint16_t lockedKeypressHistory = 0xAAAA; //2 bit per keypress = 8 keystrokes stored, bit shift old one out for new one. char lockedbikeStr[17] = {"1010101010101010"}; uint8_t MenuLastVpos = 0; int8_t MenuPos = 0; //negative vertical, positive horizontal int8_t MenuPress = 0; int8_t LastKeyPress = 1; uint8_t LastKPTMinute = 0; uint8_t LastKPTHour = 0; uint8_t isSleeping = 0; uint8_t SleepShedule = 0; uint8_t sleepWakeUpNow = 0; int8_t MenuSettingActive = 127; uint8_t MenuSelectedOption = 0; uint8_t MenuCurrentMenuItems = 0; uint8_t MenuTimeEditPos = 0; uint8_t MenuTimeEditVal = 0; char MenuTimeEditValString[2] = "0"; //Default settings uint8_t clockShowSeconds = 1; //uint8_t enabledEEPROMsave = 1; uint8_t sleepDelay = 1; // in minutes char sleepDelayStr[12]; uint8_t throttleOffTime = 10; // * ThrottleOffTimeMultiplier (12) in milliseconds char throttleOffTimeStr[8]; uint8_t numberofmagnets = 8; char numberofmagnetsStr[10]; uint8_t lockonsleep = 1; //lock bike when going to sleep? true/false char lockonsleepStr[6] = {"true"}; uint16_t wheelCircum = WHEEL_CIRCUMFERENCE; char wheelCircumStr[8]; //9999 mm char topspeedStr[10]; //uint8_t triggerPerMagnet = TRIGGERS_PER_MAGNET; //char triggerPerMagnetStr[2]; //9 //uint8_t magnetWidth = MAGNET_WIDTH; //char magnetWidthStr[6]; //99 mm uint8_t showDebugDots = 1; //EEPROM settings (2) //uint8_t EEMEM EtriggerPerMagnet = TRIGGERS_PER_MAGNET; uint16_t EEMEM EwheelCircum = WHEEL_CIRCUMFERENCE; //uint8_t EEMEM EmagnetWidth = MAGNET_WIDTH; //EEPROM settings uint8_t EEMEM EclockShowSeconds = 0; uint8_t EEMEM EsleepDelay = 1; uint8_t EEMEM EthrottleOffTime = 10; uint8_t EEMEM Enumberofmagnets = 8; uint8_t EEMEM Elockonsleep = 1; uint8_t invertRelay = 0; uint8_t EEMEM EinvertRelay = 0; uint8_t topSpeedReached = 0; uint8_t EEMEM EtopSpeedReached = 0; //Array of positions for the analog clock hand static const uint8_t xposHand[76] = {48,46,44,41,39,37,35,32,30,28,26,24,22,21,19,18,16,15,14,13,12,12,11,11,11,10,11,11,11,12,12,13,14,15,16,18,19,21,22,24,26,28,30,32,35,37,39,41,44,46,48,50,52,55,57,59,61,64,66,68,70,72,74,75,77,78,80,81,82,83,84,84,85,85,85,86}; static const uint8_t yposHand[76] = {86,85,85,85,84,84,83,82,81,80,78,77,75,74,72,70,68,66,64,61,59,57,55,52,50,48,46,44,41,39,37,35,32,30,28,26,24,22,21,19,18,16,15,14,13,12,12,11,11,11,10,11,11,11,12,12,13,14,15,16,18,19,21,22,24,26,28,30,32,35,37,39,41,44,46,48}; uint8_t xposGenHand = 0; uint8_t yposGenHand = 0; void h_speedToXY(uint8_t speed){ //speed is 0..76 uint8_t clampedspeed; if(speed > 75){ clampedspeed = 76; }else{ clampedspeed = speed; } xposGenHand = xposHand[clampedspeed]; yposGenHand = yposHand[clampedspeed]; } void h_CalculateSetDistanceBetweenMagnets(void){ C_DistBetweenMagnets = wheelCircum / numberofmagnets; /* if(magnetWidth == 0){ C_DistBetweenMagnets = wheelCircum / numberofmagnets; }else{ C_DistBetweenMagnets = (wheelCircum - (magnetWidth * numberofmagnets)) / numberofmagnets; } */ } void a_StopTachoTimer(void){ TCCR1B &= ~ (1< 0){ //We just stopped DAXkmhStopTimeMinutes = RTCminutes; //Save time we stopped DAXkmhStopTimeHours = RTChours; } DAXkmhHistory = speedkmh; if(speedkmh > 0 && MenuPos == 0){ //Only generate when we are actually displaying the odometer generate_odometer(); generate_odometer2(); } if(MenuPos == 0 || MenuPos == -1 || MenuPos == -4){ //Only generate speed string when we are displaying it //generate string generate_speed(speedkmh); } } void a_StoreOdometerValue(void){ if(OdometerKilometers - OdometerKilometersLastSaved > 100){ //Only save to EEPROM if we moved over 100 meters since last eeprom burn eeprom_busy_wait(); eeprom_update_dword(&OdoKm, OdometerKilometers); //eeprom_update_block((void*)&OdometerKilometers, &OdoKm, 4); eeprom_busy_wait(); OdometerKilometersLastSaved = OdometerKilometers; eeprom_update_dword(&Odo2Km, Odometer2Kilometers); eeprom_busy_wait(); } } void h_setRelay(uint8_t seton){ //Always set both coils to LOW just in case PORTB &= ~ (1<<4); PORTB &= ~ (1<<2); if(seton != invertRelay){ //turn on CDI debugRelayStatus = 1; PORTB |= (1<<2); u8g_Delay(RELAY_DELAY); PORTB &= ~ (1<<2); }else{ //turn off CDI debugRelayStatus = 0; PORTB |= (1<<4); u8g_Delay(RELAY_DELAY); //wait for relay to switch position PORTB &= ~ (1<<4); //reset the reset } } void GoToSleep(uint8_t quick){ if(quick){ SleepShedule = 1; }else{ isSleeping = 1; if(lockonsleep%2 == 1){ //Lock bike lockedbike = 1; lockedKeypressHistory = 0xAAAA; strcpy(lockedbikeStr, "1010101010101010"); MenuPos = MenuLastVpos; MenuSettingActive = 127; //If we are in settings we dont want to get stuck there. h_setRelay(0); //turn off CDI }else{ MenuPos = MenuLastVpos; MenuSettingActive = 127; h_setRelay(1); //turn on CDI so its on when we wake up and we could drive while sleeping. } a_burnTopSpeedReached(); //Store top speed reached in EEPROM a_StopTachoTimer(); //Turn off tachometer u8g_SleepOn(&u8g); //Display to sleep mode SleepShedule = 1; } } void a_IsBikeStopped(void){ //If bike has not moved in X minutes, save odometer value uint8_t tmpMinutes; uint8_t tmpHours; uint8_t n = 0; if(DAXkmh == 0){ //this ensures we have not moved since last time we stopped tmpMinutes = DAXkmhStopTimeMinutes; tmpHours = DAXkmhStopTimeHours; while(n <= sleepDelay){ //Same as sleep delay! (this fires first) tmpMinutes++; if(tmpMinutes == 60){ tmpHours++; tmpMinutes = 0; if(tmpHours == 24){ tmpHours = 0; } } n++; } if(tmpMinutes == RTCminutes && tmpHours == RTChours){ // X minutes has passed since last movement? a_StoreOdometerValue(); //Then go to sleep GoToSleep(0); } } } void a_setDisplayInverseOn(void){ u8g_call_dev_fn(u8gpointer, u8gpointer->dev, 18, NULL); } void a_setDisplayInverseOff(void){ u8g_call_dev_fn(u8gpointer, u8gpointer->dev, 19, NULL); } void generate_clockstring(void){ char clockbuffer[3]; //itoa/strcat seems to need one extra bit for end byte? if(MenuPos == PAGE_TIME || MenuPos == 0 || MenuPos == -2){ //Only generate if we are drawing the clock if(RTChours < 10){strcpy(RTCstring, "0");}else{strcpy(RTCstring, "");} itoa(RTChours, clockbuffer, 10); strcat(RTCstring, clockbuffer); strcat(RTCstring, ":"); //00: if(RTCminutes < 10){strcat(RTCstring, "0");}else{strcat(RTCstring, "");} itoa(RTCminutes, clockbuffer, 10); //B 00 strcat(RTCstring, clockbuffer); //00:00 //strcat(RTCstring, ":"); //00:00: if(clockShowSeconds){ if(RTCseconds < 10){strcpy(RTCstringsec, "0");}else{strcpy(RTCstringsec, "");} itoa(RTCseconds, clockbuffer, 10); //B 00 strcat(RTCstringsec, clockbuffer); //00:00:00 } } } void d_clock(uint8_t bigclock){ uint8_t tempstrwidth = 0; uint8_t tempstrmiddle = 0; uint8_t tmpmtp = MenuTimeEditPos%4; uint8_t tmpmtpX = 0; if(!bigclock){ u8g_DrawStr(&u8g, 0, 7, RTCstring); }else{ tempstrwidth = u8g_GetStrWidth(&u8g, RTCstring); tempstrmiddle = tempstrwidth / 2; u8g_DrawStr(&u8g, 48-tempstrmiddle, bigclock, RTCstring); if(MenuSettingActive == PAGE_TIME_setclock){ u8g_SetColorIndex(&u8g, 15); switch(tmpmtp){ case 0: tmpmtpX = 4; break; case 1: tmpmtpX = 25; break; case 2: tmpmtpX = 54; break; case 3: tmpmtpX = 74; } u8g_DrawBox(&u8g,tmpmtpX, bigclock-27,19,27); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g,tmpmtpX, bigclock, MenuTimeEditValString); } } if(clockShowSeconds){ if(!bigclock){ tempstrwidth = u8g_GetStrWidth(&u8g, RTCstring); u8g_SetFont(&u8g, u8g_font_pixelle_micro); u8g_DrawStr(&u8g, 1+tempstrwidth, 5, RTCstringsec); }else{ u8g_SetFont(&u8g, u8g_font_timR08); u8g_DrawStr(&u8g, 80, bigclock+11, RTCstringsec); } } } void d_speed(uint8_t ypos){ if(generatedKMH < 10){ u8g_DrawStr(&u8g, 32, ypos, DAXkmhstring); }else if(generatedKMH < 100){ u8g_DrawStr(&u8g, 17, ypos, DAXkmhstring); }else{ u8g_DrawStr(&u8g, 6, ypos, DAXkmhstring); } } void d_tachodial(void){ //0..6 u8g_SetFont(&u8g, frame); u8g_SetColorIndex(&u8g, 15); //0..2 corners u8g_DrawStr(&u8g, 0, 24, "0"); u8g_DrawStr(&u8g, 0, 64+24, "1"); u8g_DrawStr(&u8g, 64, 24, "2"); //3 left mid u8g_DrawStr(&u8g, 0, 32+24, "3"); //4 mid top u8g_DrawStr(&u8g, 32, 24, "4"); //5 mid bottom u8g_DrawStr(&u8g, 32, 64+24+24, "5"); //6 right mid u8g_DrawStr(&u8g, 64+24, 32+24, "6"); //Draw 0,25,50,75 u8g_SetColorIndex(&u8g, 1); u8g_SetFont(&u8g, u8g_font_timR08); //settings font 8pixel height if(generatedKMH > 6){ u8g_DrawStr(&u8g, 46, 79+8, "0"); } if(generatedKMH < 18 || generatedKMH > 31){ u8g_DrawStr(&u8g, 11, 44+8, "25"); } if(generatedKMH < 44 || generatedKMH > 56){ u8g_DrawStr(&u8g, 44, 11+7, "50"); } if(generatedKMH < 69){ u8g_DrawStr(&u8g, 77, 44+8, "75"); } //Draw line. //generatedKMH u8g_SetColorIndex(&u8g, 15); h_speedToXY(generatedKMH); u8g_DrawLine(&u8g, 48, 48, xposGenHand, yposGenHand); } void d_arrows(void){ u8g_SetFont(&u8g, symbols); u8g_SetColorIndex(&u8g, 1); u8g_DrawStr(&u8g, 0, 39, "0"); u8g_DrawStr(&u8g, 83, 39, "1"); } void d_bordertb(void){ u8g_SetFont(&u8g, symbols); u8g_SetColorIndex(&u8g, 1); //box *might* be faster than line because line can be diagonal u8g_DrawBox(&u8g,0,0,96,1); u8g_DrawBox(&u8g,0,95,96,1); u8g_DrawBox(&u8g,0,14,96,1); } void d_odometer(void){ if(OdometerYpos == 0 && OdometerGenerated == 1){ //First time calculate middle point. Not a bug 1 = we have something to measure. OdometerYpos = 48-(u8g_GetStrWidth(&u8g, OdometerOutputstr) / 2); } u8g_DrawStr(&u8g, OdometerYpos, 27, OdometerOutputstr); } void d_odometer2(void){ if(Odometer2Ypos == 0 && Odometer2Generated == 1){ //First time calculate middle point Odometer2Ypos = 48-(u8g_GetStrWidth(&u8g, Odometer2Outputstr) / 2); } u8g_DrawStr(&u8g, Odometer2Ypos, 45, Odometer2Outputstr); } void d_settingstitle(char* dtext){ uint8_t stringpos = 0; stringpos = 48-(u8g_GetStrWidth(&u8g, dtext)/2); u8g_DrawStr(&u8g, stringpos, 11, dtext); } void d_settingsmenu(char* items[], uint8_t iamount, uint8_t ihighlighted){ //char amessage[] = "now is the time"; //char *pmessage = "now is the time"; //same thing but pmessage data is typically stored in string table while amessage is in scope MenuCurrentMenuItems = iamount; u8g_SetFont(&u8g, u8g_font_timR08); u8g_SetColorIndex(&u8g, 15); uint8_t n = 0; uint8_t ypos = 0; while(n= 2){triggerPerMagnet = 1;}else{triggerPerMagnet++;} break; case RIGHT: if(triggerPerMagnet >= 2){triggerPerMagnet = 1;}else{triggerPerMagnet++;} break; case DOWN: if(triggerPerMagnet == 1){triggerPerMagnet = 2;}else{triggerPerMagnet--;} break; case LEFT: if(triggerPerMagnet == 1){triggerPerMagnet = 2;}else{triggerPerMagnet--;} } generate_triggerpermagnetpage(); break; case PAGE_GENERAL_magnetwidth: switch(keypress){ case UP: if(magnetWidth >= 99){magnetWidth = 0;}else{magnetWidth++;} break; case RIGHT: if(magnetWidth >= 99){magnetWidth = 0;}else{magnetWidth++;} break; case DOWN: if(magnetWidth == 0){magnetWidth = 99;}else{magnetWidth--;} break; case LEFT: if(magnetWidth == 0){magnetWidth = 99;}else{magnetWidth--;} } generate_magnetwidthpage(); break; */ } } } /* void d_triggepermagnetpage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, triggerPerMagnetStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, triggerPerMagnetStr); } */ void d_wheelcircumpage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, wheelCircumStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, wheelCircumStr); } void d_topspeed(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, topspeedStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, topspeedStr); } /* void d_magnetwidthpage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, magnetWidthStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, magnetWidthStr); } */ void d_throttlepage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, throttleOffTimeStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, throttleOffTimeStr); } void d_magnetpage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, numberofmagnetsStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, numberofmagnetsStr); } void d_sleepdelaypage(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, sleepDelayStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, sleepDelayStr); } void d_lockonsleep(void){ u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g, 18, 76,(u8g_GetStrWidth(&u8g, lockonsleepStr))+4,12); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 20, 86, lockonsleepStr); } void d_lockedbike(void){ u8g_SetFont(&u8g, symbols); u8g_SetColorIndex(&u8g, 15); u8g_DrawStr(&u8g, 42, 20, "2"); u8g_SetColorIndex(&u8g, 1); u8g_DrawStr(&u8g, 42, 20, "3"); u8g_SetColorIndex(&u8g, 15); u8g_SetFont(&u8g, u8g_font_timR08); u8g_DrawStr(&u8g, 18, 55, "THIS HONDA"); u8g_DrawStr(&u8g, 23, 65, "IS LOCKED"); u8g_DrawStr(&u8g, 8, 95, lockedbikeStr); //print cool binary data in middle (16 bits is 80 pixels long btw) } void e_unlockbike(uint8_t keypress){ //lockedKeypressHistory 16bit uint8_t twobits = 0; uint8_t tmplen = 0; char tmpbikestr[17]; //uint16_t bitmask = 3; // 0b0000000000000011 switch(keypress){ case UP: twobits = 0; break; case DOWN: twobits = 1; break; case LEFT: twobits = 2; break; case RIGHT: twobits = 3; break; } lockedKeypressHistory = (lockedKeypressHistory << 2); //shift two bits to left lockedKeypressHistory |= twobits; //OR in the two bits //generate cool looking binary string itoa(lockedKeypressHistory, tmpbikestr, 2); //check length and add leading zeros tmplen = strlen(tmpbikestr); uint8_t n = 0; uint8_t docopy = 1; n = 16-tmplen; while(n > 0){ if(n == (16-tmplen)){ strcpy(lockedbikeStr, "0"); }else{ strcat(lockedbikeStr, "0"); } docopy = 0; n--; } if(docopy){ strcpy(lockedbikeStr, tmpbikestr); }else{ strcat(lockedbikeStr, tmpbikestr); } //Check if the value is correct for unlock if(lockedKeypressHistory == PASSPHRASE){ lockedbike = 0; h_setRelay(1); //turn on CDI } } void draw(void) { if(debugRelayStatus && showDebugDots){ //debug relay status u8g_SetColorIndex(&u8g, 1); u8g_DrawPixel(&u8g,0,0); } if(lockedbike){ d_lockedbike(); return; //Dont want to draw anything else while bike is locked } //What menu do we need to draw? if(MenuPos > 0){ //in settings, show arrows and bars d_arrows(); d_bordertb(); } //Show pixel that indicates throttle is active if(ThrottleActive && showDebugDots){ u8g_SetColorIndex(&u8g, 1); u8g_DrawPixel(&u8g,95,0); } switch (MenuPos){ case PAGE_LOCK: u8g_SetFont(&u8g, u8g_font_timR08); u8g_SetColorIndex(&u8g, 15); d_settingstitle("LOCK BIKE"); u8g_SetColorIndex(&u8g, 15); u8g_DrawBox(&u8g,9,43,77,11); u8g_SetColorIndex(&u8g, 0); u8g_DrawStr(&u8g, 11, 52, "PRESS TO LOCK"); break; case PAGE_TIME: u8g_SetFont(&u8g, u8g_font_timR08); u8g_SetColorIndex(&u8g, 15); d_settingstitle("TIME SETTINGS"); char *menu_strings2[2] = { "Set time", "Show seconds"}; d_settingsmenu(menu_strings2, 2, MenuSelectedOption); u8g_SetColorIndex(&u8g, 15); u8g_SetFont(&u8g, u8g_font_fub25n); d_clock(84); break; case PAGE_GENERAL: u8g_SetFont(&u8g, u8g_font_timR08); u8g_SetColorIndex(&u8g, 15); d_settingstitle("GENERAL SETTINGS"); char *menu_strings1[5] = { "reset odometer", "throttle off-time", "magnet amount", "sleep delay", "lock on sleep"}; d_settingsmenu(menu_strings1, 5, MenuSelectedOption); if(MenuSettingActive == PAGE_GENERAL_throttleofftime){ d_throttlepage();} if(MenuSettingActive == PAGE_GENERAL_setmagnets){d_magnetpage();} if(MenuSettingActive == PAGE_GENERAL_setsleepdelay){d_sleepdelaypage();} if(MenuSettingActive == PAGE_GENERAL_setlockonsleep){d_lockonsleep();} break; case PAGE_GENERAL_TWO: u8g_SetFont(&u8g, u8g_font_timR08); u8g_SetColorIndex(&u8g, 15); d_settingstitle("MORE SETTINGS"); char *menu_strings3[4] = {"wheel circumference", "top speed", "debug dots", "invert relay"}; d_settingsmenu(menu_strings3, 4, MenuSelectedOption); //if(MenuSettingActive == PAGE_GENERAL_triggerpermagnet){ d_triggepermagnetpage();} if(MenuSettingActive == PAGE_GENERAL_wheelcircum){d_wheelcircumpage();} //if(MenuSettingActive == PAGE_GENERAL_magnetwidth){d_magnetwidthpage();} if(MenuSettingActive == PAGE_GENERAL_topspeed){d_topspeed();} break; case 0: u8g_SetColorIndex(&u8g, 1); //0 black .. 15 white u8g_SetFont(&u8g, u8g_font_timR08); d_clock(0); u8g_SetFont(&u8g, u8g_font_courR14); d_odometer(); d_odometer2(); u8g_SetColorIndex(&u8g, 15); u8g_SetFont(&u8g, speed); d_speed(96); break; case -1: u8g_SetColorIndex(&u8g, 15); u8g_SetFont(&u8g, speed); d_speed(65); break; case -2: u8g_SetColorIndex(&u8g, 15); u8g_SetFont(&u8g, u8g_font_fub25n); d_clock(55); break; case -3: #define daxbitym 20 u8g_SetFont(&u8g, dax); u8g_SetColorIndex(&u8g, 1); u8g_DrawStr(&u8g, 0, daxbitym, "0"); //b1 u8g_DrawStr(&u8g, 24, daxbitym, "3"); //b2 u8g_DrawStr(&u8g, 48, daxbitym, "6"); //b3 u8g_DrawStr(&u8g, 72, daxbitym, "9"); //b4 u8g_SetColorIndex(&u8g, 2); //half white? u8g_DrawStr(&u8g, 0, daxbitym, "1"); //h1 u8g_DrawStr(&u8g, 24, daxbitym, "4"); //h2 u8g_DrawStr(&u8g, 48, daxbitym, "7"); //h3 u8g_DrawStr(&u8g, 72, daxbitym, ":"); //h4 u8g_SetColorIndex(&u8g, 15); //white u8g_DrawStr(&u8g, 0, daxbitym, "2"); //w1 u8g_DrawStr(&u8g, 24, daxbitym, "5"); //w2 u8g_DrawStr(&u8g, 48, daxbitym, "8"); //w3 u8g_DrawStr(&u8g, 72, daxbitym, ";"); //w4 break; case -4: d_tachodial(); break; } } void checkwakeup(void){ if(sleepWakeUpNow){ isSleeping = 0; u8g_SleepOff(&u8g); //Wake up display a_StartTachoTimer(); //start the tachometer timer sleepWakeUpNow = 0; } } void checkinterrupts(void){ if(RTCinterrupt){ RTCseconds++; if(RTCseconds == 60){ RTCminutes++; if(!bootfirstsecond){ //Don't check first second after boot up if(!isSleeping){ a_IsBikeStopped(); //Every minute check if we are fully stopped //IMPORTANT: check this before sleep control } } RTCseconds = 0; if(RTCminutes == 60){ RTChours++; RTCminutes = 0; if(RTChours == 24){ RTChours = 0; } } } if(bootfirstsecond == 1){bootfirstsecond = 0;} if(!isSleeping){ //Generate strings for the clock generate_clockstring(); } RTCinterrupt = 0; } } void checksleepschedule(void){ cli(); if(SleepShedule){ SleepShedule = 0; set_sleep_mode(SLEEP_MODE_IDLE); sei(); sleep_mode(); } sei(); } void checkspeedlimit(void){ if(ThrottleActive && lockedbike == 0){ if(DAXkmh > SPEED_LIMIT){ if(debugRelayStatus){ //The CDI is on h_setRelay(0); //turn off CDI } RelayOffTimeCounter = 0; //Start counting when we are not above limit anymore }else{ if(!debugRelayStatus){ //The CDIis off, check if we can turn it on yet. //uint8_t throttleOffTime = 100; // * 12 in milliseconds. * 10 and we got 10,000th of seconds if(RelayOffTimeCounter > (throttleOffTime * ThrottleOffTimeMultiplier) * 10 ){ h_setRelay(1); //Turn on CDI } } } } } int main(void) { //Lets set a fake keypress as soon as possible so we dont sleep when a second triggers LastKPTMinute = RTCminutes; LastKPTHour = RTChours; //Grab odometer from EEPROM eeprom_busy_wait(); OdometerKilometers = eeprom_read_dword(&OdoKm);eeprom_busy_wait(); OdometerKilometersLastSaved = OdometerKilometers; Odometer2Kilometers = eeprom_read_dword(&Odo2Km);eeprom_busy_wait(); generate_odometer(); generate_odometer2(); //Grab other settings from EEPROM clockShowSeconds = eeprom_read_byte(&EclockShowSeconds);eeprom_busy_wait(); sleepDelay = eeprom_read_byte(&EsleepDelay);eeprom_busy_wait(); throttleOffTime = eeprom_read_byte(&EthrottleOffTime);eeprom_busy_wait(); numberofmagnets = eeprom_read_byte(&Enumberofmagnets);eeprom_busy_wait(); lockonsleep = eeprom_read_byte(&Elockonsleep); //grab page 2 settings from EEPROm //triggerPerMagnet = eeprom_read_byte(&EtriggerPerMagnet);eeprom_busy_wait(); wheelCircum = eeprom_read_word(&EwheelCircum);eeprom_busy_wait(); //magnetWidth = eeprom_read_byte(&EmagnetWidth);eeprom_busy_wait(); h_CalculateSetDistanceBetweenMagnets(); //Grab another setting from EEPROM eeprom_busy_wait(); invertRelay = eeprom_read_byte(&EinvertRelay); //Grab top speed reached from EEPROM eeprom_busy_wait(); topSpeedReached = eeprom_read_byte(&EtopSpeedReached); //#### RTC timer setup TIMSK3 |= (1 << OCIE3A); // Enable CTC interrupt OCR3A = 62500; //16mhz/256 //1 second TCCR3B |= ((1 << WGM32) | (1 << CS32)); //CTC mode, 256 divider //### Tachometer timer1, different timer so we can turn it off when sleeping. AND CTC clears timer on compare... TIMSK1 |= (1 << OCIE1A); OCR1A = 200; //10,000 times per second TCCR1B |= ((1 << WGM12) | (1 << CS11)); //CTC mode, 8 divider. //write all CS1x to LOW to stop clock sei(); //enable global interrupts, sets the I-bit in SREG, cli() disables interrupts //#### 5-click button setup. PORTB(C?) seems broken. DDRA &= ~ ((1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4)); PORTA |= (1<<0) | (1<<1) | (1<<2) | (1<<3) | (1<<4); //Tachometer input DDRB &= ~ (1<<0); //input = 0 PORTB &= ~ (1<<0); //external pullup = 0 //PORTB3 BURNED //Relay output on PORTB PORTB should control output on this pin now DDRB |= (1<<2) | (1<<4); PORTB &= ~ (1<<2) | (1<<4); //turn off the relay coils PCICR |= (1<>>>>> RIP!!!!!!! BUG!! checkspeedlimit(); a_setBikeSpeedKMH(); //Each frame draw speed string and see if we have stopped moving. 5 times a second. u8g_FirstPage(&u8g); do { draw(); } while ( u8g_NextPage(&u8g) ); if(MenuPress != 127){ //Key button press happened? switch(MenuPress) { case RELEASE: if(lockedbike){break;} if(MenuPos <= 0){ //Any button is released. Shit is buggy, "show credits" now deactivates throttle /* if(ThrottleActive && LastKeyPress == PRESS){ if( ((ThrottlePressStartSecond+5)%60 == RTCseconds) || ((ThrottlePressStartSecond+6)%60 == RTCseconds) ){ ThrottleActive = 0; } } */ } break; case UP: if(lockedbike){e_unlockbike(UP); break;} if(MenuPos > 0){e_settingpress(UP); break;}//inside settings if(MenuPos == 0){ MenuPos = BoxesV; }else if(MenuPos < 0){ MenuPos++; } MenuLastVpos = MenuPos; break; case DOWN: if(lockedbike){e_unlockbike(DOWN); break;} if(MenuPos > 0){e_settingpress(DOWN); break;} if(MenuPos == BoxesV){ MenuPos = 0; }else if(MenuPos <= 0){ MenuPos--; } MenuLastVpos = MenuPos; break; case LEFT: if(lockedbike){e_unlockbike(LEFT);break;} if(MenuSettingActive == 127){ if(MenuPos > 0){MenuSelectedOption = 0;} if(MenuPos <= 0){ MenuPos = BoxesH; }else if(MenuPos == 1){ MenuPos = MenuLastVpos; }else{ MenuPos--; } }else{ //pass left on to settings e_settingpress(LEFT); } break; case RIGHT: if(lockedbike){e_unlockbike(RIGHT);break;} if(MenuSettingActive == 127){ if(MenuPos > 0){MenuSelectedOption = 0;} if(MenuPos <= 0){ MenuPos = 1; }else if(MenuPos == BoxesH){ MenuPos = MenuLastVpos; }else{ MenuPos++; } }else{ //pass right on to settings e_settingpress(RIGHT); } break; case PRESS: if(lockedbike){break;} if(MenuPos > 0){ switch(MenuPos){ case PAGE_TIME: if(MenuSettingActive == 127){ switch(MenuSelectedOption){ case 0: //set time MenuSettingActive = PAGE_TIME_setclock; h_timeGetTimeDigitVal(); //needs to draw the current time hours break; case 1: //Show seconds clockShowSeconds = !clockShowSeconds; break; } }else{ //PRESS when editing = go back MenuTimeEditPos = 0; MenuSettingActive = 127; } break; case PAGE_LOCK: lockedbike = 1; lockedKeypressHistory = 0xAAAA; strcpy(lockedbikeStr, "1010101010101010"); MenuPos = MenuLastVpos; h_setRelay(0); //turn off CDI break; case PAGE_GENERAL_TWO: if(MenuSettingActive == 127){ switch(MenuSelectedOption){ /* case 0: //set triggers per magner MenuSettingActive = PAGE_GENERAL_triggerpermagnet; generate_triggerpermagnetpage(); break; */ case 0: //set wheel circum MenuSettingActive = PAGE_GENERAL_wheelcircum; generate_wheelcircumpage(); break; case 1: //"show credits".. Now show top speed, too. //MenuSettingActive = PAGE_GENERAL_magnetwidth; generate_magnetwidthpage(); //deactivate throttle ThrottleActive = 0; //Display top speed reached MenuSettingActive = PAGE_GENERAL_topspeed; generate_topspeedpage(); break; case 2: //debug dots showDebugDots = !showDebugDots; break; case 3: //invert relay output //if (invertStatement) seton = !seton; shorthand cool invertRelay = !invertRelay; h_setRelay(debugRelayStatus); //refresh relay a_burnSettingsInvert(); //burn invertSetting break; } }else{ //PRESS when editing = go back MenuSettingActive = 127; //Save settings to EEPROM a_burnSettings_two(); //Burn wheelcircum } break; case PAGE_GENERAL: if(MenuSettingActive == 127){ switch(MenuSelectedOption){ case 0: //Odometer reset Odometer2Kilometers = 0; generate_odometer2(); break; case 1: //Throttle-off-time MenuSettingActive = PAGE_GENERAL_throttleofftime; generate_throttlepage(); break; case 2: //set magnets amount MenuSettingActive = PAGE_GENERAL_setmagnets; generate_magnetpage(); break; case 3: //set sleep delay MenuSettingActive = PAGE_GENERAL_setsleepdelay; generate_sleepdelaypage(); break; case 4: //set lock on sleep true/false MenuSettingActive = PAGE_GENERAL_setlockonsleep; generate_lockonsleep(); break; } }else{ //PRESS when editing = go back MenuSettingActive = 127; //Save settings to EEPROM a_burnSettings(); } break; } }else if(MenuPos <= 0){ //This is a press in negative MenuPos AKA the main screens //enable throttle ThrottleActive = 1; //Start counting 5 seconds //ThrottlePressStartSecond = RTCseconds; } } MenuPress = 127; //allow another button press }else{ //This runs every frame a key is not pressed or released } } } ISR(TIMER3_COMPA_vect) //RealTimeClock 1 second interrupt { RTCinterrupt = 1; //no more, no less. } uint8_t tachotimerHalted = 0; uint8_t throttletimerHalted = 0; ISR(TIMER1_COMPA_vect) //10,000 times a second interrupt for tachometer { if (RelayOffTimeCounter == 0xFFFF){ //Throttle-time-counter if(!throttletimerHalted){ throttletimerHalted = 1; //Timer will stop here (after 6s) } }else{ if(throttletimerHalted){throttletimerHalted = 0;} RelayOffTimeCounter++; } if (tachoTick == 0xFFFF){ //overflow detected we are not moving, for sure (6 seconds). if(!tachotimerHalted){ DAXkmh = 0; tachotimerHalted = 1; //Timer will stop here } }else{ if(tachotimerHalted){tachotimerHalted = 0;} tachoTick++; } } void StoreLastKeypress(void){ LastKeyPress = MenuPress; LastKPTMinute = RTCminutes; LastKPTHour = RTChours; } //Button press interrupt ISR(PCINT0_vect) { //did we wake up from sleep? if(isSleeping){ sleepWakeUpNow = 1; MenuPress = RELEASE; //Just something here for safety. dont press any button when we first wake up LastKeyPress = RELEASE; LastKPTMinute = RTCminutes; LastKPTHour = RTChours; //allow sleep again without acceleration < decel DAXkmhStopTimeMinutes = RTCminutes; //Save time we stopped DAXkmhStopTimeHours = RTChours; goto ISRend; } //Pins fire only at the time. 0 when pressed. if(!(PINA & UP)){MenuPress = UP; StoreLastKeypress(); }else{ if(!(PINA & DOWN)){MenuPress = DOWN; StoreLastKeypress();}else{ if(!(PINA & LEFT)){MenuPress = LEFT; StoreLastKeypress();}else{ if(!(PINA & RIGHT)){MenuPress = RIGHT; StoreLastKeypress();}else{ if(!(PINA & PRESS)){MenuPress = PRESS; StoreLastKeypress();}else{ //Button released MenuPress = RELEASE; } } } } } ISRend: ; } //this hall sensor needs magnets to switch polarity for a new trigger to happen. //Tachometer interrupt uint32_t mathvar = 0; //Could probably be done with a 16bit int with some effort. uint16_t grabTachoTick; uint16_t odometerTmpCounter = 0; // uint16_t tmpdivision = 0; uint8_t avgFull = 0; uint8_t AvgCount[4]; uint8_t AvgAt = 0; //uint8_t SampleBreakAt = 4; ISR(PCINT1_vect) { if(!(PINB & (1<<0) )){ //only check for pin0 grabTachoTick = tachoTick; if(grabTachoTick > 100){ //If we are moving faster than 122 km/h, it's a false trigger. if(DAXkmh < 15){ mathvar = (36 * C_DistBetweenMagnets) / grabTachoTick; DAXkmh = (uint8_t) mathvar; if(avgFull){ AvgAt = 0; AvgCount[0] = 0; AvgCount[1] = 0; AvgCount[2] = 0; AvgCount[3] = 0; avgFull = 0; } }else{ mathvar = (36 * C_DistBetweenMagnets) / grabTachoTick; AvgCount[AvgAt] = (uint8_t) mathvar; if(avgFull){ //Calculate average 4 times mathvar = (AvgCount[0] + AvgCount[1] + AvgCount[2] + AvgCount[3]) / 4; DAXkmh = (uint8_t) mathvar; } if(AvgAt == 3){ AvgAt = 0; avgFull = 1; }else{ AvgAt++; } } tachoTick = 0; odometerTmpCounter = odometerTmpCounter + C_DistBetweenMagnets; if(odometerTmpCounter > 1000){ //over 1 meters traveled? //tmpdivision = (odometerTmpCounter / 1000); odometerTmpCounter = odometerTmpCounter % 1000; //remainder in mm Odometer2Kilometers++; OdometerKilometers++; //Odometer2Kilometers = Odometer2Kilometers + tmpdivision; //OdometerKilometers = OdometerKilometers + tmpdivision; //FIXED: division not needed } } } }