/*
Copyright (c) 2007, Group 2 TI ProOS 2006/2007
                    Fontys University of Professional Education

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/**
 * @file proos.h
 * @brief ProOS TCP/IP Communication API.
 *
 * ProOS API for MUTS software development.
 * Including networking, memory management and protocol handling.
 *
 * This only works on little-endian architectures.
 *
 * Using the following headers on Linux:
 * - <stdio.h>
 * - <sys/socket.h>
 * - <arpa/inet.h>
 * - <stdlib.h>
 * - <string.h>
 * - <unistd.h>
 * - "pthread.h"
 *
 * And these on Windows:
 * - <stdio.h>
 * - <winsock.h>
 * - <stdlib.h>
 * - "pthread.h"
 */

#ifndef PROOS_H
#define PROOS_H

#define PROOS_VERSION 0x03 /*< Protocol and API Version */

/*
 * Protocol in proos_protocol file.
 */
#define PROOS_PACKET_DUMMY              0x00
#define PROOS_PACKET_PING               0x01
#define PROOS_PACKET_PONG               0x02
#define PROOS_PACKET_CLIENTREG          0x03
#define PROOS_PACKET_CLIENTREG_ANSWER   0x04
#define PROOS_PACKET_CLIENTUNREG        0x05
#define PROOS_PACKET_CLIENTUNREG_ANSWER 0x06
#define PROOS_PACKET_HALTBROADCAST      0x07
#define PROOS_PACKET_REGSHARED          0x08
#define PROOS_PACKET_REGSHARED_ANSWER   0x09
#define PROOS_PACKET_REGSEM             0x10
#define PROOS_PACKET_REGSEM_ANSWER      0x11
#define PROOS_PACKET_UNREGSEM           0x12
#define PROOS_PACKET_UNREGSEM_ANSWER    0x13
#define PROOS_PACKET_SEMP               0x14
#define PROOS_PACKET_SEMP_ANSWER        0x15
#define PROOS_PACKET_SEMV               0x16
#define PROOS_PACKET_SEMV_ANSWER        0x17
#define PROOS_PACKET_MEMWONE            0x18
#define PROOS_PACKET_MEMWONE_ANSWER     0x19
#define PROOS_PACKET_MEMWTWO            0x20
#define PROOS_PACKET_MEMWTWO_ANSWER     0x21
#define PROOS_PACKET_MEMR               0x22
#define PROOS_PACKET_MEMR_ANSWER        0x23
#define PROOS_PACKET_STDOUT             0x24
#define PROOS_PACKET_STDOUT_ANSWER      0x25
#define PROOS_PACKET_UNREGSHARED        0x26
#define PROOS_PACKET_UNREGSHARED_ANSWER 0x27

typedef unsigned int proos_address; /**< 32-bit offset address for malloc. Addresses can always be incremented to match a certain offset within regged memory. (typedef for portability to 80515) */
typedef short unsigned int proos_semid; /**< 16-bit semaphore number. (typedef for portability to 80515) */

/**
 * @brief ProOS Communication Packet.
 *
 * This is the basis of all the communication with the BOSS.
 * 
 */
typedef struct {
  char protocol[3]; /**< Should be "POS" 0x504F53. */
  unsigned char version; /**< Protocol version number. */
  unsigned char client_num; /**< Local client number. Indicates sender when sent, receiver when received. */
  unsigned char command; /**< Command Byte, see proos_protocol file. */
  unsigned char data_len; /**< Length of Data Chunk. */
  unsigned char parity; /**< Parity room for serial communication: not used in TCP/IP. */
  char *data; /**< Data Chunk. */
} proos_packet;

/**
 * @brief Connect with BOSS.
 *
 * Connect with the BOSS over TCP/IP.
 * 
 * @param address String network address of the BOSS machine.
 * @param port Integer port number of the BOSS machine.
 * @return 0x01 if connected, 0x00 if failed.
 */
unsigned char proos_connect (const char *address, const unsigned int port);

/**
 * @brief Disconnect from BOSS.
 *
 * Connect from BOSS over TCP/IP.
 * 
 * @return 0x01 if disconnected, 0x00 if failed.
 */
unsigned char proos_disconnect (void);

