Subversion Repositories HomeAutomation

Rev

Details | Last modification | View Log | SVN | RSS feed

Rev Author Line No. Line
207 eqlazer 1
/**
2
 * CanBlinds.
3
 * Takes incomming packages and adjusts PWM output.
4
 * Input: -128 to +127
249 eqlazer 5
 * Position msg: <byte0 BLINDS_CMD> <byte1 position> <byte2 servo number>
6
 * Turning msg: <byte0 START/STOP> <byte 1 direction> <byte2 servo number>
207 eqlazer 7
 *
317 eqlazer 8
 * @date    2007-01-01
207 eqlazer 9
 * @author  Erik Larsson
249 eqlazer 10
 *
207 eqlazer 11
 */
12
 
317 eqlazer 13
//#define TWO_BUTTON_MODE /* If using two (or just one but nothing more) auxiliary buttons */
207 eqlazer 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 */
317 eqlazer 23
#include <bios.h>
246 eqlazer 24
#include <tc1047.h>
214 eqlazer 25
#include <rc_servo.h>
207 eqlazer 26
 
317 eqlazer 27
#include <eqlazer_funcdefs.h>
28
 
207 eqlazer 29
/* defines */
322 eqlazer 30
#define GROUP_ID    0x01L // FIXME
317 eqlazer 31
 
207 eqlazer 32
#define FAILSAFE_MODE       0x0F
214 eqlazer 33
#define FAILSAFE_TRESHOLD   60  /* Degrees celcius when nodeBlinds goes into failsafe mode */
207 eqlazer 34
 
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
214 eqlazer 40
#define BLINDS_CMD_STATUS   0x06
207 eqlazer 41
 
214 eqlazer 42
#define BLINDS_TURN_STOP    0x00
43
#define BLINDS_TURN_LEFT    0x01
44
#define BLINDS_TURN_RIGHT   0x02
207 eqlazer 45
 
317 eqlazer 46
#define STEPS_PER_TURN_PERIOD   10 /* number of steps for each adjustment */
47
#define TURN_PERIOD             100 /* ms */
320 eqlazer 48
#define STATUS_SEND_PERIOD      5000 /* ms */
317 eqlazer 49
#define FAILSAFE_SEND_PERIOD    10000 /* ms */
50
#define BOUNCE_TIME             10 /* ms */
51
#define SERVO_FEED_TIME         2000 /* ms */
52
#define BUTTON1                 1
53
#define BUTTON2                 2
207 eqlazer 54
 
323 eqlazer 55
#define SERVO_FEED_PORT         PORTC
56
#define SERVO_FEED_DDR          DDRC
57
#define SERVO_FEED_PIN          PC0
58
 
317 eqlazer 59
#define TRUE 1
60
#define FALSE !TRUE
61
 
207 eqlazer 62
/*-------------------------------------------------------------------------
63
 * Global variables
64
 * -----------------------------------------------------------------------*/
317 eqlazer 65
/*#if defined(TWO_BUTTON_MODE)
207 eqlazer 66
Can_Message_t txMsg_Button;
317 eqlazer 67
#endif*/
207 eqlazer 68
 
317 eqlazer 69
uint8_t msg_received = FALSE;
70
 
71
Can_Message_t txMsg;
72
Can_Message_t rxMsg;
73
 
207 eqlazer 74
/*----------------------------------------------------------------------------
75
 * Functions
76
 * -------------------------------------------------------------------------*/
77
void blindsFailsafe();
78
 
317 eqlazer 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 = TRUE;
96
            }
97
        }
98
    }
99
}
100
 
207 eqlazer 101
/*----------------------------------------------------------------------------
102
 * Interrupt routines
103
 * -------------------------------------------------------------------------*/
317 eqlazer 104
#if defined(TWO_BUTTON_MODE)
105
#error two button mode is still untested
207 eqlazer 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
 
317 eqlazer 117
    if( (PIND & (1<<PD1)) == 0){
207 eqlazer 118
        /* Button pressed */
119
        buttonTime[0] = Timebase_CurrentTime();
317 eqlazer 120
    }else if( (PIND & (1<<PD1)) == 1){
207 eqlazer 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
    }
