Last Updated: 2019-10-09 Wed 15:08

CSCI 2021 Assignment 2: Bit Ops and Debugging

CODE/TEST DISTRIBUTION: a2-code.zip

CHANGELOG:

Wed 09 Oct 2019 03:07:19 PM CDT
A few typos in the text of the assignment were fixed. Notably, the bit pattern for digit '9' was reported wrong and has been fixed.
Fri 04 Oct 2019 03:11:20 PM CDT
Minor update to remove typos mentioning temperature and Celsius/Fahrenheit that were left over from a previous semester. This should have been Voltage/Percent instead.
Wed 02 Oct 2019 02:58:12 PM CDT

Several corrections were made in the Battery Meter Display Figure to get text for numbers to line up with what was actually shown in the figure.

Manual inspection on Problem 1 was clarified to read "no math float ops" as the simulated battery meter CPU does not support floating point operations, only integer operations.

1 Introduction

Bit-level operations are common in C and systems programming. This assignment features a problem in which shifting and bitwise AND/OR-ing are required to complete the requirements.

Debugging is also a critical skill enabled by the debugger. The second problem in the assignment makes use of the GNU Debugger, gdb, to work through a puzzle program requiring specific inputs to pass its "phases".

1.1 Makefile

As in the first assignment, a Makefile is provided as part of this project. The essential targets pertinent to each problem are described in those sections.

1.2 Automated Tests

As in previous assignments, automated tests are provided and associated with problems. Each problem describes how to run tests associated with it.

2 Download Code and Setup

Download the code pack linked at the top of the page. Unzip this which will create a project folder. Create new files in this folder. Ultimately you will re-zip this folder to submit it.

File State Notes
Makefile Provided Build file to compile all programs
batt.h Provided Problem 1 header file
batt_main.c Provided Problem 1 main() function for battery meter simulation
batt_sim.c Provided Problem 1 simulation functions for battery meter
batt_update.c Create Problem 1 functions to write
     
test_batt_update.sh Testing Problem 1 script to test batt_update.c both normal/valgrind
test_batt_update.c Testing Problem 1 functions tests for batt_upate.c
test_batt_main.sh Testing Problem 1 shell tests for batt_main
test_batt_main_data.sh Testing Problem 1 shell test data for batt_main
puzzlebox.c Provided Problem 2 Debugging problem
input.txt Edit Problem 2 Input for puzzlebox, fill this in

3 Problem 1: Battery Meter Simulation

3.1 Overview

You are tasked with writing code which will be run by a microcontroller in a digital battery meter. The hardware has the following relevant features.

  • A voltage sensor whose value can be accessed via a memory mapped port. In C this is presented as a global variable. Another port indicates whether the voltage should be displayed in Volts or Percentage of total battery capacity.
  • A digital display with a port control port; setting certain global variable will change the display to show information to a user of the battery meter.
  • User code that you will need to write to update the display based on the sensor value.
  • A simulator program with Makefile to test your code

Each feature is discussed in subsequent sections.

Voltage Sensor

A voltage sensor is attached to the battery meter and can be accessed via a C global variable. This is declared in the batt.h header file as follows.

extern short BATT_VOLTAGE_PORT;
// Tied to the battery, provides a measure of voltage in units of
// 0.001 volts (milli volts). The sensor can sense a wide range of
// voltages including negatives but the batteries being measured are
// Full when 3.8V (3800 sensor value) or above is read and Empty when
// 3.0V (3000 sensor value) or lower is read.

You do not need to define this variable as it is already there. You do NOT need to set this variable as it is automatically changed by the hardware. Instead, you will need to access its value to determine various the voltage level of the attached battery.

As indicated in the variable documentation, a common (though mildly unreliable) means of detecting how much charge is left in a battery is to read the voltage on the battery. The type of battery being measured in this case has a higher voltage when fully charged and its lower voltage continuously lowers as it discharges. Past certain low voltage, the battery is unsafe to discharge and other hardware will disable the meter. The figure below shows the voltage range and corresponding Capacity Percentage for the battery.

