Solved

checking whether busy tone or not via command line parameters, implemented as state machine

Posted on 2004-08-09
31
283 Views
Last Modified: 2010-04-15
Hi,
i am doing this little assignment for uni, and we have to get an input of one string in the command line as 11111.......11111. this is simulating a high clock and a low clock for a phone line and we have to find out whether this is a busy signal or not. we have to use a state table for this prog,
it is doing funny stuff and not going thru the state machine properly.  the last 2 command line parameters are just not being taken in...!!
If i wud enter say ./program 111........11111....... it shud recognise that, and go thru the state machine and tell me whethere there is a busy signal or not.
im attaching the code, and hope someone can tell me whats wrong with my code.
thanks

//SAURABH MATHUR - 2113232R
//EEET 2170 BUSY TONE PROJECT
//TUTOR - MR. P J RADCLIFFE

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <string.h>

//------------- state machine data and types. -------------------------------
typedef unsigned char bool ;
typedef unsigned char byte ;
#define TRUE  1
#define FALSE 0

typedef struct
  { byte current_state ;      // state must be this value for driver to
                              //   try the exit test function.
    bool (*exit_test_ptr)() ; // routine to execute, tests if this exit is
                              //   allowed.
    byte next_state ;         // state to adopt if exit allowed.
    void (*exit_action)() ;   // action to take if exit allowed.
  } Tstate_line ;

int  state ;
int  num_state_entries ;
char arg_to_test ;
char tone;
char new_tone;
int  num_of_tones;
int num_of_new_tone;
bool range; //for checking if the range is fine or not!!!!!
int action; //for the switch statement
int input_left;
//===================== Test and Action routines ===========================
//
//  PURPOSE - this section contains two types of simple routines-
//             * test routines that only test things and return TRUE or FALSE.
//             * action routines that do a simple job.

bool test_tone()
{ if ((arg_to_test == '1') || (arg_to_test == '.'))
      {      tone = arg_to_test;
            printf("First ever tone received which is %c \n", arg_to_test);
            return( TRUE );
      }
else return( FALSE );
}

bool test_****_tone()
{ if ((arg_to_test != '1') && (arg_to_test != '.'))
      {      printf("**** received");
            return( TRUE );
      }
else return( FALSE );
}

bool test_same_tone()
{ if(arg_to_test == tone)
      {      printf("same tone received, which is %c \n", arg_to_test);
            
            return( TRUE );
      }
else return( FALSE );
}

bool test_diff_tone()
{ if(arg_to_test != tone)
      {      new_tone = arg_to_test;
            tone = arg_to_test;
            printf("new tone received, which is %c\n", arg_to_test);
            //do_check_range();
            num_of_new_tone = 1;
            return( TRUE );
      }
else return( FALSE );
}

bool test_no_tone()
{ if(input_left == 0)
      return( TRUE );
else return( FALSE );
}

bool test_2nd_tone()
{ printf("inside 2nd tone testing function\n");
  printf("tone is %c and arg_to_test is %c\n", tone, arg_to_test);
      if((tone == '1' && arg_to_test == '.') || (tone == '.' && arg_to_test == '1'))
      {        tone = arg_to_test;
            num_of_new_tone = 1;
            printf("Second tone received %c\n", arg_to_test);
            return( TRUE );
      }
else return( FALSE );
}

bool test_in_limits()
{       
      printf("checkin range\n");
      if(range == TRUE)
      { printf("Range is fine\n");
            return( TRUE );
      }
else return( FALSE );
}

bool test_notin_limits()
{       printf("checkin range\n");
      if(range != TRUE)
      {      printf("Range is not fine\n");
            return( TRUE );
            
      }
else return( FALSE );
}

bool test_nothing()
{ return( TRUE );
}

void do_keep_count()
{
      num_of_tones = num_of_tones + 1;
      printf("Number of tones = %d\n", num_of_tones);
}