317 eqlazer 132
    if( (PIND & (1<<PD2)) == 0){
207 eqlazer 133
        /* Button pressed */
134
        buttonTime[1] = Timebase_CurrentTime();
317 eqlazer 135
    }else if( (PIND & (1<<PD2)) == 1){
207 eqlazer 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
 
317 eqlazer 155
    uint8_t //blindsStatus, /* Position (-128 to 127) */
249 eqlazer 156
            servoToTurn,
214 eqlazer 157
            turnDirection = BLINDS_TURN_STOP; /* Specifies direction to turn or stopped */
207 eqlazer 158
    uint32_t boardTemperature = 0;
317 eqlazer 159
    uint32_t timeStamp = 0, timeStampTurn = 0, servoFeed_timeStamp = 0;
207 eqlazer 160
 
320 eqlazer 161
    sei();
317 eqlazer 162
    adcTemperatureInit();
163
    rcServoInit();
207 eqlazer 164
 
317 eqlazer 165
#if defined(TWO_BUTTON_MODE)
207 eqlazer 166
    /*
167
     * Initialize buttons
168
     * It is possible to use ie. sensors instead
169
     * but then change this
170
     */
171
    /* Set as input and enable pull-up */
317 eqlazer 172
    DDRD &= ~( (1<<DDD1)|(1<<DDD2) );
173
    PORTD |= (1<<PD1)|(1<<PD2);
207 eqlazer 174
 
175
    /* Enable IO-pin interrupt */
317 eqlazer 176
    PCICR |= (1<<PCIE2);
323 eqlazer 177
    /* Unmask PD1 and SERVO_FEED_PIN */
317 eqlazer 178
    PCMSK2 |= (1<<PCINT16) | (1<<PCINT17);
207 eqlazer 179
#endif
317 eqlazer 180
    /* Set output and turn off the servo current feed */
323 eqlazer 181
    SERVO_FEED_DDR |= (1<<SERVO_FEED_PIN);
182
    SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
207 eqlazer 183
 
317 eqlazer 184
    txMsg.RemoteFlag = 0;
185
    txMsg.ExtendedFlag = 1;
186
    txMsg.Id = (CLASS_SNS << CLASS_MASK_BITS)|(SNS_ACT_STATUS_SERVO << TYPE_MASK_BITS)|(NODE_ID << SID_MASK_BITS);
187
 
188
    /* Set up callback for CAN messages */
189
    bios->can_callback = &can_receive;
190
 
207 eqlazer 191
    /* main loop */
317 eqlazer 192
    while (1) {
193
        /* check if any messages have been received */
194
        if(msg_received){
195
            /* This node that control a servo is adressed */
196
            if( rxMsg.Data.bytes[0] == BLINDS_CMD_ABS ){
197
                /* Set absolute position to servo */
198
                setPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
323 eqlazer 199
                servoFeed_timeStamp = bios->timebase_get();
207 eqlazer 200
 
317 eqlazer 201
            }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_REL){
202
                /* Set relative position to servo */
203
                alterPosition( rxMsg.Data.bytes[1], rxMsg.Data.bytes[2] );
323 eqlazer 204
                servoFeed_timeStamp = bios->timebase_get();
207 eqlazer 205
 
317 eqlazer 206
            }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_START ){
207
                /* Start turning the servo */
208
                turnDirection = rxMsg.Data.bytes[1];
209
                servoToTurn = rxMsg.Data.bytes[2];
323 eqlazer 210
                servoFeed_timeStamp = bios->timebase_get();
207 eqlazer 211
 
317 eqlazer 212
            }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STOP ){
213
                /* Stop turning */
214
                turnDirection = BLINDS_TURN_STOP;
207 eqlazer 215
 
317 eqlazer 216
            }else if(rxMsg.Data.bytes[0] == BLINDS_CMD_STATUS){
217
                /* Send blinds status to CAN */
218
                boardTemperature = getTC1047temperature();
207 eqlazer 219
 
317 eqlazer 220
                if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
221
                    blindsFailsafe();
222
                }else{
223
                    txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
224
                    txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
225
                    txMsg.Data.bytes[2] = 0x00;
249 eqlazer 226
#if NUMBER_OF_RCS >0
317 eqlazer 227
                    txMsg.Data.bytes[3] = getPosition(1);
249 eqlazer 228
#endif
229
#if NUMBER_OF_RCS >1
317 eqlazer 230
                    txMsg.Data.bytes[4] = getPosition(2);
249 eqlazer 231
#endif
232
#if NUMBER_OF_RCS >2
317 eqlazer 233
                    txMsg.Data.bytes[5] = getPosition(3);
249 eqlazer 234
#endif
317 eqlazer 235
                    txMsg.DataLength = NUMBER_OF_RCS+3;
236
                    bios->can_send(&txMsg);
207 eqlazer 237
                    }