/**
 * @brief Register with BOSS.
 *
 * Be sure to run proos_connect() first.
 * 
 * @return 0x01 if registered, 0x00 if failed.
 */
unsigned char proos_register (void);

/**
 * @brief Register with BOSS.
 *
 * This will cause all memory to be freed not in use by any MUTS.
 * Be sure to run this BEFORE proos_disconnect().
 * 
 * @return 0x01 if disconnected, 0x00 if failed.
 */
unsigned char proos_unregister (void);

/**
 * @brief Allocate shared memory with BOSS.
 *
 * Two MUTS machines using the same ID to register share that part of memory.
 * If the size doesn't match the preregistered ID this request will fail.
 * 
 * @param id Id of the variable you want to register.
 * @param len Size of the memory you'd like to register.
 * @return Address of allocated memory on BOSS. 0 if failed.
 */
proos_address proos_alloc (const proos_address id, const unsigned char len);

/**
 * @brief Free shared memory with BOSS.
 *
 * Free allocated memory on the BOSS. If the memory is still in use by
 * another MUTS it only revokes your access rights to the memory block.
 *
 * @param id Id of the variable you want to unregister.
 * @return 0x01 if free success, 0x00 if failed.
 */
unsigned char proos_free (const proos_address id);

/**
 * @brief Write value to shared address on BOSS.
 *
 * The address has to be a product of proos_alloc() plus the wanted offset in
 * that memory block.
 *
 * @param address Address of memory you want to write to on the BOSS.
 * @param data Pointer to the local data buffer where your data resides.
 * @param len Length of data to read from the local data buffer.
 * @return 0x01 if write is success, 0x00 if failed.
 */
unsigned char proos_write (const proos_address address, const char *data, const unsigned char len);

/**
 * @brief Read value from shared address on BOSS.
 *
 * The address has to be a product of proos_alloc() plus the wanted offset in
 * that memory block.
 *
 * @param address Address of memory you want to read from the BOSS.
 * @param data Pointer to pre-allocated local data buffer where the data should go.
 * @param len Length of data to read from the BOSS shared address.
 * @return 0x01 if read success, 0x00 if failed.
 */
unsigned char proos_read (const proos_address address, const char *data, const unsigned char len);

/**
 * @brief Register semaphore with BOSS.
 *
 * Be sure this semaphore doesn't exist yet if you don't want it to beforehand.
 * The protocol does not support availability queries or lowest increment registering.
 *
 * @param sem_id Unique semaphore ID to register at the BOSS.
 * @param sem_val The intial value to use when registering the semaphore.
 * @return 0x01 if success, 0x00 if failed.
 */
unsigned char proos_sem_register (const proos_semid sem_id, const unsigned char sem_val);

/**
 * @brief Unregister semaphore with BOSS.
 *
 * This is also automatically done at unregister, you don't have to do this at the
 * end of your program.
 *
 * @param sem_id Semaphore ID to unregister.
 * @return 0x01 if success, 0x00 if failed.
 */
unsigned char proos_sem_unregister (const proos_semid sem_id);

/**
 * @brief Send P() semaphoric request to the BOSS.
 *
 * This is according to the theory by Dijkstra.
 *
 * @param sem_id Semaphore ID to send P() request at.
 * @return 0x01 if success, 0x00 if failed.
 */
unsigned char proos_sem_p (const proos_semid sem_id);

/**
 * @brief Send V() semaphoric request to the BOSS.
 *
 * This is according to the theory by Dijkstra.
 *
 * @param sem_id Semaphore ID to send V() request at.
 * @return 0x01 if success, 0x00 if failed.
 */
unsigned char proos_sem_v (const proos_semid sem_id);

/**
 * @brief Send message to the BOSS to be printed on it's terminal window.
 *
 * Your MUTS client number will be displayed in front of your message.
 *
 * @param msg Null terminated string containing your message.
 * @return 0x01 if success, 0x00 if failed.
 */
unsigned char proos_sendmsg (const char *msg);

/**
 * @brief Get the local client number for MUTS debug purposes.
 *
 * Do not use this in API functions, it has a global instead.
 *
 * @return Local client number. 0 if not registered.
 */
unsigned char proos_get_client_number (void);

#endif