CS107e libpi header files

#ifndef ASSERT_H
#define ASSERT_H

#include "pi.h"
#include "uart.h"

#define STRINGIFY_IMPL(x) #x
#define AS_STRING(x) STRINGIFY_IMPL(x)

#define assert(EXPR) \
   do { \
        if (!(EXPR)) { \
            uart_putstring("File " __FILE__ ", line " AS_STRING(__LINE__) ", function "); \
            uart_putstring(__func__); \
            uart_putstring("() : Assertion '" #EXPR "' failed.\n\04"); \
            pi_abort(); \
        } \
   } while (0);

#endif

#ifndef BACKTRACE_H
#define BACKTRACE_H

#include <stdint.h>

/*
 * Functions for harvesting a debugging backtrace from the stack.
 *
 * Students implement this module in assignment 4.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Mon Feb  5 20:02:27 PST 2018
 */

/* Type: frame_t
 * -------------
 * This struct stores the information for a function who has a frame on
 * the current stack.
 *
 * The `name` field is the name of the function as found by `name_of`.
 *
 * The `resume_addr` field is taken from saved lr in the callee. The saved lr
 * (sometimes referred to as "return address") is the address of the
 * instruction in the caller's sequence of instructions where control will
 * resume after the callee returns.  The `uintptr_t` type is an unsigned integer
 * of the appropriate size to store an address. This type is used to hold
 * an address that you intend to treat numerically.
 *
 * The `resume_offset` is the number of bytes from the start of the function to
 * the `resume_addr`. This offset represents how far control has advanced into
 * the caller function before it invoked the callee.
 */
typedef struct {
    const char *name;
    uintptr_t resume_addr;
    int resume_offset;
} frame_t;


/*
 * `backtrace`
 *
 * Gathers a backtrace for the calling program and writes the
 * call stack information into the array pointed to by `f`.
 *
 * A backtrace is the sequence of currently active function calls. Each element
 * in the array `f` is of type `frame_t` (struct described above). Each struct
 * represents a caller who has a frame on the stack.
 *
 * The `max_frames` argument specifies the maximum number of frames that can be
 * stored in the array f.  If the backtrace extends more than `max_frames`,
 * only the `max_frames` most recent calls are stored into the array.
 *
 * The return value of the function is the count of frames written to `f`.
 *
 * @param f            array in which to write stack frames
 * @param max_frames   maximum number of frames that can be stored in array
 * @return             count of frames written to array
 */
int backtrace(frame_t f[], int max_frames);

/*
 * `print_frames`
 *
 * Given an array of frames that has previously been filled in by a call to
 * backtrace(), `print_frames` prints the backtrace information, one line per
 * frame, using this format:
 *
 *     #0 0x85f8 at malloc+132
 *     #1 0x8868 at strndup+28
 *     #2 0x8784 at main+24
 *
 * @param f     array of stack frames
 * @param n     number of frames in array
 */
void print_frames(frame_t f[], int n);

/*
 * `print_backtrace`
 *
 * Convenience function that calls `backtrace` and `print_frames` to display
 * stack frames of currently executing program.
 */
void print_backtrace(void);

/*
 * `name_of`
 *
 * The argument to `name_of` is the numeric address in memory of the first
 * instruction of a function and `name_of` returns the name of that
 * function.
 *
 * When compiling with the `-mpoke-function-name` flag, each function's
 * name is written into the text section alongside its instructions.
 * `name_of` finds a function's name by looking in the appropriate
 * location relative to the function's start address. The `uintptr_t` type
 * is an unsigned integer of the appropriate size to store an address.
 * This type is used to hold an address that you intend to treat numerically.
 *
 * If no name is available for the given address, `name_of` returns
 * the constant string "???"
 *
 * @param fn_start_addr     numeric address of instruction in memory
 * @return                  pointer to string of function's name or
 *                          constant string "???" if name not available
 */
const char *name_of(uintptr_t fn_start_addr);


#endif

#ifndef CONSOLE_H
#define CONSOLE_H

/*
 * Interface to a text console displayed on the screen.
 *
 * Students implement this module in assignment 6.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 3/24/16
 */

#include "gl.h"

/*
 * `console_init`: required initialization for console
 *
 * Initialize the console. The console text begins empty and
 * the cursor is in the home position (upper left corner).
 *
 * @param nrows       the requested number of rows in characters
 * @param ncols       the requested number of columns in characters
 * @param foreground  foreground color used for text
 * @param background  background color
 */
void console_init(unsigned int nrows, unsigned int ncols, color_t foreground, color_t background);

/*
 * `console_clear`
 *
 * Clear all console text and move the cursor to home position.
 */
void console_clear(void);

/*
 * `console_printf`
 *
 * Print the formatted string to the console starting at current cursor
 * position. The arguments to this function are the same as `printf`.
 * When processing characters, interpret the following special characters:
 *
 * '\n' :  newline (move cursor down to the beginning of next line)
 * '\b' :  backspace (move cursor backwards one position)
 * '\f' :  form feed (clear all contents and move cursor to home position)
 *
 * @param format    format for output string. May contain ordinary characters
 *                  and format conversions
 * @param ...       variable arguments to be converted
 * @return          count of characters written to the console
 */
int console_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));


#endif

#ifndef FB_H
#define FB_H

/*
 * Low-level frameuffer routines for controlling a bare metal
 * Raspberry Pi's graphics. Presents a useful abstraction of hardware
 * that a graphics library can then use to provide useful drawing
 * primitives.
 *
 * Students implement this module for assignment 6.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: Mar 23 2016
 */

typedef enum { FB_SINGLEBUFFER = 0, FB_DOUBLEBUFFER = 1 } fb_mode_t;

/*
 * `fb_init` : Required initialized for framebuffer
 *
 * Initialize the framebuffer.
 *
 * @param width  the requested width in pixels of the framebuffer
 * @param height the requested height in pixels of the framebuffer
 * @param depth  the requested depth in bytes of each pixel
 * @param mode   whether the framebuffer should be
 *                      single buffered (FB_SINGLEBUFFER)
 *                      or double buffered (FB_DOUBLEBUFFER)
 */
void fb_init(unsigned int width, unsigned int height, unsigned int depth_in_bytes, fb_mode_t mode);

/*
 * `fb_get_width`
 *
 * Get the current width in pixels of the framebuffer.
 *
 * @return    the width in pixels
 */
unsigned int fb_get_width(void);

/*
 * `fb_get_height`
 *
 * Get the current height in pixels of the framebuffer.
 *
 * @return    the height in pixels
 */
unsigned int fb_get_height(void);

/*
 * `fb_get_depth`
 *
 * Get the current depth in bytes of a single pixel.
 *
 * @return    the depth in bytes
 */
unsigned int fb_get_depth(void);

/*
 * `fb_get_pitch`
 *
 * Get the current pitch in bytes of a single row of pixels in the framebuffer.
 * The pitch is nominally the width (number of pixels per row) multiplied by
 * the depth in bytes per pixel. However, the pitch may be greater than that if the
 * GPU elects to add padding to the end of the row.
 *
 * @return    the pitch in bytes
 */
unsigned int fb_get_pitch(void);

/*
 * `fb_get_draw_buffer`
 *
 * Get the start address of the framebuffer memory into which the
 * client can draw pixels.  The address returned is the start of an
 * array of size pitch*height bytes.
 *
 * If in single buffering mode, there is only one buffer in use, so the
 * returned address does not change. That buffer is on-screen at all
 * times. The client draws to that one buffer, and all updates are
 * immediately displayed.
 *
 * In double buffering mode, there are two buffers: the one
 * currently on-screen and a second buffer that is off-screen. The
 * address returned by `fb_get_draw_buffer` corresponds to the buffer
 * that is currently off-screen. The off-screen buffer is sometimes
 * called the draw buffer. The client will do all drawing to the off-screen
 * buffer and when ready, calls `fb_swap_buffer` to exchange the
 * on-screen and off-screen buffers. The swap brings the updated
 * drawing on-screen in one smooth update.
 *
 * Note the address is returned as `void*`. Client should store into
 * a properly typed pointer so as to access the pixel data according
 * to their desired scheme (1-d, 2-d, etc.)
 *
 * @return    the address of the current draw (off-screen) buffer
 */
void* fb_get_draw_buffer(void);

/*
 * `fb_swap_buffer`
 *
 * Swap the on-screen and off-screen buffers. The draw buffer (off-screen)
 * is moved on-screen (contents now displayed) and on-screen buffer
 * is moved off-screen (becomes the draw buffer, contents off-screen).
 *
 * If not in double buffering mode, there is only one buffer and this
 * function has no effect.
 */
void fb_swap_buffer(void);

#endif

#ifndef FONT_H
#define FONT_H

#include <stdbool.h>
#include <stddef.h>

/*
 * This module provides a font. Each ASCII character has an
 * associated glyph. A glyph is a bitmap image for drawing
 * the character.
 *
 * The font is fixed width; every glyph has the same width and
 * same height. A glyph is an image with font_get_glyph_height() rows
 * and font_get_glyph_width() columns.
 * Each pixel of the glyph image is represented as one byte.
 * The byte for an "on" pixel is 0xFF, and the byte for
 * "off" pixel is 0x00.
 *
 * Students do not implement this module: the source code for
 * its implementation is provided as part of assignment 6.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: Mar 25 2016
 */

/*
 * `font_get_glpyh_height`
 *
 * Get the height in pixels of each glyph in this font.
 *
 * @return    the height in pixels
 */
size_t font_get_glyph_height(void);

