Converting a character array of packed decimal to integer in C program - character

I need to write a C program to convert packed decimal field in a buffer to in integer value. The precision of packed decimal is 9 and Scale is 0. What is the best way to convert this in a IBM mainframe C progrram? In Cobol the format for Packed Decimal used is Comp-3
Any help is aprreciated.

If you are running the program on a Zos mainframe then the C compiler supports packed decimal natively.
Google for "Zos C fixed point decimal type" should get you the right manual page
its a simple as :
#include <decimal.h>
decimal(9,0) mynum;

The one way I think it can be done, is
long long MyGetPackedDecimalValue(char* pdIn, int length)
{
// Convert packed decimal to long
const int PlusSign = 0x0C; // Plus sign
const int MinusSign = 0x0D; // Minus `enter code here`
const int NoSign = 0x0F; // Unsigned
const int DropHO = 0xFF; // AND mask to drop HO sign bits
const int GetLO = 0x0F; // Get only LO digit
long long val = 0; // Value to return
printf ("in side ****GetPDVal \n ");
for(int i=0; i < length; i++)
{
int aByte = pdIn[i] & DropHO; // Get next 2 digits & drop sign bits
if(i == length - 1)
{ // last digit?
int digit = aByte >> 4; // First get digit
val = val*10 + digit;
printf("digit= %d, val= %lld \n",
digit,
val);
int sign = aByte & GetLO; // now get sign
if (sign == MinusSign)
{
val = -val;
}
else
{
// Do we care if there is an invalid sign?
if(sign != PlusSign && sign != NoSign)
perror("SSN:Invalid Sign nibble in Packed Decimal\n");
}
}
else
{
int digit = aByte >> 4; // HO first
val = val*10 + digit;
printf("digit= %d, val= %lld \n",
digit,
val);
digit = aByte & GetLO; // now LO
val = val*10 + digit;
printf("digit= %d, val= %lld \n",
digit,
val);
}
}`enter code here`
printf ("**** coming out GetPDVal \n ");
return val;
}

Related

How to convert a binary number into a decimal fraction in dart?

Hi i have been wondering if there is a way in which to convert binary numbers into decimal fractions.
I know how to change base as an example through this code
String binary = "11110010";
//I'd like to change this line so it produces a decimal value
String denary = int.parse(binary, radix: 2).toRadixString(10);
If anyone still wondering how to convert decimal to binary and the inverse:
print(55.toRadixString(2)); // Outputs 110111
print(int.parse("110111", radix: 2)); Outputs 55
int binaryToDecimal(int n)
{
int num = n;
int dec_value = 0;
// Initializing base value to 1, i.e 2^0
int base = 1;
int temp = num;
while (temp) {
int last_digit = temp % 10;
temp = temp / 10;
dec_value += last_digit * base;
base = base * 2;
}
return dec_value;
}
int main()
{
int num = 10101001;
cout << binaryToDecimal(num) << endl;
}
This is my c++ solution but you can implement any language

How to calculate CheckSum in FIX manually?

