Example #1
0
Ecode_t COM_ReadDataTimeout(COM_Port_t port,
                                       uint8_t *data,
                                       uint16_t length,
                                       uint16_t *bytesRead,
                                       uint16_t firstByteTimeout,
                                       uint16_t subsequentByteTimeout)
{
  if (checkValidPort(port)==false)
  {
    return EMBER_ERR_FATAL;
  }
  uint16_t bytesReadInternal = 0;
  Ecode_t status;
  uint16_t timeout = firstByteTimeout;
  uint16_t startTime = halCommonGetInt16uMillisecondTick();
  
  // loop until we read the max number of bytes or the timeout elapses
  while (bytesReadInternal < length
         && elapsedTimeInt16u(startTime,halCommonGetInt16uMillisecondTick()) < timeout) {
    status = COM_ReadByte(port, data);

    switch (status) {
      case EMBER_SUCCESS:
        ++data;
        ++bytesReadInternal;
        // reset timer and timeout for next character
        startTime = halCommonGetInt16uMillisecondTick();
        timeout = subsequentByteTimeout;
        break;

      case EMBER_SERIAL_RX_EMPTY:
        // empty queue is not an error for us, we just want to keep waiting
        break;

      default:
        // only store number of bytes read if the caller provided a non-NULL pointer
        if (bytesRead) {
          *bytesRead = bytesReadInternal;
        }
        return status;
    }
  }

  // only store number of bytes read if the caller provided a non-NULL pointer
  if (bytesRead) {
    *bytesRead = bytesReadInternal;
  }

  return bytesReadInternal == length ? EMBER_SUCCESS : EMBER_SERIAL_RX_EMPTY;
}
static void rescheduleUserControlEvent(void)
{
  // Look at all the active records and figure out when to schedule the event.
  // If any record should have been sent in the past, we immediately schedule
  // the event to send it as soon as possible.  Otherwise, we find the record
  // that has to be repeated soonest and schedule based on that.  If there are
  // no active records, we are done and cancel the event.
  uint16_t nowMs = halCommonGetInt16uMillisecondTick();
  uint16_t delayMs = MAX_INT16U_VALUE;
  uint8_t i;
  for (i = 0; i < COUNTOF(records); i++) {
    if (records[i].pairingIndex != 0xFF) {
      if (timeGTorEqualInt16u(nowMs, records[i].timeMs)) {
        delayMs = 0;
        break;
      } else {
        uint16_t remainingMs = elapsedTimeInt16u(nowMs, records[i].timeMs);
        if (remainingMs < delayMs) {
          delayMs = remainingMs;
        }
      }
    }
  }
  if (delayMs == MAX_INT16U_VALUE) {
    emberEventControlSetInactive(emberAfPluginRf4ceZrc11OutgoingUserControlEventControl);
  } else if (delayMs == 0) {
    emberEventControlSetActive(emberAfPluginRf4ceZrc11OutgoingUserControlEventControl);
  } else {
    emberEventControlSetDelayMS(emberAfPluginRf4ceZrc11OutgoingUserControlEventControl,
                                delayMs);
  }
}
static EmberStatus sendAndReschedule(UserControlRecord *record)
{
  // Construct the message and send it.
  EmberStatus status;
  emAfRf4ceZrc11BufferLength = 0;
  emAfRf4ceZrc11Buffer[emAfRf4ceZrc11BufferLength++] = record->commandCode;
  emAfRf4ceZrc11Buffer[emAfRf4ceZrc11BufferLength++] = record->rcCommandCode;
  MEMCOPY(emAfRf4ceZrc11Buffer + emAfRf4ceZrc11BufferLength,
          record->rcCommandPayload,
          record->rcCommandPayloadLength);
  emAfRf4ceZrc11BufferLength += record->rcCommandPayloadLength;
  status = emAfRf4ceZrc11Send(record->pairingIndex);

  // If this was a release, we are done and clear the record.  Otherwise, a
  // press becomes a repeat (and a repeat stays a repeat).  The next time to
  // send this record depends on the key repeat interval.  Once we adjust this
  // record, we reschedule.
  if (record->commandCode == EMBER_AF_RF4CE_ZRC_COMMAND_USER_CONTROL_RELEASED) {
    record->pairingIndex = 0xFF;
  } else {
    record->commandCode = EMBER_AF_RF4CE_ZRC_COMMAND_USER_CONTROL_REPEATED;
    record->timeMs = (halCommonGetInt16uMillisecondTick()
                      + EMBER_AF_PLUGIN_RF4CE_ZRC11_KEY_REPEAT_INTERVAL_MS);
  }
  rescheduleUserControlEvent();
  return status;
}
// Hal Button ISR Callback
// This callback is called by the framework whenever a button is pressed on the
// device. This callback is called within ISR context.
void emberAfHalButtonIsrCallback(int8u button, int8u state)
{
  if ((button == BUTTON0 || button == BUTTON1)
      && state == BUTTON_PRESSED
      && !emberEventControlGetActive(buttonEventControl)) {
    buttonPressTime = halCommonGetInt16uMillisecondTick();
    emberEventControlSetActive(buttonEventControl);
  }
}
void buttonEventHandler(void)
{
  emberEventControlSetInactive(buttonEventControl);

  EmberNetworkStatus state = emberNetworkState();
  if (state == EMBER_JOINED_NETWORK) {
    emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND
                               | ZCL_FRAME_CONTROL_CLIENT_TO_SERVER),
                              ZCL_ON_OFF_CLUSTER_ID,
                              (on ? ZCL_OFF_COMMAND_ID : ZCL_ON_COMMAND_ID),
                              "");
    emberAfGetCommandApsFrame()->profileId           = emberAfProfileIdFromIndex(0);
    emberAfGetCommandApsFrame()->sourceEndpoint      = emberAfEndpointFromIndex(0);
    emberAfGetCommandApsFrame()->destinationEndpoint = EMBER_BROADCAST_ENDPOINT;
    if (emberAfSendCommandBroadcast(EMBER_SLEEPY_BROADCAST_ADDRESS)
        == EMBER_SUCCESS) {
      on = !on;
    } else {
      halPlayTune_P(sadTune, TRUE);
    }
  } else if (state == EMBER_NO_NETWORK) {
    halPlayTune_P((emberAfZllInitiateTouchLink() == EMBER_SUCCESS
                   ? waitTune
                   : sadTune),
                  TRUE);
  } else {
    int16u elapsed = elapsedTimeInt16u(buttonPressTime,
                                       halCommonGetInt16uMillisecondTick());
    if (REPAIR_LIMIT_MS
        < elapsedTimeInt16u(buttonPressTime,
                            halCommonGetInt16uMillisecondTick())) {
      halPlayTune_P(sadTune, TRUE);
    } else {
      if (state == EMBER_JOINED_NETWORK_NO_PARENT
          && !emberStackIsPerformingRejoin()) {
        halPlayTune_P((emberFindAndRejoinNetwork(TRUE, 0) == EMBER_SUCCESS
                       ? waitTune
                       : sadTune),
                      TRUE);
      }
      emberEventControlSetDelayMS(buttonEventControl, REPAIR_DELAY_MS);
    }
  }
}
void emberAfPluginRf4ceZrc11OutgoingUserControlEventHandler(void)
{
  // We expect the user control event to fire only when there is something to
  // send.  We find it, send it, and reschedule.
  uint16_t nowMs = halCommonGetInt16uMillisecondTick();
  uint8_t i, index = 0xFF;
  for (i = 0; i < COUNTOF(records); i++) {
    if (records[i].pairingIndex != 0xFF
        && timeGTorEqualInt16u(nowMs, records[i].timeMs)) {
      index = i;
      break;
    }
  }
  assert(index != 0xFF);
  sendAndReschedule(&records[index]);
}
void buttonEventHandler(void)
{
  emberEventControlSetInactive(buttonEventControl);
  if (halButtonState(BUTTON0) == BUTTON_PRESSED) {
    EmberNetworkStatus state = emberNetworkState();
    if (state == EMBER_JOINED_NETWORK) {
      emberAfFillExternalBuffer((ZCL_CLUSTER_SPECIFIC_COMMAND
                                 | ZCL_FRAME_CONTROL_CLIENT_TO_SERVER),
                                ZCL_ON_OFF_CLUSTER_ID,
                                (on ? ZCL_OFF_COMMAND_ID : ZCL_ON_COMMAND_ID),
                                "");
      emberAfGetCommandApsFrame()->profileId           = emberAfPrimaryProfileId();
      emberAfGetCommandApsFrame()->sourceEndpoint      = emberAfPrimaryEndpoint();
      emberAfGetCommandApsFrame()->destinationEndpoint = EMBER_BROADCAST_ENDPOINT;
      if (emberAfSendCommandUnicastToBindings() == EMBER_SUCCESS) {
        on = !on;
      } else {
        halPlayTune_P(sadTune, TRUE);
      }
    } else if (state == EMBER_NO_NETWORK) {
      halPlayTune_P((emberAfStartSearchForJoinableNetwork() == EMBER_SUCCESS
                     ? waitTune
                     : sadTune),
                    TRUE);
    } else {
      if (REPAIR_LIMIT_MS
          < elapsedTimeInt16u(buttonPressTime,
                              halCommonGetInt16uMillisecondTick())) {
        halPlayTune_P(sadTune, TRUE);
      } else {
        if (state == EMBER_JOINED_NETWORK_NO_PARENT
            && !emberStackIsPerformingRejoin()) {
          halPlayTune_P((emberFindAndRejoinNetwork(TRUE, 0) == EMBER_SUCCESS
                         ? waitTune
                         : sadTune),
                        TRUE);
        }
        emberEventControlSetDelayMS(buttonEventControl, REPAIR_DELAY_MS);
      }
    }
  } else if (halButtonState(BUTTON1) == BUTTON_PRESSED) {
    emberAfEzmodeClientCommission(emberAfPrimaryEndpoint(),
                                  EMBER_AF_EZMODE_COMMISSIONING_CLIENT_TO_SERVER,
                                  clusterIds,
                                  COUNTOF(clusterIds));
  }
}
EzspStatus serialSendCommand()
{
  EzspStatus status;
  if (!checkConnection()) {
    ezspTraceEzspVerbose("serialSendCommand(): EZSP_NOT_CONNECTED");
    return EZSP_NOT_CONNECTED;
  }
  ezspTraceEzspFrameId("send command", ezspFrameContents);
  status = usbSend(ezspFrameLength, ezspFrameContents);
  if (status != EZSP_SUCCESS) {
    ezspTraceEzspVerbose("serialSendCommand(): usbSend(): 0x%x", status);
    return status;
  }
  waitingForResponse = true;
  ezspTraceEzspVerbose("serialSendCommand(): ID=0x%x Seq=0x%x",
                      ezspFrameContents[EZSP_FRAME_ID_INDEX],
                      ezspFrameContents[EZSP_SEQUENCE_INDEX]);
  waitStartTime = halCommonGetInt16uMillisecondTick();
  return status;
}
EzspStatus serialResponseReceived(void)
{
  EzspStatus status;
  EzspBuffer *buffer;
  EzspBuffer *dropBuffer = NULL;
  if (!checkConnection()) {
    ezspTraceEzspVerbose("serialResponseReceived(): EZSP_NOT_CONNECTED");
    return EZSP_NOT_CONNECTED;
  }
  // ashSendExec();
  // status = ashReceiveExec();
  status = usbReceive();
  if (status != EZSP_SUCCESS
      && status != EZSP_ASH_IN_PROGRESS
      && status != EZSP_NO_RX_DATA) {
    ezspTraceEzspVerbose("serialResponseReceived(): 0x%x",
                        status);
    return status;
  }
  if (waitingForResponse
      && elapsedTimeInt16u(waitStartTime, halCommonGetInt16uMillisecondTick())
         > WAIT_FOR_RESPONSE_TIMEOUT) {
    waitingForResponse = false;
    ezspTraceEzspFrameId("no response", ezspFrameContents);
    ezspTraceEzspVerbose("serialResponseReceived(): EZSP_ERROR_NO_RESPONSE");
    return EZSP_ERROR_NO_RESPONSE;
  }
  status = EZSP_NO_RX_DATA;
  buffer = ezspQueuePrecedingEntry(&rxQueue, NULL);
  while (buffer != NULL) {
    // While we are waiting for a response to a command, we use the asynch
    // callback flag to ignore asynchronous callbacks. This allows our caller
    // to assume that no callbacks will appear between sending a command and
    // receiving its response.
    if (waitingForResponse
        && (buffer->data[EZSP_FRAME_CONTROL_INDEX]
            & EZSP_FRAME_CONTROL_ASYNCH_CB)
         ) {
      if (ezspFreeListLength(&rxFree) == 0) {
        dropBuffer = buffer;
      }
      buffer = ezspQueuePrecedingEntry(&rxQueue, buffer);
    } else {
      ezspTraceEzspVerbose("serialResponseReceived(): ID=0x%x Seq=0x%x Buffer=%u",
                          buffer->data[EZSP_FRAME_ID_INDEX],
                          buffer->data[EZSP_SEQUENCE_INDEX],
                          buffer);
      ezspRemoveQueueEntry(&rxQueue, buffer);
      memcpy(ezspFrameContents, buffer->data, buffer->len);  
      ezspTraceEzspFrameId("got response", buffer->data);
      ezspFrameLength = buffer->len;
      ezspFreeBuffer(&rxFree, buffer);
      ezspTraceEzspVerbose("serialResponseReceived(): ezspFreeBuffer(): %u", buffer);
      buffer = NULL;
      status = EZSP_SUCCESS;
      waitingForResponse = false;
    }
  }
  if (dropBuffer != NULL) {
    ezspRemoveQueueEntry(&rxQueue, dropBuffer);
    ezspFreeBuffer(&rxFree, dropBuffer);
    ezspTraceEzspFrameId("dropping", dropBuffer->data);
    ezspTraceEzspVerbose("serialResponseReceived(): ezspFreeBuffer(): drop %u", dropBuffer);
    ezspTraceEzspVerbose("serialResponseReceived(): ezspErrorHandler(): EZSP_ERROR_QUEUE_FULL");
    ezspErrorHandler(EZSP_ERROR_QUEUE_FULL);
  }
  return status;
}