void do_check_range()
{
      printf("Number of tones till previous tone were %d\n", num_of_tones);
      if ((num_of_tones > 5) && (num_of_tones) < 10)
      {
            range = TRUE;
            //printf("Range is fine\n");
      }
      else
      {
            range = FALSE;
            //printf("Range is not fine\n");
      }
      num_of_tones = num_of_new_tone;
}

void do_store_result()
{

}

void do_nothing()
{
      num_of_tones = num_of_new_tone;
}

void do_exit()
{
}

void do_param_error()
{
      action = 7;
      printf(" there is a parameter error");
      
}

void do_cant_tell()
{
      action = 8;
      printf("cant tell");
}

void do_busy_tone()
{
      action = 9;
      printf("busy");

}

void do_not_busy()
{
      action = 10;
      printf("not busy");
}


//===================== state_table =========================================

//--- state names.  lc=lower case, uc=upper case.
#define start 0
#define unknown_tone 1
#define check_tone_range1 2
#define got_half_cycle 3
#define second_tone_state 4
#define check_tone_range2 5
#define check_other_tone 6
#define Param_Error 7
#define Cant_Tell 8
#define Busy_Tone 9
#define Not_Busy 10
#define first_tone_state 11


Tstate_line  state_table[] =
   {/*            current state            exit test           next state                exit action.*/
                      start,            &test_tone,            unknown_tone,            &do_keep_count
               ,start,            &test_****_tone,      Param_Error,            &do_exit
               ,unknown_tone,      &test_****_tone,      Param_Error,            &do_exit
               ,unknown_tone,      &test_same_tone,      unknown_tone,            &do_keep_count
               ,unknown_tone,      &test_diff_tone,      first_tone_state,      &do_nothing //nothing
               ,unknown_tone,      &test_no_tone,            Cant_Tell,            &do_exit
               ,first_tone_state,      &test_****_tone,      Param_Error,            &do_exit
               ,first_tone_state,      &test_same_tone,      first_tone_state,      &do_keep_count
               ,first_tone_state,      &test_2nd_tone,            check_tone_range1,      &do_check_range //changed exit test from diff
               ,first_tone_state,      &test_no_tone,            Cant_Tell,            &do_exit
               ,check_tone_range1,      &test_in_limits,      got_half_cycle,            &do_store_result
               ,check_tone_range1,      &test_notin_limits,      unknown_tone,            &do_nothing
               ,got_half_cycle,      &test_****_tone,      Param_Error,            &do_exit
               ,got_half_cycle,      &test_same_tone,      second_tone_state,      &do_keep_count //changed exit test from 2nd_tone
               ,got_half_cycle,      &test_no_tone,            Cant_Tell,            &do_exit
               ,second_tone_state,      &test_****_tone,      Param_Error,            &do_exit
               ,second_tone_state,      &test_same_tone,      second_tone_state,      &do_keep_count
               ,second_tone_state,      &test_diff_tone,      check_tone_range2,      &do_check_range
               ,second_tone_state,      &test_no_tone,            Cant_Tell,            &do_exit
                    ,check_tone_range2,      &test_in_limits,      Busy_Tone,            &do_exit
               ,check_tone_range2,      &test_notin_limits,      check_other_tone,      &do_nothing
               ,check_other_tone,      &test_****_tone,      Param_Error,            &do_exit
               ,check_other_tone,      &test_no_tone,            Cant_Tell,            &do_exit
               ,check_other_tone,      &test_diff_tone,      Not_Busy,            &do_exit
               ,Param_Error,      &test_nothing,            start,                  &do_param_error
               ,Cant_Tell,            &test_nothing,            start,                  &do_cant_tell
               ,Not_Busy,            &test_nothing,            start,                  &do_not_busy
               ,Busy_Tone,            &test_nothing,            start,                  &do_busy_tone
   } ;

//========================= state_reset ====================================
//
//  PURPOSE - reset state machine.
//
void state_reset()
{ state = start ;
  num_state_entries = sizeof(state_table) / sizeof( Tstate_line) ;
}


