--                              -*- Mode: Ada -*-
-- Filename        : motor_handler.adb
-- Description     : synchronization for the motor
-- Author          : Christfried Webers
-- Created On      : Mon Nov  8 10:49:07 1999
-- Last Modified By: .
-- Last Modified On: .
-- Update Count    : 0
-- Status          : Experimental
-------------------------------------------------------------------
with Text_IO;                 use Text_IO;
with Ada.Float_Text_IO;       use Ada.Float_Text_IO;

with Ada.Real_Time;           use Ada.Real_Time;

with Ada.Task_Identification; use Ada.Task_Identification;
with Ada.Exceptions;          use Ada.Exceptions;


with Flex_Common;             use Flex_Common;
with Flex_Driver;
with Motor;

---------------------
package body Motor_Handler is

   ------------------------------------------------------------------------------
   --
   -- Global constants
   --
   ------------------------------------------------------------------------------

   LinearPositionScale      : constant Float :=   87.462; -- result in mm
   AngularPositionScale     : constant Float :=    659.4; -- result in degrees

   LinearVelocityScale      : constant Float := 87_462.0; -- result in m/s
   AngularVelocityScale     : constant Float :=    659.4; -- result in degrees per second

   LinearAccelerationScale  : constant Float := 10_000.0; -- result in m/s^2
   AngularAccelerationScale : constant Float :=    606.1; -- result in degrees/s^2

   LinearTorqueScale        : constant Float := 30_000.0; -- standard settings for 1.0
   AngularTorqueScale       : constant Float := 40_000.0; -- standard settings for 1.0

   LinearAxis               : constant Raw_8Bit := 0;
   AngularAxis              : constant Raw_8Bit := 1;

   Forward                  : constant Raw_8Bit := 1;
   Backward                 : constant Raw_8Bit := 0;

   Left                     : constant Raw_8Bit := 1;
   Right                    : constant Raw_8Bit := 0;


   ------------------------------------------------------------------------------
   --
   -- Reader
   --
   ------------------------------------------------------------------------------

   protected body Reader is

      procedure RecordPacket(PacketNumber: Raw_8Bit; Data: ByteArray) is
         First        : Integer := Data'First;
         Axis         : Raw_8Bit range 0..1 := Data(First+8);
         Position     : Float :=
           Float(FourBytes_To_Signed_32Bit(Data(First+9..First+12)));

         Velocity     : Float :=
           Float(FourBytes_To_Signed_32Bit(Data(First+13..First+16)));

         Acceleration : Float :=
           Float(FourBytes_To_Signed_32Bit(Data(First+17..First+20)));

         Torque : Float :=
           Float(FourBytes_To_Signed_32Bit(Data(First+21..First+24)));

      begin
         case Axis is
            when LinearAxis =>
               NewStatus.LinearPosition     :=
                 Mm(Integer(Position / LinearPositionScale));

               NewStatus.LinearVelocity     :=
                 LinVel(Velocity / LinearVelocityScale);

               NewStatus.LinearAcceleration :=
                 LinAcc(Acceleration / LinearAccelerationScale);

               NewStatus.LinearTorque :=
                 LinTorque(Torque / LinearTorqueScale);

            when AngularAxis =>
               Position :=  Position / AngularPositionScale;

               -- map the angle on -180.0 .. +180.0
               NewStatus.AngularPosition :=
                 Degrees(Float'Remainder(Position, 360.0));

               NewStatus.AngularVelocity :=
                 AngVel(Velocity / AngularVelocityScale);

               NewStatus.AngularAcceleration :=
                 AngAcc(Acceleration / AngularAccelerationScale);

               NewStatus.AngularTorque :=
                 AngTorque(Torque / AngularTorqueScale);

               NewStatus.Timestamp := Clock;
               LastStatus          := NewStatus;
               NewDataArrived      := True;
               FirstDataArrived    := True;
         end case;
      end RecordPacket;


      entry GetCurrentStatus (MotorStatus: out Motor.Status) when FirstDataArrived is
      begin
         MotorStatus := LastStatus;
      end GetCurrentStatus;


      entry WaitForNewData when NewDataArrived or NonBlockingActive is
      begin
         if WaitForNewData'Count = 0 then
            NewDataArrived := False;
         end if;
      end WaitForNewData;


      procedure NonBlocking is
      begin
         NonBlockingActive := True;
      end NonBlocking;

   end Reader;


   ------------------------------------------------------------------------------
   --
   -- Commander
   --
   ------------------------------------------------------------------------------

   procedure SendLinearCommand(Velocity: LinVel;
                               Acceleration: LinAcc;
                               Torque: LinTorque) is
      Packet          : MotorCommandType := LinMotorCommandPacket;
      RawVelocity     : Raw_32Bit;
      RawAcceleration : Raw_32Bit;
      RawTorque       : Raw_32Bit;
      RawDirection    : Raw_8Bit;

   begin
      if Velocity >= 0.0 then
         RawDirection := Forward;
      else -- Velocity < 0.0
         RawDirection := Backward;
      end if;

      RawVelocity     := Raw_32Bit(abs(Float(Velocity) * LinearVelocityScale));
      RawAcceleration := Raw_32Bit(abs(Float(Acceleration) *
                                       LinearAccelerationScale));

      RawTorque       := Raw_32Bit(abs(Float(Torque) * LinearTorqueScale));

      Packet(5)      := LinearAxis;
      Packet(6..9)   := Raw_32Bit_To_FourBytes(RawVelocity);
      Packet(10..13) := Raw_32Bit_To_FourBytes(RawAcceleration);
      Packet(14..17) := Raw_32Bit_To_FourBytes(RawTorque);
      Packet(18)     := RawDirection;

      Flex_Driver.WriteTask.SendPacket(ByteArray(Packet), LinMotorCommand);
   end SendLinearCommand;


   procedure SendAngularCommand(Velocity: AngVel;
                                Acceleration: AngAcc;
                                Torque: AngTorque) is
      Packet          : MotorCommandType := AngMotorCommandPacket;
      RawVelocity     : Raw_32Bit;
      RawAcceleration : Raw_32Bit;
      RawTorque       : Raw_32Bit;
      RawDirection    : Raw_8Bit;
   begin
      if Velocity >= 0.0 then
         RawDirection := Left;
      else -- Velocity < 0.0
         RawDirection := Right;
      end if;

      RawVelocity     := Raw_32Bit(abs(Float(Velocity) * AngularVelocityScale));
      RawAcceleration := Raw_32Bit(abs(Float(Acceleration) *
                                       AngularAccelerationScale));

      RawTorque       := Raw_32Bit(abs(Float(Torque) * AngularTorqueScale));

      Packet(5)       := AngularAxis;
      Packet(6..9)    := Raw_32Bit_To_FourBytes(RawVelocity);
      Packet(10..13)  := Raw_32Bit_To_FourBytes(RawAcceleration);
      Packet(14..17)  := Raw_32Bit_To_FourBytes(RawTorque);
      Packet(18)      := RawDirection;

      Flex_Driver.WriteTask.SendPacket(ByteArray(Packet), AngMotorCommand);
   end SendAngularCommand;


   protected body Commander is

      procedure StartReading is
      begin
         Flex_Driver.WriteTask.SendPacket(ByteArray(MotorStartSendingPacket),
                                          MotorStartStopSending);

         -- Flex_Driver.WriteTask.SendPacket(ByteArray(DIOStartSendingPacket),
         --                                 DIOStartStopSending);
      end StartReading;


      procedure StopReading is
      begin
         Flex_Driver.WriteTask.SendPacket(ByteArray(MotorStopSendingPacket),
                                          MotorStartStopSending);

         --Flex_Driver.WriteTask.SendPacket(ByteArray(DIOStopSendingPacket),
         --                                 DIOStartStopSending);
      end StopReading;


      procedure SetLinearVelocity (Velocity: LinVel) is
      begin
         LinearVelocity := Velocity;
         SendLinearCommand(LinearVelocity, LinearAcceleration, LinearTorque);
      end SetLinearVelocity;


      procedure SetAngularVelocity (Velocity: AngVel) is
      begin
         AngularVelocity := Velocity;
         SendAngularCommand(AngularVelocity, AngularAcceleration, AngularTorque);
      end SetAngularVelocity;


      procedure SetLinearAcceleration (Acceleration: LinAcc) is
      begin
         LinearAcceleration := Acceleration;
         SendLinearCommand(LinearVelocity, LinearAcceleration, LinearTorque);
      end SetLinearAcceleration;


      procedure SetAngularAcceleration (Acceleration: AngAcc) is
      begin
         AngularAcceleration := Acceleration;
         SendAngularCommand(AngularVelocity, AngularAcceleration, AngularTorque);
      end SetAngularAcceleration;


      procedure SetLinearTorque (Torque: LinTorque) is
      begin
         LinearTorque := Torque;
         SendLinearCommand(LinearVelocity, LinearAcceleration, LinearTorque);
      end SetLinearTorque;


      procedure SetAngularTorque (Torque: AngTorque) is
      begin
         AngularTorque := Torque;
         SendAngularCommand(AngularVelocity, AngularAcceleration, AngularTorque);
      end SetAngularTorque;

   end Commander;

end Motor_Handler;