// usb_interface.h
// BCD -- Ben Hutton, Chris Leary, Devrin Talen
// 100-column width
/*
* The USB Interface is the lowest layer of the three-tier USB protocol stack. It contains both
* the Host Controller and Serial Interface Engine.
*
* The Host Controller (HC) is the interface to the upper (USB System) layer, and it instructs
* the Serial Interface Engine (SIE) to perform transactions from its transaction queue. It
* ensures that all the SIE's data fields (token length, packet length, etc.) are set properly
* before sending it the 'execute transfer' request. This includes placing the transaction to
* be executed into the SIE's buffer -- a process which includes packing the transaction fields
* into the buffer, bit stuffing the buffer, NRZI encoding the buffer, and then performing any
* prerequisite, SIE-required actions to the in-buffer data.
*
* NOTE: Several #idef DEBUG_XXX statements are scattered throughout the file which are used for
* debugging over USART. Compilation with definition flags (-D THING_TO_DEFINE) will enable
* these USART debugging capabilities.
*
* NOTE: Sever #ifndef NO_AVR_GCC statements are also scattered throughout the file, using a
* precarious double negative. These statements intend to section off those portions of the USB
* Interface that cannot be compiled in a uniprocessor fashion. Most of these sections are in some
* way tied to Atmel 8-bit assembly code, which is used a great deal (and with great skill, thanks
* to Devrin "The Assembler" Talen) in the SIE.
*/
#ifndef _USB_INTERFACE_H
#define _USB_INTERFACE_H
/************/
/* INCLUDES */
/************/
#include <stdio.h>
#include <stdlib.h>
#include "usb_primitives.h"
#ifndef NO_AVR_GCC
# include <avr/io.h>
#endif
/***********/
/* DEFINES */
/***********/
#define USBPORT PORTA
#define USBPIN PINA
#define SIE_BUFFER_SIZE 16 // size of the SIE buffer length in bytes
typedef enum {PENDING, COMPLETED, CANCELED, NOTFILLED} TD_STATUS_T;
/***********/
/* STRUCTS */
/***********/
typedef struct SerialInterfaceEngine {
uint8_t *buffer; // of length SIE_BUFFER_SIZE
ENCODING_T buffer_encoding;
uint8_t token_packet_length; // in bits
uint8_t data_packet_length; // in bits
TRANSMISSION_DIRECTION_T data_direction;
PID_T *handshake_result;
} SIE_T;
typedef struct HostController {
TRANSACTION_NODE_T *transaction_queue_head;
TRANSACTION_NODE_T *transaction_queue_tail;
SIE_T *sie; // bound to a serial interface engine
uint8_t data_sequence_bit;
} HC_T;
/*********/
/* ENUMS */
/*********/
/***********/
/* GLOBALS */
/***********/
// None
// NOTE: this is a special include. Its goal is to reduce the length of this file by placing the
// long assembly code macros in a separate file, thus making this file more readable. The include
// is placed here so that the macros can use the includes, defines, and structs if need be.
#include "usb_sie_macros.c"
/**************/
/* PROTOTYPES */
/**************/
void transaction_pull_data_from_sie(TRANSACTION_T *transaction, SIE_T *sie);
// -------------------
// - HOST CONTROLLER -
// -------------------
HC_T *HostController();
void DestroyHostController(HC_T *hc);
void hc_bind_sie(HC_T *hc, SIE_T *sie);
SIE_T *hc_unbind_sie(HC_T *hc);
void hc_push_transaction(HC_T *hc, TRANSACTION_T *new_transaction);
TRANSACTION_T *hc_pop_transaction(HC_T *hc);
TRANSACTION_T *hc_do_transaction(HC_T *hc);
// ---------------------------
// - SERIAL INTERFACE ENGINE -
// ---------------------------
SIE_T *SerialInterfaceEngine();
void DestroySerialInterfaceEngine(SIE_T *sie);
// Setup functions: Operate on the buffers and do pre-processing.
void sie_bitstuff_buffer(SIE_T *sie);
void sie_bitunstuff_buffer(SIE_T *sie);
void sie_bitstuff_buffer_helper(SIE_T *sie, STUFF_METHOD_T stuff_method);
void sie_nrzi_encode_buffer(SIE_T *sie, uint8_t transient_first_state);
void sie_nrzi_decode_buffer(SIE_T *sie, uint8_t transient_first_state);
// Transfer functions: Affect the state of the output pins and work with the buffers.
void sie_idle(SIE_T *sie);
void sie_transfer(SIE_T *sie, TRANSFER_TYPE_T type);
void sie_control_transfer(SIE_T *sie);
void sie_interrupt_transfer(SIE_T *sie);
void sie_keepalive(SIE_T *sie);
void sie_reset(SIE_T *sie);
void sie_resume(SIE_T *sie);
uint8_t sie_detect_device(SIE_T *sie);
#endif