//========================== drive_one_step ==================================
//
//  PURPOSE : drive the state machine one step using a simple linear search of
//            the state table.  Faster methods include hashing and indexing.
//
void drive_one_step(char ch)
{//--- data inits.
   int          index ;
   Tstate_line *state_line = &state_table[0] ;
   arg_to_test = ch ;

 //--- search through whole table.
   for( index = 0 ; index < num_state_entries ; index++)
    {//--- if the state_line state matches the current state,
     //      and the exit test is true ...
       if (   (   state_line->current_state == state )
           && ( (*state_line->exit_test_ptr)()       )
          )
         {//--- take the action and change the state.
            (*state_line->exit_action)() ;
            state = state_line->next_state ;
            break ; // quit searching through table as got a state change.
         } ;
      ++state_line ; //to next line.
     } ; //endfor.
}

int main(int argc, char *argv[])
{      num_of_tones = 0;
      /*--- When no parameters MUST print id string in CSV format, no comma at the end.*/
   if (argc == 1)  // no parameters.
     { printf("2113232R, s2113232@student.rmit.edu.au, Saurabh Mathur\n") ;
       return(0) ;
     }  
 
 /*--- START YOUR CODE HERE.*/

       //--- drive state machine
   state_reset() ;
   printf("   ") ;
   int i ;
   for ( i = 0 ; i < strlen( argv[1]) ; i++ )
   {
     drive_one_step( argv[1][i]) ;
   }
       printf("\n") ;

   switch (action)
     { case 7 : printf("P\n") ; break ; //PARAMETER ERROR
       case 9 : printf("B\n") ; break ; // DEFINITELY BUSY TONE
       case 10 : printf("N\n") ; break ; //DEFINITELY NOT BUSY
       case 8 : printf("?\n") ; break ; //CANT TELL
     }

   return(0) ;
}
0
Comment
Question by:saumathur
  • 15
  • 14
  • +1
31 Comments
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11760434
What does it print when you run it?

Paul
0
 

Author Comment

by:saumathur
ID: 11760495
say for example i give the input as    ./test 111.......11111
then it recognises all but the last 2 parameters of the command line.

the printf statements is what get printed and in the end, it gets stuck just before it is to get the last 2 arguments.
0
 

Author Comment

by:saumathur
ID: 11760521
basically after it gets to check_tone_range2 it just doesnt carry on...just exits out of the program.. doesnt even check the range
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11760576
That 'should' be impossible. Either 'range' is true or not so either 'test_in_limits' or 'test_notin_limits' MUST return TRUE.

Post the last 20 lines it prints.

Paul
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11760590
Try changing:

void do_check_range()
{
     printf("Number of tones till previous tone were %d\n", num_of_tones);
     if ((num_of_tones > 5) && (num_of_tones) < 10)
     {
          range = TRUE;
          //printf("Range is fine\n");
     }
     else
     {
          range = FALSE;
          //printf("Range is not fine\n");
     }
     num_of_tones = num_of_new_tone;
}

To:

void do_check_range()
{
     printf("Number of tones till previous tone were %d\n", num_of_tones);
     if ((num_of_tones > 5) && (num_of_tones) < 10)
     {
          range = TRUE;
          printf("Range is fine\n");
     }
     else
     {
          range = FALSE;
          printf("Range is not fine\n");
     }
     num_of_tones = num_of_new_tone;
}

and then post us the last 20 lines it prints.

Paul
0
 

Author Comment

by:saumathur
ID: 11760633
this is without the change :

[root@dhcppc0 home]# ./lab2 .111111......1
   First ever tone received which is .
Number of tones = 1
new tone received, which is 1
same tone received, which is 1
Number of tones = 2
same tone received, which is 1
Number of tones = 3
same tone received, which is 1
Number of tones = 4
same tone received, which is 1
Number of tones = 5
same tone received, which is 1
Number of tones = 6
inside 2nd tone testing function
tone is 1 and arg_to_test is .
Second tone received .
Number of tones till previous tone were 6
checkin range
Range is fine
same tone received, which is .
Number of tones = 2
same tone received, which is .
Number of tones = 3
same tone received, which is .
Number of tones = 4
same tone received, which is .
Number of tones = 5
new tone received, which is 1
Number of tones till previous tone were 5
 
