Subversion Repositories group.electronics

Rev

Rev 113 | Rev 115 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#include <lusb0_usb.h>
#include "SimConnect.h"


#define sbi(sfr, bit)   ((sfr) |= 1 << bit)
#define cbi(sfr, bit)   ((sfr) &= ~(1 << bit))
#define xbi(sfr, bit)   ((sfr) ^= 1 << bit)
#define rbi(sfr, bit)   (((sfr) >> (bit)) & 0x01)

// Same as in main.c
#define USB_STATE_READ  100
#define USB_LEDS_SET    101

// Console symbols
char* M_OUT = "  :<- "; // message outbound
char* M_IN = "->:   ";  // message inbound
char* M_NO = "  :   ";  // not a message
char* I_SP = " ";               // space
char* I_OK = "+";               // ignored, ok
char* I_NEX = "?";              // ignored, unexpected
char* I_EXE = "e";              // exception
char* X_SEP = "|";              // separator



#define         BUTTONS_COM1    0
#define         BUTTONS_COM2    1
#define         BUTTONS_BOTH    2
#define         BUTTONS_NAV1    3
#define         BUTTONS_NAV2    4
#define         BUTTONS_MKR     5
#define         BUTTONS_DME     6
#define         BUTTONS_ADF     7




static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName, int product, char *productName);
static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid, char *buf, int buflen);
void testCode(usb_dev_handle *handle);

void CALLBACK dispatchProc(SIMCONNECT_RECV *pData, DWORD cbData, void *pContext);

void Process_Exception(SIMCONNECT_RECV* pData);
void Process_Connected();
void Process_FSX_Quit();

char* Exception_String(DWORD Recv_Exception);
char* RECV_Msg_String(DWORD Recv_ID);
char* Format_SOL(char* Direction);
char* Format_SOL(char* Direction, char* Importance);

void Connect();
void Disconnect();


HANDLE  hSimConnect = NULL;
bool    keep_going = false;
bool    Paused = true;
char    string[80];
bool    updateLeds = true;
char    ledStatus = 0x00;
int             nBytes = 0;
char    buffer[16];

struct CommSelectData {
        double  comm1;
        double  comm2;
        double  commb;
        double  vor1;
        double  vor2;
        double  mkr;
        double  dme;
        double  adf;
};

static enum DATA_DEFINE_ID {
    DEFINITION_1,
};

static enum DATA_REQUEST_ID {
    REQUEST_1,
};



static enum EVENT_ID {
        EVENT_COM1_TRANSMIT_SELECT,
        EVENT_COM2_TRANSMIT_SELECT,
        EVENT_COM_RECEIVE_ALL_TOGGLE,
        EVENT_RADIO_VOR1_IDENT_TOGGLE,
        EVENT_RADIO_VOR2_IDENT_TOGGLE
        EVENT_MARKER_SOUND_TOGGLE,
        EVENT_RADIO_DME1_IDENT_TOGGLE,
        EVENT_RADIO_ADF_IDENT_TOGGLE,
};

static enum INPUT_ID {
    INPUT0,
};

static enum GROUP_ID {
    GROUP0,
};