/*
 * `font_get_glpyh_width`
 *
 * Get the width in pixels of each glyph in this font.
 *
 * @return    the width in pixels
 */
size_t font_get_glyph_width(void);

/*
 * `font_get_glpyh_size`
 *
 * Get the total number of bytes needed to store the glyph image
 * for one character. This is equal to the product of
 * (glyph height * glyph width).
 *
 * @return    the size in bytes of a glyph image
 */
size_t font_get_glyph_size(void);

/*
 * `font_get_glpyh`
 *
 * Fill in the glyph image for character `ch` into `buf`.
 * `buf` is an array of bytes of length font_get_glyph_size().
 * Each 'on' pixel has value 0xff, 'off' pixel has value 0x0.
 *
 * @param ch    the requested character
 * @param buf   the buffer in which to place the glyph image
 * @param buflen the length of `buf`.
 *              `buflen` should be equal to value returned by font_get_glyph_size()
 *
 * @return      returns true when successfully filled `buf`, false otherwise.
 *              Failure is when `ch` is not available in this font or `buflen`
 *              does not equal the value returned by font_get_glyph_size()
 */
bool font_get_glyph(char ch, unsigned char buf[], size_t buflen);

#endif

#ifndef GL_H
#define GL_H

/*
 * Functions for a simple bare metal Raspberry Pi graphics library
 * that draws pixels, text, lines, triangles, and rectangles. Builds
 * on the lower-level framebuffer library fb.[ch] for framebuffer
 * access and configuration; trying to use both fb and gl
 * simultaneously is discouraged.
 *
 * Students implement this module in assignment 6 (text and rectangles
 * are required, lines and triangles are an extension).
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: Mar 23 2016
 */

#include "fb.h"

typedef enum { GL_SINGLEBUFFER = FB_SINGLEBUFFER, GL_DOUBLEBUFFER = FB_DOUBLEBUFFER } gl_mode_t;

/*
 * `gl_init` : Required initialized for graphics library
 *
 * Initialize the graphic library. This function will call `fb_init` in turn
 * to initialize the framebuffer. The framebuffer will be initialzed to
 * 4-byte depth (32 bits per pixel).
 *
 * @param width  the requested width in pixels of the framebuffer
 * @param height the requested height in pixels of the framebuffer
 * @param mode   whether the framebuffer should be
 *                  single buffered (GL_SINGLEBUFFER)
 *                  or double buffered (GL_DOUBLEBUFFER)
 */
void gl_init(unsigned int width, unsigned int height, gl_mode_t mode);

/*
 * `gl_get_width`
 *
 * Get the current width in pixels of the framebuffer.
 *
 * @return    the width in pixels
 */
unsigned int gl_get_width(void);

/*
 * `gl_get_height`
 *
 * Get the current height in pixels of the framebuffer.
 *
 * @return    the height in pixels
 */
unsigned int gl_get_height(void);

/*
 * `color_t`
 *
 * Define a type for color. We use BGRA colors, where each color
 * component R, B, G, or A is a single unsigned byte. The least
 * signficant byte is the B component, and A is most significant.
 */
typedef unsigned int color_t;

/*
 * Define some common colors ...
 *
 * Note that colors are BGRA, where B is the first byte in memory
 * and the least significant byte in the unsigned word.
 */
#define GL_BLACK    0xFF000000
#define GL_WHITE    0xFFFFFFFF
#define GL_RED      0xFFFF0000
#define GL_GREEN    0xFF00FF00
#define GL_BLUE     0xFF0000FF
#define GL_CYAN     0xFF00FFFF
#define GL_MAGENTA  0xFFFF00FF
#define GL_YELLOW   0xFFFFFF00
#define GL_AMBER    0xFFFFBF00
#define GL_ORANGE   0xFFFF3F00
#define GL_PURPLE   0xFF7F00FF
#define GL_INDIGO   0xFF000040
#define GL_CAYENNE  0xFF400000
#define GL_MOSS     0xFF004000
#define GL_SILVER   0xFFBBBBBB

/*
 * `gl_color`
*
 * Returns a color composed of the specified red, green, and
 * blue components. The alpha component of the color will be
 * set to 0xff (fully opaque).
 *
 * @param r  the red component of the color
 * @param g  the green component of the color
 * @param b  the blue component of the color
 *
 * @return   the color as a single value of type color_t
 */
color_t gl_color(unsigned char r, unsigned char g, unsigned char b);

/*
 * `gl_clear`
 *
 * Clear all the pixels in the framebuffer to the given color.
 *
 * @param c  the color drawn into the framebuffer
 */
void gl_clear(color_t c);

/*
 * `gl_swap_buffer`
 *
 * If in double-buffered mode, all gl drawing takes place in the
 * off-screen buffer and updated drawing is not brought on-screen until
 * a call is made to `gl_swap_buffer` to exchange the on-screen
 * and off-screen buffers.
 *
 * If not in double-buffer mode, all drawing takes place on-screen and
 * the `gl_swap_buffer` function has no effect.
 */
void gl_swap_buffer(void);

/*
 * `gl_draw_pixel`
 *
 * Draw a single pixel at location x,y in color c.
 * If the location is outside the bounds of framebuffer, it is not drawn.
 *
 * @param x  the x location of the pixel
 * @param y  the y location of the pixel
 * @param c  the color of the pixel
 */
void gl_draw_pixel(unsigned int x, unsigned int y, color_t c);

/*
 * `gl_read_pixel`
 *
 * Return the color of the pixel at location x,y. Returns 0 if the
 * location is outside the bounds of the framebuffer.
 *
 * @param x  the x location of the pixel
 * @param y  the y location of the pixel
 *
 * @return   the color at that location
 */
color_t gl_read_pixel(unsigned int x, unsigned int y);

/*
 * `gl_draw_char`
 *
 * Draw a single character at location x,y in color c.
 * Only those pixels of the character that lie within the bounds
 * of the framebuffer are drawn. Any pixel that lies outside is
 * clipped (i.e. not drawn). Only the "on" pixels of the character
 * are drawn, all "off" pixels are left as-is.
 *
 * @param x   the x location of the upper left corner of the character glyph
 * @param y   the y location of the upper left corner of the character glyph
 * @param ch  the character to be drawn, e.g. 'a'. If this character has no glyph
 *            in the current font, nothing is drawn (refer to font_get_glyph())
 * @param c   the color of the character
 */
void gl_draw_char(unsigned int x, unsigned int y, char ch, color_t c);

/*
 * `gl_draw_string`
 *
 * Draw a string at location x,y in color c. The characters are drawn
 * left to right in a single line. Only the pixels of the characters
 * that lie within the bounds of the framebuffer are drawn. Any pixel
 * that lies outside is clipped (i.e. not drawn). Only the "on" pixels of
 * the characters are drawn, all "off" pixels are left as-is.
 *
 * @param x    the x location of the upper left corner of the first char of string
 * @param y    the y location of the upper left corner of the first char of string
 * @param str  the null-terminated string to be drawn
 * @param c    the color of the string
 */
void gl_draw_string(unsigned int x, unsigned int y, const char* str, color_t c);

/*
 * `gl_get_char_height`
 *
 * Get the height in pixels of a single character glyph.
 *
 * @return the height of character glyph in pixels
 */
unsigned int gl_get_char_height(void);

/*
 * `gl_get_char_width`
 *
 * Get the width in pixels of a single character glyph.
 *
 * @return the width of character glyph in pixels
 */
unsigned int gl_get_char_width(void);

/*
 * `gl_draw_rect`
 *
 * Draw a filled rectangle at location x,y with size w,h filled with color c.
 * All pixels in the rectangle that lie within the bounds of the
 * framebuffer are drawn. Any pixel that lies outside is clipped (i.e. not drawn).
 *
 * @param x  the x location of the upper left corner of the rectangle
 * @param y  the y location of the upper left corner of the rectangle
 * @param w  the width of the rectangle
 * @param h  the height of the rectangle
 * @param c  the color of the rectangle
 */
void gl_draw_rect(unsigned int x, unsigned int y, unsigned int w, unsigned int h, color_t c);

/*
 * `gl_draw_line`: optional extension
 *
 * Draw a line segment from location x1,y1 to location x2,y2 of color c.
 * All pixels along the line that lie within the bounds of the framebuffer
 * are drawn. Any pixel that lies outside is clipped (i.e. not drawn).
 *
 * @param x1  the x location of vertex 1
 * @param y1  the y location of vertex 1
 * @param x2  the x location of vertex 2
 * @param y2  the y location of vertex 2
 * @param c   the color of the line
 *
 * This function is NOT part of the core requirements.
 * You can leave this function unimplemented if not doing the extension.
 */
void gl_draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, color_t c);

/*
 * `gl_draw_triangle`: optional extension
 *
 * Draw a filled triangle connecting the three vertices filled with color c.
 * All pixels within the triangle that lie within the bounds of the
 * framebuffer are drawn. Any pixel that lies outside is clipped (i.e. not drawn).
 *
 * @param x1  the x location of vertex 1
 * @param y1  the y location of vertex 1
 * @param x2  the x location of vertex 2
 * @param y2  the y location of vertex 2
 * @param x3  the x location of vertex 3
 * @param y3  the y location of vertex 3
 * @param c   the color of the triangle
 *
 * This function is NOT part of the core requirements.
 * You can leave this function unimplemented if not doing the extension.
 */
void gl_draw_triangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int x3, unsigned int y3, color_t c);

#endif

#ifndef GPIO_H
#define GPIO_H