I have a FixMessage and I want to calculate the checksum manually.
8=FIX.4.2|9=49|35=5|34=1|49=ARCA|52=20150916-04:14:05.306|56=TW|10=157|
The body length here is calculated:
8=FIX.4.2|9=49|35=5|34=1|49=ARCA|52=20150916-04:14:05.306|56=TW|10=157|
0 + 0 + 5 + 5 + 8 + 26 + 5 + 0 = 49(correct)
The checksum is 157 (10=157). How to calculate it in this case?
You need to sum every byte in the message up to but not including the checksum field. Then take this number modulo 256, and print it as a number of 3 characters with leading zeroes (e.g. checksum=13 would become 013).
Link from the FIX wiki: FIX checksum
An example implementation in C, taken from onixs.biz:
char *GenerateCheckSum( char *buf, long bufLen )
{
static char tmpBuf[ 4 ];
long idx;
unsigned int cks;
for( idx = 0L, cks = 0; idx < bufLen; cks += (unsigned int)buf[ idx++ ] );
sprintf( tmpBuf, "%03d", (unsigned int)( cks % 256 ) );
return( tmpBuf );
}
Ready-to-run C example adapted from here
8=FIX.4.2|9=49|35=5|34=1|49=ARCA|52=20150916-04:14:05.306|56=TW|10=157|
#include <stdio.h>
void GenerateCheckSum( char *buf, long bufLen )
{
unsigned sum = 0;
long i;
for( i = 0L; i < bufLen; i++ )
{
unsigned val = (unsigned)buf[i];
sum += val;
printf("Char: %02c Val: %3u\n", buf[i], val); // print value of each byte
}
printf("CheckSum = %03d\n", (unsigned)( sum % 256 ) ); // print result
}
int main()
{
char msg[] = "8=FIX.4.2\0019=49\00135=5\00134=1\00149=ARCA\00152=20150916-04:14:05.306\00156=TW\001";
int len = sizeof(msg) / sizeof(msg[0]);
GenerateCheckSum(msg, len);
}
Points to Note
GenerateCheckSum takes the entire FIX message except CheckSum field
Delimiter SOH is written as \001 which has ASCII value 1
static void Main(string[] args)
{
//10=157
string s = "8=FIX.4.2|9=49|35=5|34=1|49=ARCA|52=20150916-04:14:05.306|56=TW|";
byte[] bs = GetBytes(s);
int sum=0;
foreach (byte b in bs)
sum = sum + b;
int checksum = sum % 256;
}
//string to byte[]
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
Using BodyLength[9] and CheckSum[10] fields.
BodyLength is calculated starting from field starting after BodyLenght and
before CheckSum field.
CheckSum is calculated from ‘8= upto SOH before the checksum field.
Binary value of each character is calculated and compared to the LSB of the calculated value to the checksum value.
If the checksum has been calculated to be 274 then the modulo 256 value is 18 (256 + 18 = 274). This value would be transmitted a 10=018 where
"10="is the tag for the checksum field.
In Java there is a method from QuickFixJ.
String fixStringMessage = "8=FIX.4.29=12535=81=6090706=011=014=017=020=322=837=038=4.39=054=155=ALFAA99=20220829150=0151=06020=06021=06022=F9014=Y";
int checkSum = quickfix.MessageUtils.checksum(fixStringMessage);
System.out.prinln(checkSum);
Output: 127
Hope it can help you.

Type conversion - string of characters to integer

