/**
 * Get the range in millimeters from the ultrasonic sensor.
 * @return double Range in millimeters of the target returned by the ultrasonic sensor.
 * If there is no valid value yet, i.e. at least one measurement hasn't complted, then return 0.
 *
 * @param pingSlot The slot for the digital module for the ping connection
 * @param pingChannel The channel on the digital module for the ping connection
 * @param echoSlot The slot for the digital module for the echo connection
 * @param echoChannel The channel on the digital module for the echo connection
 */
double GetUltrasonicMM(UINT32 pingSlot, UINT32 pingChannel, UINT32 echoSlot, UINT32 echoChannel)
{
	Ultrasonic *us = USptr(pingSlot, pingChannel);
	if (us != NULL)
		return us->GetRangeMM();
	else
		return 0.0;
}
void loop()
{
  Serial.print(ultrasonic.Ranging(CM)); // CM or INC
  Serial.println(" cm" );
  sum = ultrasonic.Ranging(CM) * 5;
  digitalWrite(led, HIGH);
  delay(sum);
  digitalWrite(led, LOW);
  delay(sum);
}
Example #3
0
/**
 * Background task that goes through the list of ultrasonic sensors and pings each one in turn. The counter
 * is configured to read the timing of the returned echo pulse.
 *
 * DANGER WILL ROBINSON, DANGER WILL ROBINSON:
 * This code runs as a task and assumes that none of the ultrasonic sensors will change while it's
 * running. If one does, then this will certainly break. Make sure to disable automatic mode before changing
 * anything with the sensors!!
 */
void Ultrasonic::UltrasonicChecker()
{
	Ultrasonic *u = NULL;
	while (m_automaticEnabled)
	{
		if (u == NULL) u = m_firstSensor;
		if (u == NULL) return;
		if (u->IsEnabled())
			u->m_pingChannel->Pulse(kPingTime);	// do the ping
		u = u->m_nextSensor;
		Wait(0.1);							// wait for ping to return
	}
}
    void AutonomousPeriodic()
    {
        if((Auto==1)||(Auto==2))
        {
            while(gyro.GetAngle()<ang)
            {
                motorspeed=(1/90)*abs(gyro.GetAngle()-ang);
                myRobot.TankDrive(motorspeed/2,motorspeed/-2);
            }
        }
        if((Auto==3)||(Auto==4))
        {
            while(gyro.GetAngle()>ang)
            {
                motorspeed=(1/90)*abs(gyro.GetAngle()-ang);
                myRobot.TankDrive(motorspeed/-2,motorspeed/2);
            }
        }
        while(EncDist.GetDistance()<EncVal1)
        {
            myRobot.Drive(-0.5, 0.0);
        }
        ang = -ang;
        if((Auto==1)||(Auto==2))
        {
            while(gyro.GetAngle()<ang)
            {
                motorspeed=(1/90)*abs(gyro.GetAngle()-ang);
                myRobot.TankDrive(motorspeed/2,motorspeed/-2);
            }
        }
        if((Auto==3)||(Auto==4))
        {
            while(gyro.GetAngle()>ang)
            {
                motorspeed=(1/90)*abs(gyro.GetAngle()-ang);
                myRobot.TankDrive(motorspeed/-2,motorspeed/2);
            }
        }
        launcher.Set(1.0);
        sonic.SetAutomaticMode(true);
        while(sonic.GetRangeInches()>DefToShot)
        {
            myRobot.Drive(-0.5,0.0);
        }
        myRobot.Drive(0.0,0.0);
        intake.Set(1.0);

    }