/*
 * Functions for controlling Raspberry Pi GPIO.
 *
 * Students implement this module in assignment 2.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 *         Philip Levis <pal@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last edited Jan 2018
 */

#define GPIO_INVALID_REQUEST  -1  // return value for invalid request

/*
 * `gpio_init`
 *
 * Initialize the GPIO code module. For assignment 2, this does nothing.
 * However, all libpi peripheral modules require an init, so it is included
 * for consistency's sake.
 */
void gpio_init(void);

/*
 * `gpio_set_function`
 *
 * Set a GPIO function for GPIO pin number `pin`. Settings for other pins
 * should be unchanged.
 *
 * @param pin      the GPIO pin number to configure
 * @param function the GPIO function to set for the pin
 *
 * If `pin` or `function` is invalid, does nothing.
 */
void gpio_set_function(unsigned int pin, unsigned int function);

/*
 * `gpio_get_function`
 *
 * Get the GPIO function for GPIO pin number `pin`.
 *
 * @param pin the GPIO pin number to read the function of
 * @return    the current GPIO function of the specified pin
 *
 * If `pin` is invalid, returns GPIO_INVALID_REQUEST.
 */
unsigned int gpio_get_function(unsigned int pin);

/*
 * `gpio_set_input`, `gpio_set_output`
 *
 * Convenience functions for setting a pin to GPIO_FUNC_INPUT or
 * GPIO_FUNC_OUTPUT. The implementation calls `gpio_set_function`.
 *
 * @param pin the GPIO pin number to set the function of
 */
void gpio_set_input(unsigned int pin);
void gpio_set_output(unsigned int pin);

/*
 * `gpio_write`
 *
 * Set GPIO pin number `pin` to high (1) or low (0). This
 * function assumes the pin is already in output mode.
 * Settings for other pins should be unchanged.
 *
 * @param pin   the GPIO pin number to set or clear
 * @param val   1 to set pin to high, 0 to clear pin
 *
 * If `pin` or `val` is invalid, does nothing.
 */
void gpio_write(unsigned int pin, unsigned int val);

/*
 * `gpio_read`
 *
 * Get current level (1 for high, 0 for low) for GPIO pin number `pin`.
 *
 * @param pin the GPIO pin number to read the value of
 * @return    the value of the specified pin
 *
 * If `pin` is invalid, returns GPIO_INVALID_REQUEST.
 */
unsigned int gpio_read(unsigned int pin);

/*
 * Enumeration of GPIO pin numbers
 *
 * The enumerated values below establish symbolic names for each of the GPIO pins.
 * Although you could directly refer to pins by number, using the
 * names makes it more clear to the reader what a given value represents.
 *
 * Note also the values GPIO_PIN_FIRST and GPIO_PIN_LAST that bound
 * the range of valid GPIO pin numbers.
 */
enum {
    GPIO_PIN_FIRST = 0,
    GPIO_PIN0 = 0,
    GPIO_PIN1 = 1,
    GPIO_PIN2 = 2,
    GPIO_PIN3 = 3,
    GPIO_PIN4 = 4,
    GPIO_PIN5 = 5,
    GPIO_PIN6 = 6,
    GPIO_PIN7 = 7,
    GPIO_PIN8 = 8,
    GPIO_PIN9 = 9,
    GPIO_PIN10 = 10,
    GPIO_PIN11 = 11,
    GPIO_PIN12 = 12,
    GPIO_PIN13 = 13,
    GPIO_PIN14 = 14,
    GPIO_PIN15 = 15,
    GPIO_PIN16 = 16,
    GPIO_PIN17 = 17,
    GPIO_PIN18 = 18,
    GPIO_PIN19 = 19,
    GPIO_PIN20 = 20,
    GPIO_PIN21 = 21,
    GPIO_PIN22 = 22,
    GPIO_PIN23 = 23,
    GPIO_PIN24 = 24,
    GPIO_PIN25 = 25,
    GPIO_PIN26 = 26,
    GPIO_PIN27 = 27,
    GPIO_PIN28 = 28,
    GPIO_PIN29 = 29,
    GPIO_PIN30 = 30,
    GPIO_PIN31 = 31,
    GPIO_PIN32 = 32,
    GPIO_PIN33 = 33,
    GPIO_PIN34 = 34,
    GPIO_PIN35 = 35,
    GPIO_PIN36 = 36,
    GPIO_PIN37 = 37,
    GPIO_PIN38 = 38,
    GPIO_PIN39 = 39,
    GPIO_PIN40 = 40,
    GPIO_PIN41 = 41,
    GPIO_PIN42 = 42,
    GPIO_PIN43 = 43,
    GPIO_PIN44 = 44,
    GPIO_PIN45 = 45,
    GPIO_PIN46 = 46,
    GPIO_PIN47 = 47,
    GPIO_PIN48 = 48,
    GPIO_PIN49 = 49,
    GPIO_PIN50 = 50,
    GPIO_PIN51 = 51,
    GPIO_PIN52 = 52,
    GPIO_PIN53 = 53,
    GPIO_PIN_LAST =  53
};

// GPIO pin mappings for UART
#define GPIO_TX GPIO_PIN14
#define GPIO_RX GPIO_PIN15

/*
 * Enumeration for GPIO functions
*
 * The enumerated values below establish symbolic names for each of the
 * available GPIO pin functions. Each pin function corresponds to
 * a particular "mode" of operation.  For example, setting a pin's
 * function to GPIO_FUNC_INPUT configures the pin to be used as an input.
 */
enum {
    GPIO_FUNC_INPUT   = 0,
    GPIO_FUNC_OUTPUT  = 1,
    GPIO_FUNC_ALT0    = 4,
    GPIO_FUNC_ALT1    = 5,
    GPIO_FUNC_ALT2    = 6,
    GPIO_FUNC_ALT3    = 7,
    GPIO_FUNC_ALT4    = 3,
    GPIO_FUNC_ALT5    = 2,
};


#endif

#ifndef GPIO_EXTRA_H
#define GPIO_EXTRA_H

#include <stdbool.h>

/*
 * Functions for controlling extra features of
 * Raspberry Pi GPIO: event detection and pull state.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 *         Philip Levis <pal@cs.stanford.edu>
 *         Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last edited: Feb 2018
 */

enum gpio_event {
    GPIO_DETECT_RISING_EDGE = 0,
    GPIO_DETECT_FALLING_EDGE,
    GPIO_DETECT_HIGH_LEVEL,
    GPIO_DETECT_LOW_LEVEL,
    GPIO_DETECT_ASYNC_RISING_EDGE,
    GPIO_DETECT_ASYNC_FALLING_EDGE,
};

/*
 * `gpio_enable_event_detection`
 *
 * Enables detection of GPIO `event` for GPIO pin number `pin`.
 *
 * @param pin       GPIO pin number to configure
 * @param event     which event to enable, see gpio_event enumeration
 *
 * If `pin` or `event` is invalid, does nothing.
 */
void gpio_enable_event_detection(unsigned int pin, unsigned int event);

/*
 * `gpio_disable_event_detection`
 *
 * Disables detection of GPIO `event` for GPIO pin number `pin`.
 *
 * @param pin       GPIO pin number to configure
 * @param event     which event to disable, see gpio_event enumeration
 *
 * If `pin` or `event` is invalid, does nothing.
 */
void gpio_disable_event_detection(unsigned int pin, unsigned int event);

/*
 * `gpio_get_event_detection`
 *
 * Gets the state of detection of GPIO `event` for GPIO pin number `pin`.
 * Returns true if event detection is enabled for `event`, false if disabled.
 *
 * @param pin       GPIO pin number to query
 * @param event     which event, see gpio_event enumeration
 * @return          true if enabled, false otherwise
 *
 * If `pin` or `event` is invalid, returns false.
 */
bool gpio_get_event_detection(unsigned int pin, unsigned int event);

/*
 * `gpio_disable_all_event_detection`
 *
 * Disables detection of all GPIO events for GPIO pin number `pin`.
 *
 * @param pin       GPIO pin number to disable detection of all events
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_disable_all_event_detection(unsigned int pin);

/*
 * `gpio_check_event`
 *
 * Returns the event status for GPIO pin number `pin`.
 * The event status is true if an event has been detected for `pin`
 * and the event has not been cleared, status is false otherwise.
 *
 * @param pin       GPIO pin number to check
 * @return          true if event detected, false otherwise
 *
 * If `pin` is invalid, returns false.
 */
bool gpio_check_event(unsigned int pin);

/*
 * `gpio_clear_event`
 *
 * Clears the event status for GPIO pin number `pin`. Note that if the
 * event detected is high or low level and the level is still high or low,
 * clearing the event makes no change in event status.  The event
 * status remains true as long as the high or low level is in effect.
 *
 * @param pin       GPIO pin number to clear
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_clear_event(unsigned int pin);

/*
 * `gpio_check_and_clear_event`
 *
 * Returns the event status for GPIO pin number `pin` and clears the
 * event status.
 *
 * @param pin       GPIO pin number to check and clear
 * @return          true if event detected and cleared, false otherwise
 *
 * If `pin` is invalid, does nothing and returns false.
 */
bool gpio_check_and_clear_event(unsigned int pin);

/*
 * The functions below control the pull state of a GPIO pin via its
 * internal resistor. Setting the pull state is useful for when you
 * have an input pin that would otherwise be floating. A pin configured
 * to pull-up defaults to 1. If configured to pull-down defaults to 0.
 * The Broadcom manual says pull state of a pin cannot be queried,
 * so you have to remember what state you have configured. The manual
 * is also unclear about when the pull state is reset (may not be on
 * restart, but is after power down?). Best to reset yourself to be
 * sure.
 */

