/*****************************************************************************/
/* Copyright (c) 2009 NXP B.V.  All rights are reserved.                     */
/*                                                                           */
/* Redistribution and use in source and binary forms, with or without        */
/* modification, are permitted provided that the following conditions        */
/* are met:                                                                  */
/*                                                                           */
/* Redistributions of source code must retain the above copyright            */
/* notice, this list of conditions and the following disclaimer.             */
/*                                                                           */
/* Redistributions in binary form must reproduce the above copyright         */
/* notice, this list of conditions and the following disclaimer in the       */
/* documentation and/or other materials provided with the distribution.      */
/*                                                                           */
/* Neither the name of NXP nor the names of its                              */
/* contributors may be used to endorse or promote products derived from      */
/* this software without specific prior written permission.                  */
/*                                                                           */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR     */
/* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT      */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,     */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT          */
/* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     */
/* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY     */
/* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT       */
/* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE         */
/* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH          */
/* DAMAGE.                                                                   */
/*                                                                           */
/*****************************************************************************/
/**
    @file   phStbIpc_ClientApp.c
    @brief  Client side application of this component's test.

@b  Component:  phStbIpc

*//*

Rev Date       Author      Comments
--------------------------------------------------------------------------------
  1 20060928   batelaan    Initial
  2 20061010   batelaan    Add more tests.
  3 20070102   batelaan    Port to work in kernel mode, with tmosal, too.
  4 20070209   batelaan    Remove memory access workaround - it's now inside phStbIpc.
                           tmosal task workaround (taskname "%..." use original kernel_thread api)
  5 20090121   batelaan    Update license header

--------------------------------------------------------------------------------
    For consistency and standardisation retain the Section Separators.
*/

/***********************************************
* INCLUDE FILES                                *
************************************************/

#include <phStbIpc.h>
#include <phStbIpc_TestCommon.h>
#include <string.h>

#ifdef __KERNEL__
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <tmosal.h>
#else
  #include <stdio.h>
  #include <unistd.h>
  #include <stdlib.h>
  #include <errno.h>
#endif

/***********************************************
* LOCAL MACROS                                 *
* recommendation only: <MODULE><_WORD>+        *
************************************************/

/******************************************************************
* LOCAL TYPEDEFS                                                  *
* recommendation only:                [p]phStbIpc_<Word>+_t       *
*******************************************************************/

/******************************************************************
* STATIC FUNCTION PROTOTYPES                  <Module>_<Word>+    *
*******************************************************************/

/******************************************************************
* STATIC DATA                  g[k|p|kp|pk|kpk]<Module>_<Word>+   *
*******************************************************************/

#ifdef __KERNEL__
/** Module parameter for the server address.
    If not given, then we use ::PH_STBIPC_TEST_SERVER_ADDRESS.
*/
static char *address;
module_param(address, charp, S_IRUGO);
#endif

/**************************************************************************
* EXPORTED DATA                     g[k|p|kp|pk|kpk]phStbIpc_<Word>+      *
***************************************************************************/

/*******************************************************************************
* FUNCTION IMPLEMENTATION  <Module>[_<Word>+] for static functions             *
*                          ph[<layer>]<Module>[_<Word>+] for exported functions*
********************************************************************************/

#ifdef __KERNEL__
static void sleep(uint secs)
{
    tmosalTaskSleep(secs * 1000);
}
#endif

/******************************************************************************/

static int StbIpc_ClientApp_Main(int argc, char **argv)
{
    pphStbIpc_Connection_t connection;
    char *handshakeMessage = PH_STBIPC_TEST_HANDSHAKE;
    char *serverAddress = argv[1];
    phStbIpc_Endianness_t endianness;
    size_t n;
    int ret = 1;
    tmErrorCode_t err;
    
    if (argc < 2)
    {
        serverAddress = PH_STBIPC_TEST_SERVER_ADDRESS;
    }
    else
    {
        CHECK(argc <= 2, !false);
    }
    
    PRINT("phStbIpc_ClientApp: start; address='%s'\n", serverAddress);


    CHECK(phStbIpc_ClientCreate(serverAddress, &connection),
          TM_OK);
    
    CHECK(phStbIpc_ClientHandShake(serverAddress, connection, handshakeMessage, &endianness),
          TM_OK);
    CHECK((endianness == phStbIpc_Endianness_Big) || (endianness == phStbIpc_Endianness_Little),
          !false);
    
    PRINT("client informed that server endianness = %c\n", endianness);
    
    CHECK(phStbIpc_Close(connection),
          TM_OK);



    CHECK(phStbIpc_ClientHandShake(serverAddress, NULL, handshakeMessage, &endianness),
          TM_OK);
    CHECK((endianness == phStbIpc_Endianness_Big) || (endianness == phStbIpc_Endianness_Little),
          !false);

    

    CHECK(phStbIpc_ClientCreate(serverAddress, &connection),
          TM_OK);
    CHECK(phStbIpc_Write(connection, "exit", 5, &n),
          TM_OK);
    CHECK(n == 5, !false);
    sleep(1); /* give server chance to exit. */
    CHECKSTATEMENT(err = phStbIpc_ClientHandShake(serverAddress, NULL, handshakeMessage, &endianness),
                  (err == PH_STBIPC_SYSTEM_CALL_ERR(ECONNRESET)) ||
                  (err == PH_STBIPC_SYSTEM_CALL_ERR(ECONNREFUSED)));
    CHECK(phStbIpc_Close(connection),
          TM_OK);

    PRINT("phStbIpc_ClientApp: finish OK\n");
    ret = 0;
    
  DEPARTURES:
    return ret;
}

/******************************************************************************/
#ifdef __KERNEL__
static void taskFunction(void *pArg)
{
    int argc = 1;
    char *argv[2] = {"Client"};

    /* If module param has been passed, then use it as the first argument. */
    if (address != NULL)
    {
        argv[argc] = address;
        argc++;
    }

    (void)StbIpc_ClientApp_Main(argc, argv);

    tmosalTaskExit();
}

int __init phStbIpc_ClientApp_Init(void)
{
    tmosalTaskHandle_t task;
    tmErrorCode_t err;
    err = tmosalTaskCreate(
        &taskFunction,
        NULL,
        48, /* priority. */
        4 * 1024, /* stack size */
        &task,
        "%IPc",
        tmosalTaskStarted);
    CHECK(err == TM_OK, !false);
    tmosalTaskWaitForExit(task);
    /* Always return an error, so the module immediately unloads itself. */
  DEPARTURES:
    return -ECANCELED;
}
module_init(phStbIpc_ClientApp_Init);

#else

int main(int argc, char **argv)
{
    return StbIpc_ClientApp_Main(argc, argv);
}

#endif

/******************************************************************************/
/******************************************************************************/
