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__)  \
                           ": 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.
 *
 * 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;


/* Function: backtrace
 * -------------------
 * 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 contains more than `max_frames`,
 * then the information for only the `max_frames` most recent function calls
 * are stored in the array `f`.
 *
 * The return value of the function is the number of frames written to `f`.
 */
int backtrace(frame_t f[], int max_frames);

/* Function: 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
 */
void print_frames(frame_t f[], int n);

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

/* Function: 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 "???"
 */
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.
 *
 * You implement this interface in assignment 6.
 *
 * Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: 3/24/16
 */


/*
 * 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
 */
void console_init(unsigned int nrows, unsigned int ncols);

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

/*
 * 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)
 * '\r' :  carriage return (move cursor to first position in the same line)
 * '\f' :  form feed (clear contents and move cursor to home position)
 *
 * @return the number of characters written to the console
 */
int console_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));


#endif

#ifndef DISASSEMBLE_H
#define DISASSEMBLE_H

/*
 * Various utility functions that operate on text section.
 *
 * Decode an ARM instruction into a string
 * (used by printf %pI format)
 *
 * Convert address to symbolic name and vice versa. (code
 * must be compiled -mpoke-function-name)
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Mon Feb 18 17:02:32 PST 2019
 */

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

/*
 * `buf` is the destination of the instruction string
 * `bufsize` is the size of `buf`
 * `addr` is address of instruction in memory
 *
 * Decodes instruction at location `addr`, and writes string
 * form to `buf`, truncated (if necessary) to `bufsize`.
 * Returns true if able to decode instruction, false otherwise.
 */
bool disassemble_insn(char *buf, size_t bufsize, unsigned int *addr);

/*
 * `buf` is the destination of the label string
 * `bufsize` is the size of `buf`
 * `addr` is address of instruction in memory
 *
 * Writes label to `buf`, truncated (if necessary) to
 * `bufsize`. Label is in the form of "<function+offset>"
 * if function name found, otherwise just "<>"
 */
void disassemble_label(char *buf, size_t bufsize, unsigned int *addr);

/*
 * Searches text section to find a function with embedded name that
 * matches `name`.
 * If found, returns address of the function's first instruction;
 * otherwise returns NULL.
 */
unsigned int *disassemble_name_to_addr(const char *name);

/*
 * Searches backwards from `addr` to find embedded name for the
 * function containing instruction at `addr`. If `p_offset` is non-NULL,
 *`*p_offset` is assigned the count of bytes bewteen `addr` and
 * the function's first instruction.
 * Returns embedded name (if found), otherwise returns NULL.
 */
const char *disassemble_addr_to_name(unsigned int *addr, int *p_offset);

/*
 * Returns true if `addr` lies within the text section and contents at
 * addr can be decoded as an instruction; false otherwise.
 */
bool disassemble_is_valid_text(unsigned int *addr);

#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.
 *
 * In assignment 6 you are given a single-buffered implementation
 * of this module and extend it to provide double-buffering.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: Mar 23 2016
 */

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

/*
 * 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);

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

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

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

/*
 * 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);

/*
 * 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.  The client draws to that one buffer,
 * and each update is immediately displayed.
 * In double buffering mode, the address returned is for the draw (back)
 * buffer which is currently off-screen. The client draws to
 * this buffer and when ready, calls `fb_swap_buffer` to exchange the front
 * and back buffers. The swap brings the 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 (back) buffer
 */
void* fb_get_draw_buffer(void);

/*
 * Swap the front and back buffers. The draw buffer is moved to the
 * front (contents displayed) and the front buffer is moved to the back
 * (becomes the draw buffer, contents off-screen).
 *
 * If not in double buffering mode, this function has no effect.
 */
void fb_swap_buffer(void);

#endif

#ifndef FONT_H
#define FONT_H

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

/*
 * Functions that provide bitmaps of ASCII characters.
 *
 * Each character is represented as an image that has
 * font_get_height() rows and font_get_width() columns.
 * Each pixel of the image is represented as one byte.
 * The byte for an "on" pixel is 0xFF, and the byte for
 * "off" pixel is 0x00.
 *
 * You do not have to implement this interface: the source code for
 * its implementation is provided as part of assignment 6.
 *
 * Author: Philip Levis <pal@cs.stanford.edu>
 * Date: Mar 25 2016
 */

