1.9 PRIME Service Dual Metering Demo
The PRIME Service Dual Metering Demo application implements a metering application and a PRIME dual Service Node, capable of joining a PRIME network and replying to IEC 61334-4-32 requests. It demonstrates how to send metrology data through the IEC 61334-4-32 connection.
It is based on the metering demo (for more information refer to its documentation (smartenergy_metrology repository) with added support for PRIME.
Name | Path | Boards |
---|---|---|
Service Dual Metering Demo | \smartenergy_prime_apps\apps\prime_apps\prime_service_dual_metering_demo\pic32cx_mtsh_db_pl460_rf215.X | PIC32CXMTSH-DB+ PL460-EK + REB215-XPRO |
Application Example
The PRIME Service Dual Metering Demo application implements a metering application and a PRIME dual Service Node, capable of joining a PRIME network and replying to IEC 61334-4-32 requests. It demonstrates how to send metrology data through the IEC 61334-4-32 connection.
- Baud-rate 115200 bps
- 8 data bits
- no parity
- 1 stop bit
- Metrology (app_metrology.c): Handles the metrology driver and its configuration.
- Energy (app_energy.c): Interacts with the metrology application to gather energy consumption. Energy consumption is assigned and grouped into different time zones. This application also manages the RTC peripheral.
- Events (app_events.c): Interacts with the metrology application to store the event happening and its occurrence time.
- Console (app_console.c): Interacts with the application using a serial port to send commands to the board and receive data.
- Datalog (app_datalog.c): Writes/Reads data information to/from the external flash memory.
- Display (app_display.c): Navigates through the different data shown in the display using the buttons Scroll Down and Scroll up of the demo boards.
- PRIME Management (app_prime_management.c): Handles the PRIME Stack operation and maintains the PRIME metrology connection functionality.
- PRIME Metrology (prime_metrology.c): Interacts with the metrology application to gather data and send it to the PRIME Base Node.
Application Functionality
For information about the metering demo refer to its documentation (smartenergy_metrology repository).
- Firmware upgrade handling:
- Swapping of the PRIME Stack version between v1.3.6 and v1.4
depending on the network
traffic.
static void lAPP_PRIME_MANAGEMENT_PrimeVersionSwapRequest(SRV_FU_TRAFFIC_VERSION traffic) { /* Compare current PRIME pointer with detected traffic */ if (traffic == SRV_FU_TRAFFIC_VER_PRIME_1_4) { newPrimeApi = (PRIME_API *)PRIME_SN_FWSTACK14_ADDRESS; versionSwapEn = APP_VERSION_ENABLE_SWAP; } else if (traffic == SRV_FU_TRAFFIC_VER_PRIME_1_3) { newPrimeApi = (PRIME_API *)PRIME_SN_FWSTACK13_ADDRESS; versionSwapEn = APP_VERSION_ENABLE_SWAP; } else { // Do nothing } } static void lAPP_PRIME_MANAGEMENT_SwapStackVersion(void) { /* Initialize PRIME stack with the new pointer */ if (newPrimeApi == (PRIME_API *)PRIME_SN_FWSTACK14_ADDRESS) { PRIME_Restart((uint32_t *)newPrimeApi, PRIME_VERSION_1_4); } else { PRIME_Restart((uint32_t *)newPrimeApi, PRIME_VERSION_1_3); } /* Initialize metrology application */ APP_PRIME_METROLOGY_Initialize(); /* Needed to set up callbacks */ }
- Swapping of the firmware received in a firmware upgrade
process.
static void lAPP_PRIME_MANAGEMENT_PrimeFuResultHandler(SRV_FU_RESULT fuResult) { switch (fuResult) { case SRV_FU_RESULT_SUCCESS: /* Update FU pointer */ fuSwapEn = APP_FU_ENABLE_SWAP; break; case SRV_FU_RESULT_CRC_ERROR: /* Nothing to do - FU will restart automatically */ break; case SRV_FU_RESULT_CANCEL: /* Nothing to do */ break; case SRV_FU_RESULT_FW_CONFIRM: /* Nothing to do */ break; case SRV_FU_RESULT_FW_REVERT: /* Revert FU pointer */ fuSwapEn = APP_FU_ENABLE_SWAP; break; case SRV_FU_RESULT_ERROR: /* Nothing to do */ break; case SRV_FU_RESULT_SIGNATURE_ERROR: /* Nothing to do */ break; case SRV_FU_RESULT_IMAGE_ERROR: /* Nothing to do */ break; default: break; } } static void lAPP_PRIME_MANAGEMENT_SwapFirmware(void) { /* Swap firmware */ if (SRV_FU_SwapFirmware() == true) { /* Trigger reset to launch bootloader */ SRV_RESET_HANDLER_RestartSystem(RESET_HANDLER_FU_RESET); } }
- Swapping of the PRIME Stack version between v1.3.6 and v1.4
depending on the network
traffic.
void APP_PRIME_METROLOGY_Initialize ( void )
{
/* Place the App state machine in its initial state. */
app_prime_metrologyState = APP_PRIME_METROLOGY_STATE_INIT;
(void) memset(&boardInfo, 0, sizeof(boardInfo));
/* Get the PRIME version */
SRV_STORAGE_GetConfigInfo(SRV_STORAGE_TYPE_MODE_PRIME,
(uint8_t)sizeof(boardInfo),
(void *)&boardInfo);
/* Get PRIME API pointer */
switch (boardInfo.primeVersion)
{
case PRIME_VERSION_1_3:
PRIME_API_GetPrime13API(&gPrimeApi);
break;
case PRIME_VERSION_1_4:
default:
PRIME_API_GetPrime14API(&gPrimeApi);
break;
}
isDataReceived = false;
/* Set state */
app_prime_metrologyState = APP_PRIME_METROLOGY_STATE_SERVICE_CONFIGURE;
}
case APP_PRIME_METROLOGY_STATE_SERVICE_CONFIGURE:
{
/* Check if PRIME stack is ready */
if (gPrimeApi->Status() == SYS_STATUS_READY)
{
/* Set callback functions */
lAPP_PRIME_METROLOGY_SetCallbacks();
/* Reset connection parameters */
con432Info.isOpen = false;
con432Info.baseAddr = CL_432_INVALID_ADDRESS;
con432Info.nodeAddr = CL_432_INVALID_ADDRESS;
memset(&con432Info.deviceId, 0, sizeof(con432Info.deviceId));
con432Info.deviceIdLen = 0;
/* Read parameters for serial number */
if (boardInfo.primeVersion == PRIME_VERSION_1_3)
{
gPrimeApi->MlmeGetRequest(PIB_MTP_MAC_EUI_48);
}
else
{
gPrimeApi->MlmeGetRequest(PIB_MAC_EUI_48);
}
gPrimeApi->MlmeGetRequest(PIB_MAC_APP_FW_VERSION);
gPrimeApi->MlmeGetRequest(PIB_MAC_APP_VENDOR_ID);
gPrimeApi->MlmeGetRequest(PIB_MAC_APP_PRODUCT_ID);
app_prime_metrologyState = APP_PRIME_METROLOGY_STATE_SERVICE_TASKS;
}
break;
}
static void lAPP_PRIME_METROLOGY_SetCallbacks(void)
{
MAC_CALLBACKS macCallbacks;
CL_432_CALLBACKS cl432_callbacks;
memset(&macCallbacks, 0, sizeof(macCallbacks));
memset(&cl432_callbacks, 0, sizeof(cl432_callbacks));
macCallbacks.mlme_get_cfm = lAPP_PRIME_METROLOGY_MLME_GetConfirm;
macCallbacks.mlme_register_ind = lAPP_PRIME_METROLOGY_MLME_RegisterIndication;
macCallbacks.mlme_unregister_ind = lAPP_PRIME_METROLOGY_MLME_UnregisterIndication;
gPrimeApi->MacSetCallbacks(&macCallbacks);
cl432_callbacks.cl_432_establish_cfm = lAPP_PRIME_METROLOGY_CL432_EstablishConfirm;
cl432_callbacks.cl_432_release_cfm = lAPP_PRIME_METROLOGY_CL432_ReleaseConfirm;
cl432_callbacks.cl_432_dl_data_ind = lAPP_PRIME_METROLOGY_CL432_DlDataIndication;
cl432_callbacks.cl_432_dl_data_cfm = lAPP_PRIME_METROLOGY_CL432_DlDataConfirm;
gPrimeApi->Cl432SetCallbacks(&cl432_callbacks);
}
When the Service Node registers, the PRIME Metrology application requests to open an IEC 16334-4-32 connection. If the connection is released, it requests to reopen it.
static void lAPP_PRIME_METROLOGY_MLME_RegisterIndication(uint8_t *sna, uint8_t sid)
{
if (boardInfo.primeVersion == PRIME_VERSION_1_4)
{
/* Get current security profile */
gPrimeApi->MlmeGetRequest(PIB_MAC_SEC_PROFILE_USED);
}
else
{
ae = 0;
}
/* Launch 432 connection */
gPrimeApi->Cl432EstablishRequest((uint8_t *)meterParams.meterSerial,
strlen((const char *)meterParams.meterSerial),
ae);
}
static void lAPP_PRIME_METROLOGY_CL432_ReleaseConfirm(uint16_t dstAddress,
DL_432_RESULT result)
{
(void)dstAddress;
(void)result;
/* Reset connection parameters */
con432Info.isOpen = false;
con432Info.baseAddr = CL_432_INVALID_ADDRESS;
con432Info.nodeAddr = CL_432_INVALID_ADDRESS;
memset(&con432Info.deviceId, 0, sizeof(con432Info.deviceId));
con432Info.deviceIdLen = 0;
con432Info.dstLsap = 0;
con432Info.srcLsap = 0;
con432Info.linkClass = 0;
/* Re-launch 432 connection */
gPrimeApi->Cl432EstablishRequest((uint8_t *)meterParams.meterSerial,
strlen((const char *)meterParams.meterSerial),
ae);
}
And finally, when a message is received, a response is sent with metrology data. Note that the request to send data cannot happen in the indication callback.
static void lAPP_PRIME_METROLOGY_CL432_DlDataIndication(uint8_t dstLsap,
uint8_t srcLsap, uint16_t dstAddress, uint16_t srcAddress,
uint8_t *data, uint16_t lsduLen, uint8_t linkClass)
{
(void)dstAddress;
(void)srcAddress;
(void)data;
(void)lsduLen;
con432Info.dstLsap = srcLsap;
con432Info.srcLsap = dstLsap;
con432Info.linkClass = linkClass;
isDataReceived = true;
}
case APP_PRIME_METROLOGY_STATE_SERVICE_TASKS:
{
if (isDataReceived == true)
{
/* Send metrology data */
lAPP_PRIME_METROLOGY_SendData();
isDataReceived = false;
}
break;
}