sprintf during ISR causes crash? - crash

I am trying to format a string and then print it out to an LCD during an ISR. The ISR functions correctly with sprintf() commented out; but when it is introduced the program crashes during the ISR.
void __ISR(_CHANGE_NOTICE_VECTOR, IPL1) CNIntHandler(void) {
//more of my code later
LATBINV = LEDC; //invert LEDC to a 1
hw_msDelay(20);
int buttons = read_buttons();
decode_buttons(buttons, &g_step_mode, &g_step_dir, &g_motor_delay);
LATBINV = LEDC; //reinvert LEDC to 0
mCNClearIntFlag(); //clear the CN flag
}
The sprintf() occurs within the decode_buttons() fucntion:
void decode_buttons(int f_buttons, int *f_step_mode, int *f_step_dir, int *f_motor_delay) {
char f_mode_str;
char f_dir_str;
int f_RPM;
char f_LCD_str;
switch(f_buttons) {
case 0x0000: //none pressed
*f_step_mode = HS;
f_mode_str = "HALF";
*f_step_dir = CW;
f_dir_str = "CW";
*f_motor_delay = 20; // semipermanent value
f_RPM = 15;
break;
case 0x0040: //BTN 1 pressed
*f_step_mode = FS;
f_mode_str = "FULL";
*f_step_dir = CW;
f_dir_str = "CW";
*f_motor_delay = 40;
f_RPM = 15;
break;
case 0x0080: // BTN 2 pressed
*f_step_mode = HS;
f_mode_str = "HALF";
*f_step_dir = CCW;
f_dir_str = "CCW";
*f_motor_delay = 30;
f_RPM = 10;
break;
case 0x00C0: //Both pressed
*f_step_mode = FS;
f_mode_str = "FULL";
*f_step_dir = CCW;
f_dir_str = "CCW";
*f_motor_delay = 24;
f_RPM = 25;
break;
default:
break;
}
sprintf(f_LCD_str, "%s %s %d", f_dir_str, f_mode_str, &f_RPM);
LCD_puts(f_LCD_str); //output string to LCD
return;
}
I'm working on a PIC32 Cerebot board, and the goal is to update an LCD with the current mode, direction, and RPM of a stepper motor. I'll clarify what I can and post anything needed.

sprintf composes a string and stores it in an array that must be big enough: http://www.cplusplus.com/reference/cstdio/sprintf/
In your code, the output buffer you pass to sprintf is declared as
char f_LCD_str;
which is not an array but a single character. sprintf will inevitable overflow.
A good declaration would be
char f_LCD_str[30];
(same remark for your other char arrays: f_mode_str and f_dir_str)
It is always safer to use snprintf in order to avoid overflow risks. In which case the call would be:
sprintf(f_LCD_str, 30, "%s %s %d", f_dir_str, f_mode_str, f_RPM);
note: &f_RPM will print the address of the variable, where f_RPM will print out the variable value, depending on what you want.

Related

I can't read keydatas (buttons' press values) with SPI between XMC4800 and STLED316