typedef struct  {
    unsigned char first_char, last_char;
    size_t char_width, char_height;
    unsigned char pixel_data[];
} font_t;


/*
 * Get the current font.
 */
const font_t *font_get_font(void);

/*
 * Set the current font.
 */
void font_set_font(font_t *f);

/*
 * Get the height in pixels of a character.
 *
 * @return    the character height in pixels
 */
size_t font_get_height(void);

/*
 * Get the width in pixels of a character.
 *
 * @return    the character width in pixels
 */
size_t font_get_width(void);

/*
 * Get the total number of bytes needed to store a character
 * image. This is equal to character height * character width.
 *
 * @return    the size in bytes
 */
size_t font_get_size(void);

/*
 * Fill in the image of character `ch` into the buffer `buf`.
 * `buf` is an array of bytes of length width * height (see
 * font_get_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 image of the character.
 * @param buflen the length of `buf`.
 *              `buflen` should be equal to value returned by font_get_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_size()
 */
bool font_get_char(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.
 *
 * You 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;

/*
 * 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);

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

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

/*
 * 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  0xFF1F00FF

/*
 * 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);

/*
 * 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);

/*
 * If in double-buffered mode, all gl drawing takes place off-screen
 * and a call to `gl_swap_buffer` is required to bring the drawing on-screen.
 * (Swap action exchanges the front and draw buffers of the virtual
 * framebuffer).
 *
 * 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);

/*
 * 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(int x, int y, color_t c);

/*
 * 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(int x, int y);

/*
 * 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).
 *
 * @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_char())
 * @param c   the color of the character
 */
void gl_draw_char(int x, int y, int ch, color_t c);

/*
 * 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).
 *
 * @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(int x, int y, const char* str, color_t c);

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

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

/*
 * 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(int x, int y, int w, int h, color_t c);

/*
 * 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 basic requirements.
 * You can leave this function unimplemented if not doing the extension.
 */
void gl_draw_line(int x1, int y1, int x2, int y2, color_t c);

/*
 * 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 basic requirements.
 * You can leave this function unimplemented if not doing the extension.
 */
void gl_draw_triangle(int x1, int y1, int x2, int y2, int x3, int y3, color_t c);

#endif

#ifndef GPIO_H
#define GPIO_H

/*
 * Functions for controlling Raspberry Pi GPIO.
 * You will implement this interface 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
 */


/*
 * These enumerated values 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

/*
 * These enumerated values 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,
};

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


/*
 * 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);

/*
 * 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);

/*
 * 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);

/*
 * 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);

/*
 * 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` is invalid, does nothing.
 */
void gpio_write(unsigned int pin, unsigned int val);

/*
 * 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);


#endif

#ifndef GPIO_INTERRUPTS_H
#define GPIO_INTERRUPTS_H

#include <stdbool.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 indirectiom 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`
 *
 * Initialize the GPIO interrupt modules. 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, which it
 * uses to call handlers on a per-pin basis.
 *
 */
void gpio_interrupts_init(void);

/*
 * `gpio_interrupts_enable`
 *
 * Global enable for GPIO interrupts.
 */
void gpio_interrupts_enable(void);

/*
 * `gpio_interrupts_disable`
 *
 * Global disable for GPIO interrupts.
 */
void gpio_interrupts_disable(void);

/*
 * `interrupts_register_handler`
 *
 * Register a handler function to a given GPIO pin. Each pin
 * source can have one handler: further dispatch should be invoked by
 * the handler itself. Whether or not a particular pin will
 * generate interrupts is specified by the events system,
 * defined in `gpio_extra.h`.
 *
 * Asserts if failed to install handler (e.g., the pin is invalid).
 * Pins are defined in `gpio.h`.
 */
handler_fn_t gpio_interrupts_register_handler(unsigned int pin, handler_fn_t fn);

/*
 * `gpio_interrupts_default_handler`
 *
 * The default handler for GPIO events. Does nothing. Provided
 * as reference point for what the prior handler returned from
 * registering a handler, plus as a convenience for uninstalling
 * a handler (replace it with this).
 */
bool gpio_default_handler(unsigned int pc);


#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,
};

/*
 * Enables detection of GPIO `event` for GPIO pin number `pin`.
 *
 * If `pin` or `event` is invalid, does nothing.
 */
