/*
 * Name:         Cold Controller 0.1 - Server
 *
 * Description:  This will run on the computer that has the relay board attached
 *               and listen for incoming connections from a PSP. Different signals
 *               will toggle various relays. Just fiddle around and have fun!
 *              
 * Date:         27/08/08
 * Author:       Matt. Stevens (matt.covia@gmail.com)
 *               DirtyMonkey.co.uk
 */
#include <stdio.h>
#include <stdlib.h>
#include <winsock.h>
#include <windows.h>
#include "mbdll.h"

#define PORT 8128

/* for each inidividual relay */
struct relay {
    char name[128];        // "Bedroom light" etc.
    int status;            // 1 or 0
    unsigned long bitMask; // the code for this relay
    int onCode;            // is 1 or 0 the switched on code?
};

/* function to test and update each relay */
void test_relay(unsigned long *, struct relay *);

int main(int argc, char *argv[])
{
    // although we only use 2, I have 7 relays on my board
    struct relay relays[7];
    
    // initialising relay's, you can add as many as your circuit board can handle
    // here we initialise 2, one for the living room light, the other for my TV
    strcpy(relays[0].name, "Living Room Light");
    relays[0].status = 0;
    relays[0].bitMask = (1<<0); // the bit pattern 00000001
    relays[0].onCode = 0;

    strcpy(relays[1].name, "TV");
    relays[1].status = 0;
    relays[1].bitMask = (1<<1); // the bit pattern 00000010
    relays[1].onCode = 0;

    strcpy(relays[2].name, "Bedroom Light");
    relays[2].status = 0;
    relays[2].bitMask = (1<<2); // the bit pattern 00000100
    relays[2].onCode = 0;

    // initialise relay API
    HINSTANCE BeeHandle;
    BeeHandle = LoadLibrary("mb.dll");

    Type_InitMbee InitMbee = (Type_InitMbee)GetProcAddress(BeeHandle, "InitMbee");
    Type_SetOutputs SetOutputs = (Type_SetOutputs)GetProcAddress(BeeHandle, "SetOutputs");
  
    InitMbee();

    WSADATA wsaData;
    int error_flag = 0;
    unsigned long outputs = 0;

    printf("                        PSP Cold Controller 0.1 - Server\n");
    printf("                                DirtyMonkey.co.uk\n\n\n");

    if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) {
        fprintf(stderr, "Error: problem starting WinSock API\n");
        exit(1);
    }

    int serverSock, clientSock;
    struct sockaddr_in serverInfo, clientInfo;

    serverInfo.sin_family = AF_INET;
    serverInfo.sin_port = htons(PORT);
    serverInfo.sin_addr.s_addr = INADDR_ANY;
    memset(serverInfo.sin_zero, '\0', sizeof(serverInfo.sin_zero));

    serverSock = socket(PF_INET, SOCK_STREAM, 0);

    if (serverSock == -1) {
        fprintf(stderr, "Error: problem with socket() call\n");
        WSACleanup();
        exit(1);
    }

    if (bind(serverSock, (struct sockaddr *)&serverInfo, sizeof(serverInfo)) == -1) {
        fprintf(stderr, "Error: problem with bind() call\n");
        WSACleanup();
        exit(1);
    }

    if (listen(serverSock, 1) == -1) {
        fprintf(stderr, "Error: problem with listen() call\n");
        WSACleanup();
        exit(1);
    }

    if (error_flag == 0) {
        char name[256];
        gethostname(name, sizeof(name));
        struct hostent *phe = gethostbyname(name);
        struct in_addr addr;
        memcpy(&addr, phe->h_addr_list[0], sizeof(struct in_addr));
        printf("Listening for connections on %s  ...\n\n", inet_ntoa(addr));
    } else {
        fprintf(stderr, "\nThere was a problem starting the server,");
        fprintf(stderr, "\nCheck your firewall settings and user privileges.\n\n");
        system("PAUSE");
        WSACleanup();
        exit(1);      
    }

    // client loop, executed once per connection
    while (1) {
        int structSize  = sizeof(clientInfo);
        clientSock = accept(serverSock, (struct sockaddr *)&clientInfo, &structSize);

        printf("\t-> %s has connected\n", inet_ntoa(clientInfo.sin_addr));

        // recv loop, executed once per command
        while (1) {
            char buff;

            if (recv(clientSock, &buff, 1, 0) == 0) break;
            if (buff == 'x') break;

            switch (buff) {
                case '1':
                  test_relay(&outputs, &relays[0]);
                  break;
                case '2':
                  test_relay(&outputs, &relays[1]);
                  break;
                case '3':
                  test_relay(&outputs, &relays[2]);
                  break;
            }
            
            SetOutputs(outputs);
        }

        printf("\t-> %s has disconnected\n", inet_ntoa(clientInfo.sin_addr));

        closesocket(clientSock);
    }

    closesocket(serverSock);
    WSACleanup();

    system("PAUSE");	
    return(0);
}

void test_relay(unsigned long *ptrOutputs, struct relay *ptrRelay)
{
    // bit is already set, so clear it
    if ((*ptrOutputs & ptrRelay->bitMask) == ptrRelay->bitMask) {
        *ptrOutputs &= ~ptrRelay->bitMask;
        ptrRelay->status ^= 1;
                      
        if (ptrRelay->status == ptrRelay->onCode) {
            printf("\t\t-> Client has turned the ");
            printf("%s ON\n", ptrRelay->name);      
        } else {
            printf("\t\t-> Client has turned the ");
            printf("%s OFF\n", ptrRelay->name);     
        }
    // bit is empty, so fill it
    } else {
        *ptrOutputs |= ptrRelay->bitMask;
        ptrRelay->status ^= 1;

        if (ptrRelay->status == ptrRelay->onCode) {
            printf("\t\t-> Client has turned the ");
            printf("%s ON\n", ptrRelay->name);      
        } else {
            printf("\t\t-> Client has turned the ");
            printf("%s OFF\n", ptrRelay->name);     
        }
    }
}