aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.PMR/TangoMessage.cs
blob: 410621af2394d4c18b2146e6adfc4257b6390e82 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.PMR.Common;
using Google.Protobuf;
using System.IO;

namespace Tango.PMR
{
    /// <summary>
    /// Represents composition of message <see cref="MessageContainer"/> and a PMR message. aka Tango message.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class TangoMessage<T> : ITangoMessage where T : IMessage<T>
    {
        /// <summary>
        /// Gets the container that will encapsulate the actual PMR message.
        /// </summary>
        public MessageContainer Container { get; set; }

        /// <summary>
        /// Gets or sets the message.
        /// </summary>
        public T Message { get; set; }

        /// <summary>
        /// Gets or sets the PMR message type.
        /// </summary>
        public MessageType Type { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="TangoMessage{T}"/> class.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="type">The type.</param>
        public TangoMessage(T message, MessageType type)
        {
            Message = message;
            Type = type;

            Container = new MessageContainer();
            Container.Token = Guid.NewGuid().ToString();
            Container.Type = Type;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TangoMessage{T}"/> class.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="type">The type.</param>
        public TangoMessage(MessageContainer container, T message)
        {
            Message = message;
            Container = container;
            Type = container.Type;
        }

        /// <summary>
        /// Serializes the Tango message to byte array.
        /// </summary>
        /// <returns></returns>
        public byte[] ToBytes()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                Message.WriteTo(ms);
                ms.Position = 0;
                Container.Data = ByteString.FromStream(ms);
            }

            using (MemoryStream ms = new MemoryStream())
            {
                Container.WriteTo(ms);
                return ms.ToArray();
            }
        }

        /// <summary>
        /// Serializes the Tango message to byte array representing a serialized JSON object of this Tango message.
        /// </summary>
        /// <returns></returns>
        public byte[] ToJsonBytes()
        {
            Container.Data = Message.ToByteString();
            return Encoding.UTF8.GetBytes(Container.ToString());
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="T"/> to <see cref="TangoMessage{T}"/>.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator TangoMessage<T>(T message)
        {
            var tangoMessage = MessageFactory.CreateTangoMessage<T>();
            tangoMessage.Message = message;
            return tangoMessage;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="TangoMessage{T}"/> to <see cref="T"/>.
        /// </summary>
        /// <param name="instance">The instance.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator T(TangoMessage<T> instance)
        {
            return instance.Message;
        }

        /// <summary>
        /// Performs an implicit conversion from <see cref="System.Byte[]"/> to <see cref="TangoMessage{T}"/>.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <returns>
        /// The result of the conversion.
        /// </returns>
        public static implicit operator TangoMessage<T>(byte[] data)
        {
            return MessageFactory.ParseTangoMessage<T>(data);
        }

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return String.Format(@"Message Type: {0}
Token: {1}
Error: {2}
Message: {3}", Container.Type, Container.Token, Container.Error, Message.ToString());
        }
    }
}
/************************************************************************************************************************
 * Printing.c
 * High managment logical unit of slow motors in the system ( 6 dispensers and the screw motor)
 * profile run up begins from screw homing to begin position and only then from fast motors activation.
 * when every slow motor tuches the limit switch (no matter whether its screw or dispenser)
 * an interrupt occures in the system and as long as its pushing the limit switch all the system is prevented from operation.
 * because of that the work flow with interrupts must be :
	 * design a function handle (what to do in the moment the interrupt arrives)
	 * configure the wanted interrupt in the cfg file (according to the defined port and pin and its interrupt number and the handler)
	 * enable interupt for predefined gpio in the application
	 * when the interrupt arrives the handle will be automatically called
	 * in case of the limit switches since the operation is continuess the interrupt must be disabled in order to continue the application running.
	 * then the operation is not continues (like butten pushing) there is no need in disabling the interrupts

 * Printing module is responsible for :
 	 * operating diffrent winding algorithms with predefined parameters from the UI
 	 * operating the dispensers according to predefined dispensing rate from the UI
 **************************************************************************************************************************/

////////////////////////////////State machine operation////////////////////////////////////
//the state machine operation is used to operate in runtime correct profile flow execution
//by recieved esign flow of the user from the UI
///////////////////////////////////////////////////////////////////////////////////////////
#include <Container.h>
#include <DataDef.h>
#include "include.h"
#include <ti/sysbios/knl/mailbox.h>
#include <ti/sysbios/knl/Clock.h>
#include <ti/sysbios/knl/task.h>

#include "Common/report/report.h"

#include "PMR/Printing/JobSegment.pb-c.h"
#include "PMR/Printing/JobRequest.pb-c.h"
#include "PMR/Printing/JobResponse.pb-c.h"
#include "PMR/Printing/CurrentJobRequest.pb-c.h"
#include "PMR/Printing/CurrentJobResponse.pb-c.h"
#include "PMR/Printing/ResumeCurrentJobRequest.pb-c.h"
#include "PMR/Printing/ResumeCurrentJobResponse.pb-c.h"
#include "PMR/Printing/JobUploadStrategy.pb-c.h"
#include "PMR/Printing/JobStatus.pb-c.h"
#include "PMR/Printing/AbortJobRequest.pb-c.h"
#include "PMR/Printing/AbortJobResponse.pb-c.h"
#include "PMR/Hardware/Hardwaremotor.pb-c.h"
#include "PMR/Hardware/HardwareWinder.pb-c.h"
#include "PMR/common/MessageContainer.pb-c.h"
#include "PMR/Diagnostics/EventType.pb-c.h"
#include "PMR/MachineStatus/MachineStatus.pb-c.h"

#include "Modules/General/MachineStatus.h"

#include "Modules/General/process.h"
#include "modules/Diagnostics/Diagnostics.h"

#include "PMR/Stubs/StubJobRequest.pb-c.h"
#include "PMR/Stubs/StubJobResponse.pb-c.h"
#include "PMR/Stubs/StubAbortJobRequest.pb-c.h"
#include "PMR/Stubs/StubAbortJobResponse.pb-c.h"

#include "PMR/Diagnostics/ThreadJoggingRequest.pb-c.h"
#include "PMR/Diagnostics/ThreadJoggingResponse.pb-c.h"
#include "PMR/Diagnostics/ThreadAbortJoggingRequest.pb-c.h"
#include "PMR/Diagnostics/ThreadAbortJoggingResponse.pb-c.h"

#include "StateMachines/Initialization/PowerIdle.h"

#include "drivers/Motors/Motor.h"

#include "./printingSTM.h"
#include "modules/thread/thread_ex.h"
#include "modules/AlarmHandling/AlarmHandling.h"
#include "modules/ids/ids_ex.h"
#include "Modules/heaters/heaters_ex.h"
#include "Modules/control/control.h"


#define MAX_TICKET_SIZE  10000

Mailbox_Handle JobmsgQ = NULL;

JobEndReasonEnum JobEndReason = JOB_OK;
ErrorCode JobError_to_ErrorCode[JOB_ERRORS_MAX+1] = {ERROR_CODE__NONE,ERROR_CODE__JOB_UNSPECIFIED_ERROR,ERROR_CODE__JOB_THREAD_BREAK,ERROR_CODE__JOB_WINDER_DANCER_FAIL,
                                                      ERROR_CODE__JOB_POOLER_DANCER_FAIL,ERROR_CODE__JOB_FEEDER_DANCER_FAIL,ERROR_CODE__JOB_OUT_OF_DYE,ERROR_CODE__JOB_OTHER_ALARM,
                                                      ERROR_CODE__JOB_TEMPERATURE_ALARM,ERROR_CODE__JOB_LS_ALARM,ERROR_CODE__JOB_PRESSURE_ALARM,ERROR_CODE__JOB_CURRENT_ALARM,
                                                      ERROR_CODE__JOB_MOTOR_ALARM,ERROR_CODE__JOB_OTHER_ALARM};

JobTicket *CurrentJob = NULL;
JobRequest *CurrentRequest  = NULL;

double previousJobLength;
uint32_t    StubControlId = 0xFF;
double StubLengthCounter = 0,StubLength = 0,StubSpeed=0;
JobTicket Ticket;
JobSegment *TSegment;
JobBrushStop *TbrushStop;
JobDispenser *Tdispenser;
JobSpool *Tspool;
bool CopyConfigured[MAX_SYSTEM_MODULES];
bool CleaningJobActive = false, JoggingJobActive = false;
char ErrorMsg[100];
JobUploadStrategy uploadstrategy = JOB_UPLOAD_STRATEGY__Default;

ModuleStateEnum PrepareWaiting[MAX_SYSTEM_MODULES] = {ModuleIdle,ModuleIdle,ModuleIdle,ModuleIdle,ModuleIdle};

uint16_t job_length = 0;

/********************************************************************************************
* functions describes motor operation flow and movement state during profile execution
* used to operate in runtime correct profileflow execution
*********************************************************************************************/
//static ReturnCode IdleState(void *JobDetails);
//static ReturnCode ValidateState(void *JobDetails);
static ReturnCode PrepareState(void *JobDetails);
static ReturnCode PrintState(void *JobDetails);
//static ReturnCode CleanState(void *JobDetails);
static ReturnCode ExitState(void *JobDetails);
/**********************************************************************
* the array and enum of JobState_t below must be in sync order
***********************************************************************/
//static ReturnCode (* state[])(void *JobDetails) = { IdleState, ValidateState, PrepareState,  PrintState, CleanState};
void AbortJob(char *Msg);


typedef enum
{
    Idle= 0,
	Validate,
	PrepareJob,
	Print,
	Clean,
	ExitJob
} JobState_t;

typedef struct
{
    JobState_t	m_sourceState;
    ReturnCode   		m_returnCode;
    JobState_t 	m_destinationState;
} Transition_t;


////////////////////////Slow Motor State////////////////////////////////////
bool JobActive = false;
bool JobResumed = false;
char JobToken[36+1]={0};
bool JobAbortedByUser = false;

////////////////////////////////////////////////////////////////////////////
void StartJob(void *JobDetails);


//********************************************************************************************************************
bool JobIsActive(void)
{
    return JobActive;
}
/********************************************************************************************************************
*function describes entry point of motor in profile execution - accelerate from stop position
*function described above used to operate motor operation flow and movement state during profile execution
*********************************************************************************************************************/
/*static ReturnCode IdleState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobSuccess;

    return retcode;
}*/
//********************************************************************************************************************
/*static ReturnCode ValidateState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobSuccess;

    return retcode;
}*/
//********************************************************************************************************************
bool GetHeatersPrepareWaiting(void)
{
    if (PrepareWaiting[Module_Heaters] == ModuleWaiting)
        return true;
    else
        return false;

}
//********************************************************************************************************************
static ReturnCode PrepareState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobSuccess;
    //start (fast??) heating
    DiagnosticsStart();

    if (Configured[Module_IDS])
    {
        PrepareWaiting[Module_IDS] = ModuleWaiting;
//        REPORT_MSG(Module_IDS,"Dispenser prepare waiting");
    }
    if (Configured[Module_Thread])
    {
        PrepareWaiting[Module_Thread] = ModuleWaiting;
    }
    if (Configured[Module_Winder])
    {
        PrepareWaiting[Module_Winder] = ModuleWaiting;
    }
    if (Configured[Module_Heaters])
    {
        if (HeaterCheckReady() == false) // if heaters are in heating / cooling state we must wait for them
            PrepareWaiting[Module_Heaters] = ModuleWaiting;
    }
    //wait for fast heating to end
    //start other peripheral systems: chiller, waist handling
    //check thread type
    if (Configured[Module_IDS])
    {
        //REPORT_MSG(Module_IDS,"Dispenser prepare called");
        IDSPrepareState(JobDetails);
    }
/*    if (Configured[Module_Heaters])
    {
        //heaters preparation starts on process parameters handling
    }*/
    if (Configured[Module_Thread])
    {
        ThreadPrepareState(CurrentJob);
    }
    if (Configured[Module_Winder])
    {
       if( Winder_Prepare(CurrentJob)!= OK)
       {
           SendJobProgress(0.0, 0, false, "Winder prepare failed !!!!");
       }
    }

	return retcode;
}
//********************************************************************************************************************
uint32_t PrepareReady(int ModuleId, ModuleStateEnum result)
{
    int i;
    bool ready = true;
    uint32_t retcode = 0,status = OK;

    JobMessageStruc Message;

    assert (ModuleId<MAX_SYSTEM_MODULES);
    assert (result<=ModuleFail);

    if (JobActive == false)
        return ERROR;
    if (PrepareWaiting[ModuleId] != ModuleWaiting)
    {
        LOG_ERROR (ModuleId, "Message from unrelated module!!");
        return ERROR;
    }
    REPORT_MSG(ModuleId,"module prepare called");

    PrepareWaiting[ModuleId] = result;
    //if (result == ModuleFail) status = ERROR;
    for (i=0;i<MAX_SYSTEM_MODULES ;i++)
    {
        if (PrepareWaiting[i] == ModuleWaiting)
            ready = false;
        if (PrepareWaiting[i] == ModuleFail)
            status = ERROR;
    }
    if ((ready == false)&&(status == OK))
        return OK;
    else
    {
        for (i=0;i<MAX_SYSTEM_MODULES ;i++)
        {
            if (PrepareWaiting[ModuleId] == ModuleWaiting)
                PrepareWaiting[ModuleId] = ModuleDone;
        }
        SendJobProgress(0.0, 0, false, "Prepare Ready");
        if (status == OK)    Message.messageId = PreparationResultsOk;
        else Message.messageId = PreparationResultsFail;
        //memcpy(Message.messageData,JobDetails,MAX_MSG_LEN);
        Message.msglen = 10;
        if (JobmsgQ != NULL)
            retcode = Mailbox_post(JobmsgQ , &Message, BIOS_NO_WAIT);
    }
    return retcode;
}

//********************************************************************************************************************
static ReturnCode PrintState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobSuccess;
    JobMessageStruc Message;
    PrintMessageStruc *PrtMessage = (PrintMessageStruc *)Message.messageData;