int main(int argc, char **argv) {
        usb_dev_handle *handle = NULL;
    
    handle = usbOpenDevice(0x4242, "newioit.com.au", 0xe231, "Comm Selector");

    if(handle == NULL) {
            fprintf(stderr, "Could not find USB device\n");
            exit(1);
    }

        //testCode(handle);
        
        int i;
        for (i = 0; i < 15; i++) {
                buffer[i] = 0x00;
        }
        
        nBytes = usb_control_msg(handle,
                                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
                                        USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);      

        Connect();

        if (hSimConnect != NULL) {
                keep_going = true;

                unsigned int lastButtons = 0;

                while(keep_going)
        {
                        HRESULT hr;
                        
                        // Put this in an 'On Event' thing later...
                        //hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);
                        
                        nBytes = usb_control_msg(handle,
                                                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
                                                USB_STATE_READ, 0, 0, (char *)buffer, sizeof(buffer), 5000);
                        
                        unsigned int buttons = (unsigned int)buffer[1];
                        
                        
                        
                        for (i=-; i<7; i++) {
                                        if (rbi(buttons, i) && rbi(lastButtons, i) == 0) {
                                                sbi(lastButtons, i);
                                                hr = SimConnect_TransmitClientEvent(hSimConnect,0, i, 1 ,
                                                                SIMCONNECT_GROUP_PRIORITY_STANDARD,SIMCONNECT_EVENT_FLAG_GROUPID_IS_PRIORITY);
                                        }
                                        
                                        if (rbi(lastButtons, i) && ! rbi(buttons, i)
                                                cbi(lastButtons, i);
                        }

            SimConnect_CallDispatch(hSimConnect, dispatchProc, NULL);
            Sleep(1);
        }
        Disconnect();
    } else {
                // Implement retrying
        }


    usb_close(handle);

        return 0;
}

void Connect() {
        HRESULT hr;

        if (hSimConnect == NULL) {
                printf("\n%s Requesting a SimConnect connection", Format_SOL(M_OUT));
                hr = SimConnect_Open(&hSimConnect, "Comm Selector", NULL, 0, 0, 0);
                if (hr != S_OK) {
                        // FSX may be inactive, or there is a problem
                        printf("\n%s Error %d while opening a SimConnect connection", Format_SOL(M_IN, I_OK), hr);
                } else {
                        // Connection to FSX initialized
                        printf("\n%s Connection request being processed (%d)", Format_SOL(M_IN), hSimConnect);
                        // (When connection process completes, an OPEN message will be received)
                }
        }
}

void Disconnect() {
        HRESULT hr;

        if (hSimConnect != NULL) {
                if (hr = SimConnect_Close(hSimConnect) == S_OK) {
                        printf("\n%s Connection closed (%d).", Format_SOL(M_IN), hSimConnect);
                } else {
                        printf("\n%s Error (%d) while closing the connection (%d).", Format_SOL(M_IN, I_NEX), hr, hSimConnect);
                }               
        }

        printf("\n%s Resetting internal status to disconnected.", Format_SOL(M_NO));
        hSimConnect = NULL;
        keep_going = false;
}

void CALLBACK dispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void *pContext)
{
    switch(pData->dwID)
    {
        

                case SIMCONNECT_RECV_ID_QUIT:
                        // FSX is stopping
                        Process_FSX_Quit();
            break;

                case SIMCONNECT_RECV_ID_OPEN:
                        // the connection process is complete
                        Process_Connected();
                        break;

                case SIMCONNECT_RECV_ID_EVENT: {
                        SIMCONNECT_RECV_EVENT *evt = (SIMCONNECT_RECV_EVENT*)pData;
                        switch (evt->uEventID) {
                                default:
                                        break;
                        }
                        break;
                }

                case SIMCONNECT_RECV_ID_SIMOBJECT_DATA: {
                        SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;

                        switch(pObjData->dwRequestID) {
                                case REQUEST_1: {
                                        DWORD ObjectID = pObjData->dwObjectID;
                                        CommSelectData *ps = (CommSelectData*)&pObjData->dwData;
                                        
                                        hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, ObjectID, 
                                                                                                                   SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);

                                        setLed(ps->com1, &ledStatus, BUTTONS_COM1);
                                        setLed(ps->com2, &ledStatus, BUTTONS_COM2);
                                        setLed(ps->comb, &ledStatus, BUTTONS_COMB);
                                        setLed(ps->vor1, &ledStatus, BUTTONS_NAV1);
                                        setLed(ps->vor2, &ledStatus, BUTTONS_NAV2);
                                        setLed(ps->mkr, &ledStatus, BUTTONS_MKR);
                                        setLed(ps->dme, &ledStatus, BUTTONS_DME);
                                        setLed(ps->adf, &ledStatus, BUTTONS_ADF);
                                        
                                        nBytes = usb_control_msg(handle,
                                                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
                                                USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);

                                        printf("\nSIMOBJECT_DATA %d LED Update",  );
                                        break;
                                }
                        }
                        break;  
                }
                
                case SIMCONNECT_RECV_ID_SIMOBJECT_DATA_BYTYPE: {
                        SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE *pObjData = (SIMCONNECT_RECV_SIMOBJECT_DATA_BYTYPE*)pData;

                        switch(pObjData->dwRequestID) {
                                case REQUEST_1: {
                                        DWORD ObjectID = pObjData->dwObjectID;
                                        CommSelectData *pS = (CommSelectData*)&pObjData->dwData;
                                        
                                        hr = SimConnect_RequestDataOnSimObject(hSimConnect, REQUEST_1, DEFINITION_1, ObjectID, 
                                                                                                                   SIMCONNECT_PERIOD_SECOND, SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
                                        break;
                                }
                        }
                        break;
                }


                /* Not found
                case SIMCONNECT_RECV_ID_EVENT_WEATHER_MODE:
                case SIMCONNECT_RECV_ID_AIRPORT_LIST:
                case SIMCONNECT_RECV_ID_VOR_LIST:
                case SIMCONNECT_RECV_ID_NDB_LIST:
                case SIMCONNECT_RECV_ID_WAYPOINT_LIST:
                case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SERVER_STARTED:
                case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_CLIENT_STARTED:
                case SIMCONNECT_RECV_ID_EVENT_MULTIPLAYER_SESSION_ENDED:
                case SIMCONNECT_RECV_ID_EVENT_RACE_END:
                case SIMCONNECT_RECV_ID_EVENT_RACE_LAP: */

                case SIMCONNECT_RECV_ID_EXCEPTION:
        case SIMCONNECT_RECV_ID_EVENT_OBJECT_ADDREMOVE:
                case SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
                case SIMCONNECT_RECV_ID_ASSIGNED_OBJECT_ID:
                case SIMCONNECT_RECV_ID_EVENT_FILENAME:
                case SIMCONNECT_RECV_ID_EVENT_FRAME:
                case SIMCONNECT_RECV_ID_WEATHER_OBSERVATION:
                case SIMCONNECT_RECV_ID_CLOUD_STATE:
                case SIMCONNECT_RECV_ID_RESERVED_KEY:
                case SIMCONNECT_RECV_ID_CUSTOM_ACTION:
                case SIMCONNECT_RECV_ID_SYSTEM_STATE:
                case SIMCONNECT_RECV_ID_CLIENT_DATA:

                        printf("\n%s Message ignored (%s)", RECV_Msg_String(pData->dwID), Format_SOL(M_IN, I_OK));
                        break;
                default:
                        printf("\n%s Message ignored (Unknown RECV_ID)", Format_SOL(M_IN, I_NEX));
    }
}

