Browse Source

Add support for GiveBack

Now we correctly set the GiveBack flag and minimum current fields in the
Request message when GiveBack is enabled.  Also when GiveBack is
enabled, we correctly handle GotoMin messages by lowering our power
consumption, completing negotiation, and Requesting our normal power
periodically until the power supply Accepts our Request.

At least, I believe it's correct.  I don't have any hardware that sends
GotoMin messages, so I can't test it other than that it doesn't break
anything with the GiveBack flag set to 1 or 0 when the source doesn't
ask to reduce power.
Clara Hobbs 5 years ago
parent
commit
0371b61b2a
2 changed files with 52 additions and 16 deletions
  1. 13
    4
      src/device_policy_manager.c
  2. 39
    12
      src/policy_engine.c

+ 13
- 4
src/device_policy_manager.c View File

@@ -66,9 +66,18 @@ bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg
66 66
                 /* We got what we wanted, so build a request for that */
67 67
                 request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
68 68
                     PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
69
-                request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(cfg->i)
70
-                    | PD_RDO_FV_CURRENT_SET(cfg->i)
71
-                    | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
69
+                if (cfg->flags & PDB_CONFIG_FLAGS_GIVEBACK) {
70
+                    /* GiveBack enabled */
71
+                    request->obj[0] = PD_RDO_FV_MIN_CURRENT_SET(10)
72
+                        | PD_RDO_FV_CURRENT_SET(cfg->i)
73
+                        | PD_RDO_NO_USB_SUSPEND | PD_RDO_GIVEBACK
74
+                        | PD_RDO_OBJPOS_SET(i + 1);
75
+                } else {
76
+                    /* GiveBack disabled */
77
+                    request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(cfg->i)
78
+                        | PD_RDO_FV_CURRENT_SET(cfg->i)
79
+                        | PD_RDO_NO_USB_SUSPEND | PD_RDO_OBJPOS_SET(i + 1);
80
+                }
72 81
 
73 82
                 /* Update requested voltage */
74 83
                 dpm_requested_voltage = cfg->v;
@@ -77,7 +86,7 @@ bool pdb_dpm_evaluate_capability(const union pd_msg *capabilities, union pd_msg
77 86
             }
78 87
         }
79 88
     }
80
-    /* Nothing matched (or no configuration), so get 5 V */
89
+    /* Nothing matched (or no configuration), so get 5 V at low current */
81 90
     request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
82 91
         PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
83 92
     request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(10)

+ 39
- 12
src/policy_engine.c View File

@@ -56,6 +56,8 @@ static union pd_msg *last_dpm_request = NULL;
56 56
 static bool capability_match = false;
57 57
 /* Whether or not we have an explicit contract */
58 58
 static bool explicit_contract = false;
59
+/* Whether or not we're receiving minimum power*/
60
+static bool min_power = false;
59 61
 /* Keep track of how many hard resets we've sent */
60 62
 static int hard_reset_counter = 0;
61 63
 /* Policy Engine thread mailbox */
@@ -183,6 +185,8 @@ static enum policy_engine_state pe_sink_select_cap(void)
183 185
             /* Transition to Sink Standby if necessary */
184 186
             pdb_dpm_sink_standby();
185 187
 
188
+            min_power = false;
189
+
186 190
             chPoolFree(&pdb_msg_pool, policy_engine_message);
187 191
             policy_engine_message = NULL;
188 192
             return PESinkTransitionSink;
@@ -203,9 +207,10 @@ static enum policy_engine_state pe_sink_select_cap(void)
203 207
                 return PESinkWaitCap;
204 208
             /* If we do have an explicit contract, go to the ready state */