        Message.messageId = PrintMessage;
        PrtMessage->messageId = PrintRequest;
        Message.msglen = 10;
        if (JobmsgQ != NULL)
            Mailbox_post(JobmsgQ , &Message, BIOS_NO_WAIT);

    return retcode;
}

//********************************************************************************************************************
/*static ReturnCode CleanState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobSuccess;

    return retcode;
}*/
//********************************************************************************************************************
static ReturnCode ExitState(void *JobDetails)
{
    ReturnCode retcode;
    retcode = JobStop;

    return retcode;
}

/*static void JobClockHandle(UArg arg0)
{
    //Clock_setTimeout(JobClock, 1000);
    //Clock_start(JobClock);

}*/

//********************************************************************************************************************

/*void JobInit(void)
{
    Clock_Params_init(&jobclkParams);
    jobclkParams.period = 0;
    jobclkParams.startFlag = FALSE;
    JobClock = Clock_create(JobClockHandle, 0, &jobclkParams, NULL);
    return ;
}*/
//********************************************************************************************************************
void JobAbortFunc(MessageContainer* requestContainer)
{
    MessageContainer responseContainer;
    uint8_t* container_buffer;


    AbortJobRequest* request = abort_job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    //AbortJob();
    AbortJobResponse response = ABORT_JOB_RESPONSE__INIT;
    responseContainer = createContainer(MESSAGE_TYPE__AbortJobResponse, requestContainer->token, false, &response, &abort_job_response__pack, &abort_job_response__get_packed_size);
    container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));

    size_t container_size = message_container__pack(&responseContainer, container_buffer);
    my_free(responseContainer.data.data);
    SendChars((char*)container_buffer, container_size);
    abort_job_request__free_unpacked(request,NULL);
    JobAbortedByUser = true;
    AbortJob("Job Aborted by user");
    //We keep the job request until it is done


}
//********************************************************************************************************************
uint32_t ThreadJoggingFunc(int speed)
{
    ProcessParameters ProcessParametersCopy;
    uint32_t status = OK;
    if (JobIsActive() == true)
    {
        status = ERROR;
        LOG_ERROR(JobIsActive(),"Jog JobIsActive");
    }
    else
    {
        memcpy(&CopyConfigured,&Configured,sizeof(CopyConfigured));
        usnprintf(ErrorMsg, 80,"Copy Configured T %d W %d I %d H %d W %d",CopyConfigured[Module_Thread],CopyConfigured[Module_Winder],CopyConfigured[Module_IDS],CopyConfigured[Module_Heaters],CopyConfigured[Module_Waste]);
        Report(ErrorMsg, __FILE__, __LINE__, 0, RpWarning,   0, 0);

        JoggingJobActive = true;
        //set the job handler to ignore heaters, ids and waste in the state machine
        Configured[Module_Thread] = true;
        Configured[Module_Winder] = true;
        Configured[Module_IDS] = false;
        Configured[Module_Heaters] = false;
        Configured[Module_Waste] = false;
        //set the requested speed without changing other process parameters
        memcpy (&ProcessParametersCopy,&ProcessParametersKeep,sizeof(ProcessParameters));
        if(speed)
            ProcessParametersCopy.dyeingspeed = speed;
        else
            ProcessParametersCopy.dyeingspeed = 40;
        if (HandleProcessParameters(&ProcessParametersCopy)!= OK)
        {
            status = FAILED;
        }
        else
        {
        //load essential job prameters to enable thread running
            Ticket.n_segments = 1;
            n_segments = 1;
            Ticket.segments = my_malloc(sizeof(Ticket.segments));
            TSegment = my_malloc(sizeof(JobSegment));
            Tspool = my_malloc(sizeof(JobSpool));
            TSegment->length = 200.0;
            TSegment->n_brushstops = 0;
            Ticket.segments[0] = TSegment;
            Tspool->backingrate = 32;
            Tspool->bottombackingrate = 32;
            Tspool->segmentoffsetpulses = 1000;
            Tspool->startoffsetpulses = 220;
            Tspool->rotationsperpassage = 3.1415926*2;
            Ticket.spool = Tspool;
            CurrentJob = &Ticket;
            InternalWindingConfigMessage(Tspool);
            StartJob(&Ticket);
        }
    }
    return status;
}
//********************************************************************************************************************
uint32_t ThreadCleaningJobFunc(int speed)
{
    ProcessParameters ProcessParametersCopy;
    uint32_t status = OK;
    if (JobIsActive() == true)
    {
        status = ERROR;
        LOG_ERROR(JobIsActive(),"Jog JobIsActive");
    }
    else
    {
        if (isMotorConfigured(CLEANER_DISPENSER + HARDWARE_MOTOR_TYPE__MOTO_DISPENSER_1)==false)
        {
            status = ERROR;
            LOG_ERROR(JobIsActive(),"Jog No cleaner dispenser");
        }
        else
        {
            memcpy(&CopyConfigured,&Configured,sizeof(CopyConfigured));
            CleaningJobActive = true;
            usnprintf(ErrorMsg, 80,"Copy Configured T %d W %d I %d H %d W %d",CopyConfigured[Module_Thread],CopyConfigured[Module_Winder],CopyConfigured[Module_IDS],CopyConfigured[Module_Heaters],CopyConfigured[Module_Waste]);
            Report(ErrorMsg, __FILE__, __LINE__, 0, RpWarning,   0, 0);

            //set the job handler to ignore heaters, ids and waste in the state machine
            Configured[Module_Thread] = true;
            Configured[Module_Winder] = true;
            Configured[Module_IDS] = true;
            Configured[Module_Heaters] = false;
            Configured[Module_Waste] = false;
            //set the requested speed without changing other process parameters
            memcpy (&ProcessParametersCopy,&ProcessParametersKeep,sizeof(ProcessParameters));
            if(speed)
                ProcessParametersCopy.dyeingspeed = speed;
            else
                ProcessParametersCopy.dyeingspeed = 40;
            if (HandleProcessParameters(&ProcessParametersCopy)!= OK)
            {
                status = FAILED;
            }
            else
            {
            //load essential job prameters to enable thread running
                Ticket.uploadstrategy = JOB_UPLOAD_STRATEGY__Default;
                Ticket.n_segments = 1;
                Ticket.enableintersegment = true;
                Ticket.intersegmentlength = 200;
                n_segments = 2;
                Ticket.segments = my_malloc(sizeof(Ticket.segments)*2);
                TSegment = my_malloc(sizeof(JobSegment));
                Tspool = my_malloc(sizeof(JobSpool));
                TbrushStop = my_malloc(sizeof(JobBrushStop));
                TSegment->length = 200.0;
                TSegment->n_brushstops = 1;
                TSegment->brushstops = my_malloc(sizeof(TSegment->brushstops));
                TSegment->brushstops[0] = TbrushStop;
                Tdispenser = my_malloc(sizeof(JobDispenser));

                TbrushStop->has_index =true;
                TbrushStop->index = 0;
                TbrushStop->n_dispensers = 1;
                TbrushStop->dispensers = my_malloc(sizeof(TbrushStop->dispensers));
                TbrushStop->dispensers[0] = Tdispenser;
                Tdispenser->nanolitterpersecond = 10000;
                Tdispenser->nanoliterperpulse = 2.34;
                Tdispenser->dispenserstepdivision = DISPENSER_STEP_DIVISION__Auto;
                Ticket.segments[0] = TSegment;
                Ticket.segments[1] = TSegment;
                Tspool->backingrate = 32;
                Tspool->bottombackingrate = 32;
                Tspool->segmentoffsetpulses = 1000;
                Tspool->startoffsetpulses = 220;
                Tspool->rotationsperpassage = 3.1415926*2;
                Ticket.spool = Tspool;
                CurrentJob = &Ticket;
                InternalWindingConfigMessage(Tspool);
                StartJob(&Ticket);
            }
        }
    }
    return status;
}
void ThreadJoggingRequestFunc(MessageContainer* requestContainer)
{
    uint32_t status = OK;

    MessageContainer responseContainer;
    ThreadJoggingRequest* request = thread_jogging_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    ThreadJoggingResponse response = THREAD_JOGGING_RESPONSE__INIT;

    status = ThreadJoggingFunc(request->speed);

    responseContainer = createContainer(MESSAGE_TYPE__ThreadJoggingResponse, requestContainer->token, true, &response, &thread_jogging_response__pack, &thread_jogging_response__get_packed_size);
    if (status!= OK)
    {
        responseContainer.error = ERROR_CODE__INVALID_PARAMETER;
        responseContainer.errormessage = "JOb Active or incorrect parameters";
    }
//    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    size_t container_size = message_container__pack(&responseContainer, container_buffer);
    SendChars(container_buffer, container_size);
    my_free(responseContainer.data.data);

    return ;

}
void ThreadAbortJoggingFunc(void)
{
    if (JobIsActive() == true)
    {
        AbortJob(0);
        //set the job handler to handle heaters, ids and waste in the state machine
        Task_sleep(100); //let the job end procedure role before returning the configuration to normal.
        usnprintf(ErrorMsg, 80,"Copy Configured T %d W %d I %d H %d W %d",CopyConfigured[Module_Thread],CopyConfigured[Module_Winder],CopyConfigured[Module_IDS],CopyConfigured[Module_Heaters],CopyConfigured[Module_Waste]);
        Report(ErrorMsg, __FILE__, __LINE__, 0, RpWarning,   0, 0);


        my_free(Ticket.segments);
        my_free(TSegment);
        my_free(Tspool);
    }

}
void ThreadAbortJoggingRequestFunc(MessageContainer* requestContainer)
{
    //uint32_t status = OK;

    MessageContainer responseContainer;

    ThreadAbortJoggingRequest* request = thread_abort_jogging_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    ThreadAbortJoggingResponse response = THREAD_ABORT_JOGGING_RESPONSE__INIT;

    ThreadAbortJoggingFunc();

    responseContainer = createContainer(MESSAGE_TYPE__ThreadAbortJoggingResponse,  requestContainer->token, false, &response, &thread_abort_jogging_response__pack, &thread_abort_jogging_response__get_packed_size);

    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return ;

}

