1.5.3 Using the AL Module
The following code shows a basic example on how to use Meters And Mode AL:
// *****************************************************************************
// *****************************************************************************
// Section: Global Data Definitions
// *****************************************************************************
// *****************************************************************************
static const uint8_t appDataTxDataBuffer[9] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
APP_DATA appData;
// *****************************************************************************
// *****************************************************************************
// Section: Application Callback Functions
// *****************************************************************************
// *****************************************************************************
static void APP_AL_DataIndication_callback(AL_DATA_IND_PARAMS *indParams)
{
AL_IB_VALUE ibValue;
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AL_DATA_INDICATION: DSAP=0x%02X, ECC=0x%02X, SrcAddr=0x%02X%02X%02X%02X%02X%02X, ATTR=%hhu, APDU=0x",
indParams->dsap, indParams->ecc,
indParams->srcAddress.address[0], indParams->srcAddress.address[1], indParams->srcAddress.address[2],
indParams->srcAddress.address[3], indParams->srcAddress.address[4], indParams->srcAddress.address[5],
indParams->attr);
for (uint8_t i = 0; i < indParams->apduLen; i++)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "%02X", indParams->apdu[i]);
}
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "\r\n");
if (indParams->dsap == DLL_DSAP_APPLICATION_FRAME)
{
if (indParams->rxStatus == AL_RX_STATUS_ERROR_BAD_TMAC)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "TMAC Error\r\n");
}
else if (indParams->rxStatus == AL_RX_STATUS_ERROR_AES_NO_KEY)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Error No Decryption Key\r\n");
}
else if (indParams->rxStatus == AL_RX_STATUS_ERROR_AES_DECRYPT)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Decryption Error\r\n");
}
else if (indParams->rxStatus == AL_RX_STATUS_ERROR_AES_CMAC)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Authentication Error\r\n");
}
else if (indParams->rxStatus == AL_RX_STATUS_ERROR_BAD_LEN)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Error Bad Length\r\n");
}
else
{
/* Update LMON to received value */
appData.drParams.lmon = indParams->lmon;
if ((indParams->attr == AL_MSG_READ_RESP) || (indParams->attr == AL_MSG_READ_RESP_AUTH))
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Read Response Frame received\r\n");
}
else
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Application Frame command not recognized\r\n");
}
}
}
else if (indParams->dsap == DLL_DSAP_NETWORK_MANAGEMENT)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Network Management Frame: ");
if (indParams->attr == AL_MSG_ADDRESS_RESP)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "ADDRESS RESPONSE\r\n");
}
else if (indParams->attr == AL_MSG_REQADDR_RESP)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "REQ ADDRESS RESPONSE\r\n");
}
else
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "Command not recognized\r\n");
}
}
else
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "DSAP not recognized\r\n");
}
}
static void APP_AL_DataConfirm_callback(AL_DATA_CONFIRM_PARAMS *cfmParams)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AL_DATA_CONFIRM: Result=%hhu DSAP=0x%02X, ECC=0x%02X, DestAddr=0x%02X%02X%02X%02X%02X%02X\r\n",
cfmParams->txStatus, cfmParams->dsap, cfmParams->ecc,
cfmParams->dstAddress.address[0], cfmParams->dstAddress.address[1], cfmParams->dstAddress.address[2],
cfmParams->dstAddress.address[3], cfmParams->dstAddress.address[4], cfmParams->dstAddress.address[5]);
}
static void APP_AL_EventIndication_callback(AL_EVENT_IND_PARAMS *indParams)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AL_EVENT_INDICATION: Id=0x%02X, Value=0x", indParams->eventId);
for (uint8_t i = 0; i < indParams->eventValue.length; i++)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "%02X", indParams->eventValue.value[i]);
}
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "\r\n");
}
// *****************************************************************************
// *****************************************************************************
// Section: Application Initialization and State Machine Functions
// *****************************************************************************
// *****************************************************************************
void APP_Initialize ( void )
{
/* IDLE state is used to signal when application is started */
appData.state = APP_STATE_INIT;
/* Init Timer handler */
appData.tmr1Handle = SYS_TIME_HANDLE_INVALID;
appData.tmr2Handle = SYS_TIME_HANDLE_INVALID;
appData.tmr1Expired = false;
appData.tmr2Expired = false;
/* Configure DLL Data Request parameters */
appData.drParams.ecc = DLL_ECC_AES_CTR_READ_KEY;
appData.drParams.lmon = 0ULL;
appData.drParams.apdu = (uint8_t *)appDataTxDataBuffer;
appData.drParams.apduLen = sizeof(appDataTxDataBuffer);
appData.drParams.dsap = DLL_DSAP_APPLICATION_FRAME;
appData.drParams.serviceClass = SERVICE_CLASS_S;
appData.drParams.attr = AL_MSG_COMMAND_AUTH;
appData.drParams.dstAddress.routeSize = 1;
/* First Address in the route */
appData.drParams.dstAddress.macAddress[0].address[0] = 0x11;
appData.drParams.dstAddress.macAddress[0].address[1] = 0x22;
appData.drParams.dstAddress.macAddress[0].address[2] = 0x33;
appData.drParams.dstAddress.macAddress[0].address[3] = 0x44;
appData.drParams.dstAddress.macAddress[0].address[4] = 0x55;
appData.drParams.dstAddress.macAddress[0].address[5] = 0x66;
}
void APP_Tasks ( void )
{
/* Refresh WDG */
CLEAR_WATCHDOG();
/* Check the application's current state. */
switch ( appData.state )
{
case APP_STATE_INIT:
{
AL_DataIndicationCallbackRegister(APP_AL_DataIndication_callback);
AL_DataConfirmCallbackRegister(APP_AL_DataConfirm_callback);
AL_EventIndicationCallbackRegister(APP_AL_EventIndication_callback);
/* Set MAC address */
const AL_IB_VALUE value = {
.length = 6,
.value = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00}
};
AL_SetRequest(AL_MAC_ACA_ADDRESS_IB, 0, &value);
#if defined(TEST_USE_ENCRYPTION)
/* Set Keys */
const AL_IB_VALUE valueK1 = {
.length = 16,
.value = {0x64, 0x25, 0x77, 0xB3, 0x98, 0x2E, 0x43, 0xAA, 0xF5, 0x35, 0x33, 0x59, 0x74, 0x4D, 0x06, 0x1D}
};
AL_SetRequest(AL_AUTH_WRITE_KEY_K1_IB, 0, &valueK1);
const AL_IB_VALUE valueK2 = {
.length = 16,
.value = {0xA0, 0xEE, 0x4C, 0xED, 0x9A, 0x01, 0x59, 0x3C, 0x5C, 0xA7, 0x78, 0xA2, 0xDD, 0x13, 0x34, 0xD2}
};
AL_SetRequest(AL_AUTH_READ_KEY_K2_IB, 0, &valueK2);
#endif
appData.state = APP_STATE_WAIT_AL_READY;
break;
}
case APP_STATE_WAIT_AL_READY:
{
if (AL_GetStatus() == SYS_STATUS_READY)
{
appData.state = APP_STATE_TX_FRAME;
appData.txTimeCount = SYS_TIME_Counter64Get() + SYS_TIME_USToCount(APP_TX_DELAY_US);
}
break;
}
case APP_STATE_TX_FRAME:
{
if (SYS_TIME_Counter64Get() >= appData.txTimeCount)
{
AL_IB_VALUE valueDestACA = {
.length = 6,
.value = {0x00}
};
/* Reverse ACA for Auth IB */
valueDestACA.value[0] = appData.drParams.dstAddress.macAddress[0].address[5];
valueDestACA.value[1] = appData.drParams.dstAddress.macAddress[0].address[4];
valueDestACA.value[2] = appData.drParams.dstAddress.macAddress[0].address[3];
valueDestACA.value[3] = appData.drParams.dstAddress.macAddress[0].address[2];
valueDestACA.value[4] = appData.drParams.dstAddress.macAddress[0].address[1];
valueDestACA.value[5] = appData.drParams.dstAddress.macAddress[0].address[0];
AL_SetRequest(AL_AUTH_DESTINATION_NODE_ACA_IB, 0, &valueDestACA);
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "AL_DATA_REQUEST ATTR=%hhu, APDU=0x", appData.drParams.attr);
for (uint8_t i = 0; i < appData.drParams.apduLen; i++)
{
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "%02X", appData.drParams.apdu[i]);
}
SYS_DEBUG_PRINT(SYS_ERROR_DEBUG, "\r\n");
AL_DataRequest(&appData.drParams);
appData.state = APP_STATE_WAITING;
}
break;
}
case APP_STATE_WAITING:
{
break;
}
/* The default state should never be executed. */
default:
{
break;
}
}
}
