#include "stdafx.h"
#include "ClientAPI.h"
#include <string>
#include <math.h>

// insert the IP of your SP-ICE-3
#define CARD_IP "192.168.2.138"

static rlResult markSprint(rlHandle handle);
static int printLastError(void);
uint16_t* readBmp(char* filename, int* width, int* height);


int main()
{
	// establish a connection with the card
	rlHandle handle = rlConnect(CARD_IP, 49374);
	if (handle < 0)
		return printLastError();

	rlResult status;

	// Reset the card to its default settings:
	// This restores the following settings to the values that were last saved on the card:
	// - scanner configuration (such as field size, field correction, etc.)
	// - laser configuration (such as gate/LM timing parameters, power target, etc.)
	// - process variables (such as jump speed, settling times, mark speed, etc.)
	if ((status = rlSystemResetToDefaults(handle)) != rlSUCCESS)
		goto Cleanup;

	// Set the laser power to 80%
	if ((status = rlLaserArmLaser(handle, true)) != rlSUCCESS) goto Cleanup;
	rlLaserConfig lc;
	if ( ( status = rlLaserGetConfig( handle, &lc ) ) != rlSUCCESS ) goto Cleanup;
	lc.PowerScale = 0.8;
	if ( ( status = rlLaserSetConfig( handle, &lc ) ) != rlSUCCESS ) goto Cleanup;

	status = markSprint(handle);

Cleanup:
	// print any errors
	if (status != rlSUCCESS)
		printLastError();

	// disconnect from the card
	printf("Disconnecting from card...\n");
	if (rlDisconnect(handle) != rlSUCCESS)
		return printLastError();

	printf("Exiting with status = %d\n", status);
	return status;
}


/// mark a selected bitmap with the sprint algorithm
static rlResult markSprint(rlHandle handle)
{
	rlResult result;

	// evade error, if list was aborted in previous run
	bool waitSuccess;
	int listId;
	rlListWaitForListDone(handle, 0, &waitSuccess, &listId);

	int listIndex = 0;
	double jumpSpeed = 1;
	double markSpeed = 1;

	rlLaserConfig laserConfig;
	if ((result = rlLaserGetConfig(handle, &laserConfig)) != rlSUCCESS) return result;
	laserConfig.HotPowerTarget = ptLmWidth;
	rlLaserSetConfig(handle, &laserConfig);

	rlScannerConfig config;
	if ((result = rlScannerGetConfig(handle, &config)) != rlSUCCESS) return result;

	// load a test image, and mark it on 30% of the field
	int width;
	int height;
	uint16_t* image = readBmp("..\\Sprint\\tiger.bmp", &width, &height);

	double maxX = 0.3 * config.FieldSize.X;
	double maxY = maxX /width * height;

	printf("Preparing list: index=%d...\n", listIndex);
	rlCommandListHandle list = rlListAllocate(handle);

	if ((result = rlListAppendJumpSpeed(list, jumpSpeed)) != rlSUCCESS) return result;
	if ((result = rlListAppendJumpDelay(list, 0)) != rlSUCCESS) return result;
	if ((result = rlListAppendMarkSpeed(list, markSpeed)) != rlSUCCESS) return result;
	if ((result = rlListAppendMarkDelay(list, 0)) != rlSUCCESS) return result;
	if ((result = rlListAppendLmFrequency(list, 1.0 / 200.0)) != rlSUCCESS) return result;
	if ((result = rlListAppendLmWidth(list, 200.0)) != rlSUCCESS) return result;

	uint16_t* powerValues = new uint16_t[width];

	double y = -maxY;
	double dy = (height > 1) ? (2.0 * maxY) / (height - 1) : 0;
	for (int row = height; --row >= 0; )
	{
		for (int column = 0; column < width; column++)
			powerValues[column] = (uint16_t)image[row * width + column];

		if ((result = rlListAppendBitmapLineAbs2D(list, -maxX, y, maxX, y, powerValues, width)) != rlSUCCESS) return result;
		y += dy;
	}
	if ((result = rlListAppendLaserOff(list)) != rlSUCCESS) return result;
	// close the list causing its contents to be transferred to the card
	printf("Closing list: index=%d...\n", listIndex);
	if ((result = rlListSet(handle, listIndex, list, false, -1)) != rlSUCCESS) return result;

	//if ((result = rlLaserSetPowerScale(handle, 1.0)) != rlSUCCESS) return result;

	// run the list, and wait until its execution has completed
	printf("Executing list: index=%d...\n", listIndex);
	if ((result = rlListExecute(handle, listIndex)) != rlSUCCESS) return result;


	// estimate the mark time of one bitmap (assume top-right corner as the start point)
	double executionTime = sqrt(config.FieldSize.X * config.FieldSize.X + config.FieldSize.Y * config.FieldSize.Y) / jumpSpeed;
	executionTime += height * (config.FieldSize.X / markSpeed);
	executionTime += (height - 1) * sqrt(config.FieldSize.X * config.FieldSize.X + dy * dy) / jumpSpeed;
	int timeoutMs = (int)(0.001 * executionTime) + 2000;

	bool done = false;
	int32_t listID;
	printf("Waiting until list execution is done: index=%d...\n", listIndex);
	if ((result = rlListWaitForListDone(handle, timeoutMs, &done, &listID)) != rlSUCCESS)
		return result;
	if (!done)
	{
		printf("Timeout: execution has not completed after %d ms!", timeoutMs);
		return rlERROR;
	}
	printf("Execution done: index=%d...\n", listIndex);

	// delete list on the card: this frees the card's memory occupied by the list
	printf("Deleting list: index=%d...\n", listIndex);
	if ((result = rlListDelete(handle, listIndex, true)) != rlSUCCESS)
		return result;

	// release the local list: this frees the PC's memory occupied by the card
	if ((result = rlListReleaseHandle(list)) != rlSUCCESS) return result;

	return result;
}


// helper function which displays the description of the last error
static int printLastError(void)
{
	char errBuffer[1024] = { 0 };
	rlGetLastError(errBuffer, sizeof(errBuffer) - 1);
	printf("%s", errBuffer);
	return rlERROR;
}

// convert bitmap to uint16_t array (only for 24bit bmp)
uint16_t* readBmp(char* filename, int* width, int* height)
{
	FILE* f = fopen(filename, "rb");
	unsigned char info[54];
	// read the 54-byte header
	fread(info, sizeof(unsigned char), 54, f);

	// extract image height and width from header
	*width = *(int*)&info[18];
	*height = *(int*)&info[22];

	int size = *width * *height;

	uint16_t* image= new uint16_t[size];

	uint16_t pixelGray = 0;

	int row_padded = (*width * 3 + 3) & (~3);
	unsigned char* data = new unsigned char[row_padded];

	for (int i = 0; i < *height; i++)
	{
		fread(data, sizeof(unsigned char), row_padded, f);
		for (int j = 0; j < *width * 3; j += 3)
		{
			// build average of the BGR values
			pixelGray = (data[j] + data[j + 1] + data[j + 2]) / 3;
			// invert x axis and scale from 8 to 16 bit
			image[i * *width + *width - j / 3 - 1] = pixelGray * 256;
		}
	}

	fclose(f);
	delete data;
	data = NULL;

	return image;
}