void setLed(double value, char* ledS, int bit) {
        if (value)
                sbi(ledS, bit);
        else
                cbi(ledS, bit);
}

void Process_Exception(SIMCONNECT_RECV* pData) {
        // SimConnect cannot process a client request
        SIMCONNECT_RECV_EXCEPTION *except = (SIMCONNECT_RECV_EXCEPTION *) pData;
        printf("\n%s Exception %d on packet %d, argument %d. (%s)", Format_SOL(M_IN, I_EXE),
                except->dwException, except->dwSendID, except->dwIndex,
                Exception_String(except->dwException));
}

void Process_Connected() {
        printf("\n%s Connected.", Format_SOL(M_IN));

        EVENT_COM1_TRANSMIT_SELECT,
        EVENT_COM2_TRANSMIT_SELECT,
        EVENT_COM_RECEIVE_ALL_TOGGLE,
        EVENT_RADIO_VOR1_IDENT_TOGGLE,
        EVENT_RADIO_VOR2_IDENT_TOGGLE
        EVENT_MARKER_SOUND_TOGGLE,
        RADIO_DME1_IDENT_TOGGLE,
        RADIO_ADF_IDENT_TOGGLE, 
        
        HRESULT hr;
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM1_TRANSMIT_SELECT, "COM1_TRANSMIT_SELECT");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM2_TRANSMIT_SELECT, "COM2_TRANSMIT_SELECT");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_COM_RECEIVE_ALL_TOGGLE, "COM_RECEIVE_ALL_TOGGLE");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_VOR1_IDENT_TOGGLE, "RADIO_VOR1_IDENT_TOGGLE");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_VOR2_IDENT_TOGGLE, "RADIO_VOR2_IDENT_TOGGLE");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_MARKER_SOUND_TOGGLE, "MARKER_SOUND_TOGGLE");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_DME1_IDENT_TOGGLE, "RADIO_DME1_IDENT_TOGGLE");
        hr = SimConnect_MapClientEventToSimEvent(hSimConnect, EVENT_RADIO_ADF_IDENT_TOGGLE, "RADIO_ADF_IDENT_TOGGLE");

