main.c #include USBusb.h #include USBusb_function_midi.h #include p18f2550.h #include delays.h #include stdio.h #include usart.h #include config.h configuration bits void setup_usart(void); void process_midi_in(BYTE); #pragma udata USB_VARIABLES=0x500 unsigned char ReceivedDataBuffer[64]; USB_AUDIO_MIDI_EVENT_PACKET midiData; #pragma udata USB_HANDLE USBRxHandle = 0; USB_HANDLE USBTxHandle = 0; #pragma interrupt YourHighPriorityISRCode void YourHighPriorityISRCode() { USBDeviceTasks(); } #pragma code int size_of_cin[] = { 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1 }; #define QUEUE_SIZE (60) typedef struct { int head; int tail; BYTE buffer[QUEUE_SIZE]; } queue_t; int enqueue(BYTE ch, queue_t queue) { int next_tail = (queue-tail + 1) % QUEUE_SIZE; if (next_tail == queue-head) return -1; queue-buffer[queue-tail] = ch; queue-tail = next_tail; return 0; } BYTE dequeue(queue_t queue) { BYTE ch = queue-buffer[queue-head]; queue-head = (queue-head + 1) % QUEUE_SIZE; return ch; } int is_empty(queue_t queue) { return queue-head == queue-tail; } void init_queue(queue_t queue) { queue-head = queue-tail = 0; } typedef struct { int head; int tail; DWORD buffer[QUEUE_SIZE]; } dw_queue_t; int enqueue_dw(DWORD ch, dw_queue_t queue) { int next_tail = (queue-tail + 1) % QUEUE_SIZE; if (next_tail == queue-head) return -1; queue-buffer[queue-tail] = ch; queue-tail = next_tail; return 0; } DWORD dequeue_dw(dw_queue_t queue) { DWORD ch = queue-buffer[queue-head]; queue-head = (queue-head + 1) % QUEUE_SIZE; return ch; } int is_empty_dw(dw_queue_t queue) { return queue-head == queue-tail; } void init_queue_dw(dw_queue_t queue) { queue-head = queue-tail = 0; } queue_t midi_out_queue; = { 0, 0, {0} }; queue_t midi_in_queue; = { 0, 0, {0} }; #pragma udata MIDI_IN_QUEUE=0x700 dw_queue_t midi_in_queue; = { 0, 0, {0} }; #pragma code void put(char ch) { while(BusyUSART()); WriteUSART(ch); } void main(void) { char msg[17]; USB_AUDIO_MIDI_EVENT_PACKET midi_datum; int size, i; TRISA = 0; TRISB = 0; PORTC = 0; TRISC = 0; ADCON1 = 0b1111; INTCON = 0; CMCON = 0x07; init_queue(&midi_out_queue); init_queue_dw(&midi_in_queue); setup_usart(); PORTAbits.RA0 = 1; USBDeviceAttach(); USBDeviceInit(); while(1) { USBDeviceTasks(); if((USBDeviceState CONFIGURED_STATE)(USBSuspendControl==1)) continue; if(!USBHandleBusy(USBRxHandle)) { midi_datum = (USB_AUDIO_MIDI_EVENT_PACKET)&ReceivedDataBuffer; size = size_of_cin[midi_datum-CodeIndexNumber]; for (i = 0; i size; i++) { enqueue(midi_datum-v[i+1], &midi_out_queue); } USBRxHandle = USBRxOnePacket(1,(BYTE)&ReceivedDataBuffer,64); enqueue_dw(midi_datum-Val, &midi_in_queue); } if (DataRdyUSART()) { process_midi_in(ReadUSART()); } if (!is_empty(&midi_out_queue) && !BusyUSART()) { BusyUSART sees TRMT put(dequeue(&midi_out_queue)); put data to TXREG } if (!is_empty_dw(&midi_in_queue) && !USBHandleBusy(USBTxHandle)) { PORTAbits.RA0 = 0; midiData.Val = dequeue_dw(&midi_in_queue); midiData.CableNumber = 0; USBTxHandle = USBTxOnePacket(1, (BYTE)&midiData, 4); PORTAbits.RA0 = 1; } } } #define is_status_byte(ch) ((ch) & 0b10000000) #define is_channel_message(ch) ((ch) = 0x90 && (ch) 0xf0) BYTE cin_of_system_message[] = { MIDI_CIN_SYSEX_START, MIDI_CIN_MTC, MIDI_CIN_SSP, MIDI_CIN_SONG_SELECT, 0, 0, MIDI_CIN_1_BYTE_MESSAGE, 0, MIDI_CIN_SINGLE_BYTE, 0, MIDI_CIN_SINGLE_BYTE, MIDI_CIN_SINGLE_BYTE, MIDI_CIN_SINGLE_BYTE, 0, MIDI_CIN_SINGLE_BYTE, MIDI_CIN_SINGLE_BYTE }; BYTE cin_of_status_byte(BYTE ch) { if (is_channel_message(ch)) return ch 16; else return cin_of_system_message[ch - 0xf0]; } void process_midi_in(BYTE ch) { static USB_AUDIO_MIDI_EVENT_PACKET midi_datum; static int current_size = 0; int size, i; if (is_status_byte(ch)) { midi_datum.Val = 0; midi_datum.CodeIndexNumber = cin_of_status_byte(ch); midi_datum.CableNumber = 0; midi_datum.DATA_0 = ch; current_size = 1; } else { if (current_size == 0) current_size++; midi_datum.v[current_size + 1] = ch; current_size++; } if (current_size == size_of_cin[midi_datum.CodeIndexNumber]) { enqueue_dw(midi_datum.Val, &midi_in_queue); current_size = 0; } } BOOL USER_USB_CALLBACK_EVENT_HANDLER(USB_EVENT event, void pdata, WORD size) { switch(event) { case EVENT_CONFIGURED USBEnableEndpoint(1,USB_OUT_ENABLEDUSB_IN_ENABLEDUSB_HANDSHAKE_ENABLEDUSB_DISALLOW_SETUP); USBEnableEndpoint(1,USB_OUT_ENABLEDUSB_HANDSHAKE_ENABLEDUSB_DISALLOW_SETUP); USBRxHandle = USBRxOnePacket(1,(BYTE)&ReceivedDataBuffer,64); break; case EVENT_SET_DESCRIPTOR case EVENT_EP0_REQUEST case EVENT_SOF case EVENT_SUSPEND case EVENT_RESUME case EVENT_BUS_ERROR case EVENT_TRANSFER default break; } return TRUE; } void setup_usart(void) { RCSTAbits.SPEN = 1; RCSTAbits.RX9 = 0; RCSTAbits.CREN = 1; TXSTAbits.TX9 = 0; TXSTAbits.TXEN = 1; TXSTAbits.SYNC = 0; TXSTAbits.BRGH = 0; BAUDCONbits.BRG16 = 0; SPBRG = 23; } config.h #pragma config PLLDIV = 5 Divide by 5 (20 MHz oscillator input) #pragma config USBDIV = 2 USB clock source comes from the 96 MHz PLL divided by 2 #pragma config CPUDIV = OSC1_PLL2 96 MHz PLL Src 2 #pragma config FOSC = HSPLL_HS HS oscillator, PLL enabled, HS used by USB #pragma config FCMEN = OFF Fail-Safe Clock Monitor disabled #pragma config IESO = OFF Oscillator Switchover mode disabled #pragma config PWRT = OFF PWRT enabled #pragma config BOR = ON Brown-out Reset enabled in hardware only (SBOREN is disabled) #pragma config BORV = 3 Minimum setting #pragma config VREGEN = ON USB voltage regulator enabled #pragma config WDT = OFF HW Disabled - SW Controlled #pragma config WDTPS = 32768 #pragma config MCLRE = ON MCLR pin enabled; RE3 input pin disabled #pragma config LPT1OSC = OFF Timer1 configured for higher power operation #pragma config PBADEN = ON PORTB40 pins are configured as analog input channels on Reset #pragma config CCP2MX = ON CCP2 inputoutput is multiplexed with RB3 #pragma config STVREN = ON Stack fullunderflow will cause Reset #pragma config LVP = OFF Single-Supply ICSP disabled #pragma config XINST = OFF Instruction set extension and Indexed Addressing mode disabled (Legacy mode) #pragma config DEBUG = OFF Background debugger disabled, RB6 and RB7 configured as general purpose IO pins #pragma config CP0 = OFF #pragma config CP1 = OFF #pragma config CP2 = OFF #pragma config CP3 = OFF #pragma config CPB = OFF #pragma config CPD = OFF #pragma config WRT0 = OFF #pragma config WRT1 = OFF #pragma config WRT2 = OFF #pragma config WRT3 = OFF #pragma config WRTB = OFF #pragma config WRTC = OFF #pragma config WRTD = OFF #pragma config EBTR0 = OFF #pragma config EBTR1 = OFF #pragma config EBTR2 = OFF #pragma config EBTR3 = OFF #pragma config EBTRB = OFF usb_config.h #ifndef USB_CONFIG_H #define USB_CONFIG_H #define USB_SUPPORT_DEVICE #define USB_PING_PONG_MODE USB_PING_PONG__FULL_PING_PONG #define USB_MAX_EP_NUMBER (4) #define USB_MAX_NUM_INT (3) #define USB_EP0_BUFF_SIZE (8) #define USB_PULLUP_OPTION USB_PULLUP_ENABLE #define USB_TRANSCEIVER_OPTION USB_INTERNAL_TRANSCEIVER #define USB_SPEED_OPTION USB_FULL_SPEED #define USB_NUM_STRING_DESCRIPTORS (3) #define USB_POLLING #endif USB_CONFIG_H HardwareProfile.h #ifndef HARDWARE_PROFILE_H #define HARDWARE_PROFILE_H #define self_power (1) #define USB_BUS_SENSE (1) #endif HARDWARE_PROFILE_H