//
//  main.cpp
//  BrainStem2Example
//
/////////////////////////////////////////////////////////////////////
//                                                                 //
// Copyright (c) 2023 Acroname Inc. - All Rights Reserved          //
//                                                                 //
// This file is part of the BrainStem release. See the license.txt //
// file included with this package or go to                        //
// https://acroname.com/software/brainstem-development-kit         //
// for full license details.                                       //
/////////////////////////////////////////////////////////////////////

#include <iostream>
#include "BrainStem2/BrainStem-all.h"

using namespace Acroname::BrainStem::Utilities;

//Constants
static const int LOOPS = 25;
static const int SLEEP_TIME_MS = 250;

//Function prototypes.
static void printBS_PD_Packet(BS_PD_Packet_t& packet);
static void processPacketsOneAtATime(std::shared_ptr<PDChannelLogger> logger);
static void processMultiplePacketsAtATime(std::shared_ptr<PDChannelLogger> logger);


int main(int argc, const char * argv[]) {
    // Create an instance of the USBHub3p
    aUSBHub3c chub;
    aErr err = aErrNone;
    
    err = chub.discoverAndConnect(USB);
    if (err != aErrNone) {
        printf("Failed to connect to device. Error: %d Exiting\n", err);
        return 1;
    }
    else { printf("Connected to BrainStem module.\n"); }
    

    std::vector<std::shared_ptr<PDChannelLogger>> loggers;
    
    //Create a PDChannelLogger for each port and start them up.
    for (int port = 0; port <= aUSBHub3c::PORT_ID_t::kPORT_ID_POWER_C; port++) {
        std::shared_ptr<PDChannelLogger> logger = std::make_shared<PDChannelLogger>(&chub, port);
        err = logger->setEnabled(true); //Enable PD logging
        if (aErrPermission == err) {
            printf("This USBHub3c does not have the PD Logger Feature T99-PD-LOG\n");
            return err;
        }
                    
        loggers.push_back(std::move(logger)); //The logger object is not copyable. You must move it.
    }
    
    ///////////////////////////////////////
    //Single Packet Test:
    ///////////////////////////////////////
    //Attempt to trigger PD communication on every port.
    //Note: No traffic will occur if the devices does not support PD.
    for (int port = 0; port <= aUSBHub3c::PORT_ID_t::kPORT_ID_POWER_C; port++) {
        err = chub.pd[port].request(pdRequestRemoteSourceExtendedCapabilities);
    }
    aTime_MSSleep(2000); //Wait for messages to come in.
    for (auto & l : loggers) {
        printf("\n\nPort: %d\n", l->getIndex());
        processPacketsOneAtATime(l);
    }
    ///////////////////////////////////////
    
    
    ///////////////////////////////////////
    //Multiple Packet Test:
    ///////////////////////////////////////
    //Attempt to trigger PD communication on every port.
    //Note: No traffic will occur if the devices does not support PD.
    for (int port = 0; port <= aUSBHub3c::PORT_ID_t::kPORT_ID_POWER_C; port++) {
        err = chub.pd[port].request(pdRequestRemoteSourceExtendedCapabilities);
    }
    aTime_MSSleep(2000); //Wait for messages to come in.
    for (auto & l : loggers) {
        printf("\n\nPort: %d\n", l->getIndex());
        processMultiplePacketsAtATime(l);
        l->setEnabled(false); //Disable PD Logging
    }
    ///////////////////////////////////////
    
    
    loggers.clear();

    err = chub.disconnect();

    return 0;
}


//Generic packet print formatter.
void printBS_PD_Packet(BS_PD_Packet_t& packet) {
    printf(" - Channel: %d, Seconds: %d, uSeconds: %d, Direction: %d SOP: %d \nData: ",
           packet.channel, packet.seconds, packet.uSeconds, packet.direction, packet.sop);
    for(const auto& p : packet.payload) {
        printf("0x%02X ", p);
    }
    printf("\n");
}


//Get one packet at a time.
void processPacketsOneAtATime(std::shared_ptr<PDChannelLogger> logger) {
    printf("Getting packets one at a time.\n");
    BS_PD_Packet_t packet;
    while(aErrNone == logger->getPacket(packet)) {
        printBS_PD_Packet(packet);
    }
}


//Get all available packets in single call.
//Note: Packet count is limited up to the default parameter buffer_length
void processMultiplePacketsAtATime(std::shared_ptr<PDChannelLogger> logger) {
    printf("Getting all Packets at once\n");
    //Get available packets.
    std::vector<BS_PD_Packet_t> packets;
    if(aErrNone == logger->getPackets(packets)) {
        for (auto& p : packets) {
            printBS_PD_Packet(p);
        }
    }
}