/*
 * `gpio_set_pullup`
 *
 * Set pull state of GPIO pin number `pin` to pull-up.
 *
 * @param pin       GPIO pin number to configure as pull-up
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_set_pullup(unsigned int pin);

/*
 *
 * `gpio_set_pulldown`
 *
 * Set pull state of GPIO pin number `pin` to pull-down.
 *
 * @param pin       GPIO pin number to configure as pull-down
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_set_pulldown(unsigned int pin);

/*
 * `gpio_set_pullnone`
 *
 * Disables any pull state of GPIO pin number `pin` (will float).
 *
 * @param pin       GPIO pin number to disable pull state
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_set_pullnone(unsigned int pin);

#endif

#ifndef GPIO_INTERRUPTS_H
#define GPIO_INTERRUPTS_H

#include "interrupts.h"

/*
 * Module to configure GPIO interrupts for Raspberry Pi.
 * Because all of the GPIO pins share a small set of GPIO
 * interrupts, you need a level of indirection to be able
 * to handle interrupts for particular pins. This module
 * allows a client to register one handler for each
 * GPIO pin.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 *
 * Last update:   May 2020
 */

/*
 * `gpio_interrupts_init`: Required initialization for module
 *
 * Initialize the GPIO interrupts module. The init function must be
 * called before any calls to other functions in this module.
 * The init function configures gpio interrupts to a clean state.
 * This function registers a handler for GPIO interrupts with the
 * top-level interrupts module. The top-level handler receives
 * GPIO events for all pins and in turn dispatches to the handler
 * registered with the gpio interrupts module for the specific pin.
 */
void gpio_interrupts_init(void);

/*
 * `gpio_interrupts_register_handler`
 *
 * Register a handler function to a given GPIO pin. Each GPIO
 * pin can have one handler: further dispatch should be invoked by
 * the handler itself. Use the events system defined in `gpio_extra.h`
 * to configure which GPIO events are detected by the pin.
 *
 * @param pin       GPIO pin to register handler
 * @param fn        handler function to call when interrupt generated on pin
 * @param aux_data  client's data pointer to be passed as second argument
 *                  when calling handler function
 *
 * An assert is raised if `pin` is invalid. `aux_data` can be NULL if
 * handler function has no need for auxiliary data. If `fn` is NULL, removes
 * any handler previously registered for `pin`.
 *
 * This function asserts on an attempt to register handler without first
 * initializing the module (i.e. required to call `gpio_interrupts_init`).
 */
void gpio_interrupts_register_handler(unsigned int pin, handler_fn_t fn, void *aux_data);


#endif

#ifndef INTERRUPTS_H
#define INTERRUPTS_H

#include <stdbool.h>
#include <stddef.h>

/*
 * Module to configure interrupts for Raspberry Pi.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last update:   May 2020
 */

/*
 * `interrupts_init`: Required initialization for interrupts
 *
 * Initialize interrupts and configures to a clean state.
 *
 *    - vector table is copied to destination address 0
 *    - all interrupt sources are disabled
 *    - interrupts are globally disabled
 *
 * This module init should be called once (and only once)
 * before any calls to other functions in the interrupts module.
 * Calling the init function a second time will raise an error.
 * Without more specific initialization semantics and structure,
 * this is the safe approach that avoids having to debug why a
 * source suddenly stopped receiving interrupts after a re-init
 * silently wiped the settings from previous configuration.
 */
void interrupts_init(void);

/*
 * `interrupts_global_enable`
 *
 * Turns on interrupts system-wide. An interrupt generated on
 * an enabled interrupt source will call the registered handler.
 */
void interrupts_global_enable(void);

/*
 * `interrupts_global_disable`
 *
 * Turns off interrupts system-wide. No interrupts will be generated.
 * Does not remove registered handlers or disable interrupt sources,
 * only temporarily suspends interrupt generation. Call
 * `interrupts_global_enable` to resume generating interrupts.
 */
void interrupts_global_disable(void);

/*
 * `handler_fn_t`
 *
 * This typedef gives a nickname to the type of function pointer used as
 * a handler callback. A handler is registered to an interrupt source. When
 * an interrupt is generated by that source, the handler is called to
 * process it. A handler takes two arguments. The first argument is the
 * value of the interrupted pc and second argument is the client's
 * auxiliary data pointer (can be NULL if not used).
 */
typedef void (*handler_fn_t)(unsigned int, void *);

/*
 * `interrupts_register_handler`
 *
 * Register the handler function for a given interrupt source. Each interrupt
 * source can have one handler: further dispatch should be invoked by
 * the handler itself. When a handler is registered for an interrupt source,
 * interrupts are enabled for that source. In order for interrupts to be generated,
 * must also turn on interrupts with `interrupts_global_enable`.
 *
 * This function asserts on an attempt to register handler without initializing
 * the interrupts module (i.e. required to call `interrupts_init` first).
 *
 * Valid interrupt sources are basic interrupts and those with entries in
 * the interrupt table in the BCM2835 manual: GPU and other reserved
 * interrupts are invalid.
 *
 * An interrupt source is identified by number. Valid source numbers are
 * listed below in the `interrupt_source` enumeration.
 * The sources we will commonly use are
 *     INTERRUPTS_GPIO3 for gpio interrupts (source shared by all gpios)
 *     INTERRUPTS_BASIC_ARM_TIMER_IRQ  for armtimer interrupts
 *
 * @param source    which interrupt source (see enumeration values below)
 * @param fn        handler function to call when interrupt generated on source
 * @param aux_data  client's data pointer to be passed as second argument
 *                  when calling handler function
 *
 * An assert is raised if `source` is invalid. `aux_data` can be NULL if
 * handler function has no need for auxiliary data. If `fn` is NULL, this
 * removes any handler previously registered and disables interrupts for
 * `source`.
 */
void interrupts_register_handler(unsigned int source, handler_fn_t fn, void *aux_data);

/*
 * Enumeration of valid interrupt sources
 *
 * Below are the interrupt sources that this module can enable, disable,
 * and handle. AUX through VC_UART are all IRQs from peripherals. There
 * are 64 peripheral interrupts, but only these ones should be handled by
 * your code -- the datasheet says (BCM2835 Sec 7.5)
 *    "The table has many empty entries. These should not be
 *     enabled as they will interfere with the GPU operation."
 *
 * So there is a peripheral interrupt 0 but you should not handle it.
 *
 * Values with _BASIC_ in them are basic interrupts that are generated
 * from the core itself. Normally, these are a completely separate
 * identifier space of interrupts. Basic interrupt 0 is the ARM_TIMER
 * interrupt, for example. Rather than have two separate sets of functions
 * for peripheral and basic interrupts, we just give them IDs > 64 and
 * then map them to their real values in the code. Using a single
 * identifier space means that we avoid the inevitable bug of someone
 * passing a basic interrupt ID to a peripheral interrupt function and
 * vice versa.
 */
enum interrupt_source {
    INTERRUPTS_SHARED_START    = 29,
    INTERRUPTS_AUX             = 29,
    INTERRUPTS_I2CSPISLV       = 43,
    INTERRUPTS_PWA0            = 45,
    INTERRUPTS_PWA1            = 46,
    INTERRUPTS_CPR             = 47,
    INTERRUPTS_SMI             = 48,
    INTERRUPTS_GPIO0           = 49,
    INTERRUPTS_GPIO1           = 50,
    INTERRUPTS_GPIO2           = 51,
    INTERRUPTS_GPIO3           = 52,
    INTERRUPTS_VC_I2C          = 53,
    INTERRUPTS_VC_SPI          = 54,
    INTERRUPTS_VC_I2SPCM       = 55,
    INTERRUPTS_VC_UART         = 57,
    INTERRUPTS_SHARED_END,

    INTERRUPTS_BASIC_BASE      = 64,
    INTERRUPTS_BASIC_ARM_TIMER_IRQ = INTERRUPTS_BASIC_BASE,
    INTERRUPTS_BASIC_ARM_MAILBOX_IRQ,
    INTERRUPTS_BASIC_ARM_DOORBELL_0_IRQ,
    INTERRUPTS_BASIC_GPU_0_HALTED_IRQ,
    INTERRUPTS_BASIC_GPU_1_HALTED_IRQ,
    INTERRUPTS_BASIC_ACCESS_ERROR_1_IRQ,
    INTERRUPTS_BASIC_ACCESS_ERROR_0_IRQ,
    INTERRUPTS_BASIC_END,
    INTERRUPTS_COUNT,
    INTERRUPTS_NONE = 255,
};


#endif

#ifndef KEYBOARD_H
#define KEYBOARD_H

#include "gpio.h"
#include "ps2_keys.h"

/*
 * Module to read keys typed on a PS/2 keyboard.
 *
 * Students implement this module in assignment 5.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last updated:   February 2019
 */

typedef struct {
    enum { KEY_PRESS, KEY_RELEASE } what;
    unsigned char keycode;
} key_action_t;

/*
 * These bit flags are used for the state of the various modifier
 * keys on the keyboard.
 */
typedef enum {
    KEYBOARD_MOD_SHIFT = 1 << 0,
    KEYBOARD_MOD_ALT = 1 << 1,
    KEYBOARD_MOD_CTRL = 1 << 2,
    KEYBOARD_MOD_CAPS_LOCK = 1 << 3,
    KEYBOARD_MOD_SCROLL_LOCK = 1 << 4,
    KEYBOARD_MOD_NUM_LOCK = 1 << 5,
} keyboard_modifiers_t;

