aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Embedded_SW/Embedded/Modules/IDS/IDS_print.c
blob: bfdb7b5d7259aacbd001b7d56853855935483c43 (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
generated by cgit v1.3.1 (git 2.54.0) at 2026-07-20 04:25:44 +0000
 


 color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/************************************************************************************************************************
 * Ids_print.c
 * 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
 **************************************************************************************************************************/
#include "include.h"
#include "ids.h"
#include "ids_ex.h"
#include "../control/control.h"
#include "../control/pidalgo.h"
#include "../thread/thread.h"
#include "PMR/Hardware/Hardwaremotor.pb-c.h"
#include "PMR/Hardware/HardwareDispenser.pb-c.h"
#include "StateMachines/Printing/printingSTM.h"
#include "drivers/motors/motor.h"
#include "drivers/valves/valve.h"

#include "modules/heaters/heaters.h"


typedef struct
{
    bool                m_isEnabled;
    float            m_SetParam;
    float            m_mesuredParam;
    float               m_preError;
    float               m_integral;
    float               m_calculatedError;
    bool                m_isReady;
    PID_Config_Params   m_params;
}DispenserControlConfig_t;
HardwarePidControl DispensersControl[MAX_SYSTEM_DISPENSERS] = {0};

int32_t DispenserSamples[MAX_SYSTEM_DISPENSERS][MAX_CONTROL_SAMPLES] = {0};
int DispenserSamplePointer[MAX_SYSTEM_DISPENSERS] = {0};
double DispenserNormalizedErrorCoEfficient[MAX_SYSTEM_DISPENSERS] = {0};

HardwarePidControlType ThreadDispenserIdToControlId[MAX_SYSTEM_DISPENSERS] = {  HARDWARE_PID_CONTROL_TYPE__Dispenser1,HARDWARE_PID_CONTROL_TYPE__Dispenser2,HARDWARE_PID_CONTROL_TYPE__Dispenser3,HARDWARE_PID_CONTROL_TYPE__Dispenser4,HARDWARE_PID_CONTROL_TYPE__Dispenser5,HARDWARE_PID_CONTROL_TYPE__Dispenser6,HARDWARE_PID_CONTROL_TYPE__Dispenser7,HARDWARE_PID_CONTROL_TYPE__Dispenser8};

bool    DispenserReady[MAX_SYSTEM_DISPENSERS] = {true};

/******************** STRUCTURES AND ENUMs  ********************************************/
/******************** GLOBAL PARAMETERS  ********************************************/
DispenserControlConfig_t DispenserControlConfig[MAX_SYSTEM_DISPENSERS];
uint32_t    ControlIdtoDispenserId [MAX_SYSTEM_DISPENSERS] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
int OriginalDispenserSpd_2PPS[MAX_SYSTEM_DISPENSERS] = {0,0,0,0,0,0,0,0};
bool         DispenserPreSegmentReady[MAX_SYSTEM_DISPENSERS] = {true,true,true,true,true,true,true,true};
bool         DispenserSegmentReady[MAX_SYSTEM_DISPENSERS] = {true,true,true,true,true,true,true,true};
bool         DispenserDistanceToSpoolReady[MAX_SYSTEM_DISPENSERS] = {true,true,true,true,true,true,true,true};
int JobBrushStopId = 0;

uint32_t IDS_DispenserPidRequestMessage(HardwarePidControl* request)
{
    int Dispenser_i,i;
    //int temp;
    for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
    {
        if (ThreadDispenserIdToControlId[i] == request->hardwarepidcontroltype)
        {
            Dispenser_i = i;
            break;
        }
    }
    memcpy (&DispensersControl[Dispenser_i],request,sizeof(HardwarePidControl));
    if (DispensersControl[Dispenser_i].pvinputfilterfactormode > MAX_CONTROL_SAMPLES)
        DispensersControl[Dispenser_i].pvinputfilterfactormode = MAX_CONTROL_SAMPLES;
    for (i = 0;i < DispensersControl[Dispenser_i].pvinputfilterfactormode; i++)
        DispenserSamples[Dispenser_i][i] = 0;  //reset the samples value for control beginning
    /*DispenserNormalizedErrorCoEfficient[Dispenser_i] = (2*PI*DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].armlength);
    temp = 1<<(DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].resolutionbits);
    temp=(100*(temp-1)*DancersCfg[ThreadDispenserIdToDancerId[Dispenser_i]].maximalmovementmm);
    DispenserNormalizedErrorCoEfficient[Dispenser_i] = DispenserNormalizedErrorCoEfficient[Dispenser_i] / temp;*/

    return OK;
}

/*
 * IDS Printing support
 * Prepare: build pressure in all participating dispensers
 * Print - dispense ink to the printing head
 * stop - stop dispensing
 *
 * control processes:
 * on prepare stage - each 10msec against the pressure sensors
 * on print stage - every 10/100 msec against the speed sensor
 *
 * */
//Dispenser Pressure control
//callback - calls printing stm with the result

// registration - 10 msec, dispenser pressure sensor
//    AddControlCallback(DeviceId2Dispenser[DispenserId], DispenserControlCBFunction, eHundredMillisecond);
// start the dispenser pressure building - move up in a TBD speed, valve closed
//Dispenser Speed control
//callback - handles speed
// registration - 10msec, dispenser speed senseo
// start the dispensing - move up according to the segment defined speed and microstepping, valve opened
//
void DispenserPrepareReady(void)
{
    int i;
    for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
    {
        if (DispenserReady[i] == false)
        {
            return; //not all configured Dispensers are ready
        }
    }
    PrepareReady(Module_IDS,ModuleDone);
}

//********************************************************************************************************************
 uint32_t IDSPrepareState(void *JobDetails)
{
    int Motor_i, HW_Motor_Id, Pid_Id,i;
    //start IDS control for all motors
    for (Motor_i = 0;Motor_i < MAX_SYSTEM_DISPENSERS;Motor_i++)
    {
        HW_Motor_Id = DispenserIdToMotorId[Motor_i];
        Pid_Id = Motor_i;/*IDSMotorIdToControlId[Motor_i];*/
            DispenserControlConfig[Motor_i].m_params.MAX = 1;
            DispenserControlConfig[Motor_i].m_params.MIN = DispensersControl[Pid_Id].outputproportionalpowerlimit*-1;
            DispenserControlConfig[Motor_i].m_params.Kd = DispensersControl[Pid_Id].derivativetime;
            DispenserControlConfig[Motor_i].m_params.Kp = DispensersControl[Pid_Id].proportionalgain;
            DispenserControlConfig[Motor_i].m_params.Ki = DispensersControl[Pid_Id].integraltime;
            DispenserControlConfig[Motor_i].m_params.epsilon = 0.01;
            DispenserControlConfig[Motor_i].m_params.dt = eHundredMillisecond;
            DispenserControlConfig[Motor_i].m_calculatedError = 0;
            DispenserControlConfig[Motor_i].m_integral = 0;
            DispenserControlConfig[Motor_i].m_isEnabled = true;
            DispenserControlConfig[Motor_i].m_isReady = true;
            DispenserControlConfig[Motor_i].m_mesuredParam = 0;
            DispenserControlConfig[Motor_i].m_preError = 0;
            DispenserControlConfig[Motor_i].m_SetParam = 0;//need to update SetParams on presegment stage

            MotorSetDirection((TimerMotors_t)HW_Motor_Id,MotorsCfg[HW_Motor_Id].directionthreadwize); //set the dispenser to the
            /*Start the dispensers to build initial pressure
             * check different handling for dispensers that participate in the first segment and idle dispensers
             * start control for initial pressure
             *
             */
            //ValveCommand (Enable,MixerDirection);
    }
    //set 3 dancers to the profile positions
    for (i = 0; i < MAX_SYSTEM_DISPENSERS; i++)
    {
        DispenserReady[i] = true;
    }
    DispenserPrepareReady();
    return OK;
}

 //********************************************************************************************************************
 uint32_t IDS_Valve_PresegmentReady(uint32_t deviceID, uint32_t ReadValue)
 {
     int i;
     DispenserPreSegmentReady[deviceID] = true;
     for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
     {
         if (DispenserPreSegmentReady[i] == false)
         {
             return OK; //not all configured heaters are ready
         }
     }
     PreSegmentReady(Module_IDS,ModuleDone);
  return OK; // all configured heaters are ready
 }

//********************************************************************************************************************
uint32_t IDSPreSegmentState(void *JobDetails, int SegmentId)
{
//set the speed only before the first segment, speed is constant accros job
    JobTicket* JobTicket = JobDetails;
    int Dispenser_i,n_dispensers,DispenserId;
    TimerMotors_t HW_Motor_Id;

    JobBrushStopId = 0;

    // activate control fr all motors
    /* wait for all dispensers  to get to the required pressure
     * move the presegment ready when all dispensers are ready.
     */
    if (SegmentId>=JobTicket->n_segments)
        {
            LOG_ERROR(SegmentId,"Error Segment");
            return ERROR;
        }
    if (JobBrushStopId>=JobTicket->segments[SegmentId]->n_brushstops)
    {
        LOG_ERROR(JobBrushStopId,"Error JobBrushStopId");
        return ERROR;
    }
    if (JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->n_dispensers)
    {
        n_dispensers = JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->n_dispensers;
        for (Dispenser_i = 0;Dispenser_i < n_dispensers;Dispenser_i++)
        {
            DispenserId = JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->index;
            HW_Motor_Id = DispenserIdToMotorId[DispenserId];
            if (MotorsCfg[HW_Motor_Id].hardwaremotortype != DispenserIdToMotorId[DispenserId])//unconfigured dispenser
                continue;
            DispenserPreSegmentReady[DispenserId] = false;
            Control3WayValvesWithCallback ((Valves_t)DispenserId, MidTank_Dispenser, IDS_Valve_PresegmentReady); //direction: MidTank_Dispenser or Dispenser_Mixer

            MotorStop(HW_Motor_Id,Hard_Hiz);

            /*if (JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->has_dispenserstepdivision)
                MotorSetMicroStep(HW_Motor_Id,JobTicket->segments[SegmentId]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->dispenserstepdivision);
            else*/
                MotorSetMicroStep(HW_Motor_Id,MotorsCfg[HW_Motor_Id].microstep);

        }
    }
    //call the job state machine when the thread system is ready
    //PreSegmentReady(Module_IDS,ModuleDone);

    return OK;
}
//********************************************************************************************************************

 uint32_t IDS_Valve_SegmentReady(uint32_t deviceID, uint32_t ReadValue)
 {
     int i;
     DispenserSegmentReady[deviceID] = true;
     for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
     {
         if (DispenserSegmentReady[i] == false)
         {
             return OK; //not all configured heaters are ready
         }
     }
     SegmentReady(Module_IDS,ModuleDone);
  return OK; // all configured heaters are ready
 }

//********************************************************************************************************************
 uint32_t IDSSegmentState(void *JobDetails, int SegmentId)
{
     JobTicket* JobTicket = JobDetails;
     int Dispenser_i,n_dispensers,DispenserId;
     TimerMotors_t HW_Motor_Id;
     double segmentfirst_speed;
     int CurrentSegment = SegmentId;


     if (CurrentSegment>=JobTicket->n_segments)
         {
             LOG_ERROR(CurrentSegment,"Error Segment");
             return ERROR;
         }
     if (JobBrushStopId>=JobTicket->segments[CurrentSegment]->n_brushstops)
     {
         LOG_ERROR(JobBrushStopId,"Error JobBrushStopId");
         return ERROR;
     }
     if (JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->n_dispensers)
     {
         n_dispensers = JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->n_dispensers;
         for (Dispenser_i = 0;Dispenser_i < n_dispensers;Dispenser_i++)
         {
             DispenserId = JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->index;
             HW_Motor_Id = DispenserIdToMotorId[DispenserId];
             if (MotorsCfg[HW_Motor_Id].hardwaremotortype != DispenserIdToMotorId[DispenserId])//unconfigured dispenser
                 continue;
             //(Speed*uStep*PPR)/((2*PI*Dispenser_Radius)
             segmentfirst_speed = JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->nanolitterpersecond/
                     JobTicket->segments[CurrentSegment]->brushstops[JobBrushStopId]->dispensers[Dispenser_i]->nanoliterperpulse;
             segmentfirst_speed/=MotorsCfg[HW_Motor_Id].microstep;  //the dye supply is calculated based on a 1/8 microstep
    //         double Dispenser_speed = (segmentfirst_speed *  MotorsCfg[HW_Motor_Id].pulseperround)/(2*PI* MotorsCfg[HW_Motor_Id].pulleyradius);
             //DispenserControlConfig[Dispenser_i].m_SetParam = Dispenser_speed;
    //         OriginalDispenserSpd_2PPS[Dispenser_i] = (int)Dispenser_speed;
             if ((int)segmentfirst_speed > 0)
                 {
                     DispenserSegmentReady[DispenserId] = false;
                     Control3WayValvesWithCallback (DispenserId, Dispenser_Mixer, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
                     MotorSetSpeed(HW_Motor_Id, segmentfirst_speed);
                 }
         }
     }

    return OK;
}
 //********************************************************************************************************************
  uint32_t IDS_Valve_DistanceToSpoolReady(uint32_t deviceID, uint32_t ReadValue)
  {
      int i;
      DispenserDistanceToSpoolReady[deviceID] = true;
      for (i=0;i<MAX_SYSTEM_DISPENSERS;i++)
      {
          if (DispenserDistanceToSpoolReady[i] == false)
          {
              return OK; //not all configured heaters are ready
          }
      }
      DistanceToSpoolReady(Module_IDS,ModuleDone);
   return OK; // all configured heaters are ready
  }
 //********************************************************************************************************************
 uint32_t IDSDistanceToSpoolState(void)
 {
     int Dispenser_i,DispenserId;
     TimerMotors_t HW_Motor_Id;

         for (Dispenser_i = 0;Dispenser_i < MAX_SYSTEM_DISPENSERS;Dispenser_i++)
         {
             HW_Motor_Id = DispenserIdToMotorId[Dispenser_i];
             if (MotorsCfg[HW_Motor_Id].hardwaremotortype != DispenserIdToMotorId[Dispenser_i])//unconfigured dispenser
                 continue;
             DispenserDistanceToSpoolReady[Dispenser_i] = false;
             Control3WayValvesWithCallback ((Valves_t)Dispenser_i, MidTank_Dispenser, IDS_Valve_DistanceToSpoolReady); //direction: MidTank_Dispenser or Dispenser_Mixer

             MotorStop(HW_Motor_Id,Hard_Hiz);

         }

     return OK;
 }

//********************************************************************************************************************
 uint32_t IDSEndState(void *JobDetails)
{
     int Dispenser_i;
     for ( Dispenser_i = 0;Dispenser_i < MAX_SYSTEM_DISPENSERS;Dispenser_i++)
     {
        MotorStop(DispenserIdToMotorId[Dispenser_i],Hard_Hiz);
        Control3WayValvesWithCallback (Dispenser_i, MidTank_Dispenser, NULL); //direction: MidTank_Dispenser or Dispenser_Mixer
     }

    return OK;
}