void gpio_enable_event_detection(unsigned int pin, unsigned int event);

/*
 * Disables detection of GPIO `event` for GPIO pin number `pin`.
 *
 * If `pin` or `event` is invalid, does nothing.
 */
void gpio_disable_event_detection(unsigned int pin, unsigned int event);

/*
 * 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.
 *
 * If `pin` or `event` is invalid, returns false.
 */
bool gpio_get_event_detection(unsigned int pin, unsigned int event);

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

/*
 * 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.
 *
 * If `pin` is invalid, returns false.
 */
bool gpio_check_event(unsigned int pin);

/*
 * 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.
 *
 * If `pin` is invalid, does nothing.
 */
void gpio_clear_event(unsigned int pin);

/*
 * Returns the event status for GPIO pin number `pin` and clears the
 * event status.
 *
 * 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.
 */

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

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

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

#endif

#ifndef INTERRUPTS_H
#define INTERRUPTS_H

#include <stdbool.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`
 *
 * Initialize interrupts. The init function must be called once
 * before any calls to other functions in the interrupts module.
 * The init function configures interrupts to a clean state.
 *
 *    - vector table is copied to destination address 0
 *    - all interrupt sources are off
 *    - interrupts are globally disabled
 *
 * Note that this function does _not_ deregister existing handlers.
 * This is so that if an interrupting-using module calls
 * `interrupts_init` then installs a handler, a subsequent
 * `interrupts_init` by another, unrelated module will not erase
 * the first one's handler. Without setting up more specific
 * initialization semantics and structure, this is the safe
 * approach to take that will save you from trying to debug for
 * hours why suddenly a module isn't receiving interrupts.
 */
void interrupts_init(void);

/*
 * `interrupts_global_enable`
 *
 * Turns on interrupts system-wide. Interrupts for events on sources
 * with registered handlers will call those handlers.
 */
void interrupts_global_enable(void);

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

/*
 * `interrupts_is_pending`
 *
 * Returns true if there is a pending event for the given source, false
 * otherwise. The source should be a value from the INTERRUPTS enum
 * below.
 */
bool interrupts_is_pending(unsigned int source);

/*
 * `interrupts_enable_source``
 *
 * Enable a particular interrupt source. The source itself must still
 * be configured to generate interrupts (and global interrupts must be
 * enabled) for a registered handler to be called. The source should be
 * a value from the INTERRUPTS enum below.
 */
bool interrupts_enable_source(unsigned int source);

/*
 * `interrupts_disable_source`
 *
 * Disable a particular interrpt source. Interrupts for this source
 * will not trigger a handler and will remain pending (until cleared).
 * The source should be a value from the INTERRUPTS enum below.
 */
bool interrupts_disable_source(unsigned int source);

/*
 * 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 one argument of type unsigned int
 * (value of interrupted pc) and returns a bool, which indicates whether
 * the interrupt was successfully processed.
 */
typedef bool (*handler_fn_t)(unsigned int);

/*
 * `interrupts_register_handler`
 *
 * Install the handler function for a given interrupt source. Each interrupt
 * source can have one handler: further dispatch should be invoked by
 * the handler itself.
 *
 * Asserts if failed to install handler (i.e. vector table not properly
 * initialized or specified interrupt is invalid). Returns the old
 * handler that existed (NULL if none was). Valid interrupts 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
 *
 * Note that calling this function does _not_ enable the interrupt!
 * you need to do that separately.
 */
handler_fn_t interrupts_register_handler(unsigned int source, handler_fn_t fn);

