Statistics
| Branch: | Tag: | Revision:

amiro-os / devices / PowerManagement / PowerManagement.cpp @ ba75ee1d

History | View | Annotate | Download (7.458 KB)

1
#include "ch.hpp"
2
#include "hal.h"
3
#include "PowerManagement.h"
4

    
5
#include <amiro/proximity/vcnl4020.hpp>
6
#include <global.hpp>
7

    
8
#include <algorithm>
9
#include <chprintf.h>
10

    
11
using namespace chibios_rt;
12
using namespace amiro;
13

    
14
extern Global global;
15

    
16
PowerManagement::PowerManagement(CANDriver *can)
17
    : ControllerAreaNetworkTx(can, CAN::POWER_MANAGEMENT_ID),
18
      ControllerAreaNetworkRx(can, CAN::POWER_MANAGEMENT_ID),
19
      bc_counter(0)
20
{
21
  this->powerStatus.charging_flags.value = 0;
22
}
23

    
24
msg_t PowerManagement::receiveMessage(CANRxFrame *frame) {
25
  int deviceId = this->decodeDeviceId(frame);
26
  switch (deviceId) {
27

    
28
    case CAN::SHELL_REPLY_ID(CAN::POWER_MANAGEMENT_ID):
29
      if (frame->DLC > 0) {
30
        sdWrite(&SD1, frame->data8, frame->DLC);
31
        return RDY_OK;
32
      }
33
      break;
34

    
35
    case CAN::SHELL_QUERY_ID(CAN::POWER_MANAGEMENT_ID):
36
      if (frame->DLC != 0) {
37
        global.sercanmux1.convCan2Serial(frame->data8, frame->DLC);
38
        return RDY_OK;
39
      } else {
40
        global.sercanmux1.rcvSwitchCmd(this->decodeBoardId(frame));
41
        return RDY_OK;
42
      }
43
      break;
44

    
45
    case CAN::CALIBRATE_PROXIMITY_RING:
46
      // Dont care about the payload but start the calibration
47
      // TODO Care about the payload. Differ between:
48
      // 1: Do fresh calibration (Save values to memory and to temporary values)
49
      // 2: Remove temporary Calibration and get uncalibrated values
50
      // 3: Load calibration from memory
51
      this->calibrate();
52
      break;
53

    
54
    case CAN::ROBOT_ID:
55
      if (frame->DLC == 1) {
56
        this->robotId = frame->data8[0];
57
        return RDY_OK;
58
      }
59
      break;
60
    case CAN::REQUEST_CHARGING_OVER_PIN:
61
      if (frame->DLC == 1) {
62
        // Error handling 
63
        // TODO: Error Handling, for now just set the given value
64
        this->powerStatus.charging_flags.content.diwheeldrive_enable_power_path = frame->data8[0];
65
        return RDY_OK;
66
      }
67
      break;
68

    
69
    default:
70
      break;
71
  }
72

    
73
  return -1;
74
}
75

    
76
msg_t PowerManagement::updateSensorVal() {
77

    
78
  // update charger status
79
  this->powerStatus.charging_flags.content.powermanagement_plugged_in = global.ltc4412.isPluggedIn();
80
  // this->powerStatus.charging_flags.content.powermanagement_plugged_in = (palReadPad((GPIO_TypeDef*)GPIOC, GPIOC_PATHDC) == PAL_HIGH); 
81

    
82
  // update fuel gauges values
83
  const BQ27500::Driver::UpdateData* power[2] {
84
    &global.bq27500[constants::PowerManagement::BAT_A].getStatus(),
85
    &global.bq27500[constants::PowerManagement::BAT_B].getStatus()
86
  };
87
  this->powerStatus.charging_flags.content.powermanagement_charging = (this->powerStatus.charging_flags.content.powermanagement_plugged_in &&
88
                                                                       this->powerStatus.charging_flags.content.vsys_higher_than_9V &&
89
                                                                       power[0]->minutes_to_empty == uint16_t(~0) &&
90
                                                                       power[1]->minutes_to_empty == uint16_t(~0))?
91
                                                                       true : false;
92
  this->powerStatus.charging_flags.content.diwheeldrive_charging = (this->powerStatus.charging_flags.content.diwheeldrive_enable_power_path &&
93
                                                                    this->powerStatus.charging_flags.content.vsys_higher_than_9V &&
94
                                                                    power[0]->minutes_to_empty == uint16_t(~0) &&
95
                                                                    power[1]->minutes_to_empty == uint16_t(~0))?
96
                                                                    true : false;
97
  this->powerStatus.state_of_charge = (power[0]->state_of_charge + power[1]->state_of_charge) / 2;
98
  if (this->powerStatus.charging_flags.content.powermanagement_charging || this->powerStatus.charging_flags.content.diwheeldrive_charging) {
99
    /*
100
     * Assumption:
101
     * When charging there is enough power available to charge both batteries at full rate simultaneously.
102
     * Thus, the second battery will not charge faster when the first battery is fully charged.
103
     */
104
    this->powerStatus.minutes_remaining = std::max(power[0]->minutes_to_full, power[1]->minutes_to_full);
105
  } else {
106
    /*
107
     * Computation of the remaining discharging time:
108
     * Take the time until the first of the two batteries is empty and add the remaining time of the second battery but half.
109
     *        time = min(a,b) + (max(a,b) - min(a,b))/2
110
     * <=>  2*time = 2*min(a,b) + max(a,b) - min(a,b)
111
     * <=>  2*time = min(a,b) + max(a,b)
112
     * <=>  2*time = a + b
113
     * <=>    time = (a + b)/2
114
     */
115
    this->powerStatus.minutes_remaining = (power[0]->minutes_to_empty + power[1]->minutes_to_empty) / 2;
116
  }
117
  this->powerStatus.power_consumption = (power[0]->average_power_mW + power[1]->average_power_mW) / 2;
118

    
119
  // update infrared sensor value
120
  // Note: The CANRx Value will never be updated in this thread
121
  for (int idx = 0; idx < 8; idx++)
122
    this->proximityRingValue[idx] = global.vcnl4020[idx].getProximityScaledWoOffset();
123

    
124
  return 0;
125
}
126

    
127
void PowerManagement::setStrategy(uint8_t strategy){
128
  CANTxFrame frame;
129
  chprintf((BaseSequentialStream*) &SD1, "Message Triggered!\n");
130
  // global.triggerCan = false;
131
  frame.SID = 0;
132
  this->encodeDeviceId(&frame, CAN::SET_LINE_FOLLOW_MSG);
133
  frame.data8[0] = strategy;
134
  frame.DLC = 1;
135
  this->transmitMessage(&frame);
136
}
137

    
138
void PowerManagement::periodicBroadcast() {
139
  CANTxFrame frame;
140
  if (this->bc_counter % 10 == 0) {
141
    frame.SID = 0;
142
    this->encodeDeviceId(&frame, CAN::POWER_STATUS_ID);
143
    frame.data8[0] = this->powerStatus.charging_flags.value;
144
    frame.data8[1] = this->powerStatus.state_of_charge;
145
    frame.data16[1] = this->powerStatus.minutes_remaining;
146
    frame.data16[2] = this->powerStatus.power_consumption;
147
    frame.DLC = 6;
148
    this->transmitMessage(&frame);
149
  }
150

    
151
  for (int i = 0; i < 8; i++) {
152
    frame.SID = 0;
153
    this->encodeDeviceId(&frame, CAN::PROXIMITY_RING_ID(i));
154
    frame.data16[0] = this->proximityRingValue[i];
155
    frame.DLC = 2;
156
    this->transmitMessage(&frame);
157
    BaseThread::sleep(US2ST(10)); // Use to sleep for 10 CAN cycle (@1Mbit), otherwise the cognition-board might not receive all messagee
158
  }
159
  ++this->bc_counter;
160
}
161

    
162
void PowerManagement::calibrate() {
163
  // Stop sending and receiving of values to indicate the calibration phase
164
//   eventTimerEvtSource->unregister(&this->eventTimerEvtListener);
165
//   rxFullCanEvtSource->unregister(&this->rxFullCanEvtListener);
166

    
167
  this->calibrateProximityRingValues();
168

    
169
  // Start sending and receving of values
170
//   eventTimerEvtSource->registerOne(&this->eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
171
//   rxFullCanEvtSource->registerOne(&this->rxFullCanEvtListener, CAN::RECEIVED_ID);
172
}
173

    
174
void PowerManagement::calibrateProximityRingValues() {
175

    
176
  uint16_t buffer;
177
  for (uint8_t idx = 0; idx < 8; ++idx) {
178
    global.vcnl4020[idx].calibrate();
179
    buffer = global.vcnl4020[idx].getProximityOffset();
180
    global.memory.setVcnl4020Offset(buffer,idx);
181
  }
182
}
183

    
184
ThreadReference PowerManagement::start(tprio_t PRIO) {
185
  this->ControllerAreaNetworkRx::start(PRIO + 1);
186
  this->ControllerAreaNetworkTx::start(PRIO);
187
  return NULL;
188
}
189

    
190
types::power_status&
191
PowerManagement::getPowerStatus()
192
{
193
  return this->powerStatus;
194
}
195

    
196
msg_t PowerManagement::terminate(void) {
197
  msg_t ret = RDY_OK;
198

    
199
  this->ControllerAreaNetworkTx::requestTerminate();
200
  ret |= this->ControllerAreaNetworkTx::wait();
201
  this->ControllerAreaNetworkRx::requestTerminate();
202
  ret |= this->ControllerAreaNetworkRx::wait();
203

    
204
  return ret;
205
}