I'm currently building a bootloader suitable for Dual Channel DFU and SD132. It is on nrf52832, currently on PCA10040. Although the linker script works, and creates a hex file, I am left with an app_error_code 1 after nrf_sdh_enable_request(), from sd_softdevice_enable().
Is it the LS's fault? Have I completely missed the mark? Or is it something completely different. Feel free to ask for more details, I've included the LS, as I'm unsure of what else to add.
Thanks
Below is what I have so far, cobbled together from the various examples in the SDK.
SEARCH_DIR(.)
GROUP(-lgcc -lc -lnosys)
GROUP(S132_softdevice.o)
MEMORY
{
FLASH_SOFTDEVICE (rx) : ORIGIN = 0x00001000, LENGTH = 0x00023000
FLASH (rx) : ORIGIN = 0x24000, LENGTH = 0x6CA00
SRAM_SOFTDEVICE (rwx) : ORIGIN = 0x20000000, LENGTH = 0x0005C10
RAM (rwx) : ORIGIN = 0x20005C11, LENGTH = 0x9D6F
/** Location of non initialized RAM. Non initialized RAM is used for exchanging bond information
* from application to bootloader when using buttonluss DFU OTA.
*/
NOINIT (rw) : ORIGIN = 0x2000F97F, LENGTH = 0x80
/** Location of bootloader setting in flash. */
BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0007F000, LENGTH = 0x1000
/** Location in UICR where bootloader start address is stored. */
UICR_BOOTLOADER (r) : ORIGIN = 0x10001014, LENGTH = 0x04
/** Location of mbr params page in flash. */
MBR_PARAMS_PAGE (rw) : ORIGIN = 0x0007E000, LENGTH = 0x1000
/** Location in UICR where mbr params page address is stored. */
UICR_MBR_PARAM_PAGE(r) : ORIGIN = 0x10001018, LENGTH = 0x04
}
SECTIONS
{
/* Place the bootloader settings page in flash. */
.bootloaderSettings(NOLOAD) :
{
} > BOOTLOADER_SETTINGS
/* Write the bootloader address in UICR. */
.uicrBootStartAddress :
{
KEEP(*(.uicrBootStartAddress))
} > UICR_BOOTLOADER
/* Place the mbr params page in flash. */
.mbrParamsPage(NOLOAD) :
{
} > MBR_PARAMS_PAGE
/* Write the bootloader address in UICR. */
.uicrMbrParamsPageAddress :
{
KEEP(*(.uicrMbrParamsPageAddress))
} > UICR_MBR_PARAM_PAGE
/* No init RAM section in bootloader. Used for bond information exchange. */
.noinit(NOLOAD) :
{
} > NOINIT
/* other placements follow here... */
}
SECTIONS
{
. = ALIGN(4);
.softdevice :
{
KEEP(*(.softdevice))
FILL(0xFFFFFFFF);
. = 0x00023000;
} > FLASH_SOFTDEVICE
. = ALIGN(4);
.softdevice_sram :
{
FILL(0xFFFFFFFF);
. = 0x00005C10;
} > SRAM_SOFTDEVICE
.svc_data :
{
PROVIDE(__start_svc_data = .);
KEEP(*(.svc_data))
PROVIDE(__stop_svc_data = .);
} > RAM
.fs_data :
{
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
} > RAM
.log_dynamic_data :
{
PROVIDE(__start_log_dynamic_data = .);
KEEP(*(.log_dynamic_data))
PROVIDE(__stop_log_dynamic_data = .);
} > RAM
.cli_sorted_cmd_ptrs :
{
PROVIDE(__start_cli_sorted_cmd_ptrs = .);
KEEP(*(.cli_sorted_cmd_ptrs))
PROVIDE(__stop_cli_sorted_cmd_ptrs = .);
} > RAM
} INSERT AFTER .data;
SECTIONS
{
.dfu_trans :
{
PROVIDE(__start_dfu_trans = .);
KEEP(*(SORT(.dfu_trans*)))
PROVIDE(__stop_dfu_trans = .);
} > FLASH
.pwr_mgmt_data :
{
PROVIDE(__start_pwr_mgmt_data = .);
KEEP(*(SORT(.pwr_mgmt_data*)))
PROVIDE(__stop_pwr_mgmt_data = .);
} > FLASH
.log_const_data :
{
PROVIDE(__start_log_const_data = .);
KEEP(*(.log_const_data))
PROVIDE(__stop_log_const_data = .);
} > FLASH
.cli_command :
{
PROVIDE(__start_cli_command = .);
KEEP(*(.cli_command))
PROVIDE(__stop_cli_command = .);
} > FLASH
. = ALIGN(4);
.sdh_stack_observers :
{
PROVIDE(__start_sdh_stack_observers = .);
KEEP(*(SORT(.sdh_stack_observers*)))
PROVIDE(__stop_sdh_stack_observers = .);
} > FLASH
. = ALIGN(4);
.sdh_req_observers :
{
PROVIDE(__start_sdh_req_observers = .);
KEEP(*(SORT(.sdh_req_observers*)))
PROVIDE(__stop_sdh_req_observers = .);
} > FLASH
. = ALIGN(4);
.sdh_state_observers :
{
PROVIDE(__start_sdh_state_observers = .);
KEEP(*(SORT(.sdh_state_observers*)))
PROVIDE(__stop_sdh_state_observers = .);
} > FLASH
/*.sdh_ant_observers :
*{
* PROVIDE(__start_sdh_ant_observers = .);
* KEEP(*(SORT(.sdh_ant_observers*)))
* PROVIDE(__stop_sdh_ant_observers = .);
*} > FLASH
*/
. = ALIGN(4);
.sdh_ble_observers :
{
PROVIDE(__start_sdh_ble_observers = .);
KEEP(*(SORT(.sdh_ble_observers*)))
PROVIDE(__stop_sdh_ble_observers = .);
} > FLASH
. = ALIGN(4);
.sdh_soc_observers :
{
PROVIDE(__start_sdh_soc_observers = .);
KEEP(*(SORT(.sdh_soc_observers*)))
PROVIDE(__stop_sdh_soc_observers = .);
} > FLASH
} INSERT AFTER .text
INCLUDE "nrf5x_common.ld"
PROVIDE(_sbss = __bss_start__);
PROVIDE(_ebss = __bss_end__);
PROVIDE(_sdata = __data_start__);
PROVIDE(_sidata = __etext);
PROVIDE(_estack = __StackTop);
PROVIDE(_edata =__data_end__);
PROVIDE(__isr_vector = __StackTop);
Related
I want to create a 4MB buffer allocated in a predefined section of linker script. Using ld --verbose I got the default linker script used by gcc. I want to add a section called .exchangeBuffer addresable by 32-bit (virtual addresses are up to 48-bit, but I want to allocate my section in an address lower thaN 0x0000_FFFF_FFFF).
So, I imagine my buffer should be declared like this:
#define FOUR_MEGABYTES (4*1024*1024)
uint8_t __attribute__((section (".exchangeBuffer"))) exchange[FOUR_MEGABYTES];
But then default linker script, starts like this:
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.dyn :
{
/* The scripts continue until end.... */
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}
Where and how should I place my 4MB section?
Please, note that executable is running on a 64-bit Desktop Linux compiled with their native gcc. All available information regarding this topic I found is related with embedded systems and simpler linker scripts, 32-bit processors without virtual addressing.
Thanks,
My problem is:
Livolo switches have their own Zigbee gate. I want to connect them from zigbee2mqtt with CC2531 USB dongle. In general it works, but when I turn on/off switch button (on physical device), the switch sends an incorrect ZCL package.
I'm an absolutely newbie in microcontrollers programming and in Zigbee architecture. So I hope someone can help me and answer these questions:
Where I can intercept that malformed package?
How I can fix that package to support the Zigbee standard?
I use Z-STACK-HOME 1.2.2a firmware and compile it as described there:
https://github.com/Koenkk/Z-Stack-firmware/blob/master/coordinator/Z-Stack_Home_1.2/COMPILE.md
// Malformed ZCL package
// header
0x7c, // [0111 1100]
// 01 - frame type = "Command is specific or local to a cluster"
// 1 - manufacturer spec = manufacturer code present
// 1 - direction = "from server to client"
// 1 - disable default response
// 100 - reserved
0xd2, 0x15, // manufacturer
0xd8, // sequence
0x00, // read attrs command
// endpoint adress
0x12, 0x0f, 0x05, 0x18, 0x00, 0x4b, 0x12, 0x00,
0x22, 0x00, // ????? need more data from another switches
0x03 // 0x00|0x01|0x02|0x03 - switch state
upd:
I think, what I can intercept message in AF.c file in afIncomingData function and fix in afBuildMSGIncoming.
So now I hope, someone can help me with the right message format. Which can be processed standard ZCL parcer.
void afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,
NLDE_Signal_t *sig, uint8 nwkSeqNum, uint8 SecurityUse,
uint32 timestamp, uint8 radius )
{
endPointDesc_t *epDesc = NULL;
epList_t *pList = epList;
#if !defined ( APS_NO_GROUPS )
uint8 grpEp = APS_GROUPS_EP_NOT_FOUND;
#endif
if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
{
#if !defined ( APS_NO_GROUPS )
// Find the first endpoint for this group
grpEp = aps_FindGroupForEndpoint( aff->GroupID, APS_GROUPS_FIND_FIRST );
if ( grpEp == APS_GROUPS_EP_NOT_FOUND ) {
// No endpoint found, default to endpoint 1.
// In the original source code there is a return here.
// This prevent the messags from being forwarded.
// For our use-case we want to capture all messages.
// Even if the coordinator is not in the group.
epDesc = afFindEndPointDesc( 1 );
}
else {
epDesc = afFindEndPointDesc( grpEp );
}
if ( epDesc == NULL )
return; // Endpoint descriptor not found
pList = afFindEndPointDescList( epDesc->endPoint );
#else
return; // Not supported
#endif
}
else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
{
// Set the list
if ( pList != NULL )
{
epDesc = pList->epDesc;
}
}
else if ( aff->DstEndPoint == 10 || aff->DstEndPoint == 11 ) {
if ( (epDesc = afFindEndPointDesc( 1 )) )
{
pList = afFindEndPointDescList( epDesc->endPoint );
}
}
else if ( (epDesc = afFindEndPointDesc( aff->DstEndPoint )) )
{
pList = afFindEndPointDescList( epDesc->endPoint );
}
while ( epDesc )
{
uint16 epProfileID = 0xFFFE; // Invalid Profile ID
if ( pList->pfnDescCB )
{
uint16 *pID = (uint16 *)(pList->pfnDescCB(
AF_DESCRIPTOR_PROFILE_ID, epDesc->endPoint ));
if ( pID )
{
epProfileID = *pID;
osal_mem_free( pID );
}
}
else if ( epDesc->simpleDesc )
{
epProfileID = epDesc->simpleDesc->AppProfId;
}
// First part of verification is to make sure that:
// the local Endpoint ProfileID matches the received ProfileID OR
// the message is specifically send to ZDO (this excludes the broadcast endpoint) OR
// if the Wildcard ProfileID is received the message should not be sent to ZDO endpoint
if ( (aff->ProfileID == epProfileID) ||
((epDesc->endPoint == ZDO_EP) && (aff->ProfileID == ZDO_PROFILE_ID)) ||
((epDesc->endPoint != ZDO_EP) && ( aff->ProfileID == ZDO_WILDCARD_PROFILE_ID )) )
{
// Save original endpoint
uint8 endpoint = aff->DstEndPoint;
// overwrite with descriptor's endpoint
aff->DstEndPoint = epDesc->endPoint;
afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig,
nwkSeqNum, SecurityUse, timestamp, radius );
// Restore with original endpoint
aff->DstEndPoint = endpoint;
}
if ( ((aff->FrmCtrl & APS_DELIVERYMODE_MASK) == APS_FC_DM_GROUP) )
{
#if !defined ( APS_NO_GROUPS )
// Find the next endpoint for this group
grpEp = aps_FindGroupForEndpoint( aff->GroupID, grpEp );
if ( grpEp == APS_GROUPS_EP_NOT_FOUND )
return; // No endpoint found
epDesc = afFindEndPointDesc( grpEp );
if ( epDesc == NULL )
return; // Endpoint descriptor not found
pList = afFindEndPointDescList( epDesc->endPoint );
#else
return;
#endif
}
else if ( aff->DstEndPoint == AF_BROADCAST_ENDPOINT )
{
pList = pList->nextDesc;
if ( pList )
epDesc = pList->epDesc;
else
epDesc = NULL;
}
else
epDesc = NULL;
}
}
static void afBuildMSGIncoming( aps_FrameFormat_t *aff, endPointDesc_t *epDesc,
zAddrType_t *SrcAddress, uint16 SrcPanId, NLDE_Signal_t *sig,
uint8 nwkSeqNum, uint8 SecurityUse, uint32 timestamp, uint8 radius )
{
afIncomingMSGPacket_t *MSGpkt;
const uint8 len = sizeof( afIncomingMSGPacket_t ) + aff->asduLength;
uint8 *asdu = aff->asdu;
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_allocate( len );
if ( MSGpkt == NULL )
{
return;
}
MSGpkt->hdr.event = AF_INCOMING_MSG_CMD;
MSGpkt->groupId = aff->GroupID;
MSGpkt->clusterId = aff->ClusterID;
afCopyAddress( &MSGpkt->srcAddr, SrcAddress );
MSGpkt->srcAddr.endPoint = aff->SrcEndPoint;
MSGpkt->endPoint = epDesc->endPoint;
MSGpkt->wasBroadcast = aff->wasBroadcast;
MSGpkt->LinkQuality = sig->LinkQuality;
MSGpkt->correlation = sig->correlation;
MSGpkt->rssi = sig->rssi;
MSGpkt->SecurityUse = SecurityUse;
MSGpkt->timestamp = timestamp;
MSGpkt->nwkSeqNum = nwkSeqNum;
MSGpkt->macSrcAddr = aff->macSrcAddr;
MSGpkt->macDestAddr = aff->macDestAddr;
MSGpkt->srcAddr.panId = SrcPanId;
MSGpkt->cmd.TransSeqNumber = 0;
MSGpkt->cmd.DataLength = aff->asduLength;
MSGpkt->radius = radius;
if ( MSGpkt->cmd.DataLength )
{
MSGpkt->cmd.Data = (uint8 *)(MSGpkt + 1);
osal_memcpy( MSGpkt->cmd.Data, asdu, MSGpkt->cmd.DataLength );
}
else
{
MSGpkt->cmd.Data = NULL;
}
#if defined ( MT_AF_CB_FUNC )
// If ZDO or SAPI have registered for this endpoint, dont intercept it here
if (AFCB_CHECK(CB_ID_AF_DATA_IND, *(epDesc->task_id)))
{
MT_AfIncomingMsg( (void *)MSGpkt );
// Release the memory.
osal_msg_deallocate( (void *)MSGpkt );
}
else
#endif
{
// Send message through task message.
osal_msg_send( *(epDesc->task_id), (uint8 *)MSGpkt );
}
}
I don't think you're decoding the frame control byte correctly. Looking at some code I've written, I interpret it as follows:
0x7c, // [0111 1100]
// 011 - reserved
// 1 - disable default response
// 1 - direction = "from server to client"
// 1 - manufacturer spec = manufacturer code present
// 00 - frame type = "Command acts across entire profile"
This is based on an old ZCL spec (around 2008?) and perhaps the reserved bits have taken on some meaning in a later version of the spec.
I believe the manufacturer specific bit indicates that this is not a standard Zigbee command (Read Attributes). If it was Read Attributes, I think it should have an even number of bytes following it (16-bit attribute IDs).
What were the source and destination endpoints, profile ID and cluster ID for that frame?
Update:
It looks like you could modify afIncomingData() to look at the fields of aff to identify this exact message type (frame control, endpoints, cluster, profile), and then hand it off to your own function for processing (and responding if necessary).
But I'd also take a look at documentation for MT_AF_CB_FUNC and MT_AfIncomingMsg() to see if that's the "official" way to identify frames that you want to handle in your own code.
In AF.c file in functions afIncomingData and afBuildMSGIncoming added bloks marked by
#if defined ( LIVOLO_SUPPORT )
#endif
In afIncomingData I add:
#if defined ( LIVOLO_SUPPORT )
else if ( aff->DstEndPoint == 0x08 )
{
if ( (epDesc = afFindEndPointDesc( 1 )) )
{
pList = afFindEndPointDescList( epDesc->endPoint );
}
}
#endif
It's prewent filtering message sended to unknown destEndpoint
And in afBuildMSGIncoming function:
#if defined ( LIVOLO_SUPPORT )
uint8 fixedPackage[] = {
0x18, 0xd8, 0x01, // header
0x00, 0x00, // attrId
0x00, // success
0x10, // boolean
0x00
};
if (aff->SrcEndPoint == 0x06 && aff->DstEndPoint == 0x01
&& aff->ClusterID == 0x0001 && aff->ProfileID == 0x0104) {
const uint8 mlfrmdHdr[] = { 0x7c, 0xd2, 0x15, 0xd8, 0x00 };
if (osal_memcmp(asdu, mlfrmdHdr, 5) == TRUE) {
fixedPackage[7] = asdu[aff->asduLength - 1];
MSGpkt->cmd.DataLength = 8; // sizeof(fixedPackage)
MSGpkt->clusterId = 0x06; // genOnOff
asdu = fixedPackage;
}
}
#endif
It change unsupported package to readAttrResp package.
I am Integrating paytm gateway in ios app when I generating checksum through api calling and pass this checksum with below param in web view
WEB VIEW is loading with Parms:
{
"CALLBACK_URL" = "https://securegw-stage.paytm.in/theia/paytmCallback?ORDER_ID=SJ-1552029210215";
"CHANNEL_ID" = WAP;
CHECKSUMHASH = "FRMuR8LLFvg3wkIf6gp4BqVnNigr6WvUaSm9EVJIJo6Z5RicUvU7acRGZlEfK1FGoeNSqN53R0OphttHFnJuZ0lKeAZDvrG7Pr5ZnlzTEUw=";
"CUST_ID" = 64;
EMAIL = "jitu123#gmail.com";
"INDUSTRY_TYPE_ID" = Retail;
MID = rxazcv89315285244163;
"MOBILE_NO" = 566789877;
"ORDER_ID" = "SJ-1552029210215";
"TXN_AMOUNT" = "246.0";
WEBSITE = WEBSTAGING;
}
I am getting back below response
{
"ORDERID" : "SJ-1552029210215",
"MID" : "rxazcv89315285244163",
"TXNAMOUNT" : "246.00",
"BANKTXNID" : "",
"RESPCODE" : "330",
"STATUS" : "TXN_FAILURE",
"CURRENCY" : "INR",
"RESPMSG" : "Paytm checksum mismatch."
}
how can i solve paytm checksum mismatch issue???
I want to use one embedded Linux kernel for 2 devices, I build this kernel with mkimage tool and rules in .dts file. Devices differs load and entry points. But u-boot doesn't use load and entry point addresses from configuration, only from kernel section. As result 2 big size data files (fully identical) are included into resulting .dtb file. It's inefficient. Can I transfer correct values from configuration to kernel sections? Or use links to single binary from both kernel sections?
Thank you in advance,
Dmytro Badekha.
Content of ITS file:
/dts-v1/;
/ {
description = "ARM FIT (Flattened Image Tree)";
#address-cells = <1>;
images {
kernel#1 {
description = "ARM OpenWrt Linux-3.14.77";
data = /incbin/("./Image.gz");
type = "kernel";
arch = "arm";
os = "linux";
compression = "gzip";
load = <0x42208000>;
entry = <0x42208000>;
hash#1 {
algo = "crc32";
};
hash#2 {
algo = "sha1";
};
};
kernel#2 {
description = "ARM OpenWrt Linux-3.14.77";
data = /incbin/("./Image.gz");
type = "kernel";
arch = "arm";
os = "linux";
compression = "gzip";
load = <0x80208000>;
entry = <0x80208000>;
hash#1 {
algo = "crc32";
};
hash#2 {
algo = "sha1";
};
};
fdt#v3.0-ap160 {
description = "ARM OpenWrt qcom-ipq806x-akxx device tree blob";
data = /incbin/("./qcom-ipq8064-v3.0-ap160.dtb.gz");
type = "flat_dt";
arch = "arm";
compression = "gzip";
load = <0x43F00000>;
hash#1 {
algo = "crc32";
};
hash#2 {
algo = "sha1";
};
};
fdt#ap.dk04.1-c4 {
description = "ARM OpenWrt qcom-ipq40xx-ap.dkxx device tree blob";
data = /incbin/("./qcom-ipq40xx-ap.dk04.1-c4.dtb");
type = "flat_dt";
arch = "arm";
compression = "none";
hash#1 {
algo = "crc32";
};
hash#2 {
algo = "sha1";
};
};
};
configurations {
default = "config#v3.0-ap160";
config#v3.0-ap160 {
description = "OpenWrt";
kernel = "kernel#1";
fdt = "fdt#v3.0-ap160";
};
config#ap.dk04.1-c4 {
description = "OpenWrt";
kernel = "kernel#2";
fdt = "fdt#ap.dk04.1-c4";
};
};
};
I am trying to send a log schema from raspberry pi C application, to back end kaa server.
Here is the schema
{
"type" : "record",
"name" : "RemoteSensorLog",
"namespace" : "org.kaa.iot.log.sensor",
"fields" : [ {
"name" : "deviceId",
"type" : {
"type" : "string",
"avro.java.string" : "String"
}
}, {
"name" : "temperature",
"type" : [ "double", "null" ]
}, {
"name" : "humidity",
"type" : [ "long", "null" ]
}, {
"name" : "batteryLevel",
"type" : [ "int", "null" ]
} ],
"version" : 1,
"dependencies" : [ ],
"displayName" : "RemoteSensorLog",
"description" : "This is the log sent by remote sensors"
}
Some of the items in the log schema are optional, Here is the initialization function
void kaaLogInitializing(void *context)
{
void *log_storage_context = NULL;
void *log_upload_strategy_context = NULL;
printf("Initializing the Kaa log\n");
kaa_client_t * kaa_client_context = context;
if (context == NULL) {
return;
}
/* Log delivery listener callbacks. Each callback called whenever something happen with a log bucket. */
kaa_log_delivery_listener_t log_listener = {
.on_success = success_log_delivery_callback, /* Called if log delivered successfully */
.on_failed = failed_log_delivery_callback, /* Called if delivery failed */
.on_timeout = timeout_log_delivery_callback, /* Called if timeout occurs */
.ctx = kaa_client_context, /* Optional context */
};
/* The internal memory log storage distributed with Kaa SDK */
kaa_error_t error_code = ext_unlimited_log_storage_create(&log_storage_context,
kaa_client_get_context(
kaa_client_context
)->logger
);
if (error_code) {
printf("Failed to create Kaa log storage %d\r\n", error_code);
return;
}
error_code = ext_log_upload_strategy_create(kaa_client_get_context(
kaa_client_context),
&log_upload_strategy_context, KAA_LOG_UPLOAD_VOLUME_STRATEGY);
if (error_code) {
printf("Failed to create log upload strategy, error code %d\r\n", error_code);
return;
}
error_code = ext_log_upload_strategy_set_threshold_count(log_upload_strategy_context,
LOG_UPLOAD_THRESHOLD);
if (error_code) {
printf("Failed to set threshold log record count, error code %d\r\n", error_code);
return;
}
error_code = kaa_logging_set_strategy(kaa_client_get_context(kaa_client_context)->log_collector,
log_upload_strategy_context);
if (error_code) {
printf("Failed to set log upload strategy, error code %d\r\n", error_code);
return;
}
/* Specify log bucket size constraints */
kaa_log_bucket_constraints_t bucket_sizes = {
.max_bucket_size = MAX_LOG_BUCKET_SIZE, /* Bucket size in bytes */
.max_bucket_log_count = MAX_LOG_COUNT, /* Maximum log count in one bucket */
};
/* Initialize the log storage and strategy (by default it is not set) */
error_code = kaa_logging_init(kaa_client_get_context(
kaa_client_context)->log_collector
, log_storage_context
, log_upload_strategy_context
, &bucket_sizes);
if (error_code) {
printf("Failed to initialize Kaa log %d\r\n", error_code);
return;
}
/* Add listeners to a log collector */
kaa_logging_set_listeners(kaa_client_get_context(
kaa_client_context)->log_collector,
&log_listener);
}
Here is the function I use to send log
void sendLog(void *context)
{
kaa_client_t * kaa_client_context = context;
float temperature = 25.5;
if (context == NULL) {
return;
}
logDelivered = LOG_DELIVERY_DELIVERING;
printf("Start attempt to send Log\n");
kaa_logging_remote_sensor_log_t *log_record = kaa_logging_remote_sensor_log_create();
log_record->device_id = kaa_string_copy_create("Dev1");
log_record->temperature = kaa_logging_union_double_or_null_branch_0_create();
log_record->temperature->data = &temperature; /* create subobject */
log_record->humidity = kaa_logging_union_long_or_null_branch_1_create();
log_record->battery_level = kaa_logging_union_int_or_null_branch_1_create();
printf("Log record created\n");
/* Log information. Populated when log is added via kaa_logging_add_record() */
kaa_log_record_info_t log_info;
kaa_error_t error = kaa_logging_add_record(
kaa_client_get_context(kaa_client_context)->log_collector,
log_record, &log_info);
if (error) {
printf("Failed to add log record, error code\r\n");
kaa_client_stop(kaa_client_context);
return;
}
//log_record->destroy(log_record);
}
I have 2 problems
Problem1 #### : if I uncomment the last line in sendLog function log_record->destroy(log_record); I got this error double free or corruption (out): 0x7efe05
Problem2 #### : after commenting the mentioned line and running the application I never get any error or the server get the log nothing seems to happen neither I receive log was sent successfully or failure or timeout.
You need to manually allocate memory to store the temperature value. It will be freed in thelog_record->destroy(log_record).
So, you need to do something like this:
double *p_temperature = KAA_MALLOC(sizeof(double));
if (!p_temperature) {
// error handling
}
*p_temperature = 25.5;
log_record->temperature->data = p_temperature;