CS107e library header files
#ifndef ASSERT_H
#define ASSERT_H
/*
* Interface for assertions. The `assert` macro tests the given expression and
* if it is false, prints a diagnostic message and halts execution.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include "mango.h"
#include "uart.h"
#define STRINGIFY_IMPL(x) #x
#define AS_STRING(x) STRINGIFY_IMPL(x)
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
uart_start_error(); \
uart_putstring("File " __FILE__ ", line " AS_STRING(__LINE__) ", in function "); \
uart_putstring(__func__); \
uart_putstring("() : Assertion '" #EXPR "' failed.\n"); \
uart_end_error(); \
mango_abort(); \
} \
} while (0);
#define error(STR) \
do { \
uart_start_error(); \
uart_putstring("File " __FILE__ ", line " AS_STRING(__LINE__) ", in function "); \
uart_putstring(__func__); \
uart_putstring("()\nERROR: " STR "\n"); \
uart_end_error(); \
mango_abort(); \
} while (0);
#endif
#ifndef BACKTRACE_H
#define BACKTRACE_H
/*
* Functions for harvesting a debugging backtrace from the call stack.
*
* Students implement this module in assignment 4.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdint.h>
/*
* Type: `frame_t`
*
* This struct stores the information for a function that has a frame on the
* call stack. The `resume_addr` is taken from saved ra in the callee frame.
* The return address in the caller's sequence of instructions where control
* will resume after the callee returns. The type `uintptr_t` is an
* unsigned int/long of the appropriate bitwidth to store an address. The
* `uintptr_t` type is used for an address that you intend to treat numerically.
*/
typedef struct {
uintptr_t resume_addr;
} frame_t;
/*
* `backtrace_gather_frames`
*
* Gathers a backtrace by harvesting frames from the current call stack and
* storing into the frame array `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 to harvest.
* If the current call stack contains more than `max_frames`, only the
* `max_frames` topmost calls are stored into the array.
*
* The function returns 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 f
* @return count of frames written to array f
*/
int backtrace_gather_frames(frame_t f[], int max_frames);
/*
* `backtrace_print_frames`
*
* Given an array of frames as filled in by a call to backtrace_gather_frames(),
* this function prints one line per frame zero-indexed using format:
*
* #0 0x40000124 at <label+offset>
* #1 0x4000004c at <label+offset>
* #2 0x400001d8 at <label+offset>
*
* If symbols are available, the label is the name of the function and offset.
* The offset is the number of bytes from function start to resume_addr.
* If symbols are not available, the label is the offset of the address
* within the .text section. See `symtab_label_for_addr` in symtab.h
*
* #2 0x400001d8 at <.text+2816>
*
* @param f array of stack frames
* @param n number of frames in array f
*/
void backtrace_print_frames(frame_t f[], int n);
/*
* `backtrace_print`
*
* Convenience function that calls `backtrace_gather_frames` and
* `backtrace_print_frames` to display current call stack.
*/
void backtrace_print(void);
/*
* `__stack_chk_fail`
*
* Handler function for gcc StackGuard. You should not call this function
* yourself. A call to the handler is inserted by gcc when a buffer
* overflow is detected. The handler print an error message about the issue.
* The attribute `noreturn` indicates the function does not return and
* program execution stops within the function. A noreturn function stops
* execution by entering an infinite loop or calling another noreturn function
* such as `mango_abort` or `mango_reboot`.
*/
void __stack_chk_fail(void) __attribute__ ((noreturn));
#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>
*/
#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
*
* A subsequent call to console_init after the first does a reinitialization.
*/
void console_init(int nrows, 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 DE_H
#define DE_H
/*
* Functions for interacting with Display Engine peripheral.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
/*
* `de_init` : Required initializion for DisplayEngine
*
* The DE is configured to display a framebuffer of the specified
* width and height on a screen of the specified dimensions.
* DE should be initialized only after HDMI hardware has been configured
* via hdmi_init(). If the requested fb dimensions do not fit on the
* screen, an error is raised.
*
* @param fb_width width of framebuffer in pixels
* @param fb_height height of framebuffer in pixels
* @param screen_width width of hdmi screen in pixels
* @param screen_height height of hdmi screen in pixels
*/
void de_init(int fb_width, int fb_height, int screen_width, int screen_height);
/*
* `de_set_active_framebuffer` :
*
* Change screen to show contents of framebuffer memory at `addr`.
* Framebuffer is assumed to be valid memory of size/shape matching how
* DE was configured during de_init().
*
* @param addr base address of framebuffer to display
*/
void de_set_active_framebuffer(void *addr);
#endif
#ifndef FB_H
#define FB_H
/*
* Low-level framebuffer routines. These provide a hardware
* abstraction for displaying to screen that a graphics library can
* then use to support drawing primitives.
*
* Students implement this module for assignment 6.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
typedef enum { FB_SINGLEBUFFER = 0, FB_DOUBLEBUFFER = 1 } fb_mode_t;
/*
* `fb_init` : Required initialization 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 mode whether the framebuffer should be
* single buffered (FB_SINGLEBUFFER)
* or double buffered (FB_DOUBLEBUFFER)
*
* The depth of the framebuffer is always 4 bytes; ech pixel is
* 32-bit value in format BGRA.
*
* If the requested size can be successfully accommodated by the underlying
* hardware, the function returns normally. Otherwise an assert will be raised
* within de/hdmi to report the problem.
*
* A subsequent call to fb_init after the first does a reinitialization.
* All previous framebuffer memory is deallocated and the framebuffer is
* re-initialized for the requested configuration.
*/
void fb_init(int width, int height, fb_mode_t mode);
/*
* `fb_get_width`
*
* Get the current width in pixels of the framebuffer.
*
* @return the width in pixels
*/
int fb_get_width(void);
/*
* `fb_get_height`
*
* Get the current height in pixels of the framebuffer.
*
* @return the height in pixels
*/
int fb_get_height(void);
/*
* `fb_get_depth`
*
* Get the current depth in bytes of a single pixel.
* In our case, depth is always 4.
*
* @return the depth in bytes
*/
int fb_get_depth(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 bytes of capacity width*height*depth.
*
* 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`
*
* Fast exchange of front (on-screen) and back (off-screen) buffers.
* The buffer that was previously off-screen is now displayed on-screen
* and buffer that was on-screen moves 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
/*
* This module provides a font.
*
* Author: Philip Levis <pal@cs.stanford.edu>
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*
* A font contains a glyph for each ASCII character to be drawn.
* 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.
*/
/*
* `font_get_glpyh_height`
*
* Get the height in pixels of each glyph in this font.
*
* @return the height in pixels
*/
int 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
*/
int 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
*/
int 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().
* A byte is represented as an `uint8_t`; a pixel that is 'on'
* 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, uint8_t buf[], size_t buflen);
#endif
#ifndef GL_H
#define GL_H
/*
* Functions for a simple graphics library that draws
* pixels, text, rectangles, lines, and triangles. Builds
* on the fb module to configure and access the framebuffer.
* Attempting to use both fb and gl simultaneously is discouraged.
*
* Students implement this module in assignment 6.
*
* Author: Philip Levis <pal@cs.stanford.edu>
*/
#include "fb.h"
#include <stdint.h>
typedef enum {
GL_SINGLEBUFFER = FB_SINGLEBUFFER,
GL_DOUBLEBUFFER = FB_DOUBLEBUFFER }
gl_mode_t;
/*
* `gl_init` : Required initialization for graphics library
*
* Initialize the graphic library. This function will call `fb_init` in turn
* to initialize the framebuffer.
*
* @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)
*
* A subsequent call to gl_init after the first does a reinitialization.
*/
void gl_init(int width, int height, gl_mode_t mode);
/*
* `gl_get_width`
*
* Get the current width in pixels of the framebuffer.
*
* @return the width in pixels
*/
int gl_get_width(void);
/*
* `gl_get_height`
*
* Get the current height in pixels of the framebuffer.
*
* @return the height in pixels
*/
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 uint32_t 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(uint8_t r, uint8_t g, uint8_t 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(int x, 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(int x, 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(int x, 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(int x, 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
*/
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
*/
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(int x, int y, int w, 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(int x1, int y1, int x2, 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(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 Mango Pi GPIO.
*
* Students implement this module in assignment 2.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdbool.h>
#define GPIO_INVALID_REQUEST -1 // return value for invalid request
/*
* Type: `gpio_id_t`
*
* `gpio_id_t` is an enumerated type used to refer to a gpio pin.
* A C enumeration is effectively an (unsigned) int.
* See the enumeration below for symbolic names/constants for
* the valid ids on the Mango Pi.
*/
typedef enum _mango_ids gpio_id_t;
/*
* `gpio_init`
*
* Initialize the GPIO code module. For assignment 2, this does nothing.
* However, all peripheral modules require an init, so it is included
* for consistency's sake.
*/
void gpio_init(void);
/*
* `gpio_id_is_valid`
*
* Returns true if `pin` refers to a valid GPIO pin id, false otherwse.
* See enumeration `gpio_id_t` below for list of valid ids.
*/
bool gpio_id_is_valid(gpio_id_t pin);
/*
* `gpio_set_function`
*
* Set a GPIO function for GPIO with id `pin`. The configuration for
* pins other than `pin` should not be changed.
*
* @param pin the id of the GPIO pin
* @param function the GPIO function to set for the pin
*
* If `pin` or `function` is not valid, does nothing.
*/
void gpio_set_function(gpio_id_t pin, unsigned int function);
/*
* `gpio_get_function`
*
* Get the GPIO function for GPIO with id `pin`.
*
* @param pin the id of the GPIO pin
* @return the current GPIO function of the specified pin
*
* If `pin` is not valid, returns GPIO_INVALID_REQUEST.
*/
unsigned int gpio_get_function(gpio_id_t pin);
/*
* `gpio_set_input`, `gpio_set_output`
*
* Convenience functions for setting a pin to GPIO_FN_INPUT or
* GPIO_FN_OUTPUT. The implementation calls `gpio_set_function`.
*
* @param pin the id of the GPIO pin to set function
*/
void gpio_set_input(gpio_id_t pin);
void gpio_set_output(gpio_id_t pin);
/*
* `gpio_read`
*
* Read current value for GPIO with id `pin`.
* Returns 1 if pin is high, 0 if low.
*
* @param pin the id of the GPIO pin
* @return the value of the specified pin
*
* If `pin` is not valid, returns GPIO_INVALID_REQUEST.
*/
int gpio_read(gpio_id_t pin);
/*
* `gpio_write`
*
* Set value of GPIO with id `pin` to high (1) or low (0).
* This function assumes the pin is already in output mode.
* Values for pins other than `pin` should not be changed.
*
* @param pin the id of the GPIO pin
* @param val 1 to set pin high, 0 to set pin low
*
* If `pin` is not valid, does nothing.
*/
void gpio_write(gpio_id_t pin, int val);
/*
* Enumeration of ids for GPIO pins on the Mango Pi
*
* Each GPIO pin has a symbolic id in the enumeration below.
*
* The GPIO pins are organized into six groups: PB PC PD PE PF PG
* (These are called "ports" in the user manual)
* The pins within a group are indexed by number starting from 0. Each
* group has a differing number of pins. For example, the PB group has
* 13 pins indexed from PB0 to PB12. The PC group has 8 pins PC0 to PC7.
*
* Values are assigned to each pin id in such a way to use a single hex constant
* that mashes together the group and pin index as shown below
* constant 0xNnn N = which group, nn = pin index within group
*/
enum _mango_ids {
GPIO_PB0 = 0x000, // start of B group, enum vals assigned in sequence from here
GPIO_ID_FIRST = GPIO_PB0,
GPIO_PB1,
GPIO_PB2,
GPIO_PB3,
GPIO_PB4,
GPIO_PB5,
GPIO_PB6,
GPIO_PB7,
GPIO_PB8,
GPIO_PB9,
GPIO_PB10,
GPIO_PB11,
GPIO_PB12,
GPIO_PB_LAST_INDEX = GPIO_PB12 - GPIO_PB0,
GPIO_PC0 = 0x100, // start of C group
GPIO_PC1,
GPIO_PC2,
GPIO_PC3,
GPIO_PC4,
GPIO_PC5,
GPIO_PC6,
GPIO_PC7,
GPIO_PC_LAST_INDEX = GPIO_PC7 - GPIO_PC0,
GPIO_PD0 = 0x200, // start of D group
GPIO_PD1,
GPIO_PD2,
GPIO_PD3,
GPIO_PD4,
GPIO_PD5,
GPIO_PD6,
GPIO_PD7,
GPIO_PD8,
GPIO_PD9,
GPIO_PD10,
GPIO_PD11,
GPIO_PD12,
GPIO_PD13,
GPIO_PD14,
GPIO_PD15,
GPIO_PD16,
GPIO_PD17,
GPIO_PD18,
GPIO_PD19,
GPIO_PD20,
GPIO_PD21,
GPIO_PD22,
GPIO_PD_LAST_INDEX = GPIO_PD22 - GPIO_PD0,
GPIO_PE0 = 0x300, // start of E group
GPIO_PE1,
GPIO_PE2,
GPIO_PE3,
GPIO_PE4,
GPIO_PE5,
GPIO_PE6,
GPIO_PE7,
GPIO_PE8,
GPIO_PE9,
GPIO_PE10,
GPIO_PE11,
GPIO_PE12,
GPIO_PE13,
GPIO_PE14,
GPIO_PE15,
GPIO_PE16,
GPIO_PE17,
GPIO_PE_LAST_INDEX = GPIO_PE17 - GPIO_PE0,
GPIO_PF0 = 0x400, // start of F group
GPIO_PF1,
GPIO_PF2,
GPIO_PF3,
GPIO_PF4,
GPIO_PF5,
GPIO_PF6,
GPIO_PF_LAST_INDEX = GPIO_PF6 - GPIO_PF0,
GPIO_PG0 = 0x500, // start of G group
GPIO_PG1,
GPIO_PG2,
GPIO_PG3,
GPIO_PG4,
GPIO_PG5,
GPIO_PG6,
GPIO_PG7,
GPIO_PG8,
GPIO_PG9,
GPIO_PG10,
GPIO_PG11,
GPIO_PG12,
GPIO_PG13,
GPIO_PG14,
GPIO_PG15,
GPIO_PG16,
GPIO_PG17,
GPIO_PG18,
GPIO_PG_LAST_INDEX = GPIO_PG18 - GPIO_PG0,
GPIO_ID_LAST = GPIO_PG18,
};
#define GPIO_UART_TX GPIO_PB8
#define GPIO_UART_RX GPIO_PB9
/*
* 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_FN_INPUT configures the pin to be used as an input.
*/
enum {
GPIO_FN_INPUT = 0,
GPIO_FN_OUTPUT = 1,
GPIO_FN_ALT2 = 2,
GPIO_FN_ALT3 = 3,
GPIO_FN_ALT4 = 4,
GPIO_FN_ALT5 = 5,
GPIO_FN_ALT6 = 6,
GPIO_FN_ALT7 = 7,
GPIO_FN_ALT8 = 8,
// 9 -13 are reserved
GPIO_FN_INTERRUPT = 14,
GPIO_FN_DISABLED = 15,
};
#endif
#ifndef GPIO_EXTRA_H
#define GPIO_EXTRA_H
/*
* Functions for controlling extra GPIO features (pull state and name to id conversion)
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include "gpio.h"
/*
* 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.
*/
/*
* `gpio_set_pullup`
*
* Set pull state of GPIO with id `pin` to pull-up.
*
* @param pin the id of the GPIO pin
*
* If `pin` is not valid, does nothing.
*/
void gpio_set_pullup(gpio_id_t pin);
/*
*
* `gpio_set_pulldown`
*
* Set pull state of GPIO with id `pin` to pull-down.
*
* @param pin the id of the GPIO pin
*
* If `pin` is not valid, does nothing.
*/
void gpio_set_pulldown(gpio_id_t pin);
/*
* `gpio_set_pullnone`
*
* Disables any pull state of GPIO with id `pin` (value will float).
*
* @param pin the id of the GPIO pin
*
* If `pin` is not valid, does nothing.
*/
void gpio_set_pullnone(gpio_id_t pin);
/*
* `gpio_get_name_for_id`
*
* Translate a pin id into name string suitable for display:
* e.g. GPIO_PB4 -> "PB4"
*
* @param pin the id of the GPIO pin
* @return name string
*
* If `pin` is not valid, returns GPIO_INVALID_REQUEST.
*/
const char *gpio_get_name_for_id(gpio_id_t pin);
/*
* `gpio_get_id_for_name`
*
* Translate a string name into pin id:
* e.g. "PB4" -> GPIO_PB4
*
* @param name name string
* @return the id of the GPIO pin
*
* If `name` is not valid, returns GPIO_INVALID_REQUEST.
*/
gpio_id_t gpio_get_id_for_name(const char *name);
#endif
#ifndef GPIO_INTERRUPT_H
#define GPIO_INTERRUPT_H
/*
* Module to configure GPIO interrupt processing for Mango Pi.
* Because all of the gpios within one group share the same interrupt
* source, an additional level of indirection is needed to dispatch
* those interrupts to individual handlers per specific gpio.
* This module manages that additional layer of dispatch.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdbool.h>
#include "gpio.h"
#include "interrupts.h"
/*
* `gpio_interrupt_init`: Required initialization for module
*
* Initialize the GPIO interrupt module. The init function must be
* called before any calls to other functions in this module.
* The init function coordinates with the top-level interrupts module
* to register a handler to receive events on all GPIO interrupt sources
* (i.e. for all groups). The handler will re-dispatch each interrupt
* to the per-gpio handler registered with this module.
*
* It is safe to call init more than once for this module. A re-init
* retains all handlers that were previously registered.
*
* It is an error to attempt to initialize this module without first
* initialized the top-level interrupts (i.e. required to call `interrupts_init`).
*/
void gpio_interrupt_init(void);
/*
* `gpio_interrupt_register_handler`
*
* Register a handler function to gpio with id `pin`. Each GPIO
* can have one handler.
*
* @param pin the id of the GPIO pin
* @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
*
* Raises an assert if `pin` does not refer to valid gpio id. `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`.
*
* It is an error to register handler without first
* initializing the module (i.e. required to call `gpio_interrupt_init`).
*/
void gpio_interrupt_register_handler(gpio_id_t pin, handlerfn_t fn, void *aux_data);
/*
* Enumeration for GPIO interrupt events
*
* The enumerated values below establish symbolic names for the different
* GPIO events that can trigger an interrupt.
*/
typedef enum {
GPIO_INTERRUPT_POSITIVE_EDGE = 0,
GPIO_INTERRUPT_NEGATIVE_EDGE = 1,
GPIO_INTERRUPT_HIGH_LEVEL = 2,
GPIO_INTERRUPT_LOW_LEVEL = 3,
GPIO_INTERRUPT_DOUBLE_EDGE = 4,
} gpio_event_t;
/*
* `gpio_interrupt_config`
*
* Config interrupt to trigger on `event` for GPIO with id `pin`.
* The boolean parameter `debounce` controls whether to apply debounce
* circuit to filter/coalesce sequence of rapid-fire events. If true, debounce
* filters to ~1 event/ms. If events expected to be more rapid (e.g. PS/2),
* set debounce to false to not miss events.
*
* @param pin the id of the GPIO pin
* @param event which event, see gpio_event_t enumeration
* @param debounce whether to apply debounce filter
*
* Raises an assert if `pin` or `event` is not valid.
*/
void gpio_interrupt_config(gpio_id_t pin, gpio_event_t event, bool debounce);
/*
* `gpio_interrupt_enable`
*
* Enable interrupts for GPIO with id `pin`.
*
* @param pin the id of the GPIO pin
*
* Raises an assert if `pin` is not valid.
*/
void gpio_interrupt_enable(gpio_id_t pin);
/*
* `gpio_interrupt_disable`
*
* Disable interrupts for GPIO with id `pin`.
*
* @param pin the id of the GPIO pin
*
* Raises an assert if `pin` is not valid.
*/
void gpio_interrupt_disable(gpio_id_t pin);
/*
* `gpio_interrupt_clear`
*
* Clears any pending interrupt for GPIO with id `pin`.
*
* @param pin the id of the GPIO pin
*
* Raises an assert if `pin` is not valid.
*/
void gpio_interrupt_clear(gpio_id_t pin);
#endif
#ifndef HDMI_H
#define HDMI_H
/*
* Functions for controlling display hardware.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
/*
* `hdmi_resolution_id_t` : enum of available HDMI resolutions
*
* These are the available resolutions that the HDMI display
* hardware can be configured for.
*/
typedef enum {
HDMI_1080P, /* 1920 x 1080 */
HDMI_HD, /* 1280 x 720 */
HDMI_SVGA, /* 800 x 600 */
HDMI_INVALID
} hdmi_resolution_id_t;
/*
* `hdmi_init` : Required initializion for HDMI hardware driver
*
* Initializes the HDMI hardware driver and configures output screen
* for the specified resolution.
*
* @param res requested resolution id chosen from enum above
*/
void hdmi_init(hdmi_resolution_id_t res);
/*
* `hdmi_best_match` : Return the resolution id that is the best
* match for the desired width x height.
*
* Returns the resolution id of best match or HDMI_INVALID if
* the size cannot be accommodated.
*
* @return resolution id chosen from enum above
*/
hdmi_resolution_id_t hdmi_best_match(int width, int height);
/*
* `hdmi_get_screen_width`
*
* Get the width of screen in pixels.
*
* @return the width in pixels
*/
int hdmi_get_screen_width(void);
/*
* `hdmi_get_screen_height`
*
* Get the height of screen in pixels.
*
* @return the height in pixels
*/
int hdmi_get_screen_height(void);
#endif
#ifndef HSTIMER_H
#define HSTIMER_H
/*
* Functions for Mango Pi high-speed timer.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdbool.h>
/*
* Type: `hstimer_id_t`
*
* The hstimer peripheral has two available timers: HSTIMER0 and HSTIMER1.
*/
typedef enum { HSTIMER0 = 0, HSTIMER1 = 1 } hstimer_id_t;
/*
* `hstimer_init` : required module initialization
*
* Initialize the hstimer peripheral `timer` for use as a "countdown" timer.
* The number of microsecs to count is specified as the `us_interval`
* argument. A request to init (or re-init) hstimer will configure
* the countdown interval and place the timer into a disabled state.
* Use `hstimer_enable` to begin counting down when ready.
*
* When an hstimer is enabled, its counter is decremented once per microsec.
* When counter reaches zero, it will generate an interrupt. Clearing the
* interrupt will restart the timer, causing it to countdown again from the
* initial interval value. The cycle repeats until timer is disabled.
*
* The `timer` argument specifies which hstimer id to operate on. A hstimer id
* that is not valid will be ignored.
*
* @param timer which hstimer to config (either HSTIMER0 or HSTIMER1)
* @param us_interval count of usecs per timer interval
*/
void hstimer_init(hstimer_id_t timer, long us_interval);
/*
* `hstimer_enable`
*
* Enable `timer`. Countdown will start/resume.
*
* @param timer which hstimer to enable (either HSTIMER0 or HSTIMER1)
*/
void hstimer_enable(hstimer_id_t timer);
/*
* `hstimer_disable`
*
* Disable `timer`. Suspends counting down.
*
* @param timer which hstimer to disable (either HSTIMER0 or HSTIMER1)
*/
void hstimer_disable(hstimer_id_t timer);
/*
* `hstimer_interrupt_clear`
*
* Clear any pending hstimer interrupt for `timer`. Countdown will restart
* from the initial interval.
*
* @param timer which hstimer to enable (either HSTIMER0 or HSTIMER1)
*/
void hstimer_interrupt_clear(hstimer_id_t timer);
#endif
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
/*
* Module to configure interrupts for Mango Pi.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdint.h>
typedef enum _interrupt_sources interrupt_source_t;
/*
* `interrupts_init`: Required initialization for interrupts
*
* Initialize interrupts module and configure to a clean state.
* After init, the state of the interrupt system will be:
*
* - top-level trap handler installed and active
* - 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`
*
* Turn on interrupts system-wide. An interrupt generated on an
* interrupt source that is enabled will call the registered handler.
*/
void interrupts_global_enable(void);
/*
* `interrupts_global_disable`
*
* Turn off interrupts system-wide. No interrupts will be generated.
* Does not remove registered handlers or disable interrupt sources,
* only temporarily suspends interrupt generation. To resume
* generating interrupts, call `interrupts_global_enable`.
*/
void interrupts_global_disable(void);
/*
* `interrupts_enable_source`
*
* Enable a particular interrupt source. The source itself must
* be configured to generate interrupts (and global interrupts must be
* enabled) for a registered handler to be called.
*
* @param source which interrupt source (see enumeration values below)
*
* An error is raised if `source` is not valid.
*/
void interrupts_enable_source(interrupt_source_t source);
/*
* `interrupts_disable_source`
*
* Disable a particular interrupt source. Interrupts for this source
* will not trigger a handler and will remain pending (until cleared).
*
* @param source which interrupt source (see enumeration values below)
*
* An error is raised if `source` is not valid.
*/
void interrupts_disable_source(interrupt_source_t source);
/*
* `handlerfn_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. The one argument to the handler is the client's
* auxiliary data pointer (can be NULL if not used).
*/
typedef void (*handlerfn_t)(void *);
/*
* `interrupts_register_handler`
*
* Register the handler function for a given interrupt source. Each interrupt
* source can have one handler: further dispatch should be managed by
* the handler itself. Registering a handler does not enable the source:
* this must be done separately through `interrupts_enable_source`.
* These are separate because otherwise there can be impossible-to-solve
* technical challenges such as
* - receiving an interrupt before `interrupts_register_handler` completes,
* - handling an interrupt that was pending from a different use of the source,
* - changing the handler as one part of a larger atomic action.
*
* @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 error is raised if `source` is not valid. `aux_data` can be NULL if
* handler function has no need for auxiliary data. If `fn` is NULL, this
* removes any handler previously registered for `source`.
*/
void interrupts_register_handler(interrupt_source_t source, handlerfn_t fn, void *aux_data);
/*
* 'interrupt_source_t` enumeration
*
* Below are interrupt sources for which this module can enable, disable,
* and register a handler. Interrupt source numbers are assigned in
* table 3-9 p.204-210 of the D1-H User Manual.
*/
enum _interrupt_sources {
INTERRUPT_SOURCE_UART0 = 18,
INTERRUPT_SOURCE_UART1 = 19,
INTERRUPT_SOURCE_UART2 = 20,
INTERRUPT_SOURCE_UART3 = 21,
INTERRUPT_SOURCE_UART4 = 22,
INTERRUPT_SOURCE_UART5 = 23,
INTERRUPT_SOURCE_TWI0 = 25,
INTERRUPT_SOURCE_TWI1 = 26,
INTERRUPT_SOURCE_TWI2 = 27,
INTERRUPT_SOURCE_TWI3 = 28,
INTERRUPT_SOURCE_SPI0 = 31,
INTERRUPT_SOURCE_SPI1 = 32,
INTERRUPT_SOURCE_HSTIMER0 = 71,
INTERRUPT_SOURCE_HSTIMER1 = 72,
INTERRUPT_SOURCE_GPIOB = 85,
INTERRUPT_SOURCE_GPIOC = 87,
INTERRUPT_SOURCE_GPIOD = 89,
INTERRUPT_SOURCE_GPIOE = 91,
INTERRUPT_SOURCE_GPIOF = 93,
INTERRUPT_SOURCE_GPIOG = 95,
};
#endif
#ifndef KEYBOARD_H
#define KEYBOARD_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>
*/
#include "gpio.h"
#include "ps2_keys.h"
#include <stdint.h>
// gpio pins for connecting keyboard clock/data lines
#define KEYBOARD_CLOCK GPIO_PG12
#define KEYBOARD_DATA GPIO_PB7
/*
* Type: `key_action_t`
*
* This struct represents a single action on a PS2 key.
* The action is either a press or release of a specified key.
* The key is identified by its scancode.
*/
typedef struct {
enum { KEY_PRESS, KEY_RELEASE } what;
uint8_t keycode;
} key_action_t;
/*
* Type: `keyboard_modifiers_t`
*
* This enum type represents the state of the modifier keys.
* A single bit flag is used for each modifier. The bits
* taken together as a bitset indicate the state of all modifier keys.
* A bit can be set/clear/read within the bitset by using the individual
* bit flag as a mask.
*/
typedef enum {
KEYBOARD_MOD_SHIFT = 1 << 0,
KEYBOARD_MOD_ALT = 1 << 1,
KEYBOARD_MOD_CTRL = 1 << 2,
KEYBOARD_MOD_CAPS_LOCK = 1 << 3,
} keyboard_modifiers_t;
/*
* Type: `key_event_t`
*
* This struct represents a single key event, which packages
* the raw key action with additional data about keyboard state.
*/
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;
/*
* `keyboard_init`: Required initialization for keyboard.
*
* The keyboard must first be initialized before any key events can be read.
* The two arguments are the ids of the GPIOs connected to the PS2 clock and data lines.
*
* @param clock the gpio connected to the clock line of keyboard
* @param data the gpio connected to the data line of keyboard
*/
void keyboard_init(gpio_id_t clock, gpio_id_t data);
/*
* `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 modifiers in effect.
*
* 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_special_chars`
* 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
*/
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 non-modifier key.
* The returned struct includes the ps2 key that was pressed or
* released and the keyboard modifiers in effect.
*
* `keyboard_read_event` does not return until it observes a key
* event for a non-modifier key. Pressing or releasing a modifier
* key changes the state of the modifiers for other key events
* but does not produce its own key event. For example, if the user
* presses Shift, press 'a', release Shift, and release 'a', this
* comprises four key actions (four calls to `keyboard_read_sequence`)
* but only two key events (press 'a' and release `a`). The key
* event returned for press 'a' has the shift modifier on, the key event
* returned for release 'a' has shift modifier off.
*
* 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 identifies the scancode of 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
*/
uint8_t keyboard_read_scancode(void);
/*
* `keyboard_use_interrupts` : reference only
*
* 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 MALLOC_H
#define MALLOC_H
/*
* Functions for dynamic allocation.
*
* Students implement this module in assignment 4.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stddef.h> // for size_t
/*
* `malloc`
*
* 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);
/*
* `free`
*
* 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);
/*
* `sbrk`
*
* 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(size_t nbytes);
/*
* `malloc_report`
*
* Prints a summary of malloc statistics at end of program execution.
* The report includes the number of calls to `malloc` and `free`
* and the aggregate total number of bytes requested, along with a
* list of any memory leaks (allocations not freed at time of program exit).
*
* You can leave this function unimplemented if not doing the extension.
*/
void malloc_report(void);
#endif
#ifndef MANGO_H
#define MANGO_H
/*
* Utility functions for Mango Pi.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include "gpio.h"
/*
* The blue act led on-board the Mango Pi is controlled via GPIO PD18.
*/
#define MANGO_ACTLED GPIO_PD18
/*
* Enumeration for LED state.
*/
enum led_state_t {
LED_OFF = 0,
LED_ON,
LED_TOGGLE
};
/*
* `mango_actled`
*
* Change state of the act led.
*
* @param state state change for led
*
* If state is not valid, function does nothing.
*/
void mango_actled(enum led_state_t state);
/*
* `mango_reboot`
*
* Halts current program execution and reboots the Pi.
*/
void mango_reboot(void) __attribute__ ((noreturn));
/*
* `mango_abort`
*
* Goes into an infinite loop that fast flashes
* the act led. This function does not return.
*/
void mango_abort(void) __attribute__ ((noreturn));
#endif
#ifndef MOUSE_H
#define MOUSE_H
/*
* Module to read mouse events from a PS/2 mouse.
*
* Students implement this module as an extension to assignment 7.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include "gpio.h"
#include <stdbool.h>
// gpio pins for connecting mouse clock/data lines
#define MOUSE_CLOCK GPIO_PD21
#define MOUSE_DATA GPIO_PD22
/*
* Each event corresponds to a particular user action with
* mouse (press/release button, move/drag). This enum
* identifes the four types of mouse actions.
*/
typedef enum {
MOUSE_BUTTON_PRESS = 0,
MOUSE_BUTTON_RELEASE = 1,
MOUSE_MOVED = 2,
MOUSE_DRAGGED = 3,
} mouse_action_t;
/*
* This struct captures the information associated with a mouse event.
* For information on the value and purpose of the fields, refer to
* the documentation for function `mouse_read_event` below.
*/
typedef struct {
mouse_action_t action;
int dx, dy;
bool x_overflow, y_overflow;
bool left, middle, right;
} mouse_event_t;
/*
* `mouse_init`: Required initialization for mouse.
*
* The mouse must first be initialized before any mouse events can be read.
* The two arguments are the ids of the GPIOs connected to the PS2 clock and data lines.
* `mouse_init` resets the mouse and enables data reporting mode.
*
* @param clock the gpio connected to the clock line of mouse
* @param data the gpio connected to the data line of mouse
*/
void mouse_init(gpio_id_t clock, gpio_id_t data);
/*
* `mouse_read_event`
*
* The function reads (blocking) the next event from the mouse.
* Returns a `mouse_event_t` struct that represents the mouse state/action.
* The dx, dy fields are delta values, i.e. relative change in x and y
* when mouse is moved/dragged. A delta value is within the range -255 to +255.
* The x_overflow/y_overflow fields indicate an overflow occurred in
* computing the delta value. If actual change dx or dy exceeds
* representable range (> 255), the overflow field is true, false otherwise.
* The left/middle/right fields give the state of the mouse buttons.
* The 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 PRINTF_H
#define PRINTF_H
/*
* Functions for printing formatted strings.
*
* Students implement this module in assignment 3
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdarg.h>
#include <stddef.h>
/*
* The functions vnsprintf, snprintf, and printf construct a
* formatted output from an input format string and arguments.
* All three functions support same conversion options in format
* string, but differ slightly in how each function is called
* or what it does with the output string, e.g., whether it is
* sent to the UART peripheral (printf) or written into the
* destination buffer (snprintf, vsnprintf).
*
* The supported format conversion codes are
* %c single character
* %s string
* %d signed decimal integer (%ld long decimal)
* %x unsigned hexadecimal integer (%lx long hex)
* %p pointer
* %% used to output a single percent character
*
* Each formatting code also allows an optional field width, such
* as %25s or %8lx. The field width enforces a minimum number of
* characters for this conversion. The output will be left-padded
* with spaces up to the field width. If the output of the conversion
* is hexadecimal, character '0' is used as pad instead of space char.
*
* This version of printf does not support the many fancy features of
* the standard library printf (no justification, no precision, no octal,
* no floating point, etc.). Format conversions other than the supported
* list are considered invalid. The behavior of printf for an invalid
* format 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>
*/
#include <stdbool.h>
#include <stdint.h>
#include "gpio.h"
/*
* Type: `ps2_device_t`
*
* This typedef gives a nickname to the struct that will be used to represent a
* single PS2 device. The internal details of the struct (e.g. type and names
* of struct fields) will be given in the file ps2.c; those details are private
* to the implementation and not shared in the public interface.
* Clients of the ps2 module are not privy to the details of ps2_device_t,
* nor should they be. A client simply holds on to the pointer returned by
* `ps2_new` and sends that pointer as an argument to `ps2_read`.
*/
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 different from the module_init exposed by
* other library modules. The new operation can be called more than once
* in order to create multiple PS2 devices, such as one for a keyboard and
* another for a mouse. When calling ps2_new, the client saves the
* returned pointer to use as argument in when calling ps2_read.
* This is how the client indicates which PS2 device is to be read.
*
* @param clock the id of gpio connected to the clock line of the PS2 device
* @param data the id of 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(gpio_id_t clock, gpio_id_t data);
/*
* `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
*/
uint8_t 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 for assign7.
*
* @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, uint8_t 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.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
* Author: Philip Levis <pal@cs.stanford.edu>
*/
#define PS2_CODE_RELEASE 0xF0 // Scancodes used in the PS/2 protocol
#define PS2_CODE_EXTENDED 0xE0
/*
* Type: `ps2_key_t`
*
* A ps2_key_t struct has two fields, `ch` and `other_ch`.
* These fields correspond to the unmodified and modified character produced by
* a given PS2 key. For example, the A key produces `{ 'a', 'A' }` and the
* Four key produces `{ '4', '$' }`. Keys such as Tab that are unchanged
* by the modifier have same `ch` and `other_ch`, e.g. `{'\t', '\t'}`.
* A non-ASCII key produces a char with special value >= 0x90 as
* assigned in the enumeration of special characters below.
*/
typedef struct {
char ch;
char other_ch;
} ps2_key_t;
/*
* Global constant array: `ps2_keys`
*
* 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 characters produced by that key.
* As an example, pressing the A key on a PS2 keyboard generates scancode `0x1c`.
* Accessing the array element at that index `ps2_keys[0x1c]` retrieves the ps2_key_t
* `{'a', 'A'}`. These are the unmodified and modified characters produced by the A key.
*/
extern ps2_key_t const ps2_keys[];
/*
* Enumeration of special chars
*
* Regular chars have ASCII characters values that are all <= 0x7F,
* we assign special character codes >= 0x90 to be produced by
* the non-ASCII keys.
*/
enum {
PS2_KEY_NONE = 0,
PS2_KEY_SHIFT = 0x90,
PS2_KEY_ALT, // enum 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 RAND_H
#define RAND_H
/*
* Module to generate random numbers.
*
* Author: Pat Hanrahan <hanrahan@cs.stanford.edu>
*/
/*
* `rand`
*
* Generate a 32-bit random number. Uses a psuedo-random
* generator with a fixed seed by default.
*
* @return pseudo-random value in the range 0 to UINT_MAX
*/
unsigned int rand(void);
/*
* `srand`
*
* Use argument as seed for sequence of pseudo-random numbers to be
* returned by rand(). Sequence is repeatable by calling srand()
* with the same seed value.
*/
void srand(unsigned int seed);
#endif
#ifndef RINGBUFFER_H
#define RINGBUFFER_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>
*/
#include <stdbool.h>
/*
* Type: `rb_t`
*
* This struct holds the information for a ring buffer.
*/
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 library 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
/*
* Interface to a simple shell module.
*
* Students implement this module in assignment 5.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stddef.h>
/*
* 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 char. `keyboard_read_next` is an example
* of a possible shell input function.
*/
typedef 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`.
* The basic shell discards any non-ASCII characters (i.e. ch > 0x7f).
* If doing the extension, some of these non-ASCII codes are implemented
* by the shell to access features for line editing and command history.
*
* When the user types backspace (\b):
* If there are any characters currently in the buffer, deletes the last one.
* Otherwise, calls `shell_bell`.
* Backspace through a tab character will not be tested (printing a tab
* outputs a variable number of spaces, handling of backspace does does
* not have to account for this)
*
* @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.
* - If line contains no tokens (string is empty or all whitespace),
* no command is executed and -1 is returned.
* 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 SHELL_COMMANDS_H
#define SHELL_COMMANDS_H
/*
* Interface for the shell commands.
*
* Students implement these functions in assignment 5.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
/*
* Type: `command_fn_t`
*
* 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[]);
/*
* Type: `command_t`
*
* This typedef defines the type for each entry in the command table.
* A command_t stores the info for one command, including the one-word name,
* usage, help description, and function pointer to execute the command.
*/
typedef struct {
const char *name;
const char *usage;
const char *description;
command_fn_t fn;
} command_t;
/*
* `cmd_echo`
*
* Usage: echo [args]
* Description: print arguments
*
* Example:
* Pi> echo Leland Stanford Junior University
* Leland Stanford Junior University
*
* Print arguments. Returns 0 (success).
*/
int cmd_echo(int argc, const char *argv[]);
/*
* `cmd_help`
*
* Usage: help [cmd]
* Description: print command usage and description
*
* If no argument, print a list of all available commands with
* usage and description. If an argument is given, print
* usage and description for named command. If no such
* named command, prints an error message.
*
* Examples:
* Pi> help
* help [cmd] print command usage and description
* echo [args] print arguments
* reboot reboot the Mango Pi
* peek [addr] print contents of memory at address
* poke [addr] [val] store value into memory at address
* Pi> help reboot
* reboot reboot the Mango Pi
* Pi> help please
* error: no such command 'please'
*
* Ignores any arguments after the first. Returns 0 on success,
* nonzero on error (command not found).
*/
int cmd_help(int argc, const char *argv[]);
/*
* `cmd_clear`
*
* Usage: clear
* Description: clear screen (if your terminal supports it)
*
* Example:
* Pi> clear
*
* Ignores all arguments. Sends a formfeed \f character to your terminal.
* A terminal program such as minicom that supports formfeed will
* respond by clearing the screen and putting cursor in the upper row.
* If your terminal does not support formfeed, cmd_clear will
* have no effect. The function returns 0 in all cases.
*/
int cmd_clear(int argc, const char *argv[]);
/*
* `cmd_reboot`
*
* Usage: reboot
* Description: reboot the Mango Pi
*
* Example:
* Pi> reboot
* Rebooting...
*
* Ignores all arguments. Prints informative message and reboots Pi.
* This function does not return; the program exits on reboot.
*/
int cmd_reboot(int argc, const char *argv[]);
/*
* `cmd_peek`
*
* Usage: peek [addr]
* Description: print contents of memory at address
*
* Retrieve 4-byte value at memory address and print it as an
* unsigned hex value, e.g. %08x.
* If the address argument is prefixed with 0x, it is interpreted as hex,
* otherwise interpreted as decimal. Address must be 4-byte aligned.
* If address is missing or invalid, prints an error message.
*
* Examples:
* Pi> peek 0x40000000
* 0x40000000: 30047073
* Pi> peek
* error: peek expects 1 argument [addr]
* Pi> peek fred
* error: peek cannot convert 'fred'
* Pi> peek 13
* error: peek address must be 4-byte aligned
*
* Ignores any arguments after the first. Returns 0 on success, nonzero on error.
*/
int cmd_peek(int argc, const char *argv[]);
/*
* `cmd_poke`
*
* Usage: poke [addr] [val]
* Description: store value into memory at address
*
* Writes 4-byte value to memory at address.
* If address or value is prefixed with 0x, it is interpreted as hex,
* otherwise interpreted as decimal. Address must be 4-byte aligned.
* If address or value is missing or invalid, prints an error message.
*
* Examples:
* Pi> poke 0x40000000 3
* Pi> peek 0x40000000
* 0x40000000: 00000003
* Pi> poke 0x40000000
* error: poke expects 2 arguments [addr] and [val]
* 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, nonzero 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>
*/
#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 long
* 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 representable as `unsigned long`.
*
* @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 long 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 length 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 length of dst if there were space to append all of src
*/
size_t strlcat(char *dst, const char *src, size_t dstsize);
#endif
#ifndef SYMTAB_H
#define SYMTAB_H
/*
* Functions to operate on symbol table (if available):
* - label for address
* - find symbol for name
* - find symbol for address
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
/*
* `symtab_label_for_addr`
*
* Finds function symbol for instruction at address and writes label
* to `buf`, truncated to `bufsize`. If symbol names are available,
* label is of form "<fn_name+offset>". Without symbol names,
* label is "<.text+offset>" for an address within the text
* section and "<>" otherwise.
*
* @param buf destination buffer where to write label
* @param bufsize size of destination buffer (label truncated to fit if needed)
* @param addr addr to provide label for
*/
void symtab_label_for_addr(char *buf, size_t bufsize, uintptr_t addr);
typedef struct {
const char *name; // symbol name
uintptr_t addr; // symbol start address
size_t size; // symbol size in bytes
} symbol_t;
/*
* `symtab_symbol_for_name`
*
* Search for a function symbol with the specified `name`.
* If symbol with name is found, the symbol info is written to
* the parameter `*p_symbol` and function returns true.
* If no match found, function returns false and *p_symbol is
* unchanged.
*
* @param name name of function to search for
* @param p_symbol pointer to where to store symbol data
* @return true if found, false otherwise
*/
bool symtab_symbol_for_name(const char *name, symbol_t *p_symbol);
/*
* `symtab_symbol_for_addr`
*
* Search for a function symbol that contains the specified `addr`.
* If symbol containing addr is found, the symbol info is written to
* the parameter `*p_symbol` and function returns true.
* If no match found, function returns false and *p_symbol is
* unchanged.
*
* @param addr address to search for
* @param p_symbol pointer to where to store symbol data
* @return true if found, false otherwise
*/
bool symtab_symbol_for_addr(uintptr_t addr, symbol_t *p_symbol);
#endif
#ifndef TIMER_H
#define TIMER_H
/*
* Hardware abstraction for a timer.
*
* Students implement this module in assignment 2.
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#define TICKS_PER_USEC 24 // 24 ticks counted per one microsecond
/*
* `timer_init`
*
* Initialize the timer. For assignment 2, this does nothing.
* However, all 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 initialized
* to zero at boot and increments at constant rate 24Mhz until the
* processor resets.
*
* @return system tick count
*/
unsigned long timer_get_ticks(void);
/*
* `timer_delay_us`
*
* Delay the program for `usec` microseconds in a busy loop.
*
* @param usec the number of microseconds to delay
*/
void timer_delay_us(int usec);
/*
* `timer_delay_ms`
*
* Delay for `msec` milliseconds.
*
* @param msec the number of milliseconds to delay
*/
void timer_delay_ms(int msec);
/*
* `timer_delay`
*
* Delay for `sec` seconds.
*
* @param sec the number of seconds to delay
*/
void timer_delay(int sec);
#endif
#ifndef UART_H
#define UART_H
/*
* Hardware abstraction for a serial port (UART).
*
* Author: Julie Zelenski <zelenski@cs.stanford.edu>
*/
#include <stdbool.h>
#include "gpio.h"
#include "interrupts.h"
// gpio pins for connecting uart TX/RX lines
#define UART_TX_GPIO GPIO_PB8
#define UART_RX_GPIO GPIO_PB9
/*
* `uart_init`: Required initialization for module
*
* Initialize the UART 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 PB8 (transmit)
* and PB9 (receive). Once the uart is initialized and in use,
* your code should not further access 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(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);
/*
* `uart_use_interrupts`
*
* @param handler the handler function to call
* @param client_data to write to the serial port
*/
void uart_use_interrupts(handlerfn_t handler, void *client_data);
/*
* `uart_start_error`,`uart_end_error`
*
* Output ANSI color code for red+bold on start error, restore to
* normal on end error. Used by assert/error to highlight error
* messages.
*/
void uart_start_error(void);
void uart_end_error(void);
#endif