// Filename : iqtz.cpp
//
// This file was initially generated by SpaceStudio but is meant to be modified
// by the user.
#include "iqtz.h"
#include "spacecomp_pre_cpp.h"

static const unsigned char zigzag_table [] = {
	 0,  1,  8, 16,  9,  2,  3, 10,
	17, 24, 32, 25, 18, 11,  4,  5,
	12, 19, 26, 33, 40, 48, 41, 34,
	27, 20, 13,  6,  7, 14, 21, 28,
	35, 42, 49, 56, 57, 50, 43, 36,
	29, 22, 15, 23, 30, 37, 44, 51,
	58, 59, 52, 45, 38, 31, 39, 46,
	53, 60, 61, 54, 47, 55, 62, 63
};

iqtz::iqtz(SPACECOMP_CTOR_PARAMS(iqtz, INDEX))
	: abstract_module(SPACECOMP_MBASE_ARGS(iqtz, INDEX))
	, SPACECOMP_START_ILIST(iqtz, INDEX)
	// Other initializers may go here
{
	SPACECOMP_THREAD(iqtz, INDEX, thread);
	request_stack(16 * 1024);
}

void iqtz::thread(SPACECOMP_THREAD_PARAMS(iqtz, INDEX, thread)) {
	spacecomp_thread_initialize();
	bool startTagReceived;
	unsigned long infoImageHeaderAdd = 0;

	// to receive messages from other modules and to send messages to them
	JMSG input_message;
	JMSG output_message;

	// variables for INVERSE QUANTIFICATION computation
	unsigned char index;
	unsigned short blockCounter;

	unsigned char componentindex = 0;

	startTagReceived = false;

	//	variables for INVERSE QUANTIFICATION computation
	blockCounter = 0;
	while (1) {
		const bool initializing = spacecomp_thread_loop_start();
		if (initializing) {	}
        // waiting for a command to be received

        if(!startTagReceived) {
			//
			// MESSAGES FROM EXTRACTOR
			//
			hw_compute_latency(5);
			ModuleRead(EXTR0_ID, SPACE_BLOCKING, &input_message);

            //
            // process input command from the message
            //
            switch (input_message.command) {

            //////////////////////////////////////////////////////////////////////////////////////////
            //	2.	SCMD_NEW_IMAGE
            //
            case SCMD_NEW_IMAGE:

                //
                // calculate buffer and image memory address
                //
                //infoImageHeaderAdd =  ((input_message.param1-1)*BITMAP_IMAGE_SPACER);
				infoImageHeaderAdd = (input_message.param1-1)%2 == 1 ?  BITMAP_IMAGE_SPACER : 0;

                //
                // get width and height of image to generate and write to this image info header
                //
                int t1, t2;

				DeviceRead(JPEGRAM_ID, input_message.param0 , &t1);
                DeviceWrite(BITMAPRAM_ID, infoImageHeaderAdd, &t1);
                DeviceRead(JPEGRAM_ID, input_message.param0+0x4ul, &t2);
                DeviceWrite(BITMAPRAM_ID, infoImageHeaderAdd+0x4ul, &t2);

                // get quantization table
                for (unsigned int i=0; i<JPEG_QUANTTBLSIZE/2; i++) {
					uint32_t ulQuantTblRegister;
					RegisterRead(REGISTER_FILE0_ID, i, &ulQuantTblRegister);
					unsigned int uiTableID = i / (JPEG_QUANTTBLSIZE/4);
					unsigned int uiTableIndex = 4*i % (JPEG_QUANTTBLSIZE);
					QuantTable[uiTableID][uiTableIndex    ] = (ulQuantTblRegister >> 24) & 0xFF;
					QuantTable[uiTableID][uiTableIndex + 1] = (ulQuantTblRegister >> 16) & 0xFF;
					QuantTable[uiTableID][uiTableIndex + 2] = (ulQuantTblRegister >> 8 ) & 0xFF;
					QuantTable[uiTableID][uiTableIndex + 3] = (ulQuantTblRegister      ) & 0xFF;
					hw_compute_latency(1);
				}

                // print message
                if (is_verbose())
                    SpacePrint("IQTZ: Request for new image (%dx%d) received - working at 0x%x\n", t1, t2, BITMAP_TEMP_ADDRESS);

                //
                // returning ack
                //
                input_message.command	= SCMD_NEW_IMAGE_ACK;
                input_message.param0	= infoImageHeaderAdd;

				ModuleWrite(EXTR0_ID, SPACE_BLOCKING, &input_message);
				hw_compute_latency(1);
				if (is_verbose())
                    SpacePrint("IQTZ: ACK returned to EXTRACTOR after NEW_IMAGE command\n");

				// tag telling begin of transmission is received and
                //command can be processed
                startTagReceived = true;

                break;
            }
		}
		else             {
			///
			//	MESSAGES FROM HUFFMAN
			//
			hw_compute_latency(5);
			if (is_verbose())
				SpacePrint("IQTZ: Waiting message from Huffman\n");
			ModuleRead(HUFF0_ID, SPACE_BLOCKING, &input_message);

			if (is_verbose())
				SpacePrint("IQTZ: Got message from Huffman\n");
            //
            // process input command from the message
            //
            switch (input_message.command) {


            //////////////////////////////////////////////////////////////////////////////////////////
            //	3.	SCMD_BEGIN_COMP_DATA_TRANSMISSION
            //
            case SCMD_BEGIN_COMP_DATA_TRANSMISSION:

				if (is_verbose())
					SpacePrint("IQTZ: BEGIN_COMP_DATA_TRANSMISSION received - ready to receive 64 pixels\n");

				// selection of proper table (LIGHT or COLOR table)
                componentindex = input_message.param0;
                if(componentindex > CHROMINANCE) componentindex = CHROMINANCE;

                //receiving pixels decompressed with Huffman
	            ModuleRead(HUFF0_ID, SPACE_BLOCKING, (uint32_t*)m_inblock, 32);

                blockCounter++;		//count the number of blocks received from EXTRACTOR

				//------------------------------------------------------------
				//-------------- INVERSE QUANTIZE computation ----------------
				//-----------------------------------------------------------

				for (int k=0; k<64; k++) {
                    index = zigzag_table[k];
                    //SpacePrint("IN = %x\n", m_inblock[k]);
                    // compute unquantized value
                    m_interblock[index] = (m_inblock[k] * QuantTable[componentindex][k] );
                    //SpacePrint("OUT = %x\n", m_interblock[index]);
                }

                // transmit SCMD_START_IDCT to begin inverse DCT operation
                output_message.command = SCMD_START_IDCT;
                output_message.param1 = blockCounter;

                if (blockCounter == 1)
                    output_message.param0 = BITMAP_TEMP_ADDRESS;
                else
					output_message.param0 = 0;

				if (is_verbose())
					SpacePrint("IQTZ: 64 pixels processed - awaking IDCT\n");

				hw_compute_latency(5);

				ModuleWrite(IDCT0_ID, SPACE_BLOCKING, &output_message);


                if (is_verbose())
					SpacePrint("IQTZ: Ready to send 64 pixels to IDCT\n");

				//send the 64-elements block for inverse DCT
				hw_compute_latency(32);
				ModuleWrite(IDCT0_ID, SPACE_BLOCKING, (uint32_t*)m_interblock, 64/2);

				if (is_verbose())
					SpacePrint("IQTZ: 64 pixels sucessfully sent\n");

                break;
             //////////////////////////////////////////////////////////////////////////////////////////
            //	5.	SCMD_END_IMAGE
            //
            case SCMD_END_IMAGE:

                if (is_verbose())
                    SpacePrint("IQTZ: End of Image - Reseting for next image\n");

				//
				//waiting for last block to be processed before starting a new one
				//
				output_message.command = SCMD_END_IMAGE;

				// REQUEST FOR ACK

                ModuleWrite(IDCT0_ID, SPACE_BLOCKING, &output_message);

				hw_compute_latency(1);

			    ModuleRead(IDCT0_ID, SPACE_BLOCKING, &input_message);

				blockCounter = 0;

				output_message.command = SCMD_END_IMAGE_ACK;
                ModuleWrite(EXTR0_ID, SPACE_BLOCKING, &output_message);
				hw_compute_latency(1);

                if (is_verbose())
                    SpacePrint("IQTZ: ACK returned to EXTRACTOR for END_IMAGE command\n");

				// wait for next image
                startTagReceived = false;

				break;

            default:
                break;
            } // switch
        }
	}
}

#include "spacecomp_post_cpp.h"
