Tuesday, May 26, 2020

Autobaudrate with non-received CAN msgs

Its been a very long time i have written anything. The kind of learning i was expecting was very rare nowadays due to different roles am playing and also kind of projects as we ll products.

Currently i am working on Telematics ECUs for automotive market. Let me share recent lesson learnt about the same.

Auto baudrate:

Autobaud rate is a feature where based on Rx messages, baudrate will be identified and configured the ECU for that baudrate, among the supported baudrates. For example, if your SW is developed to support for 125kbps and 250kbps CAN baudrates, SW is expected to identify the baudrate based on Rx msgs which ECU receives after the network on and start communication with that baud rate.



When same SW is meant for different types of vehicles with only baudrate change between their types, this feature is helpful to adapt the baudrate changes without any SW change.

Recently when I was checking the autobaud rate with my device, it was not working and but after couple of days, i tested the auto-baud with other device, in other system, it was working ! This created a confusion as well as problem to conclude. We proceeded with the release based on the result from other system. But this issue was troubling me in my mind.

Another fine day, i decided to crack this issue and started testing the same with my device, same CAN configuration and still it was not working. Then later, by chance i added another CAN msg to the transmit window of my CAN configuration and enabled both the msgs as periodic Tx and iit worked then !

Finally i was able to analyze the difference between the msgs and the conclusion was that, the Tx msg which was using before is not meant for TCU. This is nothing but TCU is not recipient of that CAN msg and hence there was no interrupt to receive that CAN msg. Tx msg interrupt will be raised only for msgs for which ECU is recipient.

The day got over with proper conclusion and lesson learnt..

Thank you...


Friday, July 14, 2017

Remember about memcpy/memmove, strcpy/strncpy and malloc/calloc..!

memcpy and memmove

These memory handling functions make us to confuse when anybody asks about the same. Better to keep in my blog for me...!

Among these, memmove handles memory overlapping but memcpy does not.

int main ()
{
char str1[]="Mera Bharat Mahan";
char str2[40];
char str3[40];

memcpy (str2,str1,strlen(str1)+1);
memcpy (str3,"copy successful",16);

printf ("str1: %s\nstr2: %s\nstr3: %s\n",str1,str2,str3);

return 0;
}

Output is:Mera Bharat MahanMera Bharat Mahancopy successful

Look at the following code snap.

int main ()
{
char str[] = "memmove can be very useful......";
memmove(str+20,str+15,11);
puts (str);
return 0;
}

Output is: memmove can be very very useful


If we change the above code to memcpy(), then ,
int main ()
{
 char str[] = "memmove can be very useful";
memcpy(str+20,str+15,5);
puts (str);
return 0;
}

output: memmove can be very very l


In case of memcpy, when address gets overlapped, then the data copy process starts from the beginning of src string (2nd parameter). Hence memcpy is not a better function to use when there is a possibility of address overlaps..


About 'const' qualifier...

The qualifier const can be applied to the declaration of any variable to specify that its value will not be changed ( Which depends upon where const variables are stored, we may change value of const variable by using pointer ). The result is implementation-defined if an attempt is made to change a const.

When we make some pointer as constant, its restricting the access to that memory location through that pointer variable only which means still you will be able to make any modification using other means.

#include

void main()
{
  int i=10, j=20;

  const int *p = &i;      // Pointer to a constant
  int * const p1 = &i;    // Constant pointer to an integer variable
  const int * const p2 = &j;  // Constant pointer to an integer constant 

  *p = NULL;

  p1 = NULL;

  *p2 = 25;

  i = 30;      // valid because we are accessing directly not through pointer

  printf("%d\n", p);
}

Linux 64-bit machine output:

const.c: In function `main':
const.c:10: error: assignment of read-only location
const.c:10: warning: assignment makes integer from pointer without a cast
const.c:12: error: assignment of read-only variable `p1'
const.c:14: error: assignment of read-only location'


Other easy way to remember is how the const keyword is assosiated in the variable declaration statement, as a prefix. const int * OR int const *  refers to value and (int * const ptr) refers to address. I mean, after the keyword const, is the value is there or address is there will be the actual constant (address or value). const int * const ptr where const is associated with both and hence both are constants.

Reference:
http://www.geeksforgeeks.org/const-qualifier-in-c/

Friday, June 17, 2016

Happy Programming : My own itoa function and string reversing

Even though I had programs and info while writing my previous post, thought to go for new post which will increase the post count :)

When I did my previous program, then only I wrote my own itoa function (may have limitations) but am putting here for easy traversing. When I had a consraint to not to use any library function, then only this program came out..!

//implementation of itoa - a is the given number

my_itoa ()
{
    char ptr[10];
    int i=0, temp;
    temp = a;

    for(i=0; temp!=0 ; i++)
    {
        ptr[i] = temp%10 + 48;
        temp = temp / 10;
    }
    ptr[i]='\0';
}

Also, I had done string reversing without using temporary string, long back but jus putting here.

