Statistics
| Branch: | Tag: | Revision:

amiro-os / devices / PowerManagement / PowerManagement.cpp @ 3aee55de

History | View | Annotate | Download (7.458 KB)

1 58fe0e0b Thomas Schöpping
#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 8c99e03a galberding
    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 58fe0e0b Thomas Schöpping
69
    default:
70
      break;
71
  }
72
73
  return -1;
74
}
75
76
msg_t PowerManagement::updateSensorVal() {
77
78
  // update charger status
79 98e7c69b galberding
  // 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_PATH_DC) == PAL_HIGH); 
81 58fe0e0b Thomas Schöpping
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 8c99e03a galberding
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 58fe0e0b Thomas Schöpping
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
  for (int i = 0; i < 8; i++) {
151
    frame.SID = 0;
152
    this->encodeDeviceId(&frame, CAN::PROXIMITY_RING_ID(i));
153
    frame.data16[0] = this->proximityRingValue[i];
154
    frame.DLC = 2;
155
    this->transmitMessage(&frame);
156 b4885314 Thomas Schöpping
    BaseThread::sleep(US2ST(10)); // Use to sleep for 10 CAN cycle (@1Mbit), otherwise the cognition-board might not receive all messagee
157 58fe0e0b Thomas Schöpping
  }
158
  ++this->bc_counter;
159
}
160
161
void PowerManagement::calibrate() {
162
  // Stop sending and receiving of values to indicate the calibration phase
163
//   eventTimerEvtSource->unregister(&this->eventTimerEvtListener);
164
//   rxFullCanEvtSource->unregister(&this->rxFullCanEvtListener);
165
166
  this->calibrateProximityRingValues();
167
168
  // Start sending and receving of values
169
//   eventTimerEvtSource->registerOne(&this->eventTimerEvtListener, CAN::PERIODIC_TIMER_ID);
170
//   rxFullCanEvtSource->registerOne(&this->rxFullCanEvtListener, CAN::RECEIVED_ID);
171
}
172
173
void PowerManagement::calibrateProximityRingValues() {
174
175
  uint16_t buffer;
176
  for (uint8_t idx = 0; idx < 8; ++idx) {
177
    global.vcnl4020[idx].calibrate();
178
    buffer = global.vcnl4020[idx].getProximityOffset();
179
    global.memory.setVcnl4020Offset(buffer,idx);
180
  }
181
}
182
183
ThreadReference PowerManagement::start(tprio_t PRIO) {
184
  this->ControllerAreaNetworkRx::start(PRIO + 1);
185
  this->ControllerAreaNetworkTx::start(PRIO);
186
  return NULL;
187
}
188
189
types::power_status&
190
PowerManagement::getPowerStatus()
191
{
192
  return this->powerStatus;
193
}
194
195
msg_t PowerManagement::terminate(void) {
196
  msg_t ret = RDY_OK;
197
198
  this->ControllerAreaNetworkTx::requestTerminate();
199
  ret |= this->ControllerAreaNetworkTx::wait();
200
  this->ControllerAreaNetworkRx::requestTerminate();
201
  ret |= this->ControllerAreaNetworkRx::wait();
202
203
  return ret;
204
}