// usb_primitives.h
// BCD -- Ben Hutton, Chris Leary, Devrin Talen
// 100-column width


/*
 * NOTE: On the use of fixed-width integer types
 *
 * As many specification-guzzling C programmers will know, fixed width integer types are defined by
 * the C99 standard, but not (individually) required. To quote from the ISO C99 standard:
 *
 *      These types are optional. However, if an implementation provides integer types with widths
 *      of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two's
 *      complement representation, it shall define the corresponding typedef names.
 *
 * For this reason the use of fixed width integer types is frowned upon by some members of the C 
 * community. Opting for fixed-width types in this application was a result of requiring fixed-width
 * types in one portion of the application (which involved a nibble lookup table), without which
 * the algorithm would have been terribly un-optimized.
 *
 */


#ifndef _USB_PRIMITIVES_H
#define _USB_PRIMITIVES_H


/************/
/* INCLUDES */
/************/


#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <inttypes.h>
#include <string.h>

// if NO_AVR_GCC is defined at compile time, these libraries will be excluded
#ifndef NO_AVR_GCC 
#   include <avr/io.h>
    // the following definition is necessary for delay.h to quit yammerin' about not knowing the 
    // CPU speed
#   ifndef F_CPU
#       define F_CPU 15000000UL
#   endif
#   include <avr/delay.h>
#endif


/***********/
/* DEFINES */
/***********/


#define PID_BITS 8
#define ADDR_BITS 7
#define ENDP_BITS 4
#define CRC5_BITS 5
#define CRC16_BITS 16
#define TOKEN_PACKET_SIZE ((PID_BITS + ADDR_BITS + ENDP_BITS + CRC5_BITS) >> 3)
#define BASE_DATA_PACKET_SIZE ((PID_BITS + CRC16_BITS) >> 3)
#define CHAR_BITS (sizeof(char) * 8)
#define INT_BITS (sizeof(int) * 8)


/***********/
/* GLOBALS */
/***********/


extern const uint8_t nibble_mirror[];
extern uint8_t print_buffer[];


/*********/
/* ENUMS */
/*********/


typedef enum { UNENCODED, NRZI } ENCODING_T;
typedef enum { TRANSMIT=0, RECEIVE=1, BIDIRECTIONAL=2 } TRANSMISSION_DIRECTION_T;
typedef enum { CONTROL=0, INTERRUPT=1 } TRANSFER_TYPE_T;
typedef enum { MESSAGE, STREAM_IN, STREAM_OUT } PIPE_TYPE_T;

//HID is fake
typedef enum {
    DEVICE=0x1, CONFIGURATION=0x2, INTERFACE=0x4, ENDP=0x5, STRING=0x3, HID=0xf
} DESCRIPTOR_TYPE_T;

typedef enum
// NOTE: since PRE and ERR have the same hex value, we have to combine them into one
// enum item so that switch statements can compile without a duplicate value error
{
    OUT = 0x87, IN = 0x96, SETUP = 0xb4, // token group
    DATA0 = 0xc3, DATA1 = 0xd2, DATA2 = 0xe1, MDATA = 0xf0, // data group
    UNDETERMINED = 0x00, ACK = 0x4b, NAK = 0x5a, STALL = 0x78, NYET = 0x69, // handshake
    PRE_ERR = 0x3c, SPLIT = 0x1e, PING = 0x2d // special group
} PID_T;

typedef enum { STUFF, UNSTUFF } STUFF_METHOD_T;

/***********/
/* STRUCTS */
/***********/


struct PtrNode
// A doubly linked list node that wraps a pointer
{
    void *ptr;
    struct PtrNode *prev;
    struct PtrNode *next;
};