battery-voltage-v-percent.png

Figure 1: Relationship between Voltage and Percent full for batteries being measured by the meter.

Notice the relationship between the Voltage which can be read directly and the Percent full which needs to be calculated from the voltage using the given formula:

Batt% = (BattV - 3000) / 8

Note the conversion is done in millivolts as the the voltage sensor reports in units of 0.001 volts.

Voltage Display Mode

Another global variable exposes whether the user has pressed a button which toggles between displaying Volts or Percent full in the battery.

extern unsigned char BATT_STATUS_PORT;
// Lowest order bit indicates whether display should be in Volts (0)
// or Percent (1). C code should only read this port. Tied to a user
// button which will toggle the bit. Other bits in this char may be
// set to indicate the status of other parts of the meter and should
// be ignored: ONLY THE LOW ORDER BIT MATTERS.

As per the documentation, only the lowest bit (0th bit) should be used while other bits may be nonzero and should be ignored. Bitwise operations are useful for this.

Display Port

The battery meter has a digital display which shows the remaining battery capacity. This display is controlled by a special memory area exposed as another global variable in C.

extern int BATT_DISPLAY_PORT;
// Controls battery meter display. Readable and writable. C code
// should mostly write this port with a sequence of bits which will
// light up specific elements of the LCD panel.

While listed as in int, each bit of the is actually tied to part of the LCD display screen. When bits are set to 1, part of the display is lit up while 0 means it is not lit.

The following diagrams show how various bit patterns will light up parts of the LCD display. Some bits correspond to parts of digits like "9" and "4" while others light up portions for the decimal place, Volt/Percent indicator, and bars of the leftmost visual level indicator. Above the display is the bit string which results in the elements on the display being turned on with "1" and off with a "0".

Notice the following.

  • The BATT_DISPLAY_PORT is a 32-bit integer but only some bits control the display
  • 29 bits are used to control the full battery display (bits 0-28)
  • Bits 0-6 control the rightmost digit
  • Bits 7-13 control the middle digit
  • Bits 14-20 control the left digit
  • Each digit follows the same pattern: lowest bit controls the upper right LCD digit bar with each higher bit going in a clockwise fashion and the middle bar being controlled by the highest order bit
  • Bits 21 controls whether the decimal place is on (for Volts) or off (for percent)
  • Bit 22 controls whether the 'V' Voltage indicator is shown
  • Bit 23 controls whether the '%' Percent indicator is shown
  • Bits 24 and 28 control the 'bars' in the visual level indicator

battery-meter.png

Figure 2: Full examples of how the 29 bits of the BATT_DISPLAY_PORT turns on/off parts of the LCD display. Each digit follows the same pattern of bit to bar correspondence. The lowest order (rightmost) bit controls the upper left bar of each digit and proceed around the outside clockwise with the final bit for each digit controlling the middle bar. This pattern is followed for the 3 digits. Remaining bits control the decimal place, the V and % indicators, and the bars of the visual level indicator at the left of the display. Note that only certain patterns of display come up in standard use. For example, only one of the V or % indicator should be shown normally.

3.2 batt_update.c: Updating the Display with User Code

Periodically the microcontroller will run code to adjust the battery display to show the current battery level. This function is

int batt_update();

and it will be your job to write it.

Rather than write everything that needs to be done within batt_update(), several helper functions will be used to divide this task into several more manageable and testable chunks.

These should all be written in batt_update.c and are as follows.

Converting Voltage Values to a Struct

int set_batt_from_ports(batt_t *batt);
// 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: 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.

This function works with the struct batt_t defined in batt.h which has the following layout.