the checkin range u see in this one is where it goes into the bool  test_in_limits()
0
 

Author Comment

by:saumathur
ID: 11760724
can u figure it out ????
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11761070
>>Number of tones till previous tone were 5

Clearly shows we are at 'do_check_range' the second time around (state 'second_tone_state') and 'range' is about to be set to 'FALSE' because we only had 5 '.'s.

The next state should therefore be 'check_tone_range2' and 'test_notin_limits' should return 'TRUE' but we are not getting "checkin range" or "Range is not fine".

Perhaps the state table length calculation is failing. Could I suggets you try:

                   { start,          &test_tone,          unknown_tone,          &do_keep_count },
             {start,          &test_****_tone,     Param_Error,          &do_exit},
             {unknown_tone,     &test_****_tone,     Param_Error,          &do_exit},
             {unknown_tone,     &test_same_tone,     unknown_tone,          &do_keep_count},
...

I.E. Add braces around each 'Tstate_line' in the state table to guarantee that the 'num_state_entries = sizeof(state_table) / sizeof( Tstate_line) ;' calculation is correct.

Paul
0
 

Author Comment

by:saumathur
ID: 11761226
Doesnt make a difference...!!!

Did u try to compile the code yourself ??? if thats possible maybe u can find something that i cant
0
 
LVL 16

Accepted Solution

by:
PaulCaswell earned 500 total points
ID: 11761462
Hmm,

I've added:
...
            (*state_line->exit_action)() ;
            state = state_line->next_state ;
                  printf("State=%d\n", state); // ****Added****
            break ; // quit searching through table as got a state change.
...
and the output makes interesting reading. It tells me you are not getting out of 'first_tone_state' when the tone changes. Perhaps that's your problem.

   First ever tone received which is 1
Number of tones = 1
State=1
same tone received, which is 1
Number of tones = 2
State=1
same tone received, which is 1
Number of tones = 3
State=1
same tone received, which is 1
Number of tones = 4
State=1
same tone received, which is 1
Number of tones = 5
State=1
same tone received, which is 1
Number of tones = 6
State=1
new tone received, which is .
State=11
same tone received, which is .
Number of tones = 2
State=11
same tone received, which is .
Number of tones = 3
State=11
same tone received, which is .
Number of tones = 4
State=11
same tone received, which is .
Number of tones = 5
State=11
inside 2nd tone testing function
tone is . and arg_to_test is 1
Second tone received 1
Number of tones till previous tone were 5
State=2


Paul
0
 

Author Comment

by:saumathur
ID: 11761566
hmm..interesting..!!!! how could i fix this ?? in reading, the code appears to be alright, but obvioisly it isnt. do u have any ideas ?
0
 
LVL 22

Expert Comment

by:grg99
ID: 11761582
How about you add a "default:" to the case statement so you can catch any state errors, and use the #defined symbols instead of 7, 8, 9, 10 for the states.

0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11761630
I am sorry but I am prohibited from fixing your problem, I can only provide suggestions as to how you can fix it yourself. I would suggest you draw out a flow chart of your state machine and study it. Please remember that, being an expert, I have my own work to do so you must work on this a bit.

As a general point, putting 'printf's in is a very good way to track down problems with your code.

Paul

P.S. Are you ready to close and assign points to your other question. Members who leave questions open very quickly run out of answers.


0
 

Author Comment

by:saumathur
ID: 11761636
yes but the case statement isnt really being used currently. i cant switch between some states and even though i print out everything it still misbehaves and i dont know why
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11761655
I think Greg was talking about your:

   switch (action)
     { case 7 : printf("P\n") ; break ; //PARAMETER ERROR
       case 9 : printf("B\n") ; break ; // DEFINITELY BUSY TONE
       case 10 : printf("N\n") ; break ; //DEFINITELY NOT BUSY
       case 8 : printf("?\n") ; break ; //CANT TELL
     }

code. He is right but I dont suspect this sectiion of code as a cause of your problem.

Paul
0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:saumathur
ID: 11761663
Paul,

