#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include "usb2200.h"

void Show();

int main(int argc, char **argv)
{
	int handle;
  WORD pid = USB2255_32;
  BYTE bid = 0x0;
  char input[64];
  DWORD options;

  handle = USB2200_OpenDevice(pid, bid);
	if(handle < 0) {
		printf("open failed, error code %d\n", handle);
		return 0;
	}

  Show();

  while (1){
    printf("\nPress ESC to exit.\n\n");

    if (scanf("%u", &options) != 1) break;
    int c = getchar();
    if (c == 27) break;

    switch (options){
      case 1: {
        QWORD current_mask = 0;
        WORD ret;
        BYTE o_byDOTotal;

        ret = USB2200_GetDOTotal(handle, &o_byDOTotal);
        if (ret != NO_ERR) {
            printf("Error: Get DO total channel failed (0x%04X)\n", ret);
            break;
        }

        printf("\n--- DO PowerOn Configuration ---\n");

        /* Step 1: Read-First (Bulk) */
        ret = USB2200_DO_GetPowerOnEnable(handle, &current_mask);
        if (ret != NO_ERR) {
            printf("Error: Read PowerOn failed (0x%04X)\n", ret);
            break;
        }
        printf(">> Current PowerOn Mask: 0x%016llX\n", (unsigned long long)current_mask);

        /* Step 2: Interactive Prompt */
        printf("Action: (0) Skip, (1) Set All by Mask, (2) Set Single Channel: ");
        if (!fgets(input, sizeof(input), stdin) || input[0] == '\n' || input[0] == '0') {
            break;
        }

        int action = atoi(input);
        if (action == 1) {
            /* Set Bulk */
            printf("Enter new PowerOn Mask (e.g. 0xFF): ");
            if (fgets(input, sizeof(input), stdin)) {
                QWORD set_mask = (QWORD)strtoull(input, NULL, 0);
                ret = USB2200_DO_SetPowerOnEnable(handle, set_mask);
                if (!ret) printf(">> Bulk PowerOn updated.\n");
            }
        } 
        else if (action == 2) {
            /* Set Single Channel */
            printf("Enter Channel (0-%d): ", o_byDOTotal - 1);
            if (fgets(input, sizeof(input), stdin)) {
                BYTE ch = (BYTE)atoi(input);
                printf("Set Value for Ch %d (0:Disable, 1:Enable): ", ch);
                if (fgets(input, sizeof(input), stdin)) {
                    BYTE val = (BYTE)atoi(input);
                    /* ....... Channel . API */
                    ret = USB2200_DO_SetPowerOnEnableToChannel(handle, ch, val);
                    if (!ret) printf(">> Channel %d PowerOn updated.\n", ch);
                }
            }
        }
        break;
      }
      case 2: {
        QWORD current_enable = 0, current_val = 0;
        QWORD set_enable, set_val;
        BYTE o_byDOTotal;
        WORD ret;

        ret = USB2200_GetDOTotal(handle, &o_byDOTotal);
        if (ret != NO_ERR) {
            printf("Error: Get DO total channel failed (0x%04X)\n", ret);
            break;
        }

        printf("\n--- DO Safety Configuration (Failsafe State) ---\n");

        /* Step 1: Read-First (Bulk) */
        ret = USB2200_DO_GetSafetyEnable(handle, &current_enable, &current_val);
        if (ret != NO_ERR) {
            printf("Error: Read Safety failed (0x%04X)\n", ret);
            break;
        }
        
        /* ............... %llX .. */
        printf(">> Current Safety Enable Mask: 0x%016llX\n", (unsigned long long)current_enable);
        printf(">> Current Safety Value  Mask: 0x%016llX\n", (unsigned long long)current_val);

        /* Step 2: Interactive Prompt */
        printf("\nAction: (0) Skip, (1) Set Bulk Mask, (2) Set Single Channel: ");
        if (!fgets(input, sizeof(input), stdin) || input[0] == '\n' || input[0] == '0') {
            break;
        }

        int action = atoi(input);
        if (action == 1) {
            /* 1. Set Bulk */
            printf("Enter Enable Mask (Hex, e.g. 0xFF): ");
            if (fgets(input, sizeof(input), stdin)) {
                set_enable = (QWORD)strtoull(input, NULL, 0);
                
                printf("Enter Value Mask (Hex, e.g. 0x00): ");
                if (fgets(input, sizeof(input), stdin)) {
                    set_val = (QWORD)strtoull(input, NULL, 0);
                    
                    ret = USB2200_DO_SetSafetyEnable(handle, set_enable, set_val);
                    if (!ret) printf(">> Bulk Safety settings updated successfully.\n");
                }
            }
        } 
        else if (action == 2) {
            /* 2. Set Single Channel */
            printf("Enter Channel (0-%d): ", o_byDOTotal - 1);
            if (fgets(input, sizeof(input), stdin)) {
                BYTE ch = (BYTE)atoi(input);
                if (ch >= o_byDOTotal) {
                    printf(">> Invalid Channel!\n");
                    break;
                }

                printf("Safety Enable for Ch %d (0:Disable, 1:Enable): ", ch);
                if (fgets(input, sizeof(input), stdin)) {
                    BYTE en = (BYTE)atoi(input);
                    
                    printf("Safety Value for Ch %d (0:Low, 1:High): ", ch);
                    if (fgets(input, sizeof(input), stdin)) {
                        BYTE v = (BYTE)atoi(input);
                        
                        ret = USB2200_DO_SetSafetyEnableChannel(handle, ch, en, v);
                        if (!ret) printf(">> Channel %d Safety updated successfully.\n", ch);
                    }
                }
            }
        }
        break;
      }
      case 3: {
        BYTE current_inv = 0;
        BYTE set_inv;
        WORD ret;

        printf("\n--- DO Logic Inverse Mode (Normal/Inverted) ---\n");

        /* Step 1: Read-First - ........ */
        ret = USB2200_DO_GetInverse(handle, &current_inv);
        if (ret != NO_ERR) {
            printf("Error: Read DO Inverse failed (0x%04X)\n", ret);
            break;
        }

        printf(">> Current DO Logic: [%u] %s\n", 
                current_inv, (current_inv == 1) ? "INVERTED" : "NORMAL");

        /* Step 2: Interactive Prompt */
        printf("Change setting? (0: Normal, 1: Inverse, Enter to Skip): ");
        if (!fgets(input, sizeof(input), stdin) || input[0] == '\n') {
            /* ...... Enter......... */
            break;
        }

        /* Step 3: Input Validation */
        set_inv = (BYTE)strtoul(input, NULL, 0);
        if (set_inv > 1) {
            printf(">> Invalid status. No change made.\n");
            break;
        }

        /* Step 4: Execute Set API */
        ret = USB2200_DO_SetInverse(handle, set_inv);
        if (ret == NO_ERR) {
            printf(">> Success: DO Inverse updated to [%s]\n", 
                   (set_inv == 1) ? "Inverted" : "Normal");
        } else {
            printf(">> Set DO Inverse failed: 0x%04X\n", ret);
        }
        
        break;
      }
      default:
        Show();
        break;
    }
  }

  USB2200_CloseDevice(handle);

	return 0;
}

void Show()
{
  printf("\n--- USB-2200 Digital Output Configuration ---\n");
  printf("1. [Get/Set] DO PowerOn Status (Bulk/Channel)\n");
  printf("2. [Get/Set] DO Safety Status & Value (Bulk/Channel)\n");
  printf("3. [Get/Set] DO Inverse Mode (Normal/Inverted)\n");
  printf("Others number show this list, ESC to quit.\n");
  printf("Select an option: ");
}