//********************************************************************************************************************
uint32_t SendStubJobProgress(uint32_t IfIndex, uint32_t readValue)
{
    MessageContainer responseContainer;
    uint8_t* container_buffer;
    bool done = false;
//


    //REPORT_MSG(msdid++,logmsg);
    Report("Stub Job",__FILE__,__LINE__,StubLengthCounter,RpWarning,StubLength,  StubSpeed);

    if (JobToken[0] == 0)
        return OK;


    StubJobResponse response = STUB_JOB_RESPONSE__INIT;
    JobStatus jobStatus = JOB_STATUS__INIT;

    jobStatus.has_progress = true;
    jobStatus.progress = StubLengthCounter/100;
    StubLengthCounter += StubSpeed;
    if (StubLengthCounter>=StubLength)
    {
        done = true;
        RemoveControlCallback(StubControlId, SendStubJobProgress);
    }

    jobStatus.has_currentsegmentindex = true;
    jobStatus.currentsegmentindex = 0;

    response.status = &jobStatus;
    responseContainer = createContainer(MESSAGE_TYPE__StubJobResponse, JobToken, done, &response, &stub_job_response__pack, &stub_job_response__get_packed_size);

    container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return OK;
}

void Stub_JobRequest(MessageContainer* requestContainer)
{
    uint32_t status = OK;

    MessageContainer responseContainer;

    StubJobRequest* request = stub_job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);
    JobTicket *Ticket = request->jobticket;

    StubJobResponse response = STUB_JOB_RESPONSE__INIT;
    JobStatus jobStatus = JOB_STATUS__INIT;
    StubSpeed = Ticket->processparameters->dyeingspeed;
    StubLength  = Ticket->length*100;
    StubLengthCounter = 0;
    ustrncpy (JobToken, requestContainer->token,36);
    StubControlId =  AddControlCallback( SendStubJobProgress, eOneSecond,TemplateDataReadCBFunction,0,0,0);

    jobStatus.has_progress = true;
    jobStatus.progress = 0.0;
    jobStatus.has_currentsegmentindex = false;
    response.status = &jobStatus;
    responseContainer = createContainer(MESSAGE_TYPE__StubJobResponse, JobToken, false, &response, &stub_job_response__pack, &stub_job_response__get_packed_size);
    if (status!= OK)
    {
        responseContainer.error = ERROR_CODE__INVALID_PROCESS_ID;
        responseContainer.errormessage = "JOb Active or incorrect parameters";
    }