238
                }
317 eqlazer 239
                msg_received = FALSE;
207 eqlazer 240
        }
241
 
320 eqlazer 242
        if( (bios->timebase_get() - timeStamp)  >= STATUS_SEND_PERIOD ){
317 eqlazer 243
            timeStamp = bios->timebase_get();
207 eqlazer 244
            /* Send blinds status to CAN */
245
 
246
            boardTemperature = getTC1047temperature();
247
 
248
            if( (int32_t)boardTemperature >= FAILSAFE_TRESHOLD ){
249
                blindsFailsafe();
250
            }else{
251
                txMsg.Data.bytes[0] = boardTemperature & 0x00FF;
252
                txMsg.Data.bytes[1] = (boardTemperature & 0xFF00)>>8;
249 eqlazer 253
                txMsg.Data.bytes[2] = 0x00;
254
#if NUMBER_OF_RCS >0
255
                txMsg.Data.bytes[3] = getPosition(1);
256
#endif
257
#if NUMBER_OF_RCS >1
258
                txMsg.Data.bytes[4] = getPosition(2);
259
#endif
260
#if NUMBER_OF_RCS >2
261
                txMsg.Data.bytes[5] = getPosition(3);
262
#endif
263
                txMsg.DataLength = NUMBER_OF_RCS+3;
207 eqlazer 264
 
317 eqlazer 265
                bios->can_send(&txMsg);
207 eqlazer 266
            }
267
        }
214 eqlazer 268
        /* If start turning servo */
317 eqlazer 269
        if( turnDirection ){
270
            if( bios->timebase_get() - timeStampTurn >= TURN_PERIOD ){
271
                timeStampTurn = bios->timebase_get();
214 eqlazer 272
                /* Clockwise or counterclockwise? */
273
                if( turnDirection == BLINDS_TURN_LEFT ){
249 eqlazer 274
                    alterPosition( -STEPS_PER_TURN_PERIOD , servoToTurn);
214 eqlazer 275
                }else if( turnDirection == BLINDS_TURN_RIGHT ){
249 eqlazer 276
                    alterPosition( STEPS_PER_TURN_PERIOD , servoToTurn);
214 eqlazer 277
                }
278
            }
279
        }
317 eqlazer 280
        /* Turn off the servo current feed */
281
        if( bios->timebase_get() - servoFeed_timeStamp >= SERVO_FEED_TIME ){
323 eqlazer 282
            SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
317 eqlazer 283
        }else{
323 eqlazer 284
            SERVO_FEED_PORT |= (1<<SERVO_FEED_PIN);
317 eqlazer 285
        }
207 eqlazer 286
    }
287
    return 0;
288
}
289
 
317 eqlazer 290
void blindsFailsafe()
207 eqlazer 291
{
317 eqlazer 292
    uint8_t relayStatus;
293
    uint32_t boardTemperature = 0, timeStamp = 0;
207 eqlazer 294
 
317 eqlazer 295
    /* Turn of servo current feed */
323 eqlazer 296
    SERVO_FEED_PORT &= ~(1<<SERVO_FEED_PIN);
207 eqlazer 297
 
298
 
317 eqlazer 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
        }
207 eqlazer 308
 
317 eqlazer 309
        if( bios->timebase_get() - timeStamp >= FAILSAFE_SEND_PERIOD ){
310
            timeStamp = bios->timebase_get();
207 eqlazer 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;
249 eqlazer 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;
207 eqlazer 327
 
317 eqlazer 328
            bios->can_send(&txMsg);
207 eqlazer 329
        }
330
    }
331
}
332