/*
 *  ======== perfChangeNotifyFxn ========
 *
 *  Called by Power module before and after performance level is changed.
 */
static int perfChangeNotifyFxn(unsigned int eventType, uintptr_t eventArg,
    uintptr_t clientArg)
{
    uint32_t                  clockFreq;
    PowerMSP432_Freqs         powerFreqs;
    UARTMSP432_Object        *object = ((UART_Handle) clientArg)->object;
    UARTMSP432_HWAttrs const *hwAttrs = ((UART_Handle) clientArg)->hwAttrs;

    if (eventType == PowerMSP432_START_CHANGE_PERF_LEVEL) {
        /* Disable peripheral before performance level change */
        MAP_UART_disableModule(hwAttrs->baseAddr);
    }
    else { /* eventType == PowerMSP432_DONE_CHANGE_PERF_LEVEL */
        /* Get new performance level clock frequencies */
        PowerMSP432_getFreqs((unsigned int) eventArg, &powerFreqs);
        clockFreq = (hwAttrs->clockSource == EUSCI_A_UART_CLOCKSOURCE_SMCLK) ?
            powerFreqs.SMCLK : powerFreqs.ACLK;

        /* Reconfigure UART peripheral */
        initHw(object, hwAttrs, clockFreq);
    }

    return (Power_NOTIFYDONE);
}
int main(void)
{
   // uint8_t* udpData;
    uint8_t* tcpData;
    uint8_t p=0;
    uint16_t i=0;
    Seq_number=0xfb0983f7;
    Ack_number=0x00000;
    myport=0xb921;
    id=0x1229;
    uint8_t* http;

    // init controller
    initHw();

    putsUart0("\r\nWeather forecast\r\n");
    // init ethernet interface
    etherInit(ETHER_UNICAST | ETHER_BROADCAST | ETHER_HALFDUPLEX);
    etherSetIpAddress(192,168,137,199);

    // flash phy leds
    etherWritePhy(PHLCON, 0x0880);
    RED_LED = 1;

    waitMicrosecond(500000);
    etherWritePhy(PHLCON, 0x0990);
    RED_LED = 0;
    waitMicrosecond(500000);

    sendSynWeather(data);

    // message loop
    while (1)
    {
        if (etherKbhit())
        {
            if (etherIsOverflow())
            {
                RED_LED = 1;
                waitMicrosecond(100000);
                RED_LED = 0;
            }
            // get packet
            etherGetPacket(data, 1500);
            // handle arp request

            if (etherIsArp(data))
            {
                etherSendArpResp(data);
                RED_LED = 1;
               // GREEN_LED = 1;
                waitMicrosecond(50000);
                RED_LED = 0;
                GREEN_LED = 0;
            }

            // handle ip datagram

            if (etherIsIp(data))
            {
            	if (etherIsIpUnicast(data))
            	{
            		// handle icmp ping request

            		if (etherIsPingReq(data))
					{
					  etherSendPingResp(data);
					  GREEN_LED = 1;
					  waitMicrosecond(50000);
					  GREEN_LED = 0;

					}

					if(etherIsTcp(data))
					{
						tcpData = etherGetTcpData(data);
						if(etherisHandshake1(data))
						{
							etherRespondtoHandshake1(data);
							RED_LED = 1;
							//GREEN_LED=1;
							BLUE_LED=1;
							waitMicrosecond(100000);
							RED_LED = 0;
							//GREEN_LED=0;
							BLUE_LED=0;
							break;
						}

					}


                }
            }
        }
    }

    sendGETRequest(data);

    while(1)
    {
    	if (etherKbhit())
    	{
    		etherGetPacket(data, 1500);
			if(etherIsTcp(data))
			{

				RED_LED = 1;
				//GREEN_LED=1;
				BLUE_LED=1;
				waitMicrosecond(100000);
				RED_LED = 0;
				//GREEN_LED=0;
				BLUE_LED=0;

				if(p<=7)
					{
					if(tcp_DataCount>0)
						etherRespondToData(data);
					}


				//if(p>=2)
				{
					//p=0;
					tcpData = etherGetTcpData(data);
					http=tcpData+9;
					if((*http==0x32))//|(*http==0x35))
					{
						tcpData=tcpData+299;
						for(i=0;i<(tcp_DataCount-299);i++)
						{
						putcUart0(*tcpData);
						tcpData++;
						}
						if(*http==0x32)
								break;
					}
					//break;
					//sendFinRequest(data);

				}
				p++;
			}
    	}

    }
    while(1);

    return 0;
}
/*
 *  ======== UARTMSP432_open ========
 */