//    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return ;

}
void Stub_AbortJobRequest(MessageContainer* requestContainer)
{
    //uint32_t status = OK;

    MessageContainer responseContainer;

    StubAbortJobRequest* request = stub_abort_job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    StubAbortJobResponse response = STUB_ABORT_JOB_RESPONSE__INIT;


    //RemoveControlCallback(StubControlId, SendStubJobProgress);
    StubLength  = 0;
    StubLengthCounter = 10;  //trigger job end message;

    responseContainer = createContainer(MESSAGE_TYPE__StubAbortJobResponse,  requestContainer->token, false, &response, &stub_abort_job_response__pack, &stub_abort_job_response__get_packed_size);

    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return ;

}

//********************************************************************************************************************
void JobRequestFunc(MessageContainer* requestContainer)
{
    uint32_t status = NOT_SUPPORTED;
    MessageContainer responseContainer;
    uint8_t* container_buffer;
    ErrorCode error = ERROR_CODE__NONE;
    JobEndReasonEnum JobAlarmReason = JOB_OK;

    if (JobActive == true)
    {
		LOG_ERROR(JobActive, "Job started while active");
        status = FAILED;
        error = ERROR_CODE__NO_JOB_IN_PROGRESS;
	}
    else
    {
        JobRequest* request = job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);
        if (request != NULL)
        {
            ustrncpy (JobToken, requestContainer->token,36);
            previousJobLength = 0.0;
            JobTicket *Ticket = request->jobticket;
            int TicketSize = job_ticket__get_packed_size(Ticket);
            if (TicketSize >= MAX_TICKET_SIZE)
            {
                LOG_ERROR (TicketSize, "job ticket message too long");
                status = FAILED;
                error = ERROR_CODE__BAD_CRC;
                usnprintf(ErrorMsg, 100, "job ticket message too long");
            }
            else
            {
                //memcpy(CurrentJob, Ticket,TicketSize);
                CurrentJob = Ticket;
    //            if (CurrentRequest!= NULL)
    //                job_request__free_unpacked(CurrentRequest,NULL);
                CurrentRequest = request;
                n_segments = 0;
                if (CurrentJob->uploadstrategy == JOB_UPLOAD_STRATEGY__JobDescriptionFile)
                {
                    LOG_ERROR(JobActive, "Job upload strategy file");
                    uploadstrategy = JOB_UPLOAD_STRATEGY__JobDescriptionFile;
                }
                else
                {
                    uploadstrategy = JOB_UPLOAD_STRATEGY__Default;
                    n_segments = CurrentJob->n_segments;
                }
                status  = PASSED;
                JobEndReason = JOB_OK;
                TotalProcessedLength = 0.0;
                PoolerTotalProcessedLength = 0.0;
                job_length = CurrentJob->length + dryerbufferMeters;
                Report("job length ",__FILE__,job_length,(int)CurrentJob->length,RpWarning,(int)dryerbufferCentimeters,  0);
                JobAlarmReason = AlarmHandlingPrepareJob(CurrentJob);
                if (JobAlarmReason ==OK)
                {
                    n_unit_segments = n_segments;
                    if ((Ticket->has_units)&&(Ticket->units > 1))
                    {
                        n_units = Ticket->units;
                    }
                    if (n_units>1)
                    {
                        n_segments = n_segments*n_units;
                    }
    //#warning Process parameters in job request are not handled. push separately for now
                    if (Ticket->processparameters)
                    {
                        if (HandleProcessParameters(Ticket->processparameters)!= OK)
                        {
                            status = FAILED;
                            error = ERROR_CODE__INVALID_PARAMETER;
                            usnprintf(ErrorMsg, 100, "Hardware Parameters Not Set");
                        }
                    }
                    //REPORT_MSG(0,"Process parameters in job request are not handled. push separately for now");
                    if (Ticket->spool)
                    {
                        if (InternalWindingConfigMessage(Ticket->spool)!= OK)
                        {
                            status = FAILED;
                            error = ERROR_CODE__INVALID_PARAMETER;
                            usnprintf(ErrorMsg, 100, "spool parameters error");
                        }
                    }

                }
                else
                {
                    status = FAILED;
                    error = JobError_to_ErrorCode[JobAlarmReason];
                    usnprintf(ErrorMsg, 100, "Existing alarms prevent running");
                }
            }
            if (status == PASSED)
            {
                Report("Job Request ",__FILE__,__LINE__,Ticket->processparameters->dyeingspeed,RpWarning,n_segments, Ticket->intersegmentlength);
                OpenJobFile();
                StartJob(CurrentJob);
            }
        }
        else
            status = FAILED;
    }

    JobResponse response = JOB_RESPONSE__INIT;
    JobStatus jobStatus = JOB_STATUS__INIT;
    if (status == PASSED)
    {
        JobResumed = false;
        usnprintf(ErrorMsg, 100, "Job Accepted");

        jobStatus.message =ErrorMsg;
        jobStatus.has_progress = true;
        jobStatus.progress = 0.0;
        jobStatus.has_currentsegmentindex = false;
        response.status = &jobStatus;
        response.has_canceled = false;
        responseContainer = createContainer(MESSAGE_TYPE__JobResponse, JobToken, false, &response, &job_response__pack, &job_response__get_packed_size);
        container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    }
    else
    {
        jobStatus.message = ErrorMsg;
        jobStatus.has_progress = true;
        jobStatus.progress = 0.0;
        jobStatus.has_currentsegmentindex = false;
        response.status = &jobStatus;
        response.has_canceled = true;
        response.canceled = true;
        responseContainer = createContainer(MESSAGE_TYPE__JobResponse, JobToken, true, &response, &job_response__pack, &job_response__get_packed_size);
        responseContainer.has_error = true;
        responseContainer.error = error;
        container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    }
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        my_free(responseContainer.data.data);
        SendChars((char*)container_buffer, container_size);
        //We keep the job request until it is done
        //    job_request__free_unpacked(request,NULL);
    }
}
//********************************************************************************************************************
char logmsg[254];
char infomsg[254];
uint8_t JobStatusBuffer[400];
ResumeCurrentJobResponse resumeresponse = RESUME_CURRENT_JOB_RESPONSE__INIT;
JobResponse JobResponseMsg = JOB_RESPONSE__INIT;
JobStatus jobStatus = JOB_STATUS__INIT;