Hello I am writing my program in C, using PSoC tools to program my Cypress development kit. I am facing an issue regarding type conversion of a string of characters collected in my circular buffer (buffer) to a local variable "input_R", ultimately to a global variable st_input_R. The event in my FSM calling this action function is given below:
void st_state_5_event_0(void) //S6 OR S4
{
char buffer[ST_NODE_LIMIT] = {0};
st_copy_buffer(buffer);
uint32 input_R = {0};
mi_utoa(input_R, buffer);
if ((input_R >= 19000) && (input_R <= 26000))
{
st_input_R = input_R;
_st_data.state = ST_STATE_6;
}
else
{
_st_data.status = ST_STATE_4;
}
UART_1_Stop();
st_stop();
st_empty_buffer();
}
ST_NODE_LIMIT = 64
st_copy_buffer copies the the numbers I type in using hyper terminal to the circular buffer named "buffer".
input_R is the 32 bit integer I want the buffer content to be converted to.
mi_utoa is the function I am using for converting the contents in the buffer to input_R and is detailed below:
uint8 mi_utoa(uint32 number, char *string)
{
uint8 result = MI_BAD_ARGUMENT;
if (string != NULL)
{
uint8 c = 0;
uint8 i = 0;
uint8 j = 0;
do
{
string[i++] = number % 10 + '0';
} while ((number /=10) > 0);
string[i] = '\0';
for (i = 0, j = strlen(string) - 1 ; i < j ; i++, j--)
{
c = string[i];
string[i] = string[j];
string[j] = c;
}
result = MI_SUCCESS;
}
return result;
}
The problem is, suppose if I enter 21500(+\r), the mi_utoa function converts the first digit to 0 the second digit to \000 while the other digits including the carriage return "\r" remains unaltered. As a result the input_R is NOT = 21500. Its happening for any string of digits I input. So the condition "if ((input_R >= 19000) && (input_R <= 26000))" is never satisfied. Hence the FSM returns to state 4 all the time and I am going in circles.
Can you please advice where the bug is in the mi_utoa function? Let me know if you want to know any other details.
Your function st_state_5_event_0() sets the value input_R to zero. Then you call mi_utoa(), which converts the value input_R to an ascii string, "0".
void st_state_5_event_0(void) //S6 OR S4
{
char buffer[ST_NODE_LIMIT] = {0};
//what is the value of buffer after this statement?
st_copy_buffer(buffer);
//the value of input_R after the next statement is =0
uint32 input_R = {0};
//conversion of input_R to string will give ="0"
mi_utoa(input_R, buffer);
if ((input_R >= 19000) && (input_R <= 26000))
{
st_input_R = input_R;
_st_data.state = ST_STATE_6;
}
//...
}
You probably want a function which converts your ascii buffer to a number.
uint8
mi_atou(uint32* number, char *string)
{
uint8 result = MI_BAD_ARGUMENT;
if (!string) return result;
if (!number) return result;
uint8 ndx = 0;
uint32 accum=0;
for( ndx=0; string[ndx]; ++ndx )
{
if( (string[ndx] >= '0') && (string[ndx] <= '9') )
{
accum = accum*10 + (string[ndx]-'0');
//printf("[%d] %s -> %d\n",ndx,string,accum);
}
else break;
}
//printf("[%d] %s -> %d\n",ndx,string,accum);
*number = accum;
result = MI_SUCCESS;
return result;
}
Which you would call by providing the address of the number to store the result,
mi_atou(&input_R, buffer);

Bluetooth low energy, how to parse R-R Interval value?