//reversing a string
reverse_str(char *ptr)
{
  int i, j, k;
  for(i=0, j=strlen(ptr)-1; i
  {
    k = ptr[i];
    ptr[i] = ptr[j];
    ptr[j]=k;
  }
}

Happy programming...

Searching a number pattern within a big interger..

Again, after a very long time my techblog is getting a post. Really happy to share something..

Once we cross our beginning of our professional career as a Programmer, we reach a stage where we need to manage people or team or some activitiy which will spoil our current interests and passions about programming, also at the same time we are forced to learn and like different kind of activities.

As I travelled couple of times to different countries and worked for different clients, projects what I understood is working is india for longer time is more challenging than working in abroad, especially US. I mean, in US, you can be a individual contributor for your whole life but in India, you cannot or may be very very difficult.

Anyway, apart from that, recently one programming contest had one question which I couldnt do in test and did at home staying till 3AM.


Searching a number pattern within a Big Integer:

When a given number if 123456789, you have to find out occrence of 56 or 567 kind of pattern. I was trying to use itoa() function which was not available which made me to write my own itoa() function. Also, I did in both way by considering as integers as well as by converting both the numbers to strings, which is nothing but subtring searching.

// Searching an number pattern in a whole integer (as a integer)
search_pattern()
{
    int temp, org, i=0;
    temp = a;
    org = b;
    for(; temp!=0 ; )
    {
        if( temp%10 == b%10 )
        {
            i++;
            b = b / 10;
        }
        else if(i>0  &&  b!=0 )
        {
            i = 0;
            b = org;
        }
        temp = temp / 10;
    }
    if(b==0 && i!=0)
        printf("FOUND\n");
    else 
        printf("NOT FOUND\n");
    
    return;
}

Following example is how I did it as strings. Assume that both the numbers are already converted to strings using sprintf or itoa library functions. I will post my own itoa function in my next blog. 


//searching a number pattern within a number (as strings)
search_substring(char *ptr, char *ptr1)
{
    int i, j, k, success=0;

    for(i=0, j=0;i
    {
      if(ptr[i] == ptr1[j])
      {
          j++;
          for(k=i+1;( k
          {
            if(ptr[k] == ptr1[j])
            {
               success = j;
               j++;
            }
            else
            {
               j=0;
               break;
            }            
        }
        if(j == strlen(ptr1))
        {
          printf("Found... :)\n");
          break;
        }
    }
  }
  if(j==0)
      printf("Not found..\n");
}

Happy Programming....

Thursday, April 9, 2015

Counting all unique characters in a given line, with less static memory....

After a very very log time, I am able to push something into my techBlog. If we see the number of posts per year, it is descending order only. That means, if you keep growing in years of experience, technical learnings is going to be less....!?!?!?

Recently, one of my friends asked me one question to write a program to count the number of occurances of charactaers in an given line with minimal memory. I mean, without using big array to count the characters.

int main(int argc, char **argv)
{
 char *p, *f=NULL;
 int cnt = 0,i=0, j=0, found = 0;

 p = argv[1];  //p will be the given array
 f = (char*)malloc(strlen(p)); //allocating the same size of the given array to use minimal memory
 if(f == NULL)
 {
   printf("Error\n");
 }
 memset(f, 0, strlen(f));

/* Start traversing the give n array when we find unique, count the same in the whole array and keep updating the count in respective index in the new array which is 'f'  */
 for(cnt = 0;cnt < strlen(p); cnt++)
 {
  for(i = 0; i < strlen(p); i++)
  {
   if(p[cnt] == p[i])
    f[cnt]++;
  }
 }

/* This is to print the new array , without duplicates */
/* For abcabc string, a=2, b=2, c=2, a=2, b=2, c=2 will be the final array and it should be printed as a=2, b=2, c=2 only */

 for(i=0; i less than strlen(p); i++)
 {
   for(j=0; j less than i; j++)
   {
    if(p[i] != p[j])
     continue;
    else
     found = 1;
   }
   if(!found)
   {
    printf("%c = %d\n", p[i], f[i]);
   }
   found = 0;
 }
 return 0;
}

Output:
 ./a.out asdcbascasdc
a = 3
s = 3
d = 2
c = 3
b = 1


I know this can be fine tuned but doing anyhow was my problem statement and done. Anybody can improve this and post to this blog or as a comment.

Thanks.

Tuesday, October 29, 2013

Global Variables in Shared Objects

I believe, even people are smart enough, capable enough to do more challenging tasks, they wont get opportunities. 

Recently, Because os some recent analysis of some issues. I came across one issue which made me to understand one of the good concepts of Shared Libraries in real world scenario. Even it is small but should know and understand.

One of the middleware processes and another application process shared the same library though which both can access one of the Shared Memory database. Timer was running in the middleware process to update one global counter variable in the library. It was updating and printing the values properly. 

Due to one of the issues reported by the client, we found that that counter variable needs to be reset upon one of the request from GUI. Recipient for the GUI request is Application. Hence, as application also shared the same library, we thought to reset the counter from application.  But when we did the same and print the value, counter was resetting properly. Next time, when timer started from middleware and prints the value, then it was continued from the previous value of the counter variable. This mean, resetting was not successful but we were getting proper value at application. 



After we found that, as this is shared library between application process and middleware process, global variables of shared objects will have different copy for each process. That is the reason behind using shared memory database in our project. Even SMDB is used, library to access the SMDB component is just shared object, ideally, which should not have global variables. In other words, global data will run in process address space I believe and hence each process will have its own copy. 

After few Googling, found following points are important.

1. If a shared library uses a global variable that is not exported, each process that uses that library get a copy of that variable -  Data is specific to processes, not libraries.

2. Only CODE is shared, not data (well, constant data might be shared) 

If any of you have more information or good links related to this, drop here as your comments.

Thanks in advance...

Sunday, July 14, 2013

Responses were getting delayed and taking more than 50ms....!

One of the critical issues reported after the Vehicle production started is there was a delay in response to the Diagnostics requests.

As per the requirement or as per the standard, for any diagnostics requests, response should be within 50ms. Hence at the end of assembly in production, using scripts, tested will be performed, called EOL tests (End of Line) and the result was NG (No Go or Not Good). Hence because of the failure in EOL tests, these issues became critical.

When we were analyzing the issues, we also took the same scripts were used for EOL tests where that script was sending DIAG requests continuously for every 60 ms. Hence our software module was expected to respond to the script requests within 50ms. But when there was a delay, script was showing the error. Sometimes there was no response at all..!

We were not able to reproduce the issue with the GGDS tester simulation which came with CANoe. Hence we were depending on the customer's script only. We spend more than 3-4 days of time to analyze the issue, to understand the pattern of the reproducibility. Finally, decided to use Oscilloscope to find out where and when the delay will be started. Using debug ports, configured the code and see the delay in the Transmission of CAN signal (Tx) in Oscilloscope, in CANoe itself. We started enabling all periodic messages one by one and found that one of the CAN signal handler is taking more than 50ms of time and delay is getting accumulated because which was a periodic message. Normally CAN signal handlers should not take more than 1-2ms of time because Vector task should get the CPU for every 2ms (schedule time). When we look into the code (signal handler callback) to understand which line of the code taking more time, found that there was a EEPROM Write operation was there which was taking more than 50 ms of time.

To fix this issue, later  we moved the EEPROM operation to ACC OFF handler.

This issue was not observed when there is not CAN traffic. Due to the periodic CAN messages in the netwrok, this issue was observed. This helped us to suspect one of the signal handlers might taking more time.

Due to all of the above, DIAG task was not getting the CPU to respond to the requests and delay was accumulating.

Ideally, CAN signals handlers should have minimum instructions to execute so that vector's tasks should not get delayed or blocked on anything. Schedule time of the CAN task will be 2-3 ms and which should get the CPU for every 2-3 ms. If we do any operation which takes more than the schedule of the CAN task, will cause issues.

This was one of the good analysis we made and can help us to root cause the issues where response delay is the major issue.

Friday, February 22, 2013

Experience on ‘void’ and ‘extern’

Fortunately, after very long time, I am able to have something new in my techblog. It is because of my stay @ onsite and change in the nature of work.

Since few months, may be from August 2012, I am working on brand new thing which I never worked before, never heard before. Really this is the advantage of Service Companies. In these days, I have come across many new things, even though they are small. But it was good to know. I will try to remember as many as possible.

Since I am working Vehicle Diagnostics, except Programming language, everything is new. CAN, CANoe, Renesas's High-Performance Embedded Workshop IDE (HEW), uITRON OS Platform, Flashing Tool, 16-bit co-processor HW platform etc..

When I was using HEW, I came across the wondering behavior of Renesas compiler. For absence of function prototype also, it was giving linker error. I was the first strange thing I faced with HEW/Renesas compiler.

'void' at declaration and call:

When writing one function, I declared as void for function argument. But in the same way, I copied the same prototype in the place of call.

void function (void);
Init()
{
funcrtion(void);
}

Then I got an ERROR message after the compilation. The error was

C2766 (E) parse error at near 'void'

I really took around 30 mins of time to root cause this error. As copied the prototype in place of call, 'void ' was placed as a parameter to that function. This was the reason the above error. When we declare any functions, 'void' will behave in usual way. But when we keep the same in call as a parameter, the meaning of 'void' data type, as we use only void pointers. Looks simple, but new for me.

'extern' without datatype:

As I am working with few KBs of RAM, we used many ‘extern’ to refer the variables shared between files of same module. When I copied the data from extern variable to local array, I could see different data. Say array a[4] = {1,2,3,4} and dest[4] is {1,3}. Once again I started thinking about junk platform or junk IDE kind of thoughts.

/* In one of the source file */
unsigned char a[4];


/* In another source file */
extern a[];

b[0] = a[0];
b[1] = a[1];
b[2] = a[2];
b[3] = a[3];

After the last line of execution, a was {1,2,3,4} and b is {1,3}. After some analysis, I understood the behavior.  I changed the above code as below.

/* In one of the source file */
unsigned char a[4];

/* In another source file */
extern unsigned char a[];

Here, there was no data type associated with the variable, it was  (array 'a') treated as 16-bit data as MCU was 16-bit and hence 0th byte and 2nd byte only copied from the source array.

Same kind of thing happened to me in different way.
There was a 2D array of around 20 indexes and each of 25 bytes, in other module.

const char twodarray[21][25];

I referred this 2D array as extern.

extern const char twodarray[][25];

I was copying the data in my module's init function to my local array like

U8 localArray[25];
strcpy( localArray, twodarray[3] );

It was working fine for few days. But after some time, when we tested, only 4 bytes of data being copied to the destination array. I was wondering and took few hours of time to root cause.

The main definition of the array got changed to

const char twodarray[21][30];

As it was externed as 25 bytes of array, for the strcpy function, array was behaving like twodarray[21][25] only, even though it’s original declaration having 30. When I changed to

extern const char twodarray[][30], it worked fine.

The reasons for this, i think, irrespective of the dimension of the array, all are contiguous memory. Due to this, expected chunk of data was not referenced.

Really I was happy when I could root cause these kind of issues.

Monday, August 13, 2012

Getting the core file under Linux Environment

Once again after long time, my techBlog is getting something...

When i started working on QNX environment, host environment was Linux. After few days of time, thought to do some experiements on target to know any different behavior of QNX, compare to Linux/Unix. Hence wrote small application programs. But got a question, How to compile for target..?Host machines Linux was installed with toolChain and got to know about 'qcc' command which is nothing but gcc for qnx. When i compiled using qcc command, executable getting created but it was not executing on target. When i looked at the file info,

a.out: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

But the file info of the files which were getting executed on target were

a.out: ELF 32-bit LSB executable, Hitachi SH, version 1 (SYSV), dynamically linked (uses hared libs), not stripped

This is specific to Target, SH based MC. Then i understood that qcc was creating binaries for generic target (default x86), not for specific target. Then looked into makefiles which were with full of MACROS, no direct commands. When i saw the output of makefiles, i got that some configuration files is being used to cross compile which is a argument for qcc.

qcc -V3.3.5,gcc_ntoshle q.c

Above command could create a.out file for our target and i could execute and the file on actual target. After this, i could test something on target. After this i have tested some system calls related programs and etc. I was happy when i have done what i wanted... !!!!

Core file creation under Linux environment:

For segmentation fault kind of issues, .core file was getting created on target with the process name. If process/exe file name is test, test.core file was getting created on target which we use to debug the issue. From that core file, we could backtrace (execution stack) to understand the last line of code executed, using target version of gdb.

But i knew that QNX behavior is almost same as Linux/Unix because of POSIX compliance. Means, i was expected the same kind of core file creation on linux paltform also which was not happening. After discussion with my lecturer and googling, i came to know about 'ulimit'.

[pramoda@server ~]$ ulimit -a
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
file size (blocks, -f) unlimited
pending signals (-i) 1024
max locked memory (kbytes, -l) 32
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
stack size (kbytes, -s) 10240
cpu time (seconds, -t) unlimited
max user processes (-u) 8190
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited

When i change ulimit value from 0 to unlimited, (ulimit -c unlimited) then for segFault erros, i could get core files in linux also. The filename will be like 'core.[PID]'. If the application file executed and if the PID of the same is 102302, then the core file will be core.102302.

To create the debug file, which is nothing buf object file, execute cc test.c -o test-debug command.

Using gdb, we can look into backtrace to get the execution stack.
[pramod@testServer ~]$ gdb test-debug core.14611
GNU gdb Red Hat Linux (6.1post-1.20040607.62rh)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions.

Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...(no debugging symbols found)...Using host libthread_db library "/lib64/tls/libthread_db.so.1".
warning: core file may not match specified executable file.
 
Core was generated by `./a.out'.
Program terminated with signal 6, Aborted.
Reading symbols from /lib64/tls/libc.so.6...(no debugging symbols found)...done.

Loaded symbols for /lib64/tls/libc.so.6
Reading symbols from /lib64/ld-linux-x86-64.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib64/ld-linux-x86-64.so.2
#0 0x00000031c992e4dd in raise () from /lib64/tls/libc.so.6
(gdb) bt

#0 0x00000031c992e4dd in raise () from /lib64/tls/libc.so.6
#1 0x00000031c992fc8e in abort () from /lib64/tls/libc.so.6
#2 0x00000031c9962b41 in __libc_message () from /lib64/tls/libc.so.6
#3 0x00000031c996846f in _int_free () from /lib64/tls/libc.so.6
#4 0x00000031c9968a06 in free () from /lib64/tls/libc.so.6
#5 0x000000000040057a in main ()

Most of the time, we get libc is the triggerer because of printf, sprintf kind of library calls. We may get more info like line number of our source file, function names etc which is depending on the workspace.

I am trying to get more info about ulimit and core files. Let me see...

Monday, January 30, 2012

Linux Device Drivers : Kernel APIs used for Character Device Drivers

As i have planned, i went to 4-day workshop on Linux Device Drivers by Anil Kumar Pugalia. It was fine and made us to put some individual effort to understand more. Hence i will start posting them in my blog, not in order.

First to start with, i am keeping some info about Character Device Drivers. Here are Kernel APIs to be used for Character device drivers.

1. alloc_chrdev_region() : Allocates a range of char device numbers. The major number will be chosen dynamically, and returned in dev along with the first minor number.

alloc_chrdev_region (dev_t* dev, unsigned baseMinor, unsigned count, const char* name);

dev : output param for first assigned number
baseMinor: first of the requested range of minor numbers
count: number of minor numbers required
name: name of the associated device/driver

2. cdev_init() : Initialize the cdev structure, remembering fops, making it ready to add to the system with cdev_add

cdev_add(struct cdev* cdev, const struct file_operations* fops);

cdev : the structure to initialize
fops : the file operations for this device.

3. cdev_add() : Add a char device driver to the system, making it live immediately.

cdev_add(struct cdev *p, dev_t dev, unsigned count);

p : the cdev structure for this device
dev: the first device number for which this device is responsible
count: the number of consecutive minor numbers corresponding to this device

4. class_create() : creates a struct class structure (sysfs entry and generates uevents).

class_create(struct module * owner, const char *name);

owner: THIS MODULE
name: pointer to a string for the name of this class

5. device_create() : creates a device and register it with sysfs. This will be used by character device classes. A struct device will be created in sysfs, registered to the specified class.

device_create(struct class *class, struct device *parent, dev_t dev, const char* fmt, ...);
class: output of class_create()
parent: pointer to the parent struct device (NULL for the time being)
dev: dev-t for the device to be added (output of alloc_chrdev_region())
fmt: string for the device name
...

6. unregister_chrdev_region() :

unregister_chrdev_region(dev, minor_count);

7. cdev_del():

cdev_del(&c_dev);


/*** * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if ((ret = alloc_chrdev_region(&dev, 0, 1, "final_driver")) < 0)
{
return ret;
}
cdev_init(&c_dev, &driver_fops);
if ((ret = cdev_add(&c_dev, dev, 0)) < 0)
{
unregister_chrdev_region(dev, 0);
return ret;
}
if (IS_ERR(cl = class_create(THIS_MODULE, "char")))
{
cdev_del(&c_dev);
unregister_chrdev_region(dev, 0);
return PTR_ERR(cl);
}
if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "mychar%d", 0)))
{
class_destroy(cl);
cdev_del(&c_dev);
unregister_chrdev_region(dev, 0);
return PTR_ERR(dev_ret);
}
/*** * * * * * * * * * * * ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */




Memory Allocation Related:

1. ioremap() : For mapping the physical address to virtual kernel space address.

void* ioremap(unsigned long phys_addr, unsigned long size);

phy_addr: begin of physical address range
size: size of the physical address range

ioremap builds new page tables. It doesn’t actually allocate memory. The return value of ioremap is a special address that can be used to access the specified physical address range. The return value form ioremap cannot be dereferenced directly on all platforms. Instead functions like readb, writeb etc will be used. ioremap allocates uncacheable pages.

2. ioread8(), ioread16(), ioread32(): The return address of ioremap cannot be dereferenced directly. Hence these functions are provided.

ioread8(void * address);

address: return value of opremap()

3. iowrite8(), iowrite16(), iowrite32(): To write and data into the given I/O memory returned by ioremap();

iowrite(U8 value , void *address);
iowrite16(U16 value , void *address);
iowrite32(U32 value , void *address);

4. copy_to_user() and copy_from_user() :To copy to or from user space to kernel space

copy_to_user(ubuf, kbuf, len);
copy_from_user(kbuf, ubuf, len);

5. iounmap() : Virtual address obtained by ioremap() should be released by calling iounmap()

iounmap(void * address);


About ioctl() :

This is to support unusual functionalities other than read, write, seek kind of operations with the device. Most devices can perform beyond the simple data transfers like for example eject the media, lock the door, change baud rate, change the page selection tray etc. To support these, ioctl() will be used to implement the handlers.

int (*ioctl)(struct inode *inode, struct file *filep, unsigned long cmd, unsigned long arg);


ioctl in user space:

int ioctl(int fd, unsigned cmd, . . .);

A system call can't actually have a variable number of arguments. The dots in the prototype represent not a variable number of arguments but a single optional argument. The dots are simply there to prevent type checking during compilation. The actual nature of the third argument depends on the specific control command being issued. Some commands take no arguments, some take an integer value, and some take a pointer.

ioctl() commands calculation:

The ioctl command numbers should be unique across the system in order to prevent errors caused by issuing the right command to the wrong drvice. To help programmers create unique ioctl command codes, these codes have been split up into several bitfields.

Thursday, December 15, 2011

Program to read the contact details from collection of VCF files:

After so many days, my techBlog is getting a post, Great.

Recently i baught a new lower end SAMSUMNG phone. I felt good to have that phone, Samsung Metro C3322. My phone is having an option to take the backup of messages, contacts, calendars etc. May be other phones also have. When i took the backup of contacts, .vcf files are created for each contact. I knew something about vcf files due to my project experience.

After few days, a thought came to my mind to take the print out of all the contacts of my phone. But files are more which is of indivual. Then, i decided to write a C program to extract the names and numbers of all the contacts in a directory and started immediately.

Using file I/O and string functions, i could finish as early as possible.

When i was in KPIT, i used strtok() function a lot which made me not to forget. Once again, this program made me to memorise the same. Really, strtok() function is tood good for us like Application programmers.


My program will take directory of vcf files as input and it will write the names and numbers (mobile and home only) into a file, NameNumber.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include
#include
#include

int writeToFile(char *data)
{
FILE *fp;
fp = fopen("NameNumber", "a");
if(fp == NULL)
{
printf("fopen error in function");
exit(10);
}
fwrite(data, 1, strlen(data), fp);
fclose(fp);
return 0;
}


int readFile(FILE *fp2)
{
char *ptr, Number[50], FName[50], buf[80];
int CN, FN;
char data[100];

while(!feof(fp2))
{
if(fgets(buf, 50, fp2)!= NULL)
{
ptr=strtok(buf, ":;");
printf("string is : %s\n", ptr);
while(ptr != NULL)
{
if(FN == 1)
{
memset(&FName, 0, 50); ////Note:
strncpy(FName, ptr, strlen(ptr)-1);
FName[strlen(FName)-1]='\0';
FN=0;
printf("Name is : %s\n", FName);
}
if(strcmp(ptr, "FN")==0)
{
FN=1;
}
if(CN == 1)
{
if(strcmp(ptr, "VOICE")==0)
{
ptr = strtok(NULL, ":;");
}
strcpy(Number, ptr);
CN=0;
printf("Number is %s\n", Number);
}

if(strcmp(ptr, "CELL")==0)
{
CN=1;
strcpy(Number, ptr);
}
if(strcmp(ptr, "HOME")==0)
{
CN=1;
strcpy(Number, ptr);
}
ptr = strtok(NULL, ":;");
}
}
else
{
break;
}
}
sprintf(data,"%s %s %s", FName, ":", Number);
writeToFile(data);
}

int main()
{
FILE *fp, *fp2;
int FN=0, CN=0;
char fileName[50], *ptr=NULL, buf[30], temp[10], FName[30], Number[30];
char path[100];
system("ls myPhone/contact/ > file");
fp = fopen("file", "r");
if(fp == NULL)
{
printf("Fileopen error");
exit(10);
}
while(!feof(fp))
{
strcpy(path, "myPhone/contact/");
if(fgets(fileName, 100, fp) == NULL)
{
printf("fgets error for %s", fileName);
exit(10);
}
fp2 = fopen(strncat(path, fileName, strlen(fileName)-1), "r");
if(fp2 == NULL)
{
printf("Fileopen2 error: %s\n", path);
exit(10);
}
printf("Opened is : %s\n", path);
readFile(fp2);
}
exit(10);
fclose(fp);
fclose(fp2);
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

In the above program, memset() function made this program more robust. Because, I was facing some issues related to names. When i was printing the names, i was getting some junk characters. I took quite amount of time to solve using memset function. You can try the same without memset function.

This was written and executed under Linux platform. But when i run the same program under QNX platform, program crashed and code dump is found. I am planning to dig into that to understand the behavior of QNX. Let me see...

I like to write simple programs frequently by having these kind of problem statements in hand which will make me to remember something good about this tech field.

Keep Programming, Keep Doing Good....

Tuesday, October 25, 2011

Sharing a variable between two C files : An Experience

Even though we work for some years on any language, sometimes, we will not aware of some basic concepts of languages, which is becasue of we never use those in our coding styles. For example, if we are working on C language since 5 years and suddenly if you want to use snprintf() function, definitely you will go for Google...!!!

When i wanted to share a variable between two different C files, what i have declared a variable in a common header file for both the files. While testing the application, in one file where the value being assigned, the value was fine and in another file, the value of the variable is always 0. I was wondering..!! Thinking like, how can it happen...?

After all, discussed with my guide-for-all lecturere and then only i came to know that, when we include a header file in 2 different C files, scope of the variables will become limited to those files and those are separate for both the files. That means, if we declare a variable g_temp in abc.h file if we include ab.c in a.c and b.c, g_temp will be different for both the files and hence values are local to those files.

If we declare the variable in one C file and if we use extern keyword to refer to that, then it will work fine.

Otherwise, we have to have a function in one C file and to get and set the value of a global variable which is defined in the same file.


Another scenario:

In the same way, we will not aware of some basic concepts even though we are working on the same technology, becasue we have not used those concepts particularly. For example, in C language, we use switch case statements extensively. But somebody asks if we put one printf statement before the first case statement, what will happen ? We ll test manually or we ll go for google.

Recently only i came across about the above. If we put any statement before the first case statement, that will not be executed.

#define SUCCESS 1

int state=SUCCESS;
switch(State)
{
printf("Before the case statements starts");
case SUCCESS:
printf("Testing the switch case");
break;
default:
printf("default case");
}

In the above code, the printf statement before the case statement starts, will never executes. This looks very very simple, but i came to know very recently. May be this is obvious.

Keep knowing new things... Gud Luck...

Friday, September 16, 2011

Local variables in function stack: An Experience

When we were preparing for the interviews in College days, nothing was in mind except interviews. Also we were no thinking beyond the interview requirements. But when we face the same type of situations while working in any project that will make us to understand our present and past understanding capabilities and also make us to know more.

When I was in 6th sem of my engineering, I was attended an interview of RoboSoft, UDUPI. While preparing for that, I came across a C question as follows.


#include "stdio.h"
void main()
{
int a=10, b=20;
int *ptr = &a;

ptr--;
printf("%d", *ptr);
}
This will print as 20. Also this may depends on compilers. Assume GCC for this.

When local variables are declared, will be pushed into the stack in order of their declaration. Stack address will increment from TOP(decrement from BOTTOM). Here initially ptr will point to a's location and when we decrement it will point to b's location.

Lets come to point. I have following type of declarations.

struct abc
{
union data xyz;
int i;
};

In my program, I was written as follows.

uinon data a;
int temp = 10;
printf("%d", temp);
memset(a, 0, sizeof(struct abc));
printf("%d", temp);

While testing my code, I was getting the value of temp is 10 and 0 both. Initially I was wondering how temp value is changing without doing anything. After sometime, I understood that memset is making temp 0..!!!?? But how ?

Then, due to my interview question, I closely looked into the memset statement and its declaration and came to know how memset was making the temp variable 0. Because, structure is having sizeof union +1 and hence next immediate 32 bit is setting to 0.

After knowing this, I was very happy and was feeling like anything for that point of time.

This is what will make us our work enjoyable to some extent and thats what i expected from this industry.

Happy moment...!! gUd lUcK...

Monday, September 5, 2011

'find' Command Reference : Very Useful

When we use Linux/UNIX based systems, we need to know the usage of commands which will make our work easier and faster. Because, some of the operations can be done through commands itself..!!

Also, how much you know about Linux will be decided by your command knowledge and its usage. One of those is 'find'.

Please have a look once.

1. Find Files Using Name
This is a basic usage of the find command. This example finds all files with name — MyCProgram.c in the current directory and all it’s sub-directories.
# find -name "MyCProgram.c"
./backup/MyCProgram.c
./MyCProgram.c

2. Find Files Using Name and Ignoring Case
This is a basic usage of the find command. This example finds all files with name — MyCProgram.c (ignoring the case) in the current directory and all it’s sub-directories.
# find -iname "MyCProgram.c"
./mycprogram.c
./backup/mycprogram.c
./backup/MyCProgram.c
./MyCProgram.c

3. Limit Search To Specific Directory Level Using mindepth and maxdepth
Find the passwd file under all sub-directories starting from root directory.
# find / -name passwd
./usr/share/doc/nss_ldap-253/pam.d/passwd
./usr/bin/passwd
./etc/pam.d/passwd
./etc/passwd

Find the passwd file under root and one level down. (i.e root — level 1, and one sub-directory — level 2)
# find -maxdepth 2 -name passwd
./etc/passwd

Find the passwd file under root and two levels down. (i.e root — level 1, and two sub-directories — level 2 and 3 )
# find / -maxdepth 3 -name passwd
./usr/bin/passwd
./etc/pam.d/passwd
./etc/passwd

Find the password file between sub-directory level 2 and 4.
# find -mindepth 3 -maxdepth 5 -name passwd
./usr/bin/passwd
./etc/pam.d/passwd

4. Executing Commands on the Files Found by the Find Command.
In the example below, the find command calculates the md5sum of all the files with the name MyCProgram.c (ignoring case). {} is replaced by the current file name.
# find -iname "MyCProgram.c" -exec md5sum {} \;
d41d8cd98f00b204e9800998ecf8427e ./mycprogram.c
d41d8cd98f00b204e9800998ecf8427e ./backup/mycprogram.c
d41d8cd98f00b204e9800998ecf8427e ./backup/MyCProgram.c
d41d8cd98f00b204e9800998ecf8427e ./MyCProgram.c

5. Inverting the match.
Shows the files or directories whose name are not MyCProgram.c .Since the maxdepth is 1, this will look only under current directory.
# find -maxdepth 1 -not -iname "MyCProgram.c"
.
./MybashProgram.sh
./create_sample_files.sh
./backup
./Program.c

6. Finding Files by its inode Number.
Every file has an unique inode number, using that we can identify that file. Create two files with similar name. i.e one file with a space at the end.
# touch "test-file-name"

# touch "test-file-name "
[Note: There is a space at the end]

# ls -1 test*
test-file-name
test-file-name

From the ls output, you cannot identify which file has the space at the end. Using option -i, you can view the inode number of the file, which will be different for these two files.
# ls -i1 test*
16187429 test-file-name
16187430 test-file-name

You can specify inode number on a find command as shown below. In this example, find command renames a file using the inode number.
# find -inum 16187430 -exec mv {} new-test-file-name \;

# ls -i1 *test*
16187430 new-test-file-name
16187429 test-file-name

You can use this technique when you want to do some operation with the files which are named poorly as shown in the example below. For example, the file with name — file?.txt has a special character in it. If you try to execute “rm file?.txt”, all the following three files will get removed. So, follow the steps below to delete only the “file?.txt” file.
# ls
file1.txt file2.txt file?.txt

Find the inode numbers of each file.
# ls -i1
804178 file1.txt
804179 file2.txt
804180 file?.txt

Use the inode number to remove the file that had special character in it as shown below.
# find -inum 804180 -exec rm {} \;

# ls
file1.txt file2.txt
[Note: The file with name "file?.txt" is now removed]

7. Find file based on the File-Permissions
Following operations are possible.
Find files that match exact permission
Check whether the given permission matches, irrespective of other permission bits
Search by giving octal / symbolic representation

For this example, let us assume that the directory contains the following files. Please note that the file-permissions on these files are different.
# ls -l
total 0
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 all_for_all
-rw-r--r-- 1 root root 0 2009-02-19 20:30 everybody_read
---------- 1 root root 0 2009-02-19 20:31 no_for_all
-rw------- 1 root root 0 2009-02-19 20:29 ordinary_file
-rw-r----- 1 root root 0 2009-02-19 20:27 others_can_also_read
----r----- 1 root root 0 2009-02-19 20:27 others_can_only_read

Find files which has read permission to group. Use the following command to find all files that are readable by the world in your home directory, irrespective of other permissions for that file.
# find . -perm -g=r -type f -exec ls -l {} \;
-rw-r--r-- 1 root root 0 2009-02-19 20:30 ./everybody_read
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 ./all_for_all
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read
-rw-r----- 1 root root 0 2009-02-19 20:27 ./others_can_also_read

Find files which has read permission only to group.
# find . -perm g=r -type f -exec ls -l {} \;
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read

Find files which has read permission only to group [ search by octal ]
# find . -perm 040 -type f -exec ls -l {} \;
----r----- 1 root root 0 2009-02-19 20:27 ./others_can_only_read

8. Find all empty files (zero byte file) in your home directory and it’s subdirectory
Most files of the following command output will be lock-files and place holders created by other applications.
# find ~ -empty

List all the empty files only in your home directory.
# find . -maxdepth 1 -empty

List only the non-hidden empty files only in the current directory.
# find . -maxdepth 1 -empty -not -name ".*"

9. Finding the Top 5 Big Files
The following command will display the top 5 largest file in the current directory and it’s subdirectory. This may take a while to execute depending on the total number of files the command has to process.
# find . -type f -exec ls -s {} \; sort -n -r head -5

10. Finding the Top 5 Small Files
Technique is same as finding the bigger files, but the only difference the sort is ascending order.
# find . -type f -exec ls -s {} \; sort -n head -5

In the above command, most probably you will get to see only the ZERO byte files ( empty files ). So, you can use the following command to list the smaller files other than the ZERO byte files.
# find . -not -empty -type f -exec ls -s {} \; sort -n head -5


11. Find Files Based on file-type using option -type

Find only the socket files.
# find . -type s

Find all directories
# find . -type d

Find only the normal files
# find . -type f

Find all the hidden files
# find . -type f -name ".*"

Find all the hidden directories
# find -type d -name ".*"

12. Find files by comparing with the modification time of other file.
Show files which are modified after the specified file. The following find command displays all the files that are created/modified after ordinary_file.
# ls -lrt
total 0
-rw-r----- 1 root root 0 2009-02-19 20:27 others_can_also_read
----r----- 1 root root 0 2009-02-19 20:27 others_can_only_read
-rw------- 1 root root 0 2009-02-19 20:29 ordinary_file
-rw-r--r-- 1 root root 0 2009-02-19 20:30 everybody_read
-rwxrwxrwx 1 root root 0 2009-02-19 20:31 all_for_all
---------- 1 root root 0 2009-02-19 20:31 no_for_all

# find -newer ordinary_file
.
./everybody_read
./all_for_all
./no_for_all
13. Find Files by Size
Using the -size option you can find files by size.

Find files bigger than the given size
# find ~ -size +100M

Find files smaller than the given size
# find ~ -size -100M

Find files that matches the exact given size
# find ~ -size 100M

Note: – means less than the give size, + means more than the given size, and no symbol means exact given size.

14. Create Alias for Frequent Find Operations
If you find some thing as pretty useful, then you can make it as an alias. And execute it whenever you want.

Remove the files named a.out frequently.
# alias rmao="find . -iname a.out -exec rm {} \;"
# rmao

Remove the core files generated by c program.
# alias rmc="find . -iname core -exec rm {} \;"
# rmc


15. Remove big archive files using find command
The following command removes *.zip files that are over 100M.
# find / -type f -name *.zip -size +100M -exec rm -i {} \;"
Remove all *.tar file that are over 100M using the alias rm100m (Remove 100M). Use the similar concepts and create alias like rm1g, rm2g, rm5g to remove file size greater than 1G, 2G and 5G respectively.
# alias rm100m="find / -type f -name *.tar -size +100M -exec rm -i {} \;"
# alias rm1g="find / -type f -name *.tar -size +1G -exec rm -i {} \;"
# alias rm2g="find / -type f -name *.tar -size +2G -exec rm -i {} \;"
# alias rm5g="find / -type f -name *.tar -size +5G -exec rm -i {} \;"

# rm100m
# rm1g
# rm2g
# rm5g