void SendJobProgress(double ProcessedLength, int SegmentId, bool done, char *Message)
{
    MessageContainer responseContainer;
    uint8_t* container_buffer;

    //int len;
    //static msdid = 0;
    //int length = (int)(ProcessedLength*100);
    //len = usnprintf(logmsg, 254, "MSG: Job Progress Length %d, Seg %d Done %d ",length,  SegmentId,  done);

    //REPORT_MSG(msdid++,logmsg);
    //Report(logmsg,__FILE__,__LINE__,SegmentId,RpWarning,SegmentId,  done);
    /*if (Message)
    {
        strcpy (infomsg,Message);
        Report(infomsg,__FILE__,__LINE__,55,RpWarning,33,  44);
    }*/
    UInt Key = Task_disable();
    double totlength = 0;

    if (JobToken[0] != 0)
    {

        if (Message)
        {
            jobStatus.message = Message;
        }
        //previousJobLength =  ProcessedLength;
        jobStatus.has_progress = true;
#ifdef FEEDER_LENGTH_CALCULATION
        totlength = TotalProcessedLength;
        if (TotalProcessedLength > job_length)
        {
            Report("job length bigger than assigned",__FILE__,__LINE__,TotalProcessedLength,RpWarning,job_length,  done);
            //TotalProcessedLength = job_length;
            totlength = job_length;
        }
#else
        totlength = PoolerTotalProcessedLength;
        if (PoolerTotalProcessedLength > job_length)
        {
            Report("job length bigger than assigned",__FILE__,__LINE__,PoolerTotalProcessedLength,RpWarning,job_length,  done);
            //TotalProcessedLength = job_length;
            totlength = job_length;
        }
#endif
        jobStatus.progress = totlength;
        jobStatus.has_currentsegmentindex = true;
        jobStatus.currentsegmentindex = SegmentId;

        if (JobResumed == true)
        {
            resumeresponse.status = &jobStatus;
            //responseContainer = createContainer(MESSAGE_TYPE__ResumeCurrentJobResponse,  JobToken, done, &resumeresponse, &resume_current_job_response__pack, &resume_current_job_response__get_packed_size);
            responseContainer = createAllocatedContainer(MESSAGE_TYPE__ResumeCurrentJobResponse,  JobToken, done, &resumeresponse, &resume_current_job_response__pack, &resume_current_job_response__get_packed_size,&JobStatusBuffer);
        }
        else
        {
            JobResponseMsg.status = &jobStatus;
            //responseContainer = createContainer(MESSAGE_TYPE__JobResponse, JobToken, done, &JobResponseMsg, &job_response__pack, &job_response__get_packed_size);
            responseContainer = createAllocatedContainer(MESSAGE_TYPE__JobResponse, JobToken, done, &JobResponseMsg, &job_response__pack, &job_response__get_packed_size,&JobStatusBuffer);
        }

        container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
        if (done == true)
        {
            if(JobEndReason != JOB_OK)
            {
                responseContainer.has_error = true;
                responseContainer.error = JobError_to_ErrorCode[JobEndReason];
            }
            if (JobAbortedByUser == true)
            {
                JobAbortedByUser = false;
                responseContainer.has_error = true;
                responseContainer.error = ERROR_CODE__CONTINUOUS_RESPONSE_ABORTED;
            }
        }
        if (container_buffer)
        {
            size_t container_size = message_container__pack(&responseContainer, container_buffer);
            //        if (SendChars(container_buffer, container_size) == false) //comm tx mailbox full
            if (SendCharsWithType(container_buffer, container_size,MESSAGE_TYPE__JobResponse) == false) //comm tx mailbox full
            {
                //AlarmHandlingToken[0] = 0;
                my_free(container_buffer);
            }
        }
    }

    if (done == true)
    {
        if (CurrentRequest!= NULL)
        {
        //    job_request__free_unpacked(CurrentRequest,NULL);
            CurrentRequest = NULL;
        }
        JobStopReporting();
        if(JobEndReason != JOB_OK)
        {
            switch (JobEndReason)
            {
                case JOB_THREAD_BREAK:
                    AlarmHandlingSetAlarm(EVENT_TYPE__THREAD_BREAK,true);
                    break;
                case JOB_POOLER_DANCER_FAIL:
                    AlarmHandlingSetAlarm(EVENT_TYPE__THREAD_TENSION_CONTROL_FAILURE_PULLER_DANCER,true);
                    break;
                case JOB_FEEDER_DANCER_FAIL:
                    AlarmHandlingSetAlarm(EVENT_TYPE__THREAD_TENSION_CONTROL_FAILURE_FEEDER_DANCER,true);
                    break;
                case JOB_WINDER_DANCER_FAIL:
                    AlarmHandlingSetAlarm(EVENT_TYPE__THREAD_TENSION_CONTROL_FAILURE_WINDER_DANCER,true);
                    break;
                default:
                    break;
            }
        }
        JobMessageStruc JobMessage;

        JobMessage.messageId = PrintingResultsOk;
        JobMessage.msglen = MAX_MSG_LEN;
        if (JobmsgQ != NULL)
            Mailbox_post(JobmsgQ , &JobMessage, BIOS_NO_WAIT);
    }
//    if (responseContainer.data.data)
//        my_free(responseContainer.data.data);
    Task_restore(Key);

}
void JobStopReporting(void)
{
    LOG_ERROR(0,"JobStopReporting");
    JobToken[0] = 0;
}