My application is receiving information from smart heart device. Now i can see pulse value. Could you please help me to parse R-R Interval value? How can i check device support R-R Interval value or Not ?
Any advise from you
Thanks
Have you checked the Bluetooth spec? The sample code below is in C#, but I think it shows the way to parse the data in each heart rate packet.
//first byte of heart rate record denotes flags
byte flags = heartRateRecord[0];
ushort offset = 1;
bool HRC2 = (flags & 1) == 1;
if (HRC2) //this means the BPM is un uint16
{
short hr = BitConverter.ToInt16(heartRateRecord, offset);
offset += 2;
}
else //BPM is uint8
{
byte hr = heartRateRecord[offset];
offset += 1;
}
//see if EE is available
//if so, pull 2 bytes
bool ee = (flags & (1 << 3)) != 0;
if (ee)
offset += 2;
//see if RR is present
//if so, the number of RR values is total bytes left / 2 (size of uint16)
bool rr = (flags & (1 << 4)) != 0;
if (rr)
{
int count = (heartRateRecord.Length - offset)/2;
for (int i = 0; i < count; i++)
{
//each existence of these values means an R-Wave was already detected
//the ushort means the time (1/1024 seconds) since last r-wave
ushort value = BitConverter.ToUInt16(heartRateRecord, offset);
double intervalLengthInSeconds = value/1024.0;
offset += 2;
}
}
This post is a little old but a full answer has not been given.
As I run into this post and it did help me at the end, I would like to share my final code. Hopefully it will help others.
The code provided by Daniel Judge is actually right, but as he already wrote, it is C#. HIs code is a bit better compared to what Simon M came up with at the end as the code of Daniel Judge takes into account there can be more than two RR-values within one message.
Here is the actual spec of the Heart_rate_measurement characteristic
I have translated Daniel Judge his code to Objective-C:
// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
// Get the BPM //
// https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //
// Convert the contents of the characteristic value to a data-object //
NSData *data = [characteristic value];
// Get the byte sequence of the data-object //
const uint8_t *reportData = [data bytes];
// Initialise the offset variable //
NSUInteger offset = 1;
// Initialise the bpm variable //
uint16_t bpm = 0;
// Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
// The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
// If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
if ((reportData[0] & 0x01) == 0) {
// Retrieve the BPM value for the Heart Rate Monitor
bpm = reportData[1];
offset = offset + 1; // Plus 1 byte //
}
else {
// If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
// convert this to a 16-bit value based on the host’s native byte order //
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));
offset = offset + 2; // Plus 2 bytes //
}
NSLog(#"bpm: %i", bpm);
// Determine if EE data is present //
// If the 3rd bit of the first byte is 1 this means there is EE data //
// If so, increase offset with 2 bytes //
if ((reportData[0] & 0x03) == 1) {
offset = offset + 2; // Plus 2 bytes //
}
// Determine if RR-interval data is present //
// If the 4th bit of the first byte is 1 this means there is RR data //
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
// The number of RR-interval values is total bytes left / 2 (size of uint16) //
NSUInteger length = [data length];
NSUInteger count = (length - offset)/2;
NSLog(#"RR count: %lu", (unsigned long)count);
for (int i = 0; i < count; i++) {
// The unit for RR interval is 1/1024 seconds //
uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
value = ((double)value / 1024.0 ) * 1000.0;
offset = offset + 2; // Plus 2 bytes //
NSLog(#"RR value %lu: %u", (unsigned long)i, value);
}
}
}
EDIT:
this work for me, i get the correct rr values:
In some cases you can find two values at the same time for rr.
- (void) updateWithHRMData:(NSData *)datas {
const uint8_t *reportData = [datas bytes];
uint16_t bpm = 0;
uint16_t bpm2 = 0;
if ((reportData[0] & 0x04) == 0)
{
NSLog(#"%#", #"Data are not present");
}
else
{
bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[2]));
bpm2 = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[4]));
if (bpm != 0 || bpm2 != 0) {
NSLog(#"%u", bpm);
if (bpm2 != 0) {
NSLog(#"%u", bpm2);
}
}
}
}
in #Brabbeldas solution i had to use a different flag to get rri values. but might depend on device used.
if ((reportData[0] & 0x10) == 0)
instead of
if ((reportData[0] & 0x04) == 0)
Parse heart rate parameters in "C"
I uploaded the sample application to GitHub Heart-Rate-Bluegiga
void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg)
{
if (msg->value.len < 2) {
printf("Not enough fields in Heart Rate Measurement value");
change_state(state_finish);
}
// Heart Rate Profile defined flags
const unsigned char HEART_RATE_VALUE_FORMAT = 0x01;
const unsigned char ENERGY_EXPENDED_STATUS = 0x08;
const unsigned char RR_INTERVAL = 0x10;
unsigned char current_offset = 0;
unsigned char flags = msg->value.data[current_offset];
int is_heart_rate_value_size_long = ((flags & HEART_RATE_VALUE_FORMAT) != 0);
int has_expended_energy = ((flags & ENERGY_EXPENDED_STATUS) != 0);
int has_rr_intervals = ((flags & RR_INTERVAL) != 0);
current_offset++;
uint16 heart_rate_measurement_value = 0;
if (is_heart_rate_value_size_long)
{
heart_rate_measurement_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
}
else
{
heart_rate_measurement_value = msg->value.data[current_offset];
current_offset++;
}
printf("Heart rate measurment value: %d ", heart_rate_measurement_value);
uint16 expended_energy_value = 0;
if (has_expended_energy)
{
expended_energy_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
current_offset += 2;
printf(" Expended energy value: %d ", expended_energy_value);
}
uint16 rr_intervals[10] = {0};
if (has_rr_intervals)
{
printf(" Rr intervals: ");
int rr_intervals_count = (msg->value.len - current_offset) / 2;
for (int i = 0; i < rr_intervals_count; i++)
{
int raw_rr_interval = (uint16)((msg->value.data[current_offset + 1] << 8) +
msg->value.data[current_offset]);
rr_intervals[i] = ((double)raw_rr_interval / 1024) * 1000;
current_offset += 2;
printf("%d ", rr_intervals[i]);
}
printf("\n");
}
}

Formatting a (large) number "12345" to "12,345"