Example #5
0
void app_start(int, char**) {
	srand(time(NULL));

	mbed_trace_init();

	tr_info("Application start");
	tr_info("Set I2C frequency");
	i2c.frequency(400000);

	tr_info("Initialize user interface module");
	oled = new Adafruit_SSD1306_I2c(i2c, YOTTA_CFG_HARDWARE_PINS_D2);
	mcp_keys = new MCP23008(i2c);
	for(uint8_t i = 0; i < 4; ++i) {
		mcp_keys->setup(i, MCP23008::IN);
		mcp_keys->pullup(i, true);
	}

	tr_info("Initialize state object");
	state = new State(i2c);

	tr_info("First screen out");
	state->startup_phase = State::STARTUP_CONF;
	scr = new SplashScreen(*oled, *state);
	scr->render();

	tr_info("Load config");
	state->config.load();

	state->startup_phase = State::STARTUP_NM;
	scr->render();

	tr_info("Start NetworkManager");
	wait_ms(100);
	nm = new NetworkManager(PIN_ESP_TX, PIN_ESP_RX, 9600);
	state->nm = nm;

	state->startup_phase = State::STARTUP_FIN;
	scr->render();
	
	tr_info("Start ultrasonic measuring");
	ultrasonic.start_measure();

	tr_info("Hook up routine functions");
	minar::Scheduler::postCallback(leave_splash).delay(minar::milliseconds(500));
	minar::Scheduler::postCallback(poll_key).period(minar::milliseconds(50));
	minar::Scheduler::postCallback(screen_render).period(minar::milliseconds(100));
	minar::Scheduler::postCallback(read_distance).period(minar::milliseconds(300));

	tr_info("Start process completed");
}
Example #6
0
static void read_distance(void) {
	float previous = state->distance;
	float read = ultrasonic.get_distance();
	if(read > state->config.can_height) {
		read = state->config.can_height;
	}
	if(read < 0) return;
	float delta = previous - read;
	if(delta > 10 || delta < -10) {
		if(state->distance_change++ == 5) {
			state->distance_change = 0;
			state->distance = read;
			state->level = (state->config.can_height - read) / state->config.can_height * 100;
		} else {
			read = previous - (delta * state->distance_change / 5);
			state->distance = read;
			state->level = (state->config.can_height - read) / state->config.can_height * 100;
		}
	} else {
		state->distance_change = 0;
		state->distance = read;
		state->level = (state->config.can_height - read) / state->config.can_height * 100;
	}
}
Example #7
0
/*----------------------------------------
*
* Start the massive Gcode processing loop
*-----------------------------------------
*/
void process_commands()
{
  int result;
  int motorChannel, motorPower;
  unsigned long codenum;
  char *starpos = NULL;
  
  if(code_seen('G'))
  {
    switch((int)code_value())
    {
    case 0: // G0 -> G1
    case 1: // G1
      break;
	  
    case 2:
	  break;
	  
    case 3:
	  break;
	  
    case 4: // G4 dwell
      //LCD_MESSAGEPGM(MSG_DWELL);
      codenum = 0;
      if(code_seen('P')) codenum = code_value(); // milliseconds to wait
      if(code_seen('S')) codenum = code_value() * 1000; // seconds to wait

      //codenum += millis();  // keep track of when we started waiting
      previous_millis_cmd = 0;//millis();
      while(++previous_millis_cmd  < codenum ){
        manage_inactivity();
		_delay_ms(1);
      }
      break;
	  
	case 5: // G5 - Absolute command motor C<Channel> P<motor power -1000 to 1000>
	     if(!Stopped) {
		     if(code_seen('C')) {
				motorChannel = code_value(); // motor channel 1,2
				if(code_seen('P')) {
					motorPower = code_value(); // motor power -1000,1000
					fault = 0; // clear fault flag
					motorControl->commandMotorPower(motorChannel, motorPower);
				} // code P
			 } // code C
	     } // stopped
	     break;
		 
    case 28:
      previous_millis_cmd = 0;
      break;
	  
    case 90: // G90
      break;
	  
    case 91: // G91
      break;
	  
    case 92: // G92
      break;
	  
	case 99: // G99 start watchdog timer. G99 T<time_in_millis> values are 15,30,60,120,250,500,1000,4000,8000 default 4000
		if( code_seen('T') ) {
			int time_val = code_value();
			watchdog_timer = new WatchdogTimer();
			watchdog_timer->watchdog_init(time_val);
		}
		break;
		
	case 100: // G100 reset watchog timer before time interval is expired, otherwise a reset occurs
		if( watchdog_timer != NULL )
			watchdog_timer->watchdog_reset();
		break;
		
    } // switch
  } // if code
  /*-------------------------------------
  * M Code processing
  *--------------------------------------
  */
  else if(code_seen('M'))
  {
    switch( (int)code_value() )
    {
	case 0: // M0 Set real time output off
		realtime_output = 0;
		break;
		
	case 1: // M1 Set real time output on
		realtime_output = 1;
		break;
		
	case 2: // M2 [C<channel> E<encoder pin>] set smart controller (default) with optional encoder pin per channel
		motor_status = 0;
		motorControl = &roboteqDevice;
		if(code_seen('C')) {
			channel = code_value();
			if(code_seen('E')) {
				pin_number = code_value();
				motorControl->createEncoder(channel, pin_number);
			}
		}
		break;
		
	//Set PWM motor driver, map pin to channel, this will check to prevent free running motors during inactivity
	//For a PWM motor control subsequent G5 commands are affected here. 	
	case 3: // M3 P<pin> C<channel> D<direction pin> E<default dir> W<encoder pin> [T<timer mode 0-3>] [R<resolution 8,9,10 bits>] [X<prescale 0-7>]
	  motor_status = 1;
	  pin_number = -1;
	  encode_pin = 0;
	  motorControl = (AbstractMotorControl*)&hBridgeDriver;
	  ((HBridgeDriver*)motorControl)->setMotors((PWM**)&ppwms);
	  ((HBridgeDriver*)motorControl)->setDirectionPins((Digital**)&pdigitals);
	  if(code_seen('P'))
          pin_number = code_value();
	  else
		 break;
      if(code_seen('C')) {
        channel = code_value();
		if( code_seen('D'))
			dir_pin = code_value();
		else 
			break;
		if( code_seen('E'))
			dir_default = code_value();
		else
			break;
		if( code_seen('W')) 
			encode_pin = code_value(); 
		((HBridgeDriver*)motorControl)->createPWM(channel, pin_number, dir_pin, dir_default, timer_pre, timer_res);
		if(encode_pin)
			motorControl->createEncoder(channel, encode_pin);
      } // code C
	  break;
	
	case 4:
		// BLDC motor
		// BLDC: lo1,lo2,lo3,hi1,hi2,hi3,hall1,hall2,hall3,enable
		// hall sensors hall1:bit0,hall2:bit1,hall2:bit2 of commu array offset
		// BLDC3PhaseSensor* tmotor1 = new BLDC3PhaseSensor(29,31,33,8,9,10,64,65,66);
		// tmotor2 = new BLDC3PhaseSensor(35,37,39,11,12,13,67,68,69,30);
		// tmotor1->motor_init();
		// tmotor2->Motor_init();
		break;
		
	case 11: // M11 C<channel> D<duration> Set maximum motor cycle duration for given channel.
		if( code_seen('C') ) {
			channel = code_value();
			if( code_seen('D') )
				motorControl->setDuration(channel, code_value());
		}
	break;
	
	case 12: // M12 C<channel> P<offset> set amount to add to G5 for min motor power
		if( code_seen('C') ) {
			channel = code_value();
			if( code_seen('P'))
				motorControl->setMinMotorPower(channel, code_value());
		}
		break;
			 	
    case 17:
      break;
	  
	case 18: //M18
	  break;
	  
	case 31: //M31 take time since the start of the SD print or an M109 command
      stoptime=0;//millis();
      char time[30];
      t =(stoptime-starttime)/1000;
      int sec,min;
      min=t/60;
      sec=t%60;
      sprintf_P(time, PSTR("%i min, %i sec"), min, sec);
      SERIAL_PGMLN(timeCntrlHdr);
	  SERIAL_PGM("1 ");
      SERIAL_PORT.println(time);
	  SERIAL_PORT.flush();
      //lcd_setstatus(time);
      //autotempShutdown();
      break;
	  
	case 33: // M33 P<ultrasonic pin> D<min. distance in cm> [E<direction 1- forward facing, 0 - reverse facing sensor>] 
	// link Motor controller to ultrasonic sensor, the sensor must exist via M301
	  motor_status = 1;
	  pin_number = 0;
	  if(code_seen('P')) {
        pin_number = code_value();
		if( code_seen('D'))
			dist = code_value();
		else 
			break;
		dir_face = 1; // default forward
		if( code_seen('E'))
			dir_face = code_value(); // optional
		motorControl->linkDistanceSensor((Ultrasonic**)psonics, pin_number, dist, dir_face);
	  } // code_seen = 'P'
	  break;
	  
	  case 35: //M35 - Clear all digital pins
		for(int i = 0; i < 10; i++) {
			 if(pdigitals[i]) {
				unassignPin(pdigitals[i]->pin);
				delete pdigitals[i];
				pdigitals[i] = 0;
			 }
		}
	  break;
		  
	  case 36: //M36 - Clear all analog pins
		  	 for(int i = 0; i < 10; i++) {
			  	  if(panalogs[i]) {
					unassignPin(panalogs[i]->pin);
				  	delete panalogs[i];
					panalogs[i] = 0;
			  	  }
		  	 }
	  break;
	  
	  case 37: //M36 - Clear all PWM pins
	  for(int i = 0; i < 10; i++) {
		  if(ppwms[i]) {
			  unassignPin(ppwms[i]->pin);
			  delete ppwms[i];
			  ppwms[i] = 0;
		  }
	  }
	  break;
	  
	  case 38: //M38 - Remove PWM pin P<pin>
	  	  pin_number = -1;
	  	  if (code_seen('P')) {
		  	  pin_number = code_value();
		  	  if(unassignPin(pin_number) ) {
			  	  for(int i = 0; i < 10; i++) {
				  	  if(ppwms[i] && ppwms[i]->pin == pin_number) {
					  	  delete ppwms[i];
						  ppwms[i] = 0;
				  	  } // pwms == pin_number
			  	  } // i iterate pwm array
		  	  } // unassign pin
	  	  } // code P
	  break;
	  
	  case 39: //M39 - Remove Persistent Analog pin P<pin>
	  	  pin_number = -1;
	  	  if (code_seen('P')) {
		  	  pin_number = code_value();
		  	  if(unassignPin(pin_number) ) {
			  	  for(int i = 0; i < 10; i++) {
				  	  if(panalogs[i] && panalogs[i]->pin == pin_number) {
					  	delete panalogs[i];
						panalogs[i] = 0;
					    break;
				  	  }
			  	  }
		  	  }
	  	  }
	  break;
			
	  case 40: //M40 - Remove persistent digital pin P<pin>
	       pin_number = -1;
	       if (code_seen('P')) {
		       pin_number = code_value();
		       if(unassignPin(pin_number) ) {
			       for(int i = 0; i < 10; i++) {
				       if(pdigitals[i] && pdigitals[i] == pin_number) {
					       delete pdigitals[i];
						   pdigitals[i] = 0;
					       break;
				       }
			       }
			   }
		   }
	  break;
		
	  case 41: //M41 - Create persistent digital pin, Write digital pin HIGH P<pin> (this gives you a 5v source on pin)
	     pin_number = -1;
	     if (code_seen('P')) {
		     pin_number = code_value();
		     if( assignPin(pin_number) ) {
			     dpin = new Digital(pin_number);
				 dpin->setPin(pin_number);
			     dpin->pinMode(OUTPUT);
			     dpin->digitalWrite(HIGH);
			     for(int i = 0; i < 10; i++) {
				     if(!pdigitals[i]) {
					     pdigitals[i] = dpin;
					     break;
				     }
			     }
			 } else {
			     for(int i = 0; i < 10; i++) {
				     if(pdigitals[i] && pdigitals[i]->pin == pin_number) {
						 pdigitals[i]->setPin(pin_number);
						 pdigitals[i]->pinMode(OUTPUT);
					     pdigitals[i]->digitalWrite(HIGH);
					     break;
				     }
			     }
		     }
	     }
	break;
	     
    case 42: //M42 - Create persistent digital pin, Write digital pin LOW P<pin> (This gives you a grounded pin)
	  pin_number = -1;
	  if (code_seen('P')) {
        pin_number = code_value();
		if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(OUTPUT);
			dpin->digitalWrite(LOW);
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = dpin;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == pin_number) {
					pdigitals[i]->setPin(pin_number);
					pdigitals[i]->pinMode(OUTPUT);
					pdigitals[i]->digitalWrite(LOW);
					break;
				}
			}
		}
	  }
     break;
	 
	case 43: // M43 Read from digital pin P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
   		if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(INPUT);
			int res = dpin->digitalRead();
			delete &dpin;
			unassignPin(pin_number); // reset it since this is a one-shot
			SERIAL_PGMLN(digitalPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.println();
			SERIAL_PORT.flush();
		}
		break;
	
	case 44: // M44 -Read digital pin with pullup P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
    	if( assignPin(pin_number) ) {
			dpin = new Digital(pin_number);
			dpin->pinMode(INPUT_PULLUP);
			int res = dpin->digitalRead();
			delete &dpin;
			unassignPin(pin_number); // reset it since this is a one-shot
			SERIAL_PGMLN(digitalPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.flush();
		}
		break;
		
	 // PWM value between 0 and 255, default timer mode is 2; clear on match, default resolution is 8 bits, default prescale is 1
	 // Prescale: 1,2,4,6,7,8,9 = none, 8, 64, 256, 1024, external falling, external rising
	 // Use M445 to disable pin permanently or use timer more 0 to stop pulse without removing pin assignment
     case 45: // M45 - set up PWM P<pin> S<power val 0-255> [T<timer mode 0-3>] [R<resolution 8,9,10 bits>] [X<prescale 0-7>]
	  pin_number = -1;
	  if(code_seen('P') )
          pin_number = code_value();
	  else
		 break;
      if (code_seen('S')) {
        int pin_status = code_value();
		int timer_mode = 2;
		int timer_res = 8;
		int timer_pre = 1;
		
		if( pin_status < 0 || pin_status > 255)
			pin_status = 0;
		// this is a semi-permanent pin assignment so dont add if its already assigned
		if( assignPin(pin_number) ) {
			// timer mode 0-3: 0 stop, 1 toggle on compare match, 2 clear on match, 3 set on match (see HardwareTimer)
			if( code_seen('T') ) {
				timer_mode = code_value();
				if( timer_mode < 0 || timer_mode > 3 )
					timer_mode = 0;
			}
			// timer bit resolution 8,9, or 10 bits
			if( code_seen('R')) {
				timer_res = code_value();
				if( timer_res < 8 || timer_res > 10 )
					timer_res = 8;
			}
			// X - prescale 0-7 for power of 2
			if( code_seen('X') ) {
				timer_pre = code_value();
				if( timer_pre < 0 || timer_pre > 7 )
					timer_pre = 0;
			}
			for(int i = 0; i < 10; i++) {
				if(ppwms[i] == NULL) {
					ppin = new PWM(pin_number);
					ppin->init(pin_number);
					ppin->setPWMPrescale(timer_pre);
					ppin->setPWMResolution(timer_res);
					ppin->pwmWrite(pin_status,timer_mode); // default is 2, clear on match. to turn off, use 0
					ppwms[i] = ppin;
					break;
				}
			}
		 } else { // reassign pin with new mode and value
			 for(int i = 0; i < 10; i++) {
				 if(ppwms[i] && ppwms[i]->pin == pin_number) {
					 // timer mode 0-3: 0 stop, 1 toggle on compare match, 2 clear on match, 3 set on match (see HardwareTimer)
					 if( code_seen('T') ) {
						 timer_mode = code_value();
						 if( timer_mode < 0 || timer_mode > 3 )
							timer_mode = 2; // mess up the code get clear on match default
					 }
					 //ppwms[i]->init();
					 ppwms[i]->pwmWrite(pin_status, timer_mode);
					 break;
				 }
			 }
		 }
      }
	  break;
	  
	  case 46: // M46 -Read analog pin P<pin>
        pin_number = -1;
        if (code_seen('P'))
          pin_number = code_value();
		if( assignPin(pin_number) ) {
			apin = new Analog(pin_number);
			int res = apin->analogRead();
			res = apin->analogRead(); // de-jitter
			delete &apin;
			unassignPin(pin_number);
			SERIAL_PGMLN(analogPinHdr);
			SERIAL_PGM("1 ");
			SERIAL_PORT.println(pin_number);
			SERIAL_PGM("2 ");
			SERIAL_PORT.println(res);
			SERIAL_PORT.flush();
		}
     break;
	 
     case 80: // M80 - Turn on Power Supply
	  #if defined(PS_ON_PIN) && PS_ON_PIN > -1
        SET_OUTPUT(PS_ON_PIN); //GND
        WRITE(PS_ON_PIN, PS_ON_AWAKE);
        // If you have a switch on suicide pin, this is useful
        #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1
            SET_OUTPUT(SUICIDE_PIN);
            WRITE(SUICIDE_PIN, HIGH);
        #endif
      #endif
	  break;

     case 81: // M81 - Turn off Power
      if( motorControl->isConnected())
		motorControl->commandEmergencyStop();
      #if defined(SUICIDE_PIN) && SUICIDE_PIN > -1
        suicide();
      #elif defined(PS_ON_PIN) && PS_ON_PIN > -1
        SET_OUTPUT(PS_ON_PIN);
        WRITE(PS_ON_PIN, PS_ON_ASLEEP);
      #endif
	    _delay_ms(1000); // Wait 1 sec before switch off
	  break;

    case 82:
      break;
	  
    case 83:
      break;
	  
    case 84: // M84
      break;
	  
    case 85: // M85
      break;
	  
    case 92: // M92
      break;
	  
	case 104: // M104
      break;
	  
    case 105 : // M105
      SERIAL_PORT.println();
      break; 
	   
    case 106: //M106
        break;
		
    case 107: //M107
        break;
	
    case 109: // M109 
      break;
	  
    case 115: // M115
      SERIAL_PGMLN(MSG_M115_REPORT);
      break;
	  
    case 117: 
      break;
	  
    case 114: // M114
      break;
	  
    case 120: // M120
      break;
	  
    case 121: // M121
      break;
	  
    case 119: // M119
      break; 
	  
	case 140: // M140 
      break;
	  
    case 150: // M150 - set an RGB value
        byte red;
        byte grn;
        byte blu;
        if(code_seen('R')) red = code_value();
        if(code_seen('U')) grn = code_value();
        if(code_seen('B')) blu = code_value();
        //SendColors(red,grn,blu);
      break;
	  
	case 190: // M190
      break;
	  
    case 200:
      break;
	  
    case 201: // M201
      //reset_acceleration_rates();
      break;
	  
    case 202: // M202
      break;
	  
    case 203:
      break;
	  
    case 204: // M204 acceleration T
      if(code_seen('T')) ;//max_acceleration = code_value();
      break;
	  
    case 205: //M205 advanced settings:  maximum travel speed T=travel
      if(code_seen('T')) ;//maxtravelspeed = code_value();
	  break;
	
    case 206: 
      break;
	  
    case 207:
	  break;
	  
    case 208:
      break;
	  
    case 209: 
	  break;
	  
    case 218:
	  break;
	  
    case 220: 
      if(code_seen('S'))
      {
        
      }
    break;
	
    case 221: 
      if(code_seen('S'))
      {
        
      }
    break;

	case 226: // M226 P<pin number> S<pin state>- Wait until the specified pin reaches the state required, default is opposite current state
      if(code_seen('P')) {
        int pin_number = code_value(); // pin number
        int pin_state = -1; // required pin state - default is inverted
        if(code_seen('S')) 
			pin_state = code_value(); // required pin state
		if( assignPin(pin_number) ) {
			Digital pn = new Digital(pin_number);
            pn.pinMode(INPUT);
            int target;
            switch(pin_state){
				case 1:
					target = HIGH;
					break;
				case 0:
					target = LOW;
					break;
				default:
					target = !pn.digitalRead(); // opposite of current state
					break;
            } // switch
            while(pn.digitalRead() != target) {
              manage_inactivity();
            } // while
			delete &pn;
			unassignPin(pin_number);
          } // if pin_number
      } // code seen p
    break;

	case 227: // M227 P<pin number> S<pin state>- INPUT_PULLUP Wait until the specified pin reaches the state required, default is opposite current state
	if(code_seen('P')) {
		int pin_number = code_value(); // pin number
		int pin_state = -1; // required pin state - default is inverted
		if(code_seen('S'))
		pin_state = code_value(); // required pin state
		if( assignPin(pin_number) ) {
			Digital pn = new Digital(pin_number);
			pn.pinMode(INPUT_PULLUP);
			int target;
			switch(pin_state){
				case 1:
				target = HIGH;
				break;
				case 0:
				target = LOW;
				break;
				default:
				target = !pn.digitalRead(); // opposite of current state
				break;
			} // switch
			while(pn.digitalRead() != target) {
				manage_inactivity();
			} // while
			delete &pn;
			unassignPin(pin_number);
		} // if pin_number
	} // code seen p
	break;
		
	case 240: // M240  Triggers a camera by emulating a Canon RC-1 : http://www.doc-diy.net/photo/rc-1_hacked/
	/*
      #if defined(PHOTOGRAPH_PIN) && PHOTOGRAPH_PIN > -1
        const uint8_t NUM_PULSES=16;
        const float PULSE_LENGTH=0.01524;
        for(int i=0; i < NUM_PULSES; i++) {
          WRITE(PHOTOGRAPH_PIN, HIGH);
          _delay_ms(PULSE_LENGTH);
          WRITE(PHOTOGRAPH_PIN, LOW);
          _delay_ms(PULSE_LENGTH);
        }
        delay(7.33);
        for(int i=0; i < NUM_PULSES; i++) {
          WRITE(PHOTOGRAPH_PIN, HIGH);
          _delay_ms(PULSE_LENGTH);
          WRITE(PHOTOGRAPH_PIN, LOW);
          _delay_ms(PULSE_LENGTH);
        }
      #endif
	  */
    break;
	
	case 250: 
      break;
	
    case 280: 
      break;

    case 300: // M300 - emit ultrasonic pulse on given pin and return duration P<pin number>
      uspin = code_seen('P') ? code_value() : 0;
      if (uspin > 0) {
		Ultrasonic* upin = new Ultrasonic(uspin);
		pin_number = upin->getPin();
		SERIAL_PGMLN(sonicCntrlHdr);
		SERIAL_PGM("1 "); // pin
		SERIAL_PORT.println(pin_number);
		SERIAL_PGM("2 "); // sequence
		SERIAL_PORT.println(upin->getRange()); // range
		delete upin;
      }
    break;
		
    case 301: // M301 - toggle ultrasonic during inactivity P<pin>
		// wont assign pin 0 as its sensitive
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!psonics[i]) {
					psonics[i] = new Ultrasonic(uspin);
					break;
				}
			}
		}
		break;
	
	case 302: // M302 - disable ultrasonic during inactivity P<pin>
		uspin = code_seen('P') ? code_value() : 0;
		unassignPin(uspin);
		for(int i = 0; i < 10; i++) {
				if(psonics[i] && psonics[i] == uspin) {
					delete psonics[i];
					psonics[i] = 0;
					break;
				}
		}
      break;
	
	case 303: // M303 - toggle analog read during inactivity P<pin> with exclusion range 0-1024 via L<min> H<max> if present
		// wont assign pin 0 as its sensitive
		// if optional L and H values exclude readings in that range
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!panalogs[i]) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					panalogs[i] = new Analog(uspin);
					panalogs[i]->pinMode(INPUT);
					break;
				}
			}
		} else { // reassign values for assigned pin
			for(int i = 0; i < 10; i++) {
				if(panalogs[i] && panalogs[i]->pin == uspin) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					break;
				}
			}
		}
      break;
	  
	case 304:// M304 - toggle analog read INPUT_PULLUP during inactivity P<pin> with exclusion range 0-1024 via L<min> H<max> if present
		// if optional L and H values exclude readings in that range
		uspin = code_seen('P') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!panalogs[i]) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					panalogs[i] = new Analog(uspin);
					panalogs[i]->pinMode(INPUT_PULLUP);
					break;
				}
			}
		} else { // reassign values for assigned pin
			for(int i = 0; i < 10; i++) {
				if(panalogs[i] && panalogs[i]->pin == uspin) {
					analogRanges[0][i] = code_seen('L') ? code_value() : 0;
					analogRanges[1][i] = code_seen('H') ? code_value() : 0;
					break;
				}
			}
		}
      break;
	
	case 305: // M305 - toggle digital read during inactivity M305 P<pin> T<target> 0 or 1 for target value, default 0
		// wont assign pin 0 as its sensitive
		// Looks for target value for pin during inactive, if so publish with <digitalpin> header and 1 - pin, 2 - value
		uspin = code_seen('P') ? code_value() : 0;
		digitarg = code_seen('T') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = new Digital(uspin);
					pdigitals[i]->pinMode(INPUT);
					digitalTarget[i] = digitarg;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == uspin) {
					digitalTarget[i] = digitarg;
					break;
				}
			}
		}
      break;
	
	case 306:// M306 - INPUT_PULLUP toggle digital read during inactivity M306 P<pin> T<target> 0 or 1 for target value, default 0
		// Looks for target value for pin during inactive, if so publish with <digitalpin> header and 1 - pin 2 - value
		uspin = code_seen('P') ? code_value() : 0;
		digitarg = code_seen('T') ? code_value() : 0;
		// this is a permanent pin assignment so dont add if its already assigned
		if( assignPin(uspin) ) {
			for(int i = 0; i < 10; i++) {
				if(!pdigitals[i]) {
					pdigitals[i] = new Digital(uspin);
					pdigitals[i]->pinMode(INPUT_PULLUP);
					digitalTarget[i] = digitarg;
					break;
				}
			}
		} else {
			for(int i = 0; i < 10; i++) {
				if(pdigitals[i] && pdigitals[i]->pin == uspin) {
					digitalTarget[i] = digitarg;
					break;
				}
			}
		}
		break;
	
    case 349: // M349
	/*
        if(code_seen('P')) bedKp = code_value();
        if(code_seen('I')) bedKi = scalePID_i(code_value());
        if(code_seen('D')) bedKd = scalePID_d(code_value());

        updatePID();
        SERIAL_PROTOCOL(MSG_OK);
        SERIAL_PROTOCOL(" p:");
        SERIAL_PROTOCOL(bedKp);
        SERIAL_PROTOCOL(" i:");
        SERIAL_PROTOCOL(unscalePID_i(bedKi));
        SERIAL_PROTOCOL(" d:");
        SERIAL_PROTOCOL(unscalePID_d(bedKd));
        SERIAL_PROTOCOLLN("");
		*/
      break;
	  
   case 350:
    break;
	
   case 351: 
      break;
	  
    case 400:
      
    break;
	
    case 401:
        
    break;
	
    case 402:
        
    break;
	
	case 444: // M444 - set battery warning threshold V<volts*10>!!!!!!!!!!!!!!!!!! REMEMBER ITS TIMES 10 !!!!!!!!!!!!!!!!!!
	    if(code_seen('V')) {
			BatteryThreshold = code_value(); // times 10!!!
		}
		break;
		
	case 445: // M445 - Turn off pulsed write pin - disable PWM P<pin>
      pin_number = -1;
      if (code_seen('P'))
          pin_number = code_value();
	  unassignPin(pin_number);
	  for(int i = 0; i < 10; i++) {
			if(ppwms[i] && ppwms[i] == pin_number) {
				ppwms[i]->pwmWrite(0,0); // default is 2, clear on match. to turn off, use 0 
				delete ppwms[i];
				ppwms[i] = 0;
				break;
			}
	  }
	  break;
	  
    case 500: // M500 Store settings in EEPROM
        Config_StoreSettings();
    break;
	
    case 501: // M501 Read settings from EEPROM
        Config_RetrieveSettings();
    break;
	
    case 502: // M502 Revert to default settings
        Config_ResetDefault();
    break;
	
    case 503: // M503 print settings currently in memory
        Config_PrintSettings();
    break;
	
    case 540:
        //if(code_seen('S')) abort_on_endstop_hit = code_value() > 0;
    break;
	
    case 600: 
    break;
	
    case 605: 
    break;
	
	case 666:
    break;
	  
	case 700: // return stats
	  // Check startup - does nothing if bootloader sets MCUSR to 0
	  mcu = MCUSR;
	  if(mcu & 1) SERIAL_PGMLN(MSG_POWERUP);
	  if(mcu & 2) SERIAL_PGMLN(MSG_EXTERNAL_RESET);
	  if(mcu & 4) SERIAL_PGMLN(MSG_BROWNOUT_RESET);
	  if(mcu & 8) SERIAL_PGMLN(MSG_WATCHDOG_RESET);
	  if(mcu & 32) SERIAL_PGMLN(MSG_SOFTWARE_RESET);
	  MCUSR=0;
	  SERIAL_PGM(VERSION_STRING);
	  #ifdef STRING_VERSION_CONFIG_H
	  #ifdef STRING_CONFIG_H_AUTHOR
	  SERIAL_PGM(MSG_CONFIGURATION_VER);
	  SERIAL_PGM(STRING_VERSION_CONFIG_H);
	  SERIAL_PGM(MSG_AUTHOR);
	  SERIAL_PGMLN(STRING_CONFIG_H_AUTHOR);
	  SERIAL_PGM("Compiled: ");
	  SERIAL_PGM(__DATE__);
	  #endif
	  #endif
	  SERIAL_PGM(MSG_FREE_MEMORY);
	  SERIAL_PORT.println(freeMemory());
	  SERIAL_PORT.flush();
	  break; 
	  
	case 701: // Report digital pins in use
		SERIAL_PGMLN("Digital Pins:");
		for(int i = 0; i < 10; i++) {
			if( pdigitals[i] ) {
				SERIAL_PORT.print(pdigitals[i]->pin);
				switch(pdigitals[i]->mode) {
					case INPUT:
						SERIAL_PGMLN(" INPUT");
						break;
					case INPUT_PULLUP:
						SERIAL_PGMLN(" INPUT_PULLUP");
						break;
					case OUTPUT:
						SERIAL_PGMLN(" OUTPUT");
						break;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 702: // Report analog pins in use
		SERIAL_PGMLN("Analog Pins:");
		for(int i = 0; i < 10; i++) {
			if( panalogs[i]  ) {
				SERIAL_PORT.print(panalogs[i]->pin);
				switch(panalogs[i]->mode) {
					case INPUT:
					SERIAL_PGMLN(" INPUT");
					break;
					case INPUT_PULLUP:
					SERIAL_PGMLN(" INPUT_PULLUP");
					break;
					case OUTPUT:
					SERIAL_PGMLN(" OUTPUT");
					break;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 703: // Report ultrasonic pins in use
		SERIAL_PGMLN("Ultrasonic Pins:");
		for(int i = 0; i < 10; i++) {
			if( psonics[i] ) {
				SERIAL_PGM("Pin:");
				SERIAL_PORT.println(psonics[i]->getPin());
			}
		}
		SERIAL_PORT.flush();
		break;
		
	case 704: // Report PWM pins in use
		SERIAL_PGMLN("PWM Pins:");
		for(int i = 0; i < 10; i++) {
			if( ppwms[i] ) {
				SERIAL_PGM("Pin:");
				SERIAL_PORT.print(ppwms[i]->pin);
				SERIAL_PGM(" Timer channel:");
				SERIAL_PORT.print(ppwms[i]->channel);
				switch(ppwms[i]->mode) {
					case INPUT:
						SERIAL_PGM(" INPUT");
						break;
					case INPUT_PULLUP:
						SERIAL_PGM(" INPUT_PULLUP");
						break;
					case OUTPUT:
						SERIAL_PGM(" OUTPUT");
						break;
				}
				SERIAL_PORT.println();
			}
			SERIAL_PORT.flush();
		}
		break;
		
	case 705:
			// see if it has propulsion attributes declared with M3 as interrupt serviced
			switch(motor_status) {
				case 0:
					SERIAL_PGMLN("Multi Channel Motor Controller:");
					break;
				case 1:
					SERIAL_PGMLN("H-Bridge Brushed DC Motor Driver(s):");
					break;
				case 2:
					SERIAL_PGMLN("Brushless DC Motor Driver(s):");
					break;
			}
			for(int i = 0 ; i < motorControl->getChannels(); i++) { //per channel
					SERIAL_PGM("Motor channel:");
					SERIAL_PORT.print(i+1);
					SERIAL_PGM(" Min Power:");
					SERIAL_PORT.print(motorControl->getMinMotorPower(i+1));
					SERIAL_PGM(" Speed:");
					SERIAL_PORT.print(motorControl->getMotorSpeed(i+1));
					SERIAL_PGM(" Curr. Dir:");
					SERIAL_PORT.print(motorControl->getCurrentDirection(i+1));
					SERIAL_PGM(" Default. Dir:");
					SERIAL_PORT.println(motorControl->getDefaultDirection(i+1));
					SERIAL_PGM(" Encoder Pin:");
					if(motorControl->getWheelEncoder(i+1)) {
						SERIAL_PORT.print(motorControl->getWheelEncoder(i+1)->pin);
						SERIAL_PGM(" Count:");
						SERIAL_PORT.print(motorControl->getEncoderCount(i+1));
						SERIAL_PGM(" Duration:");
						SERIAL_PORT.println(motorControl->getMaxMotorDuration(i+1));
					} else {
						SERIAL_PGMLN("None.");
					}
			}
			SERIAL_PGM("Ultrasonic pins:");
			if( motorControl->totalUltrasonics() ) {
				SERIAL_PORT.println(motorControl->totalUltrasonics());
				for(int j = 0; j < motorControl->totalUltrasonics(); j++) {
					SERIAL_PGM("Pin:");
					SERIAL_PORT.print(psonics[motorControl->getUltrasonicIndex(i+1)]->getPin());
					SERIAL_PGM(" Facing:");
					SERIAL_PORT.print(motorControl->getUltrasonicFacing(i+1));
					SERIAL_PGM(" Shutdown cm:");
					SERIAL_PORT.println(motorControl->getMinMotorDist(i+1));
				}
			} else {
						SERIAL_PGMLN("None.");
			}
			SERIAL_PORT.flush();
			break;
			
	case 706: // Report all pins in use
		for(int i = 0; i < 100; i++) {
			if( pinAssignment(i) == PIN_ASSIGNED ) {
				SERIAL_PORT.print(i);
				SERIAL_PORT.print(',');
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;
		
	case 797:
		break;
		
	case 798: // Report controller status
		//SERIAL_PGMLN(motorCntrlHdr);
		if( motorControl->isConnected() ) {
			for(int i = 0; i < motorControl->getChannels() ; i++ ) {
				SERIAL_PGM("Motor Channel:");
				SERIAL_PORT.println(i+1);
				char* buf = motorControl->getDriverInfo(i+1);
				while(*buf) {
					SERIAL_PORT.print(*buf);
					buf++;
				}
			}
		}
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;	
		
	case 799: // Reset Motor controller
		motorControl->commandEmergencyStop();
		break;		
		
	case 800: 
		break;
		
	case 801: // IMU
		prh = new PitchRollHeading();
		orient = prh->getPitchRollHeading();
		SERIAL_PGMLN(posCntrlHdr);
		SERIAL_PGM("1 ");
		SERIAL_PORT.println(orient.pitch);
		SERIAL_PGM("2 ");
		SERIAL_PORT.println(orient.roll);
		SERIAL_PGM("3 ");
		SERIAL_PORT.println(orient.heading);
		break;	
			
	case 802: // Acquire analog pin data M802 Pnn Sxxx Mxxx P=Pin number, S=number readings, M=microseconds per reading. X - pullup.
		// Publish <dataset> 1 - pin, 2 - reading
		if( code_seen('P')) {
			apin = new Analog((uint8_t)code_value());
			if( code_seen('X') )
				apin->pinMode(INPUT_PULLUP);
			else
				apin->pinMode(INPUT);
		}
		nread = 0;
		if( code_seen('S') ) {
			nread = code_value();
		}
		micros = 0;
		if( code_seen('M')) {
			micros = (uint32_t)code_value();
		}
		values = new int(nread);
		for(int i = 0; i < nread; i++) {
			*(values+i) = apin->analogRead();
			for(int j = 0; j < micros; j++) _delay_us(1);
		}
		SERIAL_PGMLN(datasetHdr);
		SERIAL_PORT.println();
		for(int i = 0; i < nread; i++) {
			SERIAL_PORT.print(i+1); // sequence
			SERIAL_PORT.print(' ');
			// 0 element is pin number
			if( i == 0 )
				SERIAL_PORT.println(apin->pin);
			else
				SERIAL_PORT.println(*(values+i)); // value
		}
		delete values;
		SERIAL_PORT.println();
		SERIAL_PORT.flush();
		break;	
		
	case 803:
		break;	
		
	case 907: 
		break; 
		 
	case 908: // M908 Control digital trimpot directly.
		uint8_t current;
		if(code_seen('P')) channel=code_value();
		if(code_seen('S')) current=code_value();
		digitalPotWrite(channel, current);
		break;
		
    case 999: // M999: Reset
		Stopped = false;
		//lcd_reset_alert_level();
		gcode_LastN = Stopped_gcode_LastN;
		//FlushSerialRequestResend();
		if( watchdog_timer != NULL )
			delete watchdog_timer;
		watchdog_timer = new WatchdogTimer();
		watchdog_timer->watchdog_init(15); // 15 ms
	
  } // switch m code

  } else { // if M code
    SERIAL_PGMLN(MSG_UNKNOWN_COMMAND);
    //SERIAL_PORT.println(cmdbuffer[bufindr]);
  }

}