void AbortJob(char *Msg)
{
    //ReturnCode retcode;
    //retcode = JobSuccess;
    JobMessageStruc Message;
    PrintMessageStruc *PrtMessage = (PrintMessageStruc *)Message.messageData;

        Message.messageId = Abort;
        PrtMessage->messageId = PrintSystemFailure;
        strncpy(PrtMessage->messageData,Msg,99);
        //PrtMessage->messageData[99] = NULL;
        Message.msglen = 10;
        if (JobmsgQ != NULL)
            Mailbox_post(JobmsgQ , &Message, BIOS_NO_WAIT);
}
uint32_t    CurrentJobRequestFunc(MessageContainer* requestContainer)
{
    uint32_t status = OK;

    MessageContainer responseContainer;

    CurrentJobRequest* request = current_job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    CurrentJobResponse response = CURRENT_JOB_RESPONSE__INIT;


    if (JobActive == true)
    {
        response.has_isjobinprogress = true;
        response.isjobinprogress = true;
        response.jobticket = CurrentJob;
    }
    else
    {
        response.has_isjobinprogress = true;
        response.isjobinprogress = false;
        response.jobticket = NULL;
    }
    responseContainer = createContainer(MESSAGE_TYPE__CurrentJobResponse,  requestContainer->token, false, &response, &current_job_response__pack, &current_job_response__get_packed_size);
    if (status!= OK)
    {
        responseContainer.error = ERROR_CODE__INVALID_PROCESS_ID;
        responseContainer.errormessage = "JOb Active or incorrect parameters";
    }
    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return OK;
}
uint32_t    ResumeCurrentJobRequestFunc(MessageContainer* requestContainer)
{
    uint32_t status = OK;

    MessageContainer responseContainer;

    ResumeCurrentJobRequest* request = resume_current_job_request__unpack(NULL, requestContainer->data.len, requestContainer->data.data);

    ResumeCurrentJobResponse response = RESUME_CURRENT_JOB_RESPONSE__INIT;
    JobStatus jobStatus = JOB_STATUS__INIT;

    if (JobActive == true)
    {
        ustrncpy (JobToken, requestContainer->token,36);
        JobResumed = true;
        usnprintf(ErrorMsg, 100, "Job Resumed");
        Report("Job resumed",__FILE__,__LINE__, JobActive,RpMessage,JobResumed,0);

        jobStatus.message =ErrorMsg;
        jobStatus.has_progress = true;
        jobStatus.progress = 0.0;
        jobStatus.has_currentsegmentindex = false;
        response.status = &jobStatus;
        response.has_canceled = false;
    }
    else
    {
        usnprintf(ErrorMsg, 100, "Job not Resumed");
        Report("Job not resumed",__FILE__,__LINE__, JobActive,RpMessage,JobResumed,0);
        jobStatus.message =ErrorMsg;
        jobStatus.has_progress = true;
        jobStatus.progress = 0.0;
        jobStatus.has_currentsegmentindex = false;
        response.status = &jobStatus;
        response.has_canceled = true;
        response.canceled = true;
    }


    responseContainer = createContainer(MESSAGE_TYPE__ResumeCurrentJobResponse,  JobToken, false, &response, &resume_current_job_response__pack, &resume_current_job_response__get_packed_size);
    if (status!= OK)
    {
        responseContainer.error = ERROR_CODE__INVALID_PROCESS_ID;
        responseContainer.errormessage = "JOb Active or incorrect parameters";
    }
    responseContainer.continuous = false;
    uint8_t* container_buffer = my_malloc(message_container__get_packed_size(&responseContainer));
    if (container_buffer)
    {
        size_t container_size = message_container__pack(&responseContainer, container_buffer);
        SendChars(container_buffer, container_size);
    }
    if (responseContainer.data.data)
        my_free(responseContainer.data.data);

    return OK;
}