Say I have a large number (integer or float) like 12345 and I want it to look like 12,345.
How would I accomplish that?
I'm trying to do this for an iPhone app, so something in Objective-C or C would be nice.
Here is the answer.
NSNumber* number = [NSNumber numberWithDouble:10000000];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:kCFNumberFormatterDecimalStyle];
[numberFormatter setGroupingSeparator:#","];
NSString* commaString = [numberFormatter stringForObjectValue:number];
[numberFormatter release];
NSLog(#"%# -> %#", number, commaString);
Try using an NSNumberFormatter.
This should allow you to handle this correctly on an iPhone. Make sure you use the 10.4+ style, though. From that page:
"iPhone OS: The v10.0 compatibility mode is not available on iPhone OS—only the 10.4 mode is available."
At least on Mac OS X, you can just use the "'" string formatter with printf(3).
$ man 3 printf
`'' Decimal conversions (d, u, or i) or the integral portion
of a floating point conversion (f or F) should be
grouped and separated by thousands using the non-mone-
tary separator returned by localeconv(3).
as in printf("%'6d",1000000);
Cleaner C code
// write integer value in ASCII into buf of size bufSize, inserting commas at tousands
// character string in buf is terminated by 0.
// return length of character string or bufSize+1 if buf is too small.
size_t int2str( char *buf, size_t bufSize, int val )
{
char *p;
size_t len, neg;
// handle easy case of value 0 first
if( val == 0 )
{
a[0] = '0';
a[1] = '\0';
return 1;
}
// extract sign of value and set val to absolute value
if( val < 0 )
{
val = -val;
neg = 1;
}
else
neg = 0;
// initialize encoding
p = buf + bufSize;
*--p = '\0';
len = 1;
// while the buffer is not yet full
while( len < bufSize )
{
// put front next digit
*--p = '0' + val % 10;
val /= 10;
++len;
// if the value has become 0 we are done
if( val == 0 )
break;
// increment length and if it's a multiple of 3 put front a comma
if( (len % 3) == 0 )
*--p = ',';
}
// if buffer is too small return bufSize +1
if( len == bufSize && (val > 0 || neg == 1) )
return bufSize + 1;
// add negative sign if required
if( neg == 1 )
{
*--p = '-';
++len;
}
// move string to front of buffer if required
if( p != buf )
while( *buf++ = *p++ );
// return encoded string length not including \0
return len-1;
}
I did this for an iPhone game recently. I was using the built-in LCD font, which is a monospaced font. I formatted the numbers, ignoring the commas, then stuck the commas in afterward. (The way calculators do it, where the comma is not considered a character.)
Check out the screenshots at RetroJuJu. Sorry--they aren't full-sized screenshots so you'll have to squint!
Hope that helps you (it's in C) :
char* intToFormat(int a)
{
int nb = 0;
int i = 1;
char* res;
res = (char*)malloc(12*sizeof(char));
// Should be enough to get you in the billions. Get it higher if you need
// to use bigger numbers.
while(a > 0)
{
if( nb > 3 && nb%3 == 0)
res[nb++] = ',';
// Get the code for the '0' char and add it the position of the
// number to add (ex: '0' + 5 = '5')
res[nb] = '0' + a%10;
nb++;
a /= 10;
}
reverse(&res);
return res;
}
There might be a few errors I didn't see (I'm blind when it comes to this...)
It's like an enhanced iToA so maybe it's not the best solution.
Use recursion, Luke:
#include <stdio.h>
#include <stdlib.h>
static int sprint64u( char* buffer, unsigned __int64 x) {
unsigned __int64 quot = x / 1000;
int chars_written;
if ( quot != 0) {
chars_written = sprint64u( buffer, quot);
chars_written += sprintf( buffer + chars_written, ".%03u", ( unsigned int)( x % 1000));
}
else {
chars_written = sprintf( buffer, "%u", ( unsigned int)( x % 1000));
}
return chars_written;
}
int main( void) {
char buffer[ 32];
sprint64u( buffer, 0x100000000ULL);
puts( buffer);
return EXIT_SUCCESS;
}