SmartMesh QSL for STM32F4 version

Fork of COG-AD4050_QSL by APS Lab

sm_clib/dn_serial_mt.c

Committer:
APS_Lab
Date:
2018-07-12
Revision:
1:b909b8399252
Parent:
0:8ca1e814a851

File content as of revision 1:b909b8399252:

/*
Copyright (c) 2014, Dust Networks. All rights reserved.

HDLC library.

\license See attached DN_LICENSE.txt.
*/

#include "dn_serial_mt.h"
#include "dn_hdlc.h"

//=========================== variables =======================================

typedef struct {
   // packet IDs
   uint8_t                   txPacketId;
   uint8_t                   rxPacketId;
   // reply callback
   uint8_t                   replyCmdId;
   dn_serial_reply_cbt       replyCb;
   // request callback
   dn_serial_request_cbt     requestCb;
} dn_serial_mt_vars_t;

dn_serial_mt_vars_t dn_serial_mt_vars;

//=========================== prototype =======================================

void dn_serial_mt_rxHdlcFrame(uint8_t* rxFrame, uint8_t rxFrameLen);
void dn_serial_mt_dispatch_response(uint8_t cmdId, uint8_t *payload, uint8_t length);
void dn_serial_sendReply(uint8_t cmdId, uint8_t rc, uint8_t *payload, uint8_t length);

//=========================== public ==========================================

/**
\brief Setting up the instance.
*/
void dn_serial_mt_init(dn_serial_request_cbt requestCb) {
   // reset local variables
   memset(&dn_serial_mt_vars, 0, sizeof(dn_serial_mt_vars));
   
   // initialize variables
   dn_serial_mt_vars.txPacketId = DN_SERIAL_PACKETID_NOTSET;
   dn_serial_mt_vars.rxPacketId = DN_SERIAL_PACKETID_NOTSET;
   dn_serial_mt_vars.requestCb  = requestCb;
   
   // initialize the HDLC module
   dn_hdlc_init(dn_serial_mt_rxHdlcFrame);
}

dn_err_t dn_serial_mt_sendRequest(uint8_t cmdId,  uint8_t extraFlags, uint8_t* payload, uint8_t length, dn_serial_reply_cbt replyCb) {
   uint8_t i;
   uint8_t flags;
   
   // register reply callback
   dn_serial_mt_vars.replyCmdId      = cmdId;
   dn_serial_mt_vars.replyCb         = replyCb;
   
   // calculate the flags
   flags      = 0;
   if (dn_serial_mt_vars.txPacketId==DN_SERIAL_PACKETID_NOTSET) {
      dn_serial_mt_vars.txPacketId = 0x00;
      flags  |= 0x01<<3;                          // sync bit
      flags  |= dn_serial_mt_vars.txPacketId<<1;     // txPacketId
   } else {
      flags  |= dn_serial_mt_vars.txPacketId<<1;     // txPacketId
   }
   flags     |= extraFlags;
   
   // send the frame over serial
   dn_hdlc_outputOpen();
   dn_hdlc_outputWrite(cmdId);                   // cmdId
   dn_hdlc_outputWrite(length);                  // length
   dn_hdlc_outputWrite(flags);                   // flags
   for (i=0; i<length; i++) {                    // payload
      dn_hdlc_outputWrite(payload[i]);
   }
   dn_hdlc_outputClose();
   
   // toggle the txPacketId
   if (dn_serial_mt_vars.txPacketId==0x00) {
      dn_serial_mt_vars.txPacketId   = 0x01;
   } else {
      dn_serial_mt_vars.txPacketId   = 0x00;
   }
   
   return DN_ERR_NONE;
}

//=========================== private =========================================

void dn_serial_mt_rxHdlcFrame(uint8_t* rxFrame, uint8_t rxFrameLen) {
   // fields in the serial API header
   uint8_t cmdId;
   uint8_t length;
   uint8_t flags;
   uint8_t isResponse;
   uint8_t packetId;
   uint8_t isSync;
   // misc
   uint8_t isRepeatId;
   
   // assert length is OK
   if (rxFrameLen<3) {
      return;
   }
   
   // parse header
   cmdId      = rxFrame[0];
   length     = rxFrame[1];
   flags      = rxFrame[2];
   isResponse = ((flags & DN_SERIAL_API_MASK_RESPONSE)!=0);
   packetId   = ((flags & DN_SERIAL_API_MASK_PACKETID)!=0);
   isSync     = ((flags & DN_SERIAL_API_MASK_SYNC)!=0);
   
   // check if valid packet ID
   if (isResponse) {
      // dispatch
      
      dn_serial_mt_dispatch_response(cmdId,&rxFrame[3],length);
   } else {
      if (isSync || packetId!=dn_serial_mt_vars.rxPacketId) {
         isRepeatId          = FALSE;
         dn_serial_mt_vars.rxPacketId = packetId;
      } else {
         isRepeatId          = TRUE;
      }
      
      // ACK
      dn_serial_sendReply(cmdId,DN_SERIAL_RC_OK,NULL,0);
      
      // dispatch
      if (isRepeatId==FALSE && length>0 && dn_serial_mt_vars.requestCb!=NULL) {
         dn_serial_mt_vars.requestCb(cmdId,flags,&rxFrame[3],length);
      }
   }
}

/**
\note Not public, only used for sending ACK.
*/
void dn_serial_sendReply(uint8_t cmdId, uint8_t rc, uint8_t *payload, uint8_t length) {
   uint8_t i;
   
   dn_hdlc_outputOpen();
   dn_hdlc_outputWrite(cmdId);                                                    // cmdId
   dn_hdlc_outputWrite(length);                                                   // length
   dn_hdlc_outputWrite(DN_SERIAL_API_MASK_RESPONSE | (dn_serial_mt_vars.rxPacketId<<1));   // flags
   dn_hdlc_outputWrite(rc);                                                       // rc
   for (i=0; i<length; i++) {                                                  // payload
      dn_hdlc_outputWrite(payload[i]);
   }
   dn_hdlc_outputClose();
}

void dn_serial_mt_dispatch_response(uint8_t cmdId, uint8_t* payload, uint8_t length) {
   uint8_t rc;
   
   rc = payload[0];
   if (cmdId==dn_serial_mt_vars.replyCmdId && dn_serial_mt_vars.replyCb!=NULL) {
      
      // call the callback
      (dn_serial_mt_vars.replyCb)(cmdId,rc,&payload[1],length);
      
      // reset
      dn_serial_mt_vars.replyCmdId   = 0x00;
      dn_serial_mt_vars.replyCb      = NULL;
   }
}

//=========================== helpers =========================================