Subversion Repositories HomeAutomation

Rev

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

  1. /**
  2.  * CanServo.
  3.  * Takes incomming packages and adjusts PWM output.
  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. //#define TWO_BUTTON_MODE /* If using two (or just one but nothing more) auxiliary buttons */
  14.  
  15. /*-----------------------------------------------------------------------------
  16.  * Includes
  17.  *---------------------------------------------------------------------------*/
  18. /* system files */
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <stdio.h>
  22. /* lib files */
  23. #include <bios.h>
  24. #include <config.h>
  25. #include <drivers/timer/timebase.h>
  26. #include <tc1047.h>
  27. #include <rc_servo.h>
  28.  
  29. #include <funcdefs.h>
  30.  
  31. /* defines */
  32. #define GROUP_ID    0x01L // FIXME
  33.  
  34. #define FAILSAFE_MODE       0x0F
  35. #define FAILSAFE_TRESHOLD   0x60  /* Degrees celcius when nodeBlinds goes into failsafe mode */
  36.  
  37. #define BLINDS_CMD_ABS      0x01 /* Absolute position */
  38. #define BLINDS_CMD_REL      0x02 /* Relative position */
  39. #define BLINDS_CMD_START    0x03 /* Start turning RC-servo */
  40. #define BLINDS_CMD_STOP     0x04 /* Stop turning RC-servo */
  41. #define BLINDS_CMD_RESET    0x05
  42. #define BLINDS_CMD_STATUS   0x06
  43.  
  44. #define BLINDS_TURN_STOP    0x00
  45. #define BLINDS_TURN_LEFT    0x01
  46. #define BLINDS_TURN_RIGHT   0x02
  47.  
  48. #define STEPS_PER_TURN_PERIOD   10 /* number of steps for each adjustment */
  49. #define TURN_PERIOD             100 /* ms */
  50. #define STATUS_SEND_PERIOD      5000 /* ms */
  51. #define FAILSAFE_SEND_PERIOD    10000 /* ms */
  52. #define BOUNCE_TIME             10 /* ms */
  53. #define SERVO_FEED_TIME         2000 /* ms */
  54. #define BUTTON1                 1
  55. #define BUTTON2                 2
  56.  
  57. #define SERVO_FEED_PORT         PORTD
  58. #define SERVO_FEED_DDR          DDRD
  59. #define SERVO_FEED_PIN          PD2
  60.  
  61.  
  62. /*-------------------------------------------------------------------------
  63.  * Global variables
  64.  * -----------------------------------------------------------------------*/
  65. /*#if defined(TWO_BUTTON_MODE)
  66. Can_Message_t txMsg_Button;
  67. #endif*/
  68.  
  69. uint8_t msg_received = 0;
  70.  
  71. Can_Message_t txMsg;
  72. Can_Message_t rxMsg;
  73.  
  74. /*----------------------------------------------------------------------------
  75.  * Functions
  76.  * -------------------------------------------------------------------------*/
  77. void blindsFailsafe();
  78.  
  79. /* Takes care about incoming messages and parses them if this node is adressed */
  80. void can_receive(Can_Message_t *msg){
  81.     uint32_t act;
  82.     uint8_t m, act_type, group, node;
  83.     if( ((msg->Id & CLASS_MASK) >> CLASS_MASK_BITS) == CLASS_ACT ){
  84.         act = (msg->Id & TYPE_MASK) >> TYPE_MASK_BITS;
  85.         act_type = (act & ACT_TYPE_MASK) >> ACT_TYPE_BITS;
  86.         group = (act & ACT_GROUP_MASK) >> ACT_GROUP_BITS;
  87.         node = (act & ACT_NODE_MASK) >> ACT_NODE_BITS;
  88.  
  89.         /* Check if it is command to control this servo */
  90.         if(act_type == ACT_TYPE_SERVO){
  91.             if(group == GROUP_ID || node == NODE_ID){
  92.                 for(m=0;m<msg->DataLength;m++){
  93.                     rxMsg.Data.bytes[m] = msg->Data.bytes[m];
  94.                 }
  95.             msg_received = 1;
  96.             }
  97.         }
  98.     }
  99. }
  100. /*----------------------------------------------------------------------------
  101.  * Interrupt routines
  102.  * -------------------------------------------------------------------------*/
  103. #if defined(TWO_BUTTON_MODE)
  104. #error two button mode is still untested
  105. ISR( PCINT2_vect )
  106. {
  107.     /*
  108.      * Auxiliary button pressed and released
  109.      * Check time between press and release to eliminate bounces
  110.      */
  111.     static uint32_t buttonTime[2];
  112.  
  113.     txMsg_Button.RemoteFlag = 0;
  114.     txMsg_Button.ExtendedFlag = 1;
  115.  
  116.     if( (PIND & (1<<PD1)) == 0){
  117.         /* Button pressed */
  118.         buttonTime[0] = Timebase_CurrentTime();
  119.     }else if( (PIND & (1<<PD1)) == 1){
  120.         if( Timebase_PassedTimeMillis( buttonTime[0] ) >= BOUNCE_TIME ){
  121.             /* No bounce, send message */
  122.             txMsg_Button.Id = BUTTON_ID;
  123.             txMsg_Button.DataLength = 1;
  124.             txMsg_Button.Data.bytes[0] = BUTTON1;
  125.             return;
  126.         }else{
  127.             /* Just bounces, ignore it */
  128.             return;
  129.         }
  130.     }
  131.     if( (PIND & (1<<PD2)) == 0){
  132.         /* Button pressed */
  133.         buttonTime[1] = Timebase_CurrentTime();
  134.     }else if( (PIND & (1<<PD2)) == 1){
  135.         if( Timebase_PassedTimeMillis( buttonTime[1] ) >= BOUNCE_TIME ){
  136.             /* No bounce, send message */
  137.             txMsg_Button.Id = BUTTON_ID;
  138.             txMsg_Button.DataLength = 1;
  139.             txMsg_Button.Data.bytes[0] = BUTTON2;
  140.             return;
  141.         }else{
  142.             /* Just bounces, ignore it */
  143.             return;
  144.         }
  145.     }
  146. }
  147. #endif
  148.  
  149. /*-----------------------------------------------------------------------------
  150.  * Main Program
  151.  *---------------------------------------------------------------------------*/
  152. int main(viod) {
  153.  
  154.     uint8_t //blindsStatus, /* Position (-128 to 127) */
  155.             servoToTurn,
  156.             turnDirection = BLINDS_TURN_STOP; /* Specifies direction to turn or stopped */
  157.     uint32_t boardTemperature = 0;
  158.     uint32_t timeStamp = 0, timeStampTurn = 0, servoFeed_timeStamp = 0;
  159.  
  160.     sei();
  161.    
  162.     Timebase_Init();
  163.     adcTemperatureInit();
  164.     rcServoInit();
  165.  
  166. #if defined(TWO_BUTTON_MODE)
  167.     /*
  168.      * Initialize buttons
  169.      * It is possible to use ie. sensors instead
  170.      * but then change this
  171.      */
  172.     /* Set as input and enable pull-up */
  173.     DDRD &= ~( (1<<DDD1)|(1<<DDD2) );
  174.     PORTD |= (1<<PD1)|(1<<PD2);
  175.  
  176.     /* Enable IO-pin interrupt */
  177.     PCICR |= (1<<PCIE2);
  178.     /* Unmask PD1 and SERVO_FEED_PIN */
  179.     PCMSK2 |= (1<<PCINT16) | (1<<PCINT17);
  180. #endif
  181.     /* Set output and turn off the servo current feed */
  182.     SERVO_FEED_DDR |= (1<<SERVO_FEED_PIN);
  183.     SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  184.  
  185.     txMsg.RemoteFlag = 0;
  186.     txMsg.ExtendedFlag = 1;
  187.     txMsg.Id = (CLASS_SNS << CLASS_MASK_BITS)|(SNS_ACT_STATUS_SERVO << TYPE_MASK_BITS)|(NODE_ID << SID_MASK_BITS);
  188.  
  189.     /* Set up callback for CAN messages */
  190.     BIOS_CanCallback = &can_receive;
  191.  
  192.     /* main loop */
  193.     while (1) {
  194.         /* check if any messages have been received */
  195.         if(msg_received){
  196.             /* This node that control a servo is adressed */
  197.             if( rxMsg.Data.bytes[0] == BLINDS_CMD_ABS ){
  198.                 /* Set absolute position to servo */
  199.                 setPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
  200.                 servoFeed_timeStamp = Timebase_CurrentTime();
  201.  
  202.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_REL){
  203.                 /* Set relative position to servo */
  204.                 alterPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
  205.                 servoFeed_timeStamp = Timebase_CurrentTime();
  206.  
  207.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_START ){
  208.                 /* Start turning the servo */
  209.                 turnDirection = rxMsg.Data.bytes[1];
  210.                 servoToTurn = rxMsg.Data.bytes[2];
  211.                 servoFeed_timeStamp = Timebase_CurrentTime();
  212.  
  213.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STOP ){
  214.                 /* Stop turning */
  215.                 turnDirection = BLINDS_TURN_STOP;
  216.  
  217.             }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STATUS){
  218.                 /* Send blinds status to CAN */
  219.                 boardTemperature = getTC1047temperature();
  220.  
  221.                 if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  222.                     blindsFailsafe();
  223.                 }else{
  224.                     txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  225.                     txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  226.                     txMsg.Data.bytes[2] = 0x00;
  227. #if NUMBER_OF_RCS >0
  228.                     txMsg.Data.bytes[3] = getPosition(1);
  229. #endif
  230. #if NUMBER_OF_RCS >1
  231.                     txMsg.Data.bytes[4] = getPosition(2);
  232. #endif
  233. #if NUMBER_OF_RCS >2
  234.                     txMsg.Data.bytes[5] = getPosition(3);
  235. #endif
  236.                     txMsg.DataLength = NUMBER_OF_RCS+3;
  237.                     BIOS_CanSend(&txMsg);
  238.                     }
  239.                 }
  240.                 msg_received = 0;
  241.         }
  242.  
  243.         if( (Timebase_CurrentTime() - timeStamp)  >= STATUS_SEND_PERIOD ){
  244.             timeStamp = Timebase_CurrentTime();
  245.             /* Send blinds status to CAN */
  246.  
  247.             boardTemperature = getTC1047temperature();
  248.  
  249.             if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
  250.                 blindsFailsafe();
  251.             }else{
  252.                 txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  253.                 txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  254.                 txMsg.Data.bytes[2] = 0x00;
  255. #if NUMBER_OF_RCS >0
  256.                 txMsg.Data.bytes[3] = getPosition(1);
  257. #endif
  258. #if NUMBER_OF_RCS >1
  259.                 txMsg.Data.bytes[4] = getPosition(2);
  260. #endif
  261. #if NUMBER_OF_RCS >2
  262.                 txMsg.Data.bytes[5] = getPosition(3);
  263. #endif
  264.                 txMsg.DataLength = NUMBER_OF_RCS+3;
  265.  
  266.                 BIOS_CanSend(&txMsg);
  267.             }
  268.         }
  269.         /* If start turning servo */
  270.         if( turnDirection ){
  271.             if( Timebase_CurrentTime() - timeStampTurn >= TURN_PERIOD ){
  272.                 timeStampTurn = Timebase_CurrentTime();
  273.                 /* Clockwise or counterclockwise? */
  274.                 if( turnDirection == BLINDS_TURN_LEFT ){
  275.                     alterPosition( -STEPS_PER_TURN_PERIOD , servoToTurn);
  276.                 }else if( turnDirection == BLINDS_TURN_RIGHT ){
  277.                     alterPosition( STEPS_PER_TURN_PERIOD , servoToTurn);
  278.                 }
  279.             }
  280.         }
  281.         /* Turn off the servo current feed */
  282.         if( Timebase_CurrentTime() - servoFeed_timeStamp >= SERVO_FEED_TIME ){
  283.             SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  284.         }else{
  285.             SERVO_FEED_PORT |= (1<<SERVO_FEED_PIN);
  286.         }
  287.     }
  288.     return 0;
  289. }
  290.  
  291. void blindsFailsafe()
  292. {
  293.     uint32_t boardTemperature = 0, timeStamp = 0;
  294.  
  295.     /* Turn of servo current feed */
  296.     SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
  297.  
  298.  
  299.     while(1){
  300.         /* check if any messages have been received */
  301.         while(msg_received) {
  302.             /* This relay is adressed*/
  303.             if(rxMsg.Data.bytes[0] == BLINDS_CMD_RESET ){
  304.                 /* Return from failsafe mode */
  305.                 return;
  306.             }
  307.         }
  308.  
  309.         if( Timebase_CurrentTime() - timeStamp >= FAILSAFE_SEND_PERIOD ){
  310.             timeStamp = Timebase_CurrentTime();
  311.             /* Send relay status to CAN */
  312.             boardTemperature = getTC1047temperature();
  313.  
  314.             txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
  315.             txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
  316.             txMsg.Data.bytes[2] = FAILSAFE_MODE;
  317. #if NUMBER_OF_RCS >0
  318.             txMsg.Data.bytes[3] = getPosition(1);
  319. #endif
  320. #if NUMBER_OF_RCS >1
  321.             txMsg.Data.bytes[4] = getPosition(2);
  322. #endif
  323. #if NUMBER_OF_RCS >2
  324.             txMsg.Data.bytes[5] = getPosition(3);
  325. #endif
  326.             txMsg.DataLength = NUMBER_OF_RCS+3;
  327.  
  328.             BIOS_CanSend(&txMsg);
  329.         }
  330.     }
  331. }
  332.  
  333.