i understand what u are saying. i shall close the first one soon. i just forgot abt that.

coming back to this problem, i think it is getting out of the first_tone_state. its after it gets out of it, goes into the check_tone_range1 and tries to check the limits it is then that something is going amiss.
0
 

Author Comment

by:saumathur
ID: 11761840
No, its not the switch statement. I ran the code again, and its coming out of the second_tone_stage too early to get to the check_tone_range2 state.

Any other ideas as to what wud cause this?
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11761861
You may be expecting too much from your program. Note that each character of input drives the state machine. Also note that '111111.....1' will and should leave you in state 2. As such, everything is working correctly. Perhaps you need to call the state machine a few more times after the last character to see what happens.

Paul
0
 

Author Comment

by:saumathur
ID: 11761974
nah!! 111111......1 should leave me in second_tone_state, which is state 4.
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11762148
Nope! Look at the results I got:

// The last '.' arrives.
same tone received, which is .
Number of tones = 5
// We stay in 'first_tone_state'
State=11
// The '1' comes in. We call test_2nd_tone which detects a new tone and switches to 'check_tone_range1'
inside 2nd tone testing function
tone is . and arg_to_test is 1
Second tone received 1
Number of tones till previous tone were 5
State=2
// No more characters are in the command line so no more state processing is performed!

Paul
0
 

Author Comment

by:saumathur
ID: 11762237
but the thing is...that the last '.' arrives. It is the 6th '.' not the 5th. The sixth one is missed. It only gets the 5th, then it somehow skips the last one. Doesnt it!!!! Im running the program rt now and thats what its doing
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11762384
Ahhhh! I see your problem. I'd suggest you put a 'printf("num_of_tones=%d\n", num_of_tones);' in whenever 'num_of_tones' changes. This shouls help you see where the problem is. Remember that it is possible that your operating system might do something with the '....'. Perhaps you should use quotes (") around the parameter to stop it touching them.

I used five dots for my test run. With six dots I get:

same tone received, which is .
Number of tones = 6
State=11
inside 2nd tone testing function
tone is . and arg_to_test is 1
Second tone received 1
Number of tones till previous tone were 6
State=2

Paul
0
 

Author Comment

by:saumathur
ID: 11762421
when i add more inputs, it seems to get thru more states. cud it be that it is not getting to the final few states cos the parameters are finished ??? and if so, how can i eliminate this?
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11762474
You could try calling the state machine once more at the end with an invalid code, perhaps '*' or something. This might trigger it to complete the process.

Paul
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11763068
How are you capturing your output? Is it possible that you are not capturing all of it?

Paul
0
 

Author Comment

by:saumathur
ID: 11763086
the output is in the form of integers being incremented. and they are being incremented according to the state table at regular intervals, when the same tone is received.
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11763130
Sorry, you misunderstand, I mean the 'printf' output. Is it possible that your program exits before all printing has completed?

To check, add a 'printf ("Bye!");' to the end of the program and make sure it appears.

Paul
0
 

Author Comment

by:saumathur
ID: 11763680
i think it might be right..!!! the printf statement isnt executing..!!  why do u think this is happening
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11763761
It's an operating system thing. Its complicated. If you really want to know, post it as a separate question.

I'd suggest you put something like:

fprintf("Done! Press a key!"); getc ();

at the very end to display a message and wait for a key to be pressed.

Paul
0
 
LVL 16

Expert Comment

by:PaulCaswell
ID: 11763768
Or perhaps

fflush ( stdout );

Paul
0
 
LVL 1

Expert Comment

by:sabrE7
ID: 11951953
Compile the application using

gcc -g -o testapp <prog_name>.c

then run it through gdb (Unix debugger), make sure you use the command 'set args 111........11111.......'

this way you can see for yourself where the program is failing.  That is if you are using Linux like you are supposed to for this project.

0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
This is a short and sweet, but (hopefully) to the point article. There seems to be some fundamental misunderstanding about the function prototype for the "main" function in C and C++, more specifically what type this function should return. I see so…
The goal of this video is to provide viewers with basic examples to understand and use pointers in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now