/*
        hr = SimConnect_AddClientEventToNotificationGroup(hSimConnect, GROUP0, EVENT_COM1_TRANSMIT_SELECT);
    hr = SimConnect_SetNotificationGroupPriority(hSimConnect, GROUP0, SIMCONNECT_GROUP_PRIORITY_HIGHEST);
*/

        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM TRANSMIT:1", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM TRANSMIT:2", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "COM RECIEVE ALL", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "NAV SOUND:1", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "NAV SOUND:2", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "MARKER SOUND", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "DME SOUND", "Bool");
        hr = SimConnect_AddToDataDefinition(hSimConnect, DEFINITION_1, "ADF SOUND:1", "Bool");
        
        hr = SimConnect_RequestDataOnSimObjectType(hSimConnect, REQUEST_1, DEFINITION_1, 0, SIMCONNECT_SIMOBJECT_TYPE_USER);


}

void Process_FSX_Quit() {
        // Stop sending commands to SimConnect
        keep_going = false;
}

char* Exception_String(DWORD Recv_Exception)
{
        // Names of Exceptions
        char* EXCEPTION_String[] =
        {
                "NONE", "ERROR", "SIZE_MISMATCH", "UNRECOGNIZED_ID", "UNOPENED", "VERSION_MISMATCH", "TOO_MANY_GROUPS",
                "NAME_UNRECOGNIZED", "TOO_MANY_EVENT_NAMES", "EVENT_ID_DUPLICATE", "TOO_MANY_MAPS",
                "TOO_MANY_OBJECTS", "TOO_MANY_REQUESTS", "WEATHER_INVALID_PORT", "WEATHER_INVALID_METAR",
                "WEATHER_UNABLE_TO_GET_OBSERVATION", "WEATHER_UNABLE_TO_CREATE_STATION",
                "WEATHER_UNABLE_TO_REMOVE_STATION", "INVALID_DATA_TYPE", "INVALID_DATA_SIZE",
                "DATA_ERROR", "INVALID_ARRAY", "CREATE_OBJECT_FAILED", "LOAD_FLIGHTPLAN_FAILED",
                "OPERATION_INVALID_FOR_OBJECT_TYPE", "ILLEGAL_OPERATION", "ALREADY_SUBSCRIBED", "INVALID_ENUM",
                "DEFINITION_ERROR", "DUPLICATE_ID", "DATUM_ID", "OUT_OF_BOUNDS", "ALREADY_CREATED",
                "OBJECT_OUTSIDE_REALITY_BUBBLE", "OBJECT_CONTAINER", "OBJECT_AI", "OBJECT_ATC", "OBJECT_SCHEDULE",
        };
        // Return "unknown" if out of bound
        return Recv_Exception > ARRAYSIZE(EXCEPTION_String) ? "unknown" : EXCEPTION_String[Recv_Exception];
}
// Format the beginning of the console line, one argument
char* Format_SOL(char* Direction)
{
        return Format_SOL(Direction, I_SP);
}
// Format the beginning of the console line, two arguments
char* Format_SOL(char* Direction, char* Importance)
{
        strcpy_s( string, Direction);
        strcat_s( string, Importance);
        strcat_s( string, X_SEP);
        return string;
}

// Returns the description of the message id
char* RECV_Msg_String(DWORD Recv_ID)
{
        // Names of RECV_ID (type of message to dispatch)
        char* RECV_ID_String[] =
        {
                "RECV_ID_EXCEPTION", "RECV_ID_OPEN", "RECV_ID_QUIT", "RECV_ID_EVENT",
                "RECV_ID_EVENT_OBJECT_ADDREMOVE", "RECV_ID_EVENT_FILENAME", "RECV_ID_EVENT_FRAME",
                "RECV_ID_SIMOBJECT_DATA", "RECV_ID_SIMOBJECT_DATA_BYTYPE",
                "RECV_ID_WEATHER_OBSERVATION", "RECV_ID_CLOUD_STATE", "RECV_ID_ASSIGNED_OBJECT_ID",
                "RECV_ID_RESERVED_KEY", "RECV_ID_CUSTOM_ACTION", "RECV_ID_SYSTEM_STATE",
                "RECV_ID_CLIENT_DATA", "RECV_ID_EVENT_WEATHER_MODE", "RECV_ID_AIRPORT_LIST",
                "RECV_ID_VOR_LIST", "RECV_ID_NDB_LIST", "RECV_ID_WAYPOINT_LIST",
                "RECV_ID_EVENT_MULTIPLAYER_SERVER_STARTED", "RECV_ID_EVENT_MULTIPLAYER_CLIENT_STARTED",
                "RECV_ID_EVENT_MULTIPLAYER_SESSION_ENDED", "RECV_ID_EVENT_RACE_END",
                "RECV_ID_EVENT_RACE_LAP",
        };
        // Return "unknown" if out of bound
        return Recv_ID > ARRAYSIZE(RECV_ID_String) ? "unknown" : RECV_ID_String[Recv_ID];
}