UART_Handle UARTMSP432_open(UART_Handle handle, UART_Params *params)
{
    unsigned int              i;
    uintptr_t                 key;
    uint32_t                  clockFreq;
    uint8_t                   numPerfLevels;
    int32_t                   baudrateIndex;
    union {
        ClockP_Params         clockParams;
        HwiP_Params           hwiParams;
        SemaphoreP_Params     semParams;
    } portsParams;
    PowerMSP432_Freqs         powerFreqs;
    UARTMSP432_Object        *object = handle->object;
    UARTMSP432_HWAttrs const *hwAttrs = handle->hwAttrs;

    if (params == NULL) {
        params = (UART_Params *) &UART_defaultParams;
    }

    /* Check that a callback is set */
    DebugP_assert((params->readMode != UART_MODE_CALLBACK) ||
        (params->readCallback != NULL));
    DebugP_assert((params->writeMode != UART_MODE_CALLBACK) ||
        (params->writeCallback != NULL));

    key = HwiP_disable();

    if (object->state.opened) {
        HwiP_restore(key);
        DebugP_log1("UART:(%p) already in use.", hwAttrs->baseAddr);
        return (NULL);
    }
    object->state.opened = true;

    HwiP_restore(key);

    /* Ensure a supported clock source is used */
    if (hwAttrs->clockSource != EUSCI_A_UART_CLOCKSOURCE_ACLK &&
        hwAttrs->clockSource != EUSCI_A_UART_CLOCKSOURCE_SMCLK) {
        DebugP_log1("UART:(%p) Error! Using unsupported clock source.",
            hwAttrs->baseAddr);
        object->state.opened = false;
        return (NULL);
    }

    /*
     * Add power management support - Disable performance transitions while
     * opening the driver is open.  This constraint remains active until a
     * UART_control() disables receive interrupts.  Afterwards performance
     * levels can be changed by the application.  A UART_control() call can
     * enable RX interrupts again and set the pertinent constraints.
     */
    Power_setConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);

    /*
     * Verify that the driver can be opened at current performance level and
     * set constraints for other performance levels.
     */
    numPerfLevels = PowerMSP432_getNumPerfLevels();
    PowerMSP432_getFreqs(Power_getPerformanceLevel(), &powerFreqs);
    if (hwAttrs->clockSource == EUSCI_A_UART_CLOCKSOURCE_ACLK) {
        /*
         * Verify if driver can be opened with ACLK; ACLK does not change
         * in any performance level.
         */
        baudrateIndex = findBaudDividerIndex(hwAttrs->baudrateLUT,
            hwAttrs->numBaudrateEntries, params->baudRate, powerFreqs.ACLK);
        if (baudrateIndex == -1) {
            DebugP_log3("UART:(%p) unable to find a valid buadrate %d "
                "configuration at clock input clock freq %d", hwAttrs->baseAddr,
                params->baudRate, powerFreqs.ACLK);
            Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
            object->state.opened = false;
            return (NULL);
        }
        clockFreq = powerFreqs.ACLK;
    }
    else {    /* hwAttrs->clockSource == EUSCI_A_UART_CLOCKSOURCE_SMCLK */
        baudrateIndex = findBaudDividerIndex(hwAttrs->baudrateLUT,
            hwAttrs->numBaudrateEntries, params->baudRate, powerFreqs.SMCLK);
        if (baudrateIndex == -1) {
            DebugP_log3("UART:(%p) unable to find a valid buadrate %d "
                "configuration at clock input clock freq %d", hwAttrs->baseAddr,
                params->baudRate, powerFreqs.SMCLK);
            Power_releaseConstraint(PowerMSP432_DISALLOW_PERF_CHANGES);
            object->state.opened = false;
            return (NULL);
        }
        clockFreq = powerFreqs.SMCLK;

        /*
         * SMCLK changes with performance levels.  Set constraints for
         * unsupported performance levels.
         */
        for (i = 0; i < numPerfLevels; i++) {
            PowerMSP432_getFreqs(i, &powerFreqs);
            baudrateIndex = findBaudDividerIndex(hwAttrs->baudrateLUT,
                hwAttrs->numBaudrateEntries, params->baudRate, powerFreqs.SMCLK);
            if (baudrateIndex == -1) {
                /* Set constraint and keep track of it in perfConstraintMask */
                object->perfConstraintMask |= (1 << i);
                Power_setConstraint(PowerMSP432_DISALLOW_PERFLEVEL_0 + i);
            }
        }
    }

    /*
     * Shutdown not supported while driver is open.  The DEEPSLEEP_0 constraint
     * keeps stops the device from going into LPM3 or higher.  This is done
     * to keep the UART peripheral receiving in the background and storing data
     * in the internal ring buff.
     */
    Power_setConstraint(PowerMSP432_DISALLOW_DEEPSLEEP_0);
    Power_setConstraint(PowerMSP432_DISALLOW_SHUTDOWN_0);
    Power_setConstraint(PowerMSP432_DISALLOW_SHUTDOWN_1);

    /* Register function to reconfigure peripheral on perf level changes */
    Power_registerNotify(&object->perfChangeNotify,
        PowerMSP432_START_CHANGE_PERF_LEVEL | PowerMSP432_DONE_CHANGE_PERF_LEVEL,
        perfChangeNotifyFxn, (uintptr_t) handle);

    /* Create the Hwi for this UART peripheral */
    HwiP_Params_init(&(portsParams.hwiParams));
    portsParams.hwiParams.arg = (uintptr_t) handle;
    portsParams.hwiParams.priority = hwAttrs->intPriority;
    object->hwiHandle = HwiP_create(hwAttrs->intNum, UARTMSP432_hwiIntFxn,
        &(portsParams.hwiParams));
    if (object->hwiHandle == NULL) {
        DebugP_log1("UART:(%p) HwiP_create() failed", hwAttrs->baseAddr);
        UARTMSP432_close(handle);
        return (NULL);
    }

    SemaphoreP_Params_init(&(portsParams.semParams));
    portsParams.semParams.mode = SemaphoreP_Mode_BINARY;

    if (params->writeMode == UART_MODE_BLOCKING) {
        /* If write mode is blocking create a semaphore and set callback. */
        object->writeSem = SemaphoreP_create(0, &(portsParams.semParams));
        if (object->writeSem == NULL) {
            DebugP_log1("UART:(%p) SemaphoreP_create() failed.",
                hwAttrs->baseAddr);
            UARTMSP432_close(handle);
            return (NULL);
        }
        object->writeCallback = &writeSemCallback;
    }
    else {
        /* UART_MODE_CALLBACK - Store application callback */
        object->writeCallback = params->writeCallback;
    }

    if (params->readMode == UART_MODE_BLOCKING) {
        /* If read mode is blocking create a semaphore and set callback. */
        object->readSem = SemaphoreP_create(0, &(portsParams.semParams));
        if (object->readSem == NULL) {
            DebugP_log1("UART:(%p) SemaphoreP_create() failed.",
                hwAttrs->baseAddr);
            UARTMSP432_close(handle);
            return (NULL);
        }
        object->readCallback = &readSemCallback;

        ClockP_Params_init(&(portsParams.clockParams));
        portsParams.clockParams.arg = (uintptr_t) handle;
        object->timeoutClk = ClockP_create((ClockP_Fxn) &readBlockingTimeout,
            &(portsParams.clockParams));
        if (object->timeoutClk == NULL) {
            DebugP_log1("UART:(%p) ClockP_create() failed.", hwAttrs->baseAddr);
            UARTMSP432_close(handle);
            return (NULL);
        }
    }
    else {
        object->state.drainByISR = false;
        object->readCallback = params->readCallback;
    }

    /*
     * Initialize UART read buffer - will store received bytes until
     * UART_read is invoked.
     */
    RingBuf_construct(&object->ringBuffer, hwAttrs->ringBufPtr,
        hwAttrs->ringBufSize);
    /*
     * Store UART parameters & initialize peripheral.  These are used to
     * re/initialize the peripheral when opened or changing performance level.
     */
    object->state.readMode       = params->readMode;
    object->state.writeMode      = params->writeMode;
    object->state.readReturnMode = params->readReturnMode;
    object->state.readDataMode   = params->readDataMode;
    object->state.writeDataMode  = params->writeDataMode;
    object->state.readEcho       = params->readEcho;
    object->readTimeout          = params->readTimeout;
    object->writeTimeout         = params->writeTimeout;
    object->baudRate             = params->baudRate;
    object->stopBits             = params->stopBits;
    object->parityType           = params->parityType;
    object->readFxns =
        staticFxnTable[object->state.readMode][object->state.readDataMode];
    object->writeBuf             = NULL;
    object->readBuf              = NULL;
    object->writeCount           = 0;
    object->readCount            = 0;
    object->writeSize            = 0;
    object->readSize             = 0;
    object->state.writeCR        = false;
    object->state.txEnabled      = false;
    object->state.rxEnabled      = true;
    initHw(object, hwAttrs, clockFreq);

    DebugP_log1("UART:(%p) opened", hwAttrs->baseAddr);

    /* Return the handle */
    return (handle);
}