// --------------------------------------------------------------------
// Copyright (c) 2007 by Terasic Technologies Inc. 
// --------------------------------------------------------------------
//
// Permission:
//
//   Terasic grants permission to use and modify this code for use
//   in synthesis for all Terasic Development Boards and Altera Development 
//   Kits made by Terasic.  Other use of this code, including the selling 
//   ,duplication, or modification of any portion is strictly prohibited.
//
// Disclaimer:
//
//   This VHDL/Verilog or C/C++ source code is intended as a design reference
//   which illustrates how these types of functions can be implemented.
//   It is the user's responsibility to verify their design for
//   consistency and functionality through the use of formal
//   verification methods.  Terasic provides no warranty regarding the use 
//   or functionality of this code.
//
// --------------------------------------------------------------------
//           
//                     Terasic Technologies Inc
//                     356 Fu-Shin E. Rd Sec. 1. JhuBei City,
//                     HsinChu County, Taiwan
//                     302
//
//                     web: http://www.terasic.com/
//                     email: support@terasic.com
//
// --------------------------------------------------------------------
// Last Compile Tools: NIOS II 9.1 (Build 222)
/* Revision
 *  0709_2008
 *  USB Controller Update: 
 *      hold time: 10 ns
 *      setup time: 10 ns
 *      write time: 20 ns
 *      read time: 30 ns
 *      clock: 100 MHZ
 *  Add USB SCRATCH register read/write test
 * 
 */
#include <stdio.h>
#include <io.h>
#include "terasic_includes.h"
#include "terasic_usb_isp1761\usb_device\bulk_device.h"

#define err(x)  printf(x);



#define DEBUG_OUT(x)  {printf("[APP]"); printf x;}
#define DEBUG_ERR(x)  {printf("[APP_ERR]!!!"); printf x;}


#define OP_LED_SET      1
#define OP_BUTTON_GET   2

void welcome_led(void){
    
    const alt_u32 led_delay = 500*1000;    
    IOWR(PIO_LED_BASE,0, 0xFFFF00); // blue
    usleep(led_delay);
    IOWR(PIO_LED_BASE,0, 0xFF00FF); // green
    usleep(led_delay);
    IOWR(PIO_LED_BASE,0, 0x00FFFF); // red
    usleep(led_delay);
    IOWR(PIO_LED_BASE,0, 0xFFFFFF); // black
    usleep(led_delay);
    IOWR(PIO_LED_BASE,0, 0x000000); // while
    usleep(led_delay);
}    

//
#define DATAIN_LEN  4
#define DATAOUT_LEN  4
alt_u8 szBulkDataIn[DATAIN_LEN];
alt_u8 szBulkDataOut[DATAOUT_LEN];
BULK_HANDLE hBulk = 0;
void WriteButtonStatus(BULK_HANDLE hBulk);
void Notify_DeviceReady(void);
void Notify_DataIn(alt_u8 *pData, alt_u32 bytes);
void Notify_DataOutComplete(void);

void WriteButtonStatus(BULK_HANDLE hBulk){
    alt_u32 ButtonMask=0, Mask;
    Mask = IORD(PIO_BUTTON_BASE, 0);
    ButtonMask |= Mask & 0x0F;
    Mask = IORD(PIO_SLIDE_SWITCH_BASE, 0);
    ButtonMask |= (Mask << 4) & 0xF0;
    Mask = IORD(PIO_DIP_SWITCH_BASE, 0);
    ButtonMask |= (Mask << 8) & 0xFF00;
    memcpy(szBulkDataOut, &ButtonMask, sizeof(ButtonMask));
    BULK_Write(hBulk, szBulkDataOut, sizeof(szBulkDataOut));
}

void Notify_DeviceReady(void){
    DEBUG_OUT(("Device Ready\n"));
    if (!hBulk)
        return;
    BULK_Read(hBulk, szBulkDataIn, sizeof(szBulkDataIn));
    //WriteButtonStatus(hBulk);
}

void Notify_DataIn(alt_u8 *pData, alt_u32 bytes){
    DEBUG_OUT(("Data In, len=%d\n", (int)bytes));
    if (!hBulk)
        return;
    if (bytes == DATAIN_LEN){
        // update led
        alt_u8 OP;
        alt_u32 Command32;
        memcpy(&Command32, pData, sizeof(Command32));
        OP = (Command32 >> 24) & 0xFF;
        if (OP == OP_LED_SET){
            IOWR(PIO_LED_BASE, 0, Command32 & 0xFFFFFF); // dont return status
        }else if (OP == OP_BUTTON_GET){
            WriteButtonStatus(hBulk); // return status;
        }else{
            DEBUG_OUT(("Invalid OP\n"));
        }            
    }
    // issue next read command
    BULK_Read(hBulk, szBulkDataIn, sizeof(szBulkDataIn));
}

void Notify_DataOutComplete(void){
    
    DEBUG_OUT(("Data Out Complete\n"));
    if (!hBulk)
        return;
    
    //WriteButtonStatus(hBulk);
}


int main()
{
    BULK_NOTIFY Notify;
    
    welcome_led();
    DEBUG_OUT(("===== DE3 ISP1761 USB Device Demo [07/09/2008]=====\n"));
    Notify.DeviceReady = Notify_DeviceReady;
    Notify.DataIn = Notify_DataIn;
    Notify.DataOutComplete = Notify_DataOutComplete;
    
   // ISP1716_Init();
    hBulk = BULK_Open(Notify);
    
    if (hBulk){    
        while(1){
            BULK_Run();
        }
    }else{
        DEBUG_OUT(("Failed to init USB\n"));
    }        
    
    
    return 0;
    
    
}
