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 additional information refer to the corresponding 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 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.
- PRIME Modem (app_modem.c): Implements the interface between the PRIME Library and an external device. This interface allows accessing the PRIME API through serial interface.
Application Functionality
For additional 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); }
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;
}