I use SPI communication between XMC4800 and STLED316 led controller. I can write datas to the display on STLED316.However, I can't read keydatas (by keyscan feature of STLED, it is written by STLED316 datasheet). I have some codes for write and read. I suppose command address or register address to send a byte to STLED is wrong. I couldn't figure out if they are the problem or something else. I simplified the codes. I used SPI_MASTER API for communication. write_7segg is working but can't use keydata's specific bits to use button press values (0,1). I need to use key press (keydata) values to change something on the display. If someone worked with STLED316 before, it maybe more understandable. Finally, STLED316 has a 5-digit display and 5 buttons with keyscan feature. read[0] = STLED316_DATA_RD = 0x40, read[1] = STLED316_READ_PAGE = 0x08, keydata[0] = STLED316_ADDR_KEY_DATA1 = 0x01. Here the codes are:
keydata = read_keyscan();
if ((((keydata) & 0x01) == 1) && (current_mode == 0)) {
write_7segg(4, arServo_Numbers[0]);
write_7segg(3, arServo_Numbers[0]);
write_7segg(2, arServo_Characters[23]);
write_7segg(1, arServo_Numbers[0]);
write_7segg(0, arServo_Characters[15]);
}
void write_7segg(unsigned char DisplayNumber, unsigned char Segments) {
// DIGITAL_IO_SetOutputLow(&DIGITAL_IO_0);
Buffer[0] = DisplayNumber;
Buffer[1] = Segments;
DIGITAL_IO_SetOutputLow(&DIGITAL_IO_8);
SPI_MASTER_Transmit(&SPI_MASTER_01,Buffer, 2);
DIGITAL_IO_SetOutputHigh(&DIGITAL_IO_8);
uint8_t readData(uint8_t address){
uint8_t sendByte = read[0]|read[1]|address;
uint8_t readByte = 0;
DIGITAL_IO_SetOutputLow(&DIGITAL_IO_8);
SPI_MASTER_Transfer(&SPI_MASTER_01,&sendByte, &readByte, 1);
DIGITAL_IO_SetOutputHigh(&DIGITAL_IO_8);
return readByte;
}
uint16_t read_keyscan(void){
uint16_t keyState = 0;
keyState = readData(keys[1]) << 8;
keyState = readData(keys[0]);
return keyState;
}

MLX90621 no Acknowlegde with the RAM

First off all I am a beginner regarding embedded programming.
For an application I do want to use the MLX90621 thermo pixel array togehter with an STM32G431KB. On the Melexis Website is an example Code with some sort off abstraction. I moddified the lowlevel part of the code to work with the HAL library of the MCU.
For some reason I can read the EEPROM and write to it, get an acknowledge... But when trying to read from the adress 0x60, the RAM, where the sensorvalues are stored i do not get an acknowledge. I do have checkt with an logic analyer and I am sending the correct messages. Just for refference I do have added the code part of the read function.
Has anybody an idea regarding some very dump timing error or something like that.
P.S. Allready tried an different sensor of my order with the exact same result.
int MLX90621_I2CRead(uint8_t slaveAddr,uint8_t command, uint8_t startAddress, uint8_t addressStep, uint8_t nMemAddressRead, uint16_t *data)
{
uint8_t sa = slaveAddr << 1;
int cnt = 0;
int i = 0;
uint8_t cmd[4] = {0,0,0,0};
uint8_t i2cData[132] = {0};
uint16_t *p;
p = data;
cmd[0] = command;
cmd[1] = startAddress;
cmd[2] = addressStep;
cmd[3] = nMemAddressRead;
if (HAL_I2C_Master_Transmit(&hi2c2, sa, cmd, 4, HAL_MAX_DELAY) != HAL_OK)
return -1;
HAL_Delay(1);
//sa = sa | 0x01;
//ack = i2c.read(sa, i2cData, 2*nMemAddressRead, 0);
if (HAL_I2C_Master_Receive(&hi2c2, sa, i2cData, 2*nMemAddressRead, HAL_MAX_DELAY) != HAL_OK)
return -1;
for (cnt = 0; cnt < nMemAddressRead; cnt++) {
i = cnt << 1;
*p++ = (uint16_t)i2cData[i+1]*256 + (uint16_t)i2cData[i];
}
return 0;
}

Sample implementation of java CBCBlockCipherMac in Objective c

Can anyone share a sample code on how to implement CBCBlockCipherMac in objective C. here is how far I got and its giving a different result from the java implementation.
const unsigned char key[16] = "\x1\x2\x3\x4\x5\x6\x7\x8\x9\x0\x1\x2\x3\x4\x5\x6";
const unsigned char data[14] = "\x54\x68\x69\x73\x69\x73\x6d\x79\x73\x74\x72\x69\x6e\x67";
CMAC_CTX *ctx = CMAC_CTX_new();
ret = CMAC_Init(ctx, key, sizeof(key), EVP_des_ede3(), 0);
printf("CMAC_Init = %d\n", ret);
ret = CMAC_Update(ctx, data, sizeof(data));
printf("CMAC_Update = %d\n", ret);
size_t size;
//unsigned int size;
unsigned char tag[4];
ret = CMAC_Final(ctx, tag, &size);
printf("CMAC_Final = %d, size = %u\n", ret, size);
CMAC_CTX_free(ctx);
printf("expected: 391d1520\n"
"got: ");
size_t index;
for (index = 0; index < sizeof(tag) - 1; ++index) {
printf("%02x", tag[index]);
if ((index + 1) % 4 == 0) {
printf(" ");
}
}
printf("%02x\n", tag[sizeof(tag) - 1]);
And my java code looks like this
String *data = "Thisismystring";
String *keyString = "1234567890123456";
bytes[]mac = new byte[4];
CBCBlockCipherMac macCipher = new CBCBlockCipherMac(DESedeEngine);
DESedeParameters keyParameter = new DESedeParameters(keyString.getBytes());
DESedeEngine engine = new DESedeEngine();
engine,init(true, keyParameter);
byte[] dataBytes = data.getBytes();
macCipher.update(dataBytes,0,data.length());
macCipher.doFinal(mac,0);
byte[] macBytesEncoded = Hex.encode(mac);
String macString = new String(macBytesEncoded);
This gives me "391d1520". But the objective c gives me "01000000"
CMAC is not the same as CBC MAC. CMAC has an an additional step at the beginning and the end of the calculation. If possible I would suggest you upgrade your Java code to use CMAC, as CBC is not as secure, e.g. using org.bouncycastle.crypto.macs.CMac.
OpenSSL does not seem to implement CBC MAC directly (at least, I cannot find any reference to it). So if you need it, you need to implement it yourself.
You can use CBC mode encryption with a zero IV and take the last 16 bytes of the encryption. Of course, this means you need to store the rest of the ciphertext in a buffer somewhere, or you need to use the update functions smartly (reusing the same buffer over and over again for the ciphertext).

Floodfill memory leak iPhone

I'm implementing a floodfill function in C for the iPhone.
The fill works, although I'm having 2 issues.
The phone gives a memory warning after a few executions of the code below. Most likely a memory leak. Also note that the unsigned char *data (the image data) is being free()'d at the end of the floodfill.
(lesser issue) If I attempt to write RGB colors to pixels that are greater than approximately (r:200,g:200,b:200,a:200) I get weird artifacting happening. A workaround for this was to simply limit the values.
I suspect there may be a correlation between both of these problems.
The code below describes my flood-fill algorithm, using a stack:
.h:
typedef struct {
int red;
int green;
int blue;
int alpha;
} GUIColor;
struct pixel_st {
int x;
int y;
struct pixel_st *nextPixel;
};
typedef struct pixel_st pixel;
.m:
void floodFill(CGPoint location, GUIColor tc, GUIColor rc, size_t width, size_t height, unsigned char *data){
if (isGUIColorEqual(tc, rc)) return;
pixel* aPixel = (pixel *) malloc(sizeof (struct pixel_st));
NSLog(#"sizeof aPixel : %i",(int)sizeof(aPixel));
(*aPixel).x = location.x;
(*aPixel).y = location.y;
(*aPixel).nextPixel = NULL;
int i = 0;
NSLog(#"Replacement color A%i, R%i, G%i, B%i",rc.alpha,rc.red,rc.green, rc.blue);
while (aPixel != NULL){
pixel *oldPixel_p = aPixel;
pixel currentPixel = *aPixel;
aPixel = currentPixel.nextPixel;
//Now we do some boundary checks
if (!isOutOfBounds(currentPixel.x, currentPixel.y, width, height)){
//Grab the current Pixel color
GUIColor currentColor = getGUIColorFromPixelAtLocation(CGPointMake(currentPixel.x, currentPixel.y), width, height, data);
if (isGUIColorSimilar(currentColor, tc)){
//Colors are similar, lets continue the spread
setGUIColorToPixelAtLocation(CGPointMake(currentPixel.x, currentPixel.y), rc, width,height, data);
pixel *newPixel;
if ((newPixel = (pixel*) malloc(sizeof(struct pixel_st))) != NULL) {
(*newPixel).x = currentPixel.x;
(*newPixel).y = currentPixel.y-1;
(*newPixel).nextPixel = aPixel;
aPixel = newPixel;
}
if ((newPixel = (pixel*) malloc(sizeof(struct pixel_st))) != NULL) {
(*newPixel).x = currentPixel.x;
(*newPixel).y = currentPixel.y+1;
(*newPixel).nextPixel = aPixel;
aPixel = newPixel;
}
if ((newPixel = (pixel*) malloc(sizeof(struct pixel_st))) != NULL) {
(*newPixel).x = currentPixel.x+1;
(*newPixel).y = currentPixel.y;
(*newPixel).nextPixel = aPixel;
aPixel = newPixel;
}
if ((newPixel = (pixel*) malloc(sizeof(struct pixel_st))) != NULL) {
(*newPixel).x = currentPixel.x-1;
(*newPixel).y = currentPixel.y;
(*newPixel).nextPixel = aPixel;
aPixel = newPixel;
}
free(oldPixel_p);
i ++;
if (i == width * height * 4 * 5) break;
}
}
}
free(aPixel);
}
This implementation of the stack is based on the ObjFloodFill found here:
https://github.com/OgreSwamp/ObjFloodFill/blob/master/src/FloodFill.m
First of all, each if ((newPixel = (pixel*) malloc(... inside the loop allocates new memory block, so, you have 4 allocations inside the loop and only 1 deallocation.
Second, I can't understand why don't you simply use objects on stack? Do you really need to allocate newPixel, oldPixel and so on on the heap? Review the implementation, there might be much simpler way to implement the same also without managing the memory issues at all.
You need to move the deallocation of oldPixel_p to outside the if blocks, because it is "consumed" always.
Also, the final free only frees the first element in the list. The list may have more than one element. You need to step through the list and free all remaining elements.

Triggering UI code from Audio Unit Render Proc on iOS

I have a Multichannel Mixer audio unit playing back audio files in an iOS app, and I need to figure out how to update the app's UI and perform a reset when the render callback hits the end of the longest audio file (which is set up to run on bus 0). As my code below shows I am trying to use KVO to achieve this (using the boolean variable tapesUnderway - the AutoreleasePool is necessary as this Objective-C code is running outside of its normal domain, see http://www.cocoabuilder.com/archive/cocoa/57412-nscfnumber-no-pool-in-place-just-leaking.html).
static OSStatus tapesRenderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData)
{
SoundBufferPtr sndbuf = (SoundBufferPtr)inRefCon;
UInt32 bufferFrames = sndbuf[inBusNumber].numFrames;
AudioUnitSampleType *in = sndbuf[inBusNumber].data;
// These mBuffers are the output buffers and are empty; these two lines are just setting the references to them (via outA and outB)
AudioUnitSampleType *outA = (AudioUnitSampleType *)ioData->mBuffers[0].mData;
AudioUnitSampleType *outB = (AudioUnitSampleType *)ioData->mBuffers[1].mData;
UInt32 sample = sndbuf[inBusNumber].sampleNum;
// --------------------------------------------------------------
// Set the start time here
if(inBusNumber == 0 && !tapesFirstRenderPast)
{
printf("Tapes first render past\n");
tapesStartSample = inTimeStamp->mSampleTime;
tapesFirstRenderPast = YES; // MAKE SURE TO RESET THIS ON SONG RESTART
firstPauseSample = tapesStartSample;
}
// --------------------------------------------------------------
// Now process the samples
for(UInt32 i = 0; i < inNumberFrames; ++i)
{
if(inBusNumber == 0)
{
// ------------------------------------------------------
// Bus 0 is the backing track, and is always playing back
outA[i] = in[sample++];
outB[i] = in[sample++]; // For stereo set desc.SetAUCanonical to (2, true) and increment samples in both output calls
lastSample = inTimeStamp->mSampleTime + (Float64)i; // Set the last played sample in order to compensate for pauses
// ------------------------------------------------------
// Use this logic to mark end of tune
if(sample >= (bufferFrames * 2) && !tapesEndPast)
{
// USE KVO TO NOTIFY METHOD OF VALUE CHANGE
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
FuturesEPMedia *futuresMedia = [FuturesEPMedia sharedFuturesEPMedia];
NSNumber *boolNo = [[NSNumber alloc] initWithBool: NO];
[futuresMedia setValue: boolNo forKey: #"tapesUnderway"];
[boolNo release];
[pool release];
tapesEndPast = YES;
}
}
else
{
// ------------------------------------------------------
// The other buses are the open sections, and are synched through the tapesSectionsTimes array
Float64 sectionTime = tapesSectionTimes[inBusNumber] * kGraphSampleRate; // Section time in samples
Float64 currentSample = inTimeStamp->mSampleTime + (Float64)i;
if(!isPaused && !playFirstRenderPast)
{
pauseGap += currentSample - firstPauseSample;
playFirstRenderPast = YES;
pauseFirstRenderPast = NO;
}
if(currentSample > (tapesStartSample + sectionTime + pauseGap) && sample < (bufferFrames * 2))
{
outA[i] = in[sample++];
outB[i] = in[sample++];
}
else
{
outA[i] = 0;
outB[i] = 0;
}
}
}
sndbuf[inBusNumber].sampleNum = sample;
return noErr;
}
At the moment when this variable is changed it triggers a method in self, but this leads to an unacceptable delay (20-30 seconds) when executed from this render callback (I am thinking because it is Objective-C code running in the high priority audio thread?). How do I effectively trigger such a change without the delay? (The trigger will change a pause button to a play button and call a reset method to prepare for the next play.)
Thanks
Yes. Don't use objc code in the render thread since its high priority. If you store state in memory (ptr or struct) and then get a timer in the main thread to poll (check) the value(s) in memory. The timer need not be anywhere near as fast as the render thread and will be very accurate.
Try this.
Global :
BOOL FlgTotalSampleTimeCollected = False;
Float64 HigestSampleTime = 0 ;
Float64 TotalSampleTime = 0;
in -(OSStatus) setUpAUFilePlayer:
AudioStreamBasicDescription fileASBD;
// get the audio data format from the file
UInt32 propSize = sizeof(fileASBD);
CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyDataFormat,
&propSize, &fileASBD),
"couldn't get file's data format");
UInt64 nPackets;
UInt32 propsize = sizeof(nPackets);
CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyAudioDataPacketCount,
&propsize, &nPackets),
"AudioFileGetProperty[kAudioFilePropertyAudioDataPacketCount] failed");
Float64 sTime = nPackets * fileASBD.mFramesPerPacket;
if (HigestSampleTime < sTime)
{
HigestSampleTime = sTime;
}
In RenderCallBack :
if (*actionFlags & kAudioUnitRenderAction_PreRender)
{
if (!THIS->FlgTotalSampleTimeCollected)
{
[THIS setFlgTotalSampleTimeCollected:TRUE];
[THIS setTotalSampleTime:(inTimeStamp->mSampleTime + THIS->HigestSampleTime)];
}
}
else if (*actionFlags & kAudioUnitRenderAction_PostRender)
{
if (inTimeStamp->mSampleTime > THIS->TotalSampleTime)
{
NSLog(#"inTimeStamp->mSampleTime :%f",inTimeStamp->mSampleTime);
NSLog(#"audio completed");
[THIS callAudioCompletedMethodHere];
}
}
This worked for me.
Test in Device.