/*
typedef struct TransferDescriptor
{
    // If False, you need an exact amount of data to fill the buffer. If True, then the last data 
    // packet may be smaller than the defined buffer without causing an error condition on the TD.
    BOOL_T buffer_rounding;

    // Two bit field that indicates the direction of data flow and the PID to be used for the token.
    // This field is only relevant to the HC if the D field in the ED was set to 00b or 11b 
    // indicating that the PID determination is deferred to the TD.
    // NOTE: altered from 2-bit field length.
    PID_T direction_pid;

    // Contains the interrupt delay count for this TD. When a TD is complete the HC may wait for 
    // delay_interrupt frames before generating an interrupt. If DelayInterrupt is 111b, then there 
    // is no interrupt associated with completion of this TD.
    uint8_t delay_interrupt;

    // Two bit field used to generate/compare the data PID value (DATA0 or DATA1). It is updated
    // after each successful transmission/reception of a data packet. The MSb of this field is '0'
    // when the data toggle value is acquired from the toggle_carry fieldin the ED and '1' when the 
    // data toggle value is taken from the LSb of this field.
    uint8_t data_toggle;

    // For each transmission error, this value is incremented. If error_count is 2 and another error
    // occurs, the error type is recorded in the ConditionCode field and placed on the done queue.
    // When a transaction completes without error, ErrorCount is reset to 0.
    uint8_t error_count;

    // Contains the status of the last attempted transaction.
    uint8_t condition_code;

    // Contains the physical address of the next memory location that will be accessed for transfer 
    // to/from the endpoint. A value of 0 indicates a zero-length data packet or that all bytes have
    // been transferred.
    uint8_t *current_buffer_pointer;

    // Contains the address of the last byte in the buffer for this TD.
    uint8_t *buffer_end;

    struct TransferDescriptor *prev;
    struct TransferDescriptor *next;
} TD_T;


typedef struct EndpointDescriptor
{
    // USB address of the function containing the endpoint that this ED controls
    uint8_t function_address;

    // USB address of the endpoint within the function
    uint8_t endpoint_number;

    // MISSING: endp direction

    // Indicates the speed of the endpoint: full-speed (S=0), low-speed (S=1)
    SPEED_T speed;

    // When this bit is set, the HC continues on to the next ED on the list without attempting 
    // access to the TD queue or issuing any USB token for the endpoint
    BOOL_T skip;

    // MISSING: format

    // Indicates the maximum number of bytes that can be sent to or received from the endpoint in a 
    // single data packet
    uint16_t maximum_packet_size;

    // The data toggle carry bit. Whenever a TD is retired, this bit is written to contain the last 
    // data toggle value (LSB of data toggle field) from the retired TD.
    BOOL_T toggle_carry;

    // Bit set by the HC to indicate that processing of the TD queue on the endpoint is halted, 
    // usually due to an error in processing a TD.
    BOOL_T halted;

    // Points to the next TD to be processed for this endpoint (if not NULL).
    TD_T *head;
    TD_T *tail;

    struct EndpointDescriptor *prev;

    // Points to next ED in the list, if not NULL.
    struct EndpointDescriptor *next;
} ED_T;

*/



// -----------
// - PACKETS -
// -----------


typedef struct TokenPacket
// 8 + 7 + 4 + 5 = 24 bits (3 bytes) in buffer
{
    PID_T pid;
    uint8_t addr;
    uint8_t endp;
    uint8_t crc5;
} TOKEN_PACKET_T;


typedef struct DataPacket
// 8 + 64 + 16 = 88 bits max (11 bytes max) in buffer; 3 bytes minimum
{
    PID_T pid;
    uint8_t *data; // 8 bytes (max) -- NOTE: according to spec, must be integral num bytes
    uint16_t crc16;
    size_t payload_size; // in bytes -- NOTE: this field is not actually transmitted on the bus
} DATA_PACKET_T;


// ----------------
// - TRANSACTIONS -
// ----------------


typedef struct PtrNode TRANSACTION_NODE_T;


typedef struct Transaction
// One of the fundamental types of the USB protocol, consisting of a transfer type (control, 
// interrupt), a mandatory token packet and an optional data packet. The handshake is undetermined
// upon creation, and is specified when it becomes available.
{
    TRANSFER_TYPE_T transfer_type;
    TOKEN_PACKET_T *token_packet;
    DATA_PACKET_T *data_packet;
    PID_T handshake;
} TRANSACTION_T;


// ---------------
// - Descriptors -
// ---------------


