CS107e libpi header files
#ifndef ASSERT_H
#define ASSERT_H
#include "pi.h"
#include "uart.h"
#define STRINGIFY_IMPL(x) #x
#define AS_STRING(x) STRINGIFY_IMPL(x)
#define assert(EXPR) \
do { \
if (!(EXPR)) { \
uart_putstring("File " __FILE__ ", line " AS_STRING(__LINE__) ", function "); \
uart_putstring(__func__); \
uart_putstring("() : Assertion '" #EXPR "' failed.\n"); \
uart_putchar(TERMINATE); \
uart_putchar(EOT); \
pi_abort(); \
} \
} while (0);
#endif
// latest version of rpi-run.py (v2.3) now recognizes/reports TERMINATE control code
// older version only recognizes EOT
// output both so EOT acts as backstop if using older rpi-run.py
// (could eventually remove when everyone up to date)
#ifndef BACKTRACE_H
#define BACKTRACE_H
#include <stdint.h>
/*
* Functions for harvesting a debugging backtrace from the stack.
*
* Students implement this module in assignment 4.
*
* Author: Julie Zelenski <[email protected]>
* Mon Feb 5 20:02:27 PST 2018
*/
/* Type: frame_t
* -------------
* This struct stores the information for a function who has a frame on
* the current stack.
*
* The `name` field is the name of the function as found by `name_of`.
*
* The `resume_addr` field is taken from saved lr in the callee. The saved lr
* (sometimes referred to as "return address") is the address of the
* instruction in the caller's sequence of instructions where control will
* resume after the callee returns. The `uintptr_t` type is an unsigned integer
* of the appropriate size to store an address. This type is used to hold
* an address that you intend to treat numerically.
*
* The `resume_offset` is the number of bytes from the start of the function to
* the `resume_addr`. This offset represents how far control has advanced into
* the caller function before it invoked the callee.
*/
typedef struct {
const char *name;
uintptr_t resume_addr;
int resume_offset;
} frame_t;
/*
* `backtrace`
*
* Gathers a backtrace for the calling program and writes the
* call stack information into the array pointed to by `f`.
*
* A backtrace is the sequence of currently active function calls. Each element
* in the array `f` is of type `frame_t` (struct described above). Each struct
* represents a caller who has a frame on the stack.
*
* The `max_frames` argument specifies the maximum number of frames that can be
* stored in the array f. If the backtrace extends more than `max_frames`,
* only the `max_frames` most recent calls are stored into the array.
*
* The return value of the function is the count of frames written to `f`.
*
* @param f array in which to write stack frames
* @param max_frames maximum number of frames that can be stored in array
* @return count of frames written to array
*/
int backtrace(frame_t f[], int max_frames);
/*
* `print_frames`
*
* Given an array of frames that has previously been filled in by a call to
* backtrace(), `print_frames` prints the backtrace information, one line per
* frame, using this format:
*
* #0 0x85f8 at malloc+132
* #1 0x8868 at strndup+28
* #2 0x8784 at main+24
*
* @param f array of stack frames
* @param n number of frames in array
*/
void print_frames(frame_t f[], int n);
/*
* `print_backtrace`
*
* Convenience function that calls `backtrace` and `print_frames` to display
* stack frames of currently executing program.
*/
void print_backtrace(void);
/*
* `name_of`
*
* The argument to `name_of` is the numeric address in memory of the first
* instruction of a function and `name_of` returns the name of that
* function.
*
* When compiling with the `-mpoke-function-name` flag, each function's
* name is written into the text section alongside its instructions.
* `name_of` finds a function's name by looking in the appropriate
* location relative to the function's start address. The `uintptr_t` type
* is an unsigned integer of the appropriate size to store an address.
* This type is used to hold an address that you intend to treat numerically.
*
* If no name is available for the given address, `name_of` returns
* the constant string "???"
*
* @param fn_start_addr numeric address of instruction in memory
* @return pointer to string of function's name or
* constant string "???" if name not available
*/
const char *name_of(uintptr_t fn_start_addr);
#endif
#ifndef CONSOLE_H
#define CONSOLE_H
/*
* Interface to a text console displayed on the screen.
*
* Students implement this module in assignment 6.
*
* Author: Pat Hanrahan <[email protected]>
* Author: Philip Levis <[email protected]>
* Date: 3/24/16
*/
#include "gl.h"
/*
* `console_init`: required initialization for console
*
* Initialize the console. The console text begins empty and
* the cursor is in the home position (upper left corner).
*
* @param nrows the requested number of rows in characters
* @param ncols the requested number of columns in characters
* @param foreground foreground color used for text
* @param background background color
*/
void console_init(unsigned int nrows, unsigned int ncols, color_t foreground, color_t background);
/*
* `console_clear`
*
* Clear all console text and move the cursor to home position.
*/
void console_clear(void);
/*
* `console_printf`
*
* Print the formatted string to the console starting at current cursor
* position. The arguments to this function are the same as `printf`.
* When processing characters, interpret the following special characters:
*
* '\n' : newline (move cursor down to the beginning of next line)
* '\b' : backspace (move cursor backwards one position)
* '\f' : form feed (clear all contents and move cursor to home position)
*
* @param format format for output string. May contain ordinary characters
* and format conversions
* @param ... variable arguments to be converted
* @return count of characters written to the console
*/
int console_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif
#ifndef FB_H
#define FB_H
/*
* Low-level frameuffer routines for controlling a bare metal
* Raspberry Pi's graphics. Presents a useful abstraction of hardware
* that a graphics library can then use to provide useful drawing
* primitives.
*
* Students implement this module for assignment 6.
*
* Author: Philip Levis <[email protected]>
* Date: Mar 23 2016
*/
typedef enum { FB_SINGLEBUFFER = 0, FB_DOUBLEBUFFER = 1 } fb_mode_t;
/*
* `fb_init` : Required initialized for framebuffer
*
* Initialize the framebuffer.
*
* @param width the requested width in pixels of the framebuffer
* @param height the requested height in pixels of the framebuffer
* @param depth the requested depth in bytes of each pixel
* @param mode whether the framebuffer should be
* single buffered (FB_SINGLEBUFFER)
* or double buffered (FB_DOUBLEBUFFER)
*
* If the requested configuration can be successfully accommodated, the
* function returns normally. Otherwise on error, the function raises
* a failed assert.
*/
void fb_init(unsigned int width, unsigned int height, unsigned int depth_in_bytes, fb_mode_t mode);
/*
* `fb_get_width`
*
* Get the current width in pixels of the framebuffer.
*
* @return the width in pixels
*/
unsigned int fb_get_width(void);
/*
* `fb_get_height`
*
* Get the current height in pixels of the framebuffer.
*
* @return the height in pixels
*/
unsigned int fb_get_height(void);
/*
* `fb_get_depth`
*
* Get the current depth in bytes of a single pixel.
*
* @return the depth in bytes
*/
unsigned int fb_get_depth(void);
/*
* `fb_get_pitch`
*
* Get the current pitch in bytes of a single row of pixels in the framebuffer.
* The pitch is nominally the width (number of pixels per row) multiplied by
* the depth in bytes per pixel. However, the pitch may be greater than that if the
* GPU elects to add padding to the end of the row.
*
* @return the pitch in bytes
*/
unsigned int fb_get_pitch(void);
/*
* `fb_get_draw_buffer`
*
* Get the start address of the framebuffer memory into which the
* client can draw pixels. The address returned is the start of an
* array of size pitch*height bytes.
*
* If in single buffering mode, there is only one buffer in use, so the
* returned address does not change. That buffer is on-screen at all
* times. The client draws to that one buffer, and all updates are
* immediately displayed.
*
* In double buffering mode, there are two buffers: the one
* currently on-screen and a second buffer that is off-screen. The
* address returned by `fb_get_draw_buffer` corresponds to the buffer
* that is currently off-screen. The off-screen buffer is sometimes
* called the draw buffer. The client will do all drawing to the off-screen
* buffer and when ready, calls `fb_swap_buffer` to exchange the
* on-screen and off-screen buffers. The swap brings the updated
* drawing on-screen in one smooth update.
*
* Note the address is returned as `void*`. Client should store into
* a properly typed pointer so as to access the pixel data according
* to their desired scheme (1-d, 2-d, etc.)
*
* @return the address of the current draw (off-screen) buffer
*/
void* fb_get_draw_buffer(void);
/*
* `fb_swap_buffer`
*
* Swap the on-screen and off-screen buffers. The draw buffer (off-screen)
* is moved on-screen (contents now displayed) and on-screen buffer
* is moved off-screen (becomes the draw buffer, contents off-screen).
*
* If not in double buffering mode, there is only one buffer and this
* function has no effect.
*/
void fb_swap_buffer(void);
#endif
#ifndef FONT_H
#define FONT_H
#include <stdbool.h>
#include <stddef.h>
/*
* This module provides a font. Each ASCII character has an
* associated glyph. A glyph is a bitmap image for drawing
* the character.
*
* The font is fixed width; every glyph has the same width and
* same height. A glyph is an image with font_get_glyph_height() rows
* and font_get_glyph_width() columns.
* Each pixel of the glyph image is represented as one byte.
* The byte for an "on" pixel is 0xFF, and the byte for
* "off" pixel is 0x00.
*
* Students do not implement this module: the source code for
* its implementation is provided as part of assignment 6.
*
* Author: Philip Levis <[email protected]>
* Date: Mar 25 2016
*/
/*
* `font_get_glpyh_height`
*
* Get the height in pixels of each glyph in this font.
*
* @return the height in pixels
*/
size_t font_get_glyph_height(void);
/*
* `font_get_glpyh_width`
*
* Get the width in pixels of each glyph in this font.
*
* @return the width in pixels
*/
size_t font_get_glyph_width(void);
/*
* `font_get_glpyh_size`
*
* Get the total number of bytes needed to store the glyph image
* for one character. This is equal to the product of
* (glyph height * glyph width).
*
* @return the size in bytes of a glyph image
*/
size_t font_get_glyph_size(void);
/*
* `font_get_glpyh`
*
* Fill in the glyph image for character `ch` into `buf`.
* `buf` is an array of bytes of length font_get_glyph_size().
* Each 'on' pixel has value 0xff, 'off' pixel has value 0x0.
*
* @param ch the requested character
* @param buf the buffer in which to place the glyph image
* @param buflen the length of `buf`.
* `buflen` should be equal to value returned by font_get_glyph_size()
*
* @return returns true when successfully filled `buf`, false otherwise.
* Failure is when `ch` is not available in this font or `buflen`
* does not equal the value returned by font_get_glyph_size()
*/
bool font_get_glyph(char ch, unsigned char buf[], size_t buflen);
#endif
#ifndef GL_H
#define GL_H
/*
* Functions for a simple bare metal Raspberry Pi graphics library
* that draws pixels, text, lines, triangles, and rectangles. Builds
* on the lower-level framebuffer library fb.[ch] for framebuffer
* access and configuration; trying to use both fb and gl
* simultaneously is discouraged.
*
* Students implement this module in assignment 6 (text and rectangles
* are required, lines and triangles are an extension).
*
* Author: Philip Levis <[email protected]>
* Date: Mar 23 2016
*/
#include "fb.h"
typedef enum { GL_SINGLEBUFFER = FB_SINGLEBUFFER, GL_DOUBLEBUFFER = FB_DOUBLEBUFFER } gl_mode_t;
/*
* `gl_init` : Required initialized for graphics library
*
* Initialize the graphic library. This function will call `fb_init` in turn
* to initialize the framebuffer. The framebuffer will be initialzed to
* 4-byte depth (32 bits per pixel).
*
* @param width the requested width in pixels of the framebuffer
* @param height the requested height in pixels of the framebuffer
* @param mode whether the framebuffer should be
* single buffered (GL_SINGLEBUFFER)
* or double buffered (GL_DOUBLEBUFFER)
*/
void gl_init(unsigned int width, unsigned int height, gl_mode_t mode);
/*
* `gl_get_width`
*
* Get the current width in pixels of the framebuffer.
*
* @return the width in pixels
*/
unsigned int gl_get_width(void);
/*
* `gl_get_height`
*
* Get the current height in pixels of the framebuffer.
*
* @return the height in pixels
*/
unsigned int gl_get_height(void);
/*
* `color_t`
*
* Define a type for color. We use BGRA colors, where each color
* component R, B, G, or A is a single unsigned byte. The least
* signficant byte is the B component, and A is most significant.
*/
typedef unsigned int color_t;
/*
* Define some common colors ...
*
* Note that colors are BGRA, where B is the first byte in memory
* and the least significant byte in the unsigned word.
*/
#define GL_BLACK 0xFF000000
#define GL_WHITE 0xFFFFFFFF
#define GL_RED 0xFFFF0000
#define GL_GREEN 0xFF00FF00
#define GL_BLUE 0xFF0000FF
#define GL_CYAN 0xFF00FFFF
#define GL_MAGENTA 0xFFFF00FF
#define GL_YELLOW 0xFFFFFF00
#define GL_AMBER 0xFFFFBF00
#define GL_ORANGE 0xFFFF3F00
#define GL_PURPLE 0xFF7F00FF
#define GL_INDIGO 0xFF000040
#define GL_CAYENNE 0xFF400000
#define GL_MOSS 0xFF004000
#define GL_SILVER 0xFFBBBBBB
/*
* `gl_color`
*
* Returns a color composed of the specified red, green, and
* blue components. The alpha component of the color will be
* set to 0xff (fully opaque).
*
* @param r the red component of the color
* @param g the green component of the color
* @param b the blue component of the color
*
* @return the color as a single value of type color_t
*/
color_t gl_color(unsigned char r, unsigned char g, unsigned char b);
/*
* `gl_clear`
*
* Clear all the pixels in the framebuffer to the given color.
*
* @param c the color drawn into the framebuffer
*/
void gl_clear(color_t c);
/*
* `gl_swap_buffer`
*
* If in double-buffered mode, all gl drawing takes place in the
* off-screen buffer and updated drawing is not brought on-screen until
* a call is made to `gl_swap_buffer` to exchange the on-screen
* and off-screen buffers.
*
* If not in double-buffer mode, all drawing takes place on-screen and
* the `gl_swap_buffer` function has no effect.
*/
void gl_swap_buffer(void);
/*
* `gl_draw_pixel`
*
* Draw a single pixel at location x,y in color c.
* If the location is outside the bounds of framebuffer, it is not drawn.
*
* @param x the x location of the pixel
* @param y the y location of the pixel
* @param c the color of the pixel
*/
void gl_draw_pixel(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
*/
unsigned int gl_get_char_height(void);
/*
* `gl_get_char_width`
*
* Get the width in pixels of a single character glyph.
*
* @return the width of character glyph in pixels
*/
unsigned int gl_get_char_width(void);
/*
* `gl_draw_rect`
*
* Draw a filled rectangle at location x,y with size w,h filled with color c.
* All pixels in the rectangle that lie within the bounds of the
* framebuffer are drawn. Any pixel that lies outside is clipped (i.e. not drawn).
*
* @param x the x location of the upper left corner of the rectangle
* @param y the y location of the upper left corner of the rectangle
* @param w the width of the rectangle
* @param h the height of the rectangle
* @param c the color of the rectangle
*/
void gl_draw_rect(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 Raspberry Pi GPIO.
*
* Students implement this module in assignment 2.
*
* Author: Pat Hanrahan <[email protected]>
* Philip Levis <[email protected]>
* Julie Zelenski <[email protected]>
*
* Last edited Jan 2018
*/
#define GPIO_INVALID_REQUEST -1 // return value for invalid request
/*
* `gpio_init`
*
* Initialize the GPIO code module. For assignment 2, this does nothing.
* However, all libpi peripheral modules require an init, so it is included
* for consistency's sake.
*/
void gpio_init(void);
/*
* `gpio_set_function`
*
* Set a GPIO function for GPIO pin number `pin`. Settings for other pins
* should be unchanged.
*
* @param pin the GPIO pin number to configure
* @param function the GPIO function to set for the pin
*
* If `pin` or `function` is invalid, does nothing.
*/
void gpio_set_function(unsigned int pin, unsigned int function);
/*
* `gpio_get_function`
*
* Get the GPIO function for GPIO pin number `pin`.
*
* @param pin the GPIO pin number to read the function of
* @return the current GPIO function of the specified pin
*
* If `pin` is invalid, returns GPIO_INVALID_REQUEST.
*/
unsigned int gpio_get_function(unsigned int pin);
/*
* `gpio_set_input`, `gpio_set_output`
*
* Convenience functions for setting a pin to GPIO_FUNC_INPUT or
* GPIO_FUNC_OUTPUT. The implementation calls `gpio_set_function`.
*
* @param pin the GPIO pin number to set the function of
*/
void gpio_set_input(unsigned int pin);
void gpio_set_output(unsigned int pin);
/*
* `gpio_write`
*
* Set GPIO pin number `pin` to high (1) or low (0). This
* function assumes the pin is already in output mode.
* Settings for other pins should be unchanged.
*
* @param pin the GPIO pin number to set or clear
* @param val 1 to set pin to high, 0 to clear pin
*
* If `pin` or `val` is invalid, does nothing.
*/
void gpio_write(unsigned int pin, unsigned int val);
/*
* `gpio_read`
*
* Get current level (1 for high, 0 for low) for GPIO pin number `pin`.
*
* @param pin the GPIO pin number to read the value of
* @return the value of the specified pin
*
* If `pin` is invalid, returns GPIO_INVALID_REQUEST.
*/
unsigned int gpio_read(unsigned int pin);
/*
* Enumeration of GPIO pin numbers
*
* The enumerated values below establish symbolic names for each of the GPIO pins.
* Although you could directly refer to pins by number, using the
* names makes it more clear to the reader what a given value represents.
*
* Note also the values GPIO_PIN_FIRST and GPIO_PIN_LAST that bound
* the range of valid GPIO pin numbers.
*/
enum {
GPIO_PIN_FIRST = 0,
GPIO_PIN0 = 0,
GPIO_PIN1 = 1,
GPIO_PIN2 = 2,
GPIO_PIN3 = 3,
GPIO_PIN4 = 4,
GPIO_PIN5 = 5,
GPIO_PIN6 = 6,
GPIO_PIN7 = 7,
GPIO_PIN8 = 8,
GPIO_PIN9 = 9,
GPIO_PIN10 = 10,
GPIO_PIN11 = 11,
GPIO_PIN12 = 12,
GPIO_PIN13 = 13,
GPIO_PIN14 = 14,
GPIO_PIN15 = 15,
GPIO_PIN16 = 16,
GPIO_PIN17 = 17,
GPIO_PIN18 = 18,
GPIO_PIN19 = 19,
GPIO_PIN20 = 20,
GPIO_PIN21 = 21,
GPIO_PIN22 = 22,
GPIO_PIN23 = 23,
GPIO_PIN24 = 24,
GPIO_PIN25 = 25,
GPIO_PIN26 = 26,
GPIO_PIN27 = 27,
GPIO_PIN28 = 28,
GPIO_PIN29 = 29,
GPIO_PIN30 = 30,
GPIO_PIN31 = 31,
GPIO_PIN32 = 32,
GPIO_PIN33 = 33,
GPIO_PIN34 = 34,
GPIO_PIN35 = 35,
GPIO_PIN36 = 36,
GPIO_PIN37 = 37,
GPIO_PIN38 = 38,
GPIO_PIN39 = 39,
GPIO_PIN40 = 40,
GPIO_PIN41 = 41,
GPIO_PIN42 = 42,
GPIO_PIN43 = 43,
GPIO_PIN44 = 44,
GPIO_PIN45 = 45,
GPIO_PIN46 = 46,
GPIO_PIN47 = 47,
GPIO_PIN48 = 48,
GPIO_PIN49 = 49,
GPIO_PIN50 = 50,
GPIO_PIN51 = 51,
GPIO_PIN52 = 52,
GPIO_PIN53 = 53,
GPIO_PIN_LAST = 53
};
// GPIO pin mappings for UART
#define GPIO_TX GPIO_PIN14
#define GPIO_RX GPIO_PIN15
/*
* Enumeration for GPIO functions
*
* The enumerated values below establish symbolic names for each of the
* available GPIO pin functions. Each pin function corresponds to
* a particular "mode" of operation. For example, setting a pin's
* function to GPIO_FUNC_INPUT configures the pin to be used as an input.
*/
enum {
GPIO_FUNC_INPUT = 0,
GPIO_FUNC_OUTPUT = 1,
GPIO_FUNC_ALT0 = 4,
GPIO_FUNC_ALT1 = 5,
GPIO_FUNC_ALT2 = 6,
GPIO_FUNC_ALT3 = 7,
GPIO_FUNC_ALT4 = 3,
GPIO_FUNC_ALT5 = 2,
};
#endif
#ifndef GPIO_EXTRA_H
#define GPIO_EXTRA_H
#include <stdbool.h>
/*
* Functions for controlling extra features of
* Raspberry Pi GPIO: event detection and pull state.
*
* Author: Pat Hanrahan <[email protected]>
* Philip Levis <[email protected]>
* Julie Zelenski <[email protected]>
*
* Last edited: Feb 2018
*/
enum gpio_event {
GPIO_DETECT_RISING_EDGE = 0,
GPIO_DETECT_FALLING_EDGE,
GPIO_DETECT_HIGH_LEVEL,
GPIO_DETECT_LOW_LEVEL,
GPIO_DETECT_ASYNC_RISING_EDGE,
GPIO_DETECT_ASYNC_FALLING_EDGE,
};
/*
* `gpio_enable_event_detection`
*
* Enables detection of GPIO `event` for GPIO pin number `pin`.
*
* @param pin GPIO pin number to configure
* @param event which event to enable, see gpio_event enumeration
*
* If `pin` or `event` is invalid, does nothing.
*/
void gpio_enable_event_detection(unsigned int pin, unsigned int event);
/*
* `gpio_disable_event_detection`
*
* Disables detection of GPIO `event` for GPIO pin number `pin`.
*
* @param pin GPIO pin number to configure
* @param event which event to disable, see gpio_event enumeration
*
* If `pin` or `event` is invalid, does nothing.
*/
void gpio_disable_event_detection(unsigned int pin, unsigned int event);
/*
* `gpio_get_event_detection`
*
* Gets the state of detection of GPIO `event` for GPIO pin number `pin`.
* Returns true if event detection is enabled for `event`, false if disabled.
*
* @param pin GPIO pin number to query
* @param event which event, see gpio_event enumeration
* @return true if enabled, false otherwise
*
* If `pin` or `event` is invalid, returns false.
*/
bool gpio_get_event_detection(unsigned int pin, unsigned int event);
/*
* `gpio_disable_all_event_detection`
*
* Disables detection of all GPIO events for GPIO pin number `pin`.
*
* @param pin GPIO pin number to disable detection of all events
*
* If `pin` is invalid, does nothing.
*/
void gpio_disable_all_event_detection(unsigned int pin);
/*
* `gpio_check_event`
*
* Returns the event status for GPIO pin number `pin`.
* The event status is true if an event has been detected for `pin`
* and the event has not been cleared, status is false otherwise.
*
* @param pin GPIO pin number to check
* @return true if event detected, false otherwise
*
* If `pin` is invalid, returns false.
*/
bool gpio_check_event(unsigned int pin);
/*
* `gpio_clear_event`
*
* Clears the event status for GPIO pin number `pin`. Note that if the
* event detected is high or low level and the level is still high or low,
* clearing the event makes no change in event status. The event
* status remains true as long as the high or low level is in effect.
*
* @param pin GPIO pin number to clear
*
* If `pin` is invalid, does nothing.
*/
void gpio_clear_event(unsigned int pin);
/*
* `gpio_check_and_clear_event`
*
* Returns the event status for GPIO pin number `pin` and clears the
* event status.
*
* @param pin GPIO pin number to check and clear
* @return true if event detected and cleared, false otherwise
*
* If `pin` is invalid, does nothing and returns false.
*/
bool gpio_check_and_clear_event(unsigned int pin);
/*
* The functions below control the pull state of a GPIO pin via its
* internal resistor. Setting the pull state is useful for when you
* have an input pin that would otherwise be floating. A pin configured
* to pull-up defaults to 1. If configured to pull-down defaults to 0.
* The Broadcom manual says pull state of a pin cannot be queried,
* so you have to remember what state you have configured. The manual
* is also unclear about when the pull state is reset (may not be on
* restart, but is after power down?). Best to reset yourself to be
* sure.
*/
/*
* `gpio_set_pullup`
*
* Set pull state of GPIO pin number `pin` to pull-up.
*
* @param pin GPIO pin number to configure as pull-up
*
* If `pin` is invalid, does nothing.
*/
void gpio_set_pullup(unsigned int pin);
/*
*
* `gpio_set_pulldown`
*
* Set pull state of GPIO pin number `pin` to pull-down.
*
* @param pin GPIO pin number to configure as pull-down
*
* If `pin` is invalid, does nothing.
*/
void gpio_set_pulldown(unsigned int pin);
/*
* `gpio_set_pullnone`
*
* Disables any pull state of GPIO pin number `pin` (will float).
*
* @param pin GPIO pin number to disable pull state
*
* If `pin` is invalid, does nothing.
*/
void gpio_set_pullnone(unsigned int pin);
#endif
#ifndef GPIO_INTERRUPTS_H
#define GPIO_INTERRUPTS_H
#include "interrupts.h"
/*
* Module to configure GPIO interrupts for Raspberry Pi.
* Because all of the GPIO pins share a small set of GPIO
* interrupts, you need a level of indirection to be able
* to handle interrupts for particular pins. This module
* allows a client to register one handler for each
* GPIO pin.
*
* Author: Philip Levis <[email protected]>
*
* Last update: May 2020
*/
/*
* `gpio_interrupts_init`: Required initialization for module
*
* Initialize the GPIO interrupts module. The init function must be
* called before any calls to other functions in this module.
* The init function coordinates with the top-level interrupts module.
* It registers a dispatch handler with the top-level interrupts module.
* This dispatch handler receives all GPIO interrupts at the top-level
* and in turn dispatches to the handler registered with this module.
* The handlers registered with this module are associated with a
* specific GPIO pin.
*
* When this function returns, GPIO interrupts are disabled and
* must be enabled with `gpio_interrupts_enable`.
*
* It is safe to call init more than once for this module. A re-init
* retains all handlers that were previously registered.
*
* Note: the top-level interrupts module must be initialized before
* attempting to initialize this module.
*/
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);
/*
* `gpio_interrupts_register_handler`
*
* Register a handler function to a given GPIO pin. Each GPIO
* pin can have one handler: further dispatch should be invoked by
* the handler itself. Use the events system defined in `gpio_extra.h`
* to configure which GPIO events are detected by the pin.
*
* @param pin GPIO pin to register handler
* @param fn handler function to call when interrupt generated on pin
* @param aux_data client's data pointer to be passed as second argument
* when calling handler function
*
* An assert is raised if `pin` is invalid. `aux_data` can be NULL if
* handler function has no need for auxiliary data. If `fn` is NULL, removes
* any handler previously registered for `pin`.
*
* This function asserts on an attempt to register handler without first
* initializing the module (i.e. required to call `gpio_interrupts_init`).
*/
void gpio_interrupts_register_handler(unsigned int pin, handler_fn_t fn, void *aux_data);
#endif
#ifndef INTERRUPTS_H
#define INTERRUPTS_H
#include <stdbool.h>
#include <stddef.h>
/*
* Module to configure interrupts for Raspberry Pi.
*
* Author: Philip Levis <[email protected]>
* Author: Pat Hanrahan <[email protected]>
* Author: Julie Zelenski <[email protected]>
*
* Last update: May 2020
*/
/*
* `interrupts_init`: Required initialization for interrupts
*
* Initialize interrupts and configures to a clean state.
*
* - vector table is copied to destination address 0
* - all interrupt sources are disabled
* - interrupts are globally disabled
*
* This module init should be called once (and only once)
* before any calls to other functions in the interrupts module.
* Calling the init function a second time will raise an error.
* Without more specific initialization semantics and structure,
* this is the safe approach that avoids having to debug why a
* source suddenly stopped receiving interrupts after a re-init
* silently wiped the settings from previous configuration.
*/
void interrupts_init(void);
/*
* `interrupts_global_enable`
*
* Turns on interrupts system-wide. An interrupt generated on
* an interrupt source that is enabled will call the registered handler.
*/
void interrupts_global_enable(void);
/*
* `interrupts_global_disable`
*
* Turns off interrupts system-wide. No interrupts will be generated.
* Does not remove registered handlers or disable interrupt sources,
* only temporarily suspends interrupt generation. Call
* `interrupts_global_enable` to resume generating interrupts.
*/
void interrupts_global_disable(void);
/*
* `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.
*/
void interrupts_enable_source(unsigned int source);
/*
* `interrupts_disable_source`
*
* Disable a particular interrupt 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.
*/
void interrupts_disable_source(unsigned int source);
/*
* `handler_fn_t`
*
* This typedef gives a nickname to the type of function pointer used as
* a handler callback. A handler is registered to an interrupt source. When
* an interrupt is generated by that source, the handler is called to
* process it. A handler takes two arguments. The first argument is the
* value of the interrupted pc and second argument is the client's
* auxiliary data pointer (can be NULL if not used).
*/
typedef void (*handler_fn_t)(unsigned int, void *);
/*
* `interrupts_register_handler`
*
* Register the handler function for a given interrupt source. Each interrupt
* source can have one handler: further dispatch should be invoked by
* the handler itself. 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
* - having an interrupt handled before `interrupts_register_handler` returns,
* - handling interrupts that were pending from a different use of the source,
* - changing the handler as one part of a larger atomic action.
*
* This function asserts on an attempt to register handler without initializing
* the interrupts module (i.e. required to call `interrupts_init` first).
*
* Valid interrupt sources are basic interrupts and those with entries in
* the interrupt table in the BCM2835 manual: GPU and other reserved
* interrupts are invalid.
*
* An interrupt source is identified by number. Valid source numbers are
* listed below in the `interrupt_source` enumeration.
* The sources we will commonly use are
* INTERRUPTS_GPIO3 for gpio interrupts (source shared by all gpios)
* INTERRUPTS_BASIC_ARM_TIMER_IRQ for armtimer interrupts
*
* @param source which interrupt source (see enumeration values below)
* @param fn handler function to call when interrupt generated on source
* @param aux_data client's data pointer to be passed as second argument
* when calling handler function
*
* An assert is raised if `source` is invalid. `aux_data` can be NULL if
* handler function has no need for auxiliary data. If `fn` is NULL, this
* removes any handler previously registered for `source`.
*/
void interrupts_register_handler(unsigned int source, handler_fn_t fn, void *aux_data);
/*
* Enumeration of valid interrupt sources
*
* Below are the interrupt sources that this module can enable, disable,
* and handle. AUX through VC_UART are all IRQs from peripherals. There
* are 64 peripheral interrupts, but only these ones should be handled by
* your code -- the datasheet says (BCM2835 Sec 7.5)
* "The table has many empty entries. These should not be
* enabled as they will interfere with the GPU operation."
*
* So there is a peripheral interrupt 0 but you should not handle it.
*
* Values with _BASIC_ in them are basic interrupts that are generated
* from the core itself. Normally, these are a completely separate
* identifier space of interrupts. Basic interrupt 0 is the ARM_TIMER
* interrupt, for example. Rather than have two separate sets of functions
* for peripheral and basic interrupts, we just give them IDs > 64 and
* then map them to their real values in the code. Using a single
* identifier space means that we avoid the inevitable bug of someone
* passing a basic interrupt ID to a peripheral interrupt function and
* vice versa.
*/
enum interrupt_source {
INTERRUPTS_SHARED_START = 29,
INTERRUPTS_AUX = 29,
INTERRUPTS_I2CSPISLV = 43,
INTERRUPTS_PWA0 = 45,
INTERRUPTS_PWA1 = 46,
INTERRUPTS_CPR = 47,
INTERRUPTS_SMI = 48,
INTERRUPTS_GPIO0 = 49,
INTERRUPTS_GPIO1 = 50,
INTERRUPTS_GPIO2 = 51,
INTERRUPTS_GPIO3 = 52,
INTERRUPTS_VC_I2C = 53,
INTERRUPTS_VC_SPI = 54,
INTERRUPTS_VC_I2SPCM = 55,
INTERRUPTS_VC_UART = 57,
INTERRUPTS_SHARED_END,
INTERRUPTS_BASIC_BASE = 64,
INTERRUPTS_BASIC_ARM_TIMER_IRQ = INTERRUPTS_BASIC_BASE,
INTERRUPTS_BASIC_ARM_MAILBOX_IRQ,
INTERRUPTS_BASIC_ARM_DOORBELL_0_IRQ,
INTERRUPTS_BASIC_GPU_0_HALTED_IRQ,
INTERRUPTS_BASIC_GPU_1_HALTED_IRQ,
INTERRUPTS_BASIC_ACCESS_ERROR_1_IRQ,
INTERRUPTS_BASIC_ACCESS_ERROR_0_IRQ,
INTERRUPTS_BASIC_END,
INTERRUPTS_COUNT,
INTERRUPTS_NONE = 255,
};
#endif
#ifndef KEYBOARD_H
#define KEYBOARD_H
#include "gpio.h"
#include "ps2_keys.h"
/*
* Module to read keys typed on a PS/2 keyboard.
*
* Students implement this module in assignment 5.
*
* Author: Philip Levis <[email protected]>
* Author: Julie Zelenski <[email protected]>
*
* Last updated: February 2023
*/
/*
* Type: `key_action_t`
*
* This struct represents a single action on a PS2 key.
* The action is either a press or release of the specified key
* (identified by its keycode).
*/
typedef struct {
enum { KEY_PRESS, KEY_RELEASE } what;
unsigned char 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.
* The required modifiers are Shift, Alt, Control, and Caps Lock.
*/
typedef enum {
KEYBOARD_MOD_SHIFT = 1 << 0,
KEYBOARD_MOD_ALT = 1 << 1,
KEYBOARD_MOD_CTRL = 1 << 2,
KEYBOARD_MOD_CAPS_LOCK = 1 << 3,
// scroll and num lock listed for completeness, NOT implemented for assign5 basic
KEYBOARD_MOD_SCROLL_LOCK = 1 << 4,
KEYBOARD_MOD_NUM_LOCK = 1 << 5,
} 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;
#define KEYBOARD_CLOCK GPIO_PIN3
#define KEYBOARD_DATA GPIO_PIN4
/*
* `keyboard_init`: Required initialization for keyboard.
*
* The keyboard must first be initialized before any key events can be read.
* The two arguments are the GPIO pins of the PS2 clock and data lines
* to use when creating the PS2 device.
*
* @param clock_gpio the gpio connected to the clock line of keyboard
* @param data_gpio the gpio connected to the data line of keyboard
*/
void keyboard_init(unsigned int clock_gpio, unsigned int data_gpio);
/*
* `keyboard_read_next`: Top level keyboard interface.
*
* This function reads (blocking) the next key typed on the keyboard.
* The character returned reflects the current keyboard 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
*/
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 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 keycode identifies the PS2 key that was acted upon.
*
* This function calls `keyboard_read_scancode` to read each scancode.
*
* @return key_action_t struct containing key action for sequence
*/
key_action_t keyboard_read_sequence(void);
/*
* `keyboard_read_scancode`: Bottom level keyboard interface.
*
* Calls into ps2 module to read (blocking) a single scancode from
* the PS2 keyboard device.
*
* @return scancode read from keyboard
*/
unsigned char keyboard_read_scancode(void);
/*
* `keyboard_use_interrupts`
*
* Change keyboard from default polling behavior to instead configure interrupts
* for gpio events. After setting keyboard to use interrupts, client must
* also globally enable interrupts at system level. This switchable feature is
* specific to reference module. The student's keyboard module is initially
* polling-only (assign5) and later changed to interrupt-only (assign7).
*/
void keyboard_use_interrupts(void);
#endif
#ifndef MAILBOX_H
#define MAILBOX_H
/*
* Interface to Raspberry Pi mailboxes for interacting with on-chip
* peripherals such as the framebuffer and touchscreen.
*
* You read the implementation of this module in Lab 6, answering
* some questions about how and why it works.
*
* Author: Pat Hanrahan <[email protected]>
* Date: Jan 31 2016
*/
#include <stdbool.h>
/*
* The maximum number of channels on the Pi
*/
#define MAILBOX_MAXCHANNEL 16
/*
* These constants define mailbox channels. Messages can be sent on
* these channels. The only channel we use in this course is the
* MAILBOX_FRAMEBUFFER channel.
*/
typedef enum {
MAILBOX_POWER_MANAGEMENT = 0,
MAILBOX_FRAMEBUFFER,
MAILBOX_VIRTUAL_UART,
MAILBOX_VCHIQ,
MAILBOX_LEDS,
MAILBOX_BUTTONS,
MAILBOX_TOUCHSCREEN,
MAILBOX_UNUSED,
MAILBOX_TAGS_ARM_TO_VC,
MAILBOX_TAGS_VC_TO_ARM,
} mailbox_channel_t;
/*
* Send a mailbox request and confirm response. Uses
* `mailbox_write` to send `addr` to `channel` and `mailbox_read`
* to verify response.
*
* @param channel send request to `channel`
* @param addr `addr` is the address of the message data to send. This address
* must be a multiple of 16 (i.e. lower 4 bits are 0).
* GPU_NOCACHE will be added to the address so that the contents
* of the message is not cached by the GPU.
* @return true if request successfully processed, false otherwise
* returns false if channel or addr is invalid
*/
bool mailbox_request(unsigned int channel, unsigned int addr);
/*
* Write a mailbox message to `channel`. After writing a message,
* must call `mailbox_read` to receive response from GPU.
*
* @param channel send the message to `channel`
* @param addr `addr` is the address of the message data to send. This address
* must be a multiple of 16 (i.e. lower 4 bits are 0).
* GPU_NOCACHE will be added to the address so that the contents
* of the message is not cached by the GPU.
* @return true if message successfully sent, false otherwise
* returns false if channel or addr is invalid
*/
bool mailbox_write(unsigned int channel, unsigned int addr);
/*
* Receive a mailbox message for `channel`.
*
* @param channel receive a message on `channel`
* @return the data in the message received
*
*/
unsigned int mailbox_read(unsigned int channel);
#endif
#ifndef MALLOC_H
#define MALLOC_H
/*
* Functions for dynamic allocation.
*
* Students implement this module in assignment 4.
*
* Author: Julie Zelenski <[email protected]>
* Mon Feb 5 20:02:27 PST 2018
*/
#include <stddef.h> // for size_t
/*
* Service a dynamic allocation request. Returns the
* address of a memory block of at least `nybtes` contiguous
* bytes or NULL if the request cannot be satisifed.
* The block address is guaranteed to be aligned to an 8-byte boundary.
* If `nbytes` is 0, malloc returns either NULL or a unique
* pointer to an allocated block of some minimum size.
*
* @param nbytes requested size in bytes
* @return address of memory block of requested size
* or NULL if request cannot be satisifed
*/
void *malloc(size_t nbytes);
/*
* Deallocate the memory block at address `ptr`.
*
* The `ptr` argument is expected to be an address that was
* previously returned by malloc and has not yet been freed.
* If this precondition is not satisified, the behavior is undefined.
* If `ptr` is NULL, the operation does nothing.
*
* @param ptr address of memory block to deallocate
*/
void free(void *ptr);
/*
* Return the address of the previous end of the heap segment
* and enlarge the segment by the specified number of bytes.
* The call `sbrk(0)` returns the address of the end of segment
* with no change in size. You may assume that no calls to
* sbrk with a non-zero argument will come from outside clients,
* calls to enlarge the segment will only come from within
* your heap allocator implementation.
*
* @param nbytes the number of bytes to extend the segment end by
* @return address of previous end of segment (before enlarge)
*/
void *sbrk(int nbytes);
#endif
#ifndef MOUSE_H
#define MOUSE_H
#include "gpio.h"
#include <stdbool.h>
/*
* Module to read mouse events from a PS/2 mouse.
*
* Students implement this module as an extension to assignment 7.
*
* Author: Julie Zelenski <[email protected]>
*
* Last updated: May 2022
*/
/*
* 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;
#define MOUSE_CLOCK GPIO_PIN5
#define MOUSE_DATA GPIO_PIN6
/*
* `mouse_init`: Required initialization for mouse.
*
* The mouse must first be initialized before any mouse events can be read.
* The two arguments are the GPIO pins of the PS2 clock and data lines
* to use when creating the PS2 device. `mouse_init` resets the mouse and
* enables data reporting mode.
*
* @param clock_gpio the gpio connected to the clock line of mouse
* @param data_gpio the gpio connected to the data line of mouse
*/
void mouse_init(unsigned int clock_gpio, unsigned int data_gpio);
/*
* `mouse_read_event`
*
* The function reads (blocking) the next event from the mouse.
* Returns a `mouse_event_t` struct that represents the mouse 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 PI_H
#define PI_H
/*
* Utility functions for Raspberry Pi.
*
* Authors: Pat Hanrahan <[email protected]>,
* Philip Levis <[email protected]>,
* Julie Zelenski <[email protected]>
*/
#include "gpio.h"
/*
* Enumeration for valid LED identifiers.
*
* The two LEDs on the Raspberry Pi board are:
* PI_ACT_LED green LED labeled `ACT`
* PI_PWR_LED red LED labeled `PWR`
*/
enum {
PI_ACT_LED = GPIO_PIN47,
PI_PWR_LED = GPIO_PIN35
};
/*
* `pi_reboot`
*
* Halts current program execution and reboots the Pi.
*/
void pi_reboot(void) __attribute__ ((noreturn));
/*
* `pi_abort`
*
* Goes into an infininte loop that flashes the red power
* LED on the Pi board. This function does not return.
*/
void pi_abort(void) __attribute__ ((noreturn));
/*
* `pi_led_on`
*
* Turns on the specified LED.
*
* @param led the led to turn on
*
* If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
*/
void pi_led_on(int led);
/*
* `pi_led_off`
*
* Turns off the specified LED.
*
* @param led the led to turn off
*
* If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
*/
void pi_led_off(int led);
/*
* `pi_led_toggle`
*
* Toggles the specified LED. If on, turns it off. If off, turns on.
*
* @param led the led to toggle
*
* If `led` is not PI_ACT_LED or PI_PWR_LED, function does nothing.
*/
void pi_led_toggle(int led);
#endif
#ifndef PRINTF_H
#define PRINTF_H
/*
* Functions for printing formatted strings.
*
* Students implement this module in assignment 3
*
* Author: Julie Zelenski <[email protected]>
* Sat Jan 27 11:27:13 PST 2018
*/
#include <stdarg.h>
#include <stddef.h>
/* The functions vnsprintf, snprintf, and printf construct a
* formatted output from an input format string and arguments.
* These functions support same conversion options in format
* string, but differ slightly in how the function is called
* or what it does with the output string, e.g., whether it is
* sent to the Raspberry Pi UART (printf) or written into the
* destination buffer (snprintf, vsnprintf).
*
* The supported format conversions are
* %c single character
* %s string
* %d signed decimal integer
* %x unsigned hexadecimal integer (hex letters in lowercase)
* %p pointer (printed as a hex address)
* %% used to output a single percent character
*
* The %d and %x formats support an optional field width.
*
* The fancier printf features (padding with spaces, justification
* left/right, precision, etc.) are not supported.
* All format conversions other than the supported ones listed above
* are considered invalid. The function's behavior for an invalid
* format conversion is undefined.
*/
/*
* `vsnprintf`
*
* Constructs a formatted output string from an input string and a va_list
* of arguments. Writes output string to the destination buffer.
*
* @param buf destination buffer where to write output string
* @param bufsize size of destination buffer (output truncated to fit if needed)
* @param format format for output string. May contain ordinary characters
* (copied to destination as-is) and format conversions (next
* argument converted and copied to destination)
* @param args list of arguments to be converted
* @return count of characters written if entire formatted string
* fits in destination; otherwise count of characters it would
* have written if there were space.
*/
int vsnprintf(char *buf, size_t bufsize, const char *format, va_list args);
/*
* `snprintf`
*
* Constructs a formatted output string from an input string and variable
* arguments. Writes output string to the destination buffer.
*
* @param buf destination buffer where to write output string
* @param bufsize size of destination buffer (output truncated to fit if needed)
* @param format format for output string. May contain ordinary characters
* and format conversions
* @param ... variable arguments to be converted
* @return count of characters written if entire formatted string
* fits in destination; otherwise count of characters it would
* have written if there were space.
*/
int snprintf(char *buf, size_t bufsize, const char *format, ...) __attribute__((format(printf, 3, 4)));
/*
* `printf`
*
* Constructs a formatted output string from an input string and arguments.
* Writes output string to UART.
*
* @param format format for output string. May contain ordinary characters
* and format conversions
* @param ... variable arguments to be converted
* @return count of characters written to UART
*/
int printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
#endif
#ifndef PS2_H
#define PS2_H
/*
* Module that communicates with a PS2 device such as a keyboard
* or mouse.
*
* Students implement this module in assignments 5 and 7.
*
* Author: Julie Zelenski <[email protected]>
*
* Last edited Feb 2023
*/
#include <stdbool.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 libpi 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_gpio the gpio pin number connected to the clock line of the PS2 device
* @param data_gpio the gpio pin number connected to the data line of the PS2 device
* @return pointer to new PS2 device or NULL if failed to create
*
* Although `ps2_new` configures the requested clock and data GPIOs
* to use the internal pull-up resistors, it is recommended to choose GPIO
* pins whose default state is already pull-up. This avoid timing issues
* if the device attempts to handshake with the Pi before `ps2_new` has
* been called.
*/
ps2_device_t *ps2_new(unsigned int clock_gpio, unsigned int data_gpio);
/*
* `ps2_read`
*
* Read (blocking) a single scancode from the specifed PS2 device.
* Bits are read on the falling edge of the clock.
*
* Reads 11 bits: 1 start bit, 8 data bits, 1 parity bit, and 1 stop bit
*
* Discards and restarts the scancode if:
* (lab5) The start bit is incorrect
* (assign5) or if parity or stop bit is incorrect
*
* Returns the 8 data bits of a well-formed PS2 scancode.
* Will not return until it reads a complete and valid scancode.
*
* @param dev PS2 device from which to read
* @return scancode read from PS2 device
*/
unsigned char ps2_read(ps2_device_t *dev);
/*
* `ps2_write`: optional extension
*
* Write a command scancode to the specifed PS2 device.
* You do not need to implement this function unless you are
* doing the mouse extension 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, unsigned char command);
/*
* `ps2_use_interrupts` : reference-only
*
* The default behavior of `ps2_read` is to read scancode bits
* by polling the clock GPIO and waiting for a falling edge. An
* alternate mode would be to register for event detection
* on the clock GPIO to be notified of each falling edge and use
* an interrupt handler to read a bit. The interrupt handler would
* enqueue a scancode to an internal queue to be later
* dequeued by`ps2_read`.
*
* The reference implementation of this module has a switch to
* change the mode for a ps2 device. The default is read-by-polling.
* After creating a device with `ps2_new`, the client may call
8 `ps2_use_interrupts(device)` to change that device into
* read-by-interrupt mode.
*
* The client must also globally enable interrupts at system level for
* interrupts to be generated.
*
* The switchable mode is specific to the reference implementation.
* The student's ps2 module does not have this function.
* The initial implementation by student is polling-only (assign5) and
* later changed to interrupt-only (assign7).
*/
void ps2_use_interrupts(ps2_device_t *dev);
#endif
#ifndef PS2_KEYS_H
#define PS2_KEYS_H
/* This module declares constants for interacting with a PS/2
* keyboard, including an array that serves as a lookup table
* to access information about the keys and the characters they produce.
*
* You use this interface in assignment 5 to implement a keyboard
* driver.
*
* Author: Julie Zelenski <[email protected]>
* Author: Philip Levis <[email protected]>
* Date: February 2023
*/
/* Scancodes used in the PS2 protocol */
#define PS2_CODE_RELEASE 0xF0
#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 ps2_special_chars enumeration below.
*/
typedef struct {
unsigned char ch;
unsigned 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[];
/* 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_special_chars {
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 RB_H
#define RB_H
#include <stdbool.h>
/*
* This module defines a ring buffer data structure that provides
* a fixed-length FIFO (first-in-first-out) queue of int elements.
*
* The queue is designed to allow concurrent access by 1 reader (rb_dequeue)
* and 1 writer (rb_enqueue). The writer is typically the interrupt handler,
* which is enqueuing data to be dequeued by the main program, the reader.
*
* Author: Philip Levis <[email protected]>
* Author: Julie Zelenski <[email protected]>
*/
typedef struct ringbuffer rb_t;
/*
* `rb_new`
*
* Initializes a new empty ring buffer and returns a pointer to it.
*
* @return pointer to new ring buffer or NULL if failed to create
*
* To set up a ring buffer in your code:
*
* rb_t *rb = rb_new();
*
* Notice that this interface is slightly different from the _init exposed by
* other libpi modules. This _new pattern allows a user to have multiple ring
* buffers, like objects in Java. It also means that users of this
* module don't need to know the implementation details (like size) of rb_t,
* since they just keep a pointer.
*/
rb_t *rb_new(void);
/*
* `rb_empty`
*
* Check if a ring buffer is currently empty.
*
* @param rb the ring buffer to check
* @return true if rb is empty, false otherwise
*/
bool rb_empty(rb_t *rb);
/*
* `rb_full`
*
* Check if a ring buffer is currently full. When full, existing
* elements must first be dequeued before further elements can
* be enqueued.
*
* @param rb the ring buffer to check
* @return true if rb is full, false otherwise
*/
bool rb_full(rb_t *rb);
/*
* `rb_enqueue`
*
* Add an element to the back of a ring buffer. If the ring buffer
* is full, no changes are made and false is returned.
*
* @param rb the ring buffer to enqueue to
* @param elem the element to enqueue
* @return true if elem was successfully enqueued, false otherwise
*/
bool rb_enqueue(rb_t *rb, int elem);
/*
* `rb_dequeue`
*
* If the ring buffer is not empty, remove frontmost element,
* store into *p_elem, and return true. p_elem should be the address
* of a valid memory location into which to store the dequeued value.
* If the ring buffer is empty, no changes are made to either the ring
* buffer or *p_elem and the return value is false.
*
* @param rb the ring buffer to dequeue from
* @param p_elem address at which to store the dequeued element
* @return true if an element was written to *p_elem, false otherwise
*/
bool rb_dequeue(rb_t *rb, int *p_elem);
#endif
#ifndef SHELL_H
#define SHELL_H
#include <stddef.h>
/*
* Interface to the CS107E shell.
*
* Students implement this module in assignment 5.
*
* Author: Julie Zelenski <[email protected]>
* Last update: February 2019
*/
/*
* Type: `input_fn_t`
*
* This typedef gives a nickname to the type of function pointer used as the
* the shell input function. A input_fn_t function takes no arguments and
* returns a value of type unsigned char. `keyboard_read_next` is an example
* of a possible shell input function.
*/
typedef unsigned char (*input_fn_t)(void);
/*
* Type: `formatted_fn_t`
*
* This typedef gives a nickname to the type of function pointer used as the
* the shell output function. A formatted_fn_t function has one fixed
* parameter (format string) and variable arguments to follow. The return
* value is of type int. `printf` is an example of a possible shell
* output function.
*/
typedef int (*formatted_fn_t)(const char *format, ...) __attribute__((format(printf, 1, 2)));
/*
* `shell_init`: Required initialization for shell
*
* The two arguments are function pointers. The `read_fn` is a function
* to read input. The shell calls this function to get the next
* input character. The `print_fn` is a function to print output.
* The shell calls this function to output formatted text.
* The client's choice of read function controls where shell reads
* input and cclient's hoice of print function controls where shell
* output is displayed.
*
* Example usage:
* `shell_init(keyboard_read_next, printf)`
* `shell_init(keyboard_read_next, console_printf)`
*
* @param read_fn function to read input char
* @param print_fn function to output formatted text
*/
void shell_init(input_fn_t read_fn, formatted_fn_t print_fn);
/*
* `shell_bell`: audio/visual beep
*
* Sends an Ascii BEL character '\a' over the uart. This gives
* an audio or visual beep depending on your terminal settings.
* https://en.wikipedia.org/wiki/Bell_character
*/
void shell_bell(void);
/*
* `shell_readline`: read function of shell read-eval-print loop
*
* Reads a single line of input from the user.
*
* Reads characters entered by user and stores them into `buf`.
* Updates display to show current line as user edits.
* Stops reading when user enters Return ('\n'). The ending newline
* is discarded (not written to `buf`). If user enters more
* characters than fit in `buf` (`bufsize` - 1), those excess characters
* are rejected (call `shell_bell`) and not written to `buf`. A
* null-terminator is written to the end of the contents in `buf`.
*
* When the user types backspace (\b):
* If there are any characters currently in the buffer, deletes the last one.
* Otherwise, calls `shell_bell`.
* 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 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 the one-word name,
* usage, help description, and function pointer to execute the command.
*/
typedef struct _command_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 Raspberry Pi
* peek [addr] print contents of memory at address
* poke [addr] [val] store value into memory at address
* Pi> help reboot
* reboot reboot the Raspberry 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_reboot`
*
* Usage: reboot
* Description: reboot the Raspberry Pi
*
* Example:
* Pi> reboot
* Rebooting Pi, see ya at the bootloader!
*
* 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.
* If address 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 0
* 0x00000000: e59ff030
* 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 0x8000 3
* Pi> peek 0x8000
* 0x00008000: 00000003
* Pi> poke 0x8000
* 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 <[email protected]>
* Sat Jan 27 11:27:13 PST 2018
*/
#include <stddef.h>
/*
* `memset`
*
* Write `n` bytes of value `val` to the memory area `dst`.
* Due to historical artifact, `val` parameter has type `int` even
* though the argument is treated as `unsigned char`. The
* least significant byte of `val` is copied `n` times.
*
* @param dst address of memory location
* @param val the byte value to replicate
* @param n the number of bytes to write
* @return argument `dst`
*/
void *memset(void *dst, int val, size_t n);
/*
* `memcpy`
*
* Copy `n` bytes of data from the memory area `src` to the
* memory area `dst`. It is a client error to call memcpy on
* `dst` and `src` areas that overlap. In such a case,
* the behavior is undefined.
*
* @param dst address of memory location area to write
* @param src address of memory location area to read
* @param n the number of bytes to copy
* @return argument `dst`
*/
void *memcpy(void *dst, const void *src, size_t n);
/*
* `strlen`
*
* Compute the length of string `str`.
*
* @param str null-terminated string
* @return the count of characters preceding terminating '\0' character
*/
size_t strlen(const char *str);
/*
* `strcmp`
*
* Lexicographically compare the null-terminated strings `s1` and `s2`.
*
* The function result indicates whether string `s1` is less than (negative),
* equal to (zero), or greater than (positive) string `s2`.
* Comparison is done as unsigned characters.
*
* @param s1, s2 null-terminated strings
* @return negative, zero, or positive result of comparing `s1` to `s2`
*/
int strcmp(const char *s1, const char *s2);
/*
* `strtonum`
*
* Convert the digit characters in `str` to the corresponding unsigned integer
* value. If `str` begins with the prefix "0x", the characters of `str` will
* be interpreted as hexadecimal digits (base 16); otherwise the characters
* are interpreted as decimal digits (base 10). No other bases are supported.
* The hex letter digits are accepted in both upper and lowercase.
*
* `strtonum` processes the characters of `str`, stopping at the first
* character that is not a valid digit in the base or at the terminating
* '\0' (whichever comes first). The function is not required to support
* leading spaces or a plus/minus sign. Such characters can be
* treated as invalid and stop the conversion.
*
* The argument `endptr` is an output parameter optionally used to
* communicate back to the caller what characters remain in `str` after having
* "consumed" the digit characters. A caller can pass NULL for `endptr`
* if they do not need this information.
*
* If `endptr` is not NULL, *endptr is updated to point to the character
* in `str` where conversion stopped. This is either the address of the
* first invalid character in `str` or the address of the terminating '\0'
* if all characters in `str` are valid digits.
*
* The function result is the converted value or 0 if the first character of
* `str` is not a valid digit and no conversion was possible.
*
* The function only needs to handle converting numbers that are within
* the range reprsentable as `unsigned int`.
*
* @param str null-terminated string to convert
* @param endptr output parameter, will point to character after conversion end
* @return result of numeric conversion (or 0 if first char is invalid)
*/
unsigned int strtonum(const char *str, const char **endptr);
/*
* `strlcat`
*
* Size-bounded string concatenation. Append the null-terminated string `src`
* to the end of `dst`. `strlcat` appends at most `dstsize - strlen(dst) - 1`
* bytes, and null-terminates `dst`. If `dst` and `src` overlap,
* the behavior is undefined.
*
* The function result is the initial length of `dst` plus the length of
* `src`, i.e. the final 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 TIMER_H
#define TIMER_H
/*
* Hardware abstractions for a Raspberry Pi timer.
*
* Students implement this module in assignment 2.
*
* Author: Philip Levis <[email protected]>
* Pat Hanrahan <[email protected]>
* Date: Jan 24, 2016
* Edited by Mark Miller, Anna Zeng, Jan 21, 2018
*/
/*
* `timer_init`
*
* Initialize the timer. For assignment 2, this does nothing.
* However, all libpi peripheral modules require an init, so it is
* included for consistency's sake.
*/
void timer_init(void);
/*
* `timer_get_ticks`
*
* Returns the current system tick count. The tick count is set to
* zero at boot and increments once per microsecond until the
* processor resets. One tick is equal to one microsecond.
*
* @return system tick count
*/
unsigned int timer_get_ticks(void);
/*
* `timer_delay_us`
*
* A simple busy loop that delays the program for `usec` microseconds.
*
* @param usec the number of microseconds to busy loop for
*/
void timer_delay_us(unsigned int usec);
/*
* `timer_delay_ms`
*
* Delay for `msec` milliseconds.
*
* @param msec the number of milliseconds to busy loop for
*/
void timer_delay_ms(unsigned int msec);
/*
* `timer_delay`
*
* Delay for `sec` seconds.
*
* @param sec the number of seconds to busy loop for
*/
void timer_delay(unsigned int sec);
#endif
#ifndef UART_H
#define UART_H
#include <stdbool.h>
/*
* Hardware abstractions for a serial port (UART).
*
* Author: Pat Hanrahan <[email protected]>
* Date: Jan 24, 2016
*/
enum {
EOT = 4, // Ascii end of transmission control char, putchar to indicate uart communication complete
EOF = -1, // Ascii end of file control char, returned by getchar to indicate no more data to read
TERMINATE = 24 // Ascii cancel control char, putchar to indicate program forcibly exited
};
/*
* `uart_init`: Required initialization for module
*
* Initialize the UART code module. A single call to `uart_init`
* should made as part of the program initialization, before any
* calls to other uart_ functions. It is allowed, although unusual,
* to call `uart_init` again to reset the UART state. A reset
* will discard any pending data in the send/receive buffer.
*
* The UART requires exclusive use of GPIO pins 14 (transmit)
* and 15 (receive). Once the UART is initialized and in use,
* your code should not muck with these two pins.
*/
void uart_init(void);
/*
* `uart_getchar`
*
* Obtains the next input character from the serial port and returns it.
* If receive buffer is empty, will block until next character is received.
*
* @return the character read or EOF if error or at end of input
*/
int uart_getchar(void);
/*
* `uart_putchar`
*
* Outputs a character to the serial port.
* If send buffer is full, will block until space available.
*
* @param ch the character to write to the serial port
* @return the character written
*/
int uart_putchar(int ch);
/*
* `uart_flush`
*
* Flushes any output characters pending in the send buffer.
*/
void uart_flush(void);
/*
* `uart_haschar`
*
* Returns whether there is a character in the receive buffer.
*
* @return true if character ready to be read, false otherwise
*/
bool uart_haschar(void);
/*
* `uart_putstring`
*
* Outputs a string to the serial port by calling `uart_putchar`
* on each character.
*
* @param str the string to output
* @return the count of characters written or EOF if error
*/
int uart_putstring(const char *str);
/*
* `uart_send`
*
* Outputs raw byte to the serial port. `uart_send` outputs the raw byte
* with no translation (unlike `uart_putchar` which adds processing for
* converting end-of-line markers). To send text character, use
* `uart_putchar`; if raw binary data, use `uart_send`.
*
* @param byte the byte to write to the serial port
*/
void uart_send(unsigned char byte);
/*
* `uart_recv`
*
* Obtain raw byte from the serial port. `uart_recv` returns the raw
* byte with no translation (unlike uart_getchar which adds processing
* for converting end-of-line and end-of-file markers). To read text
* character, use `uart_getchar`; if raw binary data, use `uart_recv`.
*
* @return the byte read from the serial port
*/
unsigned char uart_recv(void);
#endif