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