typedef struct UsbDeviceDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    uint16_t bcd_usb;
    uint8_t b_device_class;
    uint8_t b_device_subclass;
    uint8_t b_device_protocol;
    uint8_t b_max_packet_size;
    uint16_t id_vendor;
    uint16_t id_product;
    uint16_t bcd_device;
    uint8_t i_manufacturer;
    uint8_t i_product;
    uint8_t i_serial_number;
    uint8_t b_num_configurations;
} USB_DEVICE_DESCRIPTOR_T;


typedef struct UsbConfigurationDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    uint16_t w_total_length;
    uint8_t b_num_interfaces;
    uint8_t b_configuration_value;
    uint8_t i_configuration;
    uint8_t bm_attributes;
    uint8_t b_max_power;
} USB_CONF_DESCRIPTOR_T;


typedef struct UsbInterfaceDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    uint8_t b_interface_number;
    uint8_t b_alternate_setting;
    uint8_t b_num_endp;
    uint8_t b_if_class;
    uint8_t b_if_subclass;
    uint8_t b_if_protocol;
    uint8_t i_if;
} USB_IF_DESCRIPTOR_T;


typedef struct UsbEndpointDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    uint8_t b_endp_address;
    uint8_t bm_attribute;
    uint16_t w_max_packet_size;
    uint8_t b_interval;
} USB_ENDP_DESCRIPTOR_T; // 8 bytes


typedef struct UsbFirstStringDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    uint16_t w_langid0;
    uint16_t w_langid1;
    uint16_t w_langid2;
} USB_FIRST_STRING_DESCRIPTOR_T; // 9 bytes


typedef struct UsbStringDescriptor
{
    uint8_t b_length;
    DESCRIPTOR_TYPE_T b_descriptor_type;
    char *b_string; // TODO: eventually, should be unicode
} USB_STRING_DESCRIPTOR_T; // 4 bytes


/**************/
/* PROTOTYPES */
/**************/

uint16_t bitstuff_buffer(uint8_t **buf_ptr, uint16_t buf_used_bit_len, STUFF_METHOD_T stuff_method);

// -----------
// - PACKETS -
// -----------


TOKEN_PACKET_T *TokenPacket(PID_T pid, uint8_t addr, uint8_t endp);
void DestroyTokenPacket(TOKEN_PACKET_T *token_packet);
DATA_PACKET_T *DataPacket(PID_T pid, size_t payload_size);
void DestroyDataPacket(DATA_PACKET_T *data_packet);


void packet_make_crc5(TOKEN_PACKET_T *token_packet);
uint8_t packet_validate_crc5(TOKEN_PACKET_T *token_packet);
uint16_t make_crc5(uint16_t input, uint8_t bit_count);
void packet_make_crc16(DATA_PACKET_T *data_packet);
uint8_t packet_validate_crc16(DATA_PACKET_T *data_packet);
uint16_t make_crc16(uint8_t* input, uint16_t bit_count);


// ----------------
// - TRANSACTIONS -
// ----------------


TRANSACTION_T *Transaction(TRANSFER_TYPE_T transfer_type, TOKEN_PACKET_T *tp, DATA_PACKET_T *dp);
void DestroyTransaction(TRANSACTION_T *transaction);
void DestroyWholeTransaction(TRANSACTION_T *transaction);
TRANSACTION_NODE_T *TransactionNode(TRANSACTION_T *trans, TRANSACTION_NODE_T *prev,
                                    TRANSACTION_NODE_T *next);
void DestroyTransactionNode(TRANSACTION_NODE_T *transaction_node);


inline uint8_t flip_byte(uint8_t original_byte, uint8_t relevant_bits);
void transaction_place_in_buffer(TRANSACTION_T *transaction, uint8_t *buffer,
                                 uint8_t *token_packet_length, uint8_t *data_packet_length);
void transaction_place_in_buffer_helper(uint8_t *buffer, uint8_t *data, uint16_t data_bits,
                                        uint8_t *buf_byte, uint8_t *buf_bit);


// ---------
// - DEBUG -
// ---------

void send_debug();

#endif