AvaSmith-CodingSamples / C / BatterySimluation - C / batt_update.c
batt_update.c
Raw
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "batt.h"

// Uses the two global variables (ports) BATT_VOLTAGE_PORT and
// BATT_STATUS_PORT to set the fields of the parameter 'batt'.  If
// BATT_VOLTAGE_PORT is negative, then battery has been wired wrong;
// no fields of 'batt' are changed and 1 is returned to indicate an
// error.  Otherwise, sets fields of batt based on reading the voltage
// value and converting to precent using the provided formula. Returns
// 0 on a successful execution with no errors. This function DOES NOT
// modify any global variables but may access global variables.
//
// CONSTRAINT: Avoids the use of the division operation as much as
// possible. Makes use of shift operations in place of division where
// possible.
//
// CONSTRAINT: Uses only integer operations. No floating point
// operations are used as the target machine does not have a FPU.
// 
// CONSTRAINT: Limit the complexity of code as much as possible. Do
// not use deeply nested conditional structures. Seek to make the code
// as short, and simple as possible. Code longer than 40 lines may be
// penalized for complexity.
int set_batt_from_ports(batt_t *batt){
    if(BATT_VOLTAGE_PORT < 0){ //If the battery isnt wired correctly, return 1 for error
        return 1;
    }

    batt->mlvolts = BATT_VOLTAGE_PORT >> 1;     //conversions, >> x is the same as / 2^x
    batt->percent = (batt->mlvolts - 3000) >> 3;

    if(batt->mlvolts < 3000) batt->percent = 0; //checks to make sure no negatives
    if(batt->percent > 100) batt->percent = 100; //ensures percent does not go over 100%
    
    int mask = 1 << 4;                          //checks the forth bit of batt status porr to determine percent or voltage
    if(BATT_STATUS_PORT & mask){batt->mode = 1;} //volt
    else batt->mode = 2; //percent

    return 0; //sucsess!

}//set_batt_from_ports();

// Alters the bits of integer pointed to by 'display' to reflect the
// data in struct param 'batt'.  Does not assume any specific bit
// pattern stored at 'display' and completely resets all bits in it on
// successfully completing.  Selects either to show Volts (mode=1) or
// Percent (mode=2). If Volts are displayed, only displays 3 digits
// rounding the lowest digit up or down appropriate to the last digit.
// Calculates each digit to display changes bits at 'display' to show
// the volts/percent according to the pattern for each digit. Modifies
// additional bits to show a decimal place for volts and a 'V' or '%'
// indicator appropriate to the mode. In both modes, places bars in
// the level display as indicated by percentage cutoffs in provided
// diagrams. This function DOES NOT modify any global variables but
// may access global variables. Always returns 0.
// 
// CONSTRAINT: Limit the complexity of code as much as possible. Do
// not use deeply nested conditional structures. Seek to make the code
// as short, and simple as possible. Code longer than 65 lines may be
// penalized for complexity.

int set_display_from_batt(batt_t batt, int *display){ //around 30 lines of code w/o whitespace
    //creates bit layout for each numbers 0-9
    int masks[10] = {0b0111111,0b0000110,0b1011011,0b1001111,
                     0b1100110,0b1101101,0b1111101,0b0000111,
                     0b1111111,0b1101111};
    
    *display = 0;                   //sets display to all 0's
    if(batt.mode == 2){ //volts
        *display = *display | 0b110;    //assigns first three bits to reflect decimal and 'v
        short temp = batt.mlvolts;

        //Checks if needs to round and rounds if necesarry
        if(temp % 1000 != 0){   
            int round = temp % 10;  //gets last digit
            temp /=10;              //removes last digit
            if(round >=5) temp +=1; //rounds if necesarry
        }//if
      
        *display = *display | (masks[temp % 10] << 3); //calcs last digit and adds that digits bit mask to bits 3-9
        temp /=10;                                     //removes digit
        *display = *display | (masks[temp % 10] << 10);//calcs last digit and adds that digits bit mask to bits 10-16
        temp /=10;                                     //removes digit
        *display =* display | (masks[temp % 10] << 17);//calcs last digit and adds that digits bit mask to bits 17-23
    } //if
    else{ //percent
        *display = *display | 0b001;    //assigns first three bits to refelct 'p'
        int temp = batt.percent;
        *display = *display | (masks[temp % 10] << 3);                  //calcs last digit and adds that digits bit mask to bits 3-9
        temp /=10;                                                      //removes digit
        if(temp != 0) *display = *display | (masks[temp % 10] << 10);   //calcs last digit and adds that digits bit mask to bits 10-16
        temp /=10;                                                      //removes digit
        if(temp != 0) *display =* display | (masks[temp % 10] << 17);   //calcs last digit and adds that digits bit mask to bits 17-23
    } //else

    //checks what battery percent and sets bit pattern accordingly
         if(batt.percent >= 90) *display = *display | (0b11111 << 24); //(5 bars)
    else if(batt.percent >= 70) *display = *display | (0b01111 << 24); //(4 bars)
    else if(batt.percent >= 50) *display = *display | (0b00111 << 24); //(3 bars)
    else if(batt.percent >= 30) *display = *display | (0b00011 << 24); //(2 bars)
    else if(batt.percent >=  5) *display = *display | (0b00001 << 24); //(1 bar )
    
    return 0; //sucsess!

}//set_display_from_batt()

// Called to update the battery meter display.  Makes use of
// set_batt_from_ports() and set_display_from_batt() to access battery
// voltage sensor then set the display. Checks these functions and if
// they indicate an error, does NOT change the display.  If functions
// succeed, modifies BATT_DISPLAY_PORT to show current battery level.
// 
// CONSTRAINT: Does not allocate any heap memory as malloc() is NOT
// available on the target microcontroller.  Uses stack and global
// memory only.
int batt_update(){
    batt_t batt; //creates a temp batt struct
    
    int check = set_batt_from_ports(&batt); //sets variables in batt struct
    if(check){//checks for failures, returns one on failed setting of batt
        return 1;
    }
    set_display_from_batt(batt,&BATT_DISPLAY_PORT);//calcs display and sets it to BATT_DISPLAY_PORT
    
    return 0; //succsess!

}//bat_update();s