Related
I have a code that works on Maple Mini but I have to change hardware to Nucleo F030r8 because it has more ADC's and it totally sucks.
In the modbus_update() function there is a check of the size of inputBuffer and the following code should run only if the value of this variable is bigger than 0.
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
...
}
But it runs even if value of inputBuffer is exactly 0. The strange thing is that this code (with different serial ports opening method) runs perfectly on Maple Mini. Does anyone have any idea what can be be the problem?
Here is the whole code:
#define BAUDRATE 19200
#define RE_PIN PC12
#define TE_PIN PF4
#define LED_PIN LED_BUILTIN
#define SLAVE_ID 1
#define BUFFER_SIZE 256 // max frame size
#define READ_INTERNAL_REGISTERS 4 // function code
#define MIN_REGISTER_ADDRESS 30001
#define MAX_REGISTER_ADDRESS 30020
#define MAX_SENSORS_PER_ROW 10
#define SENSORS_PER_ROW 7
#define MAX_ROWS 2
#define ROWS 1
#define DEBUG true
#define INVALID_VALUE 0x7FFF
const byte INPUTS[] = {PA0, PA1, PA4, PB0, PC1, PC0};
unsigned char frame[BUFFER_SIZE];
unsigned char functionCode;
unsigned int T1;
unsigned int T1_5; // inter character time out
unsigned int T3_5; // frame delay
unsigned long millisFlag = 0;
unsigned long microsFlag = 0;
unsigned char inputBuffer = 0;
int dlyCounter = 0;
int16_t sensorVals[MAX_SENSORS_PER_ROW * MAX_ROWS];
/*
HardwareSerial *modbus = &Serial;
HardwareSerial Serial1(PA10, PA9);
HardwareSerial *debug = &Serial1;
*/
HardwareSerial debug(PA10, PA9);
void setup() {
pinMode(LED_PIN, OUTPUT);
for (int i = 0; i < SENSORS_PER_ROW; i++) {
pinMode(INPUTS[i], INPUT_PULLUP);
}
debug.begin(BAUDRATE, SERIAL_8E1);
modbus_configure(BAUDRATE, 0); // baud rate, low latency
microsFlag = micros();
}
void loop() {
readSensorVals(100);
modbus_update();
}
unsigned int modbus_update() {
unsigned char overflow = 0;
while (Serial.available()) {
if (overflow) {
Serial.read(); // empty the input buffer
} else {
if (inputBuffer == BUFFER_SIZE) {
overflow = 1;
} else {
frame[inputBuffer] = Serial.read();
inputBuffer++;
}
}
microsFlag = micros();
}
// If an overflow occurred return to the main sketch
// without responding to the request i.e. force a timeout
if (overflow) {
debug.println("Error: input buffer overflow");
return 0;
}
// if inter frame delay occurred, check the incoming package
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
debug.println("\nIncoming frame:");
for (int i = 0; i < inputBuffer; i++) {
debug.print(frame[i], HEX);
debug.print(" ");
}
debug.println();
// check CRC
unsigned int crc = ((frame[inputBuffer - 2] << 8) | frame[inputBuffer - 1]); // combine the crc Low & High bytes
if (calculateCRC(frame, inputBuffer - 2) != crc) {
debug.println("Error: checksum failed");
inputBuffer = 0;
return 0;
}
debug.println("CRC OK");
// check ID
unsigned char id = frame[0];
if (id > 242) {
debug.println("Error: Invalid ID");
inputBuffer = 0;
return 0;
}
// check if it's a broadcast message
if (id == 0) {
debug.println("Broadcast message");
inputBuffer = 0;
return 0;
}
if (id != SLAVE_ID) {
debug.println("Not my ID");
inputBuffer = 0;
return 0;
}
debug.println("ID OK");
// check function code
functionCode = frame[1];
if (functionCode != READ_INTERNAL_REGISTERS) {
debug.println("Exception: illegal function");
exceptionResponse(1);
inputBuffer = 0;
return 0;
}
debug.println("Function code OK");
// check frame size (function 4 frame MUST be 8 bytes long)
if (inputBuffer != 8) {
// some workaround here:
//if (inputBuffer != 8 || !(inputBuffer == 9 && frame[inputBuffer] == 0)) {
debug.println("Error: inaccurate frame length");
inputBuffer = 0;
return 0;
}
debug.println("Frame size OK");
// check data address range
unsigned int noOfRegisters = ((frame[4] << 8) | frame[5]); // combine the number of register bytes
if (noOfRegisters > 125) {
debug.println("Exception: illegal data address");
exceptionResponse(2);
inputBuffer = 0;
return 0;
}
unsigned int firstRegAddress = ((frame[2] << 8) | frame[3]); // combine the starting address bytes
debug.print("First address: ");
debug.println(firstRegAddress);
unsigned int lastRegAddress = firstRegAddress + noOfRegisters - 1;
debug.print("Last address: ");
debug.println(lastRegAddress);
unsigned char noOfBytes = noOfRegisters * 2;
unsigned char responseFrameSize = 5 + noOfBytes; // ID, functionCode, noOfBytes, (dataLo + dataHi) * number of registers, crcLo, crcHi
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = 0x04;
responseFrame[2] = noOfBytes;
unsigned char address = 3; // PDU starts at the 4th byte
for (int index = (int)(firstRegAddress - MIN_REGISTER_ADDRESS); index <= (int)(lastRegAddress - MIN_REGISTER_ADDRESS); index++) {
int16_t temp = (index >= 0 && index < MAX_ROWS * MAX_SENSORS_PER_ROW) ? sensorVals[index] : INVALID_VALUE;
responseFrame[address] = temp >> 8; // split the register into 2 bytes
address++;
responseFrame[address] = temp & 0xFF;
address++;
}
unsigned int crc16 = calculateCRC(responseFrame, responseFrameSize - 2);
responseFrame[responseFrameSize - 2] = crc16 >> 8; // split crc into 2 bytes
responseFrame[responseFrameSize - 1] = crc16 & 0xFF;
debug.println("Frame to send:");
for (int i = 0; i < responseFrameSize; i++) {
debug.print(responseFrame[i], HEX);
debug.print(" ");
}
debug.println();
sendPacket(responseFrame, responseFrameSize);
inputBuffer = 0;
while (Serial.available()) { // empty input buffer
Serial.read();
}
}
}
void modbus_configure(long baud, unsigned char _lowLatency) {
Serial.begin(baud, SERIAL_8E1);
pinMode(TE_PIN, OUTPUT);
pinMode(RE_PIN, OUTPUT);
rxEnable(); // pin 0 & pin 1 are reserved for RX/TX. To disable set TE and RE pin < 2
if (baud == 1000000 && _lowLatency) {
T1 = 1;
T1_5 = 1;
T3_5 = 10;
} else if (baud >= 115200 && _lowLatency) {
T1 = 50;
T1_5 = 75;
T3_5 = 175;
} else if (baud > 19200) {
T1 = 500;
T1_5 = 750;
T3_5 = 1750;
} else {
T1 = 10000000 / baud;
T1_5 = 15000000 / baud; // 1T * 1.5 = T1.5
T3_5 = 35000000 / baud; // 1T * 3.5 = T3.5
}
}
void exceptionResponse(unsigned char exception) {
unsigned char responseFrameSize = 5;
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = (functionCode | 0x80); // set the MSB bit high, informs the master of an exception
responseFrame[2] = exception;
unsigned int crc16 = calculateCRC(responseFrame, 3); // ID, functionCode + 0x80, exception code == 3 bytes
responseFrame[3] = crc16 >> 8;
responseFrame[4] = crc16 & 0xFF;
sendPacket(responseFrame, responseFrameSize); // exception response is always 5 bytes (ID, functionCode + 0x80, exception code, 2 bytes crc)
}
unsigned int calculateCRC(unsigned char f[], byte bufferSize) {
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < bufferSize; i++) {
temp = temp ^ f[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag)
temp ^= 0xA001;
}
}
// Reverse byte order.
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
return temp; // the returned value is already swapped - crcLo byte is first & crcHi byte is last
}
void rxEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, LOW);
digitalWrite(RE_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
}
void txEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, HIGH);
digitalWrite(RE_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
}
}
void sendPacket(unsigned char f[], unsigned char bufferSize) {
txEnable();
delayMicroseconds(T3_5);
for (unsigned char i = 0; i < bufferSize; i++) {
Serial.write(f[i]);
}
Serial.flush();
delayMicroseconds(T3_5); // allow frame delay to indicate end of transmission
rxEnable();
}
// #param dly delay between sensor readings in milliseconds
void readSensorVals(int dly) {
if (millis() != millisFlag) {
dlyCounter++;
millisFlag = millis();
}
if (dlyCounter >= dly) { // read sensor values
for (int i = 0; i < MAX_ROWS; i++) {
for (int j = 0; j < MAX_SENSORS_PER_ROW; j++) {
int actualIndex = i * MAX_SENSORS_PER_ROW + j;
if (i < ROWS && j < SENSORS_PER_ROW) {
sensorVals[actualIndex] = random(20, 30);
//sensorVals[actualIndex] = (4096 - analogRead(INPUTS[j])) / 20 - 133;
} else {
sensorVals[actualIndex] = INVALID_VALUE;
}
}
}
dlyCounter = 0;
}
}
I wonder: What is the intented way to read jp2 tile by tile, and to store data in buffer objects?
Right now i do something like that.
/* note I already created stream and configured decoder and resolution factor is set to 0 */
opj_codestream_index_t *pJP2CodeStreamIndex = opj_get_cstr_index(pJP2Codec);
opj_codestream_info_v2_t *pJP2CodeStreamInfo = opj_get_cstr_info(pJP2Codec);
CDrawRect myRect
GetDrawRect(&myRect);
int start_x = myRect.left;
int start_y = myRect.top;
int end_x = myRect.right;
int end_y = myRect.bottom;
int StartXTile = start_x / pJP2CodeStreamInfo->tdx;
int StartYTile = start_y / pJP2CodeStreamInfo->tdy;
int EndXTile = ceil((float)end_x / (float)pJP2CodeStreamInfo->tdx);
int EndYTile = ceil((float)end_y / (float)pJP2CodeStreamInfo->tdy);
std::vector<int> TilesToDecode;
for(int i = StartXTile; i < EndXTile; i++)
for(int j = StartYTile; j < EndYTile; j++)
{
int TileNo = i+ j*pJP2CodeStreamInfo->tw;
TilesToDecode.push_back(TileNo);
}
for(std::vector<int>::iter Iter = TilesToDecode.begin(); Iter != TilesToDecode.end(); Iter++)
{
opj_get_decoded_tile(pJP2Codec, pJP2Stream, pJP2Image, (OPJ_UINT32)TileNo);
}
/* some time later, i got read buffer for one component */
while (pDst != pEndDst)
{
OPJ_UINT32* pSrc = pJP2Image.comps[NumComp].data;
*pDst = (int)*pSrc;
pDst += stepDst;
pSrc += stepSrc;
}
But how it was intended?
Well, in fact it was quite simple. U just need to be careful with pointer mathematics and buffers' sizes.
/code is writen in C++ with MFC and WINAPI support/
First you need to start decode:
opj_stream_t* pJP2Stream = NULL;
opj_codec_t* pJP2Codec = NULL;
opj_image_t* pJP2Image = NULL;
opj_dparameters_t jp2dParams;
pJP2Stream = opj_stream_create_default_file_stream(LPCTSTR2PCHAR(Filename), OPJ_TRUE);
if(!pJP2Stream)
{
pFileInfo->ErrorCode = ERR_OPEN;
return FALSE;
}
strExt = PathFindExtension(Filename);
if(!strExt.CompareNoCase(_T(".JP2")))
pJP2Codec = opj_create_decompress(OPJ_CODEC_JP2);
if(!strExt.CompareNoCase(_T(".J2K")))
pJP2Codec = opj_create_decompress(OPJ_CODEC_J2K);
if(!strExt.CompareNoCase(_T(".JPP")))
pJP2Codec = opj_create_decompress(OPJ_CODEC_JPP);
if(!strExt.CompareNoCase(_T(".JPT")))
pJP2Codec = opj_create_decompress(OPJ_CODEC_JPT);
if(!strExt.CompareNoCase(_T(".JPX")))
pJP2Codec = opj_create_decompress(OPJ_CODEC_JPX);
if(!pJP2Codec)
{
opj_stream_destroy(pJP2Stream);
opj_destroy_codec(pJP2Codec);
return FALSE;
}
//register callbacks
opj_set_info_handler(pJP2Codec, info_callback,00);
opj_set_warning_handler(pJP2Codec, warning_callback,00);
opj_set_error_handler(pJP2Codec, error_callback,00);
opj_set_default_decoder_parameters(&jp2dParams);
if ( !opj_setup_decoder(pJP2Codec, &jp2dParams) )
{
//(stderr, "ERROR -> opj_compress: failed to setup the decoder\n");
opj_stream_destroy(pJP2Stream);
opj_destroy_codec(pJP2Codec);
return FALSE;
}
if( !opj_read_header(pJP2Stream, pJP2Codec, &pJP2Image) || (pJP2Image->numcomps == 0))
{
opj_stream_destroy(pJP2Stream);
opj_destroy_codec(pJP2Codec);
if (pJP2Image)
opj_image_destroy(pJP2Image);
return FALSE;
}
Second you should read CodestreamInfo:
opj_codestream_info_v2_t *pJP2CodeStreamInfo = opj_get_cstr_info(pJP2Codec);
be careful if u have several threads calling this function you might get a memory leak. So i suggest next code to transfer information into stack mem:
opj_codestream_info_v2_t JP2CodeStreamInfo;
opj_codestream_info_v2_t *pJP2CodeStreamInfo = NULL;
pJP2CodeStreamInfo = opj_get_cstr_info(pJP2Codec);
if(pJP2CodeStreamInfo)
{
JP2CodeStreamInfo = *pJP2CodeStreamInfo;
opj_destroy_cstr_info(&pJP2CodeStreamInfo);
}
else
return FALSE;
Codestream Info changes when you alter decode resolution factor:
opj_set_decoded_resolution_factor(pJP2Codec, nResFactor);
Resolution factor - makes decoded images smaller in 2^nResFactor ratio, loading only first of 2^n rows and columls.
I offer next code as universal solution to copy of any tile to any image block.
long posSrcOffsetX = (start_x > JP2Image.comps[NumBand].x0 ? (start_x - JP2Image.comps[NumBand].x0) : 0) >> JP2Image.comps[NumBand].factor >> (iDifRes);
long posSrcOffsetY = (start_y > JP2Image.comps[NumBand].y0 ? (start_y - JP2Image.comps[NumBand].y0) : 0) >> JP2Image.comps[NumBand].factor >> (iDifRes);
long posDstOffsetX = ((JP2Image.comps[NumBand].x0 > start_x? JP2Image.comps[NumBand].x0 - start_x : 0) >> JP2Image.comps[NumBand].factor >> (iDifRes)) ;
long posDstOffsetY = ((JP2Image.comps[NumBand].y0 > start_y? JP2Image.comps[NumBand].y0 - start_y : 0) >> JP2Image.comps[NumBand].factor >> (iDifRes)) ;
long posSrcEndX = (bInnerBlock ? ((JP2Image.comps[NumBand].x0 >> JP2Image.comps[NumBand].factor) + (end_x >> JP2Image.comps[NumBand].factor)) : JP2Image.comps[NumBand].w) >>(iDifRes) ;
long posSrcEndY = (bInnerBlock ? ((JP2Image.comps[NumBand].y0 >> JP2Image.comps[NumBand].factor) + (end_y >> JP2Image.comps[NumBand].factor)) : JP2Image.comps[NumBand].h) >>(iDifRes) ;
long TileEndX = JP2Image.comps[NumBand].x0 + (JP2Image.comps[NumBand].w << JP2Image.comps[NumBand].factor);
long TileEndY = JP2Image.comps[NumBand].y0 + (JP2Image.comps[NumBand].h << JP2Image.comps[NumBand].factor);
long posDstEndX = (TileEndX > end_x ? end_x - start_x : TileEndX - start_x) >> JP2Image.comps[NumBand].factor >> (iDifRes) ;
long posDstEndY = (TileEndY > end_y ? end_y - start_y : TileEndY - start_y) >> JP2Image.comps[NumBand].factor >> (iDifRes) ;
long stepSrcX = 1 << (iDifRes);
long stepSrcY = JP2Image.comps[NumBand].w << (iDifRes);
long stepDstX = 1;
long stepDstY = 64;
DWORD boundX = posDstEndX - posDstOffsetX;
DWORD boundY = posDstEndY - posDstOffsetY;
for(i = 0 ; i < boundY ; i++ )
{
pSrc = JP2Image.comps[NumBand].data + (posSrcOffsetX)*stepSrcX + ((posSrcOffsetY+i) * stepSrcY);
pDst = pDstLine + (posDstOffsetX + ((posDstOffsetY+i) * stepDstY))*PixelSize;
for ( j = 0; j < boundX ; j++ )
{
iValue = *(pSrc + j* stepSrcX);
iValue += JP2Image.comps[NumBand].sgnd ? (1 << (JP2Image.comps[NumBand].prec - 1)) : 0;
if (iValue > dMax)
iValue = (int)dMax;
else
if (iValue < dMin)
iValue = (int)dMin;
UCHAR bufVal = (UCHAR)iValue;
*(UCHAR*)pDst = (UCHAR)iValue;
pDst += stepDstX*PixelSize;
}
}
Just be sure to check bits per pixel and to have a for clause for all image components.
Below screen shot is the result of the execution of the function in MATLAB.
a=imread('C:\CVIPtools\images\car.bmp');
ad=im2double(a);
ht = halftoneCVIP(ad,4,255, 0.5, 0, 0);
Halftoning: it's a methods for reducing the number of gray levels by creating dot patterns or dither patterns to represent various gray levels, reduces effective spatial resolution also.
There are 6 methods in halftoning.
1. Floyd Stienberg
2. Dither
3. Threshold
4. Cluster 3
5. Cluster 4
6. Cluster 8
*Image *CVIPhalftone(Image cvip_Image, int halftone, int
maxval, float fthreshval, CVIP_BOOLEAN retain_image,
CVIP_BOOLEAN verbose)
<cvip_Image> - pointer to input image
<halftone> - indicates method used to convert from grays-
cale to binary. (one of QT_FS, QT_THRESH, QT_DITHER8,
QT_CLUSTER3, QT_CLUSTER4, QT_CLUSTER8)
<maxval> - specifies maximum range of input image (usually
255)
<fthreshval> - threshold value (for QT_THRESH) between [0.0
... 1.0].
<retain_image> - retain image after writing (CVIP_YES or
CVIP_NO)?
<verbose> - shall I be verbose (CVIP_YES or CVIP_NO)?**
I am trying to reuse a halftone function origianlly written in C. My objective is to make this function executable in MATLAB by writing a wrapper function using MEX.
Below are the code I have written and I am able to compile successfully without any errors. However, while executing the function MATLAB crashes. Does anyone know the reason behind this?
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include "mex.h"
#include "CVIPtools.h"
#include "CVIPimage.h"
#include "CVIPdef.h"
#include "CVIPmap.h"
#include "limits.h"
#include "threshold.h"
#include <float.h>
#include "CVIPmatrix.h"
#include "dithers.h"
#include "CVIPhalftone.h"
#define CVIP_WHITE 1
#define CVIP_BLACK 0
#define FS_SCALE 1024
#define HALF_FS_SCALE 512
Image *CVIPhalftone(Image *cvip_Image, int halftone, int maxval, float fthreshval, CVIP_BOOLEAN retain_image, CVIP_BOOLEAN verbose)
{
byte* grayrow;
register byte* gP;
byte* bitrow;
register byte* bP;
int rows, cols, row;
int col, limitcol, format;
char function_name[] = {"CVIPhalftone"};
long threshval, sum;
long* thiserr;
long* nexterr;
long* temperr;
int fs_direction;
Image *bit_Image;
cols = cvip_Image->image_ptr[0]->cols;
rows = cvip_Image->image_ptr[0]->rows;
bit_Image = (Image *) image_allocate(cvip_Image->image_format, BINARY, 1, rows, cols, CVIP_BYTE, REAL);
format = cvip_Image->image_format;
if( !(format==PBM || format==PGM || format==TIF || format==RAS || format==BIN || format==ITX) ) {
if(verbose)
fprintf(stderr, "\n%s: casting image to format that supports binary images - (PBM).\n",function_name);
bit_Image->image_format = PBM;
}
mexPrintf("Till here 1\n");
/* Initialize. */
switch ( halftone )
{
case QT_FS: // QT_FS=1 defined in CVIPhalftone.h
if(verbose)
fprintf(stderr, "%s: performing boustrophedonic Floyd-Steinberg error diffusion.\n\n",function_name);
/* Initialize Floyd-Steinberg error vectors. */
thiserr = (long*) calloc( cols + 2, sizeof(long) );
nexterr = (long*) calloc( cols + 2, sizeof(long) );
srand( (int) ( time( 0 ) ^ getpid( ) ) );
for ( col = 0; col < cols + 2; ++col )
thiserr[col] = ( rand( ) % FS_SCALE - HALF_FS_SCALE ) / 4;
/* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
fs_direction = 1;
threshval = fthreshval * FS_SCALE;
break;
case QT_THRESH: // QT_THRESH=2 defined in CVIPhalftone.h
threshval = fthreshval * maxval + 0.999999;
if(verbose) {
fprintf(stderr, "%s: performing simple thresholding operation.\n",function_name);
fprintf(stderr, "%s: threshold level - %ld.\n\n",function_name, threshval);
}
break;
case QT_DITHER8: // QT_DITHER8=3 defined in CVIPhalftone.h
break;
case QT_CLUSTER3: // QT_CLUSTER3=4 defined in CVIPhalftone.h
break;
case QT_CLUSTER4: // QT_CLUSTER4=5 defined in CVIPhalftone.h
break;
case QT_CLUSTER8: // QT_CLUSTER8=6 defined in CVIPhalftone.h
break;
default:
fprintf(stderr, "%s: can't happen... but apparently something did?!?\n" , function_name); break;
}
mexPrintf("Till here 2\n");
for ( row = 0; row < rows; ++row )
{
grayrow = (byte *) ((byte **) cvip_Image->image_ptr[0]->rptr)[row];
bitrow = (byte *) ((byte **) bit_Image->image_ptr[0]->rptr)[row];
switch ( halftone )
{
case QT_FS:
for ( col = 0; col < cols + 2; ++col )
nexterr[col] = 0;
if ( fs_direction )
{
col = 0;
limitcol = cols;
gP = grayrow;
bP = bitrow;
}
else
{
col = cols - 1;
limitcol = -1;
gP = &(grayrow[col]);
bP = &(bitrow[col]);
}
do
{
sum = ( (long) *gP * FS_SCALE ) / maxval + thiserr[col + 1];
if ( sum >= threshval )
{
*bP = CVIP_WHITE;
sum = sum - threshval - HALF_FS_SCALE;
}
else
*bP = CVIP_BLACK;
if ( fs_direction )
{
thiserr[col + 2] += ( sum * 7 ) / 16;
nexterr[col ] += ( sum * 3 ) / 16;
nexterr[col + 1] += ( sum * 5 ) / 16;
nexterr[col + 2] += ( sum ) / 16;
++col;
++gP;
++bP;
}
else
{
thiserr[col ] += ( sum * 7 ) / 16;
nexterr[col + 2] += ( sum * 3 ) / 16;
nexterr[col + 1] += ( sum * 5 ) / 16;
nexterr[col ] += ( sum ) / 16;
--col;
--gP;
--bP;
}
}
while ( col != limitcol );
temperr = thiserr;
thiserr = nexterr;
nexterr = temperr;
fs_direction = ! fs_direction;
break;
case QT_THRESH:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= threshval )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_DITHER8:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= dither8[row % 16][col % 16] * ( maxval + 1 ) / 256 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER3:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster3[row %6][col %6 ] * ( maxval + 1 ) / 18 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER4:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster4[row %8][col%8] * ( maxval + 1 ) / 32 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
case QT_CLUSTER8:
for ( col = 0, gP = grayrow, bP = bitrow; col < cols; ++col, ++gP, ++bP )
if ( *gP >= cluster8[row %16][col %16] * ( maxval + 1 ) / 128 )
*bP = CVIP_WHITE;
else
*bP = CVIP_BLACK;
break;
default:
fprintf(stderr, "%s: can't happen... but apparently something did?!?\n" , function_name); break;
}
}
mexPrintf("Till here 1\n");
if(!retain_image)
image_free(cvip_Image);
return bit_Image;
mexPrintf("Till here 2\n");
}
void midd( int choice, double *indata, double *outdata, int n, int row, int col, int bands)
{
Image *inputImage;
byte **image;
unsigned int r, c;
int i;
unsigned int no_of_rows,
no_of_cols,
no_of_bands;
COLOR_FORMAT color_space;
int check=0;
no_of_bands = bands;
no_of_rows = row;
no_of_cols = col;
for (i=0;i<n;i++)
{ if (check<indata[i])
check=indata[i];
}
if (check<=1){
for (i=0;i<n;i++){
//outdata[i]= floor(255*indata[i]); //By Krishna Regmi
indata[i]= floor(255*indata[i]);
}}
else
{for (i=0;i<n;i++)
//outdata[i]= floor(indata[i]); //By Krishna Regmi
indata[i]= floor(indata[i]);
}
// mexPrintf("\ first value after scaling to 0-255 %f\n", outdata[0]);
// typedef enum {PBM, PGM, PPM, EPS, TIF, GIF, RAS, ITX, IRIS, CCC, BIN, VIP, GLR, BTC, BRC, HUF, ZVL, ARITH, BTC2, BTC3, DPC, ZON, ZON2, SAFVR, JPG, WVQ, FRA, VQ, XVQ} IMAGE_FORMAT;
//typedef enum {BINARY, GRAY_SCALE, RGB, HSL, HSV, SCT, CCT, LUV, LAB, XYZ}
inputImage=new_Image (BMP, RGB, no_of_bands, row, col, CVIP_BYTE, REAL );
for(bands=0; bands < no_of_bands; bands++) {
image = getData_Image(inputImage, bands);
for(r=0; r < no_of_rows; r++) {
for(c=0; c < no_of_cols; c++)
{
image[r][c]=outdata[r+row*c+row*col*bands]; /* passing data from MATLAB variable to CVIPtools variable */
}
}
}
//Image *CVIPhalftone(Image *cvip_Image, int halftone, int maxval, float fthreshval, CVIP_BOOLEAN retain_image, CVIP_BOOLEAN verbose)
//inputImage= CVIPhalftone(cvipImage,QT_THRESH,255,0.5,CVIP_NO,CVIP_NO);
inputImage = CVIPhalftone(inputImage, choice, 255, 0.5, CVIP_NO, CVIP_NO);
for(bands=0; bands < no_of_bands; bands++) {
image = getData_Image(inputImage, bands);
for(r=0; r < no_of_rows; r++) {
for(c=0; c < no_of_cols; c++)
{
outdata[r+row*c+row*col*bands] = floor(image[r][c]); /* passing data back to MATLAB variable from CVIPtools variable */
}
}
}
} /* end of wrapper function*/
/* main gateway function*/
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
double *outdata, *indata;
int r,c,bands;
const mwSize *dim_array;
int choice,n;
//char color_type;
// COLOR_FORMAT color_space;
//int choice;
//int n = mxGetNumberOfElements(prhs[0]);
n = mxGetNumberOfElements(prhs[0]);
indata = mxGetData(prhs[0]);
//double *indata = (double *)mxGetData(prhs[0]);
dim_array = mxGetDimensions(prhs[0]);
//color_type = mxGetChars(prhs[1]);
choice = mxGetScalar(prhs[1]);
r = dim_array[0];
c = dim_array[1];
bands = dim_array[2];
// mexPrintf("total elements %d\n", n);
if(bands==3){
plhs[0] = mxCreateNumericArray(3, dim_array, mxDOUBLE_CLASS, mxREAL);
}
else
{ plhs[0] = mxCreateDoubleMatrix(r,c,mxREAL);
bands=1;
}
outdata = mxGetData(plhs[0]);
midd(choice, indata, outdata, n, r, c, bands);
}
Sounds like a segmentation fault in your mex code. Check the input datatypes. Make sure that the data type of the parameters passed from matlab match those that are expected by the C function. Also, keep in mind that matlab arrays are column-major, and the sizes are [rows, cols], not [width height].
If you can't spot the problem easily, then you would need to attach a debugger to the matlab process, or add a lot of mexPrintf's into your code to see where exactly it fails.
I need to place numbers within a grid such that it doesn't collide with each other. This number placement should be random and can be horizontal or vertical. The numbers basically indicate the locations of the ships. So the points for the ships should be together and need to be random and should not collide.
I have tried it:
int main()
{
srand(time(NULL));
int Grid[64];
int battleShips;
bool battleShipFilled;
for(int i = 0; i < 64; i++)
Grid[i]=0;
for(int i = 1; i <= 5; i++)
{
battleShips = 1;
while(battleShips != 5)
{
int horizontal = rand()%2;
if(horizontal == 0)
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != j)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row+k)*8+(column)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row+k)*8+(column)] = 1;
battleShipFilled = true;
}
battleShips++;
}
else
{
battleShipFilled = false;
while(!battleShipFilled)
{
int row = rand()%8;
int column = rand()%8;
while(Grid[(row)*8+(column)] == 1)
{
row = rand()%8;
column = rand()%8;
}
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
for(int k = -j/2; k <= j/2; k++)
Grid[(row)*8+(column+k)] = 1;
battleShipFilled = true;
}
battleShips++;
}
}
}
}
But the code i have written is not able to generate the numbers randomly in the 8x8 grid.
Need some guidance on how to solve this. If there is any better way of doing it, please tell me...
How it should look:
What My code is doing:
Basically, I am placing 5 ships, each of different size on a grid. For each, I check whether I want to place it horizontally or vertically randomly. After that, I check whether the surrounding is filled up or not. If not, I place them there. Or I repeat the process.
Important Point: I need to use just while, for loops..
You are much better of using recursion for that problem. This will give your algorithm unwind possibility. What I mean is that you can deploy each ship and place next part at random end of the ship, then check the new placed ship part has adjacent tiles empty and progress to the next one. if it happens that its touches another ship it will due to recursive nature it will remove the placed tile and try on the other end. If the position of the ship is not valid it should place the ship in different place and start over.
I have used this solution in a word search game, where the board had to be populated with words to look for. Worked perfect.
This is a code from my word search game:
bool generate ( std::string word, BuzzLevel &level, CCPoint position, std::vector<CCPoint> &placed, CCSize lSize )
{
std::string cPiece;
if ( word.size() == 0 ) return true;
if ( !level.inBounds ( position ) ) return false;
cPiece += level.getPiece(position)->getLetter();
int l = cPiece.size();
if ( (cPiece != " ") && (word[0] != cPiece[0]) ) return false;
if ( pointInVec (position, placed) ) return false;
if ( position.x >= lSize.width || position.y >= lSize.height || position.x < 0 || position.y < 0 ) return false;
placed.push_back(position);
bool used[6];
for ( int t = 0; t < 6; t++ ) used[t] = false;
int adj;
while ( (adj = HexCoord::getRandomAdjacentUnique(used)) != -1 )
{
CCPoint nextPosition = HexCoord::getAdjacentGridPositionInDirection((eDirection) adj, position);
if ( generate ( word.substr(1, word.size()), level, nextPosition, placed, lSize ) ) return true;
}
placed.pop_back();
return false;
}
CCPoint getRandPoint ( CCSize size )
{
return CCPoint ( rand() % (int)size.width, rand() % (int)size.height);
}
void generateWholeLevel ( BuzzLevel &level,
blockInfo* info,
const CCSize &levelSize,
vector<CCLabelBMFont*> wordList
)
{
for ( vector<CCLabelBMFont*>::iterator iter = wordList.begin();
iter != wordList.end(); iter++ )
{
std::string cWord = (*iter)->getString();
// CCLog("Curront word %s", cWord.c_str() );
vector<CCPoint> wordPositions;
int iterations = 0;
while ( true )
{
iterations++;
//CCLog("iteration %i", iterations );
CCPoint cPoint = getRandPoint(levelSize);
if ( generate (cWord, level, cPoint, wordPositions, levelSize ) )
{
//Place pieces here
for ( int t = 0; t < cWord.size(); t++ )
{
level.getPiece(wordPositions[t])->addLetter(cWord[t]);
}
break;
}
if ( iterations > 1500 )
{
level.clear();
generateWholeLevel(level, info, levelSize, wordList);
return;
}
}
}
}
I might add that shaped used in the game was a honeycomb. Letter could wind in any direction, so the code above is way more complex then what you are looking for I guess, but will provide a starting point.
I will provide something more suitable when I get back home as I don't have enough time now.
I can see a potential infinite loop in your code
int j = 0;
if(i == 1) j= (i+1);
else j= i;
for(int k = -j/2; k <= j/2; k++)
{
int numberOfCorrectLocation = 0;
while(numberOfCorrectLocation != i)
{
if(row+k> 0 && row+k<8)
{
if(Grid[(row)*8+(column+k)] == 1) break;
numberOfCorrectLocation++;
}
}
if(numberOfCorrectLocation !=i) break;
}
Here, nothing prevents row from being 0, as it was assignd rand%8 earlier, and k can be assigned a negative value (since j can be positive). Once that happens nothing will end the while loop.
Also, I would recommend re-approaching this problem in a more object oriented way (or at the very least breaking up the code in main() into multiple, shorter functions). Personally I found the code a little difficult to follow.
A very quick and probably buggy example of how you could really clean your solution up and make it more flexible by using some OOP:
enum Orientation {
Horizontal,
Vertical
};
struct Ship {
Ship(unsigned l = 1, bool o = Horizontal) : length(l), orientation(o) {}
unsigned char length;
bool orientation;
};
class Grid {
public:
Grid(const unsigned w = 8, const unsigned h = 8) : _w(w), _h(h) {
grid.resize(w * h);
foreach (Ship * sp, grid) {
sp = nullptr;
}
}
bool addShip(Ship * s, unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) { // if in valid range
if (s->orientation == Horizontal) {
if ((x + s->length) <= _w) { // if not too big
int p = 0; //check if occupied
for (int c1 = 0; c1 < s->length; ++c1) if (grid[y * _w + x + p++]) return false;
p = 0; // occupy if not
for (int c1 = 0; c1 < s->length; ++c1) grid[y * _w + x + p++] = s;
return true;
} else return false;
} else {
if ((y + s->length) <= _h) {
int p = 0; // check
for (int c1 = 0; c1 < s->length; ++c1) {
if (grid[y * _w + x + p]) return false;
p += _w;
}
p = 0; // occupy
for (int c1 = 0; c1 < s->length; ++c1) {
grid[y * _w + x + p] = s;
p += _w;
}
return true;
} else return false;
}
} else return false;
}
void drawGrid() {
for (int y = 0; y < _h; ++y) {
for (int x = 0; x < _w; ++x) {
if (grid.at(y * w + x)) cout << "|S";
else cout << "|_";
}
cout << "|" << endl;
}
cout << endl;
}
void hitXY(unsigned x, unsigned y) {
if ((x <= _w) && (y <= _h)) {
if (grid[y * _w + x]) cout << "You sunk my battleship" << endl;
else cout << "Nothing..." << endl;
}
}
private:
QVector<Ship *> grid;
unsigned _w, _h;
};
The basic idea is create a grid of arbitrary size and give it the ability to "load" ships of arbitrary length at arbitrary coordinates. You need to check if the size is not too much and if the tiles aren't already occupied, that's pretty much it, the other thing is orientation - if horizontal then increment is +1, if vertical increment is + width.
This gives flexibility to use the methods to quickly populate the grid with random data:
int main() {
Grid g(20, 20);
g.drawGrid();
unsigned shipCount = 20;
while (shipCount) {
Ship * s = new Ship(qrand() % 8 + 2, qrand() %2);
if (g.addShip(s, qrand() % 20, qrand() % 20)) --shipCount;
else delete s;
}
cout << endl;
g.drawGrid();
for (int i = 0; i < 20; ++i) g.hitXY(qrand() % 20, qrand() % 20);
}
Naturally, you can extend it further, make hit ships sink and disappear from the grid, make it possible to move ships around and flip their orientation. You can even use diagonal orientation. A lot of flexibility and potential to harness by refining an OOP based solution.
Obviously, you will put some limits in production code, as currently you can create grids of 0x0 and ships of length 0. It's just a quick example anyway. I am using Qt and therefore Qt containers, but its just the same with std containers.
I tried to rewrite your program in Java, it works as required. Feel free to ask anything that is not clearly coded. I didn't rechecked it so it may have errors of its own. It can be further optimized and cleaned but as it is past midnight around here, I would rather not do that at the moment :)
public static void main(String[] args) {
Random generator = new Random();
int Grid[][] = new int[8][8];
for (int battleShips = 0; battleShips < 5; battleShips++) {
boolean isHorizontal = generator.nextInt(2) == 0 ? true : false;
boolean battleShipFilled = false;
while (!battleShipFilled) {
// Select a random row and column for trial
int row = generator.nextInt(8);
int column = generator.nextInt(8);
while (Grid[row][column] == 1) {
row = generator.nextInt(8);
column = generator.nextInt(8);
}
int lengthOfBattleship = 0;
if (battleShips == 0) // Smallest ship should be of length 2
lengthOfBattleship = (battleShips + 2);
else // Other 4 ships has the length of 2, 3, 4 & 5
lengthOfBattleship = battleShips + 1;
int numberOfCorrectLocation = 0;
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal && row + k > 0 && row + k < 8) {
if (Grid[row + k][column] == 1)
break;
} else if (!isHorizontal && column + k > 0 && column + k < 8) {
if (Grid[row][column + k] == 1)
break;
} else {
break;
}
numberOfCorrectLocation++;
}
if (numberOfCorrectLocation == lengthOfBattleship) {
for (int k = 0; k < lengthOfBattleship; k++) {
if (isHorizontal)
Grid[row + k][column] = 1;
else
Grid[row][column + k] = 1;
}
battleShipFilled = true;
}
}
}
}
Some important points.
As #Kindread said in an another answer, the code has an infinite loop condition which must be eliminated.
This algorithm will use too much resources to find a solution, it should be optimized.
Code duplications should be avoided as it will result in more maintenance cost (which might not be a problem for this specific case), and possible bugs.
Hope this answer helps...
I'm working on a program in c++ to do md5 checksums. I'm doing this mainly because I think I'll learn a lot of different things about c++, checksums, OOP, and whatever else I run into.
I'm having trouble the check sums and I think the problem is in the function padbuff which does the message padding.
#include "HashMD5.h"
int leftrotate(int x, int y);
void padbuff(uchar * buffer);
//HashMD5 constructor
HashMD5::HashMD5()
{
Type = "md5";
Hash = "";
}
HashMD5::HashMD5(const char * hashfile)
{
Type = "md5";
std::ifstream filestr;
filestr.open(hashfile, std::fstream::in | std::fstream::binary);
if(filestr.fail())
{
std::cerr << "File " << hashfile << " was not opened.\n";
std::cerr << "Open failed with error ";
}
}
std::string HashMD5::GetType()
{
return this->Type;
}
std::string HashMD5::GetHash()
{
return this->Hash;
}
bool HashMD5::is_open()
{
return !((this->filestr).fail());
}
void HashMD5::CalcHash(unsigned int * hash)
{
unsigned int *r, *k;
int r2[4] = {0, 4, 9, 15};
int r3[4] = {0, 7, 12, 19};
int r4[4] = {0, 4, 9, 15};
uchar * buffer;
int bufLength = (2<<20)*8;
int f,g,a,b,c,d, temp;
int *head;
uint32_t maxint = 1<<31;
//Initialized states
unsigned int h[4]{ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476};
r = new unsigned int[64];
k = new unsigned int[64];
buffer = new uchar[bufLength];
if(r==NULL || k==NULL || buffer==NULL)
{
std::cerr << "One of the dyn alloc failed\n";
}
// r specifies the per-round shift amounts
for(int i = 0; i<16; i++)
r[i] = 7 + (5 * ((i)%4) );
for(int i = 16; i < 32; i++)
r[i] = 5 + r2[i%4];
for(int i = 32; i< 48; i++)
r[i] = 4 + r3[i%4];
for(int i = 48; i < 63; i++)
r[i] = 6 + r4[i%4];
for(int i = 0; i < 63; i++)
{
k[i] = floor( fabs( sin(i + 1)) * maxint);
}
while(!(this->filestr).eof())
{
//Read in 512 bits
(this->filestr).read((char *)buffer, bufLength-512);
padbuff(buffer);
//The 512 bits are now 16 32-bit ints
head = (int *)buffer;
for(int i = 0; i < 64; i++)
{
if(i >=0 && i <=15)
{
f = (b & c) | (~b & d);
g = i;
}
else if(i >= 16 && i <=31)
{
f = (d & b) | (~d & b);
g = (5*i +1) % 16;
}
else if(i >=32 && i<=47)
{
f = b ^ c ^ d;
g = (3*i + 5 ) % 16;
}
else
{
f = c ^ (b | ~d);
g = (7*i) % 16;
}
temp = d;
d = c;
c = b;
b = b + leftrotate((a + f + k[i] + head[g]), r[i]);
a = temp;
}
h[0] +=a;
h[1] +=b;
h[2] +=c;
h[3] +=d;
}
delete[] r;
delete[] k;
hash = h;
}
int leftrotate(int x, int y)
{
return(x<<y) | (x >> (32 -y));
}
void padbuff(uchar* buffer)
{
int lack;
int length = strlen((char *)buffer);
uint64_t mes_size = length % UINT64_MAX;
if((lack = (112 - (length % 128) ))>0)
{
*(buffer + length) = ('\0'+1 ) << 3;
memset((buffer + length + 1),0x0,lack);
memcpy((void*)(buffer+112),(void *)&mes_size, 64);
}
}
In my test program I run this on the an empty message. Thus length in padbuff is 0. Then when I do *(buffer + length) = ('\0'+1 ) << 3;, I'm trying to pad the message with a 1. In the Netbeans debugger I cast buffer as a uint64_t and it says buffer=8. I was trying to put a 1 bit in the most significant spot of buffer so my cast should have been UINT64_MAX. Its not, so I'm confused about how my padding code works. Can someone tell me what I'm doing and what I'm supposed to do in padbuff? Thanks, and I apologize for the long freaking question.
Just to be clear about what the padding is supposed to be doing, here is the padding excerpt from Wikipedia:
The message is padded so that its length is divisible by 512. The padding works as follows: first a single bit, 1, is appended to the end of the message. This is followed by as many zeros as are required to bring the length of the message up to 64 bits fewer than a multiple of 512. The remaining bits are filled up with 64 bits representing the length of the original message, modulo 264.
I'm mainly looking for help for padbuff, but since I'm trying to learn all comments are appreciated.
The first question is what you did:
length % UINT64_MAX doesn't make sense at all because length is in bytes and MAX is the value you can store in UINT64.
You thought that putting 1 bit in the most significant bit would give the maximum value. In fact, you need to put 1 in all bits to get it.
You shift 1 by 3. It's only half the length of the byte.
The byte pointed by buffer is the least significant in little endian. (I assume you have little endian since the debugger showed 8).
The second question how it should work.
I don't know what exactly padbuff should do but if you want to pad and get UINT64_MAX, you need something like this:
int length = strlen((char *)buffer);
int len_of_padding = sizeof(uint64_t) - length % sizeof(uint64_t);
if(len_of_padding > 0)
{
memset((void*)(buffer + length), 0xFF, len_of_padding);
}
You worked with the length of two uint64 values. May be you wanted to zero the next one:
uint64_t *after = (uint64_t*)(buffer + length + len_of_padding);
*after = 0;