// Breaks battery stats down into constituent parts
typedef struct{
  short volts;          // voltage read from port, units of 0.001 Volts
  char  percent;        // percent full converted from voltage
  char  mode;           // 0 for volts, 1 for percent
} batt_t;

The function set_batt_from_ports() will read the global variables mentioned above and fill in values for the struct fields of the parameter batt. Keep the following in mind while implementing the function.

  1. Read the BATT_VOLTAGE_PORT value directly into the volt field.
  2. Use the previously mentioned conversion formula to convert Volts to Percentage to fill in the percent field of the struct.

    Batt% = (BattV - 3000) / 8
    
    
  3. Note the constraint: make use only of integer operations. Do not use float or double variables. This is emulates the somewhat common situation where simple microprocessors cannot perform floating point operations as they lack a Floating Point Unit (FPU).

Setting Display from a batt_t

int set_display_from_batt(batt_t batt, int *display);
// Alters the bits of integer pointed to by display to reflect the
// data in struct param 'batt'.  Selects either to show Volts (mode=0)
// or Percent (mode=1). 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 85 lines may be
// penalized for complexity.

Importantly, this function sets the bits in the integer pointed to by display which may or MAY NOT BE the global display variable.

To properly set the display bits, set_display_from_batt() will need to do bit shifting along with bitwise operations to construct the correct bit pattern for the display.

A good trick to use is to create a series of bit patterns that correspond to the various digits. For example, according to the diagrams above, the bit pattern for 9 is 0b1110111. If a 9 should appear on the display somewhere, this bit pattern should be shifted and combined with the existing bits in display so that a 9 will show. Creating similar constant mask patterns for each digit, the decimal place, the positions of the Voltage/Percent indicator, and the bars for the visual level indicator is a good way to make this problem manageable.

A detailed explanation of one approach to the problem follows.

  • Create an array of bit masks for each of the digits 0-9. The 0th element of the array contains a bit mask like 0b0111111 which represents the bits that should be set for a 0 digit, the 1th element of this array has a mask like 0b0000011 which are the bits to be set for a 1. There should be ten entries in this array in indices 0-9.
  • Use modulo to determine the integer value for right, middle, and left digits for the display from volts or percent. Each digit should have a value from 0-9 and be Stored in its own variable.
  • Start with an integer variable of 0 (all 0 bits).
  • Use left digit variable to index into your array of masks to determine the bits that should be set for it and shift them over an appropriate amount combining with the existin display bits.
  • Combining bits here is a logical operation of setting all bits that are one in the mask to 1 in the display variable.
  • Repeat this process for the middle and right digits shifting left by appropriate to where the digits should line up.
  • There are several special cases to consider such as leading 0's in a percent should be blanks so nothing should be drawn.
  • Don't forget to set the additional bits like the decimal place, the V/% indicator, and the level bars for the visual indicator.
  • Importantly make code as simple as possible as the target CPU has a limited amount of RAM and longer codes will occupy more RAM. Avoid nesting conditionals very deeply: if/else if/else structures are fine but nesting a conditional within this will be penalized.

Overall Update Function

int batt_update();
// 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.

This function makes use of the previous two functions and the global variables that correspond to the hardware to alter the display. It should be relatively short by making use of the previous functions.

3.3 Battery Meter Simulator

While we do not have actual hardware with the features mentioned, a simulator for the system is in the provided files batt_main.c / batt_sim.c. You do not need to modify or understand code in either file to complete the assignment though it will certainly expand you C skills to spend some time examining them.

The main() function in batt_main.c accepts two command line arguments which are the value for the voltage sensor and whether to show Voltage or Percent for the battery. It will call your functions for this problem and show results for it. You are encouraged to use this main() to test your code incrementally.

  • Examine whether set_batt_from_ports() is correct based on the first part of output in batt_main.c
  • Once set_batt_from_ports() is complete, examine whether the output of set_display_from_batt() is correct based on the latter part of the output.
  • Once both these functions are correct, examine whether batt_update() is correct based on the final part of the output of the main() function.