void StartJob(void *JobDetails)
{
    JobMessageStruc Message;

    Message.messageId = JobRequestMsg;
    Message.msglen = MAX_MSG_LEN;
    if (JobmsgQ != NULL)
       Mailbox_post(JobmsgQ , &Message, BIOS_NO_WAIT);
}

/******************************************************************************
 *  ======== messageTsk ========
 *  Task for this function is created statically. See the project's .cfg file.
 *  this message task is created statically in system initialization,
 ******************************************************************************/
Void jobTask(UArg arg0, UArg arg1)
{
    JobMessageStruc Message;
    //char str[60];
    //uint16_t length;
    //Clock_setTimeout(HostKAClock, 1000);
    //Clock_start(HostKAClock);
    JobmsgQ = Mailbox_create(MAX_MSG_LEN, 20, NULL,NULL);


    while(1)
    {
        Mailbox_pend(JobmsgQ , &Message, BIOS_WAIT_FOREVER);
        switch (Message.messageId)
        {
            case JobRequestMsg:
                JobEndReason = JOB_OK;
                Report("JobRequestMsg",__FILE__,__LINE__, JobActive,RpMessage,JobResumed,0);
                JobActive = true;
                SetMachineStatus(MACHINE_STATE__PreparingJob);
                JobResumed = false;
                setmachineActive(true);
                PrepareState (CurrentJob);
                break;
            case ValidationResultsFail:
                //send message data as a validation error message to host
                ExitState(Message.messageData);
                break;
            case PreparationResultsOk:
                PrintState(CurrentJob);
                break;
            case PreparationResultsFail:
                //send message data as a validation error message to host
                EndState(CurrentJob, "Prepare Failed");
                //ExitState(Message.messageData);
                break;
            case PrintMessage:
                //send message data as a validation error message to host
                PrintSTMMsgHandler(&Message);
                break;
            case PrintingResultsOk:
                JobActive = false;
                setmachineActive(false);
                SetMachineStatus(MACHINE_STATE__Ready);
                resetIdleCounter();
                CurrentJob = NULL;
                  //if (CurrentRequest!= NULL)
                  //    job_request__free_unpacked(CurrentRequest,NULL);
                  //CurrentRequest = NULL;
                  SuspendLargeMessages = false;
                  LOG_ERROR(4,"ResumeLargeMessages PrintingResultsOk");
                  //DiagnosticsStart();
                //CleanState(CurrentJob);
                break;
            case PrintingResultsFail:
                JobActive = false;
                setmachineActive(false);
                SetMachineStatus(MACHINE_STATE__Error);
                resetIdleCounter();
                CurrentJob = NULL;
                  //if (CurrentRequest!= NULL)
                  //    job_request__free_unpacked(CurrentRequest,NULL);
                  //CurrentRequest = NULL;
                  SuspendLargeMessages = false;
                  LOG_ERROR(3,"ResumeLargeMessages PrintingResultsFail");
                  //DiagnosticsStart();

                //send message data as a validation error message to host
                ExitState(Message.messageData);
                break;
            case CleaningResultsOk:
                //send message data as a validation error message to host
                ExitState(Message.messageData);
                break;
            case CleaningResultsFail:
                //send message data as a validation error message to host
                ExitState(Message.messageData);
                break;
            case SystemFailure:
                //send message data as a validation error message to host
                ExitState(Message.messageData);
                break;
            case Abort:
                PrintSTMMsgHandler(&Message);
                break;
            default:
                break;
        }
    }
}