typedef struct {
    key_action_t action;                // see struct declared above
    ps2_key_t key;                      // entry taken from ps2_keys table (see ps2_keys.h)
    keyboard_modifiers_t modifiers;     // modifiers in effect, composed of above bit flags
} key_event_t;


#define KEYBOARD_CLOCK GPIO_PIN3
#define KEYBOARD_DATA GPIO_PIN4

/*
 * `keyboard_init`: Required initialization for keyboard.
 *
 * The keyboard must first be initialized before any key events can be read.
 * The two arguments are the GPIO pins of the PS2 clock and data lines
 * to use when creating the PS2 device.
 *
 * @param clock_gpio    the gpio connected to the clock line of keyboard
 * @param data_gpio     the gpio connected to the data line of keyboard
 */
void keyboard_init(unsigned int clock_gpio, unsigned int data_gpio);

/*
 * `keyboard_read_next`: Top level keyboard interface.
 *
 * This function reads (blocking) the next key typed on the keyboard.
 * The character returned reflects the current keyboard modifier settings.
 *
 * Return values in the range 0 - 0x7f indicate the typed key is an ordinary
 * Ascii character. For a typed key not associated with an Ascii character,
 * such an arrow or function key, the function returns a value >= 0x90. The
 * value assigned to each non-Ascii key is given in the list of `ps2_codes`
 * in the `ps2_keys.h` header file.
 *
 * This function calls `keyboard_read_event` to receive a key press event.
 *
 * @return      Ascii value of typed char or function code for non-ascii key
 */
unsigned char keyboard_read_next(void);

/*
 * `keyboard_read_event`: Mid level keyboard interface.
 *
 * The function reads (blocking) the next key event.
 * Returns a `key_event_t` struct that represents the key event.
 * A key event is a press or release of a single key. The returned
 * struct includes the key that was pressed or released and the state
 * of the modifier flags.
 *
 * Returned key events do not include modifier keys. Pressing shift,
 * for example, will not result in a key event being returned, but if a key
 * that does produce a key event (e.g., 'a') is pressed before the shift
 * is released, `keyboard_read_event` will return an event for this
 * key with the shift modifier set.
 *
 * This function calls `keyboard_read_sequence` to read a sequence.
 *
 * @return      key_event_t struct containing key event information
 */
key_event_t keyboard_read_event(void);

/*
 * `keyboard_read_sequence`: Low level keyboard interface.
 *
 * Reads a sequence of scancode bytes corresponding to the press or
 * release of a single key.  Returns a `key_action_t` struct that
 * represents the key action for the sequence read. Reads 1, 2, or 3
 * scancodes:
 *    1 byte:  ordinary key press
 *    2 bytes: ordinary key release or extended key press
 *    3 bytes: extended key release
 *
 * The `keycode` field of the returned key_action_t stores the last byte
 * of the sequence. This keycode identifies the PS2 key that was acted upon.
 *
 * This function calls `keyboard_read_scancode` to read each scancode.
 *
 * @return      key_action_t struct containing key action for sequence
 */
key_action_t keyboard_read_sequence(void);

/*
 * `keyboard_read_scancode`: Bottom level keyboard interface.
 *
 * Calls into ps2 module to read (blocking) a single scancode from
 * the PS2 keyboard device.
 *
 * @return      scancode read from keyboard
 */
unsigned char keyboard_read_scancode(void);

/*
 * `keyboard_use_interrupts`
 *
 * Change keyboard from default polling behavior to instead configure interrupts
 * for gpio events. After setting keyboard to use interrupts, client must
 * also globally enable interrupts at system level. This switchable feature is
 * specific to reference module. The student's keyboard module is initially
 * polling-only (assign5) and later changed to interrupt-only (assign7).
 */
void keyboard_use_interrupts(void);


#endif

#ifndef MAILBOX_H
#define MAILBOX_H
/*
 * Interface to Raspberry Pi mailboxes for interacting with on-chip
 * peripherals such as the framebuffer and touchscreen.
 *
 * You read the implementation of this module in Lab 6, answering
 * some questions about how and why it works.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Date: Jan 31 2016
 */

#include <stdbool.h>

/*
 * The maximum number of channels on the Pi
 */
#define MAILBOX_MAXCHANNEL 16

/*
 * These constants define mailbox channels. Messages can be sent on
 * these channels. The only channel we use in this course is the
 * MAILBOX_FRAMEBUFFER channel.
 */
typedef enum {
    MAILBOX_POWER_MANAGEMENT = 0,
    MAILBOX_FRAMEBUFFER,
    MAILBOX_VIRTUAL_UART,
    MAILBOX_VCHIQ,
    MAILBOX_LEDS,
    MAILBOX_BUTTONS,
    MAILBOX_TOUCHSCREEN,
    MAILBOX_UNUSED,
    MAILBOX_TAGS_ARM_TO_VC,
    MAILBOX_TAGS_VC_TO_ARM,
} mailbox_channel_t;


/*
 * Send a mailbox request and confirm response. Uses
 * `mailbox_write` to send `addr` to `channel` and `mailbox_read`
 * to verify response.
 *
 * @param channel send request to `channel`
 * @param addr    `addr` is the address of the message data to send. This address
 *                must be a multiple of 16 (i.e. lower 4 bits are 0).
 *                GPU_NOCACHE will be added to the address so that the contents
 *                of the message is not cached by the GPU.
 * @return        true if request successfully processed, false otherwise
 *                returns false if channel or addr is invalid
 */
bool mailbox_request(unsigned int channel, unsigned int addr);

/*
 * Write a mailbox message to `channel`. After writing a message,
 * must call `mailbox_read` to receive response from GPU.
 *
 * @param channel send the message to `channel`
 * @param addr    `addr` is the address of the message data to send. This address
 *                must be a multiple of 16 (i.e. lower 4 bits are 0).
 *                GPU_NOCACHE will be added to the address so that the contents
 *                of the message is not cached by the GPU.
 * @return        true if message successfully sent, false otherwise
 *                returns false if channel or addr is invalid
 */
bool mailbox_write(unsigned int channel, unsigned int addr);

/*
 * Receive a mailbox message for `channel`.
 *
 * @param channel  receive a message on `channel`
 * @return         the data in the message received
 *
 */
unsigned int mailbox_read(unsigned int channel);


#endif

#ifndef MALLOC_H
#define MALLOC_H

/*
 * Functions for dynamic allocation.
 *
 * Students implement this module in assignment 4.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Mon Feb  5 20:02:27 PST 2018
 */
#include <stddef.h> // for size_t


/*
 * Service a dynamic allocation request. Returns the
 * address of a memory block of at least `nybtes` contiguous
 * bytes or NULL if the request cannot be satisifed.
 * The block address is guaranteed to be aligned to an 8-byte boundary.
 * If `nbytes` is 0, malloc returns either NULL or a unique
 * pointer to an allocated block of some minimum size.
 *
 * @param nbytes    requested size in bytes
 * @return          address of memory block of requested size
 *                  or NULL if request cannot be satisifed
 */
void *malloc(size_t nbytes);

/*
 * Deallocate the memory block at address `ptr`.
 *
 * The `ptr` argument is expected to be an address that was
 * previously returned by malloc and has not yet been freed.
 * If this precondition is not satisified, the behavior is undefined.
 * If `ptr` is NULL, the operation does nothing.
 *
 * @param ptr       address of memory block to deallocate
 */
void free(void *ptr);

/*
 * Return the address of the previous end of the heap segment
 * and enlarge the segment by the specified number of bytes.
 * The call `sbrk(0)` returns the address of the end of segment
 * with no change in size. You may assume that no calls to
 * sbrk with a non-zero argument will come from outside clients,
 * calls to enlarge the segment will only come from within
 * your heap allocator implementation.
 *
 * @param nbytes    the number of bytes to extend the segment end by
 * @return          address of previous end of segment (before enlarge)
 */
void *sbrk(int nbytes);


#endif

#ifndef MOUSE_H
#define MOUSE_H

#include "gpio.h"
#include <stdbool.h>


typedef enum {
    MOUSE_BUTTON_PRESS = 0,
    MOUSE_BUTTON_RELEASE = 1,
    MOUSE_MOVED = 2,
    MOUSE_DRAGGED = 3,
} mouse_action_t;


typedef struct {
    mouse_action_t action;
    int dx, dy;
    bool x_overflow, y_overflow;
    bool left, middle, right;
} mouse_event_t;

#define MOUSE_CLOCK GPIO_PIN5
#define MOUSE_DATA GPIO_PIN6

/*
 * `mouse_init`: Required initialization for mouse.
 *
 * The mouse must first be initialized before any mouse events can be read.
 * The two arguments are the GPIO pins of the PS2 clock and data lines
 * to use when creating the PS2 device.
 *
 * @param clock_gpio    the gpio connected to the clock line of mouse
 * @param data_gpio     the gpio connected to the data line of mouse
 */
void mouse_init(unsigned int clock_gpio, unsigned int data_gpio);

/*
 * `mouse_read_event`
 *
 * The function reads (blocking) the next event from the mouse.
 * Returns a `mouse_event_t` struct that represents the mouse event.  The
 * struct includes the relative change in x and y (dx, dy fields). A delta
 * value will be in range +/- 255, the x_overflow/y_overflow fields are true
 * if actual value of dx/dy exceeded +/- 255.  The left/middle/right fields
 * give the state of the mouse buttons. Each field is true if the corresponding
 * mouse button is down, false otherwise.
 *
 * @return         mouse_event_t struct containing event data
 */
mouse_event_t mouse_read_event(void);

