Subversion Repositories HomeAutomation

Rev

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

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