/*
 *      *** USB Functions ***
 */

static int usbGetDescriptorString(usb_dev_handle *dev, int index, int langid,
                                  char *buf, int buflen) {
    char buffer[256];
    int rval, i;

        // make standard request GET_DESCRIPTOR, type string and given index
    // (e.g. dev->iProduct)
        rval = usb_control_msg(dev,
        USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
        USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, langid,
        buffer, sizeof(buffer), 1000);

    if(rval < 0) // error
                return rval;

    // rval should be bytes read, but buffer[0] contains the actual response size
        if((unsigned char)buffer[0] < rval)
                rval = (unsigned char)buffer[0]; // string is shorter than bytes read

        if(buffer[1] != USB_DT_STRING) // second byte is the data type
                return 0; // invalid return type

        // we're dealing with UTF-16LE here so actual chars is half of rval,
        // and index 0 doesn't count
        rval /= 2;

        /* lossy conversion to ISO Latin1 */
        for(i = 1; i < rval && i < buflen; i++) {
                if(buffer[2 * i + 1] == 0)
                        buf[i-1] = buffer[2 * i];
                else
                        buf[i-1] = '?'; /* outside of ISO Latin1 range */
        }
        buf[i-1] = 0;

        return i-1;
}

static usb_dev_handle * usbOpenDevice(int vendor, char *vendorName,
                                      int product, char *productName) {
        struct usb_bus *bus;
        struct usb_device *dev;
        char devVendor[256], devProduct[256];

        usb_dev_handle * handle = NULL;

        usb_init();
        usb_find_busses();
        usb_find_devices();

        for(bus=usb_get_busses(); bus; bus=bus->next) {
                for(dev=bus->devices; dev; dev=dev->next) {

                        if(dev->descriptor.idVendor != vendor ||
                                dev->descriptor.idProduct != product)
                                continue;

                         /* we need to open the device in order to query strings */
                        if(!(handle = usb_open(dev))) {
                                fprintf(stderr, "Warning: cannot open USB device: %s\n",
                                usb_strerror());
                                continue;
                        }

                        /* get vendor name */
                        if(usbGetDescriptorString(handle, dev->descriptor.iManufacturer, 0x4242, devVendor, sizeof(devVendor)) < 0) {
                                fprintf(stderr, "Warning: cannot query manufacturer for device: %s\n", usb_strerror());
                                usb_close(handle);
                                continue;
                        }

                        /* get product name */
                        if(usbGetDescriptorString(handle, dev->descriptor.iProduct, 0xe231, devProduct, sizeof(devVendor)) < 0) {
                                fprintf(stderr, "Warning: cannot query product for device: %s\n", usb_strerror()); usb_close(handle);
                                continue;
                        }

                        if(strcmp(devVendor, vendorName) == 0 && strcmp(devProduct, productName) == 0)
                                return handle;
                        else
                                usb_close(handle);
                }
        }

        return NULL;
}

void testCode(usb_dev_handle *handle) {

        int nBytes = 0;
    char buffer[16];
        int i;
        for (i = 0; i < 15; i++) {
                buffer[i] = 0x00;
        }

        char ledStatus = 0;
        char keyIn = 0x00;

        // Return to old testing code
        printf("Press ESC to continue... (Or debug codes)\n");
        while (1) {
                keyIn = _getch();
                printf("Key: %02X\n", keyIn);
                if (keyIn == 0x1B || keyIn == 0x71) {
                        return;
                } else if (keyIn >= 0x31 && keyIn <= 0x38) {
                                char j = atoi(&keyIn);
                                xbi(ledStatus, (j-1) );                         
                                                
                                nBytes = usb_control_msg(handle,
                                                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
                                                USB_LEDS_SET, ledStatus, 0, (char *)buffer, sizeof(buffer), 5000);
                } else if(keyIn == 'r') {
                                nBytes = usb_control_msg(handle,
                                                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN,
                                                USB_STATE_READ, 0, 0, (char *)buffer, sizeof(buffer), 5000);
                        printf("Got %d bytes: %s\n", nBytes, buffer);
                        for (i = 0; i < 15; i++) {
                                if (i>0) printf(":");
                                printf("%02X",  buffer[i]);
                        }
                        printf("\n");
                }
                Sleep(1);
        }
}