#endif

#ifndef PI_H
#define PI_H

/*
 * Utility functions for Raspberry Pi.
 *
 * Authors: Pat Hanrahan <hanrahan@cs.stanford.edu>,
 *          Philip Levis <pal@cs.stanford.edu>,
 *          Julie Zelenski <zelenski@cs.stanford.edu>
 */

#include "gpio.h"

/*
 * Enumeration for valid LED identifiers.
 *
 * The two LEDs on the Raspberry Pi board are:
 *  PI_ACT_LED    green LED labeled `ACT`
 *  PI_PWR_LED    red LED labeled `PWR`
 */
enum {
    PI_ACT_LED = GPIO_PIN47,
    PI_PWR_LED = GPIO_PIN35
};

/*
 * `pi_reboot`
 *
 * Halts current program execution and reboots the Pi.
 */
void pi_reboot(void) __attribute__ ((noreturn));

/*
 * `pi_abort`
 *
 * Goes into an infininte loop that flashes the red power
 * LED on the Pi board. This function does not return.
 */
void pi_abort(void) __attribute__ ((noreturn));

/*
 * `pi_led_on`
 *
 * Turns on the specified LED.
 *
 * @param led      the led to turn on
 *
 * If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
 */
void pi_led_on(int led);

/*
 * `pi_led_off`
 *
 * Turns off the specified LED.
 *
 * @param led      the led to turn off
 *
 * If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
 */
void pi_led_off(int led);

/*
 * `pi_led_toggle`
 *
 * Toggles the specified LED. If on, turns it off. If off, turns on.
 *
 * @param led      the led to toggle
 *
 * If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
 */
void pi_led_toggle(int led);

#endif

#ifndef PRINTF_H
#define PRINTF_H

/*
 * Functions for printing formatted strings.
 *
 * Students implement this module in assignment 3
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Sat Jan 27 11:27:13 PST 2018
 */
#include <stdarg.h>
#include <stddef.h>

/* The functions vnsprintf, snprintf, and printf construct a
 * formatted output from an input format string and arguments.
 * These functions support same conversion options in format
 * string, but differ slightly in how the function is called
 * or what it does with the output string, e.g., whether it is
 * sent to the Raspberry Pi UART (printf) or written into the
 * destination buffer (snprintf, vsnprintf).
 *
 * The supported format conversions are
 *   %c    single character
 *   %s    string
 *   %d    signed decimal integer
 *   %x    unsigned hexadecimal integer (hex letters in lowercase)
 *   %p    pointer (printed as a hex address)
 *   %%    used to output a single percent character
 *
 * The %d and %x formats support an optional field width.
 *
 * The fancier printf features (padding with spaces, justification
 * left/right, precision, etc.) are not supported.
 * All format conversions other than the supported ones listed above
 * are considered invalid. The function's behavior for an invalid
 * format conversion is undefined.
 */

/*
 * `vsnprintf`
 *
 * Constructs a formatted output string from an input string and a va_list
 * of arguments. Writes output string to the destination buffer.
 *
 * @param buf       destination buffer where to write output string
 * @param bufsize   size of destination buffer (output truncated to fit if needed)
 * @param format    format for output string. May contain ordinary characters
 *                  (copied to destination as-is) and format conversions (next
 *                  argument converted and copied to destination)
 * @param args      list of arguments to be converted
 * @return          count of characters written if entire formatted string
 *                  fits in destination; otherwise count of characters it would
 *                  have written if there were space.
 */
int vsnprintf(char *buf, size_t bufsize, const char *format, va_list args);

/*
 * `snprintf`
 *
 * Constructs a formatted output string from an input string and variable
 * arguments. Writes output string to the destination buffer.
 *
 * @param buf       destination buffer where to write output string
 * @param bufsize   size of destination buffer (output truncated to fit if needed)
 * @param format    format for output string. May contain ordinary characters
 *                  and format conversions
 * @param ...       variable arguments to be converted
 * @return          count of characters written if entire formatted string
 *                  fits in destination; otherwise count of characters it would
 *                  have written if there were space.
 */
int snprintf(char *buf, size_t bufsize, const char *format, ...) __attribute__((format(printf, 3, 4)));

/*
 * `printf`
 *
 * Constructs a formatted output string from an input string and arguments.
 * Writes output string to UART.
 *
 * @param format    format for output string. May contain ordinary characters
 *                  and format conversions
 * @param ...       variable arguments to be converted
 * @return          count of characters written to UART
 */
int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));

#endif

#ifndef PS2_H
#define PS2_H

/*
 * Module that communicates with a PS2 device such as a keyboard
 * or mouse.
 *
 * Students implement this module in assignments 5 and 7.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 *
 * Last edited Feb 2021
 */

#include <stdbool.h>

typedef struct ps2_device ps2_device_t;

/*
 *  `ps2_new`
 *
 * Initializes a new PS2 device connected to specified clock and data GPIO
 * pins and returns pointer to device.
 *
 * To configure a new PS2 device in your code:
 *
 *     ps2_device_t *dev = ps2_new(KEYBOARD_CLK, KEYBOARD_DATA);
 *
 * Notice that this interface is slightly different from the _init exposed by
 * other libpi modules. The _new pattern allows a client to create multiple PS2
 * devices, such as one for a keyboard and another for a mouse. It also means
 * that clients of this module don't need to know the implementation details
 * (like size) of ps2_device_t, since they just keep a pointer.
 *
 * @param clock_gpio    the gpio connected to the clock line of the PS2 device
 * @param data_gpio     the gpio connected to the data line of the PS2 device
 * @return              pointer to new PS2 device or NULL if failed to create
 *
 * Although `ps2_new` configures the requested clock and data GPIOs
 * to use the internal pull-up resistors, it is recommended to choose GPIO
 * pins whose default state is already pull-up. This avoid timing issues
 * if the device attempts to handshake with the Pi before `ps2_new` has
 * been called.
 */
ps2_device_t *ps2_new(unsigned int clock_gpio, unsigned int data_gpio);


/*
 * `ps2_read`
 *
 * Read (blocking) a single scancode from the specifed PS2 device.
 * Bits are read on the falling edge of the clock.
 *
 * Reads 11 bits: 1 start bit, 8 data bits, 1 parity bit, and 1 stop bit
 *
 * Discards and restarts the scancode if:
 *   (lab5) The start bit is incorrect
 *   (assign5) or if parity or stop bit is incorrect
 *
 * Returns the 8 data bits of a well-formed PS2 scancode.
 * Will not return until it reads a complete and valid scancode.
 *
 * @param dev     PS2 device from which to read
 * @return        scancode read from PS2 device
 */
unsigned char ps2_read(ps2_device_t *dev);


/*
 * `ps2_write`: optional extension
 *
 * Write a command scancode to the specifed PS2 device.
 * You do not need to implement this function unless you are
 * doing the mouse extension.
 *
 * @param dev       PS2 device to which to write
 * @param command   scancode to write
 * @return          true if successful write, false otherwise
 */
bool ps2_write(ps2_device_t *dev, unsigned char command);


/*
 * `ps2_use_interrupts` : reference-only
 *
 * The default behavior of `ps2_read` is to read scancode bits
 * by polling the clock GPIO and waiting for a falling edge. An
 * alternate mode would be to register for event detection
 * on the clock GPIO to be notified of each falling edge and use
 * an interrupt handler to read a bit. The interrupt handler would
 * enqueue a scancode to an internal queue to be later
 * dequeued by`ps2_read`.
 *
 * The reference implementation of this module has a switch to
 * change the mode for a ps2 device. The default is read-by-polling.
 * After creating a device with `ps2_new`, the client may call
 8 `ps2_use_interrupts(device)` to change that device into
 * read-by-interrupt mode.
 *
 * The client must also globally enable interrupts at system level for
 * interrupts to be generated.
 *
 * The switchable mode is specific to the reference implementation.
 * The student's ps2 module does not have this function.
 * The initial implementation by student is polling-only (assign5) and
 * later changed to interrupt-only (assign7).
 */
void ps2_use_interrupts(ps2_device_t *dev);


#endif
#ifndef PS2_KEYS_H
#define PS2_KEYS_H

/* This module declares constants for interacting with a PS/2
 * keyboard, including an array that serves as a lookup table
 * to access information about the keys and the characters they produce.
 *
 * Each entry in the array corresponds to one physical key on the keyboard.
 * Each key has an assigned PS/2 scancode. The array is organized
 * in order of scancode. The scancode is used as an index to access
 * the character produced by that key.  For the
 * special keys (non-character), its associated char is a value >= 0x90
 * from the ps2_codes enumeration below. The `other_ch` is the key
 * when shift is applied: for some key it is the same as `ch`.
 *
 * You use this interface in assignment 5 to implement a keyboard
 * driver.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date:   November 2020
 */


typedef struct {
    unsigned char ch;
    unsigned char other_ch;
} ps2_key_t;

extern ps2_key_t const ps2_keys[];

/* Since regular chars have ASCII values that are all <= 0x7F,
 * we assign codes >= 0x90 to the non-char keys.
 */
