Dependencies:   KS0108 mbed

Revision:
0:b669c97da2c0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jun 18 16:47:00 2012 +0000
@@ -0,0 +1,381 @@
+// Display Test
+#include "KS0108.h"
+#include "calsolimage.h"
+#include "MyPhone_20.h"
+#include "MyPhone_40.h"
+#include "rtos.h"
+
+// Declare each of the things you're going to use
+
+// The display
+KS0108 display(p23,p21,p22,p20,p24,p25,p17,p18,p19,p30,p29,p28,p27,p26);
+// The button on the breadboard
+DigitalIn topButton(p13);
+// For printing things to the computer
+Serial pc(USBTX,USBRX);
+
+// Timers
+Timer timer;
+Timer testTimer;
+
+//Methods
+void readFromCAN();
+void setupScreen();
+void updateBattery(int newVoltage);
+void updateBatteryGraphic(int newPercentage, int percentage);
+void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
+void printCenteredInt(int newInt, int oldInt, int leftLimit, int rightLimit, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
+void printRightJustifiedInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
+
+// Constants
+
+//Maximum voltage for battery = 151.2 V (4.2V per cell, 36 cells total)
+const double MaxVoltage = 151.2;
+//Minimum voltage for battery = 108 V (3V per cell, 36 cells total)
+const double MinVoltage = 108;
+
+// Mutex and screen state
+Mutex screen_mutex;
+CAN can(p9, p10);
+int demo = 0;
+
+
+//Speed: int from 0 to 999, in mph
+int speed = 0, newSpeed = 0;
+//Voltage: int from MinVoltage to MaxVoltage, in volts
+int voltage = MinVoltage, newVoltage = MinVoltage;
+//Current: int from 0 to 9999, in milliAmps
+int amperage = 0, newAmperage = 0;
+
+
+//Union type to make float to char conversion easier (used to read CAN messages)
+typedef union _data
+{
+    float f[2];
+    char s[8];
+} floatchar;
+
+//Union type to make int to char conversion easier (used to read CAN messages)
+typedef union _data2
+{
+    uint16_t i[4];
+    char s[8];
+} intchar;
+
+
+/* Input thread - Modifies state variables based on input */
+void input_runner(void const *argument) {
+    while (true) {
+        // If top button is pressed, don't accept other input
+        if (!topButton) {
+            // Debounce wait
+            Thread::wait(100);
+            if (!topButton) {
+                screen_mutex.lock();
+                demo++;
+                if (demo > 1) {
+                    demo = 0;
+                }
+                screen_mutex.unlock();
+            }
+            // Don't accept other input while button is pressed
+            while(!topButton) {
+                Thread::wait(100);
+            }
+        }
+    }
+}
+
+
+// This is where your programs starts running
+int main()
+{
+  // Initialize variables**
+  int current_demo = demo;
+  topButton.mode(PullUp);
+  // Display CalSol logo
+  display.FullScreenBMP(pic);
+  Thread::wait(200);
+
+  timer.start();
+  
+  // Start the button thread
+  Thread button_thread(input_runner);
+  
+  // Main thread
+  while(1) {
+    // First, check if the state has changed, if so, wipe the screen
+    int changed = 0;
+    screen_mutex.lock();
+    if (current_demo != demo)
+    {
+        changed = 1;
+    }
+    current_demo = demo;
+    screen_mutex.unlock();
+    
+    // Wipe the screen
+    if (changed)
+    {
+        display.ClearScreen();
+        changed = 0;
+    }
+    
+    // Now run the actual program
+    switch(current_demo)
+    {
+        // Demo 0: Just display the CalSol logo
+        case 0:
+            if(timer.read_ms() > 500)
+            {
+                display.FullScreenBMP(pic);
+                timer.reset();
+            }
+            break;
+        
+        // Demo 1: Display a mock speedometer, with battery level
+        case 1:
+            //Initialize variables
+            speed = newSpeed = 60;
+            amperage = newAmperage = 900;
+            voltage = newVoltage = MaxVoltage;
+            
+            setupScreen();
+            testTimer.start();
+            
+            //Display values as they are being changed
+            while (true)
+            {
+                /* This part tests the printing
+                
+                //Randomly selects values between appropriate ranges.
+                speed = (int)(rand()%200);
+                amperage = (int)(rand()%1000);
+                voltage = (int)(rand()%100);
+                
+                //Changes values from 1 to 3 or 4 digits to test proper spacing and erasing with changing num of digits
+                if (testTimer.read_ms()%1000 == 0)
+                {
+                    switch ((testTimer.read_ms()/1000)%4)
+                    {
+                        case 0: //1 digit
+                            newSpeed = (int)(rand()%9)+1;
+                            newAmperage = (int)(rand()%9)+1;
+                            break;
+                        case 3: //2 digits
+                            newSpeed = (int)(rand()%90)+10;
+                            newAmperage = (int)(rand()%90)+10;
+                            break;
+                        case 2: //3 digits
+                            newSpeed = (int)(rand()%900)+100;
+                            newAmperage = (int)(rand()%900)+100;
+                            break;
+                        case 1: //4 digits
+                            newSpeed = (int)(rand()%90)+100;
+                            newAmperage = (int)(rand()%900)+1000;
+                            break;
+                        default: break;
+                    }
+                }*/
+                
+                //Keeps screen from updating too much
+                if (testTimer.read_ms()%1000==0)
+                {
+                    /* More printing testing
+                    
+                    //Randomly increases or decreases values within a small range
+                    newSpeed += (int)((rand()%5)-2);
+                    newAmperage += (int)((rand()%21)-10);
+                    newVoltage += (int)((rand()%3)-1);
+                    
+                    //Keeps voltage between allowed values
+                    if (newVoltage < MinVoltage || newVoltage > MaxVoltage)
+                        newVoltage = MaxVoltage;
+                    */
+                        
+                    readFromCAN();
+                    
+                    updateBattery(newVoltage);
+                    
+                    //Updates speed
+                    display.SelectFont(MyPhone_40, BLACK, ReadData);
+                    printCenteredInt(newSpeed, speed, 12, 16, 15, 23, 1, 3);
+                    speed = newSpeed;
+                    
+                    //Updates amperage
+                    display.SelectFont(MyPhone_20, BLACK, ReadData);
+                    printCenteredInt(newAmperage, amperage, 76, 40+8, 8, 11, 1, 4);
+                    amperage = newAmperage;
+                }
+            }
+            break;
+        default: break;
+        }
+    }
+}
+
+void setupScreen()
+{
+    //Draws grid lines to separate the screen.
+    //Dimensions: (Speed) 70x64, (Battery) 57x42, (Amperage) 57x22 
+    display.HLineShort(71, 42, 57, BLACK);
+    display.VLineShort(71, 0, 64, BLACK);
+    
+    //This covers the stray black pixel...
+    display.SetPixel(71-5, 42, WHITE);
+  
+    //Draws the outline for battery graphic. Dimensions: 40x24, 4x8
+    display.RoundRectangle(82, 4, 40, 24, 4, BLACK);
+    display.EmptyRectangle(78, 12, 78+4, 12+8, BLACK);
+    
+    //Prints MPH
+    display.SelectFont(System5x7, BLACK, ReadData);
+    display.GotoXY(26, 48);
+    display.PrintString("MPH");
+    
+    //Print mAmp
+    display.SelectFont(System5x7, BLACK, ReadData);
+    display.GotoXY(114, 24+24);
+    display.PrintString("mA");
+    
+    //Prints the percent sign
+    display.GotoXY(108, 24+8);
+    display.PrintString("%");
+    
+    //Draws initial shaded box for battery
+    display.FullRectangle(86+(int)(((double)(100-((newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100))/100.0)*32), 4+4, 86+32, 4+24-4, BLACK);
+}
+
+//This exists to fix the problem with the percentage printing that was occuring for unknown reasons.
+//Writes an int to the screen right-justified over another int.
+void printRightJustifiedPercentage(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits)
+{
+    for (int digits = maxDigits; digits > 0; digits--)
+    {
+        if (newInt >= (int)pow(10.0, digits-1))
+        {
+            //Instead of checking if digits need to be erased, all digits will be erased
+            //Erases digits that will not be covered by new text.
+            display.FullRectangle(startX, startY, startX + (charWidth+charSpacing) * (maxDigits - digits), startY + charHeight, WHITE);
+            display.GotoXY(startX + (charWidth+charSpacing) * (maxDigits - digits), startY);
+            //Break out of loop.
+            digits = -1;
+        }
+    }
+    display.PrintNumber(newInt);
+}
+
+//Writes an int to the screen center-justified over another int.
+void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits)
+{
+    for (int digits = maxDigits; digits > 0; digits--)
+    {
+        //If current value has "digits" number of digits
+        if (newInt >= (int)pow(10.0, digits-1))
+        {
+            //If previous value had more digits than current value
+            if (oldInt >= (int)pow(10.0, digits))
+            {
+                //Erases all possible digits that could be on screen.
+                //**First parameter should logically be startX, but it starts erasing 1 pixel too far to the right for some reason. ???
+                display.FullRectangle(startX-1, startY, startX + maxDigits*(charWidth+charSpacing), startY + charHeight, WHITE);
+            }
+            display.GotoXY(startX + 0.5*((maxDigits - digits)*charWidth + (maxDigits - digits - 1)*charSpacing), startY);
+            //Break out of loop.
+            digits = -1;
+        }
+    }
+    display.PrintNumber(newInt);
+}
+
+//Updates the battery graphic and prints corresponding percentage or voltage.
+void updateBattery(int newVoltage)
+{
+    //These are needed for the battery graphic, even if the values won't be displayed.
+    int percentage = (voltage - MinVoltage)/(MaxVoltage - MinVoltage)*100;
+    int newPercentage = (newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100;
+    
+    //This line fixes the printing problem with the percentage that was caused by drawing shaded rectangle. Might have something to do with the method WriteInstruction(int, int) used by both methods.
+    display.SetPixel(88, 32, WHITE);
+    
+    // ** Problem: after a while of letting it run, sometimes a 0 will show up 1 pxl to the right of the hundreds place. But it gets erased when voltage drops enough
+    //Prints percentage
+    display.SelectFont(System5x7, BLACK, ReadData);
+    printRightJustifiedPercentage(newPercentage, percentage, 88, 32, 5, 7, 1, 3);
+    
+    //Prints voltage -- currently NOT IN USE
+    /*display.SelectFont(System5x7, BLACK, ReadData);
+    display.GotoXY(108, 24+8);
+    display.PrintString("V");
+    display.SelectFont(System5x7, BLACK, ReadData);
+    printRightJustifiedInt(newVoltage, voltage, 88, 32, 5, 7, 1, 3);*/
+    
+    updateBatteryGraphic(newPercentage, percentage);
+    
+    percentage = newPercentage;
+    voltage = newVoltage;
+}
+
+//Changes shaded area of graphic to reflect current battery level. Dimensions 32x16
+void updateBatteryGraphic(int newPercentage, int percentage)
+{
+    //Stores x-coordinates of shaded part of battery.
+    int barX = 86+(int)(((double)(100-percentage)/100.0)*32);
+    int newBarX = 86+(int)(((double)(100-newPercentage)/100.0)*32);
+    
+    //Draws increase in percentage.
+    if (newBarX < barX)
+    {
+        display.FullRectangle(newBarX, 4+4, barX, 4+24-4, BLACK);
+    }
+    //Draws decrease.
+    else
+    {
+        display.FullRectangle(86, 4+4, newBarX, 4+24-4, WHITE);
+    }
+}
+
+//***This method has NOT BEEN TESTED.
+
+//Gets information about speed, voltage, current, and battery life through CAN.
+void readFromCAN()
+{
+    const int speedID = 0x403;
+    const int voltageAmperageID = 0x523;
+    
+    //Gets message from CAN.
+    CANMessage msg;
+    can.read(msg);
+    int id = msg.id;
+    
+    switch (id)
+    {
+        case voltageAmperageID: //contains four messages: voltage 1 and 2 in volts, current 1 and 2 in mA. each is an int (2 bytes)
+            
+            //Read & store amperage value.
+            intchar amp_data;
+            for (int i = 0; i < 2; i++){
+                amp_data.s[i] = msg.data[i];
+            }
+            amperage = amp_data.i[0]; //***is this correct?
+            
+            //Read & store voltage/battery life value.
+            floatchar volt_data;
+            for (int i = 0; i < 2; i++){
+                volt_data.s[i] = msg.data[i+4];
+            }
+            voltage = volt_data.f[0];   //***should this be reading voltage 1 or voltage 2? (volt1.f[0 or 1])
+            break;
+            
+        case speedID:
+            //** This packet actually contains motor velocity in rpm as well as vehicle velociy in m/s. How do I get only the second part?
+            floatchar speed_data;
+            for (int i = 0; i < 4; i++) {
+                speed_data.s[i] = msg.data[i];
+            }
+            //Conversion factor: 1 m/s = 2.23693629 mph
+            speed = (speed_data.f[2])*2.23693629; //** should this be a combination of f[2] and f[3]? 
+            break;
+        default: break;
+    }
+}
\ No newline at end of file