Subversion Repositories HomeAutomation

Rev

Rev 501 | Rev 563 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /**
  2.  * CAN Servo.
  3.  *
  4.  * Input: 0 to 255
  5.  * Position msg: <byte0 BLINDS_CMD> <byte1 position> <byte2 servo number>
  6.  * Turning msg: <byte0 START/STOP> <byte 1 direction> <byte2 servo number>
  7.  *
  8.  * @date    2007-01-01
  9.  * @author  Erik Larsson
  10.  *
  11.  */
  12.  
  13. /*-----------------------------------------------------------------------------
  14.  * Includes
  15.  *---------------------------------------------------------------------------*/
  16. /* system files */
  17. #include <avr/io.h>
  18. #include <avr/interrupt.h>
  19. #include <inttypes.h>
  20. #include <stdio.h>
  21.  
  22. /* lib files */
  23. #include <bios.h>
  24. #include <config.h>
  25. #include <settings.h>
  26.  
  27. #include <drivers/timer/timebase.h>
  28. #include <drivers/sensor/tc1047/tc1047.h>
  29. #include <drivers/actuator/rc-servo/rc_servo.h>
  30.  
  31. /*-----------------------------------------------------------------------------
  32.  * Defines
  33.  *---------------------------------------------------------------------------*/
  34. #define FAILSAFE_MODE       0x0F
  35. #define BLINDS_CMD_ABS      0x01 // Absolute position
  36. #define BLINDS_CMD_REL      0x02 // Relative position
  37. #define BLINDS_CMD_START    0x03 // Start turning RC-servo
  38. #define BLINDS_CMD_STOP     0x04 // Stop turning RC-servo
  39. #define BLINDS_CMD_RESET    0x05
  40. #define BLINDS_CMD_STATUS   0x06
  41.  
  42. #define BLINDS_TURN_STOP    0x00
  43. #define BLINDS_TURN_CCW     0x01
  44. #define BLINDS_TURN_CW      0x02
  45.  
  46. #define STATUS_SEND_PERIOD      5000 // ms
  47. #define FAILSAFE_SEND_PERIOD    10000 // ms
  48. #define BOUNCE_TIME             10 // ms
  49. #define BUTTON1                 1
  50. #define BUTTON2                 2
  51.  
  52. #define SERVO_FEED_PORT         PORTC
  53. #define SERVO_FEED_DDR          DDRC
  54. #define SERVO_FEED_PIN          PC0
  55.  
  56. #define APP_TYPE    CAN_APPTYPES_SERVO
  57. #define APP_VERSION 0x0001
  58.  
  59.  
  60. /*-------------------------------------------------------------------------
  61.  * Global variables
  62.  * -----------------------------------------------------------------------*/
  63. /*#if defined(TWO_BUTTON_MODE)
  64. Can_Message_t txMsg_Button;
  65. #endif*/
  66.  
  67. volatile uint8_t rxMsgFull;
  68.  
  69. volatile Can_Message_t rxMsg;
  70.  
  71. /*----------------------------------------------------------------------------
  72.  * Functions
  73.  * -------------------------------------------------------------------------*/
  74. void blindsFailsafe(void);
  75.  
  76. void can_receive(Can_Message_t *msg){
  77. // CAN callback function
  78.     if(!rxMsgFull){
  79.         memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
  80.         rxMsgFull = 1;
  81.     }
  82. }
  83. /*----------------------------------------------------------------------------
  84.  * Interrupt routines
  85.  * -------------------------------------------------------------------------*/
  86. #if defined(TWO_BUTTON_MODE)
  87. #error two button mode is still untested
  88. ISR( PCINT2_vect )
  89. {
  90.     /*
  91.      * Auxiliary button pressed and released
  92.      * Check time between press and release to eliminate bounces
  93.      */
  94.     static uint32_t buttonTime[2];
  95.  
  96.     txMsg_Button.RemoteFlag = 0;
  97.     txMsg_Button.ExtendedFlag = 1;
  98.  
  99.     if( (PIND & (1<<PD1)) == 0){
  100.         /* Button pressed */
  101.         buttonTime[0] = Timebase_CurrentTime();
  102.     }else if( (PIND & (1<<PD1)) == 1){
  103.         if( Timebase_PassedTimeMillis( buttonTime[0] ) >= BOUNCE_TIME ){
  104.             /* No bounce, send message */
  105.             txMsg_Button.Id = BUTTON_ID;
  106.             txMsg_Button.DataLength = 1;
  107.             txMsg_Button.Data.bytes[0] = BUTTON1;
  108.             return;
  109.         }else{
  110.             /* Just bounces, ignore it */
  111.             return;
  112.         }
  113.     }
  114.     if( (PIND & (1<<PD2)) == 0){
  115.         /* Button pressed */
  116.         buttonTime[1] = Timebase_CurrentTime();
  117.     }else if( (PIND & (1<<PD2)) == 1){
  118.         if( Timebase_PassedTimeMillis( buttonTime[1] ) >= BOUNCE_TIME ){
  119.             /* No bounce, send message */
  120.             txMsg_Button.Id = BUTTON_ID;
  121.             txMsg_Button.DataLength = 1;
  122.             txMsg_Button.Data.bytes[0] = BUTTON2;
  123.             return;
  124.         }else{
  125.             /* Just bounces, ignore it */
  126.             return;
  127.         }
  128.     }
  129. }
  130. #endif
  131.  
  132. /*-----------------------------------------------------------------------------
  133.  * Main Program
  134.  *---------------------------------------------------------------------------*/
  135. int main(void) {
  136.     uint8_t temp_id, servoid;
  137.     uint16_t acttype;
  138.  
  139.     uint8_t //blindsStatus, /* Position (-128 to 127) */
  140.             servoToTurn,
  141.             turnDirection = BLINDS_TURN_STOP; /* Specifies direction to turn or stopped */
  142.     uint32_t boardTemperature = 0;
  143.     uint32_t timeStamp = 0, timeStampTurn = 0, servoFeed_timeStamp = 0;
  144.  
  145.     Can_Message_t txMsg;
  146.  
  147.     // Set up callback for CAN messages
  148.     BIOS_CanCallback = &can_receive;
  149.  
  150.     sei();
  151.  
  152.     Timebase_Init();
  153.     adcTemperatureInit();
  154.     rcServoInit();
  155.  
  156. #if defined(TWO_BUTTON_MODE)
  157.     /*
  158.      * Initialize buttons
  159.      * It is possible to use ie. sensors instead
  160.      * but then change this
  161.      */
  162.     /* Set as input and enable pull-up */
  163.     DDRD &= ~( (1<<DDD1)|(1<<DDD2) );
  164.     PORTD |= (1<<PD1)|(1<<PD2);
  165.  
  166.     /* Enable IO-pin interrupt */
  167.     PCICR |= (1<<PCIE2);
  168.     /* Unmask PD1 and SERVO_FEED_PIN */
  169.     PCMSK2 |= (1<<PCINT16) | (1<<PCINT17);
  170. #endif
  171.     /* Set output and turn off the servo current feed */
  172.     //SERVO_FEED_DDR |= (1<<SERVO_FEED_PIN);
  173.     //SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  174.  
  175.     txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
  176.     txMsg.RemoteFlag = 0;
  177.     txMsg.ExtendedFlag = 1;
  178.     txMsg.DataLength = 4;
  179.     txMsg.Data.words[0] = APP_TYPE;
  180.     txMsg.Data.words[1] = APP_VERSION;
  181.  
  182.     BIOS_CanSend(&txMsg); // Send startup message
  183.  
  184.     txMsg.Id = 0x08000c0b; //(CLASS_SNS << CLASS_MASK_BITS)|(SNS_ACT_STATUS_SERVO << TYPE_MASK_BITS)|(NODE_ID << SID_MASK_BITS);
  185.  
  186.     // Main loop
  187.     while (1) {
  188.         // check if any messages have been received
  189.         if(rxMsgFull){
  190.             if( ((rxMsg.Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS) == CAN_ACT ){
  191.                 // Actuator package
  192.                 acttype = (uint16_t)((rxMsg.Id & CAN_MASK_ACT_TYPE) >> CAN_SHIFT_ACT_TYPE);
  193.                 servoid = (uint8_t)((rxMsg.Id & CAN_MASK_ACT_ID) >> CAN_SHIFT_ACT_ID);
  194.  
  195.         // Check if it is command to control this servo
  196.                 if(acttype == ACT_TYPE_SERVO && (servoid == SERVOID_1 || servoid == SERVOID_2 || servoid == SERVOID_3)){
  197.                     // This node that control a servo is adressed
  198.                     if(servoid == SERVOID_1){
  199.                         temp_id = 1; // First servo
  200.                     }else if(servoid == SERVOID_2){
  201.                         temp_id = 2; // and so on
  202.                     }else if(servoid == SERVOID_3){
  203.                         temp_id = 3;
  204.                     }else{
  205.                         temp_id = 0;
  206.                     }
  207.  
  208.                     if(rxMsg.DataLength == 1 || (rxMsg.DataLength == 2 && rxMsg.Data.bytes[1] == BLINDS_CMD_ABS)){
  209.                         // Set absolute position to servo
  210.  
  211.                         setPosition( rxMsg.Data.bytes[0], temp_id );
  212.                         servoFeed_timeStamp = Timebase_CurrentTime();
  213.  
  214.                     }else if(rxMsg.DataLength == 2){
  215.                         if(rxMsg.Data.bytes[1] == BLINDS_CMD_REL){
  216.                             // Set relative position to servo
  217.  
  218.                             alterPosition( rxMsg.Data.bytes[0], temp_id );
  219.                             servoFeed_timeStamp = Timebase_CurrentTime();
  220.  
  221.                         }else if(rxMsg.Data.bytes[1] == BLINDS_CMD_START ){
  222.                             // Start turning the servo
  223.  
  224.                             turnDirection = (rxMsg.Data.bytes[0]&0x80)?BLINDS_TURN_CW:BLINDS_TURN_CCW; // FIXME riktning beroende på positivt eller negativt tal?
  225.                             servoToTurn = temp_id;
  226.                             servoFeed_timeStamp = Timebase_CurrentTime();
  227.  
  228.                         }else if(rxMsg.Data.bytes[1] == BLINDS_CMD_STOP ){
  229.                             // Stop turning
  230.  
  231.                             turnDirection = BLINDS_TURN_STOP;
  232.  
  233.                         }/*else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STATUS){
  234.                             // Send blinds status to CAN
  235.                             boardTemperature = getTC1047temperature();
  236.  
  237.                             if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  238.                                 blindsFailsafe();
  239.                             }else{
  240.                             txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  241.                             txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  242.                             txMsg.Data.bytes[2] = 0x00;
  243.                             txMsg.Data.bytes[3] = getPosition(1);
  244.                             txMsg.Data.bytes[4] = getPosition(2);
  245.                             txMsg.Data.bytes[5] = getPosition(3);
  246.                             txMsg.DataLength = 6;
  247.                             BIOS_CanSend(&txMsg);
  248.                         }*/
  249.                     }
  250.                 }
  251.             }
  252.  
  253.             rxMsgFull = 0;
  254.         }
  255.  
  256.         if( (Timebase_CurrentTime() - timeStamp)  >= STATUS_SEND_PERIOD ){
  257.             timeStamp = Timebase_CurrentTime();
  258.             // Send blinds status to CAN periodically
  259.  
  260.             boardTemperature = getTC1047temperature();
  261.  
  262.             if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  263.                 blindsFailsafe();
  264.                 }else{
  265.                 txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  266.                 txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  267.                 txMsg.Data.bytes[2] = 0x00;
  268.                 txMsg.Data.bytes[3] = getPosition(1);
  269.                 txMsg.Data.bytes[4] = getPosition(2);
  270.                 txMsg.Data.bytes[5] = getPosition(3);
  271.                 txMsg.DataLength = 6;
  272.  
  273.                 BIOS_CanSend(&txMsg);
  274.             }
  275.         }
  276.         // If start turning servo
  277.         if( turnDirection ){
  278.             if( Timebase_CurrentTime() - timeStampTurn >= TURN_PERIOD ){
  279.                 timeStampTurn = Timebase_CurrentTime();
  280.                 // Clockwise or counterclockwise?
  281.                 if( turnDirection == BLINDS_TURN_CCW ){
  282.                     alterPosition( -STEPS_PER_TURN_PERIOD , servoToTurn);
  283.                 }else if( turnDirection == BLINDS_TURN_CW ){
  284.                     alterPosition( STEPS_PER_TURN_PERIOD , servoToTurn);
  285.                 }
  286.                 servoFeed_timeStamp = Timebase_CurrentTime();
  287.             }
  288.         }
  289.  
  290.         // Turn off the servo current feed after timeout
  291.         if( Timebase_CurrentTime() - servoFeed_timeStamp >= SERVO_FEED_TIME ){
  292.             SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  293.             servoDisable();
  294.         }else{
  295.             SERVO_FEED_PORT |= (1<<SERVO_FEED_PIN);
  296.             servoEnable();
  297.         }
  298.     }
  299.     return 0;
  300. }
  301.  
  302. void blindsFailsafe()
  303. {
  304. /*  uint32_t boardTemperature = 0, timeStamp = 0;
  305.  
  306.     // Turn of servo current feed
  307.     SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  308.  
  309.  
  310.     while(1){
  311.         // check if any messages have been received
  312.         while(rxMsgFull) {
  313.             // This relay is adressed
  314.             if(rxMsg.Data.bytes[0] == BLINDS_CMD_RESET ){
  315.                 // Return from failsafe mode
  316.                 return;
  317.             }
  318.         }
  319.  
  320.         if( Timebase_CurrentTime() - timeStamp >= FAILSAFE_SEND_PERIOD ){
  321.             timeStamp = Timebase_CurrentTime();
  322.             // Send relay status to CAN
  323.             boardTemperature = getTC1047temperature();
  324.  
  325.             txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  326.             txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  327.             txMsg.Data.bytes[2] = FAILSAFE_MODE;
  328. #if NUMBER_OF_RCS >0
  329.             txMsg.Data.bytes[3] = getPosition(1);
  330. #endif
  331. #if NUMBER_OF_RCS >1
  332.             txMsg.Data.bytes[4] = getPosition(2);
  333. #endif
  334. #if NUMBER_OF_RCS >2
  335.             txMsg.Data.bytes[5] = getPosition(3);
  336. #endif
  337.             txMsg.DataLength = NUMBER_OF_RCS+3;
  338.  
  339.             BIOS_CanSend(&txMsg);
  340.         }
  341.     }*/
  342. }
  343.  
  344.