enum ps2_codes {
    PS2_KEY_NONE = 0,
    PS2_CODE_RELEASE = 0xF0,
    PS2_CODE_EXTENDED = 0xE0,
    PS2_KEY_SHIFT = 0x90,
    PS2_KEY_ALT,    // values assigned in increasing sequence from here
    PS2_KEY_CTRL,
    PS2_KEY_CAPS_LOCK,
    PS2_KEY_ENTER,
    PS2_KEY_ESC,
    PS2_KEY_F1,
    PS2_KEY_F2,
    PS2_KEY_F3,
    PS2_KEY_F4,
    PS2_KEY_F5,
    PS2_KEY_F6,
    PS2_KEY_F7,
    PS2_KEY_F8,
    PS2_KEY_F9,
    PS2_KEY_F10,
    PS2_KEY_F11,
    PS2_KEY_F12,
    PS2_KEY_NUM_LOCK,
    PS2_KEY_HOME,
    PS2_KEY_PAGE_UP,
    PS2_KEY_PAGE_DOWN,
    PS2_KEY_INSERT,
    PS2_KEY_DELETE,
    PS2_KEY_END,
    PS2_KEY_SCROLL_LOCK,
    PS2_KEY_ARROW_UP,
    PS2_KEY_ARROW_DOWN,
    PS2_KEY_ARROW_LEFT,
    PS2_KEY_ARROW_RIGHT
};


#endif

#ifndef RB_H
#define RB_H

#include <stdbool.h>

/*
 * This module defines a ring buffer data structure that provides
 * a fixed-length FIFO (first-in-first-out) queue of int elements.
 *
 * The queue is designed to allow concurrent access by 1 reader (rb_dequeue)
 * and 1 writer (rb_enqueue). The writer is typically the interrupt handler,
 * which is enqueuing data to be dequeued by the main program, the reader.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 */

typedef struct ringbuffer rb_t;

/*
 * `rb_new`
 *
 * Initializes a new empty ring buffer and returns a pointer to it.
 *
 * @return      pointer to new ring buffer or NULL if failed to create
 *
 * To set up a ring buffer in your code:
 *
 *     rb_t *rb = rb_new();
 *
 * Notice that this interface is slightly different from the _init exposed by
 * other libpi modules. This _new pattern allows a user to have multiple ring
 * buffers, like objects in Java. It also means that users of this
 * module don't need to know the implementation details (like size) of rb_t,
 * since they just keep a pointer.
 */
rb_t *rb_new(void);

/*
 * `rb_empty`
 *
 * Check if a ring buffer is currently empty.
 *
 * @param rb    the ring buffer to check
 * @return      true if rb is empty, false otherwise
 */
bool rb_empty(rb_t *rb);

/*
 *  `rb_full`
 *
 * Check if a ring buffer is currently full. When full, existing
 * elements must first be dequeued before further elements can
 * be enqueued.
 *
 * @param rb    the ring buffer to check
 * @return      true if rb is full, false otherwise
 */
bool rb_full(rb_t *rb);

/*
 * `rb_enqueue`
 *
 * Add an element to the back of a ring buffer. If the ring buffer
 * is full, no changes are made and false is returned.
 *
 * @param rb    the ring buffer to enqueue to
 * @param elem  the element to enqueue
 * @return      true if elem was successfully enqueued, false otherwise
 */
bool rb_enqueue(rb_t *rb, int elem);

/*
 * `rb_dequeue`
 *
 * If the ring buffer is not empty, remove frontmost element,
 * store into *p_elem, and return true.  p_elem should be the address
 * of a valid memory location into which to store the dequeued value.
 * If the ring buffer is empty, no changes are made to either the ring
 * buffer or *p_elem and the return value is false.
 *
 * @param rb        the ring buffer to dequeue from
 * @param p_elem    address at which to store the dequeued element
 * @return          true if an element was written to *p_elem, false otherwise
 */
bool rb_dequeue(rb_t *rb, int *p_elem);

#endif

#ifndef SHELL_H
#define SHELL_H

#include <stddef.h>

/*
 * Interface to the CS107E shell.
 *
 * Students implement this module in assignment 5.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Last update: February 2019
 */

/*
 * Type: `input_fn_t`
 *
 * This typedef gives a nickname to the type of function pointer used as the
 * the shell input function.  A input_fn_t function takes no arguments and
 * returns a value of type unsigned char. `keyboard_read_next` is an example
 * of a possible shell input function.
 */
typedef unsigned char (*input_fn_t)(void);

/*
 * Type: `formatted_fn_t`
 *
 * This typedef gives a nickname to the type of function pointer used as the
 * the shell output function.  A formatted_fn_t function has one fixed
 * parameter (format string) and variable arguments to follow. The return
 * value is of type int. `printf` is an example of a possible shell
 *  output function.
 */
typedef int (*formatted_fn_t)(const char *format, ...) __attribute__((format(printf, 1, 2)));

/*
 * `shell_init`: Required initialization for shell
 *
 * The two arguments are function pointers. The `read_fn` is a function
 * to read input. The shell calls this function to get the next
 * input character. The `print_fn` is a function to print output.
 * The shell calls this function to output formatted text.
 * The client's choice of read function controls where shell reads
 * input and cclient's hoice of print function controls where shell
 * output is displayed.
 *
 * Example usage:
 *   `shell_init(keyboard_read_next, printf)`
 *   `shell_init(keyboard_read_next, console_printf)`
 *
 * @param read_fn    function to read input char
 * @param print_fn   function to output formatted text
 */
void shell_init(input_fn_t read_fn, formatted_fn_t print_fn);

/*
 * `shell_bell`: audio/visual beep
 *
 * Sends an Ascii BEL character '\a' over the uart. This gives
 * an audio or visual beep depending on your terminal settings.
 * https://en.wikipedia.org/wiki/Bell_character
 */
void shell_bell(void);

/*
 * `shell_readline`: read function of shell read-eval-print loop
 *
 * Reads a single line of input from the user.
 *
 * Reads characters entered by user and stores them into `buf`.
 * Updates display to show current line as user edits.
 * Stops reading when user enters Return ('\n'). The ending newline
 * is discarded (not written to `buf`).  If user enters more
 * characters than fit in `buf` (`bufsize` - 1), those excess characters
 * are rejected (call `shell_bell`) and not written to `buf`.  A
 * null-terminator is written to the end of the contents in `buf`.
 *
 * When the user types backspace (\b):
 *   If there are any characters currently in the buffer, deletes the last one.
 *   Otherwise, calls `shell_bell`.
 *
 * @param buf       destination buffer to store characters
 * @param bufsize   size of the buffer
 */
void shell_readline(char buf[], size_t bufsize);

/*
 * `shell_evaluate`: eval function of shell read-eval-print loop
 *
 * Parses line and execute command.
 *
 * Parsing proceeds as follows:
 *   - Divide the line into an array of tokens. A token consists
 *     of a sequence of non-space chars.  Ignore/skip all whitespace
 *     in between tokens as well as leading and trailing whitespace.
 *     Whitespace includes space, tab, and newline.
 *   - The first token is the name of the command to execute, the
 *     subsequent tokens are the arguments to the command.
 * After parsing, execute the command:
 *   - Find the function pointer associated with the command name.
 *   - If no such command is found, give error:
 *           error: no such command 'binky'.
 *   - Otherwise, execute the function, passing array of arguments.
 *
 * Returns the result of the call to the command function, or -1 if no
 * command was executed.
 *
 * @param line       command line to parse and execute
 * @return           result returned by command function or -1 if none
 */
int shell_evaluate(const char *line);

/*
 * `shell_run`: Top level shell interface.
 *
 * Main function of the shell module. Must be preceded by calls
 * to `shell_init` and `keyboard_init`.
 *
 * Enters a read-eval-print loop that repeatedly cycles between `shell_readline`
 * and `shell_evaluate`. This function never returns.
 */
void shell_run(void);


#endif

#ifndef COMMANDS_H
#define COMMANDS_H

/*
 * This typedef gives a nickname to the type of function pointer used as the
 * a shell command.  A command_fn_t function has two parameters, the array
 * of tokens and its count. The return value is of type int.
 */
typedef int (*command_fn_t)(int argc, const char *argv[]);

/*
 * This typedef defines the type for each entry in the command table.
 * A command_t stores the info for one command, including one-word name,
 * help description, and function pointer to execute the command.
 */
typedef struct _command_struct {
    const char *name;
    const char *description;
    command_fn_t fn;
} command_t;

/*
 * `cmd_echo`
 *
 * Prints its arguments and returns 0.
*/
int cmd_echo(int argc, const char *argv[]);

/*
 * `cmd_help`
 *
 * When called without arguments:
 *   Prints a list of all available commands and their descriptions.
 *
 * Example:
 *   Pi> help
 *   echo:   echo user input to the screen
 *   reboot: reboot the Raspberry Pi back to the bootloader
 *   ...
 *
 * When called with one argument
 *   Prints the description for that command, or an error message if that
 * command does exist:
 *
 *   Pi> help reboot
 *   reboot:  reboot the Raspberry Pi back to the bootloader
 *   Pi> help please
 *   error: no such command `please`.
 *
 * Ignores any arguments after the first. Returns 0 on success,
 * 1 on error (command not found).
 */
int cmd_help(int argc, const char *argv[]);

/*
 * `cmd_reboot`
 *
 * reboot the Raspberry Pi back to the bootloader using `pi_reboot`
 *
 * Ignores all arguments. This function does not return; the program
 * exits and Pi is restarted.
 */
int cmd_reboot(int argc, const char *argv[]);

/*
 * `cmd_peek`
 *
 * Usage: peek [addresss]
 *
 * Prints the contents (4 bytes) of memory at address.
 * If address argument is prefixed with 0x, it is interpreted as hex,
 * otherwise interpreted as decimal. Address must be 4-byte aligned.
 *
 * Example:
 *
 *   Pi> peek 0
 *   0x00000000:  e59ff030
 *
 * If the address argument is missing or invalid, prints an error message:
 *
 *   Pi> peek
 *   error: peek requires 1 argument [address]
 *   Pi> peek fred
 *   error: peek cannot convert 'fred'
 *
 * Ignores any arguments after the first. Returns 0 on success, 1 on error.
 */
