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 7 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
                 /* We got what we wanted, so build a request for that */
66
                 /* We got what we wanted, so build a request for that */
67
                 request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
67
                 request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
68
                     PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
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
                 /* Update requested voltage */
82
                 /* Update requested voltage */
74
                 dpm_requested_voltage = cfg->v;
83
                 dpm_requested_voltage = cfg->v;
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
     request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
90
     request->hdr = PD_MSGTYPE_REQUEST | PD_DATAROLE_UFP |
82
         PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
91
         PD_SPECREV_2_0 | PD_POWERROLE_SINK | PD_NUMOBJ(1);
83
     request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(10)
92
     request->obj[0] = PD_RDO_FV_MAX_CURRENT_SET(10)

+ 39
- 12
src/policy_engine.c View File

56
 static bool capability_match = false;
56
 static bool capability_match = false;
57
 /* Whether or not we have an explicit contract */
57
 /* Whether or not we have an explicit contract */
58
 static bool explicit_contract = false;
58
 static bool explicit_contract = false;
59
+/* Whether or not we're receiving minimum power*/
60
+static bool min_power = false;
59
 /* Keep track of how many hard resets we've sent */
61
 /* Keep track of how many hard resets we've sent */
60
 static int hard_reset_counter = 0;
62
 static int hard_reset_counter = 0;
61
 /* Policy Engine thread mailbox */
63
 /* Policy Engine thread mailbox */
183
             /* Transition to Sink Standby if necessary */
185
             /* Transition to Sink Standby if necessary */
184
             pdb_dpm_sink_standby();
186
             pdb_dpm_sink_standby();
185
 
187
 
188
+            min_power = false;
189
+
186
             chPoolFree(&pdb_msg_pool, policy_engine_message);
190
             chPoolFree(&pdb_msg_pool, policy_engine_message);
187
             policy_engine_message = NULL;
191
             policy_engine_message = NULL;
188
             return PESinkTransitionSink;
192
             return PESinkTransitionSink;
203
                 return PESinkWaitCap;
207
                 return PESinkWaitCap;
204
             /* If we do have an explicit contract, go to the ready state */
208
             /* If we do have an explicit contract, go to the ready state */
205
             } else {
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
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
214
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
210
                 policy_engine_message = NULL;
215
                 policy_engine_message = NULL;
211
                 return PESinkReady;
216
                 return PESinkReady;
242
             explicit_contract = true;
247
             explicit_contract = true;
243
 
248
 
244
             /* Set the output appropriately */
249
             /* Set the output appropriately */
245
-            pdb_dpm_output_set(capability_match);
250
+            pdb_dpm_output_set(capability_match && !min_power);
246
 
251
 
247
             chPoolFree(&pdb_msg_pool, policy_engine_message);
252
             chPoolFree(&pdb_msg_pool, policy_engine_message);
248
             policy_engine_message = NULL;
253
             policy_engine_message = NULL;
265
 
270
 
266
 static enum policy_engine_state pe_sink_ready(void)
271
 static enum policy_engine_state pe_sink_ready(void)
267
 {
272
 {
273
+    eventmask_t evt;
274
+
268
     /* Wait for an event */
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
     /* If we got reset signaling, transition to default */
284
     /* If we got reset signaling, transition to default */
273
     if (evt & PDB_EVT_PE_RESET) {
285
     if (evt & PDB_EVT_PE_RESET) {
279
         return PESinkHardReset;
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
     /* If we received a message */
300
     /* If we received a message */
283
     if (evt & PDB_EVT_PE_MSG_RX) {
301
     if (evt & PDB_EVT_PE_MSG_RX) {
284
         if (chMBFetch(&pdb_pe_mailbox, (msg_t *) &policy_engine_message, TIME_IMMEDIATE) == MSG_OK) {
302
         if (chMBFetch(&pdb_pe_mailbox, (msg_t *) &policy_engine_message, TIME_IMMEDIATE) == MSG_OK) {
330
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
348
                 chPoolFree(&pdb_msg_pool, policy_engine_message);
331
                 policy_engine_message = NULL;
349
                 policy_engine_message = NULL;
332
                 return PESinkSendReject;
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
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_GOTOMIN
352
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_GOTOMIN
337
                     && PD_NUMOBJ_GET(policy_engine_message) == 0) {
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
             /* Evaluate new Source_Capabilities */
368
             /* Evaluate new Source_Capabilities */
342
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_SOURCE_CAPABILITIES
369
             } else if (PD_MSGTYPE_GET(policy_engine_message) == PD_MSGTYPE_SOURCE_CAPABILITIES
343
                     && PD_NUMOBJ_GET(policy_engine_message) > 0) {
370
                     && PD_NUMOBJ_GET(policy_engine_message) > 0) {

Loading…
Cancel
Save