Note that there are a variety of functions in the batt_sim.c which are used to simulate how the battery meter will display. This is also where the global variables like BATT_DISPLAY_PORT are defined. However, you do not need to modify or even understand the code; it is only used to show how the display would look when the BATT_DISPLAY_PORT bits are set.

3.4 Sample Runs of batt_main

Below are samples generated by compiling and running the main() function in the batt_main.c file. The code is compiled by using the provided Makefile to create the batt_main program. It compiles the the functions you write in the file batt_update.c and combines them with functions in batt_main.c.

> make batt_main
make: 'batt_main' is up to date.

==========Voltage FOR 3942==========
> ./batt_main 3942 V
BATT_VOLTAGE_PORT set to: 3942
set_batt_from_ports(&batt );
batt is {
  .volts   = 3942
  .percent = 100
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111011110011111101111010011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111011110011111101111010011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  #  #     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|  ####   ####  ####  V  
|#####|     #      #     #     
|#####|     #      #     #     
+-----+  #### o ####     #     


==========Percent FOR 3942==========
> ./batt_main 3942 P
BATT_VOLTAGE_PORT set to: 3942
set_batt_from_ports(&batt );
batt is {
  .volts   = 3942
  .percent = 100
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111100000001101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111100000001101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+     #   ####  ####     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #  %  
|#####|     #   #  #  #  #     
+-----+     #   ####  ####     


==========Voltage FOR 3800==========
> ./batt_main 3800 V
BATT_VOLTAGE_PORT set to: 3800
set_batt_from_ports(&batt );
batt is {
  .volts   = 3800
  .percent = 100
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111011110011111111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111011110011111111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|  ####   ####  #  #  V  
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
+-----+  #### o ####  ####     


==========Percent FOR 3800==========
> ./batt_main 3800 P
BATT_VOLTAGE_PORT set to: 3800
set_batt_from_ports(&batt );
batt is {
  .volts   = 3800
  .percent = 100
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111100000001101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111100000001101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+     #   ####  ####     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #  %  
|#####|     #   #  #  #  #     
+-----+     #   ####  ####     


==========Voltage FOR 3765==========
> ./batt_main 3765 V
BATT_VOLTAGE_PORT set to: 3765
set_batt_from_ports(&batt );
batt is {
  .volts   = 3765
  .percent = 95
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111011110011101000110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111011110011101000110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|#####|     #      #     #     
|#####|     #      #     #     
|#####|  ####      #     #  V  
|#####|     #      #     #     
|#####|     #      #     #     
+-----+  #### o    #     #     


==========Percent FOR 3765==========
> ./batt_main 3765 P
BATT_VOLTAGE_PORT set to: 3765
set_batt_from_ports(&batt );
batt is {
  .volts   = 3765
  .percent = 95
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011111100000000011101111110110
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011111100000000011101111110110
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+         ####  ####     
|#####|         #  #  #        
|#####|         #  #  #        
|#####|         ####  ####     
|#####|            #     #  %  
|#####|            #     #     
+-----+         ####  ####     


==========Voltage FOR 3601==========
> ./batt_main 3601 V
BATT_VOLTAGE_PORT set to: 3601
set_batt_from_ports(&batt );
batt is {
  .volts   = 3601
  .percent = 75
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011110011110011111111100111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011110011110011111111100111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #   #     #  #     
|#####|     #   #     #  #     
|#####|  ####   ####  #  #  V  
|#####|     #   #  #  #  #     
|#####|     #   #  #  #  #     
+-----+  #### o ####  ####     


==========Percent FOR 3601==========
> ./batt_main 3601 P
BATT_VOLTAGE_PORT set to: 3601
set_batt_from_ports(&batt );
batt is {
  .volts   = 3601
  .percent = 75
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011110100000000001000111110110
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011110100000000001000111110110
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+         ####  ####     
|     |            #  #        
|#####|            #  #        
|#####|            #  ####     
|#####|            #     #  %  
|#####|            #     #     
+-----+            #  ####     


==========Voltage FOR 3513==========
> ./batt_main 3513 V
BATT_VOLTAGE_PORT set to: 3513
set_batt_from_ports(&batt );
batt is {
  .volts   = 3513
  .percent = 64
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011100011110011111101100000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011100011110011111101100000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####     #     
|     |     #   #        #     
|     |     #   #        #     
|#####|  ####   ####     #  V  
|#####|     #      #     #     
|#####|     #      #     #     
+-----+  #### o ####     #     


==========Percent FOR 3513==========
> ./batt_main 3513 P
BATT_VOLTAGE_PORT set to: 3513
set_batt_from_ports(&batt );
batt is {
  .volts   = 3513
  .percent = 64
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011100100000000011111101010011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011100100000000011111101010011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+         ####  #  #     
|     |         #     #  #     
|     |         #     #  #     
|#####|         ####  ####     
|#####|         #  #     #  %  
|#####|         #  #     #     
+-----+         ####     #     


==========Voltage FOR 3333==========
> ./batt_main 3333 V
BATT_VOLTAGE_PORT set to: 3333
set_batt_from_ports(&batt );
batt is {
  .volts   = 3333
  .percent = 41
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011000011110011111001111100111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011000011110011111001111100111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #      #     #     
|     |     #      #     #     
|     |  ####   ####  ####  V  
|#####|     #      #     #     
|#####|     #      #     #     
+-----+  #### o ####  ####     


==========Percent FOR 3333==========
> ./batt_main 3333 P
BATT_VOLTAGE_PORT set to: 3333
set_batt_from_ports(&batt );
batt is {
  .volts   = 3333
  .percent = 41
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011000100000000010100110000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011000100000000010100110000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+         #  #     #     
|     |         #  #     #     
|     |         #  #     #     
|     |         ####     #     
|#####|            #     #  %  
|#####|            #     #     
+-----+            #     #     


==========Voltage FOR 3298==========
> ./batt_main 3298 V
BATT_VOLTAGE_PORT set to: 3298
set_batt_from_ports(&batt );
batt is {
  .volts   = 3298
  .percent = 37
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011000011110011111001110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011000011110011111001110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #      #  #  #     
|     |     #      #  #  #     
|     |  ####   ####  #  #  V  
|#####|     #      #  #  #     
|#####|     #      #  #  #     
+-----+  #### o ####  ####     


==========Percent FOR 3298==========
> ./batt_main 3298 P
BATT_VOLTAGE_PORT set to: 3298
set_batt_from_ports(&batt );
batt is {
  .volts   = 3298
  .percent = 37
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00011000100000000011001110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00011000100000000011001110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+         ####  ####     
|     |            #     #     
|     |            #     #     
|     |         ####     #     
|#####|            #     #  %  
|#####|            #     #     
+-----+         ####     #     


==========Voltage FOR 3107==========
> ./batt_main 3107 V
BATT_VOLTAGE_PORT set to: 3107
set_batt_from_ports(&batt );
batt is {
  .volts   = 3107
  .percent = 13
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00010000011110011100000110000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00010000011110011100000110000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####      #     #     
|     |     #      #     #     
|     |     #      #     #     
|     |  ####      #     #  V  
|     |     #      #     #     
|#####|     #      #     #     
+-----+  #### o    #     #     


==========Percent FOR 3107==========
> ./batt_main 3107 P
BATT_VOLTAGE_PORT set to: 3107
set_batt_from_ports(&batt );
batt is {
  .volts   = 3107
  .percent = 13
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00010000100000000000000111100111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00010000100000000000000111100111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+            #  ####     
|     |            #     #     
|     |            #     #     
|     |            #  ####     
|     |            #     #  %  
|#####|            #     #     
+-----+            #  ####     


==========Voltage FOR 3074==========
> ./batt_main 3074 V
BATT_VOLTAGE_PORT set to: 3074
set_batt_from_ports(&batt );
batt is {
  .volts   = 3074
  .percent = 9
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00010000011110011101111110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00010000011110011101111110100011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #   #  #     #     
|     |     #   #  #     #     
|     |  ####   #  #     #  V  
|     |     #   #  #     #     
|#####|     #   #  #     #     
+-----+  #### o ####     #     


==========Percent FOR 3074==========
> ./batt_main 3074 P
BATT_VOLTAGE_PORT set to: 3074
set_batt_from_ports(&batt );
batt is {
  .volts   = 3074
  .percent = 9
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00010000100000000000000001110111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00010000100000000000000001110111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+               ####     
|     |               #  #     
|     |               #  #     
|     |               ####     
|     |                  #  %  
|#####|                  #     
+-----+               ####     


==========Voltage FOR 3015==========
> ./batt_main 3015 V
BATT_VOLTAGE_PORT set to: 3015
set_batt_from_ports(&batt );
batt is {
  .volts   = 3015
  .percent = 1
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000011110011101111111101101
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000011110011101111111101101
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #   #  #     #     
|     |     #   #  #     #     
|     |  ####   #  #  ####  V  
|     |     #   #  #  #        
|     |     #   #  #  #        
+-----+  #### o ####  ####     


==========Percent FOR 3015==========
> ./batt_main 3015 P
BATT_VOLTAGE_PORT set to: 3015
set_batt_from_ports(&batt );
batt is {
  .volts   = 3015
  .percent = 1
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000000011
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+                  #     
|     |                  #     
|     |                  #     
|     |                  #     
|     |                  #  %  
|     |                  #     
+-----+                  #     


==========Voltage FOR 3000==========
> ./batt_main 3000 V
BATT_VOLTAGE_PORT set to: 3000
set_batt_from_ports(&batt );
batt is {
  .volts   = 3000
  .percent = 0
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000011110011101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000011110011101111110111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #   #  #  #  #     
|     |     #   #  #  #  #     
|     |  ####   #  #  #  #  V  
|     |     #   #  #  #  #     
|     |     #   #  #  #  #     
+-----+  #### o ####  ####     


==========Percent FOR 3000==========
> ./batt_main 3000 P
BATT_VOLTAGE_PORT set to: 3000
set_batt_from_ports(&batt );
batt is {
  .volts   = 3000
  .percent = 0
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+               ####     
|     |               #  #     
|     |               #  #     
|     |               #  #     
|     |               #  #  %  
|     |               #  #     
+-----+               ####     


==========Voltage FOR 2982==========
> ./batt_main 2982 V
BATT_VOLTAGE_PORT set to: 2982
set_batt_from_ports(&batt );
batt is {
  .volts   = 2982
  .percent = 0
  .mode    = 0
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000011110110111101111111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000011110110111101111111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+  ####   ####  ####     
|     |     #   #  #  #  #     
|     |     #   #  #  #  #     
|     |  ####   ####  ####  V  
|     |  #         #  #  #     
|     |  #         #  #  #     
+-----+  #### o ####  ####     


==========Percent FOR 2982==========
> ./batt_main 2982 P
BATT_VOLTAGE_PORT set to: 2982
set_batt_from_ports(&batt );
batt is {
  .volts   = 2982
  .percent = 0
  .mode    = 1
}

Checking results for display bits
set_display_from_batt(batt, &display);

display is:
        3         2         1         0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Running batt_update()

BATT_DISPLAY_PORT is:
index:  3         2         1    0    0
index: 10987654321098765432109876543210
bits:  00000000100000000000000000111111
guide:  |    |    |    |    |    |    |
index:  30        20        10        0

Battery Meter Display:
+-^^^-+               ####     
|     |               #  #     
|     |               #  #     
|     |               #  #     
|     |               #  #  %  
|     |               #  #     
+-----+               ####     


3.5 Problem 1 Grading Criteria   grading

Both sets automated tests can be run with make test-p1

Weight Criteria
  AUTOMATED TESTS
15 test_batt_update.sh tests of functions in batt_update.c
  Compile and run using make test-p1a
  30 tests, 0.5 points per test
  Deductions for memory problems identified by Valgrind
   
5 test_batt_main.sh tests of batt_main.c
  Compile and run using make test-p1b
  5 Tests, 1 point per test passed
  Deductions for memory problems identified by Valgrind
  MANUAL INSPECTION of batt_update.c
10 set_batt_from_ports()
  Clear effort to do error checking of out of bounds values.
  Clear flow to how each field of batt is calculated.
  Correctly setting fields of batt via pointer dereference or arrow operator.
  Adherence to constraints: no floats, no float math ops, no deeply nested conditionals
  Short, simple code that is no more than 50 lines long.
   
15 set_display_from_batt()
  Clear code that calculates digits to be displayed
  Use of bit masks corresponding to digits to be displayed
  Use of bitwise operators to shift bits appropriately
  Use of bitwise operators to combine shifted digit bits
  Clear code to turn on decimal place, V/% indicator, and level indicators
  Clear dereference/set of the integer pointed to by the display parameter
  Adherence to constraints: no floats, no math float ops, no deeply nested conditionals
  Short, simple code that is no more than 85 lines long.
   
5 batt_update()
  Use of the global variables like BATT_DISPLAY_PORT
  Does not re-define these variables
  Use of previous two functions
  Error checking on sensor values
  No use of malloc()
  Short, simple code.

4 Problem 2: Debugging the Puzzlebox

4.1 Overview

The file puzzlebox.c contains source code that reads inputs from a file named on the command line. If the inputs are correct, points are awarded. If inputs are incorrect, error messages are printed.

The puzzlebox is arranged into a series of phases each of which has some points associated with it.

  • Not all phases must be completed to get full credit but the phases must done in order.
  • Each phase reads inputs from the file provided on the command line and performs calculations on them to see if they are "correct" according to various criteria
  • The very first input is your internet ID like kauf0095 (first part of your UMN email address). This input is used to add randomness to the puzzle so that your answers will be different from most other students. You must you use your own internet ID.

The purpose of this problem is get familiar with using a debugger. This is a powerful tool that pauses programs, allows internal values to be printed and code to be stepped through line by line. It is nearly essential to use as the code in puzzlebox is intentionally convoluted in places. Being able to pause execution and print values at various points make it much easier to solve the puzzles.

4.2 input.txt Input File

Name your input file input.txt and put your internet ID in it along with some numbers like 1 2 3. Then compile and run the puzzlebox program on it.

> make puzzlebox                             # compile puzzlebox
gcc -Wall -g -c puzzlebox.c
gcc -Wall -g -o puzzlebox puzzlebox.o

> cat input.txt                              # show contents of input.txt
kauf0095 1 2 3

> ./puzzlebox input.txt                      # run puzzlebox with input.txt
UserID 'kauf0095' accepted: hash value = 1397510491
PHASE 1: A puzzle you say? Challenge accepted!

Ah ah ah, you didn't say the magic word...
Failure: Double debugger burger, order up!

  * Score: 0 / 50 pts *

This is automated with the Makefile target make test-p2:

> make test-p2                       # compile/run puzzlebox with input.txt
gcc -Wall -g -c puzzlebox.c
gcc -Wall -g -o puzzlebox puzzlebox.o
./puzzlebox input.txt
UserID 'kauf0095' accepted: hash value = 1397510491
PHASE 1: A puzzle you say? Challenge accepted!

Ah ah ah, you didn't say the magic word...
Failure: Double debugger burger, order up!

  * Score: 0 / 50 pts *

These initial forays are not positive (0 / 50 points) but the real meat of the problem is in examining the source code and determining inputs for input.txt.

4.3 gdb The GNU Debugger

You will definitely need to use a debugger to solve the puzzlebox and gdb is the quintessential debugger associated with our compiler gcc. It is installed by default on all lab machines and is an easy install on must Linux machines.

For a quick overview of GDB, here are some resources

4.4 Typical Cycle

A typical cycle of working on puzzlebox will be the following.

  • Start the debugger with puzzlebox

    gdb -tui ./puzzlebox
    
    
  • Set the arguments array to input.txt

    set args input.txt
    
    
  • Set a breakpoint at a phase like phase3

    break phase3
    
    
  • Run the program

    run
    
    
  • Do some stepping / nexting

    step
    next
    
    
  • Print some variables

    print a
    print/x b
    
    
  • Make some changes to input.txt in a different window
  • Re-run the program to see if things have changed favorably

    kill
    run
    
    

4.5 Kinds of Puzzles

The puzzles presented in the different phases make use of a variety of C program techniques which we have or will discuss including.

  • Bit-wise operations and their use in place of arithmetic
  • String and character array manipulations
  • Interpreting bits as one of several kinds of things (integer, float, character) through pointers and unions
  • More extensive C control structures like goto and labels

4.6 Tests for puzzlebox.c   grading

puzzlebox.c itself reports how many points one can earn at the end of its execution.

Currently there are 60 points available but 50 points is considered full credit.

If any additional points are earned, they will be counted towards the overall assignment total for the course to make up for lost credit on other assignments. Your total score on All assignments cannot exceed 100% so any points beyond will simply be dropped.

Run the following command to 'test' puzzlebox:

make test-p2

5 Assignment Submission

5.1 Submit to Gradescope

  1. In a terminal, change to your assignment code directory and type make zip which will create a zip file of your code. A session should look like this:

       > cd Desktop/2021/a2-code      # location of assignment code
    
       > ls 
       Makefile    batt_update.c  puzzlebox.c  test_batt_main.sh 
       ...
    
       > make zip                     # create a zip file using Makefile target
       rm -f a2-code.zip
       cd .. && zip "a2-code/a2-code.zip" -r "a2-code"
         adding: a2-code/ (stored 0%)
         adding: a2-code/test_batt_main.sh (deflated 69%)
         adding: a2-code/Makefile (deflated 59%)
         adding: a2-code/test-data/ (stored 0%)
         ...
       Zip created in a2-code.zip
    
       > ls a2-code.zip
       a2-code.zip
    
  2. Log into Gradescope and locate and click 'Assignment 2' which will open up submission
  3. Click on the 'Drag and Drop' text which will open a file selection dialog; locate and choose your a2-code.zip file
  4. This will show the contents of the Zip file and should include your C source files along with testing files and directories.
  5. Click 'Upload' which will show progress uploading files. It may take a few seconds before this dialog closes to indicate that the upload is successful. Note: there is a limit of 256 files per upload; normal submissions are not likely to have problems with this but you may want to make sure that nothing has gone wrong such as infinite loops creating many files or incredibly large files.
  6. Once files have successfully uploaded, the Autograder will begin running the command line tests and recording results. These are the same tests that are run via make test.
  7. When the tests have completed, results will be displayed summarizing scores along with output for each batch of tests.
  8. Refer to the Submission instructions for A1 for details and pictures but note that the A2 Makefile is already complete so no new version needs to be downloaded.

5.2 Late Policies

You may wish to review the policy on late project submission which will cost you late tokens to submit late or credit if you run out of tokens. No projects will be accepted more than 48 hours after the deadline.

https://www-users.cs.umn.edu/~kauffman/2021/syllabus.html#org02d3f97


Author: Chris Kauffman (kauffman@umn.edu)
Date: 2019-10-09 Wed 15:08