
`include "usb_defs.v"
`include "uvc_defs.v"

module usb_control_handler(
    input               RESET_IN, // asynchronous positive reset
    input               PHY_CLKOUT, // USB phy clock (60MHz)

    input               SETUP_ACTIVE,
    input               USB_RXACT,
    input               USB_RXVAL,
    input   [7:0]       USB_RXDAT,
    input               USB_TXACT,
    input               USB_TXPOP,
    input   [3:0]       USB_ENDPT_SEL,

    output              ENDPT0_SEND,
    output  [7:0]       ENDPT0_DAT,
    output  [11:0]      ENDPT0_DAT_LEN

);


// Probe and commit control values, Video class
reg  [15:0] bmHint                  ;//short
reg  [ 7:0] bFormatIndex            ;//char
reg  [ 7:0] bFrameIndex             ;//char
reg  [31:0] dwFrameInterval         ;//int
reg  [31:0] dwFrameIntervalMinMax   ;//int
reg  [15:0] wKeyFrameRate           ;//short
reg  [15:0] wPFrameRate             ;//short
reg  [15:0] wCompQuality            ;//short
reg  [15:0] wCompWindowSize         ;//short
reg  [15:0] wDelay                  ;//short
reg  [31:0] dwMaxVideoFrameSize     ;//int
reg  [31:0] dwMaxVideoFrameSizeMinMax;//int
reg  [31:0] dwMaxPayloadTransferSize;//int
reg  [31:0] dwMaxPayloadTransferSizeMinMax;//int
reg  [31:0] dwClockFrequency        ;//int
reg  [31:0] dwClockFrequencyMinMax  ;//int
reg  [ 7:0] bmFramingInfo           ;//char
reg  [ 7:0] bPreferedVersion        ;//char
reg  [ 7:0] bMinVersion             ;//char
reg  [ 7:0] bMaxVersion             ;//char

reg  [ 7:0] bmRequestType; ///< Specifies direction of dataflow, type of rquest and recipient
reg  [ 7:0] bRequest     ; ///< Specifies the request
reg  [15:0] wValue       ; ///< Host can use this to pass info to the device in its own way
reg  [15:0] wIndex       ; ///< Typically used to pass index/offset such as interface or EP no
reg  [15:0] wLength      ; ///< Number of data bytes in the data stage (for Host -> Device this this is exact count, for Dev->Host is a max)
reg  [ 7:0] sub_stage    ;
reg  [ 7:0] stage        ;
reg  [ 7:0] endpt0_dat   ;
reg         endpt0_send  ;
reg  [11:0] endpt0_dat_len ;

assign ENDPT0_SEND = endpt0_send;
assign ENDPT0_DAT = endpt0_dat;
assign ENDPT0_DAT_LEN = endpt0_dat_len;