205 209
             } else {
206
-                /* TODO: we should take note if we got here from a Wait
207
-                 * message, because we Should run the SinkRequestTimer in the
208
-                 * Ready state if that's the case. */
210
+                /* If we got here from a Wait message, we Should run
211
+                 * SinkRequestTimer in the Ready state. */
212
+                min_power = (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_WAIT);
213
+
209 214
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
210 215
                 policy_engine_message = NULL;
211 216
                 return PESinkReady;
@@ -242,7 +247,7 @@ static enum policy_engine_state pe_sink_transition_sink(void)
242 247
             explicit_contract = true;
243 248
 
244 249
             /* Set the output appropriately */
245
-            pdb_dpm_output_set(capability_match);
250
+            pdb_dpm_output_set(capability_match && !min_power);
246 251
 
247 252
             chPoolFree(&pdb_msg_pool, policy_engine_message);
248 253
             policy_engine_message = NULL;
@@ -265,9 +270,16 @@ static enum policy_engine_state pe_sink_transition_sink(void)
265 270
 
266 271
 static enum policy_engine_state pe_sink_ready(void)
267 272
 {
273
+    eventmask_t evt;
274
+
268 275
     /* Wait for an event */
269
-    eventmask_t evt = chEvtWaitAny(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
270
-            | PDB_EVT_PE_I_OVRTEMP);
276
+    if (min_power) {
277
+        evt = chEvtWaitAnyTimeout(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
278
+                | PDB_EVT_PE_I_OVRTEMP, PD_T_SINK_REQUEST);
279
+    } else {
280
+        evt = chEvtWaitAny(PDB_EVT_PE_MSG_RX | PDB_EVT_PE_RESET
281
+                | PDB_EVT_PE_I_OVRTEMP);
282
+    }
271 283
 
272 284
     /* If we got reset signaling, transition to default */
273 285
     if (evt & PDB_EVT_PE_RESET) {
@@ -279,6 +291,12 @@ static enum policy_engine_state pe_sink_ready(void)
279 291
         return PESinkHardReset;
280 292
     }
281 293
 
294
+    /* If no event was received, the timer ran out. */
295
+    if (evt == 0) {
296
+        /* Repeat our Request message */
297
+        return PESinkSelectCap;
298
+    }
299
+
282 300
     /* If we received a message */
283 301
     if (evt & PDB_EVT_PE_MSG_RX) {
284 302
         if (chMBFetch(&pdb_pe_mailbox, (msg_t *) &policy_engine_message, TIME_IMMEDIATE) == MSG_OK) {
@@ -330,14 +348,23 @@ static enum policy_engine_state pe_sink_ready(void)
330 348
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
331 349
                 policy_engine_message = NULL;
332 350
                 return PESinkSendReject;
333
-            /* Reject GotoMin messages
334
-             * Until we actually support GiveBack, this is the correct
335
-             * behavior according to S. 6.3.4 */
351
+            /* Handle GotoMin messages */
336 352
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_GOTOMIN
337 353
                     && PD_NUMOBJ_GET(policy_engine_message) == 0) {
338
-                chPoolFree(&pdb_msg_pool, policy_engine_message);
339
-                policy_engine_message = NULL;
340
-                return PESinkSendReject;
354
+                if (pdb_dpm_giveback_enabled()) {
355
+                    /* We support GiveBack, so go to minimum power */
356
+                    pdb_dpm_output_set(false);
357
+                    min_power = true;
358
+
359
+                    chPoolFree(&pdb_msg_pool, policy_engine_message);
360
+                    policy_engine_message = NULL;
361
+                    return PESinkTransitionSink;
362
+                } else {
363
+                    /* We don't support GiveBack, so send a Reject */
364
+                    chPoolFree(&pdb_msg_pool, policy_engine_message);
365
+                    policy_engine_message = NULL;
366
+                    return PESinkSendReject;
367
+                }
341 368
             /* Evaluate new Source_Capabilities */
342 369
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_SOURCE_CAPABILITIES
343 370
                     && PD_NUMOBJ_GET(policy_engine_message) > 0) {

Loading…
Cancel
Save