/* The valid 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.h"

/*
 * Module to read keys typed on a PS/2 keyboard.
 *
 * You implement this module in assignments 5 and 7.
 *
 * 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.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 first and second arguments identify which GPIO pins to use for the
 * PS/2 clock and data lines, respectively.
 *
 * Although `keyboard_init` 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, such as KEYBOARD_CLOCK and
 * KEYBOARD_DATA defined above. This avoid timing issues due to the keyboard
 * attempting to handshake with the Pi before `keyboard_init` has executed.
 */
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.h` header file.
 *
 * This function calls `keyboard_read_event` to receive a key press event.
 */
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.
 */
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 PS/2 key that was acted upon.
 *
 * This function calls `keyboard_read_scancode` to read each scancode.
 */
key_action_t keyboard_read_sequence(void);


/*
 * `keyboard_read_scancode`: Bottom level keyboard interface.
 *
 * Read (blocking) a single scancode from the PS/2 keyboard.
 * 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 PS/2 scancode.
 * Will not return until it reads a complete and valid scancode.
 */
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.
 */
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
 */

/*
 * 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;

/*
 * Write a mailbox message to `channel`
 *
 * @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.
 */
void 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.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Mon Feb  5 20:02:27 PST 2018
 */
#include <stddef.h> // for size_t


/* Function: malloc
 * ----------------
 * Services a dynamic allocation request. Returns the
 * address of a block of at least `nybtes` contiguous bytes
 * or NULL if the request cannot be satisifed.
 * The returned pointer 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.
 */
void *malloc(size_t nbytes);

/* Function: free
 * --------------
 * Deallocates the memory at address `ptr`.
 *
 * The `ptr` argument is expected to be an address that was previously
 * return 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.
 */
void free(void *ptr);

/* Function: realloc
 * -----------------
 * Changes the size of the memory block pointed to by `ptr` to at least
 * `new_size` bytes. The contents of the memory block are unchanged
 * from the start to the minimum of the old and new sizes. If
 * requested change in size cannot be accommodated in-place,
 * realloc() creates a new allocation, copies as much of the data
 * pointed to by `ptr` as will fit to the new allocation, frees
 * the previous allocation, and returns a pointer to the new memory.
 *
 * The `ptr` argument is expected to an address that was
 * previously returned by malloc and has not yet been freed.
 * If this precondition is not satisified, the behavior is undefined.
 *
 * The call realloc(NULL, size) is equivalent to malloc(size)
 * The call realloc(ptr, 0) is equivalent to free(ptr) and returns NULL
 */
void *realloc(void *ptr, size_t new_size)  __attribute__ ((warn_unused_result));

#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"


/*
 * 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
};

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

/*
 * 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));

/*
 * Turns on the specified LED.
 *
 * `led` must be either PI_ACT_LED or PI_PWR_LED. If not, this function does nothing.
 */
void pi_led_on(int led);

/*
 * Turns off the specified LED.
 *
 * `led` must be either PI_ACT_LED or PI_PWR_LED. If not, this function does nothing.
 */
void pi_led_off(int led);

/*
 * Toggles the specified LED. If on, turns it off. If off, turns on.
 *
 * `led` must be either PI_ACT_LED or PI_PWR_LED. If not, this function does nothing.
 */
void pi_led_toggle(int led);

#endif

#ifndef PRINTF_H
#define PRINTF_H

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

/* These three functions from the printf family construct a
 * formatted output from an input format string and arguments.
 * All three functions accept format strings specified using the same
 * kind of conversions, 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
 * client's 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.
 */

/*
 * Constructs a formatted output string from an input string and arguments.
 *
 * `buf` is the destination where output string is to be written
 * `bufsize` is the size of `buf`, output string will be truncated
 * if necessary to fit
 * `format` string may contain ordinary characters (copied to `buf` as-is)
 * and/or format conversions (written to `buf` after converting next
 * argument to string).
 *
 * Returns total number of characters written if entire formatted string
 * fits in `buf`; otherwise returns the number of characters it would
 * have written if there were space.
 */
int vsnprintf(char *buf, size_t bufsize, const char *format, va_list args);

/*
 * Constructs a formatted output string from an input string and arguments.
 *
 * `buf` is the destination where output string is to be written
 * `bufsize` is the size of `buf`, output string will be truncated
 * if necessary to fit
 * `format` string may contain ordinary characters (copied to `buf` as-is)
 * and/or format conversions (written to `buf` after converting next
 * argument to string).
 *
 * Returns total number of characters written if entire formatted string
 * fits in `buf`; otherwise returns the number 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)));

/*
 * Constructs a formatted output string from an input string and arguments,
 * and outputs final string to UART.
 *
 * `format` string may contain ordinary characters (output as-is)
 * and/or format conversions (output after converting next argument to string).
 *
 * Returns the number of characters written to UART.
 */
int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));

#endif

#ifndef PS2_H
#define PS2_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:   Novembner 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,
 * who 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 volatile struct ringbuffer rb_t;

/*
 * Initializes a new empty ring buffer and returns a pointer to it.
 *
 * @return  pointer to the new ring buffer or NULL if cannot satisfy request.
 *
 * 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);

/*
 * 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);

/*
 * 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);

/*
 * 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);

/*
 * 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. You implement the beginnings
 * of your shell in assignment 5 and complete it in assignment 7.
 *
 * Author: Julie Zelenski <zelenski@cs.stanford.edu>
 * Last update: February 2019
 */


/*
 * 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.
 */
typedef int (*formatted_fn_t)(const char *format, ...) __attribute__((format(printf, 1, 2)));

/*
 * `shell_init`: Required initialization for shell
 *
 * One argument is a function pointer `print_fn`. The shell will call
 * this function whenever it wants to output text.  By supplying
 * a different function, you control how/where the output is displayed.
 *
 * Example usage:
 *   * `shell_init(printf)`
 *   * `shell_init(console_printf)`
 */
void shell_init(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 keyboard.
 *
 * Reads characters typed on the keyboard and stores them into `buf`.
 * Reading stops when the user types Return ('\n') or when `buf` is
 * full (`bufsize` - 1), whichever comes first. A null-terminator is
 * written to the end of the contents in `buf`.
 * The ending newline is discarded (not written to buf).
 *
 * When the user types backspace (\b):
 *   If there are any characters currently in the buffer, deletes the last one.
 *   Otherwise, calls `shell_bell`.
 */
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.
 */
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

#include <stddef.h>

/*
 * Write `n` bytes of value `c` (converted to an unsigned char) to the memory
 * area pointed to by `s`.
 *
 * Return its first argument: `s`.
 */
void *memset(void *s, int c, size_t n);

/*
 * Copy `n` bytes from the memory area `src` to the memory area `dst`. If `dst`
 * and `src` overlap, the behavior is undefined.
 *
 * Returns its first argument: `dst`.
 */
void *memcpy(void *dst, const void *src, size_t n);

/*
 * Report the length of string `s`.
 *
 * Returns the number of characters that precede the null-terminator.
 */
size_t strlen(const char *s);

/*
 * Lexicographically compare the null-terminated strings `s1` and `s2`.
 *
 * Returns an integer value greater than, equal to, or less than 0, according
 * to whether the string `s1` is greater than, equal to, or less than
 * the string `s2`. Comparison is done as unsigned characters.
 */
int strcmp(const char *s1, const char *s2);

/*
 * 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 to be specified in 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
 * null (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 null
 * if all characters in `str` are valid digits.
 *
 * Returns the result of the conversion as an unsigned integer. Returns 0
 * if the first character of `str` is not a valid digit.
 */
unsigned int strtonum(const char *str, const char **endptr);

/*
 * Size-bounded string concatenation. Append the null-terminated string `src`
 * to the end of `dst`. `dst` may or may not be null terminated. If `dst` is
 * null terminated, `strlcat` appends at most `maxsize - strlen(dst) - 1` bytes, and
 * null-terminates `dst`. If `dst` is not null terminated, `strlcat` writes
 * nothing to `dst`. If `dst` and `src` overlap, the behavior is undefined.
 *
 * Returns the initial length of `dst` plus the length of `src`. This is
 * equal to the final size of `dst` if there were space to write all of
 * `src`. If `dst` is not null terminated, this is equal to `maxsize
 * + strlen(src)`.
 */
size_t strlcat(char *dst, const char *src, size_t maxsize);

#endif

#ifndef TIMER_H
#define TIMER_H

/*
 * Hardware abstractions for a Raspberry Pi timer.
 *
 * 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
 */

/*
 * 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);

/*
 * 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);

/*
 * 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);

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

/*
 * 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

};

/*
 * Initialize the UART code module. The init function should be called
 * once before any calls to other functions in the uart module. 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.
 * It is possible, although rare, to call uart_init() again to
 * reset the UART state. A re-initialization will discard any
 * pending data in the send/receive buffer.
 */
void uart_init(void);

/*
 * 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);

/*
 * 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);

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

/*
 * Returns true if there is a character ready to be read, false otherwise.
 */
bool uart_haschar(void);

/*
 * 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);

/*
 * 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);

/*
 * 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