int cmd_peek(int argc, const char *argv[]);

/*
 * `cmd_poke`
 *
 * Usage: poke [adress] [value]
 *
 * Stores `value` into the memory at `address`.
 * If a numeric argument is prefixed with 0x, it is interpreted as hex,
 * otherwise interpreted as decimal. Address must be 4-byte aligned.
 *
 * Example:
 *
 *   Pi> poke 0x1000 3
 *   Pi> peek 0x1000
 *   0x00001000: 00000003
 *
 * If argument is missing or invalid, prints an error message:
 *
 *   Pi> poke 0xFFFC
 *   error: poke requires 2 arguments [address] and [value]
 *   Pi> poke bob 3
 *   error: poke cannot convert 'bob'
 *   Pi> poke 11 0
 *   error: poke address must be 4-byte aligned
 *
 * Ignores any arguments after the second. Returns 0 on success, 1 on error.
 */
int cmd_poke(int argc, const char *argv[]);


#endif

#ifndef STRINGS_H
#define STRINGS_H
/*
 * Functions for handling strings.
 *
 * Students implement this module in assignment 3
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Sat Jan 27 11:27:13 PST 2018
 */

#include <stddef.h>

/*
 * `memset`
 *
 * Write `n` bytes of value `val` to the memory area `dst`.
 * Due to historical artifact, `val` parameter has type `int` even
 * though the argument is treated as `unsigned char`. The
 * least significant byte of `val` is copied `n` times.
 *
 * @param dst   address of memory location
 * @param val   the byte value to replicate
 * @param n     the number of bytes to write
 * @return      argument `dst`
 */
void *memset(void *dst, int val, size_t n);

/*
 * `memcpy`
 *
 * Copy `n` bytes of data from the memory area `src` to the
 * memory area `dst`. It is a client error to call memcpy on
 * `dst` and `src` areas that overlap. In such a case,
 * the behavior is undefined.
 *
 * @param dst   address of memory location area to write
 * @param src   address of memory location area to read
 * @param n     the number of bytes to copy
 * @return      argument `dst`
 */
void *memcpy(void *dst, const void *src, size_t n);

/*
 * `strlen`
 *
 * Compute the length of string `str`.
 *
 * @param str   null-terminated string
 * @return      the count of characters preceding terminating '\0' character
 */
size_t strlen(const char *str);

/*
 * `strcmp`
 *
 * Lexicographically compare the null-terminated strings `s1` and `s2`.
 *
 * The function result indicates whether string `s1` is less than (negative),
 * equal to (zero), or greater than (positive) string `s2`.
 * Comparison is done as unsigned characters.
 *
 * @param s1, s2    null-terminated strings
 * @return          negative, zero, or positive result of comparing `s1` to `s2`
 */
int strcmp(const char *s1, const char *s2);

/*
 * `strtonum`
 *
 * Convert the digit characters in `str` to the corresponding unsigned integer
 * value. If `str` begins with the prefix "0x", the characters of `str` will
 * be interpreted as hexadecimal digits (base 16); otherwise the characters
 * are interpreted as decimal digits (base 10). No other bases are supported.
 * The hex letter digits are accepted in both upper and lowercase.
 *
 * `strtonum` processes the characters of `str`, stopping at the first
 * character that is not a valid digit in the base or at the terminating
 * '\0' (whichever comes first).  The function is not required to support
 * leading spaces or a plus/minus sign. Such characters can be
 * treated as invalid and stop the conversion.
 *
 * The argument `endptr` is an output parameter optionally used to
 * communicate back to the caller what characters remain in `str` after having
 * "consumed" the digit characters. A caller can pass NULL for `endptr`
 * if they do not need this information.
 *
 * If `endptr` is not NULL, *endptr is updated to point to the character
 * in `str` where conversion stopped. This is either the address of the
 * first invalid character in `str` or the address of the terminating '\0'
 * if all characters in `str` are valid digits.
 *
 * The function result is the converted value or 0 if the first character of
 * `str` is not a valid digit and no conversion was possible.
 *
 * The function only needs to handle converting numbers that are within
 * the range reprsentable as `unsigned int`.
 *
 * @param str       null-terminated string to convert
 * @param endptr    output parameter, will point to character after conversion end
 * @return          result of numeric conversion (or 0 if first char is invalid)
 */
unsigned int strtonum(const char *str, const char **endptr);

/*
 * `strlcat`
 *
 * Size-bounded string concatenation. Append the null-terminated string `src`
 * to the end of `dst`. `strlcat` appends at most `dstsize - strlen(dst) - 1`
 * bytes, and null-terminates `dst`. If `dst` and `src` overlap,
 * the behavior is undefined.
 *
 * The function result is the initial length of `dst` plus the length of
 * `src`, i.e. the final size of `dst` if there were space to append
 * all of `src`.
 *
 * If there is no null terminator within the first `dstsize` characters of
 * `dst`, either `dstsize` is incorrect or `dst` is not a proper string.
 * In such cases, nothing is written to `dst` and the return result is
 * `dstsize + strlen(src)`
 *
 * @param dst       destination buffer containing null-terminated string
 * @param str       null-terminated string to append to destination
 * @param dstsize   size of the dst buffer
 * @return          final size of dst if there were space to append all of src
 */
size_t strlcat(char *dst, const char *src, size_t dstsize);

#endif

#ifndef TIMER_H
#define TIMER_H

/*
 * Hardware abstractions for a Raspberry Pi timer.
 *
 * Students implement this module in assignment 2.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 *         Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Date: Jan 24, 2016
 * Edited by Mark Miller, Anna Zeng, Jan 21, 2018
 */

/*
 * `timer_init`
 *
 * Initialize the timer. For assignment 2, this does nothing.
 * However, all libpi peripheral modules require an init, so it is
 * included for consistency's sake.
 */
void timer_init(void);

/*
 * `timer_get_ticks`
 *
 * Returns the current system tick count. The tick count is set to
 * zero at boot and increments once per microsecond until the
 * processor resets.  One tick is equal to one microsecond.
 *
 * @return  system tick count
 */
unsigned int timer_get_ticks(void);

/*
 * `timer_delay_us`
 *
 * A simple busy loop that delays the program for `usec` microseconds.
 *
 * @param usec  the number of microseconds to busy loop for
 */
void timer_delay_us(unsigned int usec);

/*
 * `timer_delay_ms`
 *
 * Delay for `msec` milliseconds.
 *
 * @param msec  the number of milliseconds to busy loop for
 */
void timer_delay_ms(unsigned int msec);

/*
 * `timer_delay`
 *
 * Delay for `sec` seconds.
 *
 * @param sec the number of seconds to busy loop for
 */
void timer_delay(unsigned int sec);

#endif

#ifndef UART_H
#define UART_H

#include <stdbool.h>

/*
 * Hardware abstractions for a serial port (UART).
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Date: Jan 24, 2016
 */

enum {
    EOT = 4,  // Output end of transmission to indicate uart communication complete
    EOF = -1  // Receive end of file when no more data to read
};

/*
 * `uart_init`: Required initialization for module
 *
 * Initialize the UART code module. A single call to `uart_init`
 * should made as part of the program initialization, before any
 * calls to other uart_ functions.  It is allowed, although unusual,
 * to call `uart_init` again to reset the UART state. A reset
 * will discard any pending data in the send/receive buffer.
 *
 * The UART requires exclusive use of GPIO pins 14 (transmit)
 * and 15 (receive).  Once the UART is initialized and in use,
 * your code should not muck with these two pins.
 */
void uart_init(void);

/*
 * `uart_getchar`
 *
 * Obtains the next input character from the serial port and returns it.
 * If receive buffer is empty, will block until next character is received.
 *
 * @return    the character read or EOF if error or at end of input
 */
int uart_getchar(void);

/*
 * `uart_putchar`
 *
 * Outputs a character to the serial port.
 * If send buffer is full, will block until space available.
 *
 * @param ch   the character to write to the serial port
 * @return     the character written
 */
int uart_putchar(int ch);

/*
 * `uart_flush`
 *
 * Flushes any output characters pending in the send buffer.
 */
void uart_flush(void);

/*
 * `uart_haschar`
 *
 * Returns whether there is a character in the receive buffer.
 *
 * @return      true if character ready to be read, false otherwise
 */
bool uart_haschar(void);

/*
 * `uart_putstring`
 *
 * Outputs a string to the serial port by calling `uart_putchar`
 * on each character.
 *
 * @param str  the string to output
 * @return     the count of characters written or EOF if error
 */
int uart_putstring(const char *str);

/*
 * `uart_send`
 *
 * Outputs raw byte to the serial port. `uart_send` outputs the raw byte
 * with no translation (unlike `uart_putchar` which adds processing for
 * converting end-of-line markers). To send text character, use
 * `uart_putchar`; if raw binary data, use `uart_send`.
 *
 * @param byte   the byte to write to the serial port
 */
void uart_send(unsigned char byte);

/*
 * `uart_recv`
 *
 * Obtain raw byte from the serial port. `uart_recv` returns the raw
 * byte with no translation (unlike uart_getchar which adds processing
 * for converting end-of-line and end-of-file markers). To read text
 * character, use `uart_getchar`; if raw binary data, use `uart_recv`.
 *
 * @return   the byte read from the serial port
 */
unsigned char uart_recv(void);


#endif