always @(posedge PHY_CLKOUT,posedge RESET_IN) begin
    if (RESET_IN) begin
        stage <= 8'd0;
        sub_stage <= 8'd0;
        endpt0_send <= 1'd0;
        endpt0_dat  <= 8'd0;
        bmRequestType <= 8'd0;
        bRequest      <= 8'd0;
        wValue        <= 16'd0;
        wIndex        <= 16'd0;
        wLength       <= 16'd0;
        bmHint                   <= 0;
        bFormatIndex             <= 8'h01;
        bFrameIndex              <= 8'h01;
        dwFrameInterval          <= `FRAME_INTERVAL;//333333;//`FRAME_INTERVAL;
        dwFrameIntervalMinMax    <= `FRAME_INTERVAL;//333333;//`FRAME_INTERVAL;
        wKeyFrameRate            <= 0;
        wPFrameRate              <= 0;
        wCompQuality             <= 0;
        wCompWindowSize          <= 0;
        wDelay                   <= 0;
        dwMaxVideoFrameSize      <= `MAX_FRAME_SIZE_PROBE;
        dwMaxVideoFrameSizeMinMax      <= `MAX_FRAME_SIZE_PROBE;
        dwMaxPayloadTransferSize <= /*32'd1024;*/ `PAYLOAD_SIZE;
        dwMaxPayloadTransferSizeMinMax <= /*32'd1024;*/ `PAYLOAD_SIZE;
        dwClockFrequency         <= 60000000;
        dwClockFrequencyMinMax         <= 60000000;
        bmFramingInfo            <= 0;
        bPreferedVersion         <= 0;
        bMinVersion              <= 0;
        bMaxVersion              <= 0;
    end
    else begin
        if (SETUP_ACTIVE) begin
            if (USB_RXVAL) begin
                case (stage)
                    8'd0 : begin
                        bmRequestType <= USB_RXDAT;
                        stage <= stage + 8'd1;
                        sub_stage <= 8'd0;
                        endpt0_send <= 1'd0;
                    end
                    8'd1 : begin
                        bRequest <= USB_RXDAT;
                        stage <= stage + 8'd1;
                    end
                    8'd2 : begin
                        wValue[7:0] <= USB_RXDAT;
                        stage <= stage + 8'd1;
                    end
                    8'd3 : begin
                        wValue[15:8] <= USB_RXDAT;
                        stage <= stage + 8'd1;
                    end
                    8'd4 : begin
                        stage <= stage + 8'd1;
                        wIndex[7:0] <= USB_RXDAT;
                    end
                    8'd5 : begin
                        stage <= stage + 8'd1;
                        wIndex[15:8] <= USB_RXDAT;
                    end
                    8'd6 : begin
                        if ((bRequest == `GET_CUR)||(bRequest == `GET_DEF)||(bRequest == `GET_MIN)||(bRequest == `GET_MAX)) begin
                        //if ((bRequest == `SET_CUR)||(bRequest == `GET_CUR)||(bRequest == `GET_DEF)) begin
                            if (wIndex[7:0] == 8'h01) begin //Video Steam Interface
                                if (wValue[15:8] == `VS_PROBE_CONTROL) begin
                                    endpt0_send <= 1'd1;
                                    endpt0_dat_len <= 8'd34;
                                end
                            end
                        end
                        wLength[7:0] <= USB_RXDAT;
                        stage <= stage + 8'd1;
                    end
                    8'd7 : begin
                        wLength[15:8] <= USB_RXDAT;
                        stage <= stage + 8'd1;
                        sub_stage <= 8'd0;
                    end
                    8'd8 : begin
                        ;
                    end
                endcase
            end
        end
        else if (bRequest == `SET_CUR) begin
            stage <= 8'd0;
            if (wIndex[7:0] == 8'h01) begin
                if (wValue[15:8] == `VS_PROBE_CONTROL) begin
                    if ((USB_RXACT)&&(USB_ENDPT_SEL == 4'd0)) begin
                        if (USB_RXVAL) begin
                            sub_stage <= sub_stage + 8'd1;
                            case (sub_stage)
                                8'd0 :
                                    bmHint[7:0] <= USB_RXDAT;
                                8'd1 :
                                    bmHint[15:8] <= USB_RXDAT;
                                8'd2 :
                                    bFormatIndex[7:0] <= USB_RXDAT;
                                8'd3 :
                                    bFrameIndex[7:0] <= USB_RXDAT;
                                8'd4 :
                                    dwFrameInterval[7:0]  <= USB_RXDAT;
                                8'd5 :
                                    dwFrameInterval[15:8] <= USB_RXDAT;
                                8'd6 :
                                    dwFrameInterval[23:16] <= USB_RXDAT;
                                8'd7 :
                                    dwFrameInterval[31:24] <= USB_RXDAT;
                                8'd8 :
                                    wKeyFrameRate[7:0] <= USB_RXDAT;
                                8'd9 :
                                    wKeyFrameRate[15:8] <= USB_RXDAT;
                                8'd10 :
                                    wPFrameRate[7:0] <= USB_RXDAT;
                                8'd11 :
                                    wPFrameRate[15:8]<= USB_RXDAT;
                                8'd12 :
                                    wCompQuality[7:0] <= USB_RXDAT;
                                8'd13 :
                                    wCompQuality[15:8] <= USB_RXDAT;
                                8'd14 :
                                    wCompWindowSize[7:0] <= USB_RXDAT;
                                8'd15 :
                                    wCompWindowSize[15:8] <= USB_RXDAT;
                                8'd16 :
                                    wDelay[7:0] <= USB_RXDAT;
                                8'd17 :
                                    wDelay[15:8] <= USB_RXDAT;
                                8'd18 :
                                    dwMaxVideoFrameSize[7:0]  <= USB_RXDAT;
                                8'd19 :
                                    dwMaxVideoFrameSize[15:8] <= USB_RXDAT;
                                8'd20 :
                                    dwMaxVideoFrameSize[23:16] <= USB_RXDAT;
                                8'd21 :
                                    dwMaxVideoFrameSize[31:24] <= USB_RXDAT;
                                8'd22 :
                                    ;//dwMaxPayloadTransferSize[7:0]  <= USB_RXDAT;
                                8'd23 :
                                    ;//dwMaxPayloadTransferSize[15:8] <= USB_RXDAT;
                                8'd24 :
                                    ;//dwMaxPayloadTransferSize[23:16] <= USB_RXDAT;
                                8'd25 :
                                    ;//dwMaxPayloadTransferSize[31:24] <= USB_RXDAT;
                                8'd26 :
                                    dwClockFrequency[7:0]  <= USB_RXDAT;
                                8'd27 :
                                    dwClockFrequency[15:8] <= USB_RXDAT;
                                8'd28 :
                                    dwClockFrequency[23:16] <= USB_RXDAT;
                                8'd29 :
                                    dwClockFrequency[31:24] <= USB_RXDAT;
                                8'd30 :
                                    bmFramingInfo[7:0] <= USB_RXDAT;
                                8'd31 :
                                    bPreferedVersion[7:0] <= USB_RXDAT;
                                8'd32 :
                                    bMinVersion[7:0] <= USB_RXDAT;
                                8'd33 :
                                    bMaxVersion[7:0] <= USB_RXDAT;
                                default : ;
                            endcase
                        end
                    end
                    else begin
                        sub_stage <= 8'd0;
                    end
                end
            end
        end
        //else if ((bRequest == `SET_CUR)||(bRequest == `GET_CUR)||(bRequest == `GET_DEF)) begin
        else if ((bRequest == `GET_CUR)||(bRequest == `GET_DEF)) begin
            stage <= 8'd0;
            if (wIndex[7:0] == 8'h01) begin
                if (wValue[15:8] == `VS_PROBE_CONTROL) begin
                    if ((USB_TXACT)&&(USB_ENDPT_SEL == 4'd0)) begin
                        if (endpt0_send == 1'b1) begin
                            if (USB_TXPOP) begin
                                sub_stage <= sub_stage + 8'd1;
                                if (sub_stage == 12'd33) begin
                                    endpt0_send <= 1'd0;
                                end
                                case (sub_stage)
                                    8'd0 :
                                        endpt0_dat <= bmHint[15:8];
                                    8'd1 :
                                        endpt0_dat <= bFormatIndex[7:0];
                                    8'd2 :
                                        endpt0_dat <= bFrameIndex[7:0];
                                    8'd3 :
                                        endpt0_dat <= dwFrameInterval[7:0];
                                    8'd4 :
                                        endpt0_dat <= dwFrameInterval[15:8];
                                    8'd5 :
                                        endpt0_dat <= dwFrameInterval[23:16];
                                    8'd6 :
                                        endpt0_dat <= dwFrameInterval[31:24];
                                    8'd7 :
                                        endpt0_dat <= wKeyFrameRate[7:0];
                                    8'd8 :
                                        endpt0_dat <= wKeyFrameRate[15:8];
                                    8'd9 :
                                        endpt0_dat <= wPFrameRate[7:0];
                                    8'd10 :
                                        endpt0_dat <= wPFrameRate[15:8];
                                    8'd11 :
                                        endpt0_dat <= wCompQuality[7:0];
                                    8'd12 :
                                        endpt0_dat <= wCompQuality[15:8];
                                    8'd13 :
                                        endpt0_dat <= wCompWindowSize[7:0];
                                    8'd14 :
                                        endpt0_dat <= wCompWindowSize[15:8];
                                    8'd15 :
                                        endpt0_dat <= wDelay[7:0];
                                    8'd16 :
                                        endpt0_dat <= wDelay[15:8];
                                    8'd17 :
                                        endpt0_dat <= dwMaxVideoFrameSize[7:0];
                                    8'd18 :
                                        endpt0_dat <= dwMaxVideoFrameSize[15:8];
                                    8'd19 :
                                        endpt0_dat <= dwMaxVideoFrameSize[23:16];
                                    8'd20 :
                                        endpt0_dat <= dwMaxVideoFrameSize[31:24];
                                    8'd21 :
                                        endpt0_dat <= dwMaxPayloadTransferSize[7:0];
                                    8'd22 :
                                        endpt0_dat <= dwMaxPayloadTransferSize[15:8];
                                    8'd23 :
                                        endpt0_dat <= dwMaxPayloadTransferSize[23:16];
                                    8'd24 :
                                        endpt0_dat <= dwMaxPayloadTransferSize[31:24];
                                    8'd25 :
                                        endpt0_dat <= dwClockFrequency[7:0];
                                    8'd26 :
                                        endpt0_dat <= dwClockFrequency[15:8];
                                    8'd27 :
                                        endpt0_dat <= dwClockFrequency[23:16];
                                    8'd28 :
                                        endpt0_dat <= dwClockFrequency[31:24];
                                    8'd29 :
                                        endpt0_dat <= bmFramingInfo[7:0];
                                    8'd30 :
                                        endpt0_dat <= bPreferedVersion[7:0];
                                    8'd31 :
                                        endpt0_dat <= bMinVersion[7:0];
                                    8'd32 :
                                        endpt0_dat <=  bMaxVersion[7:0];
                                    default : ;
                                endcase
                            end
                            else if (sub_stage == 8'd0) begin
                                endpt0_dat <= bmHint[7:0];
                            end
                        end
                    end
                    else begin
                        sub_stage <= 8'd0;
                    end
                end
            end
        end
        else if ((bRequest == `GET_MIN)||(bRequest == `GET_MAX)) begin

            stage <= 8'd0;
            if (wIndex[7:0] == 8'h01) begin
                if (wValue[15:8] == `VS_PROBE_CONTROL) begin
                    if ((USB_TXACT)&&(USB_ENDPT_SEL == 4'd0)) begin
                        if (endpt0_send == 1'b1) begin
                            if (USB_TXPOP) begin
                                sub_stage <= sub_stage + 8'd1;
                                if (sub_stage == 12'd33) begin
                                    endpt0_send <= 1'd0;
                                end
                                case (sub_stage)
                                    8'd0 :
                                        endpt0_dat <= 8'h00;
                                    8'd1 :
                                        endpt0_dat <= 8'h01;
                                    8'd2 :
                                        endpt0_dat <= 8'h01;
                                    8'd3 :
                                        endpt0_dat <= dwFrameIntervalMinMax[7:0];
                                    8'd4 :
                                        endpt0_dat <= dwFrameIntervalMinMax[15:8];
                                    8'd5 :
                                        endpt0_dat <= dwFrameIntervalMinMax[23:16];
                                    8'd6 :
                                        endpt0_dat <= dwFrameIntervalMinMax[31:24];
                                    8'd7 :
                                        endpt0_dat <= 8'h00;
                                    8'd8 :
                                        endpt0_dat <= 8'h00;
                                    8'd9 :
                                        endpt0_dat <= 8'h00;
                                    8'd10 :
                                        endpt0_dat <= 8'h00;
                                    8'd11 :
                                        endpt0_dat <= 8'h00;
                                    8'd12 :
                                        endpt0_dat <= 8'h00;
                                    8'd13 :
                                        endpt0_dat <= 8'h00;
                                    8'd14 :
                                        endpt0_dat <= 8'h00;
                                    8'd15 :
                                        endpt0_dat <= 8'h00;
                                    8'd16 :
                                        endpt0_dat <= 8'h00;
                                    8'd17 :
                                        endpt0_dat <= dwMaxVideoFrameSizeMinMax[7:0];
                                    8'd18 :
                                        endpt0_dat <= dwMaxVideoFrameSizeMinMax[15:8];
                                    8'd19 :
                                        endpt0_dat <= dwMaxVideoFrameSizeMinMax[23:16];
                                    8'd20 :
                                        endpt0_dat <= dwMaxVideoFrameSizeMinMax[31:24];
                                    8'd21 :
                                        endpt0_dat <= dwMaxPayloadTransferSizeMinMax[7:0];
                                    8'd22 :
                                        endpt0_dat <= dwMaxPayloadTransferSizeMinMax[15:8];
                                    8'd23 :
                                        endpt0_dat <= dwMaxPayloadTransferSizeMinMax[23:16];
                                    8'd24 :
                                        endpt0_dat <= dwMaxPayloadTransferSizeMinMax[31:24];
                                    8'd25 :
                                        endpt0_dat <= dwClockFrequencyMinMax[7:0];
                                    8'd26 :
                                        endpt0_dat <= dwClockFrequencyMinMax[15:8];
                                    8'd27 :
                                        endpt0_dat <= dwClockFrequencyMinMax[23:16];
                                    8'd28 :
                                        endpt0_dat <= dwClockFrequencyMinMax[31:24];
                                    8'd29 :
                                        endpt0_dat <= 8'h00;
                                    8'd30 :
                                        endpt0_dat <= 8'h00;
                                    8'd31 :
                                        endpt0_dat <= 8'h00;
                                    8'd32 :
                                        endpt0_dat <=  8'h00;
                                    default : ;
                                endcase
                            end
                            else if (sub_stage == 8'd0) begin
                                endpt0_dat <= 8'h00;
                            end
                        end
                    end
                    else begin
                        sub_stage <= 8'd0;
                    end
                end
            end
        end
                 
        else begin
             stage <= 8'd0;
             sub_stage <= 8'd0;
        end
    end
end

endmodule

